jacksaw / Blutopia BON Blackjack

// ==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() {
  ```
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⢆⡱⢫⡟⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⢿⣻⢿⣟⡿⡤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠠⠀⢂⡘⢦⡳⣏⣾⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣞⣿⣳⣁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠐⠈⣌⢣⡑⢦⣙⢮⣳⢻⡾⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣾⢷⣿⢯⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣌⡳⢈⡒⡌⡖⣭⢺⡭⣞⡥⣏⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣟⡾⣏⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡈⢑⡣⢜⡜⡱⣌⢧⡽⣲⣽⢻⣾⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣽⣻⡽⣷⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠁⠂⠐⢈⠐⡡⠊⢎⡳⣟⠾⣝⡾⣛⣾⢳⢯⡻⡝⣯⢟⡿⣻⢿⣟⡿⣟⣿⢻⠿⡿⣿⢿⡿⣿⣿⢿⣾⣿⣿⣷⡿⣽⣳⠭⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠐⣸⢮⣷⡱⣭⣞⡵⣏⢿⡱⣏⠷⣎⣟⢮⢳⡙⡴⢋⡴⢩⠞⡼⡙⢮⠘⣉⠣⡙⠤⢋⡹⢱⠫⣟⢿⣽⣿⣟⣿⣯⣟⡷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⢭⣻⣽⣿⡷⣯⢻⣜⣣⢟⣼⡻⣝⣮⣛⢦⡙⡖⢣⠜⣡⠚⡔⣩⠂⢇⢢⠱⡱⢌⡒⠤⡃⠵⣈⠞⣽⣾⣿⣿⣽⣯⠷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠠⣈⣶⣽⣾⡿⣽⢏⡷⣎⢷⣫⠾⣽⣹⢶⡹⣎⡵⣍⢳⢪⢅⡫⠴⣡⢋⡜⢢⢣⡑⢎⡸⢐⡉⢖⡡⢚⡜⣯⣿⣿⣯⣟⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⡸⣟⣿⡿⣽⣻⢎⣷⡹⣎⣷⣛⣧⢯⣗⡻⣜⡞⣬⢇⡳⢊⡕⢣⢆⢣⠜⣡⠆⡍⢦⠡⠣⠜⢢⡑⢣⢜⣱⢯⣿⢿⡽⠌⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣁⢷⣻⣯⢿⣯⢷⣛⠶⣝⣳⢾⣹⢮⢷⡺⣝⢧⡻⣔⢫⡔⢫⠜⡡⢎⢎⡜⢢⡙⡜⠤⢋⡅⣋⠦⡙⢆⢮⡹⣟⣾⣿⡻⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠰⢬⢏⣷⡿⣟⣮⢳⣭⢻⣭⣟⣯⣿⣯⣿⣷⣯⣿⣳⣮⣳⣜⢣⢎⡱⢎⡖⣸⢡⠚⣄⠫⠔⡘⡔⢢⠍⢎⢲⡹⣽⢾⡷⣟⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡉⢆⢫⣞⢿⡝⣮⢳⢮⣟⣼⢻⣞⡷⢯⡳⣏⢿⡻⣟⡿⣷⢯⣟⣎⠖⣭⢞⡵⣎⡵⣂⠧⣙⠰⣉⠦⡙⡌⢶⣹⢯⣟⣿⡱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⡐⢬⢷⡞⣯⡝⣮⢏⣷⣚⣮⢷⣻⣾⣿⣷⣿⣞⣷⣯⣟⣿⣻⡾⣝⠎⡜⢯⡾⣿⣽⢿⣻⣮⢷⡜⣦⣑⢚⢦⣻⣯⡿⣞⠥⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⡄⢫⠞⡑⢊⠱⠉⠞⣲⣛⠾⣏⡿⣹⢾⡹⢣⢏⠾⣽⣻⢾⣽⣻⢭⡚⣌⢣⢛⣷⣯⣿⣧⡝⣎⡝⠶⡭⡞⢦⣻⣯⢿⡉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠰⣎⡷⣞⣧⡚⠀⠀⠀⠀⡘⠴⣩⠿⣜⣳⡱⢎⡵⣋⢮⡟⣷⢯⣟⣾⢣⠷⡱⢌⠦⡙⣎⠿⣹⠻⡟⣷⢾⡱⢣⠝⡲⢯⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢌⣻⣽⣻⡽⣶⡹⠄⠀⢌⠰⣌⡳⣝⣯⢳⡧⣝⣏⢶⡹⣎⡿⣽⣻⢾⣝⡯⢏⡵⢊⠖⡱⢌⡚⢥⠓⡜⢤⠣⡙⢥⢋⡵⣻⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠂⢳⣳⢯⣟⡾⣝⢦⠈⣂⠳⡜⣽⢺⡼⣳⡽⣞⣼⣳⢿⣹⣟⡷⢯⣛⣮⡝⣮⠰⣉⢎⡱⠌⡜⢢⡙⡜⢢⡑⡩⢆⢣⢺⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠡⢏⡿⣾⣽⢫⣮⡑⠤⡛⣼⢣⡯⣗⡯⢷⣛⡾⣽⣞⣷⣻⣾⢿⡿⣷⢿⣞⣳⣵⢪⠴⡩⢜⠡⡒⠌⡥⢒⡱⢊⢆⠯⣼⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠭⢳⢧⣛⡧⣷⣙⢦⡙⣦⢏⡷⣹⢞⡯⣯⣽⢳⣞⡷⣯⣟⣯⠿⣝⠻⡜⡭⠻⣍⠚⡵⣊⠵⣡⢋⡔⢣⠜⣡⠞⡰⢭⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠾⣱⠿⣼⡹⢮⡱⣎⠿⣜⢧⢯⣳⠷⣭⣟⡾⡽⢧⣻⣜⠳⣌⠳⡩⠔⢣⠌⡓⢬⢃⡞⢤⠣⡜⢣⡙⣤⢛⡥⢫⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠠⢉⢧⡳⣭⢻⡜⣯⢞⣵⣻⣳⢯⡾⣽⢯⣷⣞⣷⣬⣳⡹⣌⠣⡜⢱⢊⠖⡸⢂⡳⢌⢣⠜⡰⣋⠖⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡘⢦⡻⣜⢧⣻⡜⣯⢞⡵⣯⣿⣿⣿⣿⣿⣾⣽⣾⣽⣿⣽⣷⣎⡕⡪⢜⡡⢓⡜⡌⢦⡙⡔⠡⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢉⠲⣝⢮⡳⢧⡻⣜⢯⡽⣳⡽⣞⣯⣟⡻⣙⢛⠻⣻⢿⡿⣟⢯⡛⡕⢪⠔⡣⢜⡘⠆⠱⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢪⠔⡹⢮⡝⣧⢻⡜⣧⢻⡵⣛⣾⢳⣯⢷⣹⢮⡗⣧⢛⡼⢌⠦⡑⢮⡑⢎⡱⢊⠔⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢞⡡⣛⡼⣣⢟⡼⣣⠿⣜⠿⣼⣻⣞⣯⢷⣻⣼⢣⢏⡲⣉⠖⡩⢆⡙⢦⠱⡉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢭⡚⣵⢣⡟⣵⢯⣞⡵⣻⢭⡟⡶⣓⠮⡜⢭⡒⣍⠣⢎⠴⡡⢎⡕⢪⡑⢎⡱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢟⡼⣣⢿⡹⡾⣼⣹⢧⡟⣾⣱⢏⡷⣙⢦⡱⢌⠳⣌⠲⡑⢎⡜⡥⡙⢦⡑⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠭⣞⡵⣛⡮⣗⢿⣱⢯⠾⣝⡾⣭⣟⡾⣵⢮⣱⢋⠶⣈⢧⣙⠲⣜⡡⢝⢢⡹⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡹⢎⡷⣫⢷⣹⡞⣧⢟⣻⡽⣽⣳⢯⡿⣽⣞⡷⣯⢻⡭⢶⢩⠓⢦⡙⢬⠲⣑⢻⣷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠱⣏⡞⣷⢫⣶⢻⡼⣫⣗⢯⡷⣯⠿⣽⠳⢯⡝⣎⢳⡙⢎⡲⡙⢦⡙⢦⡙⠤⠈⣿⣿⣿⣷⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠄⠛⠼⡙⢞⠻⡜⡳⢏⠷⣞⣻⡼⢧⡻⣜⢫⠖⣜⡸⢆⡝⣪⢕⡹⢦⡙⢦⡙⠆⠀⢾⣿⣿⣿⣿⣿⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠌⣀⡾⡀⢄⡀⠀⠀⠀⠈⣈⠀⣈⣟⣧⢻⣌⢳⡚⡴⢣⢏⡼⣡⢎⡵⢪⡱⢣⡝⠠⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣭⡳⣖⡤⣄⣠⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠄⡌⠀⠀⠌⢢⣝⣣⠷⣌⢯⡻⣝⢯⣟⢧⡛⣵⣻⣼⡳⣎⢷⣹⢣⠟⣜⡲⡱⢎⡜⣣⢽⡓⠄⠀⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣱⣳⣎⡷⣯⣛⡷⣚⡴⣠⢄⣀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⡔⢤⢃⡜⢤⣉⠒⡀⠀⢈⠜⢤⡿⣜⣯⠽⣎⡳⡭⢞⢮⡳⣙⢾⣳⢯⡿⣽⡺⣵⢫⡟⢦⢳⡙⢮⣜⡷⡋⠔⠀⠀⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣞⣿⣽⣯⣟⡷⣽⡖⣯⢾⣹⣞⣵⣲⢦⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣄⢢⢵⣸⡼⣧⣻⣜⠧⢦⣉⠀⠀⠰⣈⠲⣟⡹⣎⠿⣼⡹⣝⣫⠶⣍⠧⣻⡽⣯⣟⣷⣻⡵⣻⡜⣯⢇⣿⣳⢏⠇⠡⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣷⣿⣿⣿⣳⣿⡾⣽⣻⣾⣽⣳⢯⣟⡶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⢀⢡⡘⣌⡟⣼⣿⣿⣿⣿⣼⡟⡄⢀⠀⠀⡁⠀⢡⣏⡘⣏⠛⣤⢹⡌⣧⢋⡙⣌⢡⣿⣡⢻⡜⣇⣿⢡⢻⣸⢻⡜⢡⠈⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣿⣿⣿⣿⣿⣿⣿⣏⡟⣧⣼⢹⡟⣤⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠄⢢⡱⣜⣮⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡱⣃⠀⢀⠐⠈⢠⣯⠵⣯⡻⣵⢫⡞⣵⢫⠷⣌⢻⡶⣯⢿⣽⣻⣞⣯⢿⡽⡏⢎⠁⠂⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣷⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⡄⢢⠱⣤⢫⣷⣽⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣛⡄⠀⠀⡌⢀⠰⣏⢿⡱⣟⡼⢧⡻⣜⢯⡳⣌⢳⡿⣽⣻⡾⣷⣻⢾⢏⠓⡁⠂⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⠀⠀⢀⠠⡐⡌⢤⠳⣜⣣⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷⡌⠀⠐⢨⠀⡜⣿⣺⢽⣺⡝⣧⣻⠼⣧⣛⠤⣫⣟⣷⢿⡽⡷⢏⠋⠄⠃⢀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⠀⢠⡘⣤⠳⡼⣜⣷⣻⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢀⠣⡘⢸⣷⢯⣛⡶⣏⠷⣭⢟⡶⢭⣚⣱⢿⣞⢯⠹⡑⠊⠌⠐⠀⠀⠀⠀⠀⠀⠠⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢀⣶⡽⣞⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⢄⠓⡌⢳⣿⢯⣝⠾⣭⣻⢧⣻⡼⢧⡳⠘⡏⠜⢂⠡⠐⠡⠈⠀⠀⠀⠀⠀⠀⠐⣤⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠐⣌⢘⡰⠉⢞⡛⠎⠛⠱⠋⠉⠑⠙⠋⠓⠡⢎⠘⣀⠂⡁⠂⠠⠀⠀⠀⠀⠀⢄⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡅⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⢡⣂⡶⣤⣳⣼⣟⣶⣳⡾⣴⣦⣤⣤⣖⡴⣎⢧⡛⣤⣒⡄⡁⠀⠀⠀⠀⠀⡈⡔⣋⢟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣖⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣛⢏⡻⠹⣿⠁⠁⠹⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣴⣦⣼⣷⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⢐⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⡔⠀⠀⠀⠀⢁⣰⣎⣴⣈⣦⡑⣬⢡⡉⢌⠈⣁⠫⣙⠹⣋⠟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢻⠟⡝⠀⠀⠀⠀⠀⠿⡿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣷⣾⣾⣾⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⡳⣼⡱⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣧⣾⡔⠈⠀⠄⠀⢀⡸⣄⣄⣊⣄⢂⡡⢉⠜⣩⠋⠟⡛⠟⡿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢞⣵⣳⢏⡷⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⡿⢆⠁⠀⠀⠀⠂⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣼⣷⣮⣷⣼⣳⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣫⢾⣽⣻⢼⡱⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⢾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣦⣓⡆⢀⠦⣄⠀⡀⢰⡠⡑⣨⠉⡝⢩⠛⣛⠻⡛⠿⠿⡿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⢿⣳⣟⣮⢳⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⡛⢿⣿⣿⣿⣿⣿⣿⣿⡗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⣹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢇⠠⢈⠀⢂⠰⣿⣷⣿⣷⣿⣿⣷⣿⣶⣷⣽⣮⣵⣜⣶⡴⣮⣝⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣾⡹⢾⣿⣿⣿⣿⣿⣿⡿⢣⣛⠜⡠⢉⠿⣿⣿⣿⣿⣿⡦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡽⣌⠆⡐⢀⡈⠄⠂⠭⡙⢋⠟⡛⢟⠻⢟⠿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣧⢻⡹⣿⣿⣿⡿⣟⠣⣍⠣⢜⢢⡑⢦⣜⡽⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢆⣠⢀⢀⡈⢤⣷⣯⣿⣮⣷⣮⣷⣬⣮⣤⣳⣌⣦⣱⣊⡵⣩⢟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⢾⣻⣽⢣⡳⡹⢿⡿⣵⢊⡱⢠⡍⢦⣣⣟⡿⣾⣿⣿⣿⣿⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣙⠦⣹⣯⣀⡘⡿⢻⠿⡻⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⡽⣾⢯⣗⣯⢯⡝⣆⠳⣜⢧⡟⣷⣻⣾⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣯⡗⣯⣜⣿⣴⣧⣮⣵⣎⡶⣤⣃⣆⢦⡱⣨⢱⡩⢍⣋⢟⡹⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢯⣿⣽⣻⢾⣝⡾⣽⢎⡷⣈⠎⡝⣎⢟⣿⣿⣿⣿⣿⣿⣿⡃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⡙⣿⢸⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣾⣿⣷⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣞⡷⢯⣟⡾⣽⣳⡟⡶⣥⢚⡘⣤⢋⠾⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣧⣙⡯⢜⣳⣌⡖⣌⢦⣡⢋⡜⡩⢍⢫⡙⣋⠟⡛⢟⡻⢟⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢷⣯⣟⣳⢎⡳⢧⣏⠿⣽⢖⡯⣞⡶⣍⢏⣿⣿⣿⣿⣿⣿⣿⣿⣧⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠧⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣿⣼⣷⣽⣶⣳⣮⣷⣾⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣾⣽⣻⢮⡱⢫⡜⣹⢎⡽⢺⡵⢻⡜⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢤⡛⣷⢸⡏⣍⢫⠝⣋⠟⡹⢛⠻⡛⢿⠻⠿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢯⣿⡽⣧⣻⡕⣮⡱⢎⡔⢣⢚⡕⢺⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣀⠀⠀⠀⠀⠀⠀⠀⠀
  ⠀⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣝⡷⢺⣿⣾⣿⣿⣾⣽⣷⣯⣷⣽⣦⣽⣜⣦⣳⣌⡶⣰⣎⡼⣧⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢯⣿⣽⢯⡷⡙⢦⢻⡜⣬⡓⣎⡜⣣⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀
  ⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⡼⣯⢹⡟⢿⠻⡟⠿⡿⢿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⢫⣟⡯⣟⢾⡹⣏⠳⣉⠢⡙⡟⣶⡹⢆⡿⣱⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀
  ⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡼⣧⢻⣽⣶⣷⣮⣷⣼⣎⣦⣵⣢⢦⡱⣌⣣⢍⡹⣩⠛⣝⣫⢟⡿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣫⢞⡵⣋⠶⡱⣍⠳⢄⠢⢱⡙⢦⡙⢮⡜⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣖⠀⠀⠀⠀⠀⠀
  ⠀⠰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣹⢧⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣾⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⡼⣝⢮⡱⢎⡵⣊⡕⣣⢎⡳⣌⢇⠾⣱⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠀⠀⠀
  ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⢺⣧⢿⣳⣜⣦⣕⢮⣡⢏⣭⢫⡝⣋⠟⡛⡟⡻⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣹⢚⡶⣽⣺⢵⣫⢶⡝⣮⢻⡵⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢆⠀⠀⠀⠀
  ⠀⠀⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢯⡷⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣷⣿⣴⣫⣼⣍⣟⣿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢿⣷⡿⣯⢷⣏⢿⣼⣳⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀
  ⠀⠀⠼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢺⣗⣿⣭⣋⣟⣹⢋⡟⡹⢛⡛⣟⠻⡟⢿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣽⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀
  ⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡽⣾⣽⣿⣿⣿⣿⣿⣾⣿⣷⣿⣼⣷⣿⣮⣷⣵⣦⣧⣝⣮⣝⣯⣻⣽⣻⣟⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀
  ⠀⠀⡸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣞⡷⣯⢟⡛⣟⠻⣟⠿⡿⢿⢿⡿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠆⠀
  ⠀⠀⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣺⣽⣻⣿⣿⣾⣿⣾⣿⣽⣾⣶⣳⣭⣾⣴⣣⡽⣌⣯⣹⣙⣏⡻⣝⢯⣛⣿⣻⣟⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀
  ⠀⠀⢺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣳⣿⢿⢻⠟⡿⢿⠿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄
  ⠀⢀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣞⡷⣿⣧⣿⣾⣵⣯⣾⣼⣳⣮⣷⣭⢯⣹⣍⣻⣙⡟⣛⡟⣛⢻⡛⡟⢿⡻⣟⠿⣿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡷
  ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢺⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏
  ⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢻⣞⣿⣦⣳⣴⣦⣵⣬⣖⣭⣞⣭⣏⡿⣹⣛⣟⣻⠻⣟⢻⠟⡿⣻⠿⣟⡿⣟⡿⣿⢿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀
  ```
}