NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Blutopia BON Blackjack // @namespace https://openuserjs.org/users/jacksaw // @description Enables the functionality to make others become poor // @version 1.0 // @updateURL https://openuserjs.org/meta/jacksaw/Blutopia_BON_Blackjack.meta.js // @downloadURL https://openuserjs.org/install/jacksaw/Blutopia_BON_Blackjack.user.js // @license GPL-3.0-or-later // @match https://blutopia.cc/ // @grant none // ==/UserScript== // ==OpenUserJS== // @author jacksaw // ==/OpenUserJS== // Credits to Coasty for creating the Giveaway script, from which some code has been reused to create this one. // Credits to dantayy for the original getSponsors function (current version in this script has been modified) // TODO // Add emoji when message is multiple lines? // Add link to forum post in !info / !help // Validate mins and maxs // Kick only if not started // Add to unclaimed bets mid game not doubling // Start round automatically on a timer // Add input validation // Ensure that host commands can only be executed at appropriate times // Miscellaneous settings regarding the script var GENERAL_SETTINGS = { chatbox_rate_limit: 1000, // Minimum delay in ms between messages room_check: "Blackjack", // Verify that game is hosted in the specified room. Set to "" to disable the check. default_min_players: 1, // Default value for the minimum number of players default_max_players: 4, // Default value for the maximum number of players default_min_bet: 5000, // Default value for the minimum bet default_max_bet: 50000 // Default value for the maximum bet } // These settings can be used to test different portions of the script. By default, all should be set to false. var DEBUG_SETTINGS = { log_chat_messages: false, // Send a copy of all sendMessage instances in the log disable_chat_output: false, // Disable actually sending messages to the chatbox disable_exit_warnings: false // Disable the alert when trying to leave while the script is running } var last_message_sent_timestamp = 0 var message_queue = 0 var gameStart = null var sponsorsInterval = null var cardShoe = [] var processedGiftMessages = [] var dealerName = "Dealer" const chatboxID = "chatbox__messages-create" var chatbox = null var observer var regNum = /^-?\d+$/ var regGift = /([^ \n]+)\shas\sgifted\s([0-9.]+)\sBON\sto\s([^ \n]+)/ var whitespace = document.createTextNode(" ") var coinsIcon = document.createElement("i") coinsIcon.setAttribute("class", "fas fa-coins") var goldCoins = document.createElement("i") goldCoins.setAttribute("class", "fas fa-coins") goldCoins.style.color = "#ffc00a" goldCoins.style.padding = "5px" var blackjackBTN = document.createElement("a") blackjackBTN.setAttribute("class", "form__button form__button--text") blackjackBTN.textContent = "Blackjack" blackjackBTN.prepend(coinsIcon.cloneNode(false)) blackjackBTN.onclick = toggleMenu var frameHTML = ` <section id="blackjackFrame" class="panelV2" style="width: 450px; height: 90%; position: fixed; z-index: 9999; inset: 50px 150px auto auto; overflow: auto; border-style: solid; border-width: 1px; border-color: black" hidden="true"> <header class="panel__heading"> <div class="button-holder no-space"> <div class="button-left"> <h4 class="panel__heading"> <i class="fas fa-coins" style="padding: 5px;"></i> Blackjack Menu </h4> </div> <div class="button-right"> <button id="resetButton" class="form__button form__button--text"> Reset </button> <button id="closeButton" class="form__button form__button--text"> Close </button> </div> </div> </header> <div class="panel__body"> <h1 id="coinHeader" class="panel__heading--centered"> </h1> <form class="form" id="blackjackForm" style="display: flex; flex-flow: column; align-items: center;"> <p class="form__group" style="max-width: 40%;"> <input class="form__text" required="" id="minEntryInput" pattern="[0-9]*" value="${GENERAL_SETTINGS.default_min_bet}" inputmode="numeric" type="text"> <label class="form__label form__label--floating" for="minEntryInput"> Blackjack Min Bet </label> </p> <p class="form__group" style="max-width: 40%;"> <input class="form__text" required="" id="maxEntryInput" pattern="[0-9]*" value="${GENERAL_SETTINGS.default_max_bet}" inputmode="numeric" type="text"> <label class="form__label form__label--floating" for="maxEntryInput"> Blackjack Max Bet </label> </p> <div class="panel__body" style="display: flex; justify-content: center; gap: 20px"> <p class="form__group" style="width: 25%;"> <input class="form__text" required="" id="minPlayersInput" pattern="[0-9]*" value="${GENERAL_SETTINGS.default_min_players}" inputmode="numeric" type="text" maxlength="6"> <label class="form__label form__label--floating" for="minPlayersInput"> Min Players </label> </p> <p class="form__group" style="width: 25%;"> <input class="form__text" required="" id="maxPlayersInput" pattern="[0-9]*" value="${GENERAL_SETTINGS.default_max_players}" inputmode="numeric" type="text" maxlength="6"> <label class="form__label form__label--floating" for="maxPlayersInput"> Max Players </label> </p> </div> <div class="panel__body" style="display: flex; justify-content: center; gap: 20px"> </div> <p class="form__group" style="text-align: center;"> <button id="startButton" class="form__button form__button--filled"> Start </button> </p> </form> <h2 id="countdownHeader" class="panel__heading--centered" hidden=""> </h2> <div id="playersWrapper" class="data-table-wrapper" hidden=""> <table id="playersTable" class="data-table"> <thead> <tr> <th> Players </th> <th> Bet # </th> <th> Hand Value </th> </tr> </thead> <tbody> </tbody> </table> </div> </div> </section> ` var blackjackGame, blackjackFrame, resetButton, closeButton, coinHeader, minEntryInput, maxEntryInput, minPlayersInput, maxPlayersInput, waitTimeInput, startButton, blackjackForm, playersWrapper injectMenu() function injectMenu() { var chatbox_header = document.querySelector(`#chatbox_header div`) if (chatbox_header == null) { // Chatbox hasnt loaded, so wait another 100ms before checking again setTimeout(function() { injectMenu() }, 100) } else { document.body.insertAdjacentHTML("beforeend", frameHTML) // New panel name chatbox_header.prepend(blackjackBTN) blackjackBTN.parentNode.insertBefore(whitespace, blackjackBTN.nextSibling) blackjackFrame = document.getElementById("blackjackFrame") resetButton = document.getElementById("resetButton") resetButton.onclick = resetBlackjack closeButton = document.getElementById("closeButton") closeButton.onclick = toggleMenu coinHeader = document.getElementById("coinHeader") coinHeader.textContent = document.getElementsByClassName("ratio-bar__points")[0].firstElementChild.textContent.trim() coinHeader.prepend(goldCoins.cloneNode(false)) maxEntryInput = document.getElementById("maxEntryInput") minEntryInput = document.getElementById("minEntryInput") minPlayersInput = document.getElementById("minPlayersInput") maxPlayersInput = document.getElementById("maxPlayersInput") //waitTimeInput = document.getElementById("waitTimeInput") startButton = document.getElementById("startButton") startButton.onclick = startBlackjack countdownHeader = document.getElementById("countdownHeader") playersWrapper = document.getElementById("playersWrapper") blackjackForm = document.getElementById("blackjackForm") document.body.appendChild(blackjackFrame) // TODO: Reuse this to add validation to the entry price (you should have atleast 4x the cost of the entry) // Attach event listener to scale the number of reminders automatically //timerInput.addEventListener("input", function(){reminderAutoScaling()}) } } function toggleMenu() { blackjackFrame.hidden = !blackjackFrame.hidden } function updatePlayers() { let tableStart = "<thead><tr><th>Players</th><th>Bet #</th><th>Hand Value</th></tr></thead><tbody>" let tableEntries = "" let tableEnd = "</tbody>" blackjackGame.getPlayers.forEach((player, name) => { tableEntries += `<tr><td>${player.getFancyName}</td><td>${player.getBet}</td><td>${player.getHand.getValue}</td></tr>`; //need ; to fix syntax highligthing }) document.getElementById("playersTable").innerHTML = tableStart + tableEntries + tableEnd } function startBlackjack() { var currentRoom = document.getElementsByClassName("panel__tab chatbox__tab panel__tab--active")[0].childNodes[1].textContent.trim() var hostsBon = parseInt(document.getElementsByClassName("ratio-bar__points")[0].textContent.trim().replace(/\s/g, ''), 10) var minHostingBon = parseInt(maxEntryInput.value) * parseInt(maxPlayersInput.value) * 3 if (GENERAL_SETTINGS.room_check != currentRoom && GENERAL_SETTINGS.room_check != "") { window.alert(`ERORR: Please run the blackjack script in the blackjack room to avoid spam in unrelated rooms. If you are certain about running the script in the current room, you may disable the room check in the script under GENERAL_SETTINGS.`) } else if (hostsBon < minHostingBon) { window.alert(`BLACKJACK ERROR: Your current BON (${hostsBon}) is not enough to host the blackjack table. To host a cable you must have atleast 3x the maximum bet, times the number of players. Current settings: 3x ${parseInt(maxEntryInput.value)} x ${parseInt(maxPlayersInput.value)} = ${minHostingBon}. Please reduce the maximum bet and/or the maximum number of players.`) //resetBlackjack(blackjackData) // TODO reset? } else { maxEntryInput.disabled = true minEntryInput.disabled = true maxPlayersInput.disabled = true minPlayersInput.disabled = true startButton.parentElement.hidden = true playersWrapper.hidden = false startButton.hidden = true // TODO input variables to the constructor // Setup an alert when trying to exit the tab while hosting a blackjack table if (!DEBUG_SETTINGS.disable_exit_warnings) { window.onbeforeunload = function() { return "Blackjack in progress" } } blackjackGame = new Blackjack() blackjackGame.setMaxEntry = parseInt(maxEntryInput.value) blackjackGame.setMinEntry = parseInt(minEntryInput.value) blackjackGame.setMaxPlayers = parseInt(maxPlayersInput.value) blackjackGame.setMinPlayers = parseInt(minPlayersInput.value) var introMessage = `I am hosting a [b][color=orange]blackjack table[/color][/b]. You may enter by sending [b][color=red]!join[/color][/b]. Bets must be between [b]${blackjackGame.getMinEntry}[/b] and [b]${blackjackGame.getMaxEntry}[/b] inclusive.` sendBotMessage(introMessage) //blackjackGame.setGameBonus = 5000 if (observer) { startObserver() } else { addObserver() } gameStart = Date.now() //MAYBE UNNEEDED RETURN? return false; } } function addObserver() { observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { for (var i = 0; i < mutation.addedNodes.length; i++) { var tablist = document.querySelectorAll('[role="tablist"]'); var general = tablist[0].childNodes[0] // !!! Here it is really important not to pass the giveawayData object to the parseMessage function. If done so, then it will for some reason always retain the pointer of the first // reference it was given, therefore when more than one giveaway is done in a row, the following giveaways messages will be parsed against the old giveawayData information. parseMessage(mutation.addedNodes[i]) } }) }) startObserver() } function startObserver() { var messageList = document.getElementsByClassName("chatroom__messages")[0] observer.observe(messageList, { childList: true }) } function parseMessage(messageNode) { var isBot = messageNode.querySelector(".chatbox-message__content") == null var messageContent if (isBot) { messageContent = messageNode.querySelector(".chatbox-message__header").querySelector("div").textContent } else { var author = messageNode.querySelector(".user-tag").textContent.trim() messageContent = messageNode.querySelector(".chatbox-message__content").textContent var fancyName = messageNode.querySelector(".user-tag").outerHTML } if (messageContent[0] == "!") { handleCommands(author, messageContent, fancyName, blackjackGame) } //else if (isBot) { //handleBotMessages(messageContent, blackjackData) //} } // TODO redo status and some fixes function handleGiftMessage(messageContent) { var gift = regGift.exec(messageContent) var giftAmount = parseInt(gift[2]) var gifter = gift[1] var recpt = gift[3] // Check if gift is for host console.log(`Processing gift from ${gifter} to ${recpt} for ${giftAmount} (raw *${gift[2]}*)`) if (recpt == blackjackGame.getHost) { let player = blackjackGame.getPlayer(gifter) // Check if player in game if (player != null) { // Check status of the game if (blackjackGame.getStatus != "started") { // Handle bets var newTotal = player.getBet += giftAmount if (newTotal > blackjackGame.getMaxEntry) { if (giftAmount > blackjackGame.getMaxEntry) { sendBotMessage(`${User.formattedName(gifter)}: Your bet (${giftAmount}) is above the table limit (${blackjackGame.getMaxEntry}). Please place a new bet. To reclaim this BON, please type !claim.`) } else { sendBotMessage(`${User.formattedName(gifter)}: Your new bet (${giftAmount}) cannot be added to your previous bet (${player.getBet}) as it would exceed table limits (${blackjackGame.getMaxEntry}). To reclaim this BON, please type !claim.`) } player.addUnclaimedBon(giftAmount) } else if (newTotal < blackjackGame.minEntry) { sendBotMessage(`${User.formattedName(gifter)}: Your bet (${newTotal}) is below the table minimum (${blackjackGame.minEntry}). Please place a new bet. To reclaim this BON, please type !claim.`) player.addUnclaimedBon(giftAmount) } else { if (player.getBet == 0) { msg = `${User.formattedName(gifter)}: has placed a bet of ${giftAmount}.` if (blackjackGame.getBonus != 0) { player.addBet(blackjackGame.getBonus) msg += ` A bonus of ${blackjackGame.getBonus} has also been added!` } } else { msg = `${User.formattedName(gifter)}: has added ${giftAmount} to their bet, now totalling ${player.getBet}.` } player.addBet(giftAmount) updatePlayers() sendBotMessage(msg) } } else { console.log("Game has started, so it must be a double") // Handle doubling if (blackjackGame.getCurrentPlayer == player.getName) { console.log("Gifter is the current player") if (player.getHand.canDouble) { if (giftAmount == player.getBet) { player.double() blackjackGame.hit() } else { sendBotMessage(`${User.formattedName(gifter)}: you have gifted ${giftAmount} BON, but to double you must provide the same amount as your bet (${player.getBet} BON). To reclaim this BON, please type !claim.`) player.addUnclaimedBon(giftAmount) } } else { sendBotMessage(`${User.formattedName(gifter)}: you may only double during your first card. To reclaim this BON, please type !claim.`) player.addUnclaimedBon(giftAmount) } } } } else { sendBotMessage(`${User.formattedName(gifter)}: to bet in the game, first you must !join. Your gift of ${giftAmount} BON has not been counted as a bet. Please request a refund if needed.`) console.log(`${new Date()} - ${gifter} has placed a bet without being in the game of: ${giftAmount}.`) } } } function handleCommands(author, messageContent, fancyName, blackjackGame) { var arguments = messageContent.substring(1).trim().split(" ") var command = arguments[0].toLowerCase() if (author == blackjackGame.getHost && ["start", "kick", "next", "setbet", "addbet", "refund", "refundall", "stop", "resume"].includes(command)) { if (command == "next" && blackjackGame.getStatus == "started") { blackjackGame.nextPlayer() } else if (command == "start") { if (blackjackGame.status != "started") { blackjackGame.startRound() } } else if (command == "kick") { if (blackjackGame.playerExists(arguments[1]) && blackjackGame.getStatus == "started") { blackjackGame.refundPlayer(arguments[1]) blackjackGame.removePlayer(arguments[1]) } } else if (command == "setbet") { blackjackGame.getPlayer(arguments[1]).setBet = parseInt(arguments[2]) updatePlayers() } else if (command == "addbet") { blackjackGame.getPlayer(arguments[1]).addBet(parseInt(arguments[2])) updatePlayers() } else if (command == "refund") { blackjackGame.refundPlayer(arguments[1]) } else if (command == "refundall") { blackjackGame.refundAll() } else if (command == "stop") { blackjackGame.stop() } else if (command == "resume") { blackjackGame.resume() } } else if (command == "join") { if (blackjackGame.playerExists(author)) { sendBotMessage(`${User.formattedName(author)}: you have already joined!`) } else if (blackjackGame.getStatus != "open") { sendBotMessage(`${User.formattedName(author)}: table is currently closed!`) } else if (blackjackGame.getPlayers.length >= blackjackGame.getMaxPlayers) { sendBotMessage(`${User.formattedName(author)}: [b]you are unable to join[/b] because the maximum number of players (${blackjackGame.maxPlayers}) has been reached! Please wait for the next game or for a player to leave.`) } else { blackjackGame.addPlayer(author, fancyName) } } // Check for refunds else if (command == "leave") { if (!blackjackGame.playerExists(author)) { sendBotMessage(`${User.formattedName(author)}: you are not in the table! To enter please !join`) } else if (blackjackGame.getStatus == "started") { sendBotMessage(`${User.formattedName(author)}: you may not leave once the game starts!`) // TODO allow leave but forfeit? } else { var player = blackjackGame.getPlayer(author) if (player.getBet > 0) { sendBotMessage(`${User.formattedName(author)}: existing bet (${player.getBet} BON) has been automatically refunded.`) player.refundBet() } blackjackGame.removePlayer(author) } } else if (command == "start") { if (blackjackGame.playerExists(author) && blackjackGame.status != "started") blackjackGame.startRound() else sendBotMessage(`${User.formattedName(author)}: you may start a game if you are not in the table!`) } else if (command == "bet") { if (!blackjackGame.playerExists(author)) sendBotMessage(`${User.formattedName(author)}: please !join before placing any bets`) else sendBotMessage(`${User.formattedName(author)}: your current bet is of [b][color=#ffc00a]${blackjackGame.getPlayer(author).getBet} BON[/color][/b]`) } else if (command == "hit") { if (blackjackGame.getStatus == "started") { if (blackjackGame.getCurrentPlayer == author) { blackjackGame.hit() } } else { sendBotMessage(`${User.formattedName(author)}: no game is currently in progress.`) } } else if (command == "double") { if (blackjackGame.getStatus == "started") { if (blackjackGame.getCurrentPlayer == author) { var player = blackjackGame.getPlayer(author) if (player.canDouble) { sendBotMessage(`${User.formattedName(author)}: to double please bet again the same amount: [b]/gift ${blackjackGame.getHost} ${blackjackGame.getPlayer(author).getBet} blackjack[/b], otherwise you can !hit or !stand`) } else { sendBotMessage(`${User.formattedName(author)}: you may only double at the beginning of the hand!`) } } } else { sendBotMessage(`${User.formattedName(author)}: no game is currently in progress.`) } } else if (command == "stand") { if (blackjackGame.getStatus == "started") { if (blackjackGame.getCurrentPlayer == author) { blackjackGame.nextPlayer() } } else { sendBotMessage(`${User.formattedName(author)}: no game is currently in progress.`) } } else if (command == "info" || command == "help") { sendBotMessage(`${User.formattedName(author)}: please refer to the guide in the [url=https://blutopia.cc/forums/topics/5707]forum post[/b].`) } else if (command == "claim") { if(blackjackGame.playerExists(author)) { var player = blackjackGame.getPlayer(author) if (player.getUnclaimedBon > 0) { sendBotMessage(`${User.formattedName(author)}: You have been returned ${player.unclaimedBon} BON.`) player.refundUnclaimedBon() } else { sendBotMessage(`${User.formattedName(author)}: You currently have no unclaimed BON.`) } } else { sendBotMessage(`${User.formattedName(author)}: Invalid use of !claim, you are not in the game.`) } } else if (command == "refundbet") { if(blackjackGame.playerExists(author)) { var player = blackjackGame.getPlayer(author) if (blackjackGame.getStatus == "started") { sendBotMessage(`${User.formattedName(author)}: You may not refund your bet after the game starts.`) } else if(player.getBet > 0) { sendBotMessage(`${User.formattedName(author)}: Your bet (${player.getBet}) has been refunded, and your current bet for the game has been set to 0.`) player.refundBet() } else { sendBotMessage(`${User.formattedName(author)}: You have not placed any bets.`) } } else { sendBotMessage(`${User.formattedName(author)}: You are not in the game.`) } } } class Blackjack { constructor() { this.host = document.getElementsByClassName("top-nav__username")[0].children[0].textContent.trim() this.maxPlayers = 0 this.minPlayers = 0 this.maxEntry = 0 this.minEntry = 0 this.waitTime = 0 this.bonus = 0 this.players = new Map() this.dealerHand = null this.status = "open" this.playerIterator = null this.currentPlayer = null sponsorsInterval = setInterval(getSponsors, 1000) } get getStatus() { return this.status } get getHost() { return this.host } get getMaxEntry() { return this.maxEntry } /** * @param {number} amount */ set setMaxEntry(amount) { this.maxEntry = amount } get getMinEntry() { return this.minEntry } /** * @param {number} amount */ set setMinEntry(amount) { this.minEntry = amount } get getMaxPlayers() { return this.maxPlayers } /** * @param {number} amount */ set setMaxPlayers(amount) { this.maxPlayers = amount } get getMinPlayers() { return this.minPlayers } /** * @param {number} amount */ set setMinPlayers(amount) { this.minPlayers = amount } get getCurrentPlayer() { return this.currentPlayer } playerExists(username) { return this.getPlayer(username) != null } getPlayer(username) { return this.players.get(username) } refundAll() { this.players.forEach((player, name) => { this.refundPlayer(name) }) } /** * @param {number} amount */ set setGameBonus(amount) { this.bonus = amount sendBotMessage(`The host has activated a [b]bonus[/b] of [b][color=#ffc00a]${this.bonus} BON[/color][/b]! The bonus will be applied with the [b]first bet[/b] of each player!`) } clearGameBonus() { this.bonus = 0 sendBotMessage(`The host has deactivated the bonus.`) } get getBonus() { return this.bonus } refundPlayer(username) { if(this.playerExists(username)) { let player = this.getPlayer(username) if (player.getBet > 0) { sendBotMessage(`${player.formattedName} has been refunded their bet: [b][[color=#ffc00a]${player.getBet} BON[/color]][/b]`) player.refundBet() updatePlayers() } } } addPlayer(username, fancyName) { var newUser = new User(username, fancyName) this.players.set(username, newUser) updatePlayers() sendBotMessage(`${newUser.formattedName} has joined the table. Please place your bet with: [b]/gift ${this.host} *amount* blackjack[/b]`) } removePlayer(username) { this.players.delete(username) updatePlayers() sendBotMessage(`${User.formattedName(username)} has left the table.`) } hit() { var player = this.getPlayer(this.getCurrentPlayer) var newCard = player.getHand.addCard() var handValue = player.getHand.getValue updatePlayers() var hitMessage = `${player.formattedName}: You drew a ${newCard.toFancyString}. You current hand is: ${player.getHand.toFancyString} (${handValue})` if (handValue > 21) { hitMessage += `\n > [b]Busted![/b]` } else if (handValue == 21) { hitMessage += `\n > Hit [b][color=green]21[/color][/b] exactly!` } else if (!player.hasDoubled) { hitMessage += `\n > Would you like to !hit or !stand?` } sendBotMessage(hitMessage) if (handValue > 20 || player.hasDoubled) { this.nextPlayer() } } getPlayer(username) { return this.players.get(username) } get getPlayers() { return this.players } startRound() { console.log(this.players.length) console.log(this.minPlayers) if (this.players.size == 0) { sendBotMessage(`A blackjack game cannot be started if the table is empty!`) return false } else if (this.players.size < this.minPlayers) { sendBotMessage(`For the game to start, [b]the miniumum number of ${this.minPlayers} player(s) must be reached[/b]. Current number of players: ${this.players.length}`) return false } var missingBets = false var missingBetsMsg = `For the game to start, [b]all players must have placed a bet[/b]. Missing bets:[color=red]` this.players.forEach((player, name) => { if (player.getBet == 0) { missingBets = true missingBetsMsg = missingBetsMsg + " " + name } }); missingBetsMsg += `[/color]` if (missingBets) { sendBotMessage(missingBetsMsg) return false } this.status = "started" this.playerIterator = this.players.keys() this.dealHands() updatePlayers() this.printHands() if (this.dealerHand.isBlackjack) { sendBotMessage("[b]Dealer has blackjack![b]") this.finishGame() } else { this.nextPlayer() } } nextPlayer() { var next = this.playerIterator.next() if (!next.done) { this.currentPlayer = next.value console.log(`Next player: ${this.currentPlayer}`) // Check if the next player has blackjack var player = this.getPlayer(this.currentPlayer) if (player.getHand.isBlackjack) { var message = `${player.formattedName} got a blackjack! Skipping.` sendBotMessage(message) this.nextPlayer() } else { var message = `${player.formattedName}: Your hand is: ${player.getHand.toFancyString} (${player.getHand.getValue}). Would you like to !double, !hit, or !stand?` sendBotMessage(message) } } else { var allPlayersBusted = true this.players.forEach((player, key) => { if (!player.getHand.isBust) { allPlayersBusted = false } }) if (allPlayersBusted) { sendBotMessage("All players have [b]busted[b], dealer wins!") } else { sendBotMessage("All players are done, dealer's turn:") this.playDealer() } this.finishGame() this.currentPlayer = null } } playDealer() { var hand = this.dealerHand var msg = "" sendBotMessage(`Dealer's hand is: ${hand.toFancyString} (${hand.getValue})`) // rigDealerCards() while (hand.getValue < 17) { let newCard = hand.addCard() msg = `Dealer drew a ${newCard.toFancyString}. Current hand is: ${hand.toFancyString} (${hand.getValue})` console.log(msg) sendBotMessage(msg) } if (hand.getValue > 21) { msg = `Dealer busts!` } else if (hand.getValue == 21) { msg = "Dealer hits 21 exactly!" } else { msg = `Got ${hand.getValue}. Dealer stands on 17 or above!` } sendBotMessage(msg) } finishGame() { clearInterval(sponsorsInterval) observer.disconnect() var dealerHand = this.dealerHand var dealerValue = dealerHand.getValue this.players.forEach((player, name) => { var hand = player.getHand var handValue = hand.getValue var bet = player.getBet var message = `[b]${player.formattedName}[/b]: ` var payout = 0 if (handValue > 21) { message += `[b][color=#ff3333]busted[/color][/b] with ${handValue}.` } else if (hand.isBlackjack && !dealerHand.isBlackjack) { payout = 2.5 * bet message += `[b][color=green]won with blackjack![/color][/b]` } else if (handValue > dealerValue || (dealerValue > 21)) { payout = 2 * bet message += `[b][color=green]won[/color][/b] with ${handValue}!` } else if (handValue == dealerValue) { payout = bet message += `[b][color=#aaaaaa]push[/color][/b] with ${handValue}.` } else { message += `[b][color=#ff3333]lost[/color][/b] with ${handValue}.` } message += ` [b][[color=#ffc00a]${bet} BON[/color]][/b]` sendBotMessage(message) if (payout > 0) { sendMessage(`/gift ${name} ${payout} Blackjack Bot`) } }); cardShoe = [] this.status = "finished" } printHands() { var handsString = "Cards have been dealt! " var nameArr = [] var card1Arr = [] var card2Arr = [] this.players.forEach((player, name) => { handsString = handsString + `\n - ${player.formattedName} has been dealt: ${player.getHand.toFancyString} (${player.getHand.getValue})` }); handsString = handsString + `\n>Dealer shows: ${this.dealerHand.getCard(0).toFancyString} (${this.dealerHand.getCard(0).getValue})` sendBotMessage(handsString) } dealHands() { this.players.forEach((player, name) => { player.getHand.deal() }); this.dealerHand = new Hand() this.dealerHand.deal() } stop() { sendBotMessage(`Blackjack game has been stopped!`) clearInterval(sponsorsInterval) observer.disconnect() this.status = "stopped-" + this.status } resume() { sendBotMessage(`Blackjack game has been resumed!`) gameStart = new Date() sponsorsInterval = setInterval(getSponsors, 1000) startObserver() this.status = this.status.substring(8) } } class User { constructor(username, fancyName) { this.bet = 0 this.hand = new Hand() this.name = username this.fancyName = fancyName this.doubled = false this.unclaimedBon = 0 } get getUnclaimedBon() { return this.unclaimedBon } /** * @param {number} amount */ set setUnclaimedBon(amount) { this.unclaimedBon = amount } addUnclaimedBon(amount) { this.unclaimedBon += amount } refundUnclaimedBon() { if(this.unclaimedBon > 0) { sendMessage(`/gift ${this.name} ${this.unclaimedBon} Blackjack Unclaimed BON Refund`) this.unclaimedBon = 0 } } get formattedName() { return User.formattedName(this.name) } static formattedName(name) { return "[b]" + name + "[/b]" } get getHand() { return this.hand } get getBet() { return this.bet } get getFancyName() { return this.fancyName } get getName() { return this.name } get hasDoubled() { return this.doubled } refundBet() { if(this.bet > 0) { sendMessage(`/gift ${this.name} ${this.bet} Blackjack Bet Refund`) this.bet = 0 } } double() { this.bet *= 2 this.doubled = true } addBet(amount) { this.bet += amount } /** * @param {number} amount */ set setBet(amount) { this.bet = amount } get canDouble() { return this.hand.canDouble } } class Hand { constructor() { this.cards = [] } get getSize() { return this.cards.length } get getValue() { let sum = 0; let numAces = 0; // Calculate the sum of card values, treating Aces as 1 initially for (let card of this.cards) { if (card.getNumber === 1) { // Ace numAces++; sum += 1; } else if (card.getNumber >= 11 && card.getNumber <= 13) { // Jack, Queen, King sum += 10; } else { sum += card.getNumber; } } // Adjust the sum by converting Aces from 1 to 11 if it doesn't bust the hand while (numAces > 0 && sum + 10 <= 21) { sum += 10; // Convert Ace from 1 to 11 numAces--; } return sum; } get isBlackjack() { return (this.cards.length == 2 && this.getValue == 21) } get canDouble() { return this.cards.length == 2 } get isBust() { return this.getValue > 21 } get toString() { var handString = "" this.cards.forEach((card) => { handString = handString + card.toString + ", " }); handString = handString.substring(0,handString.length-2) return handString } get toFancyString() { var handString = "" this.cards.forEach((card) => { handString = handString + card.toFancyString + ", " }); handString = handString.substring(0,handString.length-2) return handString } addCard() { var newCard = new Card() this.cards.push(newCard) return newCard } getCard(i) { return this.cards[i] } deal() { this.cards = [new Card(), new Card()] } } class Card { constructor() { var suit, number, simpleCardStr do { suit = Math.floor(Math.random() * 4) + 1; number = Math.floor(Math.random() * 13) + 1; simpleCardStr = number + "-" + suit } while (cardShoe.includes(simpleCardStr)) cardShoe.push(simpleCardStr) this.suit = suit this.number = number } get getNumber() { return this.number } get getSuit() { return this.suit } get getValue() { if (this.number > 10) return 10; else if (this.number == 1) return 11; else return this.number; } get getNumberString() { if (this.number < 11 && this.number > 1) { return this.number } else if (this.number == 1) { return "Ace" } else if (this.number == 11) { return "J" } else if (this.number == 12) { return "Q" } else if (this.number == 13) { return "K" } else { return "ERROR" } } get getSuitString() { if (this.suit == 1) { return "♠️" //return "Spades" } else if (this.suit == 2) { return "♥️" //return "Hearts" } else if (this.suit == 3) { return "♣️" //return "Diamonds" } else if (this.suit == 4) { return "♦️" //return "Clubs" } } get getColor() { if (this.suit == 1 || this.suit == 3) { return "black" } else { return "red" } } get toString() { return this.getNumberString + this.getSuitString } get toFancyNumberString() { if (this.getColor == "black") { return `[b][color=#6e7180]${this.getNumberString}[/color][/b]` } else { return `[b][color=#db4040]${this.getNumberString}[/color][/b]` } } get toFancyString() { return this.toFancyNumberString + this.getSuitString } } function sendBotMessage(messageStr) { sendMessage("🎰 " + messageStr) } function sendMessage(messageStr) { if (chatbox == null) { chatbox = document.querySelector(`#${chatboxID}`) } if (!DEBUG_SETTINGS.disable_chat_output) { var timeSinceLastMessage = Date.now() - last_message_sent_timestamp if ((timeSinceLastMessage < GENERAL_SETTINGS.chatbox_rate_limit)) { var waittime = GENERAL_SETTINGS.chatbox_rate_limit - timeSinceLastMessage setTimeout(sendMessage, waittime + last_message_sent_timestamp, messageStr) timeSinceLastMessage = GENERAL_SETTINGS.chatbox_rate_limit + last_message_sent_timestamp } else { chatbox.value = messageStr chatbox.dispatchEvent(new KeyboardEvent("keydown", { keyCode: 13 })) if (last_message_sent_timestamp < Date.now()) { last_message_sent_timestamp = Date.now() } } } if (DEBUG_SETTINGS.log_chat_messages) { console.log(messageStr) } } function cleanBonString(bonAmount) { if (bonAmount % 1 == 0) { return bonAmount } else { return bonAmount.toFixed(2) } } function resetBlackjack() { // Clear onbeforeunload alert window.onbeforeunload = null //countdownHeader.hidden = true startButton.parentElement.hidden = false playersWrapper.hidden = true startButton.disabled = false maxEntryInput.disabled = false minEntryInput.disabled = false maxPlayersInput.disabled = false minPlayersInput.disabled = false clearInterval(sponsorsInterval) observer.disconnect() delete observer delete blackjackGame blackjackForm.reset() } function beutifyBotname(name) { return "[b]" + name + "[/b]" } const getSponsors = async () => { const api = `https://blutopia.cc/api/chat/messages/1`; try { const response = await fetch(api, { method: 'GET', headers: { 'Cookie': document.cookie // Include cookies from the main page } }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); const messages = data.data; messages.reverse().forEach((message) => { var messageTime = new Date(message.created_at).getTime(); var giftMessage = message.message.includes("gifted"); var isBot = (message.bot != null) if (messageTime > gameStart && isBot && giftMessage && !processedGiftMessages.includes(message.id)) { processedGiftMessages.push(message.id) handleGiftMessage(stripHtml(message.message)) } }) } catch (error) { console.error('There was a problem with the fetch operation:', error); } }; function stripHtml(html) { let tmp = document.createElement("DIV"); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ""; } function rigDealerCards() { ``` ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⢆⡱⢫⡟⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⢿⣻⢿⣟⡿⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠠⠀⢂⡘⢦⡳⣏⣾⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣞⣿⣳⣁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠐⠈⣌⢣⡑⢦⣙⢮⣳⢻⡾⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣾⢷⣿⢯⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣌⡳⢈⡒⡌⡖⣭⢺⡭⣞⡥⣏⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣟⡾⣏⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡈⢑⡣⢜⡜⡱⣌⢧⡽⣲⣽⢻⣾⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣽⣻⡽⣷⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠁⠂⠐⢈⠐⡡⠊⢎⡳⣟⠾⣝⡾⣛⣾⢳⢯⡻⡝⣯⢟⡿⣻⢿⣟⡿⣟⣿⢻⠿⡿⣿⢿⡿⣿⣿⢿⣾⣿⣿⣷⡿⣽⣳⠭⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠐⣸⢮⣷⡱⣭⣞⡵⣏⢿⡱⣏⠷⣎⣟⢮⢳⡙⡴⢋⡴⢩⠞⡼⡙⢮⠘⣉⠣⡙⠤⢋⡹⢱⠫⣟⢿⣽⣿⣟⣿⣯⣟⡷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⢭⣻⣽⣿⡷⣯⢻⣜⣣⢟⣼⡻⣝⣮⣛⢦⡙⡖⢣⠜⣡⠚⡔⣩⠂⢇⢢⠱⡱⢌⡒⠤⡃⠵⣈⠞⣽⣾⣿⣿⣽⣯⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠠⣈⣶⣽⣾⡿⣽⢏⡷⣎⢷⣫⠾⣽⣹⢶⡹⣎⡵⣍⢳⢪⢅⡫⠴⣡⢋⡜⢢⢣⡑⢎⡸⢐⡉⢖⡡⢚⡜⣯⣿⣿⣯⣟⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡸⣟⣿⡿⣽⣻⢎⣷⡹⣎⣷⣛⣧⢯⣗⡻⣜⡞⣬⢇⡳⢊⡕⢣⢆⢣⠜⣡⠆⡍⢦⠡⠣⠜⢢⡑⢣⢜⣱⢯⣿⢿⡽⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣁⢷⣻⣯⢿⣯⢷⣛⠶⣝⣳⢾⣹⢮⢷⡺⣝⢧⡻⣔⢫⡔⢫⠜⡡⢎⢎⡜⢢⡙⡜⠤⢋⡅⣋⠦⡙⢆⢮⡹⣟⣾⣿⡻⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠰⢬⢏⣷⡿⣟⣮⢳⣭⢻⣭⣟⣯⣿⣯⣿⣷⣯⣿⣳⣮⣳⣜⢣⢎⡱⢎⡖⣸⢡⠚⣄⠫⠔⡘⡔⢢⠍⢎⢲⡹⣽⢾⡷⣟⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡉⢆⢫⣞⢿⡝⣮⢳⢮⣟⣼⢻⣞⡷⢯⡳⣏⢿⡻⣟⡿⣷⢯⣟⣎⠖⣭⢞⡵⣎⡵⣂⠧⣙⠰⣉⠦⡙⡌⢶⣹⢯⣟⣿⡱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⡐⢬⢷⡞⣯⡝⣮⢏⣷⣚⣮⢷⣻⣾⣿⣷⣿⣞⣷⣯⣟⣿⣻⡾⣝⠎⡜⢯⡾⣿⣽⢿⣻⣮⢷⡜⣦⣑⢚⢦⣻⣯⡿⣞⠥⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⡄⢫⠞⡑⢊⠱⠉⠞⣲⣛⠾⣏⡿⣹⢾⡹⢣⢏⠾⣽⣻⢾⣽⣻⢭⡚⣌⢣⢛⣷⣯⣿⣧⡝⣎⡝⠶⡭⡞⢦⣻⣯⢿⡉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠰⣎⡷⣞⣧⡚⠀⠀⠀⠀⡘⠴⣩⠿⣜⣳⡱⢎⡵⣋⢮⡟⣷⢯⣟⣾⢣⠷⡱⢌⠦⡙⣎⠿⣹⠻⡟⣷⢾⡱⢣⠝⡲⢯⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢌⣻⣽⣻⡽⣶⡹⠄⠀⢌⠰⣌⡳⣝⣯⢳⡧⣝⣏⢶⡹⣎⡿⣽⣻⢾⣝⡯⢏⡵⢊⠖⡱⢌⡚⢥⠓⡜⢤⠣⡙⢥⢋⡵⣻⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⢳⣳⢯⣟⡾⣝⢦⠈⣂⠳⡜⣽⢺⡼⣳⡽⣞⣼⣳⢿⣹⣟⡷⢯⣛⣮⡝⣮⠰⣉⢎⡱⠌⡜⢢⡙⡜⢢⡑⡩⢆⢣⢺⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠡⢏⡿⣾⣽⢫⣮⡑⠤⡛⣼⢣⡯⣗⡯⢷⣛⡾⣽⣞⣷⣻⣾⢿⡿⣷⢿⣞⣳⣵⢪⠴⡩⢜⠡⡒⠌⡥⢒⡱⢊⢆⠯⣼⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠭⢳⢧⣛⡧⣷⣙⢦⡙⣦⢏⡷⣹⢞⡯⣯⣽⢳⣞⡷⣯⣟⣯⠿⣝⠻⡜⡭⠻⣍⠚⡵⣊⠵⣡⢋⡔⢣⠜⣡⠞⡰⢭⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠾⣱⠿⣼⡹⢮⡱⣎⠿⣜⢧⢯⣳⠷⣭⣟⡾⡽⢧⣻⣜⠳⣌⠳⡩⠔⢣⠌⡓⢬⢃⡞⢤⠣⡜⢣⡙⣤⢛⡥⢫⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠠⢉⢧⡳⣭⢻⡜⣯⢞⣵⣻⣳⢯⡾⣽⢯⣷⣞⣷⣬⣳⡹⣌⠣⡜⢱⢊⠖⡸⢂⡳⢌⢣⠜⡰⣋⠖⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⢦⡻⣜⢧⣻⡜⣯⢞⡵⣯⣿⣿⣿⣿⣿⣾⣽⣾⣽⣿⣽⣷⣎⡕⡪⢜⡡⢓⡜⡌⢦⡙⡔⠡⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠲⣝⢮⡳⢧⡻⣜⢯⡽⣳⡽⣞⣯⣟⡻⣙⢛⠻⣻⢿⡿⣟⢯⡛⡕⢪⠔⡣⢜⡘⠆⠱⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢪⠔⡹⢮⡝⣧⢻⡜⣧⢻⡵⣛⣾⢳⣯⢷⣹⢮⡗⣧⢛⡼⢌⠦⡑⢮⡑⢎⡱⢊⠔⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢞⡡⣛⡼⣣⢟⡼⣣⠿⣜⠿⣼⣻⣞⣯⢷⣻⣼⢣⢏⡲⣉⠖⡩⢆⡙⢦⠱⡉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢭⡚⣵⢣⡟⣵⢯⣞⡵⣻⢭⡟⡶⣓⠮⡜⢭⡒⣍⠣⢎⠴⡡⢎⡕⢪⡑⢎⡱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢟⡼⣣⢿⡹⡾⣼⣹⢧⡟⣾⣱⢏⡷⣙⢦⡱⢌⠳⣌⠲⡑⢎⡜⡥⡙⢦⡑⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠭⣞⡵⣛⡮⣗⢿⣱⢯⠾⣝⡾⣭⣟⡾⣵⢮⣱⢋⠶⣈⢧⣙⠲⣜⡡⢝⢢⡹⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡹⢎⡷⣫⢷⣹⡞⣧⢟⣻⡽⣽⣳⢯⡿⣽⣞⡷⣯⢻⡭⢶⢩⠓⢦⡙⢬⠲⣑⢻⣷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠱⣏⡞⣷⢫⣶⢻⡼⣫⣗⢯⡷⣯⠿⣽⠳⢯⡝⣎⢳⡙⢎⡲⡙⢦⡙⢦⡙⠤⠈⣿⣿⣿⣷⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠄⠛⠼⡙⢞⠻⡜⡳⢏⠷⣞⣻⡼⢧⡻⣜⢫⠖⣜⡸⢆⡝⣪⢕⡹⢦⡙⢦⡙⠆⠀⢾⣿⣿⣿⣿⣿⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⣀⡾⡀⢄⡀⠀⠀⠀⠈⣈⠀⣈⣟⣧⢻⣌⢳⡚⡴⢣⢏⡼⣡⢎⡵⢪⡱⢣⡝⠠⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣭⡳⣖⡤⣄⣠⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠄⡌⠀⠀⠌⢢⣝⣣⠷⣌⢯⡻⣝⢯⣟⢧⡛⣵⣻⣼⡳⣎⢷⣹⢣⠟⣜⡲⡱⢎⡜⣣⢽⡓⠄⠀⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣱⣳⣎⡷⣯⣛⡷⣚⡴⣠⢄⣀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⡔⢤⢃⡜⢤⣉⠒⡀⠀⢈⠜⢤⡿⣜⣯⠽⣎⡳⡭⢞⢮⡳⣙⢾⣳⢯⡿⣽⡺⣵⢫⡟⢦⢳⡙⢮⣜⡷⡋⠔⠀⠀⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣞⣿⣽⣯⣟⡷⣽⡖⣯⢾⣹⣞⣵⣲⢦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣄⢢⢵⣸⡼⣧⣻⣜⠧⢦⣉⠀⠀⠰⣈⠲⣟⡹⣎⠿⣼⡹⣝⣫⠶⣍⠧⣻⡽⣯⣟⣷⣻⡵⣻⡜⣯⢇⣿⣳⢏⠇⠡⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣷⣿⣿⣿⣳⣿⡾⣽⣻⣾⣽⣳⢯⣟⡶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⢀⢡⡘⣌⡟⣼⣿⣿⣿⣿⣼⡟⡄⢀⠀⠀⡁⠀⢡⣏⡘⣏⠛⣤⢹⡌⣧⢋⡙⣌⢡⣿⣡⢻⡜⣇⣿⢡⢻⣸⢻⡜⢡⠈⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣿⣿⣿⣿⣿⣿⣿⣏⡟⣧⣼⢹⡟⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠄⢢⡱⣜⣮⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡱⣃⠀⢀⠐⠈⢠⣯⠵⣯⡻⣵⢫⡞⣵⢫⠷⣌⢻⡶⣯⢿⣽⣻⣞⣯⢿⡽⡏⢎⠁⠂⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣷⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⡄⢢⠱⣤⢫⣷⣽⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣛⡄⠀⠀⡌⢀⠰⣏⢿⡱⣟⡼⢧⡻⣜⢯⡳⣌⢳⡿⣽⣻⡾⣷⣻⢾⢏⠓⡁⠂⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⢀⠠⡐⡌⢤⠳⣜⣣⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷⡌⠀⠐⢨⠀⡜⣿⣺⢽⣺⡝⣧⣻⠼⣧⣛⠤⣫⣟⣷⢿⡽⡷⢏⠋⠄⠃⢀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⢠⡘⣤⠳⡼⣜⣷⣻⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢀⠣⡘⢸⣷⢯⣛⡶⣏⠷⣭⢟⡶⢭⣚⣱⢿⣞⢯⠹⡑⠊⠌⠐⠀⠀⠀⠀⠀⠀⠠⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢀⣶⡽⣞⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢄⠓⡌⢳⣿⢯⣝⠾⣭⣻⢧⣻⡼⢧⡳⠘⡏⠜⢂⠡⠐⠡⠈⠀⠀⠀⠀⠀⠀⠐⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠐⣌⢘⡰⠉⢞⡛⠎⠛⠱⠋⠉⠑⠙⠋⠓⠡⢎⠘⣀⠂⡁⠂⠠⠀⠀⠀⠀⠀⢄⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⢡⣂⡶⣤⣳⣼⣟⣶⣳⡾⣴⣦⣤⣤⣖⡴⣎⢧⡛⣤⣒⡄⡁⠀⠀⠀⠀⠀⡈⡔⣋⢟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣖⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣛⢏⡻⠹⣿⠁⠁⠹⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣴⣦⣼⣷⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢐⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⡔⠀⠀⠀⠀⢁⣰⣎⣴⣈⣦⡑⣬⢡⡉⢌⠈⣁⠫⣙⠹⣋⠟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢻⠟⡝⠀⠀⠀⠀⠀⠿⡿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣷⣾⣾⣾⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⡳⣼⡱⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣧⣾⡔⠈⠀⠄⠀⢀⡸⣄⣄⣊⣄⢂⡡⢉⠜⣩⠋⠟⡛⠟⡿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢞⣵⣳⢏⡷⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⡿⢆⠁⠀⠀⠀⠂⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣼⣷⣮⣷⣼⣳⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣫⢾⣽⣻⢼⡱⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⢾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣦⣓⡆⢀⠦⣄⠀⡀⢰⡠⡑⣨⠉⡝⢩⠛⣛⠻⡛⠿⠿⡿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⢿⣳⣟⣮⢳⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⡛⢿⣿⣿⣿⣿⣿⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢇⠠⢈⠀⢂⠰⣿⣷⣿⣷⣿⣿⣷⣿⣶⣷⣽⣮⣵⣜⣶⡴⣮⣝⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣾⡹⢾⣿⣿⣿⣿⣿⣿⡿⢣⣛⠜⡠⢉⠿⣿⣿⣿⣿⣿⡦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡽⣌⠆⡐⢀⡈⠄⠂⠭⡙⢋⠟⡛⢟⠻⢟⠿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣧⢻⡹⣿⣿⣿⡿⣟⠣⣍⠣⢜⢢⡑⢦⣜⡽⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢆⣠⢀⢀⡈⢤⣷⣯⣿⣮⣷⣮⣷⣬⣮⣤⣳⣌⣦⣱⣊⡵⣩⢟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⢾⣻⣽⢣⡳⡹⢿⡿⣵⢊⡱⢠⡍⢦⣣⣟⡿⣾⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣙⠦⣹⣯⣀⡘⡿⢻⠿⡻⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣾⢯⣗⣯⢯⡝⣆⠳⣜⢧⡟⣷⣻⣾⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣯⡗⣯⣜⣿⣴⣧⣮⣵⣎⡶⣤⣃⣆⢦⡱⣨⢱⡩⢍⣋⢟⡹⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢯⣿⣽⣻⢾⣝⡾⣽⢎⡷⣈⠎⡝⣎⢟⣿⣿⣿⣿⣿⣿⣿⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⡙⣿⢸⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣾⣿⣷⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣞⡷⢯⣟⡾⣽⣳⡟⡶⣥⢚⡘⣤⢋⠾⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣧⣙⡯⢜⣳⣌⡖⣌⢦⣡⢋⡜⡩⢍⢫⡙⣋⠟⡛⢟⡻⢟⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢷⣯⣟⣳⢎⡳⢧⣏⠿⣽⢖⡯⣞⡶⣍⢏⣿⣿⣿⣿⣿⣿⣿⣿⣧⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠧⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣼⣷⣽⣶⣳⣮⣷⣾⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣾⣽⣻⢮⡱⢫⡜⣹⢎⡽⢺⡵⢻⡜⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢤⡛⣷⢸⡏⣍⢫⠝⣋⠟⡹⢛⠻⡛⢿⠻⠿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢯⣿⡽⣧⣻⡕⣮⡱⢎⡔⢣⢚⡕⢺⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣝⡷⢺⣿⣾⣿⣿⣾⣽⣷⣯⣷⣽⣦⣽⣜⣦⣳⣌⡶⣰⣎⡼⣧⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢯⣿⣽⢯⡷⡙⢦⢻⡜⣬⡓⣎⡜⣣⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀ ⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⡼⣯⢹⡟⢿⠻⡟⠿⡿⢿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⢫⣟⡯⣟⢾⡹⣏⠳⣉⠢⡙⡟⣶⡹⢆⡿⣱⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀ ⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡼⣧⢻⣽⣶⣷⣮⣷⣼⣎⣦⣵⣢⢦⡱⣌⣣⢍⡹⣩⠛⣝⣫⢟⡿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣫⢞⡵⣋⠶⡱⣍⠳⢄⠢⢱⡙⢦⡙⢮⡜⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣖⠀⠀⠀⠀⠀⠀ ⠀⠰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣹⢧⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣾⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⡼⣝⢮⡱⢎⡵⣊⡕⣣⢎⡳⣌⢇⠾⣱⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀ ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢺⣧⢿⣳⣜⣦⣕⢮⣡⢏⣭⢫⡝⣋⠟⡛⡟⡻⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣹⢚⡶⣽⣺⢵⣫⢶⡝⣮⢻⡵⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢆⠀⠀⠀⠀ ⠀⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢯⡷⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⣿⣴⣫⣼⣍⣟⣿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⣷⡿⣯⢷⣏⢿⣼⣳⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀ ⠀⠀⠼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢺⣗⣿⣭⣋⣟⣹⢋⡟⡹⢛⡛⣟⠻⡟⢿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣽⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀ ⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡽⣾⣽⣿⣿⣿⣿⣿⣾⣿⣷⣿⣼⣷⣿⣮⣷⣵⣦⣧⣝⣮⣝⣯⣻⣽⣻⣟⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀ ⠀⠀⡸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣞⡷⣯⢟⡛⣟⠻⣟⠿⡿⢿⢿⡿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠆⠀ ⠀⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣺⣽⣻⣿⣿⣾⣿⣾⣿⣽⣾⣶⣳⣭⣾⣴⣣⡽⣌⣯⣹⣙⣏⡻⣝⢯⣛⣿⣻⣟⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀ ⠀⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣳⣿⢿⢻⠟⡿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄ ⠀⢀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣞⡷⣿⣧⣿⣾⣵⣯⣾⣼⣳⣮⣷⣭⢯⣹⣍⣻⣙⡟⣛⡟⣛⢻⡛⡟⢿⡻⣟⠿⣿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷ ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢺⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏ ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢻⣞⣿⣦⣳⣴⣦⣵⣬⣖⣭⣞⣭⣏⡿⣹⣛⣟⣻⠻⣟⢻⠟⡿⣻⠿⣟⡿⣟⡿⣿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀ ``` }