diff --git a/assets/js/games/engine/ansi-converter.js b/assets/js/games/engine/ansi-converter.js
new file mode 100644
index 0000000..1b409b3
--- /dev/null
+++ b/assets/js/games/engine/ansi-converter.js
@@ -0,0 +1,212 @@
+// ANSI to HTML Converter
+// Converts ANSI escape sequences (256-color) to HTML spans with inline styles
+// Supports: 38;5;N (foreground), 48;5;N (background), and standard reset codes
+
+const AnsiConverter = {
+ // 256-color palette - standard xterm colors
+ palette: [
+ // Standard colors (0-15)
+ "#000000", "#800000", "#008000", "#808000", "#000080", "#800080", "#008080", "#c0c0c0",
+ "#808080", "#ff0000", "#00ff00", "#ffff00", "#0000ff", "#ff00ff", "#00ffff", "#ffffff",
+ // 216 color cube (16-231)
+ ...(() => {
+ const colors = [];
+ const levels = [0, 95, 135, 175, 215, 255];
+ for (let r = 0; r < 6; r++) {
+ for (let g = 0; g < 6; g++) {
+ for (let b = 0; b < 6; b++) {
+ colors.push(`#${levels[r].toString(16).padStart(2, "0")}${levels[g].toString(16).padStart(2, "0")}${levels[b].toString(16).padStart(2, "0")}`);
+ }
+ }
+ }
+ return colors;
+ })(),
+ // Grayscale (232-255)
+ ...(() => {
+ const grays = [];
+ for (let i = 0; i < 24; i++) {
+ const level = 8 + i * 10;
+ const hex = level.toString(16).padStart(2, "0");
+ grays.push(`#${hex}${hex}${hex}`);
+ }
+ return grays;
+ })(),
+ ],
+
+ // Get color from palette by index
+ getColor(index) {
+ if (index >= 0 && index < this.palette.length) {
+ return this.palette[index];
+ }
+ return null;
+ },
+
+ // Parse ANSI escape sequence and return style object
+ parseEscapeCode(code) {
+ const style = {};
+ const parts = code.split(";");
+
+ let i = 0;
+ while (i < parts.length) {
+ const num = parseInt(parts[i], 10);
+
+ // Reset
+ if (num === 0 || num === "m" || isNaN(num)) {
+ style.reset = true;
+ i++;
+ continue;
+ }
+
+ // 256-color foreground: 38;5;N
+ if (num === 38 && parts[i + 1] === "5") {
+ const colorIndex = parseInt(parts[i + 2], 10);
+ const color = this.getColor(colorIndex);
+ if (color) {
+ style.fg = color;
+ }
+ i += 3;
+ continue;
+ }
+
+ // 256-color background: 48;5;N
+ if (num === 48 && parts[i + 1] === "5") {
+ const colorIndex = parseInt(parts[i + 2], 10);
+ const color = this.getColor(colorIndex);
+ if (color) {
+ style.bg = color;
+ }
+ i += 3;
+ continue;
+ }
+
+ // Standard foreground colors (30-37)
+ if (num >= 30 && num <= 37) {
+ style.fg = this.palette[num - 30];
+ i++;
+ continue;
+ }
+
+ // Bright foreground colors (90-97)
+ if (num >= 90 && num <= 97) {
+ style.fg = this.palette[num - 90 + 8];
+ i++;
+ continue;
+ }
+
+ // Standard background colors (40-47)
+ if (num >= 40 && num <= 47) {
+ style.bg = this.palette[num - 40];
+ i++;
+ continue;
+ }
+
+ // Bright background colors (100-107)
+ if (num >= 100 && num <= 107) {
+ style.bg = this.palette[num - 100 + 8];
+ i++;
+ continue;
+ }
+
+ // Bold (1) - we'll treat as bright
+ if (num === 1) {
+ style.bold = true;
+ i++;
+ continue;
+ }
+
+ i++;
+ }
+
+ return style;
+ },
+
+ // Convert ANSI string to HTML
+ convert(ansiString) {
+ // Regex to match ANSI escape sequences
+ // Matches: \e[...m or \x1b[...m or actual escape character
+ const ansiRegex = /(?:\x1b|\u001b|\\e|\\x1b)\[([0-9;]*)m/g;
+
+ let html = "";
+ let currentFg = null;
+ let currentBg = null;
+ let lastIndex = 0;
+ let spanOpen = false;
+
+ // Replace escaped representations with actual escape character for easier processing
+ let processed = ansiString
+ .replace(/\\e/g, "\x1b")
+ .replace(/\\x1b/g, "\x1b");
+
+ let match;
+ while ((match = ansiRegex.exec(processed)) !== null) {
+ // Add text before this escape sequence
+ const textBefore = processed.slice(lastIndex, match.index);
+ if (textBefore) {
+ html += this.escapeHtml(textBefore);
+ }
+
+ // Parse the escape code
+ const style = this.parseEscapeCode(match[1]);
+
+ // Close previous span if needed
+ if (spanOpen) {
+ html += "";
+ spanOpen = false;
+ }
+
+ // Handle reset
+ if (style.reset) {
+ currentFg = null;
+ currentBg = null;
+ }
+
+ // Update current colors
+ if (style.fg) currentFg = style.fg;
+ if (style.bg) currentBg = style.bg;
+
+ // Open new span if we have colors
+ if (currentFg || currentBg) {
+ const styles = [];
+ if (currentFg) styles.push(`color:${currentFg}`);
+ if (currentBg) styles.push(`background-color:${currentBg}`);
+ html += ``;
+ spanOpen = true;
+ }
+
+ lastIndex = match.index + match[0].length;
+ }
+
+ // Add remaining text
+ const remaining = processed.slice(lastIndex);
+ if (remaining) {
+ html += this.escapeHtml(remaining);
+ }
+
+ // Close any open span
+ if (spanOpen) {
+ html += "";
+ }
+
+ return html;
+ },
+
+ // Escape HTML special characters (but preserve our spans)
+ escapeHtml(text) {
+ return text
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """);
+ },
+
+ // Convert and wrap in a pre-formatted container for proper display
+ convertToBlock(ansiString, className = "ansi-art") {
+ const html = this.convert(ansiString);
+ return `
${html}`;
+ },
+};
+
+// Export for use in other modules
+if (typeof window !== "undefined") {
+ window.AnsiConverter = AnsiConverter;
+}
diff --git a/assets/js/games/engine/game-engine.js b/assets/js/games/engine/game-engine.js
new file mode 100644
index 0000000..2b03baf
--- /dev/null
+++ b/assets/js/games/engine/game-engine.js
@@ -0,0 +1,210 @@
+// Game Engine - Main orchestrator for terminal games
+class GameEngine {
+ constructor(gameDefinition) {
+ this.definition = gameDefinition;
+ this.terminal = null;
+ this.adapter = null;
+ this.state = null;
+ this.input = null;
+ this.scenes = null;
+
+ this.isRunning = false;
+ this.originalExecuteCommand = null;
+ }
+
+ // Register this game as a terminal command
+ register() {
+ if (!window.terminal) {
+ console.warn("Terminal not available, cannot register game:", this.definition.id);
+ return;
+ }
+
+ this.terminal = window.terminal;
+ const self = this;
+ const def = this.definition;
+
+ this.terminal.registerCommand(
+ def.command || def.id,
+ def.description || `Play ${def.name}`,
+ async (args) => {
+ if (args[0] === "reset") {
+ self._reset();
+ return;
+ }
+ if (args[0] === "continue" || args[0] === "resume") {
+ await self.start(true);
+ return;
+ }
+ await self.start();
+ },
+ );
+ }
+
+ // Start the game
+ async start(continueGame = false) {
+ if (this.isRunning) {
+ this.terminal.printWarning("Game is already running!");
+ return;
+ }
+
+ this.isRunning = true;
+
+ // Initialize components
+ this.adapter = new TerminalAdapter(this.terminal);
+ this.state = new StateManager(this.definition.id);
+ this.input = new InputManager(this.adapter);
+ this.scenes = new SceneManager(this.adapter, this.state, this.input);
+
+ // Initialize state
+ this.state.init(this.definition.initialState || {});
+
+ // Register scenes
+ this.scenes.registerScenes(this.definition.scenes);
+
+ // Hook into terminal input
+ this._hookInput();
+
+ // Check for existing save
+ const hasSave = this.state.hasSavedState();
+
+ // Show intro unless continuing
+ if (!continueGame && !hasSave) {
+ if (this.definition.intro) {
+ await this._playIntro();
+ }
+ } else if (hasSave && !continueGame) {
+ // Ask if player wants to continue
+ this.adapter.clear();
+ this.adapter.printInfo("A saved game was found.");
+ const shouldContinue = await this.input.awaitConfirm("Continue from where you left off?");
+
+ if (!shouldContinue) {
+ this.state.reset();
+ this.state.init(this.definition.initialState || {});
+ if (this.definition.intro) {
+ await this._playIntro();
+ }
+ }
+ }
+
+ // Go to start scene (or last scene if continuing)
+ const startScene = this.state.get("_currentScene") || this.definition.startScene || "start";
+ await this.scenes.goTo(startScene);
+ }
+
+ async _playIntro() {
+ this.adapter.clear();
+
+ // Show title
+ if (this.definition.name) {
+ this.adapter.printHTML(
+ `${this.definition.name}
`,
+ );
+ this.adapter.print("");
+ }
+
+ // Show intro content
+ if (typeof this.definition.intro === "string") {
+ this.adapter.print(this.definition.intro);
+ } else if (Array.isArray(this.definition.intro)) {
+ await this.scenes._renderContent(this.definition.intro);
+ }
+
+ this.adapter.print("");
+
+ // Wait for input to continue
+ await this.input.awaitOption(
+ [{ text: "Begin", value: true }],
+ "Press Enter or 1 to start...",
+ );
+ }
+
+ _hookInput() {
+ // Store original executeCommand
+ this.originalExecuteCommand = this.terminal.executeCommand.bind(this.terminal);
+
+ // Override to intercept input
+ const self = this;
+ this.terminal.executeCommand = function (commandString) {
+ if (!self.isRunning) {
+ return self.originalExecuteCommand(commandString);
+ }
+
+ // Check for exit commands
+ const cmd = commandString.toLowerCase().trim();
+ if (cmd === "quit" || cmd === "exit" || cmd === "q") {
+ self.stop();
+ return;
+ }
+
+ // Check for save command
+ if (cmd === "save") {
+ self._saveProgress();
+ return;
+ }
+
+ // Pass to input manager if in text mode
+ if (self.input.getMode() === "text") {
+ self.input.handleTextInput(commandString);
+ }
+ };
+ }
+
+ _saveProgress() {
+ // Save current scene for resuming
+ const currentSceneId = this.scenes.getCurrentSceneId();
+ if (currentSceneId) {
+ this.state.set("_currentScene", currentSceneId);
+ }
+ this.adapter.printSuccess("Game progress saved.");
+ }
+
+ // Stop the game and restore terminal
+ stop() {
+ // Save progress before stopping
+ this._saveProgress();
+
+ this.isRunning = false;
+
+ // Cleanup input manager
+ if (this.input) {
+ this.input.destroy();
+ }
+
+ // Restore original command handler
+ if (this.originalExecuteCommand) {
+ this.terminal.executeCommand = this.originalExecuteCommand;
+ }
+
+ this.adapter.print("");
+ this.adapter.printInfo(`Exited ${this.definition.name}. Progress saved.`);
+ this.adapter.print('Type "help" for available commands.');
+ this.adapter.print(
+ `Type "${this.definition.command || this.definition.id}" to continue playing.`,
+ );
+ }
+
+ _reset() {
+ if (this.state) {
+ this.state.reset();
+ } else {
+ // Create temporary state manager just to reset
+ const tempState = new StateManager(this.definition.id);
+ tempState.reset();
+ }
+ this.terminal.printSuccess(`${this.definition.name} progress has been reset.`);
+ }
+
+ // Check if game is currently running
+ isActive() {
+ return this.isRunning;
+ }
+
+ // Get game definition
+ getDefinition() {
+ return this.definition;
+ }
+}
+
+// Make available globally
+window.GameEngine = GameEngine;
diff --git a/assets/js/games/engine/input-manager.js b/assets/js/games/engine/input-manager.js
new file mode 100644
index 0000000..26658ed
--- /dev/null
+++ b/assets/js/games/engine/input-manager.js
@@ -0,0 +1,205 @@
+// Input Manager - Handles text input and option selection modes
+class InputManager {
+ constructor(adapter) {
+ this.adapter = adapter;
+ this.mode = "idle"; // "idle" | "text" | "options"
+ this.options = [];
+ this.selectedIndex = 0;
+ this.inputResolve = null;
+ this.optionsContainerId = "game-options-" + Date.now();
+ this.keydownHandler = null;
+
+ this._setupKeyboardListener();
+ }
+
+ _setupKeyboardListener() {
+ this.keydownHandler = (e) => {
+ if (this.mode !== "options") return;
+
+ if (e.key === "ArrowUp") {
+ e.preventDefault();
+ e.stopPropagation();
+ this._selectPrevious();
+ } else if (e.key === "ArrowDown") {
+ e.preventDefault();
+ e.stopPropagation();
+ this._selectNext();
+ } else if (e.key === "Enter") {
+ e.preventDefault();
+ e.stopPropagation();
+ this._confirmSelection();
+ } else if (/^[1-9]$/.test(e.key)) {
+ const index = parseInt(e.key) - 1;
+ if (index < this.options.length) {
+ e.preventDefault();
+ e.stopPropagation();
+ this.selectedIndex = index;
+ this._confirmSelection();
+ }
+ }
+ };
+
+ document.addEventListener("keydown", this.keydownHandler, true);
+ }
+
+ // Text input mode - wait for user to type something
+ awaitText(prompt = "") {
+ return new Promise((resolve) => {
+ if (prompt) {
+ this.adapter.printInfo(prompt);
+ }
+
+ this.mode = "text";
+ this.inputResolve = resolve;
+
+ this.adapter.captureInput((value) => {
+ this.adapter.print(`> ${value}`);
+ this.mode = "idle";
+ this.adapter.releaseInput();
+ if (this.inputResolve) {
+ const res = this.inputResolve;
+ this.inputResolve = null;
+ res(value);
+ }
+ });
+
+ this.adapter.focusInput();
+ });
+ }
+
+ // Options selection mode - display choices and wait for selection
+ awaitOption(options, prompt = "") {
+ return new Promise((resolve) => {
+ this.mode = "options";
+ this.options = options;
+ this.selectedIndex = 0;
+ this.optionsContainerId = "game-options-" + Date.now();
+
+ if (prompt) {
+ this.adapter.print("");
+ this.adapter.printInfo(prompt);
+ }
+ this.adapter.print("");
+
+ this._renderOptions();
+
+ this.inputResolve = (index) => {
+ this.mode = "idle";
+ resolve({
+ index,
+ option: this.options[index],
+ });
+ };
+ });
+ }
+
+ // Yes/No confirmation
+ awaitConfirm(prompt = "Continue?") {
+ return this.awaitOption(
+ [
+ { text: "Yes", value: true },
+ { text: "No", value: false },
+ ],
+ prompt,
+ ).then((result) => result.option.value);
+ }
+
+ // Handle text input from game engine
+ handleTextInput(value) {
+ if (this.mode === "text" && this.inputResolve) {
+ this.adapter.print(`> ${value}`);
+ this.mode = "idle";
+ const res = this.inputResolve;
+ this.inputResolve = null;
+ res(value);
+ }
+ }
+
+ _renderOptions() {
+ const optionsHTML = this.options
+ .map((opt, idx) => {
+ const selected = idx === this.selectedIndex;
+ const prefix = selected ? ">" : " ";
+ const className = selected ? "game-option-selected" : "game-option";
+ const text = typeof opt === "string" ? opt : opt.text;
+ return `${prefix} ${idx + 1}. ${text}
`;
+ })
+ .join("");
+
+ this.adapter.printHTML(
+ `${optionsHTML}
`,
+ );
+ this.adapter.scrollToBottom();
+ }
+
+ _updateOptionsDisplay() {
+ const container = document.getElementById(this.optionsContainerId);
+ if (!container) return;
+
+ const optionDivs = container.querySelectorAll("div");
+ optionDivs.forEach((div, idx) => {
+ const selected = idx === this.selectedIndex;
+ div.className = selected ? "game-option-selected" : "game-option";
+ const text =
+ typeof this.options[idx] === "string"
+ ? this.options[idx]
+ : this.options[idx].text;
+ div.textContent = `${selected ? ">" : " "} ${idx + 1}. ${text}`;
+ });
+ }
+
+ _selectPrevious() {
+ if (this.selectedIndex > 0) {
+ this.selectedIndex--;
+ this._updateOptionsDisplay();
+ }
+ }
+
+ _selectNext() {
+ if (this.selectedIndex < this.options.length - 1) {
+ this.selectedIndex++;
+ this._updateOptionsDisplay();
+ }
+ }
+
+ _confirmSelection() {
+ if (this.inputResolve) {
+ const res = this.inputResolve;
+ this.inputResolve = null;
+
+ // Show what was selected
+ const selectedOpt = this.options[this.selectedIndex];
+ const text =
+ typeof selectedOpt === "string" ? selectedOpt : selectedOpt.text;
+ this.adapter.print("");
+ this.adapter.printSuccess(`> ${text}`);
+
+ res(this.selectedIndex);
+ }
+ }
+
+ // Check if currently waiting for input
+ isWaiting() {
+ return this.mode !== "idle";
+ }
+
+ // Get current mode
+ getMode() {
+ return this.mode;
+ }
+
+ // Cancel current input (for cleanup)
+ cancel() {
+ this.mode = "idle";
+ this.inputResolve = null;
+ this.adapter.releaseInput();
+ }
+
+ // Cleanup when game ends
+ destroy() {
+ if (this.keydownHandler) {
+ document.removeEventListener("keydown", this.keydownHandler, true);
+ }
+ this.cancel();
+ }
+}
diff --git a/assets/js/games/engine/scene-manager.js b/assets/js/games/engine/scene-manager.js
new file mode 100644
index 0000000..4a96ec5
--- /dev/null
+++ b/assets/js/games/engine/scene-manager.js
@@ -0,0 +1,367 @@
+// Scene Manager - Handles scene definitions, rendering, and transitions
+class SceneManager {
+ constructor(adapter, stateManager, inputManager) {
+ this.adapter = adapter;
+ this.state = stateManager;
+ this.input = inputManager;
+ this.scenes = {};
+ this.currentScene = null;
+ this.sceneHistory = [];
+ }
+
+ // Register scenes from game definition
+ registerScenes(sceneDefinitions) {
+ for (const [id, scene] of Object.entries(sceneDefinitions)) {
+ this.scenes[id] = { id, ...scene };
+ }
+ }
+
+ // Get scene by ID
+ getScene(sceneId) {
+ return this.scenes[sceneId];
+ }
+
+ // Navigate to a scene
+ async goTo(sceneId, options = {}) {
+ const scene = this.getScene(sceneId);
+ if (!scene) {
+ this.adapter.printError(`Scene not found: ${sceneId}`);
+ return;
+ }
+
+ // Track history for back navigation
+ if (this.currentScene && !options.noHistory) {
+ this.sceneHistory.push(this.currentScene.id);
+ }
+
+ this.currentScene = scene;
+
+ // Execute onEnter actions
+ if (scene.onEnter) {
+ await this._executeActions(scene.onEnter);
+ }
+
+ // Render the scene
+ await this._renderScene(scene);
+ }
+
+ // Go back to previous scene
+ async goBack() {
+ if (this.sceneHistory.length === 0) {
+ this.adapter.printWarning("No previous scene");
+ return;
+ }
+ const previousId = this.sceneHistory.pop();
+ await this.goTo(previousId, { noHistory: true });
+ }
+
+ // Render a scene
+ async _renderScene(scene) {
+ // Clear screen unless disabled
+ if (scene.clear !== false) {
+ this.adapter.clear();
+ }
+
+ // Render title
+ if (scene.title) {
+ this.adapter.printHTML(
+ `${scene.title}`,
+ );
+ this.adapter.print("");
+ }
+
+ // Render content blocks
+ if (scene.content) {
+ await this._renderContent(scene.content);
+ }
+
+ // Handle navigation
+ if (scene.options) {
+ await this._handleOptions(scene);
+ } else if (scene.input) {
+ await this._handleTextInput(scene);
+ } else if (scene.next) {
+ // Auto-advance with optional delay
+ const delay = scene.delay || 0;
+ if (delay > 0) {
+ await this._sleep(delay);
+ }
+ await this.goTo(scene.next);
+ }
+ }
+
+ // Render content blocks (supports conditional content)
+ async _renderContent(content) {
+ const blocks = Array.isArray(content) ? content : [content];
+
+ for (const block of blocks) {
+ // Simple string
+ if (typeof block === "string") {
+ this._printText(block);
+ continue;
+ }
+
+ // Conditional block
+ if (block.condition !== undefined) {
+ if (this.state.evaluate(block.condition)) {
+ if (block.content) {
+ await this._renderContent(block.content);
+ }
+ } else if (block.else) {
+ await this._renderContent(block.else);
+ }
+ continue;
+ }
+
+ // Typed blocks
+ if (block.type === "ascii") {
+ this.adapter.print(block.art, block.className || "game-ascii");
+ continue;
+ }
+
+ if (block.type === "ansi") {
+ // Convert ANSI escape codes to HTML
+ const html = AnsiConverter.convertToBlock(
+ block.art,
+ block.className || "game-ansi-art",
+ );
+ this.adapter.printHTML(html);
+ continue;
+ }
+
+ if (block.type === "html") {
+ this.adapter.printHTML(block.html, block.className || "");
+ continue;
+ }
+
+ if (block.type === "delay") {
+ await this._sleep(block.ms || 1000);
+ continue;
+ }
+
+ if (block.type === "typewriter") {
+ await this._typewriter(block.text, block.speed || 50);
+ continue;
+ }
+
+ // Text with optional className
+ if (block.text !== undefined) {
+ this._printText(block.text, block.className || "");
+ continue;
+ }
+ }
+ }
+
+ // Print text with variable interpolation
+ _printText(text, className = "") {
+ // Support ${path} interpolation
+ const interpolated = text.replace(/\$\{([^}]+)\}/g, (match, path) => {
+ const value = this.state.get(path);
+ return value !== undefined ? String(value) : match;
+ });
+
+ if (className) {
+ this.adapter.print(interpolated, className);
+ } else {
+ this.adapter.print(interpolated);
+ }
+ }
+
+ // Handle options/choices
+ async _handleOptions(scene) {
+ // Filter options based on conditions
+ const availableOptions = scene.options.filter((opt) => {
+ if (opt.condition !== undefined) {
+ return this.state.evaluate(opt.condition);
+ }
+ return true;
+ });
+
+ if (availableOptions.length === 0) {
+ if (scene.fallback) {
+ await this.goTo(scene.fallback);
+ }
+ return;
+ }
+
+ const result = await this.input.awaitOption(
+ availableOptions.map((o) => ({
+ text: this._interpolateText(o.text),
+ value: o,
+ })),
+ scene.prompt || "What do you do?",
+ );
+
+ const selected = result.option.value;
+
+ // Execute option actions
+ if (selected.actions) {
+ await this._executeActions(selected.actions);
+ }
+
+ // Navigate to next scene
+ if (selected.next) {
+ await this.goTo(selected.next);
+ }
+ }
+
+ // Handle text input
+ async _handleTextInput(scene) {
+ const inputDef = scene.input;
+ const value = await this.input.awaitText(inputDef.prompt);
+
+ // Store value if specified
+ if (inputDef.store) {
+ this.state.set(inputDef.store, value);
+ }
+
+ // Check for pattern matches
+ if (inputDef.matches) {
+ for (const match of inputDef.matches) {
+ const pattern =
+ match.pattern instanceof RegExp
+ ? match.pattern
+ : new RegExp(match.pattern, "i");
+
+ if (pattern.test(value)) {
+ if (match.actions) {
+ await this._executeActions(match.actions);
+ }
+ if (match.next) {
+ await this.goTo(match.next);
+ }
+ return;
+ }
+ }
+ }
+
+ // No match - use default
+ if (inputDef.default) {
+ if (inputDef.default.actions) {
+ await this._executeActions(inputDef.default.actions);
+ }
+ if (inputDef.default.next) {
+ await this.goTo(inputDef.default.next);
+ }
+ } else if (inputDef.next) {
+ await this.goTo(inputDef.next);
+ }
+ }
+
+ // Execute action commands
+ async _executeActions(actions) {
+ const actionList = Array.isArray(actions) ? actions : [actions];
+
+ for (const action of actionList) {
+ if (action.set !== undefined) {
+ this.state.set(action.set, action.value);
+ }
+
+ if (action.increment !== undefined) {
+ this.state.increment(action.increment, action.amount || 1);
+ }
+
+ if (action.decrement !== undefined) {
+ this.state.decrement(action.decrement, action.amount || 1);
+ }
+
+ if (action.addItem !== undefined) {
+ this.state.addToArray(action.to || "inventory", action.addItem);
+ }
+
+ if (action.removeItem !== undefined) {
+ this.state.removeFromArray(
+ action.from || "inventory",
+ action.removeItem,
+ );
+ }
+
+ if (action.print !== undefined) {
+ this._printText(action.print, action.className || "");
+ }
+
+ if (action.printSuccess !== undefined) {
+ this.adapter.printSuccess(this._interpolateText(action.printSuccess));
+ }
+
+ if (action.printError !== undefined) {
+ this.adapter.printError(this._interpolateText(action.printError));
+ }
+
+ if (action.printWarning !== undefined) {
+ this.adapter.printWarning(this._interpolateText(action.printWarning));
+ }
+
+ if (action.printInfo !== undefined) {
+ this.adapter.printInfo(this._interpolateText(action.printInfo));
+ }
+
+ if (action.delay !== undefined) {
+ await this._sleep(action.delay);
+ }
+
+ if (action.goTo !== undefined) {
+ await this.goTo(action.goTo);
+ return; // Stop processing further actions after navigation
+ }
+
+ if (action.callback && typeof action.callback === "function") {
+ await action.callback(this.state, this.adapter, this);
+ }
+ }
+ }
+
+ // Interpolate variables in text
+ _interpolateText(text) {
+ if (typeof text !== "string") return text;
+ return text.replace(/\$\{([^}]+)\}/g, (match, path) => {
+ const value = this.state.get(path);
+ return value !== undefined ? String(value) : match;
+ });
+ }
+
+ // Typewriter effect
+ async _typewriter(text, speed) {
+ const interpolated = this._interpolateText(text);
+ let output = "";
+
+ for (const char of interpolated) {
+ output += char;
+ // Create a single updating line for typewriter
+ const typewriterSpan =
+ this.adapter.terminal.output.querySelector(".typewriter-line");
+
+ if (typewriterSpan) {
+ typewriterSpan.textContent = output;
+ } else {
+ this.adapter.printHTML(
+ `${output}`,
+ );
+ }
+
+ this.adapter.scrollToBottom();
+ await this._sleep(speed);
+ }
+
+ // Finalize the line - remove the typewriter-line class so future typewriters create new lines
+ const typewriterSpan =
+ this.adapter.terminal.output.querySelector(".typewriter-line");
+ if (typewriterSpan) {
+ typewriterSpan.classList.remove("typewriter-line");
+ }
+ }
+
+ _sleep(ms) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+ }
+
+ // Get current scene ID
+ getCurrentSceneId() {
+ return this.currentScene ? this.currentScene.id : null;
+ }
+
+ // Reset scene history
+ resetHistory() {
+ this.sceneHistory = [];
+ }
+}
diff --git a/assets/js/games/engine/state-manager.js b/assets/js/games/engine/state-manager.js
new file mode 100644
index 0000000..7d25f41
--- /dev/null
+++ b/assets/js/games/engine/state-manager.js
@@ -0,0 +1,208 @@
+// State Manager - Manages game state with persistence and conditions
+class StateManager {
+ constructor(gameId) {
+ this.gameId = gameId;
+ this.state = {};
+ this.storageKey = `game_${gameId}_state`;
+ }
+
+ // Initialize with default state
+ init(defaultState = {}) {
+ this.state = this._deepClone(defaultState);
+ this._loadFromStorage();
+ }
+
+ // Get value using dot notation path (e.g., "inventory.sword")
+ get(path, defaultValue = undefined) {
+ const parts = path.split(".");
+ let current = this.state;
+
+ for (const part of parts) {
+ if (current === undefined || current === null) {
+ return defaultValue;
+ }
+ current = current[part];
+ }
+
+ return current !== undefined ? current : defaultValue;
+ }
+
+ // Set value using dot notation path
+ set(path, value) {
+ const parts = path.split(".");
+ let current = this.state;
+
+ for (let i = 0; i < parts.length - 1; i++) {
+ const part = parts[i];
+ if (current[part] === undefined) {
+ current[part] = {};
+ }
+ current = current[part];
+ }
+
+ current[parts[parts.length - 1]] = value;
+ this._saveToStorage();
+ }
+
+ // Increment a numeric value
+ increment(path, amount = 1) {
+ const current = this.get(path, 0);
+ this.set(path, current + amount);
+ }
+
+ // Decrement a numeric value
+ decrement(path, amount = 1) {
+ this.increment(path, -amount);
+ }
+
+ // Add item to an array (if not already present)
+ addToArray(path, item) {
+ const arr = this.get(path, []);
+ if (!arr.includes(item)) {
+ arr.push(item);
+ this.set(path, arr);
+ }
+ }
+
+ // Remove item from an array
+ removeFromArray(path, item) {
+ const arr = this.get(path, []);
+ const index = arr.indexOf(item);
+ if (index > -1) {
+ arr.splice(index, 1);
+ this.set(path, arr);
+ }
+ }
+
+ // Check if array contains item
+ hasItem(path, item) {
+ const arr = this.get(path, []);
+ return arr.includes(item);
+ }
+
+ // Evaluate a condition against current state
+ evaluate(condition) {
+ if (typeof condition === "boolean") {
+ return condition;
+ }
+
+ if (typeof condition === "string") {
+ // Simple path check - truthy value
+ return !!this.get(condition);
+ }
+
+ if (typeof condition === "object" && condition !== null) {
+ return this._evaluateConditionObject(condition);
+ }
+
+ return true;
+ }
+
+ _evaluateConditionObject(cond) {
+ // Logical operators
+ if (cond.and) {
+ return cond.and.every((c) => this.evaluate(c));
+ }
+ if (cond.or) {
+ return cond.or.some((c) => this.evaluate(c));
+ }
+ if (cond.not) {
+ return !this.evaluate(cond.not);
+ }
+
+ // Value comparisons
+ const value = this.get(cond.path);
+
+ if ("equals" in cond) {
+ return value === cond.equals;
+ }
+ if ("notEquals" in cond) {
+ return value !== cond.notEquals;
+ }
+ if ("greaterThan" in cond) {
+ return value > cond.greaterThan;
+ }
+ if ("greaterThanOrEqual" in cond) {
+ return value >= cond.greaterThanOrEqual;
+ }
+ if ("lessThan" in cond) {
+ return value < cond.lessThan;
+ }
+ if ("lessThanOrEqual" in cond) {
+ return value <= cond.lessThanOrEqual;
+ }
+ if ("contains" in cond) {
+ return Array.isArray(value) && value.includes(cond.contains);
+ }
+ if ("notContains" in cond) {
+ return !Array.isArray(value) || !value.includes(cond.notContains);
+ }
+
+ // Default: check truthiness of path
+ return !!value;
+ }
+
+ // Get entire state (for debugging)
+ getAll() {
+ return this._deepClone(this.state);
+ }
+
+ // Reset state and clear storage
+ reset() {
+ this.state = {};
+ try {
+ localStorage.removeItem(this.storageKey);
+ } catch (e) {
+ console.warn("Failed to clear game state from storage:", e);
+ }
+ }
+
+ // Check if there is saved state
+ hasSavedState() {
+ try {
+ return localStorage.getItem(this.storageKey) !== null;
+ } catch (e) {
+ return false;
+ }
+ }
+
+ _saveToStorage() {
+ try {
+ localStorage.setItem(this.storageKey, JSON.stringify(this.state));
+ } catch (e) {
+ console.warn("Failed to save game state:", e);
+ }
+ }
+
+ _loadFromStorage() {
+ try {
+ const saved = localStorage.getItem(this.storageKey);
+ if (saved) {
+ const parsed = JSON.parse(saved);
+ this.state = this._mergeDeep(this.state, parsed);
+ }
+ } catch (e) {
+ console.warn("Failed to load game state:", e);
+ }
+ }
+
+ _deepClone(obj) {
+ return JSON.parse(JSON.stringify(obj));
+ }
+
+ _mergeDeep(target, source) {
+ const result = { ...target };
+ for (const key of Object.keys(source)) {
+ if (
+ source[key] &&
+ typeof source[key] === "object" &&
+ !Array.isArray(source[key])
+ ) {
+ result[key] = this._mergeDeep(result[key] || {}, source[key]);
+ } else {
+ result[key] = source[key];
+ }
+ }
+ return result;
+ }
+}
diff --git a/assets/js/games/engine/terminal-adapter.js b/assets/js/games/engine/terminal-adapter.js
new file mode 100644
index 0000000..5b414b3
--- /dev/null
+++ b/assets/js/games/engine/terminal-adapter.js
@@ -0,0 +1,70 @@
+// Terminal Adapter - Bridges game engine to existing TerminalShell
+class TerminalAdapter {
+ constructor(terminal) {
+ this.terminal = terminal;
+ this.inputCallback = null;
+ }
+
+ // Output methods - delegate to terminal
+ print(text, className = "") {
+ this.terminal.print(text, className);
+ }
+
+ printHTML(html, className = "") {
+ this.terminal.printHTML(html, className);
+ }
+
+ printError(text) {
+ this.terminal.printError(text);
+ }
+
+ printSuccess(text) {
+ this.terminal.printSuccess(text);
+ }
+
+ printInfo(text) {
+ this.terminal.printInfo(text);
+ }
+
+ printWarning(text) {
+ this.terminal.printWarning(text);
+ }
+
+ clear() {
+ this.terminal.clear();
+ }
+
+ scrollToBottom() {
+ this.terminal.scrollToBottom();
+ }
+
+ // Input capture - allows game to intercept terminal input
+ captureInput(callback) {
+ this.inputCallback = callback;
+ }
+
+ releaseInput() {
+ this.inputCallback = null;
+ }
+
+ // Called by game engine when input is received
+ handleInput(value) {
+ if (this.inputCallback) {
+ this.inputCallback(value);
+ return true;
+ }
+ return false;
+ }
+
+ // Get the input element for focus management
+ getInputElement() {
+ return this.terminal.input;
+ }
+
+ // Focus the input
+ focusInput() {
+ if (this.terminal.input) {
+ this.terminal.input.focus();
+ }
+ }
+}
diff --git a/assets/js/games/games/boxing-day.js b/assets/js/games/games/boxing-day.js
new file mode 100644
index 0000000..05b0ac8
--- /dev/null
+++ b/assets/js/games/games/boxing-day.js
@@ -0,0 +1,1457 @@
+// Boxing Day - Day 1: December 26, 1999
+// A BBS-themed mystery game
+
+// ASCII Art Constants
+const BOXING_DAY_TITLE = `
+ ____ _____ ___ __ ____ _ __________ ____ _____ __ __
+ / __ )/ __ \\ \\/ / / // / / / | / / ____/ / / __ \\/ ___// / / /
+ / __ / / / /\\ / / // /_/ / |/ / / __/ / / / / /\\__ \\/ /_/ /
+ / /_/ / /_/ / / / /__ __/ /| / /_/ / /___/ /_/ /___/ / __ /
+/_____/\\____/ /_/ /_/ /_/ |_/\\____/_____/_____//____/_/ /_/
+`;
+
+const DARK_TOWER_HEADER = `e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;4m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;240;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;234;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;235;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;232;48;5;0m▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[38;5;242;48;5;240m▄\e[38;5;17;48;5;0m▄\e[38;5;4;48;5;17m▄\e[38;5;18;48;5;4m▄\e[38;5;18;48;5;19m▄\e[38;5;18;48;5;4m▄\e[38;5;4;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;233;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;238;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;232;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;20;48;5;4m▄\e[38;5;18;48;5;19m▄\e[38;5;17;48;5;17m▄\e[48;5;0m \e[38;5;239;48;5;234m▄\e[48;5;0m \e[38;5;4;48;5;17m▄\e[38;5;20;48;5;18m▄\e[38;5;18;48;5;18m▄▄\e[38;5;19;48;5;0m▄▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;233m▄▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;233m▄\e[38;5;235;48;5;236m▄\e[38;5;235;48;5;237m▄\e[48;5;0m \e[38;5;235;48;5;233m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;19m▄\e[38;5;19;48;5;17m▄\e[38;5;19;48;5;0m▄\e[38;5;20;48;5;19m▄\e[38;5;20;48;5;0m▄▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;0m▄\e[38;5;238;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;186;48;5;232m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[38;5;17;48;5;17m▄\e[38;5;19;48;5;18m▄\e[38;5;18;48;5;18m▄\e[38;5;0;48;5;0m▄▄\e[38;5;18;48;5;18m▄\e[38;5;19;48;5;18m▄\e[38;5;4;48;5;18m▄\e[38;5;17;48;5;18m▄\e[38;5;17;48;5;19m▄\e[38;5;19;48;5;19m▄\e[38;5;19;48;5;18m▄\e[38;5;18;48;5;19m▄\e[48;5;0m \e[38;5;241;48;5;59m▄\e[48;5;0m \e[38;5;0;48;5;17m▄\e[38;5;20;48;5;19m▄\e[38;5;17;48;5;19m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;18m▄\e[38;5;0;48;5;19m▄\e[38;5;0;48;5;18m▄\e[38;5;18;48;5;19m▄\e[38;5;0;48;5;0m▄\e[38;5;60;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[38;5;0;48;5;87m▄\e[48;5;0m \e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;234m▄\e[38;5;117;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;52m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;19m▄\e[38;5;0;48;5;24m▄\e[38;5;0;48;5;19m▄▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;235;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;166m▄\e[38;5;0;48;5;202m▄\e[38;5;52;48;5;0m▄\e[38;5;0;48;5;130m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;17m▄▄\e[38;5;18;48;5;18m▄\e[38;5;0;48;5;17m▄▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;18;48;5;17m▄\e[38;5;4;48;5;4m▄\e[38;5;19;48;5;4m▄\e[38;5;4;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;242;48;5;239m▄\e[38;5;241;48;5;243m▄\e[48;5;0m \e[38;5;18;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;19m▄\e[38;5;17;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;232;48;5;0m▄\e[38;5;23;48;5;0m▄\e[38;5;68;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;232m▄\e[38;5;18;48;5;17m▄\e[38;5;4;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;232m▄\e[38;5;220;48;5;202m▄\e[38;5;52;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;17m▄▄\e[38;5;18;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;202;48;5;0m▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;232m▄▄\e[38;5;17;48;5;232m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;232m▄\e[38;5;17;48;5;17m▄\e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;20;48;5;19m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;52m▄\e[38;5;208;48;5;166m▄\e[38;5;124;48;5;233m▄\e[38;5;52;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;146;48;5;233m▄\e[38;5;17;48;5;19m▄\e[38;5;0;48;5;19m▄\e[38;5;18;48;5;17m▄\e[38;5;4;48;5;17m▄\e[38;5;18;48;5;17m▄\e[38;5;19;48;5;4m▄\e[38;5;20;48;5;18m▄\e[38;5;0;48;5;19m▄\e[38;5;12;48;5;19m▄\e[38;5;19;48;5;12m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;102;48;5;8m▄\e[38;5;8;48;5;243m▄\e[48;5;0m \e[38;5;19;48;5;4m▄\e[38;5;8;48;5;251m▄\e[38;5;20;48;5;20m▄\e[38;5;19;48;5;20m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;25m▄\e[38;5;17;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[38;5;18;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;18;48;5;18m▄▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;232m▄▄\e[38;5;52;48;5;52m▄\e[38;5;160;48;5;9m▄\e[38;5;220;48;5;11m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[38;5;248;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;26;48;5;4m▄\e[38;5;17;48;5;18m▄\e[38;5;17;48;5;232m▄\e[38;5;17;48;5;0m▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;4m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;24m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄▄\e[38;5;250;48;5;1m▄\e[38;5;248;48;5;160m▄\e[38;5;11;48;5;11m▄\e[38;5;88;48;5;52m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;17;48;5;24m▄\e[38;5;19;48;5;18m▄\e[38;5;4;48;5;18m▄▄▄\e[38;5;20;48;5;20m▄\e[38;5;12;48;5;20m▄\e[38;5;27;48;5;12m▄\e[38;5;247;48;5;250m▄\e[38;5;57;48;5;12m▄\e[38;5;236;48;5;17m▄\e[38;5;241;48;5;238m▄\e[38;5;247;48;5;234m▄\e[38;5;102;48;5;241m▄\e[38;5;236;48;5;243m▄\e[38;5;59;48;5;237m▄\e[48;5;0m \e[38;5;243;48;5;243m▄\e[38;5;20;48;5;12m▄\e[38;5;61;48;5;20m▄\e[38;5;237;48;5;234m▄\e[38;5;19;48;5;4m▄\e[38;5;4;48;5;0m▄\e[38;5;19;48;5;17m▄\e[38;5;17;48;5;0m▄▄▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;232;48;5;232m▄\e[38;5;233;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;52m▄\e[38;5;124;48;5;52m▄\e[38;5;124;48;5;160m▄\e[38;5;227;48;5;166m▄\e[38;5;227;48;5;11m▄\e[38;5;52;48;5;202m▄\e[38;5;52;48;5;232m▄\e[38;5;0;48;5;220m▄\e[38;5;0;48;5;88m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;88m▄\e[38;5;0;48;5;1m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;103m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;24m▄▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;25m▄\e[38;5;0;48;5;145m▄\e[38;5;0;48;5;235m▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;17;48;5;0m▄\e[38;5;17;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;235;48;5;234m▄\e[38;5;1;48;5;52m▄\e[38;5;124;48;5;88m▄\e[38;5;166;48;5;160m▄\e[38;5;227;48;5;227m▄\e[38;5;227;48;5;220m▄\e[38;5;52;48;5;1m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;232m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;4m▄\e[38;5;17;48;5;4m▄\e[38;5;19;48;5;18m▄\e[38;5;19;48;5;4m▄\e[38;5;19;48;5;19m▄\e[38;5;20;48;5;4m▄\e[38;5;12;48;5;12m▄\e[38;5;235;48;5;253m▄\e[38;5;0;48;5;233m▄\e[38;5;242;48;5;102m▄\e[38;5;237;48;5;232m▄\e[38;5;102;48;5;0m▄\e[38;5;247;48;5;234m▄\e[38;5;232;48;5;232m▄\e[38;5;242;48;5;235m▄\e[38;5;235;48;5;0m▄\e[38;5;0;48;5;239m▄\e[38;5;0;48;5;232m▄\e[38;5;27;48;5;20m▄\e[38;5;233;48;5;234m▄\e[38;5;237;48;5;238m▄\e[38;5;19;48;5;19m▄\e[38;5;4;48;5;18m▄\e[38;5;17;48;5;4m▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;19m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;11;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;214m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;232;48;5;243m▄\e[48;5;0m \e[38;5;17;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;232m▄\e[38;5;233;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;130;48;5;0m▄\e[38;5;172;48;5;232m▄\e[38;5;179;48;5;52m▄▄\e[38;5;227;48;5;1m▄\e[38;5;228;48;5;221m▄\e[38;5;230;48;5;228m▄\e[38;5;227;48;5;52m▄\e[38;5;172;48;5;0m▄▄▄\e[38;5;166;48;5;0m▄\e[38;5;1;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;52;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄▄▄▄▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;88;48;5;52m▄\e[38;5;124;48;5;124m▄\e[38;5;208;48;5;223m▄\e[38;5;229;48;5;9m▄\e[38;5;187;48;5;228m▄\e[38;5;221;48;5;88m▄\e[38;5;52;48;5;241m▄\e[38;5;234;48;5;234m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;19;48;5;19m▄\e[38;5;20;48;5;19m▄\e[38;5;27;48;5;20m▄\e[38;5;27;48;5;19m▄\e[38;5;63;48;5;12m▄\e[38;5;251;48;5;251m▄\e[38;5;252;48;5;252m▄\e[38;5;0;48;5;0m▄\e[38;5;248;48;5;242m▄\e[38;5;232;48;5;236m▄\e[48;5;0m \e[38;5;232;48;5;237m▄\e[38;5;240;48;5;246m▄\e[38;5;235;48;5;236m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;27;48;5;20m▄\e[38;5;20;48;5;17m▄\e[38;5;4;48;5;0m▄\e[38;5;25;48;5;0m▄\e[38;5;14;48;5;17m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;17m▄▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;4m▄\e[38;5;188;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;18;48;5;232m▄\e[38;5;0;48;5;52m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;52;48;5;202m▄▄\e[38;5;227;48;5;202m▄\e[38;5;221;48;5;202m▄\e[38;5;187;48;5;202m▄\e[38;5;0;48;5;202m▄▄▄\e[38;5;94;48;5;202m▄\e[38;5;186;48;5;202m▄\e[38;5;228;48;5;220m▄\e[38;5;208;48;5;220m▄\e[38;5;220;48;5;0m▄\e[38;5;124;48;5;0m▄\e[38;5;124;48;5;52m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;208;48;5;17m▄\e[38;5;220;48;5;0m▄▄\e[38;5;11;48;5;0m▄▄▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;221;48;5;0m▄\e[38;5;11;48;5;0m▄▄\e[38;5;220;48;5;0m▄\e[38;5;208;48;5;0m▄\e[38;5;214;48;5;0m▄\e[38;5;220;48;5;0m▄▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;19m▄▄\e[38;5;214;48;5;0m▄\e[38;5;220;48;5;0m▄▄\e[38;5;11;48;5;0m▄\e[38;5;227;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;232m▄\e[38;5;52;48;5;52m▄\e[38;5;227;48;5;227m▄\e[38;5;221;48;5;228m▄\e[38;5;202;48;5;228m▄\e[38;5;0;48;5;214m▄\e[38;5;0;48;5;202m▄\e[38;5;0;48;5;52m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;19;48;5;17m▄\e[38;5;18;48;5;232m▄\e[38;5;12;48;5;20m▄\e[38;5;12;48;5;12m▄\e[38;5;12;48;5;20m▄\e[38;5;20;48;5;12m▄\e[38;5;33;48;5;27m▄\e[38;5;188;48;5;248m▄\e[38;5;255;48;5;254m▄\e[38;5;15;48;5;0m▄\e[38;5;254;48;5;251m▄\e[38;5;248;48;5;234m▄\e[38;5;8;48;5;0m▄\e[38;5;238;48;5;237m▄\e[38;5;243;48;5;242m▄\e[38;5;238;48;5;235m▄\e[38;5;0;48;5;232m▄\e[38;5;238;48;5;0m▄\e[38;5;60;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;27;48;5;27m▄\e[38;5;19;48;5;12m▄\e[38;5;20;48;5;19m▄\e[38;5;12;48;5;19m▄\e[38;5;12;48;5;4m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;4;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;18;48;5;19m▄\e[38;5;0;48;5;4m▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;4m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄\e[38;5;251;48;5;230m▄\e[38;5;145;48;5;255m▄\e[38;5;253;48;5;255m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;94m▄\e[38;5;214;48;5;252m▄\e[38;5;145;48;5;255m▄\e[38;5;248;48;5;254m▄\e[38;5;187;48;5;220m▄\e[38;5;0;48;5;88m▄\e[38;5;0;48;5;124m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;254;48;5;214m▄\e[38;5;223;48;5;221m▄\e[38;5;254;48;5;229m▄\e[38;5;250;48;5;229m▄\e[38;5;220;48;5;235m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;214m▄\e[38;5;255;48;5;221m▄▄\e[38;5;228;48;5;131m▄\e[38;5;0;48;5;166m▄\e[38;5;52;48;5;130m▄\e[38;5;187;48;5;222m▄\e[38;5;254;48;5;228m▄\e[38;5;230;48;5;94m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;179;48;5;202m▄\e[38;5;253;48;5;221m▄\e[38;5;254;48;5;229m▄\e[38;5;101;48;5;3m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;223;48;5;0m▄\e[38;5;242;48;5;180m▄\e[38;5;52;48;5;243m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;4;48;5;4m▄\e[38;5;18;48;5;23m▄\e[38;5;18;48;5;25m▄▄\e[38;5;26;48;5;25m▄\e[38;5;20;48;5;26m▄\e[38;5;33;48;5;33m▄\e[38;5;0;48;5;253m▄\e[38;5;145;48;5;15m▄\e[38;5;234;48;5;251m▄\e[38;5;239;48;5;0m▄\e[38;5;233;48;5;232m▄\e[38;5;234;48;5;237m▄\e[38;5;232;48;5;0m▄\e[38;5;234;48;5;234m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;240m▄\e[38;5;0;48;5;239m▄\e[38;5;233;48;5;238m▄\e[48;5;0m \e[38;5;26;48;5;27m▄\e[38;5;26;48;5;26m▄\e[38;5;19;48;5;19m▄\e[38;5;19;48;5;4m▄\e[38;5;18;48;5;236m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;18;48;5;0m▄\e[38;5;19;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;19;48;5;19m▄\e[38;5;20;48;5;19m▄\e[38;5;20;48;5;0m▄\e[38;5;19;48;5;19m▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄\e[38;5;52;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[38;5;247;48;5;240m▄\e[38;5;59;48;5;240m▄\e[38;5;242;48;5;8m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;137;48;5;242m▄\e[38;5;246;48;5;248m▄\e[38;5;253;48;5;249m▄\e[38;5;221;48;5;221m▄\e[38;5;88;48;5;1m▄\e[38;5;0;48;5;0m▄\e[38;5;179;48;5;0m▄\e[38;5;249;48;5;246m▄\e[38;5;0;48;5;136m▄\e[38;5;8;48;5;223m▄\e[38;5;8;48;5;248m▄\e[38;5;138;48;5;173m▄\e[38;5;94;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;7;48;5;255m▄▄\e[38;5;221;48;5;229m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;88m▄\e[38;5;245;48;5;254m▄\e[38;5;242;48;5;254m▄\e[38;5;233;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;137;48;5;144m▄\e[38;5;248;48;5;59m▄\e[38;5;8;48;5;243m▄\e[38;5;3;48;5;137m▄\e[38;5;222;48;5;0m▄\e[38;5;102;48;5;229m▄\e[38;5;95;48;5;59m▄\e[38;5;0;48;5;208m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;0m▄\e[38;5;24;48;5;17m▄\e[38;5;19;48;5;4m▄\e[38;5;4;48;5;4m▄\e[38;5;4;48;5;18m▄\e[38;5;25;48;5;19m▄\e[38;5;25;48;5;4m▄\e[38;5;25;48;5;20m▄\e[38;5;26;48;5;27m▄\e[38;5;27;48;5;27m▄\e[38;5;33;48;5;27m▄▄\e[38;5;250;48;5;233m▄\e[38;5;249;48;5;59m▄\e[38;5;245;48;5;239m▄\e[38;5;241;48;5;234m▄\e[38;5;243;48;5;233m▄\e[38;5;235;48;5;233m▄\e[38;5;246;48;5;240m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;236;48;5;0m▄\e[38;5;238;48;5;0m▄\e[38;5;239;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;26;48;5;0m▄\e[38;5;27;48;5;20m▄\e[38;5;27;48;5;18m▄\e[38;5;19;48;5;17m▄\e[38;5;232;48;5;17m▄\e[38;5;19;48;5;18m▄\e[38;5;0;48;5;17m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;17m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;19m▄\e[38;5;18;48;5;19m▄\e[38;5;20;48;5;19m▄\e[38;5;19;48;5;18m▄\e[38;5;19;48;5;19m▄\e[38;5;20;48;5;19m▄\e[38;5;20;48;5;0m▄\e[38;5;19;48;5;4m▄\e[38;5;24;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;17;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;17;48;5;179m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;234m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;253m▄\e[38;5;236;48;5;8m▄\e[38;5;8;48;5;241m▄\e[38;5;59;48;5;59m▄\e[38;5;0;48;5;0m▄▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;52;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;180;48;5;94m▄\e[38;5;140;48;5;111m▄\e[38;5;8;48;5;146m▄\e[38;5;186;48;5;101m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;240;48;5;180m▄\e[38;5;238;48;5;174m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;7;48;5;147m▄\e[38;5;189;48;5;153m▄\e[38;5;246;48;5;185m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;8;48;5;251m▄\e[38;5;246;48;5;249m▄\e[38;5;242;48;5;166m▄\e[38;5;230;48;5;0m▄▄\e[38;5;145;48;5;187m▄\e[38;5;0;48;5;242m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;52;48;5;52m▄\e[38;5;239;48;5;241m▄\e[38;5;245;48;5;247m▄\e[38;5;241;48;5;242m▄\e[38;5;243;48;5;179m▄\e[38;5;8;48;5;249m▄\e[38;5;145;48;5;253m▄\e[38;5;59;48;5;101m▄\e[38;5;0;48;5;0m▄\e[38;5;88;48;5;0m▄\e[38;5;1;48;5;1m▄\e[38;5;0;48;5;52m▄\e[38;5;232;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;101;48;5;17m▄\e[38;5;31;48;5;66m▄\e[38;5;25;48;5;25m▄▄\e[38;5;25;48;5;32m▄\e[38;5;45;48;5;27m▄\e[38;5;81;48;5;26m▄\e[38;5;81;48;5;33m▄\e[38;5;26;48;5;33m▄\e[38;5;81;48;5;27m▄\e[38;5;251;48;5;243m▄\e[38;5;250;48;5;232m▄\e[38;5;240;48;5;8m▄\e[38;5;242;48;5;243m▄\e[38;5;238;48;5;235m▄\e[38;5;172;48;5;233m▄\e[38;5;246;48;5;8m▄\e[38;5;0;48;5;0m▄\e[38;5;238;48;5;236m▄\e[38;5;237;48;5;237m▄\e[38;5;233;48;5;0m▄\e[38;5;235;48;5;238m▄\e[48;5;0m \e[38;5;74;48;5;26m▄\e[38;5;0;48;5;19m▄\e[38;5;25;48;5;20m▄\e[38;5;236;48;5;18m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;52m▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;4;48;5;17m▄\e[38;5;17;48;5;234m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;242;48;5;248m▄\e[38;5;242;48;5;240m▄\e[38;5;253;48;5;237m▄\e[48;5;0m \e[38;5;233;48;5;0m▄\e[38;5;234;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;144;48;5;179m▄\e[38;5;145;48;5;239m▄\e[38;5;238;48;5;239m▄\e[38;5;230;48;5;187m▄\e[48;5;0m \e[38;5;243;48;5;59m▄\e[38;5;59;48;5;7m▄\e[38;5;236;48;5;251m▄\e[38;5;238;48;5;187m▄\e[38;5;59;48;5;187m▄\e[38;5;241;48;5;230m▄\e[38;5;242;48;5;245m▄\e[38;5;242;48;5;246m▄\e[38;5;186;48;5;235m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;241;48;5;239m▄\e[38;5;239;48;5;243m▄\e[38;5;102;48;5;242m▄\e[38;5;0;48;5;238m▄\e[38;5;242;48;5;246m▄\e[38;5;7;48;5;254m▄\e[38;5;255;48;5;230m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;52;48;5;52m▄\e[38;5;242;48;5;242m▄\e[38;5;247;48;5;8m▄\e[38;5;246;48;5;246m▄\e[38;5;243;48;5;241m▄\e[38;5;0;48;5;238m▄\e[38;5;240;48;5;241m▄\e[38;5;239;48;5;243m▄\e[38;5;245;48;5;173m▄\e[38;5;172;48;5;52m▄\e[38;5;1;48;5;52m▄\e[38;5;0;48;5;232m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;53m▄\e[38;5;20;48;5;25m▄\e[38;5;234;48;5;25m▄\e[38;5;25;48;5;17m▄\e[38;5;25;48;5;25m▄\e[38;5;19;48;5;75m▄\e[38;5;25;48;5;81m▄\e[38;5;27;48;5;123m▄\e[38;5;27;48;5;45m▄\e[38;5;242;48;5;246m▄\e[38;5;250;48;5;250m▄\e[38;5;8;48;5;245m▄\e[48;5;242m \e[38;5;11;48;5;11m▄▄\e[38;5;243;48;5;246m▄\e[38;5;233;48;5;234m▄\e[38;5;237;48;5;236m▄\e[38;5;235;48;5;238m▄\e[38;5;0;48;5;234m▄▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;24;48;5;232m▄\e[38;5;233;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[38;5;19;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;234;48;5;232m▄\e[38;5;52;48;5;17m▄\e[38;5;0;48;5;18m▄\e[38;5;52;48;5;17m▄\e[38;5;235;48;5;17m▄\e[38;5;232;48;5;233m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;246;48;5;246m▄\e[38;5;250;48;5;243m▄\e[38;5;187;48;5;8m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;239m▄\e[38;5;17;48;5;60m▄\e[38;5;0;48;5;0m▄\e[38;5;229;48;5;0m▄\e[38;5;239;48;5;246m▄\e[38;5;242;48;5;102m▄\e[38;5;0;48;5;254m▄\e[48;5;0m \e[38;5;240;48;5;0m▄\e[38;5;59;48;5;240m▄\e[38;5;0;48;5;248m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;102;48;5;240m▄\e[38;5;240;48;5;243m▄\e[38;5;239;48;5;236m▄\e[38;5;145;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;59;48;5;239m▄\e[38;5;254;48;5;248m▄\e[38;5;246;48;5;248m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;238;48;5;242m▄\e[38;5;246;48;5;247m▄\e[38;5;8;48;5;255m▄\e[38;5;15;48;5;0m▄\e[48;5;0m \e[38;5;8;48;5;245m▄\e[38;5;247;48;5;240m▄\e[38;5;242;48;5;102m▄\e[38;5;239;48;5;101m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;246m▄\e[38;5;240;48;5;243m▄\e[38;5;246;48;5;187m▄\e[38;5;214;48;5;88m▄\e[38;5;1;48;5;1m▄\e[38;5;232;48;5;52m▄\e[38;5;232;48;5;17m▄\e[38;5;232;48;5;146m▄\e[38;5;167;48;5;182m▄\e[38;5;239;48;5;232m▄\e[38;5;17;48;5;4m▄\e[38;5;4;48;5;32m▄\e[38;5;18;48;5;17m▄\e[38;5;4;48;5;17m▄\e[38;5;0;48;5;18m▄\e[38;5;26;48;5;26m▄\e[38;5;19;48;5;12m▄\e[38;5;236;48;5;236m▄\e[38;5;242;48;5;249m▄\e[38;5;241;48;5;245m▄\e[38;5;242;48;5;242m▄\e[38;5;240;48;5;11m▄\e[38;5;246;48;5;220m▄\e[38;5;245;48;5;8m▄\e[38;5;235;48;5;232m▄\e[38;5;232;48;5;236m▄\e[38;5;233;48;5;232m▄\e[38;5;233;48;5;214m▄\e[48;5;0m \e[38;5;23;48;5;17m▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;23;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;233;48;5;232m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[m
+\e[48;5;0m \e[38;5;255;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄\e[38;5;52;48;5;52m▄\e[38;5;0;48;5;0m▄\e[38;5;1;48;5;0m▄\e[38;5;88;48;5;0m▄\e[38;5;52;48;5;0m▄\e[38;5;160;48;5;0m▄▄\e[38;5;160;48;5;52m▄\e[38;5;52;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;7;48;5;137m▄\e[38;5;236;48;5;237m▄\e[38;5;237;48;5;8m▄\e[38;5;102;48;5;187m▄\e[38;5;242;48;5;0m▄\e[38;5;187;48;5;0m▄\e[38;5;144;48;5;0m▄\e[38;5;245;48;5;232m▄\e[38;5;245;48;5;253m▄\e[38;5;254;48;5;239m▄\e[38;5;0;48;5;245m▄\e[38;5;0;48;5;243m▄\e[48;5;0m \e[38;5;250;48;5;0m▄\e[38;5;237;48;5;251m▄\e[38;5;102;48;5;243m▄\e[38;5;242;48;5;0m▄\e[38;5;255;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;104;48;5;0m▄\e[38;5;59;48;5;245m▄\e[38;5;247;48;5;239m▄\e[38;5;247;48;5;8m▄\e[38;5;245;48;5;245m▄\e[38;5;7;48;5;0m▄\e[38;5;250;48;5;232m▄\e[38;5;252;48;5;237m▄\e[38;5;102;48;5;247m▄\e[38;5;102;48;5;254m▄\e[38;5;15;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;7;48;5;238m▄\e[38;5;248;48;5;237m▄\e[38;5;246;48;5;240m▄\e[38;5;240;48;5;233m▄\e[38;5;248;48;5;255m▄\e[38;5;248;48;5;8m▄\e[38;5;102;48;5;59m▄\e[38;5;59;48;5;246m▄\e[38;5;254;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;230m▄\e[38;5;0;48;5;8m▄\e[38;5;180;48;5;8m▄\e[38;5;187;48;5;137m▄\e[38;5;221;48;5;124m▄\e[38;5;9;48;5;0m▄\e[38;5;160;48;5;0m▄\e[38;5;208;48;5;202m▄\e[38;5;1;48;5;52m▄\e[38;5;124;48;5;52m▄\e[38;5;88;48;5;17m▄\e[38;5;52;48;5;233m▄\e[38;5;0;48;5;17m▄▄\e[38;5;232;48;5;18m▄\e[38;5;59;48;5;0m▄\e[38;5;241;48;5;246m▄\e[38;5;233;48;5;235m▄\e[38;5;240;48;5;243m▄\e[38;5;233;48;5;242m▄\e[38;5;241;48;5;243m▄\e[38;5;233;48;5;236m▄\e[38;5;242;48;5;238m▄\e[38;5;233;48;5;0m▄▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;24;48;5;0m▄\e[38;5;236;48;5;232m▄\e[38;5;0;48;5;23m▄\e[48;5;0m \e[38;5;234;48;5;233m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;17;48;5;0m▄\e[38;5;1;48;5;172m▄\e[38;5;202;48;5;208m▄▄▄▄▄▄\e[38;5;214;48;5;214m▄\e[38;5;208;48;5;214m▄▄\e[38;5;11;48;5;11m▄▄\e[38;5;220;48;5;11m▄\e[38;5;202;48;5;11m▄\e[38;5;220;48;5;227m▄\e[38;5;208;48;5;228m▄\e[38;5;214;48;5;228m▄\e[38;5;130;48;5;227m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;232m▄\e[38;5;52;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;52;48;5;227m▄\e[38;5;137;48;5;227m▄\e[38;5;208;48;5;227m▄\e[38;5;202;48;5;11m▄\e[38;5;202;48;5;227m▄\e[38;5;220;48;5;228m▄\e[38;5;202;48;5;11m▄▄▄\e[38;5;202;48;5;220m▄\e[38;5;202;48;5;124m▄\e[38;5;202;48;5;160m▄\e[38;5;208;48;5;160m▄\e[38;5;220;48;5;160m▄\e[38;5;88;48;5;88m▄\e[38;5;124;48;5;238m▄\e[38;5;233;48;5;235m▄\e[38;5;240;48;5;242m▄\e[38;5;235;48;5;241m▄\e[38;5;233;48;5;243m▄\e[38;5;232;48;5;59m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;232m▄\e[38;5;11;48;5;160m▄\e[38;5;0;48;5;232m▄\e[38;5;235;48;5;0m▄\e[38;5;0;48;5;25m▄\e[38;5;25;48;5;25m▄\e[38;5;39;48;5;32m▄\e[38;5;0;48;5;25m▄\e[38;5;232;48;5;25m▄\e[38;5;233;48;5;17m▄\e[38;5;234;48;5;0m▄▄\e[38;5;235;48;5;23m▄\e[38;5;0;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;232;48;5;4m▄\e[38;5;17;48;5;18m▄\e[38;5;52;48;5;52m▄\e[38;5;15;48;5;131m▄\e[38;5;8;48;5;179m▄\e[38;5;187;48;5;143m▄\e[38;5;0;48;5;250m▄\e[38;5;0;48;5;247m▄\e[38;5;0;48;5;232m▄\e[38;5;101;48;5;239m▄\e[38;5;223;48;5;221m▄\e[38;5;186;48;5;221m▄\e[38;5;15;48;5;222m▄\e[38;5;247;48;5;101m▄\e[38;5;0;48;5;249m▄\e[38;5;0;48;5;181m▄\e[38;5;239;48;5;229m▄\e[38;5;243;48;5;179m▄\e[38;5;242;48;5;214m▄\e[38;5;239;48;5;94m▄\e[38;5;0;48;5;0m▄▄\e[38;5;166;48;5;0m▄▄\e[38;5;221;48;5;202m▄\e[38;5;228;48;5;202m▄\e[38;5;180;48;5;202m▄\e[38;5;186;48;5;202m▄\e[38;5;208;48;5;202m▄\e[38;5;208;48;5;94m▄\e[38;5;208;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;173;48;5;202m▄\e[38;5;166;48;5;202m▄\e[38;5;227;48;5;202m▄\e[38;5;214;48;5;202m▄\e[38;5;228;48;5;202m▄\e[38;5;52;48;5;214m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;241;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;166;48;5;202m▄\e[38;5;221;48;5;202m▄\e[38;5;215;48;5;202m▄\e[38;5;124;48;5;208m▄\e[38;5;52;48;5;202m▄\e[38;5;180;48;5;208m▄\e[38;5;229;48;5;208m▄▄\e[38;5;222;48;5;208m▄\e[38;5;137;48;5;202m▄\e[38;5;243;48;5;202m▄\e[38;5;242;48;5;202m▄\e[38;5;187;48;5;202m▄\e[38;5;228;48;5;202m▄\e[38;5;166;48;5;202m▄\e[38;5;228;48;5;208m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;229;48;5;214m▄\e[38;5;185;48;5;208m▄\e[38;5;230;48;5;214m▄\e[38;5;15;48;5;221m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;255m▄\e[38;5;0;48;5;179m▄\e[38;5;254;48;5;202m▄\e[38;5;188;48;5;202m▄\e[38;5;228;48;5;202m▄\e[38;5;215;48;5;202m▄\e[38;5;208;48;5;166m▄\e[38;5;166;48;5;52m▄\e[38;5;124;48;5;52m▄\e[38;5;232;48;5;243m▄\e[38;5;241;48;5;59m▄\e[38;5;232;48;5;232m▄\e[38;5;243;48;5;239m▄\e[38;5;0;48;5;232m▄\e[38;5;235;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;220m▄\e[38;5;233;48;5;234m▄\e[38;5;232;48;5;234m▄\e[48;5;0m \e[38;5;18;48;5;25m▄\e[38;5;23;48;5;232m▄\e[38;5;25;48;5;32m▄\e[38;5;32;48;5;25m▄\e[38;5;0;48;5;17m▄\e[38;5;23;48;5;24m▄▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;145;48;5;255m▄\e[38;5;0;48;5;246m▄\e[48;5;0m \e[38;5;247;48;5;246m▄\e[38;5;7;48;5;254m▄\e[38;5;249;48;5;251m▄\e[38;5;15;48;5;15m▄\e[38;5;187;48;5;187m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;8m▄\e[38;5;246;48;5;8m▄\e[38;5;233;48;5;237m▄\e[38;5;208;48;5;0m▄\e[38;5;15;48;5;172m▄\e[38;5;255;48;5;255m▄\e[38;5;188;48;5;254m▄\e[38;5;15;48;5;15m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;8m▄\e[38;5;250;48;5;255m▄\e[38;5;15;48;5;15m▄\e[38;5;15;48;5;179m▄\e[38;5;186;48;5;0m▄\e[48;5;0m \e[38;5;251;48;5;15m▄\e[38;5;15;48;5;15m▄\e[38;5;250;48;5;251m▄\e[38;5;15;48;5;15m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;236;48;5;233m▄\e[38;5;254;48;5;223m▄\e[38;5;215;48;5;0m▄\e[38;5;52;48;5;1m▄\e[38;5;0;48;5;52m▄\e[38;5;236;48;5;0m▄\e[48;5;0m \e[38;5;144;48;5;234m▄\e[38;5;15;48;5;15m▄\e[38;5;246;48;5;15m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;15;48;5;15m▄▄\e[38;5;252;48;5;15m▄\e[38;5;186;48;5;187m▄\e[48;5;0m \e[38;5;0;48;5;8m▄\e[38;5;243;48;5;251m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;15;48;5;15m▄\e[38;5;251;48;5;249m▄\e[38;5;15;48;5;15m▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;240m▄\e[38;5;187;48;5;255m▄\e[48;5;15m \e[38;5;15;48;5;15m▄▄\e[38;5;186;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;237;48;5;232m▄\e[38;5;237;48;5;241m▄\e[38;5;238;48;5;235m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;234m▄\e[38;5;0;48;5;233m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;20;48;5;20m▄\e[38;5;19;48;5;26m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;178m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;245;48;5;0m▄\e[38;5;236;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄▄\e[38;5;249;48;5;247m▄\e[48;5;0m \e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;249;48;5;248m▄\e[38;5;241;48;5;246m▄\e[38;5;242;48;5;242m▄\e[38;5;8;48;5;247m▄\e[38;5;250;48;5;247m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;187;48;5;0m▄\e[38;5;109;48;5;251m▄\e[38;5;248;48;5;255m▄\e[38;5;102;48;5;248m▄\e[38;5;59;48;5;252m▄\e[38;5;254;48;5;251m▄\e[48;5;0m \e[38;5;246;48;5;246m▄\e[38;5;255;48;5;254m▄\e[38;5;255;48;5;255m▄\e[38;5;15;48;5;15m▄\e[48;5;0m \e[38;5;0;48;5;7m▄\e[38;5;236;48;5;238m▄\e[38;5;145;48;5;102m▄\e[38;5;59;48;5;243m▄\e[38;5;223;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;250;48;5;248m▄\e[38;5;254;48;5;255m▄\e[38;5;15;48;5;186m▄\e[38;5;237;48;5;0m▄\e[38;5;1;48;5;52m▄\e[38;5;52;48;5;0m▄\e[48;5;0m \e[38;5;187;48;5;249m▄\e[38;5;15;48;5;15m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;255;48;5;254m▄\e[38;5;255;48;5;247m▄\e[38;5;102;48;5;102m▄\e[38;5;144;48;5;7m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;52;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;60m▄\e[48;5;0m \e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;252;48;5;251m▄\e[38;5;8;48;5;245m▄\e[38;5;250;48;5;240m▄\e[38;5;8;48;5;8m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;255;48;5;144m▄\e[38;5;252;48;5;248m▄\e[38;5;253;48;5;188m▄\e[38;5;248;48;5;246m▄\e[38;5;252;48;5;144m▄\e[38;5;0;48;5;0m▄▄\e[38;5;59;48;5;237m▄\e[38;5;247;48;5;59m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;234;48;5;232m▄\e[38;5;236;48;5;237m▄\e[38;5;0;48;5;0m▄▄\e[38;5;4;48;5;20m▄\e[38;5;17;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;103;48;5;232m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;24;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;19m▄\e[38;5;0;48;5;17m▄▄\e[38;5;17;48;5;17m▄▄\e[38;5;18;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[38;5;4;48;5;17m▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;247;48;5;145m▄\e[38;5;241;48;5;241m▄\e[38;5;242;48;5;236m▄\e[38;5;246;48;5;245m▄\e[38;5;144;48;5;144m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;250;48;5;187m▄\e[38;5;255;48;5;245m▄\e[38;5;246;48;5;7m▄\e[38;5;247;48;5;248m▄\e[38;5;8;48;5;8m▄\e[38;5;250;48;5;7m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;243;48;5;241m▄\e[38;5;243;48;5;246m▄\e[38;5;249;48;5;245m▄\e[38;5;242;48;5;247m▄\e[38;5;102;48;5;101m▄\e[48;5;0m \e[38;5;254;48;5;245m▄\e[38;5;240;48;5;237m▄\e[38;5;233;48;5;8m▄\e[38;5;247;48;5;187m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;1;48;5;52m▄\e[38;5;144;48;5;101m▄\e[38;5;242;48;5;251m▄\e[38;5;252;48;5;252m▄\e[38;5;246;48;5;15m▄\e[38;5;247;48;5;242m▄\e[38;5;0;48;5;0m▄\e[38;5;52;48;5;88m▄\e[38;5;187;48;5;0m▄\e[38;5;7;48;5;245m▄\e[38;5;240;48;5;255m▄\e[48;5;0m \e[38;5;17;48;5;17m▄\e[38;5;0;48;5;0m▄▄\e[38;5;59;48;5;247m▄\e[38;5;242;48;5;145m▄\e[38;5;246;48;5;242m▄\e[38;5;251;48;5;250m▄\e[38;5;232;48;5;0m▄▄\e[38;5;0;48;5;88m▄\e[38;5;0;48;5;52m▄\e[38;5;0;48;5;0m▄\e[38;5;251;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;61;48;5;4m▄\e[48;5;0m \e[38;5;250;48;5;246m▄\e[38;5;245;48;5;242m▄\e[38;5;240;48;5;250m▄\e[38;5;241;48;5;247m▄\e[38;5;233;48;5;233m▄\e[48;5;0m \e[38;5;0;48;5;18m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;238;48;5;0m▄\e[38;5;247;48;5;254m▄\e[38;5;246;48;5;245m▄\e[38;5;240;48;5;247m▄\e[38;5;254;48;5;245m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;237;48;5;233m▄\e[38;5;240;48;5;234m▄\e[38;5;8;48;5;233m▄\e[38;5;238;48;5;232m▄\e[38;5;234;48;5;233m▄\e[38;5;23;48;5;0m▄\e[38;5;237;48;5;234m▄\e[38;5;237;48;5;58m▄\e[38;5;233;48;5;0m▄\e[38;5;235;48;5;232m▄\e[38;5;0;48;5;20m▄\e[38;5;19;48;5;18m▄\e[38;5;232;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;25;48;5;0m▄▄\e[38;5;0;48;5;23m▄\e[38;5;0;48;5;24m▄\e[38;5;17;48;5;234m▄\e[38;5;233;48;5;234m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;225;48;5;249m▄\e[38;5;242;48;5;246m▄\e[38;5;241;48;5;242m▄\e[38;5;242;48;5;241m▄\e[38;5;255;48;5;243m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;19m▄\e[38;5;17;48;5;19m▄\e[38;5;0;48;5;0m▄▄\e[38;5;239;48;5;15m▄\e[38;5;240;48;5;247m▄\e[38;5;8;48;5;251m▄\e[38;5;239;48;5;145m▄\e[38;5;240;48;5;59m▄\e[38;5;102;48;5;248m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;243;48;5;242m▄\e[38;5;243;48;5;240m▄\e[38;5;241;48;5;247m▄\e[38;5;242;48;5;243m▄\e[38;5;238;48;5;102m▄\e[48;5;0m \e[38;5;238;48;5;8m▄\e[38;5;102;48;5;243m▄\e[38;5;145;48;5;241m▄\e[38;5;234;48;5;240m▄\e[38;5;250;48;5;144m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;248;48;5;246m▄\e[38;5;238;48;5;59m▄\e[38;5;236;48;5;246m▄\e[38;5;242;48;5;247m▄\e[38;5;245;48;5;249m▄\e[38;5;102;48;5;8m▄\e[48;5;0m \e[38;5;240;48;5;144m▄\e[38;5;248;48;5;254m▄\e[48;5;0m \e[38;5;0;48;5;19m▄\e[48;5;0m \e[38;5;15;48;5;0m▄\e[38;5;102;48;5;242m▄\e[38;5;243;48;5;253m▄\e[38;5;239;48;5;145m▄\e[38;5;248;48;5;102m▄\e[38;5;8;48;5;248m▄\e[38;5;242;48;5;248m▄\e[38;5;241;48;5;255m▄\e[38;5;237;48;5;253m▄\e[38;5;251;48;5;246m▄\e[48;5;0m \e[38;5;0;48;5;18m▄▄\e[38;5;15;48;5;0m▄\e[38;5;102;48;5;254m▄\e[38;5;236;48;5;239m▄\e[38;5;8;48;5;241m▄\e[38;5;247;48;5;246m▄\e[38;5;233;48;5;232m▄\e[48;5;0m \e[38;5;187;48;5;0m▄\e[38;5;249;48;5;187m▄\e[38;5;240;48;5;245m▄\e[38;5;242;48;5;248m▄\e[38;5;245;48;5;241m▄\e[38;5;0;48;5;251m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;234;48;5;0m▄\e[38;5;235;48;5;236m▄\e[38;5;240;48;5;232m▄\e[38;5;102;48;5;243m▄\e[38;5;237;48;5;232m▄\e[38;5;236;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;234;48;5;237m▄\e[38;5;236;48;5;0m▄\e[38;5;232;48;5;0m▄▄\e[48;5;0m \e[38;5;18;48;5;26m▄\e[38;5;18;48;5;0m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;236m▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;31m▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;23m▄\e[38;5;0;48;5;25m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;236;48;5;23m▄\e[38;5;23;48;5;24m▄\e[38;5;25;48;5;0m▄\e[38;5;25;48;5;24m▄\e[38;5;25;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;23;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;235m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;251;48;5;15m▄\e[38;5;238;48;5;243m▄\e[38;5;240;48;5;241m▄\e[38;5;238;48;5;241m▄\e[38;5;7;48;5;247m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;235;48;5;242m▄\e[38;5;238;48;5;238m▄\e[38;5;60;48;5;60m▄\e[38;5;62;48;5;59m▄\e[38;5;61;48;5;102m▄\e[38;5;7;48;5;145m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;241;48;5;242m▄\e[38;5;60;48;5;8m▄\e[38;5;101;48;5;241m▄\e[38;5;62;48;5;247m▄\e[38;5;60;48;5;103m▄\e[48;5;0m \e[38;5;69;48;5;247m▄\e[38;5;62;48;5;248m▄▄\e[38;5;235;48;5;102m▄\e[38;5;245;48;5;0m▄\e[38;5;248;48;5;235m▄\e[38;5;243;48;5;241m▄\e[38;5;234;48;5;247m▄\e[38;5;81;48;5;245m▄\e[38;5;60;48;5;242m▄\e[38;5;238;48;5;102m▄\e[38;5;242;48;5;8m▄\e[38;5;0;48;5;0m▄\e[38;5;251;48;5;242m▄\e[38;5;103;48;5;252m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;249;48;5;250m▄\e[38;5;238;48;5;249m▄\e[38;5;8;48;5;245m▄\e[38;5;249;48;5;248m▄\e[48;5;0m \e[38;5;0;48;5;236m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;18m▄\e[38;5;0;48;5;17m▄\e[48;5;0m \e[38;5;247;48;5;251m▄\e[38;5;60;48;5;241m▄\e[38;5;238;48;5;243m▄\e[38;5;241;48;5;248m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;188m▄\e[38;5;8;48;5;102m▄\e[38;5;243;48;5;247m▄\e[38;5;61;48;5;246m▄\e[38;5;61;48;5;247m▄\e[38;5;246;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;236;48;5;232m▄\e[38;5;238;48;5;0m▄\e[38;5;233;48;5;235m▄\e[38;5;0;48;5;240m▄\e[38;5;241;48;5;239m▄\e[38;5;239;48;5;234m▄\e[38;5;235;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;235;48;5;0m▄\e[38;5;23;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;237m▄\e[38;5;25;48;5;25m▄\e[38;5;26;48;5;19m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;23;48;5;233m▄\e[38;5;232;48;5;232m▄\e[38;5;235;48;5;234m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;236;48;5;0m▄\e[38;5;233;48;5;233m▄\e[38;5;233;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;23m▄▄\e[38;5;234;48;5;32m▄\e[38;5;60;48;5;67m▄\e[38;5;239;48;5;66m▄\e[38;5;241;48;5;240m▄\e[38;5;235;48;5;234m▄\e[38;5;232;48;5;233m▄\e[38;5;234;48;5;232m▄\e[38;5;236;48;5;234m▄\e[48;5;0m \e[38;5;246;48;5;249m▄\e[38;5;238;48;5;239m▄\e[38;5;234;48;5;240m▄\e[38;5;239;48;5;239m▄\e[38;5;246;48;5;250m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;235m▄\e[38;5;239;48;5;239m▄\e[38;5;61;48;5;102m▄\e[38;5;24;48;5;243m▄\e[38;5;18;48;5;239m▄\e[38;5;24;48;5;145m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;242;48;5;243m▄\e[38;5;61;48;5;242m▄\e[38;5;239;48;5;239m▄\e[38;5;240;48;5;238m▄\e[38;5;67;48;5;8m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;239m▄\e[38;5;245;48;5;7m▄\e[38;5;242;48;5;249m▄\e[38;5;233;48;5;60m▄\e[38;5;239;48;5;255m▄\e[38;5;246;48;5;255m▄\e[38;5;235;48;5;102m▄\e[48;5;0m \e[38;5;0;48;5;233m▄\e[38;5;103;48;5;146m▄\e[38;5;249;48;5;102m▄\e[38;5;245;48;5;59m▄\e[38;5;237;48;5;15m▄\e[38;5;245;48;5;8m▄\e[38;5;0;48;5;240m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;4m▄\e[38;5;19;48;5;0m▄\e[38;5;20;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;102;48;5;7m▄\e[38;5;236;48;5;245m▄\e[38;5;239;48;5;59m▄\e[38;5;245;48;5;145m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;0m▄▄\e[38;5;245;48;5;103m▄\e[38;5;239;48;5;241m▄\e[38;5;60;48;5;240m▄\e[38;5;238;48;5;241m▄\e[38;5;232;48;5;233m▄\e[48;5;0m \e[38;5;0;48;5;251m▄\e[38;5;59;48;5;249m▄\e[38;5;59;48;5;102m▄\e[38;5;238;48;5;240m▄\e[38;5;61;48;5;237m▄\e[38;5;8;48;5;241m▄\e[48;5;0m \e[38;5;235;48;5;0m▄\e[38;5;0;48;5;239m▄\e[38;5;238;48;5;239m▄\e[38;5;234;48;5;232m▄\e[38;5;94;48;5;130m▄\e[38;5;232;48;5;234m▄\e[38;5;238;48;5;238m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;239;48;5;238m▄\e[38;5;232;48;5;11m▄\e[48;5;0m \e[38;5;235;48;5;0m▄\e[38;5;0;48;5;232m▄▄▄\e[38;5;23;48;5;233m▄\e[38;5;233;48;5;234m▄\e[38;5;232;48;5;232m▄\e[38;5;23;48;5;233m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;233m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;238;48;5;0m▄\e[38;5;236;48;5;0m▄\e[38;5;233;48;5;233m▄\e[38;5;0;48;5;0m▄▄\e[38;5;236;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;239;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;233m▄\e[48;5;0m \e[38;5;103;48;5;248m▄\e[38;5;4;48;5;237m▄\e[38;5;25;48;5;239m▄\e[38;5;60;48;5;60m▄\e[38;5;245;48;5;145m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;25;48;5;61m▄\e[38;5;20;48;5;27m▄\e[38;5;25;48;5;26m▄\e[38;5;18;48;5;19m▄\e[38;5;25;48;5;75m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;74;48;5;67m▄\e[38;5;25;48;5;24m▄\e[38;5;26;48;5;24m▄\e[38;5;25;48;5;67m▄\e[38;5;0;48;5;239m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;67;48;5;248m▄\e[38;5;73;48;5;246m▄\e[38;5;24;48;5;66m▄\e[38;5;38;48;5;103m▄\e[38;5;87;48;5;238m▄\e[38;5;0;48;5;238m▄\e[38;5;0;48;5;0m▄▄\e[38;5;44;48;5;80m▄\e[38;5;24;48;5;246m▄\e[38;5;31;48;5;60m▄\e[38;5;25;48;5;60m▄\e[38;5;81;48;5;145m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;18m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;81;48;5;80m▄\e[38;5;25;48;5;67m▄\e[38;5;25;48;5;236m▄\e[38;5;31;48;5;246m▄\e[38;5;0;48;5;0m▄▄\e[38;5;19;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;110;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;26;48;5;69m▄\e[38;5;18;48;5;233m▄\e[38;5;19;48;5;232m▄\e[38;5;18;48;5;24m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;248m▄\e[38;5;17;48;5;237m▄\e[38;5;18;48;5;240m▄▄\e[38;5;17;48;5;236m▄\e[38;5;241;48;5;0m▄\e[38;5;0;48;5;237m▄\e[38;5;238;48;5;238m▄\e[38;5;239;48;5;238m▄\e[38;5;238;48;5;239m▄\e[38;5;52;48;5;52m▄\e[38;5;241;48;5;60m▄\e[38;5;236;48;5;239m▄\e[38;5;17;48;5;237m▄\e[38;5;232;48;5;0m▄\e[38;5;235;48;5;234m▄\e[38;5;235;48;5;23m▄\e[38;5;130;48;5;124m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;24m▄\e[38;5;233;48;5;233m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;233m▄\e[38;5;233;48;5;235m▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;234m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;4m▄▄\e[38;5;0;48;5;26m▄\e[38;5;0;48;5;0m▄▄\e[38;5;234;48;5;232m▄\e[38;5;233;48;5;17m▄\e[38;5;109;48;5;23m▄\e[38;5;236;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;111;48;5;146m▄\e[38;5;19;48;5;25m▄\e[38;5;19;48;5;17m▄\e[38;5;68;48;5;4m▄\e[38;5;123;48;5;116m▄\e[38;5;0;48;5;0m▄▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;23m▄\e[38;5;23;48;5;25m▄\e[38;5;45;48;5;25m▄\e[38;5;25;48;5;32m▄\e[38;5;45;48;5;38m▄\e[38;5;123;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;45;48;5;24m▄\e[38;5;32;48;5;24m▄\e[38;5;45;48;5;32m▄\e[38;5;44;48;5;39m▄\e[38;5;0;48;5;87m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;73m▄\e[38;5;38;48;5;44m▄\e[38;5;39;48;5;31m▄\e[38;5;45;48;5;32m▄\e[38;5;87;48;5;81m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;19;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;87;48;5;32m▄\e[38;5;45;48;5;25m▄\e[38;5;45;48;5;32m▄\e[38;5;81;48;5;81m▄\e[38;5;0;48;5;0m▄▄\e[38;5;4;48;5;18m▄\e[38;5;17;48;5;4m▄\e[38;5;17;48;5;0m▄\e[38;5;81;48;5;75m▄\e[38;5;14;48;5;81m▄\e[38;5;14;48;5;25m▄\e[38;5;45;48;5;25m▄\e[38;5;45;48;5;81m▄\e[38;5;123;48;5;0m▄▄\e[38;5;123;48;5;17m▄\e[38;5;87;48;5;17m▄\e[38;5;81;48;5;0m▄\e[38;5;45;48;5;153m▄\e[38;5;87;48;5;31m▄\e[38;5;0;48;5;0m▄\e[38;5;123;48;5;32m▄\e[38;5;75;48;5;26m▄\e[38;5;19;48;5;25m▄\e[38;5;33;48;5;19m▄\e[38;5;33;48;5;32m▄\e[38;5;80;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;116;48;5;67m▄\e[38;5;19;48;5;19m▄\e[38;5;75;48;5;19m▄\e[38;5;75;48;5;18m▄\e[38;5;19;48;5;75m▄\e[38;5;116;48;5;0m▄\e[38;5;0;48;5;235m▄\e[38;5;232;48;5;236m▄\e[38;5;238;48;5;59m▄\e[38;5;239;48;5;233m▄\e[38;5;66;48;5;242m▄\e[38;5;237;48;5;236m▄\e[38;5;0;48;5;23m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;236;48;5;23m▄\e[38;5;237;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;235;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;233m▄\e[38;5;232;48;5;0m▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;234;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;17m▄\e[38;5;24;48;5;233m▄\e[38;5;234;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;17;48;5;232m▄\e[38;5;23;48;5;0m▄\e[38;5;45;48;5;81m▄\e[38;5;25;48;5;19m▄\e[38;5;32;48;5;26m▄\e[38;5;87;48;5;25m▄\e[38;5;87;48;5;31m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;183;48;5;0m▄\e[38;5;132;48;5;0m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;87m▄\e[38;5;0;48;5;195m▄\e[38;5;0;48;5;123m▄\e[38;5;0;48;5;14m▄▄▄\e[38;5;0;48;5;123m▄▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;17;48;5;18m▄\e[38;5;4;48;5;18m▄\e[38;5;19;48;5;0m▄\e[38;5;87;48;5;38m▄\e[38;5;14;48;5;38m▄\e[38;5;159;48;5;45m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;25;48;5;17m▄\e[38;5;4;48;5;0m▄\e[38;5;25;48;5;74m▄\e[38;5;87;48;5;32m▄\e[38;5;195;48;5;38m▄\e[38;5;0;48;5;0m▄\e[38;5;4;48;5;17m▄\e[38;5;4;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;238;48;5;0m▄\e[38;5;237;48;5;14m▄\e[38;5;236;48;5;45m▄\e[38;5;235;48;5;14m▄\e[38;5;234;48;5;45m▄\e[38;5;234;48;5;33m▄\e[38;5;234;48;5;39m▄\e[38;5;236;48;5;32m▄\e[38;5;235;48;5;31m▄\e[38;5;234;48;5;87m▄\e[38;5;234;48;5;33m▄\e[38;5;235;48;5;81m▄\e[38;5;234;48;5;81m▄\e[38;5;0;48;5;0m▄\e[38;5;81;48;5;123m▄\e[38;5;123;48;5;74m▄\e[38;5;26;48;5;25m▄\e[38;5;26;48;5;19m▄\e[38;5;32;48;5;4m▄\e[38;5;123;48;5;87m▄\e[38;5;236;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;24;48;5;17m▄\e[38;5;24;48;5;0m▄\e[38;5;44;48;5;33m▄\e[38;5;25;48;5;19m▄\e[38;5;19;48;5;19m▄▄\e[38;5;25;48;5;38m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;233;48;5;23m▄\e[38;5;234;48;5;233m▄\e[38;5;66;48;5;238m▄\e[38;5;237;48;5;240m▄\e[38;5;0;48;5;17m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;23m▄\e[38;5;239;48;5;94m▄\e[38;5;184;48;5;130m▄\e[38;5;235;48;5;236m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[38;5;0;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;245;48;5;0m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;17m▄\e[38;5;4;48;5;17m▄\e[38;5;0;48;5;24m▄\e[38;5;234;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;25;48;5;17m▄\e[38;5;189;48;5;25m▄\e[38;5;87;48;5;195m▄\e[38;5;15;48;5;14m▄\e[38;5;159;48;5;14m▄▄\e[38;5;195;48;5;159m▄\e[38;5;159;48;5;195m▄\e[38;5;67;48;5;159m▄\e[38;5;241;48;5;253m▄\e[38;5;59;48;5;0m▄\e[38;5;243;48;5;0m▄\e[38;5;241;48;5;232m▄\e[38;5;239;48;5;4m▄\e[38;5;0;48;5;27m▄▄\e[38;5;0;48;5;32m▄\e[38;5;4;48;5;25m▄\e[38;5;26;48;5;33m▄\e[38;5;26;48;5;17m▄\e[38;5;25;48;5;17m▄\e[38;5;26;48;5;17m▄\e[38;5;32;48;5;234m▄\e[38;5;26;48;5;235m▄\e[38;5;232;48;5;23m▄▄\e[38;5;39;48;5;24m▄\e[38;5;26;48;5;14m▄\e[38;5;232;48;5;87m▄\e[38;5;0;48;5;14m▄\e[38;5;17;48;5;39m▄\e[38;5;45;48;5;45m▄\e[38;5;26;48;5;25m▄\e[38;5;117;48;5;123m▄\e[38;5;195;48;5;255m▄\e[38;5;18;48;5;0m▄\e[38;5;25;48;5;18m▄\e[38;5;87;48;5;26m▄\e[38;5;87;48;5;33m▄\e[38;5;39;48;5;27m▄\e[38;5;32;48;5;18m▄\e[38;5;15;48;5;195m▄\e[38;5;87;48;5;15m▄\e[38;5;39;48;5;17m▄\e[38;5;45;48;5;24m▄\e[38;5;0;48;5;81m▄\e[38;5;232;48;5;87m▄\e[38;5;24;48;5;45m▄\e[38;5;45;48;5;25m▄\e[38;5;38;48;5;24m▄\e[38;5;0;48;5;32m▄\e[38;5;26;48;5;17m▄\e[38;5;33;48;5;0m▄▄\e[38;5;39;48;5;232m▄\e[38;5;26;48;5;18m▄\e[38;5;19;48;5;25m▄\e[38;5;0;48;5;4m▄▄\e[38;5;38;48;5;18m▄\e[38;5;81;48;5;4m▄\e[38;5;31;48;5;74m▄\e[38;5;67;48;5;14m▄\e[38;5;195;48;5;15m▄\e[38;5;31;48;5;14m▄\e[38;5;32;48;5;159m▄\e[38;5;74;48;5;15m▄\e[38;5;195;48;5;159m▄\e[38;5;159;48;5;87m▄\e[38;5;159;48;5;23m▄\e[38;5;0;48;5;24m▄\e[38;5;24;48;5;24m▄\e[38;5;24;48;5;0m▄\e[38;5;45;48;5;39m▄\e[38;5;14;48;5;14m▄\e[38;5;14;48;5;45m▄\e[38;5;45;48;5;14m▄\e[38;5;14;48;5;195m▄\e[38;5;110;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;60m▄\e[38;5;24;48;5;60m▄\e[38;5;236;48;5;241m▄\e[38;5;234;48;5;237m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;237m▄\e[38;5;23;48;5;233m▄\e[38;5;23;48;5;239m▄\e[38;5;238;48;5;208m▄\e[38;5;234;48;5;238m▄\e[38;5;236;48;5;233m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[m
+\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;24;48;5;232m▄\e[38;5;87;48;5;17m▄\e[38;5;123;48;5;45m▄\e[38;5;32;48;5;87m▄\e[38;5;25;48;5;195m▄\e[38;5;14;48;5;87m▄\e[38;5;4;48;5;81m▄\e[38;5;18;48;5;4m▄\e[38;5;17;48;5;17m▄\e[38;5;17;48;5;4m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄\e[38;5;0;48;5;25m▄\e[38;5;0;48;5;17m▄\e[38;5;33;48;5;0m▄\e[38;5;4;48;5;32m▄\e[38;5;0;48;5;26m▄\e[38;5;18;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;24m▄\e[38;5;0;48;5;24m▄\e[38;5;33;48;5;255m▄\e[38;5;25;48;5;25m▄\e[38;5;25;48;5;81m▄\e[38;5;25;48;5;123m▄\e[38;5;45;48;5;123m▄\e[38;5;26;48;5;81m▄\e[38;5;26;48;5;26m▄\e[38;5;18;48;5;25m▄\e[38;5;17;48;5;38m▄\e[38;5;39;48;5;0m▄\e[38;5;32;48;5;0m▄\e[38;5;0;48;5;25m▄\e[38;5;0;48;5;38m▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;23m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;233m▄\e[38;5;4;48;5;17m▄\e[38;5;26;48;5;45m▄\e[38;5;17;48;5;17m▄\e[38;5;18;48;5;18m▄\e[38;5;25;48;5;17m▄\e[38;5;38;48;5;38m▄\e[38;5;18;48;5;4m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;117;48;5;45m▄\e[38;5;15;48;5;123m▄\e[38;5;195;48;5;14m▄\e[38;5;15;48;5;14m▄\e[38;5;15;48;5;87m▄\e[38;5;87;48;5;87m▄\e[38;5;14;48;5;17m▄\e[38;5;18;48;5;17m▄\e[38;5;19;48;5;17m▄\e[38;5;4;48;5;24m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;17m▄▄\e[38;5;0;48;5;237m▄\e[38;5;232;48;5;233m▄▄\e[38;5;234;48;5;235m▄\e[38;5;233;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[m
+\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;235;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;45m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;4;48;5;0m▄\e[38;5;17;48;5;24m▄\e[38;5;20;48;5;25m▄\e[38;5;4;48;5;18m▄\e[38;5;45;48;5;45m▄\e[38;5;19;48;5;4m▄\e[38;5;19;48;5;19m▄\e[38;5;4;48;5;19m▄\e[38;5;18;48;5;18m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;19m▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;0m▄▄\e[38;5;235;48;5;0m▄\e[38;5;233;48;5;236m▄\e[38;5;236;48;5;66m▄\e[38;5;240;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;24;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;27m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;27m▄\e[38;5;27;48;5;17m▄\e[38;5;0;48;5;18m▄\e[38;5;26;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;18;48;5;19m▄\e[38;5;20;48;5;12m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;0m▄\e[38;5;0;48;5;33m▄\e[38;5;0;48;5;0m▄\e[38;5;18;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;19;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;234;48;5;17m▄\e[38;5;4;48;5;4m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;17m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;17m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;4m▄\e[38;5;17;48;5;17m▄▄\e[38;5;4;48;5;26m▄\e[38;5;17;48;5;4m▄\e[38;5;232;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;39;48;5;39m▄\e[38;5;4;48;5;18m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;17m▄\e[38;5;234;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;81;48;5;195m▄\e[38;5;26;48;5;26m▄\e[38;5;19;48;5;26m▄\e[38;5;24;48;5;19m▄\e[38;5;25;48;5;18m▄\e[38;5;4;48;5;14m▄\e[38;5;18;48;5;159m▄\e[38;5;159;48;5;45m▄\e[38;5;87;48;5;17m▄\e[38;5;4;48;5;0m▄\e[38;5;17;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;234;48;5;236m▄\e[38;5;0;48;5;23m▄\e[38;5;238;48;5;0m▄\e[38;5;0;48;5;23m▄\e[38;5;232;48;5;237m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[m
+\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄▄\e[38;5;239;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;234;48;5;0m▄\e[38;5;232;48;5;17m▄\e[38;5;17;48;5;25m▄\e[38;5;17;48;5;19m▄\e[38;5;0;48;5;4m▄\e[38;5;232;48;5;18m▄\e[38;5;27;48;5;39m▄\e[38;5;20;48;5;19m▄\e[38;5;19;48;5;25m▄\e[38;5;25;48;5;18m▄\e[38;5;26;48;5;25m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;239m▄\e[38;5;0;48;5;238m▄\e[38;5;0;48;5;234m▄▄\e[38;5;237;48;5;234m▄\e[38;5;235;48;5;0m▄\e[38;5;232;48;5;236m▄\e[38;5;243;48;5;102m▄\e[38;5;8;48;5;66m▄\e[38;5;66;48;5;241m▄\e[38;5;103;48;5;233m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;233;48;5;238m▄\e[38;5;23;48;5;0m▄\e[38;5;24;48;5;17m▄\e[38;5;17;48;5;0m▄▄▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;26m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;26m▄\e[38;5;232;48;5;24m▄\e[38;5;31;48;5;17m▄\e[38;5;18;48;5;20m▄\e[38;5;17;48;5;17m▄\e[38;5;232;48;5;26m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;23;48;5;232m▄\e[38;5;23;48;5;24m▄\e[38;5;234;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;235;48;5;234m▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;238;48;5;0m▄\e[38;5;24;48;5;23m▄\e[38;5;17;48;5;4m▄\e[38;5;24;48;5;24m▄▄\e[38;5;110;48;5;4m▄\e[38;5;24;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;32;48;5;32m▄\e[38;5;0;48;5;24m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;235;48;5;0m▄\e[38;5;17;48;5;4m▄\e[38;5;17;48;5;17m▄\e[38;5;19;48;5;27m▄\e[38;5;25;48;5;232m▄\e[38;5;18;48;5;18m▄\e[38;5;17;48;5;18m▄\e[38;5;0;48;5;24m▄\e[38;5;17;48;5;4m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;17m▄\e[38;5;4;48;5;4m▄\e[38;5;17;48;5;68m▄\e[38;5;24;48;5;14m▄\e[38;5;17;48;5;37m▄\e[38;5;0;48;5;0m▄\e[38;5;14;48;5;0m▄\e[38;5;0;48;5;23m▄\e[38;5;236;48;5;236m▄\e[38;5;0;48;5;236m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;17m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;25;48;5;27m▄\e[38;5;234;48;5;18m▄\e[38;5;232;48;5;17m▄\e[38;5;24;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;233m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;232m▄▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;234m▄\e[38;5;232;48;5;23m▄\e[38;5;235;48;5;66m▄\e[38;5;0;48;5;236m▄▄\e[38;5;0;48;5;60m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;23m▄\e[48;5;0m \e[38;5;233;48;5;232m▄\e[38;5;0;48;5;237m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;208;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;17;48;5;19m▄\e[38;5;0;48;5;23m▄\e[38;5;0;48;5;0m▄\e[38;5;33;48;5;27m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;233;48;5;232m▄\e[38;5;233;48;5;17m▄\e[38;5;241;48;5;60m▄\e[38;5;8;48;5;25m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;24m▄\e[38;5;232;48;5;66m▄\e[38;5;17;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;98m▄\e[38;5;0;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;234;48;5;236m▄\e[38;5;243;48;5;248m▄\e[38;5;243;48;5;245m▄\e[38;5;242;48;5;0m▄\e[38;5;233;48;5;4m▄\e[38;5;241;48;5;25m▄\e[38;5;23;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;234;48;5;24m▄\e[38;5;25;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;4;48;5;236m▄\e[38;5;232;48;5;234m▄\e[38;5;15;48;5;19m▄\e[38;5;17;48;5;25m▄\e[38;5;0;48;5;236m▄\e[38;5;24;48;5;0m▄\e[38;5;17;48;5;4m▄▄\e[38;5;0;48;5;17m▄\e[38;5;23;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;23;48;5;17m▄\e[38;5;233;48;5;23m▄\e[38;5;0;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;235m▄\e[38;5;233;48;5;234m▄\e[48;5;0m \e[38;5;234;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;234m▄\e[38;5;232;48;5;237m▄\e[38;5;233;48;5;232m▄\e[38;5;4;48;5;235m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;101;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;233;48;5;0m▄\e[38;5;233;48;5;234m▄\e[38;5;232;48;5;234m▄\e[38;5;239;48;5;239m▄\e[38;5;236;48;5;237m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[38;5;0;48;5;18m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;234m▄\e[38;5;232;48;5;233m▄\e[38;5;0;48;5;17m▄\e[38;5;102;48;5;245m▄\e[38;5;245;48;5;243m▄\e[38;5;60;48;5;0m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;236;48;5;232m▄\e[38;5;236;48;5;233m▄\e[38;5;235;48;5;233m▄\e[38;5;238;48;5;236m▄\e[38;5;232;48;5;60m▄\e[38;5;242;48;5;245m▄\e[38;5;236;48;5;236m▄\e[38;5;233;48;5;17m▄\e[38;5;0;48;5;17m▄\e[38;5;233;48;5;0m▄\e[38;5;0;48;5;220m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;239;48;5;24m▄\e[38;5;238;48;5;234m▄\e[38;5;0;48;5;17m▄\e[38;5;110;48;5;73m▄\e[38;5;60;48;5;23m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;233m▄\e[38;5;235;48;5;233m▄\e[38;5;235;48;5;0m▄\e[38;5;234;48;5;17m▄\e[38;5;237;48;5;233m▄\e[38;5;233;48;5;17m▄\e[38;5;23;48;5;17m▄\e[38;5;235;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;235;48;5;232m▄\e[38;5;52;48;5;232m▄\e[48;5;0m \e[38;5;232;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;23m▄\e[38;5;233;48;5;17m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;239;48;5;236m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;233;48;5;234m▄\e[38;5;232;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;233m▄\e[38;5;241;48;5;235m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;237;48;5;60m▄\e[38;5;235;48;5;232m▄\e[48;5;0m \e[38;5;234;48;5;0m▄\e[38;5;232;48;5;234m▄\e[38;5;233;48;5;234m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;240m▄\e[38;5;59;48;5;239m▄▄\e[38;5;66;48;5;0m▄\e[38;5;23;48;5;0m▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;233;48;5;17m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;234;48;5;0m▄▄\e[38;5;232;48;5;233m▄\e[38;5;235;48;5;236m▄\e[38;5;0;48;5;233m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;241;48;5;236m▄\e[38;5;235;48;5;232m▄\e[38;5;236;48;5;236m▄\e[38;5;0;48;5;238m▄\e[38;5;0;48;5;242m▄\e[38;5;24;48;5;243m▄\e[38;5;23;48;5;23m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;17m▄\e[38;5;234;48;5;233m▄\e[38;5;233;48;5;233m▄\e[38;5;0;48;5;241m▄\e[38;5;234;48;5;235m▄\e[38;5;23;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;233;48;5;232m▄\e[38;5;233;48;5;235m▄\e[38;5;233;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;66;48;5;240m▄\e[38;5;239;48;5;59m▄\e[38;5;232;48;5;234m▄\e[38;5;0;48;5;0m▄\e[38;5;59;48;5;240m▄\e[38;5;60;48;5;24m▄▄\e[38;5;232;48;5;0m▄\e[38;5;235;48;5;232m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;236;48;5;0m▄\e[38;5;236;48;5;236m▄\e[38;5;233;48;5;233m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;214m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;233;48;5;0m▄\e[38;5;24;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;236m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[38;5;232;48;5;236m▄\e[38;5;237;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;66m▄\e[38;5;232;48;5;237m▄\e[38;5;234;48;5;237m▄\e[38;5;233;48;5;60m▄\e[38;5;0;48;5;238m▄\e[38;5;234;48;5;233m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;234;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;23m▄\e[38;5;0;48;5;232m▄\e[38;5;232;48;5;234m▄\e[38;5;0;48;5;238m▄\e[38;5;0;48;5;234m▄\e[38;5;0;48;5;8m▄\e[38;5;0;48;5;239m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;233m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;233m▄\e[38;5;232;48;5;0m▄\e[38;5;23;48;5;0m▄\e[38;5;24;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;233;48;5;0m▄\e[38;5;237;48;5;240m▄\e[38;5;239;48;5;233m▄\e[38;5;59;48;5;246m▄\e[38;5;239;48;5;66m▄\e[38;5;60;48;5;0m▄\e[38;5;240;48;5;240m▄\e[38;5;235;48;5;60m▄\e[38;5;236;48;5;233m▄\e[38;5;234;48;5;237m▄\e[38;5;236;48;5;236m▄\e[38;5;236;48;5;166m▄\e[38;5;233;48;5;233m▄\e[38;5;232;48;5;235m▄\e[38;5;237;48;5;236m▄\e[38;5;236;48;5;234m▄\e[38;5;235;48;5;0m▄\e[38;5;0;48;5;232m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;235m▄▄\e[38;5;0;48;5;0m▄\e[38;5;234;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;233;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;232;48;5;232m▄\e[38;5;239;48;5;235m▄\e[38;5;232;48;5;233m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;238m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄▄▄▄\e[38;5;235;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;24;48;5;232m▄\e[38;5;4;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[38;5;235;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[38;5;232;48;5;232m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[38;5;25;48;5;233m▄\e[38;5;233;48;5;0m▄\e[38;5;234;48;5;232m▄\e[38;5;235;48;5;233m▄\e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;237;48;5;233m▄\e[38;5;241;48;5;238m▄\e[38;5;240;48;5;240m▄\e[38;5;239;48;5;0m▄\e[38;5;60;48;5;0m▄\e[38;5;238;48;5;238m▄\e[38;5;0;48;5;239m▄\e[38;5;23;48;5;240m▄\e[38;5;235;48;5;236m▄\e[38;5;237;48;5;234m▄\e[38;5;234;48;5;233m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;236m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;233;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[48;5;0m \e[m
+\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;238;48;5;0m▄\e[38;5;239;48;5;237m▄\e[38;5;0;48;5;240m▄\e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;17;48;5;0m▄\e[38;5;18;48;5;0m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;0;48;5;24m▄\e[38;5;0;48;5;25m▄\e[38;5;0;48;5;0m▄▄\e[38;5;232;48;5;0m▄\e[38;5;24;48;5;189m▄\e[38;5;232;48;5;232m▄\e[38;5;0;48;5;0m▄▄▄▄\e[38;5;17;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[38;5;232;48;5;0m▄▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;236m▄\e[38;5;0;48;5;232m▄\e[38;5;24;48;5;23m▄\e[38;5;4;48;5;0m▄\e[38;5;25;48;5;0m▄\e[38;5;0;48;5;23m▄\e[38;5;232;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;232;48;5;0m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;0;48;5;17m▄\e[38;5;0;48;5;24m▄\e[38;5;0;48;5;23m▄\e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[38;5;234;48;5;238m▄\e[38;5;236;48;5;233m▄\e[38;5;232;48;5;233m▄\e[38;5;0;48;5;60m▄\e[38;5;23;48;5;0m▄\e[38;5;233;48;5;232m▄\e[38;5;0;48;5;233m▄\e[38;5;239;48;5;23m▄\e[38;5;235;48;5;60m▄\e[38;5;232;48;5;24m▄\e[48;5;0m \e[38;5;232;48;5;233m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;240;48;5;0m▄\e[38;5;59;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄▄▄▄▄\e[48;5;0m \e[38;5;0;48;5;234m▄\e[38;5;232;48;5;234m▄\e[38;5;0;48;5;0m▄▄▄\e[38;5;232;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄\e[38;5;0;48;5;232m▄\e[38;5;0;48;5;0m▄▄\e[38;5;0;48;5;235m▄\e[38;5;0;48;5;239m▄\e[38;5;0;48;5;240m▄\e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄\e[48;5;0m \e[38;5;0;48;5;234m▄\e[48;5;0m \e[38;5;0;48;5;0m▄▄▄▄\e[48;5;0m \e[m
+\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m \e[38;5;0;48;5;0m▄\e[48;5;0m `;
+
+const LIGHTHOUSE_HEADER = `
+ .
+ /|\\
+ / | \\
+ / | \\
+ / | \\
+ / | \\
+ / .--+--. \\
+ /__/ | \\__\\
+ [__] | [__]
+ |
+ ~~~~~~~~~|~~~~~~~~~
+`;
+
+const GLITCH_ART = `
+ ▓▓▓▒▒░░ E̸̢R̷̨R̵̢O̸̧R̷̨ ░░▒▒▓▓▓
+ ░▒▓█ D̶̨A̷̧T̸̢Ą̵ C̷̢Ǫ̸Ŗ̵R̷̨U̸̢P̵̧T̷̨ █▓▒░
+ ▓░▒█ ???????????????? █▒░▓
+`;
+
+const END_SCREEN = `
+ ╔════════════════════════════════════════╗
+ ║ ║
+ ║ CONNECTION TERMINATED ║
+ ║ ║
+ ║ Five days remain... ║
+ ║ ║
+ ╚════════════════════════════════════════╝
+`;
+
+const boxingDayGame = {
+ id: "boxing-day",
+ name: "Boxing Day",
+ command: "dial",
+ description: "Connect to Dark Tower BBS - December 26, 1999",
+
+ initialState: {
+ // Core progression flags
+ downloaded_cascade: false,
+ talked_to_sysop: false,
+ deleted_corrupted_file: false,
+ route_taken: null, // "immediate" | "cautious" | "ignored"
+
+ // Progression tracking
+ read_new_message: false,
+ found_number: false,
+ dialed_lighthouse: false,
+
+ // rm -rf deletion flags (persist across sessions)
+ archives_deleted: false,
+ corrupted_file_deleted: false,
+
+ // Scene visit tracking
+ visited: {},
+ },
+
+ intro: [
+ { type: "ascii", art: BOXING_DAY_TITLE, className: "game-ascii" },
+ "",
+ { text: "December 26, 1999", className: "info" },
+ { text: "11:47 PM", className: "info" },
+ "",
+ { type: "delay", ms: 600 },
+ "Five days until the millennium.",
+ { type: "delay", ms: 400 },
+ "Five days until everything might change.",
+ "",
+ { type: "delay", ms: 600 },
+ "Your 56k modem hums quietly in the dark.",
+ "The house is silent. Everyone else is asleep.",
+ "",
+ { type: "delay", ms: 400 },
+ { text: 'Type "quit" at any time to save and exit.', className: "info" },
+ ],
+
+ startScene: "connect_prompt",
+
+ scenes: {
+ // ==========================================
+ // OPENING SEQUENCE
+ // ==========================================
+
+ connect_prompt: {
+ content: [
+ "Your terminal awaits a command.",
+ "",
+ { text: "The familiar glow illuminates your face.", className: "info" },
+ ],
+ options: [{ text: "Connect to Dark Tower BBS", next: "modem_connect" }],
+ },
+
+ modem_connect: {
+ clear: true,
+ content: [
+ { type: "typewriter", text: "ATDT 555-0199", speed: 80 },
+ { type: "delay", ms: 800 },
+ "",
+ { text: "DIALING...", className: "info" },
+ { type: "delay", ms: 600 },
+ "",
+ { text: "RING", className: "warning" },
+ { type: "delay", ms: 800 },
+ { text: "RING", className: "warning" },
+ { type: "delay", ms: 600 },
+ "",
+ {
+ type: "typewriter",
+ text: "~~ eEe ~~ EEE ~~ eee ~~ CONNECT 56000",
+ speed: 35,
+ },
+ { type: "delay", ms: 400 },
+ "",
+ { text: "Carrier detected.", className: "success" },
+ { type: "delay", ms: 300 },
+ { text: "Negotiating protocol...", className: "info" },
+ { type: "delay", ms: 500 },
+ { text: "Connection established.", className: "success" },
+ ],
+ next: "dark_tower_main",
+ delay: 800,
+ },
+
+ // ==========================================
+ // DARK TOWER BBS HUB
+ // ==========================================
+
+ dark_tower_main: {
+ clear: true,
+ content: [
+ { type: "ansi", art: DARK_TOWER_HEADER, className: "game-ansi-art" },
+ "",
+ { text: "SysOp: NightWatchman", className: "info" },
+ { text: "Users Online: 3", className: "info" },
+ { text: "Local Time: 11:52 PM", className: "info" },
+ "",
+ // New message notification (only if not read)
+ {
+ condition: { not: "read_new_message" },
+ content: [
+ {
+ text: "*** YOU HAVE 1 NEW PRIVATE MESSAGE ***",
+ className: "warning",
+ },
+ "",
+ ],
+ },
+ // Return visitor message
+ {
+ condition: "visited.dark_tower_main",
+ content: { text: "[Returning to main menu]", className: "info" },
+ },
+ ],
+ onEnter: [{ set: "visited.dark_tower_main", value: true }],
+ prompt: "Select:",
+ options: [
+ {
+ text: "Read Private Messages",
+ next: "read_messages",
+ condition: { not: "read_new_message" },
+ },
+ {
+ text: "Message Archive",
+ next: "message_archive",
+ condition: "read_new_message",
+ },
+ { text: "Browse Message Boards", next: "browse_boards" },
+ { text: "File Library", next: "dark_tower_files" },
+ { text: "Who's Online", next: "whos_online" },
+ {
+ text: "Dial The Lighthouse (555-0237)",
+ next: "confirm_dial_lighthouse",
+ condition: "found_number",
+ },
+ { text: "Disconnect", next: "leave_early" },
+ ],
+ },
+
+ // ==========================================
+ // MESSAGE DISCOVERY
+ // ==========================================
+
+ read_messages: {
+ title: "Private Messages",
+ content: [
+ "═══ INBOX ═══",
+ "",
+ { text: "1 unread message", className: "warning" },
+ "",
+ " FROM: [SENDER UNKNOWN]",
+ " DATE: 12/25/1999 11:59:59 PM",
+ " SUBJ: For your eyes only",
+ "",
+ ],
+ options: [
+ { text: "Open message", next: "new_message" },
+ { text: "Back to main menu", next: "dark_tower_main" },
+ ],
+ },
+
+ new_message: {
+ title: "Reading Message...",
+ content: [
+ { type: "delay", ms: 300 },
+ "─── BEGIN MESSAGE ───",
+ "",
+ {
+ type: "typewriter",
+ text: "I know you've been searching.",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ "",
+ {
+ type: "typewriter",
+ text: "The lighthouse keeper left something behind.",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ "",
+ {
+ type: "typewriter",
+ text: "Dial 555-0237 before midnight strikes.",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ "",
+ { type: "typewriter", text: "The cascade is coming.", speed: 70 },
+ { type: "delay", ms: 800 },
+ "",
+ "─── END MESSAGE ───",
+ "",
+ {
+ text: "The number burns in your mind: 555-0237",
+ className: "warning",
+ },
+ "",
+ { type: "delay", ms: 400 },
+ "Your clock reads 11:54 PM.",
+ "Six minutes until midnight.",
+ ],
+ onEnter: [
+ { set: "read_new_message", value: true },
+ { set: "found_number", value: true },
+ ],
+ prompt: "What do you do?",
+ options: [
+ {
+ text: "Dial the number NOW",
+ next: "choice_immediate",
+ actions: [{ set: "route_taken", value: "immediate" }],
+ },
+ {
+ text: "Explore Dark Tower first",
+ next: "dark_tower_main",
+ actions: [{ set: "route_taken", value: "cautious" }],
+ },
+ {
+ text: "Delete the message and forget it",
+ next: "choice_ignored",
+ actions: [{ set: "route_taken", value: "ignored" }],
+ },
+ ],
+ },
+
+ message_archive: {
+ title: "Message Archive",
+ content: [
+ "═══ ARCHIVED MESSAGES ═══",
+ "",
+ {
+ condition: "read_new_message",
+ content: [
+ " 1. [SENDER UNKNOWN] - For your eyes only",
+ { text: " (The number: 555-0237)", className: "info" },
+ ],
+ },
+ "",
+ { text: "No other messages.", className: "info" },
+ ],
+ options: [{ text: "Back", next: "dark_tower_main" }],
+ },
+
+ // ==========================================
+ // CHOICE A/B/C - WHEN TO DIAL
+ // ==========================================
+
+ choice_immediate: {
+ clear: true,
+ content: [
+ "Your fingers move before doubt can settle.",
+ "",
+ { type: "typewriter", text: "ATH0", speed: 100 },
+ { type: "delay", ms: 400 },
+ { text: "NO CARRIER", className: "warning" },
+ { type: "delay", ms: 600 },
+ "",
+ "You disconnect from Dark Tower.",
+ "The silence of your room feels heavier now.",
+ "",
+ { type: "delay", ms: 500 },
+ { text: "Something compels you forward.", className: "info" },
+ ],
+ next: "dial_lighthouse",
+ delay: 1000,
+ },
+
+ choice_ignored: {
+ clear: true,
+ content: [
+ "You highlight the message.",
+ "",
+ { type: "typewriter", text: "DELETE MESSAGE? [Y/N]", speed: 50 },
+ { type: "delay", ms: 600 },
+ { type: "typewriter", text: "Y", speed: 100 },
+ { type: "delay", ms: 400 },
+ "",
+ { text: "MESSAGE DELETED", className: "success" },
+ "",
+ { type: "delay", ms: 1000 },
+ "The number fades from memory.",
+ "Just another piece of BBS spam, you tell yourself.",
+ "",
+ { type: "delay", ms: 800 },
+ "You browse Dark Tower for another hour.",
+ "Download some wallpapers. Chat about nothing.",
+ "",
+ { type: "delay", ms: 800 },
+ "At 11:47 PM, you disconnect.",
+ "",
+ { type: "delay", ms: 800 },
+ "Five days later, the millennium arrives.",
+ "Fireworks. Champagne. Relief.",
+ "",
+ { type: "delay", ms: 600 },
+ "Nothing happens.",
+ "",
+ { type: "delay", ms: 1000 },
+ { text: "Or does it?", className: "warning" },
+ "",
+ { type: "delay", ms: 800 },
+ "You never find out what cascade.exe would have done.",
+ "The lighthouse keeper's message was never meant for you.",
+ "",
+ { type: "delay", ms: 600 },
+ { text: "Perhaps that's for the best.", className: "info" },
+ "",
+ { type: "delay", ms: 1000 },
+ { text: "[END - Route C: The Road Not Taken]", className: "warning" },
+ ],
+ options: [{ text: "Return to terminal", next: "game_end_ignored" }],
+ },
+
+ game_end_ignored: {
+ clear: true,
+ content: [
+ { type: "ascii", art: END_SCREEN, className: "game-ascii" },
+ "",
+ { text: "BOXING DAY", className: "game-title" },
+ { text: "Day 1 Complete - Route C", className: "info" },
+ "",
+ "You chose not to follow the signal.",
+ "Some doors are better left closed.",
+ "",
+ {
+ text: 'Type "dial" to play again, or "dial reset" to start fresh.',
+ className: "info",
+ },
+ ],
+ },
+
+ // ==========================================
+ // DARK TOWER EXPLORATION
+ // ==========================================
+
+ browse_boards: {
+ title: "Message Boards",
+ content: [
+ "═══ DARK TOWER MESSAGE BOARDS ═══",
+ "",
+ " [1] General Discussion (47 new)",
+ " [2] Tech Support (12 new)",
+ // Archives conditionally shown
+ {
+ condition: { not: "archives_deleted" },
+ content: " [3] The Archives (3 new)",
+ },
+ {
+ condition: "archives_deleted",
+ content: { text: " [3] ", className: "error" },
+ },
+ " [4] File Announcements (8 new)",
+ "",
+ ],
+ prompt: "Select board:",
+ options: [
+ { text: "General Discussion", next: "board_general" },
+ { text: "Tech Support", next: "board_tech" },
+ {
+ text: "The Archives",
+ next: "board_archives",
+ condition: { not: "archives_deleted" },
+ },
+ { text: "File Announcements", next: "board_files" },
+ { text: "Back to main menu", next: "dark_tower_main" },
+ ],
+ },
+
+ board_general: {
+ title: "General Discussion",
+ content: [
+ "═══ GENERAL DISCUSSION ═══",
+ "",
+ " [HOT] Y2K Preparation Thread - 234 replies",
+ " [NEW] Anyone else getting weird messages? - 12 replies",
+ " [NEW] Happy Boxing Day everyone! - 8 replies",
+ " Best BBS games? - 45 replies",
+ " New user intro thread - 67 replies",
+ "",
+ {
+ text: "The usual chatter. Nothing about lighthouses.",
+ className: "info",
+ },
+ ],
+ options: [
+ { text: "Read 'weird messages' thread", next: "thread_weird" },
+ { text: "Back to boards", next: "browse_boards" },
+ ],
+ },
+
+ thread_weird: {
+ title: "Thread: Anyone else getting weird messages?",
+ content: [
+ "═══ Anyone else getting weird messages? ═══",
+ "",
+ { text: "Posted by: Static_User", className: "info" },
+ "Got a strange PM last night. No sender listed.",
+ "Just a phone number and something about a 'cascade'.",
+ "Probably spam, but creepy timing with Y2K coming up.",
+ "",
+ "---",
+ { text: "Reply from: NightWatchman [SYSOP]", className: "warning" },
+ "Looking into it. Please forward any suspicious messages.",
+ "And don't dial any numbers you don't recognize.",
+ "",
+ "---",
+ { text: "Reply from: [DELETED USER]", className: "error" },
+ "[This post has been removed]",
+ "",
+ { type: "delay", ms: 300 },
+ {
+ condition: "found_number",
+ content: {
+ text: "You notice your message was similar...",
+ className: "warning",
+ },
+ },
+ ],
+ options: [{ text: "Back", next: "board_general" }],
+ },
+
+ board_tech: {
+ title: "Tech Support",
+ content: [
+ "═══ TECH SUPPORT ═══",
+ "",
+ " [STICKY] READ FIRST: Y2K Compliance Guide",
+ " [NEW] Modem dropping connection at midnight?",
+ " Best virus scanner for 1999?",
+ " How to increase download speeds",
+ "",
+ {
+ text: "Standard tech questions. Nothing unusual.",
+ className: "info",
+ },
+ ],
+ options: [{ text: "Back to boards", next: "browse_boards" }],
+ },
+
+ board_archives: {
+ title: "The Archives",
+ content: [
+ "═══ THE ARCHIVES ═══",
+ { text: "Historical posts - Read only", className: "info" },
+ "",
+ " [1998] The Lighthouse Project - NightWatchman",
+ " [1999] Frequencies and Patterns - Signal_Lost",
+ " [1999] RE: Has anyone heard from Keeper? - Anonymous",
+ "",
+ {
+ condition: { not: "visited.archive_warning" },
+ content: [
+ "",
+ { text: "These posts feel... different.", className: "warning" },
+ { text: "Like echoes from somewhere else.", className: "info" },
+ ],
+ },
+ ],
+ onEnter: [{ set: "visited.archive_warning", value: true }],
+ options: [
+ { text: "Read 'The Lighthouse Project'", next: "archive_lighthouse" },
+ {
+ text: "Read 'Frequencies and Patterns'",
+ next: "archive_frequencies",
+ },
+ {
+ text: "Read 'Has anyone heard from Keeper?'",
+ next: "archive_keeper",
+ },
+ { text: "Back to boards", next: "browse_boards" },
+ ],
+ },
+
+ archive_lighthouse: {
+ title: "The Lighthouse Project",
+ content: [
+ "═══ The Lighthouse Project ═══",
+ {
+ text: "Posted by: NightWatchman - November 15, 1998",
+ className: "info",
+ },
+ "",
+ "Some of you have asked about the secondary BBS.",
+ "Yes, it exists. No, I can't give you the number.",
+ "",
+ "The Lighthouse was set up by someone who called himself 'Keeper'.",
+ "He said he found something in the noise between stations.",
+ "Patterns that shouldn't exist.",
+ "",
+ "I hosted his board as a favor.",
+ "Then one day, he stopped logging in.",
+ "",
+ "The board is still there. Still running.",
+ "I check it sometimes. The files he left behind...",
+ "",
+ "Some doors are better left closed.",
+ "",
+ { text: "- NW", className: "info" },
+ ],
+ options: [{ text: "Back", next: "board_archives" }],
+ },
+
+ archive_frequencies: {
+ title: "Frequencies and Patterns",
+ content: [
+ "═══ Frequencies and Patterns ═══",
+ { text: "Posted by: Signal_Lost - March 22, 1999", className: "info" },
+ "",
+ "I've been analyzing radio static for three months.",
+ "There's something there. In the spaces between signals.",
+ "",
+ "It's not random. It's STRUCTURED.",
+ "Like code. Like a message.",
+ "",
+ "Keeper knew. That's why he built cascade.exe.",
+ "To translate. To REVEAL.",
+ "",
+ "I'm close to understanding.",
+ "So close.",
+ "",
+ {
+ text: "[User Signal_Lost has not logged in since March 23, 1999]",
+ className: "warning",
+ },
+ ],
+ options: [{ text: "Back", next: "board_archives" }],
+ },
+
+ archive_keeper: {
+ title: "RE: Has anyone heard from Keeper?",
+ content: [
+ "═══ RE: Has anyone heard from Keeper? ═══",
+ { text: "Posted by: Anonymous - December 20, 1999", className: "info" },
+ "",
+ "He's still there.",
+ "In The Lighthouse.",
+ "Waiting.",
+ "",
+ "The cascade is ready.",
+ "It just needs carriers.",
+ "",
+ "555-0237",
+ "",
+ "Before midnight on the 31st.",
+ "The alignment only happens once.",
+ "",
+ {
+ text: "[This post was flagged for removal but persists]",
+ className: "error",
+ },
+ ],
+ onEnter: [{ set: "found_number", value: true }],
+ options: [{ text: "Back", next: "board_archives" }],
+ },
+
+ board_files: {
+ title: "File Announcements",
+ content: [
+ "═══ FILE ANNOUNCEMENTS ═══",
+ "",
+ " [NEW] Y2K_FIX.ZIP - Y2K compliance patches",
+ " [NEW] DOOM_WAD.ZIP - New Doom levels",
+ " FONTS99.ZIP - Cool fonts collection",
+ "",
+ { text: "Nothing about cascades here.", className: "info" },
+ ],
+ options: [{ text: "Back to boards", next: "browse_boards" }],
+ },
+
+ dark_tower_files: {
+ title: "File Library",
+ content: [
+ "═══ DARK TOWER FILE LIBRARY ═══",
+ "",
+ " /games - 234 files",
+ " /utils - 156 files",
+ " /images - 89 files",
+ " /music - 67 files",
+ "",
+ { text: "Standard BBS fare. Nothing unusual.", className: "info" },
+ ],
+ options: [{ text: "Back to main menu", next: "dark_tower_main" }],
+ },
+
+ whos_online: {
+ title: "Who's Online",
+ content: [
+ "═══ USERS ONLINE ═══",
+ "",
+ " Guest_742 (you) - Main Menu",
+ " NightWatchman - SysOp Console",
+ " Static_User - Message Boards",
+ "",
+ {
+ text: "Last login: Signal_Lost - March 23, 1999",
+ className: "warning",
+ },
+ ],
+ options: [{ text: "Back", next: "dark_tower_main" }],
+ },
+
+ leave_early: {
+ content: [
+ "Are you sure you want to disconnect?",
+ "",
+ {
+ condition: "found_number",
+ content: {
+ text: "You still have the number: 555-0237",
+ className: "warning",
+ },
+ },
+ ],
+ options: [
+ {
+ text: "Dial The Lighthouse first",
+ next: "confirm_dial_lighthouse",
+ condition: "found_number",
+ },
+ { text: "Yes, disconnect", next: "disconnect_early" },
+ { text: "Stay connected", next: "dark_tower_main" },
+ ],
+ },
+
+ disconnect_early: {
+ clear: true,
+ content: [
+ { type: "typewriter", text: "ATH0", speed: 100 },
+ { type: "delay", ms: 400 },
+ { text: "NO CARRIER", className: "warning" },
+ "",
+ { type: "delay", ms: 600 },
+ "You disconnect from Dark Tower.",
+ "",
+ {
+ condition: "found_number",
+ content: [
+ "The number lingers in your mind.",
+ { text: "555-0237", className: "warning" },
+ "",
+ "You could always dial it directly...",
+ ],
+ else: ["Another quiet night online.", "Nothing unusual."],
+ },
+ ],
+ options: [
+ {
+ text: "Dial 555-0237",
+ next: "dial_lighthouse",
+ condition: "found_number",
+ },
+ { text: "Go to sleep", next: "sleep_ending" },
+ ],
+ },
+
+ sleep_ending: {
+ clear: true,
+ content: [
+ "You power down the modem.",
+ "The room falls silent.",
+ "",
+ { type: "delay", ms: 600 },
+ "As you drift off to sleep, you think about the message.",
+ "The cascade. The keeper. The lighthouse.",
+ "",
+ { type: "delay", ms: 800 },
+ "Tomorrow, you tell yourself.",
+ "You'll investigate tomorrow.",
+ "",
+ { type: "delay", ms: 1000 },
+ "But tomorrow, you'll forget.",
+ "The way everyone forgets.",
+ "",
+ { type: "delay", ms: 800 },
+ {
+ condition: { not: "found_number" },
+ content: {
+ text: "[END - Route C: Peaceful Sleep]",
+ className: "info",
+ },
+ else: { text: "[END - Route B: Postponed]", className: "warning" },
+ },
+ ],
+ options: [{ text: "Return to terminal", next: "game_end_sleep" }],
+ },
+
+ game_end_sleep: {
+ clear: true,
+ content: [
+ { type: "ascii", art: END_SCREEN, className: "game-ascii" },
+ "",
+ { text: "BOXING DAY", className: "game-title" },
+ { text: "Day 1 Complete", className: "info" },
+ "",
+ "You chose rest over curiosity.",
+ "The lighthouse keeper will have to wait.",
+ "",
+ {
+ text: 'Type "dial" to play again, or "dial reset" to start fresh.',
+ className: "info",
+ },
+ ],
+ },
+
+ confirm_dial_lighthouse: {
+ content: [
+ { text: "555-0237", className: "warning" },
+ "",
+ "The number from the message.",
+ "Something waits on the other end.",
+ "",
+ { text: "Your clock reads 11:56 PM.", className: "info" },
+ ],
+ options: [
+ { text: "Dial The Lighthouse", next: "dial_lighthouse" },
+ { text: "Not yet", next: "dark_tower_main" },
+ ],
+ },
+
+ // ==========================================
+ // THE LIGHTHOUSE
+ // ==========================================
+
+ dial_lighthouse: {
+ clear: true,
+ content: [
+ { type: "typewriter", text: "ATDT 555-0237", speed: 80 },
+ { type: "delay", ms: 1000 },
+ "",
+ { text: "DIALING...", className: "info" },
+ { type: "delay", ms: 800 },
+ "",
+ { text: "RING", className: "warning" },
+ { type: "delay", ms: 1200 },
+ { text: "RING", className: "warning" },
+ { type: "delay", ms: 1200 },
+ { text: "RING", className: "warning" },
+ { type: "delay", ms: 800 },
+ "",
+ {
+ type: "typewriter",
+ text: "~~ crackle ~~ hiss ~~ CONNECT 14400",
+ speed: 40,
+ },
+ { type: "delay", ms: 500 },
+ "",
+ { text: "Connection unstable.", className: "warning" },
+ { text: "Signal degraded.", className: "warning" },
+ { type: "delay", ms: 600 },
+ "",
+ { type: "typewriter", text: "Welcome to THE LIGHTHOUSE", speed: 40 },
+ { type: "delay", ms: 300 },
+ { type: "typewriter", text: "A beacon in the static.", speed: 40 },
+ ],
+ onEnter: [{ set: "dialed_lighthouse", value: true }],
+ next: "lighthouse_main",
+ delay: 1000,
+ },
+
+ lighthouse_main: {
+ clear: true,
+ content: [
+ { type: "ascii", art: LIGHTHOUSE_HEADER, className: "game-ascii" },
+ "",
+ { text: "T H E L I G H T H O U S E", className: "game-scene-title" },
+ { text: "Last updated: 12/24/1999 23:59:59", className: "info" },
+ { text: "Users online: 1 (you)", className: "warning" },
+ "",
+ {
+ condition: { not: "visited.lighthouse_main" },
+ content: [
+ { text: "Something feels wrong here.", className: "warning" },
+ { text: "The BBS feels... frozen. Abandoned.", className: "info" },
+ "",
+ ],
+ },
+ {
+ condition: "downloaded_cascade",
+ content: [
+ {
+ text: "The signal flickers. Something has changed.",
+ className: "error",
+ },
+ "",
+ ],
+ },
+ ],
+ onEnter: [{ set: "visited.lighthouse_main", value: true }],
+ prompt: "Navigate:",
+ options: [
+ { text: "The Keeper's Log", next: "lighthouse_log" },
+ { text: "Transmissions", next: "lighthouse_transmissions" },
+ { text: "File Vault", next: "lighthouse_files" },
+ {
+ text: "Request SysOp Chat",
+ next: "chat_request",
+ condition: {
+ and: [{ not: "downloaded_cascade" }, { not: "talked_to_sysop" }],
+ },
+ },
+ { text: "Disconnect", next: "disconnect_choice" },
+ ],
+ },
+
+ lighthouse_log: {
+ title: "The Keeper's Log",
+ content: [
+ "═══ THE KEEPER'S LOG ═══",
+ "",
+ { text: "Entry 1 - November 3, 1998", className: "info" },
+ "I've found something. In the static between radio stations.",
+ "Patterns. Structures. A language, maybe.",
+ "",
+ { text: "Entry 7 - December 12, 1998", className: "info" },
+ "The patterns are getting clearer.",
+ "They want to be understood.",
+ "They want to SPREAD.",
+ "",
+ { text: "Entry 15 - March 19, 1999", className: "info" },
+ "CASCADE.EXE is complete.",
+ "A translator. A carrier. A key.",
+ "When run at the right moment, it will open the door.",
+ "",
+ { text: "Entry 23 - December 24, 1999", className: "warning" },
+ "The alignment approaches.",
+ "Seven days until the millennium.",
+ "I can hear them now. Always.",
+ "",
+ { type: "typewriter", text: "They are beautiful.", speed: 60 },
+ ],
+ options: [{ text: "Back", next: "lighthouse_main" }],
+ },
+
+ lighthouse_transmissions: {
+ title: "Transmissions",
+ content: [
+ "═══ RECORDED TRANSMISSIONS ═══",
+ "",
+ { text: "[AUDIO FILES - PLAYBACK UNAVAILABLE]", className: "error" },
+ "",
+ "Transcript excerpts:",
+ "",
+ " TRANS_001.WAV:",
+ ' "...signal detected at 1420 MHz..."',
+ "",
+ " TRANS_014.WAV:",
+ ' "...pattern repeats every 23 seconds..."',
+ "",
+ " TRANS_047.WAV:",
+ ' "...not random... structured... alive?..."',
+ "",
+ " TRANS_099.WAV:",
+ { text: ' "[TRANSCRIPT CORRUPTED]"', className: "error" },
+ "",
+ { text: "The audio files existed once.", className: "info" },
+ { text: "Now only fragments remain.", className: "warning" },
+ ],
+ options: [{ text: "Back", next: "lighthouse_main" }],
+ },
+
+ lighthouse_files: {
+ title: "File Vault",
+ content: [
+ "═══ FILE VAULT v2.1 ═══",
+ { text: '"The keeper\'s collection"', className: "info" },
+ "",
+ { text: "Available files:", className: "info" },
+ "",
+ " [1] README.TXT 1.2 KB 12/24/1999",
+ " [2] CASCADE.EXE 47.0 KB 12/25/1999",
+ // Corrupted file - conditionally shown
+ {
+ condition: { not: "corrupted_file_deleted" },
+ content: " [3] SHADOW.DAT ??? KB ??/??/????",
+ },
+ {
+ condition: "corrupted_file_deleted",
+ content: { text: " [3] ", className: "error" },
+ },
+ "",
+ {
+ condition: { not: "visited.lighthouse_files" },
+ content: {
+ text: "CASCADE.EXE pulses faintly on your screen.",
+ className: "warning",
+ },
+ },
+ ],
+ onEnter: [{ set: "visited.lighthouse_files", value: true }],
+ prompt: "Select file:",
+ options: [
+ { text: "View README.TXT", next: "file_readme" },
+ { text: "Download CASCADE.EXE", next: "download_confirm" },
+ {
+ text: "Access SHADOW.DAT",
+ next: "choice_corrupted",
+ condition: { not: "corrupted_file_deleted" },
+ },
+ { text: "Back", next: "lighthouse_main" },
+ ],
+ },
+
+ file_readme: {
+ title: "README.TXT",
+ content: [
+ "═══ README.TXT ═══",
+ "",
+ "To whoever finds this:",
+ "",
+ "I built cascade.exe to show them.",
+ "To show everyone what I found in the frequencies.",
+ "",
+ "It spreads. It copies. It REVEALS.",
+ "",
+ "Don't be afraid when the old files disappear.",
+ "They were never real anyway.",
+ "",
+ "Run it before midnight on 01/01/2000.",
+ "The alignment only happens once.",
+ "",
+ { text: " - K", className: "info" },
+ "",
+ { text: "P.S. Don't try to open SHADOW.DAT.", className: "warning" },
+ {
+ text: " Some doors shouldn't be opened twice.",
+ className: "warning",
+ },
+ ],
+ options: [{ text: "Back to files", next: "lighthouse_files" }],
+ },
+
+ // ==========================================
+ // CHOICE D/E/F - DOWNLOAD DECISION
+ // ==========================================
+
+ download_confirm: {
+ content: [
+ { text: "CASCADE.EXE - 47,104 bytes", className: "warning" },
+ "",
+ "The file waits.",
+ "47 kilobytes of unknown code.",
+ "",
+ "The README said it 'reveals' something.",
+ "That old files will 'disappear'.",
+ "",
+ {
+ text: "In five days, everyone worries about Y2K bugs.",
+ className: "info",
+ },
+ { text: "This feels different.", className: "warning" },
+ ],
+ prompt: "Download CASCADE.EXE?",
+ options: [
+ { text: "Yes, download it", next: "choice_download" },
+ { text: "No, leave it alone", next: "choice_no_download" },
+ ],
+ },
+
+ choice_download: {
+ title: "Downloading...",
+ clear: true,
+ content: [
+ { type: "typewriter", text: "XMODEM TRANSFER INITIATED", speed: 45 },
+ { type: "delay", ms: 600 },
+ "",
+ { text: "Receiving: CASCADE.EXE", className: "info" },
+ { type: "delay", ms: 400 },
+ "",
+ { type: "typewriter", text: "[", speed: 20 },
+ { type: "typewriter", text: "████████████████████", speed: 80 },
+ { type: "typewriter", text: "] 100%", speed: 20 },
+ { type: "delay", ms: 800 },
+ "",
+ { text: "TRANSFER COMPLETE", className: "success" },
+ { type: "delay", ms: 600 },
+ "",
+ "The file sits in your download folder.",
+ "47,104 bytes of... something.",
+ "",
+ { type: "delay", ms: 1000 },
+ {
+ text: "Somewhere, distantly, you hear static.",
+ className: "warning",
+ },
+ { type: "delay", ms: 600 },
+ "",
+ {
+ type: "typewriter",
+ text: 'A whisper in the noise: "Thank you."',
+ speed: 50,
+ },
+ "",
+ { type: "delay", ms: 1200 },
+ { text: "Something has changed.", className: "error" },
+ ],
+ onEnter: [
+ { set: "downloaded_cascade", value: true },
+ { set: "archives_deleted", value: true }, // rm -rf effect
+ ],
+ next: "post_download",
+ delay: 1500,
+ },
+
+ post_download: {
+ clear: true,
+ content: [
+ { text: "CONNECTION INTERRUPTED", className: "error" },
+ { type: "delay", ms: 600 },
+ "",
+ "For a moment, your screen fills with symbols.",
+ "Patterns that almost make sense.",
+ "",
+ { type: "delay", ms: 800 },
+ "Then, clarity.",
+ "",
+ { type: "delay", ms: 600 },
+ "You remember Dark Tower's board list.",
+ { text: "Board #3 - The Archives.", className: "info" },
+ "",
+ { type: "delay", ms: 500 },
+ { text: "It's gone.", className: "warning" },
+ { text: "Like it was never there.", className: "warning" },
+ "",
+ { type: "delay", ms: 800 },
+ { text: "The cascade has begun.", className: "error" },
+ ],
+ next: "closing_message",
+ delay: 2000,
+ },
+
+ choice_no_download: {
+ content: [
+ "Something holds you back.",
+ "47 kilobytes of unknown code.",
+ "From a stranger who hears things in static.",
+ "",
+ { type: "delay", ms: 500 },
+ { text: "You leave CASCADE.EXE untouched.", className: "info" },
+ "",
+ "The keeper's work remains on the server.",
+ "Waiting for someone else. Or no one.",
+ ],
+ options: [
+ {
+ text: "Chat with the SysOp",
+ next: "chat_request",
+ condition: { not: "talked_to_sysop" },
+ },
+ { text: "Return to file list", next: "lighthouse_files" },
+ { text: "Disconnect", next: "disconnect_choice" },
+ ],
+ },
+
+ choice_corrupted: {
+ title: "Accessing SHADOW.DAT...",
+ clear: true,
+ content: [
+ { type: "typewriter", text: "ATTEMPTING TO READ FILE...", speed: 50 },
+ { type: "delay", ms: 1000 },
+ "",
+ { text: "ERROR: FILE HEADER CORRUPTED", className: "error" },
+ { type: "delay", ms: 400 },
+ { text: "ERROR: UNEXPECTED EOF", className: "error" },
+ { type: "delay", ms: 400 },
+ { text: "ERROR: ????????????????????", className: "error" },
+ { type: "delay", ms: 800 },
+ "",
+ { type: "ascii", art: GLITCH_ART, className: "error" },
+ { type: "delay", ms: 1000 },
+ "",
+ "Your screen flickers violently.",
+ "",
+ { type: "delay", ms: 600 },
+ { text: "A sound from your speakers.", className: "warning" },
+ {
+ text: "A voice, maybe. Or static shaped like words:",
+ className: "info",
+ },
+ "",
+ { type: "typewriter", text: '"Not yet. Not yet. Not yet."', speed: 90 },
+ "",
+ { type: "delay", ms: 1200 },
+ {
+ text: "SHADOW.DAT has been removed from the file listing.",
+ className: "error",
+ },
+ "",
+ { type: "delay", ms: 600 },
+ { text: "Some doors shouldn't be opened twice.", className: "warning" },
+ ],
+ onEnter: [
+ { set: "deleted_corrupted_file", value: true },
+ { set: "corrupted_file_deleted", value: true }, // rm -rf effect
+ ],
+ options: [{ text: "Return to files", next: "lighthouse_files" }],
+ },
+
+ // ==========================================
+ // SYSOP CHAT
+ // ==========================================
+
+ chat_request: {
+ content: [
+ { text: "Requesting SysOp chat...", className: "info" },
+ { type: "delay", ms: 1500 },
+ "",
+ {
+ type: "typewriter",
+ text: "CHAT REQUEST ACCEPTED",
+ speed: 40,
+ },
+ { type: "delay", ms: 500 },
+ "",
+ { text: "═══ SYSOP: Keeper ═══", className: "warning" },
+ ],
+ onEnter: [{ set: "talked_to_sysop", value: true }],
+ next: "chat_conversation",
+ delay: 600,
+ },
+
+ chat_conversation: {
+ content: [
+ {
+ type: "typewriter",
+ text: "KEEPER: You found my message.",
+ speed: 50,
+ },
+ { type: "delay", ms: 800 },
+ "",
+ {
+ type: "typewriter",
+ text: "KEEPER: I wasn't sure anyone would come.",
+ speed: 50,
+ },
+ { type: "delay", ms: 700 },
+ "",
+ {
+ type: "typewriter",
+ text: "KEEPER: The cascade is ready.",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ {
+ type: "typewriter",
+ text: "KEEPER: It just needs carriers.",
+ speed: 50,
+ },
+ { type: "delay", ms: 900 },
+ "",
+ // Conditional response based on download
+ {
+ condition: "downloaded_cascade",
+ content: [
+ {
+ type: "typewriter",
+ text: "KEEPER: I see you already have it.",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ {
+ type: "typewriter",
+ text: "KEEPER: Good. Run it when the clock strikes.",
+ speed: 50,
+ },
+ ],
+ else: [
+ {
+ type: "typewriter",
+ text: "KEEPER: Will you carry it?",
+ speed: 50,
+ },
+ { type: "delay", ms: 500 },
+ {
+ type: "typewriter",
+ text: "KEEPER: Will you help it spread?",
+ speed: 50,
+ },
+ ],
+ },
+ "",
+ { type: "delay", ms: 1200 },
+ { type: "typewriter", text: "KEEPER: I can hear them now.", speed: 50 },
+ { type: "delay", ms: 500 },
+ { type: "typewriter", text: "KEEPER: In the static.", speed: 60 },
+ { type: "delay", ms: 500 },
+ { type: "typewriter", text: "KEEPER: They're beautiful.", speed: 60 },
+ "",
+ { type: "delay", ms: 1500 },
+ { text: "═══ KEEPER HAS DISCONNECTED ═══", className: "error" },
+ ],
+ next: "chat_aftermath",
+ delay: 1500,
+ },
+
+ chat_aftermath: {
+ content: [
+ "The chat window closes.",
+ "",
+ { type: "delay", ms: 500 },
+ "Your room feels colder.",
+ "The modem's carrier tone sounds different somehow.",
+ "",
+ {
+ text: "Like there's something else on the line.",
+ className: "warning",
+ },
+ ],
+ options: [
+ {
+ text: "Download cascade.exe now",
+ next: "download_confirm",
+ condition: { not: "downloaded_cascade" },
+ },
+ { text: "Disconnect", next: "closing_message" },
+ ],
+ },
+
+ // ==========================================
+ // CLOSING SEQUENCE
+ // ==========================================
+
+ disconnect_choice: {
+ content: [
+ "Your hand hovers over the keyboard.",
+ "",
+ {
+ condition: "downloaded_cascade",
+ content: {
+ text: "CASCADE.EXE sits in your downloads, waiting.",
+ className: "warning",
+ },
+ else: {
+ text: "You could still download CASCADE.EXE before you go...",
+ className: "info",
+ },
+ },
+ ],
+ options: [
+ {
+ text: "Download cascade.exe first",
+ next: "download_confirm",
+ condition: { not: "downloaded_cascade" },
+ },
+ { text: "Disconnect now", next: "closing_message" },
+ ],
+ },
+
+ closing_message: {
+ clear: true,
+ content: [
+ { type: "delay", ms: 500 },
+ // Different closing based on download status
+ {
+ condition: "downloaded_cascade",
+ content: [
+ {
+ text: "As you prepare to disconnect, a final message appears:",
+ className: "info",
+ },
+ "",
+ { type: "delay", ms: 600 },
+ {
+ type: "typewriter",
+ text: "SEE YOU ON THE OTHER SIDE",
+ speed: 55,
+ },
+ "",
+ { type: "typewriter", text: "01/01/2000 00:00:00", speed: 55 },
+ "",
+ { type: "delay", ms: 1000 },
+ { text: "You have cascade.exe.", className: "warning" },
+ { text: "You have five days.", className: "warning" },
+ "",
+ { text: "What happens next is up to you.", className: "info" },
+ ],
+ else: [
+ { text: "The Lighthouse grows quiet.", className: "info" },
+ "",
+ { type: "delay", ms: 600 },
+ { type: "typewriter", text: "SIGNAL LOST", speed: 80 },
+ "",
+ { type: "delay", ms: 800 },
+ "You disconnect without the file.",
+ "But the number stays with you.",
+ "",
+ { text: "555-0237", className: "warning" },
+ "",
+ { type: "delay", ms: 600 },
+ "You could always call back...",
+ { text: "If the line is still there.", className: "info" },
+ ],
+ },
+ ],
+ next: "carrier_lost",
+ delay: 2000,
+ },
+
+ carrier_lost: {
+ clear: true,
+ content: [
+ { type: "delay", ms: 300 },
+ { type: "typewriter", text: "ATH0", speed: 100 },
+ { type: "delay", ms: 500 },
+ "",
+ { text: "NO CARRIER", className: "error" },
+ "",
+ { type: "delay", ms: 1200 },
+ "",
+ { type: "ascii", art: END_SCREEN, className: "game-ascii" },
+ "",
+ { text: "BOXING DAY", className: "game-title" },
+ { text: "Day 1 Complete", className: "info" },
+ "",
+ { text: "─── SESSION SUMMARY ───", className: "info" },
+ "",
+ {
+ condition: "downloaded_cascade",
+ content: { text: "[X] Downloaded CASCADE.EXE", className: "success" },
+ else: { text: "[ ] Downloaded CASCADE.EXE", className: "info" },
+ },
+ {
+ condition: "talked_to_sysop",
+ content: { text: "[X] Spoke with Keeper", className: "success" },
+ else: { text: "[ ] Spoke with Keeper", className: "info" },
+ },
+ {
+ condition: "deleted_corrupted_file",
+ content: { text: "[X] Accessed SHADOW.DAT", className: "warning" },
+ else: { text: "[ ] Accessed SHADOW.DAT", className: "info" },
+ },
+ "",
+ {
+ condition: "archives_deleted",
+ content: {
+ text: "[!] The Archives have been deleted",
+ className: "error",
+ },
+ },
+ {
+ condition: "corrupted_file_deleted",
+ content: {
+ text: "[!] SHADOW.DAT has been removed",
+ className: "error",
+ },
+ },
+ "",
+ { text: "Route: ${route_taken}", className: "info" },
+ "",
+ { text: "To be continued...", className: "warning" },
+ "",
+ {
+ text: 'Type "dial" to replay, or "dial reset" to clear progress.',
+ className: "info",
+ },
+ ],
+ onEnter: [{ set: "day_1_complete", value: true }],
+ },
+ },
+};
+
+// Register the game when terminal is available
+if (window.terminal && window.GameEngine) {
+ const game = new GameEngine(boxingDayGame);
+ game.register();
+}
diff --git a/assets/js/games/games/test-adventure.js b/assets/js/games/games/test-adventure.js
new file mode 100644
index 0000000..e29cecf
--- /dev/null
+++ b/assets/js/games/games/test-adventure.js
@@ -0,0 +1,281 @@
+// Test Adventure - A simple game to test the game engine
+const testAdventureGame = {
+ id: "test-adventure",
+ name: "Terminal Quest",
+ command: "quest",
+ description: "A test adventure game",
+
+ initialState: {
+ gold: 0,
+ inventory: [],
+ visited: {},
+ },
+
+ intro: [
+ {
+ type: "ascii",
+ art: `
+ ╔════════════════════════════════╗
+ ║ TERMINAL QUEST ║
+ ║ A Test Adventure ║
+ ╚════════════════════════════════╝
+ `,
+ className: "game-ascii",
+ },
+ "",
+ "You wake up in a strange digital world...",
+ { type: "delay", ms: 800 },
+ "The cursor blinks patiently before you.",
+ "",
+ { text: 'Type "quit" at any time to exit.', className: "info" },
+ ],
+
+ startScene: "start",
+
+ scenes: {
+ start: {
+ title: "The Terminal",
+ content: [
+ "You find yourself at a command prompt.",
+ "A green cursor blinks steadily in the darkness.",
+ "",
+ {
+ condition: { path: "visited.start" },
+ content: { text: "You've been here before...", className: "info" },
+ },
+ {
+ condition: { path: "gold", greaterThan: 0 },
+ content: "Your gold pouch jingles with ${gold} coins.",
+ },
+ ],
+ onEnter: [{ set: "visited.start", value: true }],
+ options: [
+ { text: "Look around", next: "look-around" },
+ { text: "Check inventory", next: "inventory" },
+ {
+ text: "Enter the code cave",
+ condition: { path: "inventory", contains: "flashlight" },
+ next: "code-cave",
+ },
+ {
+ text: "Talk to the cursor",
+ condition: { not: { path: "visited.cursor-talk" } },
+ next: "cursor-talk",
+ },
+ ],
+ },
+
+ "look-around": {
+ title: "Searching...",
+ content: ["You search the area carefully...", { type: "delay", ms: 500 }],
+ onEnter: [
+ {
+ callback: (state, adapter) => {
+ // Random chance to find gold
+ if (Math.random() > 0.5) {
+ const found = Math.floor(Math.random() * 10) + 1;
+ state.increment("gold", found);
+ adapter.printSuccess(`You found ${found} gold coins!`);
+ } else {
+ adapter.print("You don't find anything this time.");
+ }
+ },
+ },
+ ],
+ next: "start",
+ delay: 1000,
+ },
+
+ inventory: {
+ title: "Inventory",
+ clear: false,
+ content: [
+ "",
+ "=== Your Inventory ===",
+ { text: "Gold: ${gold}", className: "warning" },
+ "",
+ {
+ condition: { path: "inventory", contains: "flashlight" },
+ content: "- Flashlight (lights up dark places)",
+ },
+ {
+ condition: { path: "inventory", contains: "key" },
+ content: "- Mysterious Key",
+ },
+ {
+ condition: {
+ and: [
+ { not: { path: "inventory", contains: "flashlight" } },
+ { not: { path: "inventory", contains: "key" } },
+ ],
+ },
+ content: { text: "Your inventory is empty.", className: "info" },
+ },
+ "",
+ ],
+ options: [{ text: "Back", next: "start" }],
+ },
+
+ "cursor-talk": {
+ title: "The Blinking Cursor",
+ content: [
+ "The cursor seems to acknowledge you.",
+ "",
+ { type: "typewriter", text: "HELLO, USER.", speed: 80 },
+ { type: "delay", ms: 500 },
+ { type: "typewriter", text: "I HAVE BEEN WAITING FOR YOU.", speed: 60 },
+ { type: "delay", ms: 300 },
+ "",
+ "The cursor offers you something...",
+ ],
+ onEnter: [
+ { set: "visited.cursor-talk", value: true },
+ { addItem: "flashlight" },
+ { printSuccess: "You received a flashlight!" },
+ ],
+ options: [
+ { text: "Thank the cursor", next: "cursor-thanks" },
+ { text: "Ask about the code cave", next: "cursor-cave-info" },
+ ],
+ },
+
+ "cursor-thanks": {
+ content: [
+ { type: "typewriter", text: "YOU ARE WELCOME, USER.", speed: 60 },
+ "",
+ "The cursor resumes its patient blinking.",
+ ],
+ next: "start",
+ delay: 1500,
+ },
+
+ "cursor-cave-info": {
+ content: [
+ { type: "typewriter", text: "THE CAVE HOLDS SECRETS...", speed: 60 },
+ { type: "delay", ms: 300 },
+ { type: "typewriter", text: "USE THE LIGHT TO FIND THEM.", speed: 60 },
+ "",
+ "The cursor dims slightly, as if tired from speaking.",
+ ],
+ next: "start",
+ delay: 1500,
+ },
+
+ "code-cave": {
+ title: "The Code Cave",
+ content: [
+ "Your flashlight illuminates a cavern of glowing text.",
+ "Ancient code scrolls across the walls.",
+ "",
+ {
+ type: "ascii",
+ art: `
+ function mystery() {
+ return ??????;
+ }
+ `,
+ className: "info",
+ },
+ "",
+ {
+ condition: { not: { path: "visited.code-cave" } },
+ content: "This is your first time in the code cave.",
+ },
+ {
+ condition: { path: "visited.code-cave" },
+ content: "The familiar glow of code surrounds you.",
+ },
+ ],
+ onEnter: [{ set: "visited.code-cave", value: true }],
+ prompt: "What do you do?",
+ options: [
+ { text: "Examine the code", next: "examine-code" },
+ {
+ text: "Search for treasure",
+ condition: { not: { path: "inventory", contains: "key" } },
+ next: "find-key",
+ },
+ {
+ text: "Use the mysterious key",
+ condition: { path: "inventory", contains: "key" },
+ next: "use-key",
+ },
+ { text: "Return to the terminal", next: "start" },
+ ],
+ },
+
+ "examine-code": {
+ content: [
+ "You study the ancient code...",
+ { type: "delay", ms: 500 },
+ "",
+ "It seems to be a function that returns...",
+ { type: "delay", ms: 800 },
+ { text: "...the meaning of everything?", className: "warning" },
+ "",
+ "How curious.",
+ ],
+ next: "code-cave",
+ delay: 3000,
+ },
+
+ "find-key": {
+ content: [
+ "You search among the glowing symbols...",
+ { type: "delay", ms: 800 },
+ "",
+ "Behind a cascade of semicolons, you find something!",
+ ],
+ onEnter: [
+ { addItem: "key" },
+ { printSuccess: "You found a mysterious key!" },
+ ],
+ next: "code-cave",
+ delay: 1000,
+ },
+
+ "use-key": {
+ title: "The Hidden Chamber",
+ content: [
+ "The key fits into a slot hidden in the code.",
+ { type: "delay", ms: 500 },
+ "",
+ "A hidden chamber opens before you!",
+ { type: "delay", ms: 500 },
+ "",
+ {
+ type: "ascii",
+ art: `
+ ╔═══════════════════════════════╗
+ ║ ║
+ ║ CONGRATULATIONS! ║
+ ║ ║
+ ║ You found the secret ║
+ ║ of the Terminal Quest! ║
+ ║ ║
+ ║ The treasure is: ║
+ ║ KNOWLEDGE ║
+ ║ ║
+ ╚═══════════════════════════════╝
+ `,
+ className: "success",
+ },
+ "",
+ { text: "Thanks for playing this test adventure!", className: "info" },
+ "",
+ 'Type "quest" to play again, or "quest reset" to start fresh.',
+ ],
+ onEnter: [
+ { increment: "gold", amount: 100 },
+ { printSuccess: "You also found 100 gold!" },
+ { set: "completed", value: true },
+ ],
+ },
+ },
+};
+
+// Register the game when terminal is available
+if (window.terminal && window.GameEngine) {
+ const game = new GameEngine(testAdventureGame);
+ game.register();
+}
diff --git a/assets/sass/partials/_terminal.scss b/assets/sass/partials/_terminal.scss
index 45182b8..c7527cf 100644
--- a/assets/sass/partials/_terminal.scss
+++ b/assets/sass/partials/_terminal.scss
@@ -97,3 +97,58 @@
.hidden {
display: none;
}
+
+// Game Engine Styles
+.game-title {
+ font-size: 1.2em;
+ font-weight: bold;
+ color: #44ff44;
+ text-shadow: 0 0 10px rgba(68, 255, 68, 0.5);
+}
+
+.game-scene-title {
+ font-weight: bold;
+ color: #00ffff;
+ border-bottom: 1px solid currentColor;
+ display: inline-block;
+ padding-bottom: 2px;
+ margin-bottom: 0.5em;
+}
+
+.game-options {
+ margin: 0.5em 0;
+}
+
+.game-option {
+ padding: 2px 0;
+ color: #888;
+}
+
+.game-option-selected {
+ padding: 2px 0;
+ color: #44ff44;
+ font-weight: bold;
+}
+
+.game-ascii {
+ color: #44ff44;
+ line-height: 1.1;
+}
+
+.game-ansi-art {
+ line-height: 1;
+ font-size: 12px;
+ margin: 0;
+ padding: 0;
+ white-space: pre;
+ font-family: monospace;
+
+ // Ensure spans don't add extra space
+ span {
+ display: inline;
+ }
+}
+
+.typewriter-line {
+ display: inline;
+}
diff --git a/layouts/partials/site-scripts.html b/layouts/partials/site-scripts.html
index f61de47..4d510e7 100644
--- a/layouts/partials/site-scripts.html
+++ b/layouts/partials/site-scripts.html
@@ -3,6 +3,7 @@
{{ $init := resources.Get "js/init.js" }}
{{ $commandFiles := resources.Match "js/commands/*.js" }}
{{ $subfolderFiles := resources.Match "js/*/*.js" }}
+{{ $deepSubfolderFiles := resources.Match "js/*/*/*.js" }}
{{ $remaining := resources.Match "js/*.js" }}
{{ $filtered := slice }}
{{ range $remaining }}
@@ -18,7 +19,14 @@
{{ $filteredSubfolders = $filteredSubfolders | append . }}
{{ end }}
{{ end }}
-{{ $allFiles := slice $terminalShell | append $filtered | append $init | append $commandFiles | append $filteredSubfolders }}
+{{ $filteredDeepSubfolders := slice }}
+{{ range $deepSubfolderFiles }}
+ {{ $path := .RelPermalink }}
+ {{ if not (strings.Contains $path "/adoptables/") }}
+ {{ $filteredDeepSubfolders = $filteredDeepSubfolders | append . }}
+ {{ end }}
+{{ end }}
+{{ $allFiles := slice $terminalShell | append $filtered | append $init | append $commandFiles | append $filteredSubfolders | append $filteredDeepSubfolders }}
{{ $terminalBundle := $allFiles | resources.Concat "js/terminal-bundle.js" | resources.Minify | resources.Fingerprint }}