diff --git a/dist/BlueMarble-For-GreasyFork.user.js b/dist/BlueMarble-For-GreasyFork.user.js index 6d13596..eb3f285 100644 --- a/dist/BlueMarble-For-GreasyFork.user.js +++ b/dist/BlueMarble-For-GreasyFork.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.433 +// @version 0.88.440 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -425,599 +425,6 @@ Getting Y ${pixelY}-${pixelY + drawSizeY}`); return _colorpalette; }; - // src/templateManager.js - var _TemplateManager_instances, loadTemplate_fn, storeTemplates_fn, parseBlueMarble_fn, parseOSU_fn, calculateCorrectPixelsOnTile_And_FilterTile_fn; - var TemplateManager = class { - /** The constructor for the {@link TemplateManager} class. - * @since 0.55.8 - */ - constructor(name2, version2, overlay) { - __privateAdd(this, _TemplateManager_instances); - this.name = name2; - this.version = version2; - this.overlay = overlay; - this.templatesVersion = "1.0.0"; - this.userID = null; - this.encodingBase = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"; - this.tileSize = 1e3; - this.drawMult = 3; - this.paletteTolerance = 3; - this.paletteBM = colorpaletteForBlueMarble(this.paletteTolerance); - this.template = null; - this.templateState = ""; - this.templatesArray = []; - this.templatesJSON = null; - this.templatesShouldBeDrawn = true; - this.templatePixelsCorrect = null; - this.shouldFilterColor = /* @__PURE__ */ new Map(); - } - /** Creates the JSON object to store templates in - * @returns {{ whoami: string, scriptVersion: string, schemaVersion: string, templates: Object }} The JSON object - * @since 0.65.4 - */ - async createJSON() { - return { - "whoami": this.name.replace(" ", ""), - // Name of userscript without spaces - "scriptVersion": this.version, - // Version of userscript - "schemaVersion": this.templatesVersion, - // Version of JSON schema - "templates": {} - // The templates - }; - } - /** Creates the template from the inputed file blob - * @param {File} blob - The file blob to create a template from - * @param {string} name - The display name of the template - * @param {Array} coords - The coordinates of the top left corner of the template - * @since 0.65.77 - */ - async createTemplate(blob, name2, coords2) { - if (!this.templatesJSON) { - this.templatesJSON = await this.createJSON(); - console.log(`Creating JSON...`); - } - this.overlay.handleDisplayStatus(`Creating template at ${coords2.join(", ")}...`); - const template = new Template({ - displayName: name2, - sortID: 0, - // Object.keys(this.templatesJSON.templates).length || 0, // Uncomment this to enable multiple templates (1/2) - authorID: numberToEncoded(this.userID || 0, this.encodingBase), - file: blob, - coords: coords2 - }); - const { templateTiles, templateTilesBuffers } = await template.createTemplateTiles(this.tileSize, this.paletteBM); - template.chunked = templateTiles; - const _pixels = { "total": template.pixelCount.total, "colors": Object.fromEntries(template.pixelCount.colors) }; - this.templatesJSON.templates[`${template.sortID} ${template.authorID}`] = { - "name": template.displayName, - // Display name of template - "coords": coords2.join(", "), - // The coords of the template - "enabled": true, - "pixels": _pixels, - // The total pixels in the template - "tiles": templateTilesBuffers - // Stores the chunked tile buffers - }; - this.templatesArray = []; - this.templatesArray.push(template); - this.overlay.handleDisplayStatus(`Template created at ${coords2.join(", ")}!`); - console.log(Object.keys(this.templatesJSON.templates).length); - console.log(this.templatesJSON); - console.log(this.templatesArray); - console.log(JSON.stringify(this.templatesJSON)); - await __privateMethod(this, _TemplateManager_instances, storeTemplates_fn).call(this); - } - /** Deletes a template from the JSON object. - * Also delete's the corrosponding {@link Template} class instance - */ - deleteTemplate() { - } - /** Disables the template from view - */ - async disableTemplate() { - if (!this.templatesJSON) { - this.templatesJSON = await this.createJSON(); - console.log(`Creating JSON...`); - } - } - /** Draws all templates on the specified tile. - * This method handles the rendering of template overlays on individual tiles. - * @param {File} tileBlob - The pixels that are placed on a tile - * @param {Array} tileCoords - The tile coordinates [x, y] - * @since 0.65.77 - */ - async drawTemplateOnTile(tileBlob, tileCoords) { - if (!this.templatesShouldBeDrawn) { - return tileBlob; - } - const drawSize = this.tileSize * this.drawMult; - tileCoords = tileCoords[0].toString().padStart(4, "0") + "," + tileCoords[1].toString().padStart(4, "0"); - console.log(`Searching for templates in tile: "${tileCoords}"`); - const templateArray = this.templatesArray; - console.log(templateArray); - templateArray.sort((a, b) => { - return a.sortID - b.sortID; - }); - console.log(templateArray); - const templatesToDraw = templateArray.map((template) => { - const matchingTiles = Object.keys(template.chunked).filter( - (tile) => tile.startsWith(tileCoords) - ); - if (matchingTiles.length === 0) { - return null; - } - const matchingTileBlobs = matchingTiles.map((tile) => { - const coords2 = tile.split(","); - return { - instance: template, - bitmap: template.chunked[tile], - chunked32: template.chunked32?.[tile], - tileCoords: [coords2[0], coords2[1]], - pixelCoords: [coords2[2], coords2[3]] - }; - }); - return matchingTileBlobs?.[0]; - }).filter(Boolean); - console.log(templatesToDraw); - const templateCount = templatesToDraw?.length || 0; - console.log(`templateCount = ${templateCount}`); - if (templateCount > 0) { - const totalPixels = templateArray.filter((template) => { - const matchingTiles = Object.keys(template.chunked).filter( - (tile) => tile.startsWith(tileCoords) - ); - return matchingTiles.length > 0; - }).reduce((sum, template) => sum + (template.pixelCount.total || 0), 0); - const pixelCountFormatted = new Intl.NumberFormat().format(totalPixels); - this.overlay.handleDisplayStatus( - `Displaying ${templateCount} template${templateCount == 1 ? "" : "s"}. -Total pixels: ${pixelCountFormatted}` - ); - } else { - this.overlay.handleDisplayStatus(`Sleeping -Version: ${this.version}`); - return tileBlob; - } - const tileBitmap = await createImageBitmap(tileBlob); - const canvas = new OffscreenCanvas(drawSize, drawSize); - const context = canvas.getContext("2d"); - context.imageSmoothingEnabled = false; - context.beginPath(); - context.rect(0, 0, drawSize, drawSize); - context.clip(); - context.clearRect(0, 0, drawSize, drawSize); - context.drawImage(tileBitmap, 0, 0, drawSize, drawSize); - const tileBeforeTemplates = context.getImageData(0, 0, drawSize, drawSize); - const tileBeforeTemplates32 = new Uint32Array(tileBeforeTemplates.data.buffer); - for (const template of templatesToDraw) { - console.log(`Template:`); - console.log(template); - const templateHasErased = !!template.instance.pixelCount?.colors?.get(-1); - let templateBeforeFilter32 = template.chunked32.slice(); - const coordXtoDrawAt = Number(template.pixelCoords[0]) * this.drawMult; - const coordYtoDrawAt = Number(template.pixelCoords[1]) * this.drawMult; - if (this.shouldFilterColor.size == 0 && !templateHasErased) { - context.drawImage(template.bitmap, coordXtoDrawAt, coordYtoDrawAt); - } - if (!templateBeforeFilter32) { - const templateBeforeFilter = context.getImageData(coordXtoDrawAt, coordYtoDrawAt, template.bitmap.width, template.bitmap.height); - templateBeforeFilter32 = new Uint32Array(templateBeforeFilter.data.buffer); - } - const timer = Date.now(); - const { - correctPixels: pixelsCorrect, - filteredTemplate: templateAfterFilter - } = __privateMethod(this, _TemplateManager_instances, calculateCorrectPixelsOnTile_And_FilterTile_fn).call(this, { - tile: tileBeforeTemplates32, - template: templateBeforeFilter32, - templateInfo: [coordXtoDrawAt, coordYtoDrawAt, template.bitmap.width, template.bitmap.height] - }); - let pixelsCorrectTotal = 0; - const transparentColorID = 0; - for (const [color, total] of pixelsCorrect) { - if (color == transparentColorID) { - continue; - } - pixelsCorrectTotal += total; - } - if (this.shouldFilterColor.size != 0 || templateHasErased) { - console.log("Colors to filter: ", this.shouldFilterColor); - context.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(templateAfterFilter.buffer), template.bitmap.width, template.bitmap.height)), coordXtoDrawAt, coordYtoDrawAt); - } - console.log(`Finished calculating correct pixels & filtering colors for the tile ${tileCoords} in ${(Date.now() - timer) / 1e3} seconds! -There are ${pixelsCorrectTotal} correct pixels.`); - if (typeof template.instance.pixelCount["correct"] == "undefined") { - template.instance.pixelCount["correct"] = {}; - } - template.instance.pixelCount["correct"][tileCoords] = pixelsCorrect; - } - return await canvas.convertToBlob({ type: "image/png" }); - } - /** Imports the JSON object, and appends it to any JSON object already loaded - * @param {string} json - The JSON string to parse - */ - importJSON(json) { - console.log(`Importing JSON...`); - console.log(json); - if (json?.whoami == "BlueMarble") { - __privateMethod(this, _TemplateManager_instances, parseBlueMarble_fn).call(this, json); - } - } - /** Sets the `templatesShouldBeDrawn` boolean to a value. - * @param {boolean} value - The value to set the boolean to - * @since 0.73.7 - */ - setTemplatesShouldBeDrawn(value) { - this.templatesShouldBeDrawn = value; - } - }; - _TemplateManager_instances = new WeakSet(); - /** Generates a {@link Template} class instance from the JSON object template - */ - loadTemplate_fn = function() { - }; - storeTemplates_fn = async function() { - GM.setValue("bmTemplates", JSON.stringify(this.templatesJSON)); - }; - parseBlueMarble_fn = async function(json) { - console.log(`Parsing BlueMarble...`); - const templates = json.templates; - console.log(`BlueMarble length: ${Object.keys(templates).length}`); - if (Object.keys(templates).length > 0) { - for (const template in templates) { - const templateKey = template; - const templateValue = templates[template]; - console.log(`Template Key: ${templateKey}`); - if (templates.hasOwnProperty(template)) { - const templateKeyArray = templateKey.split(" "); - const sortID = Number(templateKeyArray?.[0]); - const authorID = templateKeyArray?.[1] || "0"; - const displayName = templateValue.name || `Template ${sortID || ""}`; - const pixelCount = { - total: templateValue.pixels.total, - colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value])) - }; - const tilesbase64 = templateValue.tiles; - const templateTiles = {}; - const templateTiles32 = {}; - const actualTileSize = this.tileSize * this.drawMult; - for (const tile in tilesbase64) { - console.log(tile); - if (tilesbase64.hasOwnProperty(tile)) { - const encodedTemplateBase64 = tilesbase64[tile]; - const templateUint8Array = base64ToUint8(encodedTemplateBase64); - const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); - const templateBitmap = await createImageBitmap(templateBlob); - templateTiles[tile] = templateBitmap; - const canvas = new OffscreenCanvas(actualTileSize, actualTileSize); - const context = canvas.getContext("2d"); - context.drawImage(templateBitmap, 0, 0); - const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height); - templateTiles32[tile] = new Uint32Array(imageData.data.buffer); - } - } - const template2 = new Template({ - displayName, - sortID: sortID || this.templatesArray?.length || 0, - authorID: authorID || "" - //coords: coords, - }); - template2.pixelCount = pixelCount; - template2.chunked = templateTiles; - template2.chunked32 = templateTiles32; - this.templatesArray.push(template2); - console.log(this.templatesArray); - console.log(`^^^ This ^^^`); - } - } - } - }; - /** Parses the OSU! Place JSON object - */ - parseOSU_fn = function() { - }; - /** Calculates the correct pixels on this tile. - * In addition, this function filters colors based on user input. - * In addition, this function modifies colors to properly display (#deface). - * This function has multiple purposes only to reduce iterations of scans over every pixel on the template. - * @param {Object} params - Object containing all parameters - * @param {Uint32Array} params.tile - The tile without templates as a Uint32Array - * @param {Uint32Array} params.template - The template without filtering as a Uint32Array - * @param {Array} params.templateInfo - Information about template location and size - * @returns {{correctPixels: Map, filteredTemplate: Uint32Array}} A Map containing the color IDs (keys) and how many correct pixels there are for that color (values) - */ - calculateCorrectPixelsOnTile_And_FilterTile_fn = function({ - tile: tile32, - template: template32, - templateInfo: templateInformation - }) { - const pixelSize = this.drawMult; - const tileWidth = this.tileSize * pixelSize; - const tileHeight = tileWidth; - const tilePixelOffsetY = -1; - const tilePixelOffsetX = 0; - const templateCoordX = templateInformation[0]; - const templateCoordY = templateInformation[1]; - const templateWidth = templateInformation[2]; - const templateHeight = templateInformation[3]; - const tolerance = this.paletteTolerance; - const { palette: _, LUT: lookupTable } = this.paletteBM; - const _colorpalette = /* @__PURE__ */ new Map(); - for (let templateRow = 1; templateRow < templateHeight; templateRow += pixelSize) { - for (let templateColumn = 1; templateColumn < templateWidth; templateColumn += pixelSize) { - const tileRow = templateCoordY + templateRow + tilePixelOffsetY; - const tileColumn = templateCoordX + templateColumn + tilePixelOffsetX; - const tilePixelAbove = tile32[tileRow * tileWidth + tileColumn]; - const templatePixel = template32[templateRow * templateWidth + templateColumn]; - const templatePixelAlpha = templatePixel >>> 24 & 255; - const tilePixelAlpha = tilePixelAbove >>> 24 & 255; - const bestTemplateColorID = lookupTable.get(templatePixel) ?? -2; - if (this.shouldFilterColor.get(bestTemplateColorID)) { - template32[templateRow * templateWidth + templateColumn] = tilePixelAbove; - } - if (bestTemplateColorID == -1) { - const blackTrans = 536870912; - if (this.shouldFilterColor.get(bestTemplateColorID)) { - template32[templateRow * templateWidth + templateColumn] = 0; - } else { - if ((tileRow / pixelSize & 1) == (tileColumn / pixelSize & 1)) { - template32[templateRow * templateWidth + templateColumn] = blackTrans; - template32[(templateRow - 1) * templateWidth + (templateColumn - 1)] = blackTrans; - template32[(templateRow - 1) * templateWidth + (templateColumn + 1)] = blackTrans; - template32[(templateRow + 1) * templateWidth + (templateColumn - 1)] = blackTrans; - template32[(templateRow + 1) * templateWidth + (templateColumn + 1)] = blackTrans; - } else { - template32[templateRow * templateWidth + templateColumn] = 0; - template32[(templateRow - 1) * templateWidth + templateColumn] = blackTrans; - template32[(templateRow + 1) * templateWidth + templateColumn] = blackTrans; - template32[templateRow * templateWidth + (templateColumn - 1)] = blackTrans; - template32[templateRow * templateWidth + (templateColumn + 1)] = blackTrans; - } - } - } - if (bestTemplateColorID == -1 && tilePixelAbove <= tolerance) { - const colorIDcount2 = _colorpalette.get(bestTemplateColorID); - _colorpalette.set(bestTemplateColorID, colorIDcount2 ? colorIDcount2 + 1 : 1); - continue; - } - if (templatePixelAlpha <= tolerance || tilePixelAlpha <= tolerance) { - continue; - } - const bestTileColorID = lookupTable.get(tilePixelAbove) ?? -2; - if (bestTileColorID != bestTemplateColorID) { - continue; - } - const colorIDcount = _colorpalette.get(bestTemplateColorID); - _colorpalette.set(bestTemplateColorID, colorIDcount ? colorIDcount + 1 : 1); - } - } - console.log(`List of template pixels that match the tile:`); - console.log(_colorpalette); - return { correctPixels: _colorpalette, filteredTemplate: template32 }; - }; - - // src/apiManager.js - var ApiManager = class { - /** Constructor for ApiManager class - * @param {TemplateManager} templateManager - * @since 0.11.34 - */ - constructor(templateManager2) { - this.templateManager = templateManager2; - this.disableAll = false; - this.chargeRefillTimerID = ""; - this.coordsTilePixel = []; - this.templateCoordsTilePixel = []; - } - /** Determines if the spontaneously received response is something we want. - * Otherwise, we can ignore it. - * Note: Due to aggressive compression, make your calls like `data['jsonData']['name']` instead of `data.jsonData.name` - * - * @param {Overlay} overlay - The Overlay class instance - * @since 0.11.1 - */ - spontaneousResponseListener(overlay) { - window.addEventListener("message", async (event) => { - const data = event.data; - const dataJSON = data["jsonData"]; - if (!(data && data["source"] === "blue-marble")) { - return; - } - if (!data["endpoint"]) { - return; - } - const endpointText = data["endpoint"]?.split("?")[0].split("/").filter((s) => s && isNaN(Number(s))).filter((s) => s && !s.includes(".")).pop(); - console.log(`%cBlue Marble%c: Recieved message about "%s"`, "color: cornflowerblue;", "", endpointText); - switch (endpointText) { - case "me": - if (dataJSON["status"] && dataJSON["status"]?.toString()[0] != "2") { - overlay.handleDisplayError(`You are not logged in! -Could not fetch userdata.`); - return; - } - const nextLevelPixels = Math.ceil(Math.pow(Math.floor(dataJSON["level"]) * Math.pow(30, 0.65), 1 / 0.65) - dataJSON["pixelsPainted"]); - console.log(dataJSON["id"]); - if (!!dataJSON["id"] || dataJSON["id"] === 0) { - console.log(numberToEncoded( - dataJSON["id"], - "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" - )); - } - this.templateManager.userID = dataJSON["id"]; - if (this.chargeRefillTimerID.length != 0) { - const chargeRefillTimer = document.querySelector("#" + this.chargeRefillTimerID); - if (chargeRefillTimer) { - const chargeData = dataJSON["charges"]; - chargeRefillTimer.dataset["endDate"] = Date.now() + (chargeData["max"] - chargeData["count"]) * chargeData["cooldownMs"]; - } - } - overlay.updateInnerHTML("bm-user-droplets", `Droplets: ${new Intl.NumberFormat().format(dataJSON["droplets"])}`); - overlay.updateInnerHTML("bm-user-nextlevel", `Next level in ${new Intl.NumberFormat().format(nextLevelPixels)} pixel${nextLevelPixels == 1 ? "" : "s"}`); - break; - case "pixel": - const coordsTile = data["endpoint"].split("?")[0].split("/").filter((s) => s && !isNaN(Number(s))); - const payloadExtractor = new URLSearchParams(data["endpoint"].split("?")[1]); - const coordsPixel = [payloadExtractor.get("x"), payloadExtractor.get("y")]; - if (this.coordsTilePixel.length && (!coordsTile.length || !coordsPixel.length)) { - overlay.handleDisplayError(`Coordinates are malformed! -Did you try clicking the canvas first?`); - return; - } - this.coordsTilePixel = [...coordsTile, ...coordsPixel]; - const displayTP = serverTPtoDisplayTP(coordsTile, coordsPixel); - const spanElements = document.querySelectorAll("span"); - for (const element of spanElements) { - if (element.textContent.trim().includes(`${displayTP[0]}, ${displayTP[1]}`)) { - let displayCoords = document.querySelector("#bm-display-coords"); - const text = `(Tl X: ${coordsTile[0]}, Tl Y: ${coordsTile[1]}, Px X: ${coordsPixel[0]}, Px Y: ${coordsPixel[1]})`; - if (!displayCoords) { - displayCoords = document.createElement("span"); - displayCoords.id = "bm-display-coords"; - displayCoords.textContent = text; - displayCoords.style = "margin-left: calc(var(--spacing)*3); font-size: small;"; - element.parentNode.parentNode.insertAdjacentElement("afterend", displayCoords); - } else { - displayCoords.textContent = text; - } - } - } - break; - case "tiles": - let tileCoordsTile = data["endpoint"].split("/"); - tileCoordsTile = [parseInt(tileCoordsTile[tileCoordsTile.length - 2]), parseInt(tileCoordsTile[tileCoordsTile.length - 1].replace(".png", ""))]; - const blobUUID = data["blobID"]; - const blobData = data["blobData"]; - const timer = Date.now(); - const templateBlob = await this.templateManager.drawTemplateOnTile(blobData, tileCoordsTile); - console.log(`Finished loading the tile in ${(Date.now() - timer) / 1e3} seconds!`); - window.postMessage({ - source: "blue-marble", - blobID: blobUUID, - blobData: templateBlob, - blink: data["blink"] - }); - break; - case "robots": - this.disableAll = dataJSON["userscript"]?.toString().toLowerCase() == "false"; - break; - } - }); - } - // Sends a heartbeat to the telemetry server - async sendHeartbeat(version2) { - console.log("Sending heartbeat to telemetry server..."); - let userSettings2 = GM_getValue("bmUserSettings", "{}"); - userSettings2 = JSON.parse(userSettings2); - if (!userSettings2 || !userSettings2.telemetry || !userSettings2.uuid) { - console.log("Telemetry is disabled, not sending heartbeat."); - return; - } - const ua = navigator.userAgent; - let browser = await this.getBrowserFromUA(ua); - let os = this.getOS(ua); - GM_xmlhttpRequest({ - method: "POST", - url: "https://telemetry.thebluecorner.net/heartbeat", - headers: { - "Content-Type": "application/json" - }, - data: JSON.stringify({ - uuid: userSettings2.uuid, - version: version2, - browser, - os - }), - onload: (response) => { - if (response.status !== 200) { - consoleError("Failed to send heartbeat:", response.statusText); - } - }, - onerror: (error) => { - consoleError("Error sending heartbeat:", error); - } - }); - } - async getBrowserFromUA(ua = navigator.userAgent) { - ua = ua || ""; - if (ua.includes("OPR/") || ua.includes("Opera")) return "Opera"; - if (ua.includes("Edg/")) return "Edge"; - if (ua.includes("Vivaldi")) return "Vivaldi"; - if (ua.includes("YaBrowser")) return "Yandex"; - if (ua.includes("Kiwi")) return "Kiwi"; - if (ua.includes("Brave")) return "Brave"; - if (ua.includes("Firefox/")) return "Firefox"; - if (ua.includes("Chrome/")) return "Chrome"; - if (ua.includes("Safari/")) return "Safari"; - if (navigator.brave && typeof navigator.brave.isBrave === "function") { - if (await navigator.brave.isBrave()) return "Brave"; - } - return "Unknown"; - } - getOS(ua = navigator.userAgent) { - ua = ua || ""; - if (/Windows NT 11/i.test(ua)) return "Windows 11"; - if (/Windows NT 10/i.test(ua)) return "Windows 10"; - if (/Windows NT 6\.3/i.test(ua)) return "Windows 8.1"; - if (/Windows NT 6\.2/i.test(ua)) return "Windows 8"; - if (/Windows NT 6\.1/i.test(ua)) return "Windows 7"; - if (/Windows NT 6\.0/i.test(ua)) return "Windows Vista"; - if (/Windows NT 5\.1|Windows XP/i.test(ua)) return "Windows XP"; - if (/Mac OS X 10[_\.]15/i.test(ua)) return "macOS Catalina"; - if (/Mac OS X 10[_\.]14/i.test(ua)) return "macOS Mojave"; - if (/Mac OS X 10[_\.]13/i.test(ua)) return "macOS High Sierra"; - if (/Mac OS X 10[_\.]12/i.test(ua)) return "macOS Sierra"; - if (/Mac OS X 10[_\.]11/i.test(ua)) return "OS X El Capitan"; - if (/Mac OS X 10[_\.]10/i.test(ua)) return "OS X Yosemite"; - if (/Mac OS X 10[_\.]/i.test(ua)) return "macOS"; - if (/Android/i.test(ua)) return "Android"; - if (/iPhone|iPad|iPod/i.test(ua)) return "iOS"; - if (/Linux/i.test(ua)) return "Linux"; - return "Unknown"; - } - }; - - // src/confetttiManager.js - var ConfettiManager = class { - /** The constructor for the confetti manager. - * @since 0.88.356 - */ - constructor() { - this.confettiCount = Math.ceil(80 / 1300 * window.innerWidth); - this.colorPalette = colorpalette.slice(1); - } - /** Immedently creates confetti inside the parent element. - * @param {HTMLElement} parentElement - The parent element to create confetti inside of - * @since 0.88.356 - */ - createConfetti(parentElement) { - const confettiContainer = document.createElement("div"); - for (let currentCount = 0; currentCount < this.confettiCount; currentCount++) { - const confettiShard = document.createElement("confetti-piece"); - confettiShard.style.setProperty("--x", `${Math.random() * 100}vw`); - confettiShard.style.setProperty("--delay", `${Math.random() * 2}s`); - confettiShard.style.setProperty("--duration", `${3 + Math.random() * 3}s`); - confettiShard.style.setProperty("--rot", `${Math.random() * 360}deg`); - confettiShard.style.setProperty("--size", `${6 + Math.random() * 6}px`); - confettiShard.style.backgroundColor = `rgb(${this.colorPalette[Math.floor(Math.random() * this.colorPalette.length)].rgb.join(",")})`; - confettiShard.onanimationend = () => { - if (confettiShard.parentNode.childElementCount <= 1) { - confettiShard.parentNode.remove(); - } else { - confettiShard.remove(); - } - }; - confettiContainer.appendChild(confettiShard); - } - parentElement.appendChild(confettiContainer); - } - }; - var BlueMarbleConfettiPiece = class extends HTMLElement { - }; - customElements.define("confetti-piece", BlueMarbleConfettiPiece); - // src/Overlay.js var _Overlay_instances, createElement_fn, applyAttribute_fn; var Overlay = class { @@ -2231,6 +1638,696 @@ Did you try clicking the canvas first?`); } }; + // src/WindowWizard.js + var _WindowWizard_instances, displaySchemaHealth_fn; + var WindowWizard = class extends Overlay { + /** Constructor for the Template Wizard window + * @param {string} name - The name of the userscript + * @param {string} version - The version of the userscript + * @param {string} schemaVersionBleedingEdge - The bleeding edge of schema versions for Blue Marble + * @since 0.88.434 + * @see {@link Overlay#constructor} for examples + */ + constructor(name2, version2, schemaVersionBleedingEdge) { + super(name2, version2); + __privateAdd(this, _WindowWizard_instances); + this.window = null; + this.windowID = "bm-window-wizard"; + this.windowParent = document.body; + this.currentJSON = JSON.parse(GM_getValue("bmTemplates", "{}")); + this.scriptVersion = this.currentJSON?.scriptVersion; + this.schemaVersion = this.currentJSON?.schemaVersion; + this.schemaHealth = void 0; + this.schemaVersionBleedingEdge = schemaVersionBleedingEdge; + } + /** Spawns a Template Wizard window. + * If another template wizard window already exists, we DON'T spawn another! + * Parent/child relationships in the DOM structure below are indicated by indentation. + * @since 0.88.434 + */ + buildWindow() { + if (document.querySelector(`#${this.windowID}`)) { + this.handleDisplayError("Template Wizard window already exists!"); + return; + } + this.window = this.addDiv({ "id": this.windowID, "class": "bm-window", "style": "z-index: 9001;" }).addDragbar().addButton({ "class": "bm-button-circle", "textContent": "\u25BC", "aria-label": 'Minimize window "Template Wizard"', "data-button-status": "expanded" }, (instance, button) => { + button.onclick = () => instance.handleMinimization(button); + button.ontouchend = () => { + button.click(); + }; + }).buildElement().addDiv().buildElement().addButton({ "class": "bm-button-circle", "textContent": "\u{1F7AA}", "aria-label": 'Close window "Template Wizard"' }, (instance, button) => { + button.onclick = () => { + document.querySelector(`#${this.windowID}`)?.remove(); + }; + button.ontouchend = () => { + button.click(); + }; + }).buildElement().buildElement().addDiv({ "class": "bm-window-content" }).addDiv({ "class": "bm-container bm-center-vertically" }).addHeader(1, { "textContent": "Template Wizard" }).buildElement().buildElement().addHr().buildElement().addDiv({ "class": "bm-container" }).addP({ "id": "bm-wizard-status", "textContent": "Loading template storage status..." }).buildElement().buildElement().addDiv({ "class": "bm-container bm-scrollable" }).addSpan({ "textContent": "Detected templates:" }).buildElement().buildElement().buildElement().buildElement().buildOverlay(this.windowParent); + __privateMethod(this, _WindowWizard_instances, displaySchemaHealth_fn).call(this); + } + }; + _WindowWizard_instances = new WeakSet(); + /** Determines how "healthy" the template storage is. + * @since 0.88.436 + */ + displaySchemaHealth_fn = function() { + const schemaVersionArray = this.schemaVersion.split(/[-\.\+]/); + const schemaVersionBleedingEdgeArray = this.schemaVersionBleedingEdge.split(/[-\.\+]/); + let schemaHealthBanner = ""; + if (schemaVersionArray[0] == schemaVersionBleedingEdgeArray[0]) { + if (schemaVersionArray[1] == schemaVersionBleedingEdgeArray[1]) { + schemaHealthBanner = "Template storage health: Healthy!
No futher action required. (Reason: Semantic version matches)"; + this.schemaHealth = "Good"; + } else { + schemaHealthBanner = "Template storage health: Poor!
You can still use your template, but some features may not work. It is recommended that you update Blue Marble's template storage. (Reason: MINOR version mismatch)"; + this.schemaHealth = "Poor"; + } + } else { + schemaHealthBanner = "Template storage health: Dead!
Blue Marble can not load the template storage. (Reason: MAJOR version mismatch)"; + this.schemaHealth = "Dead"; + } + this.updateInnerHTML("#bm-wizard-status", `${schemaHealthBanner}
The current schema version (${escapeHTML(this.schemaVersion)}) was created during Blue Marble version ${escapeHTML(this.scriptVersion)}.
The current Blue Marble version (${escapeHTML(this.version)}) requires schema version ${escapeHTML(this.schemaVersionBleedingEdge)}.
If you don't want to upgrade the template storage (schema), then downgrade Blue Marble to version ${escapeHTML(this.scriptVersion)}.`); + if (this.schemaHealth == "Poor" || this.schemaHealth == "Bad") { + const buttonOptions = new Overlay(this.name, this.version); + buttonOptions.addDiv({ "class": "bm-container bm-flex-center bm-center-vertically" }).addButton({ "textContent": `Update template storage to ${this.schemaVersionBleedingEdge}` }, (instance, button) => { + button.onclick = () => { + }; + }).buildElement().buildElement().buildOverlay(document.querySelector("#bm-wizard-status").parentNode); + } + }; + + // src/templateManager.js + var _TemplateManager_instances, loadTemplate_fn, storeTemplates_fn, parseBlueMarble_fn, parseOSU_fn, calculateCorrectPixelsOnTile_And_FilterTile_fn; + var TemplateManager = class { + /** The constructor for the {@link TemplateManager} class. + * @since 0.55.8 + */ + constructor(name2, version2, overlay) { + __privateAdd(this, _TemplateManager_instances); + this.name = name2; + this.version = version2; + this.overlay = overlay; + this.schemaVersion = "1.1.0"; + this.userID = null; + this.encodingBase = "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + this.tileSize = 1e3; + this.drawMult = 3; + this.paletteTolerance = 3; + this.paletteBM = colorpaletteForBlueMarble(this.paletteTolerance); + this.template = null; + this.templateState = ""; + this.templatesArray = []; + this.templatesJSON = null; + this.templatesShouldBeDrawn = true; + this.templatePixelsCorrect = null; + this.shouldFilterColor = /* @__PURE__ */ new Map(); + } + /** Creates the JSON object to store templates in + * @returns {{ whoami: string, scriptVersion: string, schemaVersion: string, templates: Object }} The JSON object + * @since 0.65.4 + */ + async createJSON() { + return { + "whoami": this.name.replace(" ", ""), + // Name of userscript without spaces + "scriptVersion": this.version, + // Version of userscript + "schemaVersion": this.schemaVersion, + // Version of JSON schema + "templates": {} + // The templates + }; + } + /** Creates the template from the inputed file blob + * @param {File} blob - The file blob to create a template from + * @param {string} name - The display name of the template + * @param {Array} coords - The coordinates of the top left corner of the template + * @since 0.65.77 + */ + async createTemplate(blob, name2, coords2) { + if (!this.templatesJSON) { + this.templatesJSON = await this.createJSON(); + console.log(`Creating JSON...`); + } + this.overlay.handleDisplayStatus(`Creating template at ${coords2.join(", ")}...`); + const template = new Template({ + displayName: name2, + sortID: 0, + // Object.keys(this.templatesJSON.templates).length || 0, // Uncomment this to enable multiple templates (1/2) + authorID: numberToEncoded(this.userID || 0, this.encodingBase), + file: blob, + coords: coords2 + }); + const { templateTiles, templateTilesBuffers } = await template.createTemplateTiles(this.tileSize, this.paletteBM); + template.chunked = templateTiles; + const _pixels = { "total": template.pixelCount.total, "colors": Object.fromEntries(template.pixelCount.colors) }; + this.templatesJSON.templates[`${template.sortID} ${template.authorID}`] = { + "name": template.displayName, + // Display name of template + "coords": coords2.join(", "), + // The coords of the template + "enabled": true, + "pixels": _pixels, + // The total pixels in the template + "tiles": templateTilesBuffers + // Stores the chunked tile buffers + }; + this.templatesArray = []; + this.templatesArray.push(template); + this.overlay.handleDisplayStatus(`Template created at ${coords2.join(", ")}!`); + console.log(Object.keys(this.templatesJSON.templates).length); + console.log(this.templatesJSON); + console.log(this.templatesArray); + console.log(JSON.stringify(this.templatesJSON)); + await __privateMethod(this, _TemplateManager_instances, storeTemplates_fn).call(this); + } + /** Deletes a template from the JSON object. + * Also delete's the corrosponding {@link Template} class instance + */ + deleteTemplate() { + } + /** Disables the template from view + */ + async disableTemplate() { + if (!this.templatesJSON) { + this.templatesJSON = await this.createJSON(); + console.log(`Creating JSON...`); + } + } + /** Draws all templates on the specified tile. + * This method handles the rendering of template overlays on individual tiles. + * @param {File} tileBlob - The pixels that are placed on a tile + * @param {Array} tileCoords - The tile coordinates [x, y] + * @since 0.65.77 + */ + async drawTemplateOnTile(tileBlob, tileCoords) { + if (!this.templatesShouldBeDrawn) { + return tileBlob; + } + const drawSize = this.tileSize * this.drawMult; + tileCoords = tileCoords[0].toString().padStart(4, "0") + "," + tileCoords[1].toString().padStart(4, "0"); + console.log(`Searching for templates in tile: "${tileCoords}"`); + const templateArray = this.templatesArray; + console.log(templateArray); + templateArray.sort((a, b) => { + return a.sortID - b.sortID; + }); + console.log(templateArray); + const templatesToDraw = templateArray.map((template) => { + const matchingTiles = Object.keys(template.chunked).filter( + (tile) => tile.startsWith(tileCoords) + ); + if (matchingTiles.length === 0) { + return null; + } + const matchingTileBlobs = matchingTiles.map((tile) => { + const coords2 = tile.split(","); + return { + instance: template, + bitmap: template.chunked[tile], + chunked32: template.chunked32?.[tile], + tileCoords: [coords2[0], coords2[1]], + pixelCoords: [coords2[2], coords2[3]] + }; + }); + return matchingTileBlobs?.[0]; + }).filter(Boolean); + console.log(templatesToDraw); + const templateCount = templatesToDraw?.length || 0; + console.log(`templateCount = ${templateCount}`); + if (templateCount > 0) { + const totalPixels = templateArray.filter((template) => { + const matchingTiles = Object.keys(template.chunked).filter( + (tile) => tile.startsWith(tileCoords) + ); + return matchingTiles.length > 0; + }).reduce((sum, template) => sum + (template.pixelCount.total || 0), 0); + const pixelCountFormatted = new Intl.NumberFormat().format(totalPixels); + this.overlay.handleDisplayStatus( + `Displaying ${templateCount} template${templateCount == 1 ? "" : "s"}. +Total pixels: ${pixelCountFormatted}` + ); + } else { + this.overlay.handleDisplayStatus(`Sleeping +Version: ${this.version}`); + return tileBlob; + } + const tileBitmap = await createImageBitmap(tileBlob); + const canvas = new OffscreenCanvas(drawSize, drawSize); + const context = canvas.getContext("2d"); + context.imageSmoothingEnabled = false; + context.beginPath(); + context.rect(0, 0, drawSize, drawSize); + context.clip(); + context.clearRect(0, 0, drawSize, drawSize); + context.drawImage(tileBitmap, 0, 0, drawSize, drawSize); + const tileBeforeTemplates = context.getImageData(0, 0, drawSize, drawSize); + const tileBeforeTemplates32 = new Uint32Array(tileBeforeTemplates.data.buffer); + for (const template of templatesToDraw) { + console.log(`Template:`); + console.log(template); + const templateHasErased = !!template.instance.pixelCount?.colors?.get(-1); + let templateBeforeFilter32 = template.chunked32.slice(); + const coordXtoDrawAt = Number(template.pixelCoords[0]) * this.drawMult; + const coordYtoDrawAt = Number(template.pixelCoords[1]) * this.drawMult; + if (this.shouldFilterColor.size == 0 && !templateHasErased) { + context.drawImage(template.bitmap, coordXtoDrawAt, coordYtoDrawAt); + } + if (!templateBeforeFilter32) { + const templateBeforeFilter = context.getImageData(coordXtoDrawAt, coordYtoDrawAt, template.bitmap.width, template.bitmap.height); + templateBeforeFilter32 = new Uint32Array(templateBeforeFilter.data.buffer); + } + const timer = Date.now(); + const { + correctPixels: pixelsCorrect, + filteredTemplate: templateAfterFilter + } = __privateMethod(this, _TemplateManager_instances, calculateCorrectPixelsOnTile_And_FilterTile_fn).call(this, { + tile: tileBeforeTemplates32, + template: templateBeforeFilter32, + templateInfo: [coordXtoDrawAt, coordYtoDrawAt, template.bitmap.width, template.bitmap.height] + }); + let pixelsCorrectTotal = 0; + const transparentColorID = 0; + for (const [color, total] of pixelsCorrect) { + if (color == transparentColorID) { + continue; + } + pixelsCorrectTotal += total; + } + if (this.shouldFilterColor.size != 0 || templateHasErased) { + console.log("Colors to filter: ", this.shouldFilterColor); + context.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(templateAfterFilter.buffer), template.bitmap.width, template.bitmap.height)), coordXtoDrawAt, coordYtoDrawAt); + } + console.log(`Finished calculating correct pixels & filtering colors for the tile ${tileCoords} in ${(Date.now() - timer) / 1e3} seconds! +There are ${pixelsCorrectTotal} correct pixels.`); + if (typeof template.instance.pixelCount["correct"] == "undefined") { + template.instance.pixelCount["correct"] = {}; + } + template.instance.pixelCount["correct"][tileCoords] = pixelsCorrect; + } + return await canvas.convertToBlob({ type: "image/png" }); + } + /** Imports the JSON object, and appends it to any JSON object already loaded + * @param {string} json - The JSON string to parse + */ + importJSON(json) { + console.log(`Importing JSON...`); + console.log(json); + if (json?.whoami == "BlueMarble") { + __privateMethod(this, _TemplateManager_instances, parseBlueMarble_fn).call(this, json); + } + } + /** Sets the `templatesShouldBeDrawn` boolean to a value. + * @param {boolean} value - The value to set the boolean to + * @since 0.73.7 + */ + setTemplatesShouldBeDrawn(value) { + this.templatesShouldBeDrawn = value; + } + }; + _TemplateManager_instances = new WeakSet(); + /** Generates a {@link Template} class instance from the JSON object template + */ + loadTemplate_fn = function() { + }; + storeTemplates_fn = async function() { + GM.setValue("bmTemplates", JSON.stringify(this.templatesJSON)); + }; + parseBlueMarble_fn = async function(json) { + console.log(`Parsing BlueMarble...`); + const templates = json.templates; + console.log(`BlueMarble length: ${Object.keys(templates).length}`); + const schemaVersion = json?.schemaVersion; + const schemaVersionArray = schemaVersion.split(/[-\.\+]/); + const schemaVersionBleedingEdge = this.schemaVersion.split(/[-\.\+]/); + const scriptVersion = json?.scriptVersion; + console.log(`BlueMarble Template Schema: ${schemaVersion}; Script Version: ${scriptVersion}`); + if (schemaVersionArray[0] == schemaVersionBleedingEdge[0]) { + if (schemaVersionArray[1] == schemaVersionBleedingEdge[1]) { + loadSchemaVersion_1_x_x(); + } else { + const windowWizard = new WindowWizard(this.name, this.version, this.schemaVersion); + windowWizard.buildWindow(); + loadSchemaVersion_1_x_x(); + } + } else { + this.overlay.handleDisplayError(`Template version ${schemaVersion} is unsupported. +Use Blue Marble version ${scriptVersion} or load a new template.`); + } + async function loadSchemaVersion_1_x_x() { + if (Object.keys(templates).length > 0) { + for (const template in templates) { + const templateKey = template; + const templateValue = templates[template]; + console.log(`Template Key: ${templateKey}`); + if (templates.hasOwnProperty(template)) { + const templateKeyArray = templateKey.split(" "); + const sortID = Number(templateKeyArray?.[0]); + const authorID = templateKeyArray?.[1] || "0"; + const displayName = templateValue.name || `Template ${sortID || ""}`; + const pixelCount = { + total: templateValue.pixels.total, + colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value])) + }; + const tilesbase64 = templateValue.tiles; + const templateTiles = {}; + const templateTiles32 = {}; + const actualTileSize = this.tileSize * this.drawMult; + for (const tile in tilesbase64) { + console.log(tile); + if (tilesbase64.hasOwnProperty(tile)) { + const encodedTemplateBase64 = tilesbase64[tile]; + const templateUint8Array = base64ToUint8(encodedTemplateBase64); + const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); + const templateBitmap = await createImageBitmap(templateBlob); + templateTiles[tile] = templateBitmap; + const canvas = new OffscreenCanvas(actualTileSize, actualTileSize); + const context = canvas.getContext("2d"); + context.drawImage(templateBitmap, 0, 0); + const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height); + templateTiles32[tile] = new Uint32Array(imageData.data.buffer); + } + } + const template2 = new Template({ + displayName, + sortID: sortID || this.templatesArray?.length || 0, + authorID: authorID || "" + //coords: coords, + }); + template2.pixelCount = pixelCount; + template2.chunked = templateTiles; + template2.chunked32 = templateTiles32; + this.templatesArray.push(template2); + console.log(this.templatesArray); + console.log(`^^^ This ^^^`); + } + } + } + } + }; + /** Parses the OSU! Place JSON object + */ + parseOSU_fn = function() { + }; + /** Calculates the correct pixels on this tile. + * In addition, this function filters colors based on user input. + * In addition, this function modifies colors to properly display (#deface). + * This function has multiple purposes only to reduce iterations of scans over every pixel on the template. + * @param {Object} params - Object containing all parameters + * @param {Uint32Array} params.tile - The tile without templates as a Uint32Array + * @param {Uint32Array} params.template - The template without filtering as a Uint32Array + * @param {Array} params.templateInfo - Information about template location and size + * @returns {{correctPixels: Map, filteredTemplate: Uint32Array}} A Map containing the color IDs (keys) and how many correct pixels there are for that color (values) + */ + calculateCorrectPixelsOnTile_And_FilterTile_fn = function({ + tile: tile32, + template: template32, + templateInfo: templateInformation + }) { + const pixelSize = this.drawMult; + const tileWidth = this.tileSize * pixelSize; + const tileHeight = tileWidth; + const tilePixelOffsetY = -1; + const tilePixelOffsetX = 0; + const templateCoordX = templateInformation[0]; + const templateCoordY = templateInformation[1]; + const templateWidth = templateInformation[2]; + const templateHeight = templateInformation[3]; + const tolerance = this.paletteTolerance; + const { palette: _, LUT: lookupTable } = this.paletteBM; + const _colorpalette = /* @__PURE__ */ new Map(); + for (let templateRow = 1; templateRow < templateHeight; templateRow += pixelSize) { + for (let templateColumn = 1; templateColumn < templateWidth; templateColumn += pixelSize) { + const tileRow = templateCoordY + templateRow + tilePixelOffsetY; + const tileColumn = templateCoordX + templateColumn + tilePixelOffsetX; + const tilePixelAbove = tile32[tileRow * tileWidth + tileColumn]; + const templatePixel = template32[templateRow * templateWidth + templateColumn]; + const templatePixelAlpha = templatePixel >>> 24 & 255; + const tilePixelAlpha = tilePixelAbove >>> 24 & 255; + const bestTemplateColorID = lookupTable.get(templatePixel) ?? -2; + if (this.shouldFilterColor.get(bestTemplateColorID)) { + template32[templateRow * templateWidth + templateColumn] = tilePixelAbove; + } + if (bestTemplateColorID == -1) { + const blackTrans = 536870912; + if (this.shouldFilterColor.get(bestTemplateColorID)) { + template32[templateRow * templateWidth + templateColumn] = 0; + } else { + if ((tileRow / pixelSize & 1) == (tileColumn / pixelSize & 1)) { + template32[templateRow * templateWidth + templateColumn] = blackTrans; + template32[(templateRow - 1) * templateWidth + (templateColumn - 1)] = blackTrans; + template32[(templateRow - 1) * templateWidth + (templateColumn + 1)] = blackTrans; + template32[(templateRow + 1) * templateWidth + (templateColumn - 1)] = blackTrans; + template32[(templateRow + 1) * templateWidth + (templateColumn + 1)] = blackTrans; + } else { + template32[templateRow * templateWidth + templateColumn] = 0; + template32[(templateRow - 1) * templateWidth + templateColumn] = blackTrans; + template32[(templateRow + 1) * templateWidth + templateColumn] = blackTrans; + template32[templateRow * templateWidth + (templateColumn - 1)] = blackTrans; + template32[templateRow * templateWidth + (templateColumn + 1)] = blackTrans; + } + } + } + if (bestTemplateColorID == -1 && tilePixelAbove <= tolerance) { + const colorIDcount2 = _colorpalette.get(bestTemplateColorID); + _colorpalette.set(bestTemplateColorID, colorIDcount2 ? colorIDcount2 + 1 : 1); + continue; + } + if (templatePixelAlpha <= tolerance || tilePixelAlpha <= tolerance) { + continue; + } + const bestTileColorID = lookupTable.get(tilePixelAbove) ?? -2; + if (bestTileColorID != bestTemplateColorID) { + continue; + } + const colorIDcount = _colorpalette.get(bestTemplateColorID); + _colorpalette.set(bestTemplateColorID, colorIDcount ? colorIDcount + 1 : 1); + } + } + console.log(`List of template pixels that match the tile:`); + console.log(_colorpalette); + return { correctPixels: _colorpalette, filteredTemplate: template32 }; + }; + + // src/apiManager.js + var ApiManager = class { + /** Constructor for ApiManager class + * @param {TemplateManager} templateManager + * @since 0.11.34 + */ + constructor(templateManager2) { + this.templateManager = templateManager2; + this.disableAll = false; + this.chargeRefillTimerID = ""; + this.coordsTilePixel = []; + this.templateCoordsTilePixel = []; + } + /** Determines if the spontaneously received response is something we want. + * Otherwise, we can ignore it. + * Note: Due to aggressive compression, make your calls like `data['jsonData']['name']` instead of `data.jsonData.name` + * + * @param {Overlay} overlay - The Overlay class instance + * @since 0.11.1 + */ + spontaneousResponseListener(overlay) { + window.addEventListener("message", async (event) => { + const data = event.data; + const dataJSON = data["jsonData"]; + if (!(data && data["source"] === "blue-marble")) { + return; + } + if (!data["endpoint"]) { + return; + } + const endpointText = data["endpoint"]?.split("?")[0].split("/").filter((s) => s && isNaN(Number(s))).filter((s) => s && !s.includes(".")).pop(); + console.log(`%cBlue Marble%c: Recieved message about "%s"`, "color: cornflowerblue;", "", endpointText); + switch (endpointText) { + case "me": + if (dataJSON["status"] && dataJSON["status"]?.toString()[0] != "2") { + overlay.handleDisplayError(`You are not logged in! +Could not fetch userdata.`); + return; + } + const nextLevelPixels = Math.ceil(Math.pow(Math.floor(dataJSON["level"]) * Math.pow(30, 0.65), 1 / 0.65) - dataJSON["pixelsPainted"]); + console.log(dataJSON["id"]); + if (!!dataJSON["id"] || dataJSON["id"] === 0) { + console.log(numberToEncoded( + dataJSON["id"], + "!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~" + )); + } + this.templateManager.userID = dataJSON["id"]; + if (this.chargeRefillTimerID.length != 0) { + const chargeRefillTimer = document.querySelector("#" + this.chargeRefillTimerID); + if (chargeRefillTimer) { + const chargeData = dataJSON["charges"]; + chargeRefillTimer.dataset["endDate"] = Date.now() + (chargeData["max"] - chargeData["count"]) * chargeData["cooldownMs"]; + } + } + overlay.updateInnerHTML("bm-user-droplets", `Droplets: ${new Intl.NumberFormat().format(dataJSON["droplets"])}`); + overlay.updateInnerHTML("bm-user-nextlevel", `Next level in ${new Intl.NumberFormat().format(nextLevelPixels)} pixel${nextLevelPixels == 1 ? "" : "s"}`); + break; + case "pixel": + const coordsTile = data["endpoint"].split("?")[0].split("/").filter((s) => s && !isNaN(Number(s))); + const payloadExtractor = new URLSearchParams(data["endpoint"].split("?")[1]); + const coordsPixel = [payloadExtractor.get("x"), payloadExtractor.get("y")]; + if (this.coordsTilePixel.length && (!coordsTile.length || !coordsPixel.length)) { + overlay.handleDisplayError(`Coordinates are malformed! +Did you try clicking the canvas first?`); + return; + } + this.coordsTilePixel = [...coordsTile, ...coordsPixel]; + const displayTP = serverTPtoDisplayTP(coordsTile, coordsPixel); + const spanElements = document.querySelectorAll("span"); + for (const element of spanElements) { + if (element.textContent.trim().includes(`${displayTP[0]}, ${displayTP[1]}`)) { + let displayCoords = document.querySelector("#bm-display-coords"); + const text = `(Tl X: ${coordsTile[0]}, Tl Y: ${coordsTile[1]}, Px X: ${coordsPixel[0]}, Px Y: ${coordsPixel[1]})`; + if (!displayCoords) { + displayCoords = document.createElement("span"); + displayCoords.id = "bm-display-coords"; + displayCoords.textContent = text; + displayCoords.style = "margin-left: calc(var(--spacing)*3); font-size: small;"; + element.parentNode.parentNode.insertAdjacentElement("afterend", displayCoords); + } else { + displayCoords.textContent = text; + } + } + } + break; + case "tiles": + let tileCoordsTile = data["endpoint"].split("/"); + tileCoordsTile = [parseInt(tileCoordsTile[tileCoordsTile.length - 2]), parseInt(tileCoordsTile[tileCoordsTile.length - 1].replace(".png", ""))]; + const blobUUID = data["blobID"]; + const blobData = data["blobData"]; + const timer = Date.now(); + const templateBlob = await this.templateManager.drawTemplateOnTile(blobData, tileCoordsTile); + console.log(`Finished loading the tile in ${(Date.now() - timer) / 1e3} seconds!`); + window.postMessage({ + source: "blue-marble", + blobID: blobUUID, + blobData: templateBlob, + blink: data["blink"] + }); + break; + case "robots": + this.disableAll = dataJSON["userscript"]?.toString().toLowerCase() == "false"; + break; + } + }); + } + // Sends a heartbeat to the telemetry server + async sendHeartbeat(version2) { + console.log("Sending heartbeat to telemetry server..."); + let userSettings2 = GM_getValue("bmUserSettings", "{}"); + userSettings2 = JSON.parse(userSettings2); + if (!userSettings2 || !userSettings2.telemetry || !userSettings2.uuid) { + console.log("Telemetry is disabled, not sending heartbeat."); + return; + } + const ua = navigator.userAgent; + let browser = await this.getBrowserFromUA(ua); + let os = this.getOS(ua); + GM_xmlhttpRequest({ + method: "POST", + url: "https://telemetry.thebluecorner.net/heartbeat", + headers: { + "Content-Type": "application/json" + }, + data: JSON.stringify({ + uuid: userSettings2.uuid, + version: version2, + browser, + os + }), + onload: (response) => { + if (response.status !== 200) { + consoleError("Failed to send heartbeat:", response.statusText); + } + }, + onerror: (error) => { + consoleError("Error sending heartbeat:", error); + } + }); + } + async getBrowserFromUA(ua = navigator.userAgent) { + ua = ua || ""; + if (ua.includes("OPR/") || ua.includes("Opera")) return "Opera"; + if (ua.includes("Edg/")) return "Edge"; + if (ua.includes("Vivaldi")) return "Vivaldi"; + if (ua.includes("YaBrowser")) return "Yandex"; + if (ua.includes("Kiwi")) return "Kiwi"; + if (ua.includes("Brave")) return "Brave"; + if (ua.includes("Firefox/")) return "Firefox"; + if (ua.includes("Chrome/")) return "Chrome"; + if (ua.includes("Safari/")) return "Safari"; + if (navigator.brave && typeof navigator.brave.isBrave === "function") { + if (await navigator.brave.isBrave()) return "Brave"; + } + return "Unknown"; + } + getOS(ua = navigator.userAgent) { + ua = ua || ""; + if (/Windows NT 11/i.test(ua)) return "Windows 11"; + if (/Windows NT 10/i.test(ua)) return "Windows 10"; + if (/Windows NT 6\.3/i.test(ua)) return "Windows 8.1"; + if (/Windows NT 6\.2/i.test(ua)) return "Windows 8"; + if (/Windows NT 6\.1/i.test(ua)) return "Windows 7"; + if (/Windows NT 6\.0/i.test(ua)) return "Windows Vista"; + if (/Windows NT 5\.1|Windows XP/i.test(ua)) return "Windows XP"; + if (/Mac OS X 10[_\.]15/i.test(ua)) return "macOS Catalina"; + if (/Mac OS X 10[_\.]14/i.test(ua)) return "macOS Mojave"; + if (/Mac OS X 10[_\.]13/i.test(ua)) return "macOS High Sierra"; + if (/Mac OS X 10[_\.]12/i.test(ua)) return "macOS Sierra"; + if (/Mac OS X 10[_\.]11/i.test(ua)) return "OS X El Capitan"; + if (/Mac OS X 10[_\.]10/i.test(ua)) return "OS X Yosemite"; + if (/Mac OS X 10[_\.]/i.test(ua)) return "macOS"; + if (/Android/i.test(ua)) return "Android"; + if (/iPhone|iPad|iPod/i.test(ua)) return "iOS"; + if (/Linux/i.test(ua)) return "Linux"; + return "Unknown"; + } + }; + + // src/confetttiManager.js + var ConfettiManager = class { + /** The constructor for the confetti manager. + * @since 0.88.356 + */ + constructor() { + this.confettiCount = Math.ceil(80 / 1300 * window.innerWidth); + this.colorPalette = colorpalette.slice(1); + } + /** Immedently creates confetti inside the parent element. + * @param {HTMLElement} parentElement - The parent element to create confetti inside of + * @since 0.88.356 + */ + createConfetti(parentElement) { + const confettiContainer = document.createElement("div"); + for (let currentCount = 0; currentCount < this.confettiCount; currentCount++) { + const confettiShard = document.createElement("confetti-piece"); + confettiShard.style.setProperty("--x", `${Math.random() * 100}vw`); + confettiShard.style.setProperty("--delay", `${Math.random() * 2}s`); + confettiShard.style.setProperty("--duration", `${3 + Math.random() * 3}s`); + confettiShard.style.setProperty("--rot", `${Math.random() * 360}deg`); + confettiShard.style.setProperty("--size", `${6 + Math.random() * 6}px`); + confettiShard.style.backgroundColor = `rgb(${this.colorPalette[Math.floor(Math.random() * this.colorPalette.length)].rgb.join(",")})`; + confettiShard.onanimationend = () => { + if (confettiShard.parentNode.childElementCount <= 1) { + confettiShard.parentNode.remove(); + } else { + confettiShard.remove(); + } + }; + confettiContainer.appendChild(confettiShard); + } + parentElement.appendChild(confettiContainer); + } + }; + var BlueMarbleConfettiPiece = class extends HTMLElement { + }; + customElements.define("confetti-piece", BlueMarbleConfettiPiece); + // src/WindowFilter.js var _WindowFilter_instances, buildColorList_fn, sortColorList_fn, selectColorList_fn; var WindowFilter = class extends Overlay { diff --git a/dist/BlueMarble-Standalone.user.js b/dist/BlueMarble-Standalone.user.js index ef0238c..aa6b8f2 100644 --- a/dist/BlueMarble-Standalone.user.js +++ b/dist/BlueMarble-Standalone.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.433 +// @version 0.88.440 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -27,4 +27,4 @@ // License --> https://www.mozilla.org/en-US/MPL/2.0/ // Donate --> https://ko-fi.com/swingthevine -(()=>{var t=t=>{throw TypeError(t)},e=(e,i,n)=>i.has(e)?t("Cannot add the same private member more than once"):i instanceof WeakSet?i.add(e):i.set(e,n),i=(e,i,n)=>(((e,i)=>{i.has(e)||t("Cannot access private method")})(e,i),n);function n(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function s(...t){(0,console.log)(...t)}function o(...t){(0,console.error)(...t)}function a(t,e){if(0===t)return e[0];let i="";const n=e.length;for(;t>0;)i=e[t%n]+i,t=Math.floor(t/n);return i}function r(t){let e="";for(let i=0;i(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}var h,m,d,u,b,p,f=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],g=class{constructor({displayName:t="My template",t:i=0,i:n="",url:s="",file:o=null,coords:a=null,o:r=null,l:l={},h:c=1e3}={}){e(this,h),this.displayName=t,this.t=i,this.i=n,this.url=s,this.file=o,this.coords=a,this.o=r,this.l=l,this.h=c,this.m={total:0,colors:new Map}}async u(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),s=n.width,o=n.height;this.h=t;const a={},l={},c=new OffscreenCanvas(this.h,this.h),d=c.getContext("2d",{p:!0});c.width=s,c.height=o,d.imageSmoothingEnabled=!1,d.drawImage(n,0,0);let u=Date.now();const b=i(this,h,m).call(this,d.getImageData(0,0,s,o),e);console.log(`Calculating total pixels took ${(Date.now()-u)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.m={total:p,colors:b},u=Date.now();const f=new OffscreenCanvas(3,3),g=f.getContext("2d");g.clearRect(0,0,3,3),g.fillStyle="white",g.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:s.get(e)??-2;const a=o.get(n);o.set(n,a?a+1:1)}return console.log(o),o},d=new WeakSet,u=async function(){GM.setValue("bmTemplates",JSON.stringify(this.T))},b=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;if(console.log(`BlueMarble length: ${Object.keys(e).length}`),Object.keys(e).length>0)for(const t in e){const i=t,n=e[t];if(console.log(`Template Key: ${i}`),e.hasOwnProperty(t)){const t=i.split(" "),e=Number(t?.[0]),s=t?.[1]||"0",o=n.name||`Template ${e||""}`,a={total:n.pixels.total,colors:new Map(Object.entries(n.pixels.colors).map(([t,e])=>[Number(t),e]))},r=n.tiles,c={},h={},m=this.h*this.S;for(const t in r)if(console.log(t),r.hasOwnProperty(t)){const e=l(r[t]),i=new Blob([e],{type:"image/png"}),n=await createImageBitmap(i);c[t]=n;const s=new OffscreenCanvas(m,m).getContext("2d");s.drawImage(n,0,0);const o=s.getImageData(0,0,n.width,n.height);h[t]=new Uint32Array(o.data.buffer)}const d=new g({displayName:o,t:e||this.C?.length||0,i:s||""});d.m=a,d.o=c,d.l=h,this.C.push(d),console.log(this.C),console.log("^^^ This ^^^")}}},p=function({D:t,O:e,k:i}){const n=this.S,s=this.h*n,o=i[0],a=i[1],r=i[2],l=i[3],c=this.L,{palette:h,M:m}=this.N,d=new Map;for(let i=1;i>>24&255,g=b>>>24&255,w=m.get(p)??-2;if(this.B.get(w)&&(e[i*r+l]=b),-1==w){const t=536870912;this.B.get(w)?e[i*r+l]=0:(h/n&1)==(u/n&1)?(e[i*r+l]=t,e[(i-1)*r+(l-1)]=t,e[(i-1)*r+(l+1)]=t,e[(i+1)*r+(l-1)]=t,e[(i+1)*r+(l+1)]=t):(e[i*r+l]=0,e[(i-1)*r+l]=t,e[(i+1)*r+l]=t,e[i*r+(l-1)]=t,e[i*r+(l+1)]=t)}if(-1==w&&b<=c){const t=d.get(w);d.set(w,t?t+1:1);continue}if(f<=c||g<=c)continue;if((m.get(b)??-2)!=w)continue;const y=d.get(w);d.set(w,y?y+1:1)}return console.log("List of template pixels that match the tile:"),console.log(d),{I:d,P:e}};var w,y,v,x=class{constructor(){this.A=Math.ceil(80/1300*window.innerWidth),this.H=f.slice(1)}U(t){const e=document.createElement("div");for(let t=0;t{t.parentNode.childElementCount<=1?t.parentNode.remove():t.remove()},e.appendChild(t)}t.appendChild(e)}},$=class extends HTMLElement{};customElements.define("confetti-piece",$);var M,T,S,C,D=class{constructor(t,i){e(this,w),this.name=t,this.version=i,this.W=null,this.G="bm-o",this.F=null,this.Y=null,this._=[]}j(t){this.W=t}X(){return this._.length>0&&(this.Y=this._.pop()),this}R(t){t?.appendChild(this.F),this.F=null,this.Y=null,this._=[]}J(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"div",{},t)),this}V(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"p",{},t)),this}q(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"small",{},t)),this}Z(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"span",{},t)),this}K(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"details",{},t)),this}tt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"summary",{},t)),this}et(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"img",{},t)),this}it(t,e={},n=()=>{}){return n(this,i(this,w,y).call(this,"h"+t,{},e)),this}nt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"hr",{},t)),this}st(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"br",{},t)),this}ot(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"form",{},t)),this}rt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"fieldset",{},t)),this}lt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"legend",{},t)),this}ct(t={},e=()=>{}){const n=i(this,w,y).call(this,"label",{textContent:t.textContent??""});delete t.textContent;const s=i(this,w,y).call(this,"input",{type:"checkbox"},t);return n.insertBefore(s,n.firstChild),this.X(),e(this,n,s),this}ht(t={},e=()=>{}){const n=i(this,w,y).call(this,"label",{textContent:t.textContent??"",for:t.id??""});return delete t.textContent,this.X(),e(this,n,i(this,w,y).call(this,"select",{},t)),this}dt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"option",{},t)),this}ut(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"ol",{},t)),this}bt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"ul",{},t)),this}ft(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"menu",{},t)),this}gt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"li",{},t)),this}wt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"table",{},t)),this}yt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"caption",{},t)),this}vt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"thead",{},t)),this}xt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tbody",{},t)),this}$t(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tfoot",{},t)),this}Mt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tr",{},t)),this}Tt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"th",{},t)),this}St(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"td",{},t)),this}Ct(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"button",{},t)),this}Dt(t={},e=()=>{}){const n=t.title??t.textContent??"Help: No info";delete t.textContent,t.title=`Help: ${n}`;const s={textContent:"?",className:"bm-D",onclick:()=>{this.Ot(this.G,n)}};return e(this,i(this,w,y).call(this,"button",s,t)),this}kt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"input",{},t)),this}Lt(t={},e=()=>{}){const n=t.textContent??"";delete t.textContent;const s=i(this,w,y).call(this,"div"),o=i(this,w,y).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true"},t);this.X();const a=i(this,w,y).call(this,"button",{textContent:n});return this.X(),this.X(),a.addEventListener("click",()=>{o.click()}),o.addEventListener("change",()=>{a.style.maxWidth=`${a.offsetWidth}px`,o.files.length>0?a.textContent=o.files[0].name:a.textContent=n}),e(this,s,o,a),this}Nt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"textarea",{},t)),this}Bt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"div",{class:"bm-1h"},t)),this}It(t=Date.now(),e=500,n={},s=()=>{}){const o="bm-1l",a=n?.id||o+"-"+crypto.randomUUID().slice(0,8),r={class:o},l=i(this,w,y).call(this,"time",r,n);return l.id=a,l.dataset.endDate=t,setInterval(()=>{if(!l.isConnected)return;const t=Math.max(l.dataset.endDate-Date.now(),0),e=Math.floor(t/1e3),i=Math.floor(e/3600),n=Math.floor(e%60),s=Math.floor(e%3600/60);l.setAttribute("datetime",`PT${i}H${s}M${n}S`),l.textContent=String(i).padStart(2,"0")+":"+String(s).padStart(2,"0")+":"+String(n).padStart(2,"0")},e),s(this,l),this}Ot(t,e,i=!1){const n=document.getElementById(t.replace(/^#/,""));n&&(n instanceof HTMLInputElement?n.value=e:i?n.textContent=e:n.innerHTML=e)}Pt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1j"),i=t.closest(".bm-1h"),n=e.querySelector("h1"),s=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){s.style.height=s.scrollHeight+"px",e.style.width=e.scrollWidth+"px",s.style.height="0",s.addEventListener("transitionend",function e(){s.style.display="none",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)});const i=n.cloneNode(!0),o=i.textContent;t.nextElementSibling.appendChild(i),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${o}"`}else{const n=i.querySelector("h1"),o=n.textContent;n.remove(),s.style.display="",s.style.height="0",e.style.width="",s.style.height=s.scrollHeight+"px",s.addEventListener("transitionend",function e(){s.style.height="",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${o}"`}}At(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.Ht(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let i,n=!1,s=0,o=null,a=0,r=0,l=0,c=0,h=null;const m=()=>{if(n){const e=Math.abs(a-l),i=Math.abs(r-c);(e>.5||i>.5)&&(a=l,r=c,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),o=requestAnimationFrame(m)}},d=(d,f)=>{n=!0,h=t.getBoundingClientRect(),i=d-h.left,s=f-h.top;const g=window.getComputedStyle(t).transform;if(g&&"none"!==g){const t=new DOMMatrix(g);a=t.m41,r=t.m42}else a=h.left,r=h.top;l=a,c=r,document.body.style.userSelect="none",e.classList.add("bm-1c"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),o&&cancelAnimationFrame(o),m()},u=()=>{n=!1,o&&(cancelAnimationFrame(o),o=null),document.body.style.userSelect="",e.classList.remove("bm-1c"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{n&&h&&(l=t.clientX-i,c=t.clientY-s)},p=t=>{if(n&&h){const e=t.touches[0];if(!e)return;l=e.clientX-i,c=e.clientY-s,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),d(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(d(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}Ut(t){(0,console.info)(`${this.name}: ${t}`),this.Ot(this.G,"Status: "+t,!0)}Ht(t){(0,console.error)(`${this.name}: ${t}`),this.Ot(this.G,"Error: "+t,!0)}};w=new WeakSet,y=function(t,e={},n={}){const s=document.createElement(t);this.F?(this.Y?.appendChild(s),this._.push(this.Y),this.Y=s):(this.F=s,this.Y=s);for(const[t,n]of Object.entries(e))i(this,w,v).call(this,s,t,n);for(const[t,e]of Object.entries(n))i(this,w,v).call(this,s,t,e);return s},v=function(t,e,i){if("class"==e)t.classList.add(...i.split(/\s+/));else if("for"==e)t.htmlFor=i;else if("tabindex"==e)t.tabIndex=Number(i);else if("readonly"==e)t.readOnly="true"==i||"1"==i;else if("maxlength"==e)t.maxLength=Number(i);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=i;else if(e.startsWith("aria")){const n=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+n[0].toUpperCase()+n.slice(1)]=i}else t[e]=i};var O,k,L,N,B,I=class extends D{constructor(t){super(t.name,t.version),e(this,M),this.window=null,this.Wt="bm-Y",this.Gt=document.body,this.Ft=t.W?.Ft,this.Et='',this.Yt='',this._t=new Intl.NumberFormat,this.jt=new Intl.NumberFormat(void 0,{style:"percent",Xt:2,Rt:2}),this.Jt={Vt:"long",zt:"numeric",qt:"2-digit",Qt:"2-digit",Zt:"2-digit"};const{palette:i,M:n}=this.Ft.N;this.palette=i,this.Kt=0,this.te=0}ee(){if(document.querySelector(`#${this.Wt}`))return void this.Ht("Color Filter window already exists!");this.window=this.J({id:this.Wt,class:"bm-1j"}).Bt().Ct({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.Pt(e),e.ontouchend=()=>{e.click()}}).X().J().X().Ct({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Wt}`)?.remove()},e.ontouchend=()=>{e.click()}}).X().X().J({class:"bm-U"}).J({class:"bm-1b bm-Q"}).it(1,{textContent:"Color Filter"}).X().X().nt().X().J({class:"bm-1b bm-_ bm-Q",style:"gap: 1.5ch;"}).Ct({textContent:"Select All"},(t,e)=>{e.onclick=()=>i(this,M,C).call(this,!1)}).X().Ct({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>i(this,M,C).call(this,!0)}).X().X().J({class:"bm-1b bm-17"}).J({class:"bm-1b",style:"margin-left: 2.5ch; margin-right: 2.5ch;"}).J({class:"bm-1b"}).Z({id:"bm-R",innerHTML:"Tiles Loaded: 0 / ???"}).X().st().X().Z({id:"bm-M",innerHTML:"Correct Pixels: ???"}).X().st().X().Z({id:"bm-S",innerHTML:"Total Pixels: ???"}).X().st().X().Z({id:"bm-I",innerHTML:"Complete: ??? (???)"}).X().st().X().Z({id:"bm-J",innerHTML:"??? ???"}).X().X().J({class:"bm-1b"}).V({innerHTML:`Colors with the icon ${this.Et.replace("{e.onclick=t=>{t.preventDefault();const e=new FormData(document.querySelector(`#${this.Wt} form`)),n={};for(const[t,i]of e)n[t]=i;console.log(`Primary: ${n.sortPrimary}; Secondary: ${n.sortSecondary}; Unused: ${"on"==n.showUnused}`),i(this,M,S).call(this,n.sortPrimary,n.sortSecondary,"on"==n.showUnused)}}).X().X().X().X().X().X().X().R(this.Gt),this.At(`#${this.Wt}.bm-1j`,`#${this.Wt} .bm-1h`);const t=document.querySelector(`#${this.Wt} .bm-1b.bm-17`);let e=0,n=0;const s=new Map,o=new Map;for(const t of this.Ft.C){e+=t.m?.total??0??0;const i=t.m?.colors??new Map;for(const[t,e]of i){const i=Number(e)||0,n=o.get(t)??0;o.set(t,n+i)}const a=t.m?.correct??{};this.Kt+=Object.keys(a).length,this.te+=Object.keys(t.o).length;for(const t of Object.values(a))for(const[e,i]of t){const t=Number(i)||0;n+=t;const o=s.get(e)??0;s.set(e,o+t)}}console.log(`Tiles loaded: ${this.Kt} / ${this.te}`),n>=e&&e&&this.Kt==this.te&&(new x).U(document.querySelector(`#${this.Wt}`));const a=new Date(30*(e-n)*1e3+Date.now()),r=a.toLocaleString(void 0,this.Jt);this.Ot("#bm-R",`Tiles Loaded: ${this._t.format(this.Kt)} / ${this._t.format(this.te)}`),this.Ot("#bm-M",`Correct Pixels: ${this._t.format(n)}`),this.Ot("#bm-S",`Total Pixels: ${this._t.format(e)}`),this.Ot("#bm-I",`Remaining: ${this._t.format((e||0)-(n||0))} (${this.jt.format(((e||0)-(n||0))/(e||1))})`),this.Ot("#bm-J",`Completed at: `),i(this,M,T).call(this,t,s,o),i(this,M,S).call(this,"id","ascending",!1)}};M=new WeakSet,T=function(t,e,i){const n=new D(this.name,this.version);n.J({class:"bm-13"});for(const t of this.palette){const s=c(t.rgb);let o=1.05/(s+.05)>(s+.05)/.05?"white":"black";t.id||(o="transparent");const a="white"==o?"bm-O":"bm-P",r=i.get(t.id)??0,l=this._t.format(r);let h=0,m="0",d=this.jt.format(1);0!=r&&(h=e.get(t.id)??"???","number"!=typeof h&&this.Kt==this.te&&t.id&&(h=0),m="string"==typeof h?h:this._t.format(h),d=isNaN(h/r)?"???":this.jt.format(h/r));const u=parseInt(r)-parseInt(h),b=!!this.Ft.B.get(t.id);n.J({class:"bm-1b bm-10 bm-_","data-id":t.id,"data-name":t.name,"data-premium":+t.premium,"data-correct":Number.isNaN(parseInt(h))?"0":h,"data-total":r,"data-percent":"%"==d.slice(-1)?d.slice(0,-1):"0","data-incorrect":u||0}).J({class:"bm-K",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).Ct({class:"bm-11 "+a,"data-state":b?"hidden":"shown","aria-label":b?`Show the color ${t.name||""} on templates.`:`Hide the color ${t.name||""} on templates.`,innerHTML:b?this.Yt.replace("{i.onclick=()=>{i.style.textDecoration="none",i.disabled=!0,"shown"==i.dataset.state?(i.innerHTML=this.Yt.replace("{const o=n.getAttribute("data-"+t),a=s.getAttribute("data-"+t),r=parseFloat(o),l=parseFloat(a),c=!isNaN(r),h=!isNaN(l);if(i?n.classList.remove("bm-18"):Number(n.getAttribute("data-total"))||n.classList.add("bm-18"),c&&h)return"ascending"===e?r-l:l-r;{const t=o.toLowerCase(),i=a.toLowerCase();return ti?"ascending"===e?1:-1:0}}),s.forEach(t=>n.appendChild(t))},C=function(t){const e=document.querySelector(".bm-13"),i=Array.from(e.children);for(const e of i){if(e.classList?.contains("bm-18"))continue;const i=e.querySelector(".bm-K button");("hidden"!=i.dataset.state||t)&&("shown"==i.dataset.state&&t||i.click())}},O=new WeakSet,k=function(){new I(this).ee()},L=async function(t,e,i){i.preventDefault();const n=await async function(t){let e="";return t&&(e=t.clipboardData.getData("text/plain")),0!=e.length||(await navigator.clipboard.readText().then(t=>{e=t}).catch(t=>{s("Failed to retrieve clipboard data using navigator! Using fallback methods...")}),0!=e.length||(e=window.clipboardData?.getData("Text"))),e}(i),o=n.split(/[^a-zA-Z0-9]+/).filter(t=>t).map(Number).filter(t=>!isNaN(t));2==o.length&&"bm-x"==e.id?(t.Ot("bm-x",o?.[0]||""),t.Ot("bm-y",o?.[1]||"")):1==o.length?t.Ot(e.id,o?.[0]||""):(t.Ot("bm-v",o?.[0]||""),t.Ot("bm-w",o?.[1]||""),t.Ot("bm-x",o?.[2]||""),t.Ot("bm-y",o?.[3]||""))},N=new WeakSet,B=function(t){const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=t,GM.setValue("bmUserSettings",JSON.stringify(e))};var P=GM_info.script.name.toString(),A=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",P),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",i=t?.getAttribute("bm-B")||"",n=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${n.size} Recieved IMAGE message about blob "${a}"`,i,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,i,""),console.log(n),console.groupEnd(),"blue-marble"==s&&a&&r&&!o){const t=n.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,i,"",a),n.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const o=await s.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,i,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,i,"",t)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const t=Date.now(),s=await a.blob();return console.log(`%c${e}%c: ${n.size} Sending IMAGE message about endpoint "${r}"`,i,""),new Promise(o=>{const l=crypto.randomUUID();n.set(l,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${n.size} Processed blob "${l}"`,i,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:s,blink:t})}).catch(s=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,i,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,i,""),console.log(`Endpoint: ${r}\nThere are ${n.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",s),console.groupEnd()})}return o}});var H=`div:has(>confetti-piece){position:absolute;inset:0;overflow:hidden;pointer-events:none}confetti-piece{position:absolute;top:-10px;width:var(--size);height:var(--size);background:currentColor;transform:translate3d(var(--x),-10vh,0) rotate(var(--rot));animation:fall var(--duration) linear var(--delay);will-change:transform;pointer-events:none}@keyframes fall{to{transform:translate3d(var(--x),110vh,0) rotate(calc(var(--rot) + 720deg))}}.bm-screenreader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1j{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:fit-content;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-14{max-width:300px}.bm-1h{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1h.bm-1c{cursor:grabbing}.bm-1j:has(.bm-1h.bm-1c){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1h.bm-1c{pointer-events:auto}.bm-1i{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1j h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1h h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1h div:has(h1){display:contents}.bm-1j h2{display:inline-block;font-size:larger;font-weight:700;vertical-align:middle}.bm-1b.bm-Q{width:fit-content;margin-left:auto;margin-right:auto}.bm-1b{margin:.5em 0}.bm-1j button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1j button:hover,.bm-1j button:focus-visible{background-color:#1061e5}.bm-1j button:active,.bm-1j button:disabled{background-color:#2e97ff}.bm-1j button:disabled{text-decoration:line-through}.bm-Z{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-19{vertical-align:middle}.bm-19 svg{width:50%;margin:0 auto;fill:#111}.bm-1j button.bm-11{background-color:unset}.bm-11.bm-O:hover,.bm-11.bm-O:focus{background-color:#ffffff2b}.bm-11.bm-O:active{background-color:#ffffff38}.bm-11.bm-P:hover,.bm-11.bm-P:focus{background-color:#0000002b}.bm-11.bm-P:active{background-color:#00000038}input[type=number].bm-12{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-12::-webkit-outer-spin-button,input[type=number].bm-12::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-1a)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-1a,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-1j select{color:#fff;background-color:#144eb9;border-radius:1em;padding:0 .5ch}.bm-1j label:has(input[type=checkbox]){display:flex;width:fit-content;gap:1ch}.bm-1j input[type=checkbox]{width:1em}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1j textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1j small{font-size:x-small;color:#d3d3d3}.bm-1j ul li{list-style:disc;margin-left:5ch}.bm-1j .bm-1b.bm-17{max-height:calc(80vh - 150px);overflow:auto}.bm-_{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-15{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-Y p svg{display:inline;height:1em;fill:#fff}.bm-13{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:1em 3ch}.bm-10{width:fit-content;max-width:35ch;background-color:#153063e6;border-radius:1em;padding:.5em;gap:1ch;transition:background-color .3s ease}.bm-10:hover,.bm-10:focus-within{background-color:#112855e6}.bm-K{display:block;border:thick double darkslategray;width:fit-content;height:fit-content;padding:1ch}.bm-10[data-id="-2"] .bm-K{background:conic-gradient(#a00,#aa0 16.6%,#0a0,#0aa 50%,#00a 66.6%,#a0a,#a00)}.bm-10[data-id="-1"] .bm-K{background:url('data:image/svg+xml;utf8,') repeat;background-color:transparent!important}.bm-10[data-id="-1"] .bm-K svg{fill:#fff!important}.bm-10[data-id="0"] .bm-K{background-color:transparent!important}.bm-K button{padding:.75em .5ch}.bm-K svg{width:4ch}.bm-10>.bm-_{flex-direction:column;align-items:flex-start;gap:0}.bm-10 small{font-size:.75em}#bm-Y .bm-10.bm-18{display:none}`;GM_addStyle(H);var U,W="@font-face{font-family:'Roboto Mono';font-style:normal;font-weight:400;src:url(data:font/woff2;base64,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)format('woff2');}";W.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(W)):((U=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",U.rel="preload",U.as="style",U.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(U)),new class{constructor(){this.ie=null,this.ne=null,this.se="#bm-h"}oe(t){return this.ne=t,this.ie=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.se)}),this}ae(){return this.ie}observe(t,e=!1,i=!1){t.observe(this.ne,{childList:e,subtree:i})}};var G=new class extends D{constructor(t,i){super(t,i),e(this,O),this.window=null,this.Wt="bm-14",this.Gt=document.body}ee(){document.querySelector(`#${this.Wt}`)?this.Ht("Main window already exists!"):(this.window=this.J({id:this.Wt,class:"bm-1j",style:"top: 10px; left: unset; right: 75px;"}).Bt().Ct({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.Pt(e),e.ontouchend=()=>{e.click()}}).X().J().X().X().J({class:"bm-U"}).J({class:"bm-1b"}).et({class:"bm-1i",src:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALEQa0zv0AAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAABF2lDQ1BJQ0MgUHJvZmlsZQAAKM9jYGDiyUnOLWYSYGDIzSspCnJ3UoiIjFJgv8PAyCDJwMygyWCZmFxc4BgQ4MOAE3y7BlQNBJd1QWYxkAa4UlKLk4H0HyCOSy4oKmFgYIwBsrnLSwpA7AwgWyQpG8yuAbGLgA4EsieA2OkQ9hKwGgh7B1hNSJAzkH0GyHZIR2InIbGh9oIAc7IRA9VBSWpFCYh2c2JgAIUpelghxJjFgNgYGBdLEGL5ixgYLL4CxScgxJJmMjBsb2VgkLiFEFNZwMDA38LAsO18cmlRGdRqKSA+zXiSOZl1Ekc29zcBe9FAaRPFj5oTjCSsJ7mxBpbHvs0uqGLt3DirZk3m/trLh18a/P8PAN5BU32YWvgkAAAACXBIWXMAAA7BAAAOwQG4kWvtAAAAGHRFWHRTb2Z0d2FyZQBQYWludC5ORVQgNS4xLjgbaeqoAAAAjGVYSWZJSSoACAAAAAUAGgEFAAEAAABKAAAAGwEFAAEAAABSAAAAKAEDAAEAAAACAAAAMQECABAAAABaAAAAaYcEAAEAAABqAAAAAAAAANl2AQDoAwAA2XYBAOgDAABQYWludC5ORVQgNS4xLjgAAgAAkAcABAAAADAyMzABoAMAAQAAAP//AAAAAAAAubU+IZJzuMAAAAtoSURBVFhHlZZ3fJSFGce/NzKOhITL4kJCEgmJ7D2UXQKJghVBFEWkLC3ioNWigFrhg9ZRKBZUWigtcTBEQUEgBDAESEJCQvYk+7LnZV4u6+2TV8unfqRqnz9yd2/unvF7fs/veTT8HxaXVKBk52QSNGQSN65dxeThTktbG0tWPkhWtpmq8ho65fOTT87+xX5/9ouRV9MV38BRlKZl4qLvwdJQi03RU9fSQmuFGX9fD3q7e+g3ZAS2tibq65rxDwzEXFjKmjVhP+tf+/3rHS0lvlSZP3YUyWdP4NxazgCNFZMzuGg7aKsq5mjERSy2LmbOmQ3VhXSaywjw82XPnn0cPXmSLa8fUN58M1z53t0d7Y4Z5uQ3KSXJmQTfZaIgJ4Wapka8DY70dzLQqXSRVVROVXMHGYUFpOcUsPG3q4lPSaOsrJ4unQMjh48iJSUFo9GIp7s7OvTs/2jTHWP96OGXX11XTHZ2dHVY8PPxwCLBK2obyMnJU/9fUlsDenvqmhrwMQ1i+tQptJcV0m61EpVXh2mQD7m3CnBwcECvs0ej9PLrB+8nIz2Xd7av+1E83fevqqXlNSiDNBpKSouwaXuJS8wk6VYhCZlZFNfVUCdBrN0KS5c9Rn/n/thLIuYSM55+AQSPu4dDn30uXnoZM3o0nbYOdFo7enp6ce3fDw/3Abh4jtiWkRy1/bto39kPMsq4VqzEpSeTlZUjUHfTam3hMQlWUFBAUZEZN0836i11LJwbQoetmcK8QhRF4S8f7cPbN0AQ88PT012SMxJ9JZqgoEAyMrLQ2Ot4as1akm9m0iRcOvLP3bfj3n5z8JNYpaailAaBeOKUiXR1W7GTVujt9Nw1xBtHgxMbX3yJ3yx/mAN/O0j05dM8/8ImTpw4xdMbt2Ls78zhw4fZsWMb02eMRiee1659lt9v3EhMQgaJiamUmSvwMg3k2KG3bsdVp+C5V95QstLTKSuvZOS48Zw5F0FRcZEgkcF9908TOLsxDnBBo+1h+vQpvL97F4Iss341l4eWLMXoaiA27hLOBmdC50xjzpwFzJy1iH4GN4YODWbnzr8wYcI4nJ0N0iGFdc+8dHsy1Ex2vHdGeXbDAjZufBeFDuqqyqWy/bS22jh+/Dg6nZan1i3n8pU4cjLycHJ25IknliF0IXTBozg7uXDg4G7GCg+CgkZQU9uIl5cXDZZmdQpqa2v59uJZPg4/Rn6h8MvazqEDO9TY6h+LVVGOH7tO5IVvWPrIElKSEklMiWX08BEMDQpg1LBRZGalS/JdpKcms/ihJSTciMfPP5AVKxbx1ekobt7M5datXCqqanBzd1PbFxQUJChmERERQei8+fK7B2U0Pbh+I4709BjOnTym0Z77Nls5+ukVNDobK1YuIV4cOzo50c/BhbgbN5kbMotBvp6kZ6TRabWpaAQFD2HavbPw8vFl3VObpV3VvP76ejy9XAWVTkkmkaTEJKKiolQCL168hJDQEM6cPStC5UeJoGDo59pXO7qpUx/Ydv3GdemNla9PfUNzk4WczEz8/Qbx4d93kxYfS8yVqxgMBiZPGsvqVU9icHTgwoXLglIWZnM5MVejVIjvHjmJkSNHkF9QwiOPLCM//5aqBzU1VcTExuLlaWLixAm0t7ZT1dhMdmrcds3W7V8oVZX5rF2zgkmTfZg3r6+3dvRzdsFqbeXhkAk0WazMDw0lPimewMAgTkecE/oqtHTYizo6SzU6snIShTP2ooZlzJ41i9TUVFz6D6BFdoajqKhOWhIWFkbUpUt0dnaxfsPTrFz6K422trpJoPPlhqBwITKVltZuCdiGz6BB7N3zIff/ehUd1nKK067grBdxirtIeVmukKdbHHVSJgsp8lwkPgN9qayoAEVLQnwigUOCmCIq2dLaohZTVVktvNDjIOM8NPhuIs9HMWHKDEXrNdBNCCFEuXCBzVvfYOaM8fQ9W7XyNzg66Aj/4hCeHgMJmxtKjyCydetrEribygbZgMKV1rZWnFwHkJVbhr2d7AvRA6ObkUQh8uiRQQwWngyQZ31INArsM+6dJm0zy0grOLu5oXn+pXDFIrru4aEVFt+iuqqeKqlk6LBArB1WQcLEc+tX4+/iyF/ff5dRkyeg2PfnVESs6qSns1cds+amViGyXtrQiru7USXY3j27cXfzFOleKpA/x/79/xAS6wgICKC+sY6Y859qNO/uvqTEJ8TgN9gLk7cn0d9eJOy+aQTeNVKd488OfyIE1GNtrOT8ha9F+8vY9/dwFj68nEOHPiYvL4+OjnaZdy8KCovp7OrkgYUP0GipJ1aIFx4ezvhx/gwJnin74LvEFi1aRHV1BQf3/lGj9ZIFH7bgXh5dtoSvvzqlVmPQG2XU7qLcXMILzz9PY50FvZMrkZfjaLPCn/70KtPH+7Hzzd8Rff4zHIUbztKOzq4ORowIFkLexEP2Bppetm9/g7lhK1i8YBZdXV00NzfLdOTLDulRk9Gk5jQqJtMA0lIzOLA/nIeXPsTE8aNlzC7hIFBfkypy5Azz9R2EU39H2ltauW9hGKsef4C2duGBQSuvLdg5uvDOe/tISLyJr7TN5O2Ng07h48Of8/QzzxEaMofHV6xh2oyZ+PkO5tq1y0Sc2K/Rjh1m1OzaeZDBgz1EFXQsk37Nnj2bM2dOsPyJecTFR+Ef4MumV15k7/tvU1FWypYtWzh46DhOMn595mhwIepyNsNEA4xurjRbmnCVdd3c1q0iM3XyFHJyC7hnyiRir8XIiCarwft+q3qYH7Z6W8jscYg+sHBhqDDZDUtjIyufWCwtaSYlNY2YmGvs2f2hZH6WTb/bwJixI9GKi6y8IiGji6qW2bK8CkX5Nr/ysozgZJrFh5u7C9djbzJ82HAcHA2YBpqorq0kNyNBvQvUBJ7d+MY2g5OGiZPGcPTIFwTfPUyqX46vj1HQmMrMmfNEUm/x1o63ZKcnS2UdREcn8cG+f1EnQbJzs4RYi2WSPKmoKGdY8HAyMzKZLaNrsbQKqUPlONGLgjoK+xuorDRLAolqAioMffbt1QJloMlFUtKTmpRFQX42pSWlBAf58uhjK9TxKikuxUNmvEUSOHLkKM7CiQ0bNpCansGpM6eIjDjLp58cFq14leXLH+fk16fp7e1l7pwQBvsHSBuyqSg3c+Rfu27HvX0VN7Y2U1ZSK4pVw+dHD7N+/Vr0ej0h8+/H0bFPYisYM2Y8v//DJpxEft95b5squ2ZzKTnZ6WTKUbrl5dfYvHmzzPsBQegqrq5Gurt71ZugsaGR+IREiSRj9F92O5M+O3e1SPngrx/xzLpVjBoeQHFpGa/+8TXOfvM5WmnWgX3HGDduNK5GV+GJK0Z3J24mpaki5D14IPvlUhou7auqrcNPtp4ok/r5auw1GurrcHPz4u1tT/0g5g8+9FlWoaLs/eDPFOYX4T/YW86uFzj55XF1scyfN0NgN1ApatnT06PefFpZzyXFZpKS06VlZZSUFLN69TpsNhtNMrI1VdWUV9RIZ7Ukxl8k8uxnP51An52KKFCKi7JEt++RSvUoIihGo5sEKMfHx0fOMRGUFgtNcrL3wdvb262qodXWwwDhyIVz0XJHDqGisk5dyc1CvLyCdL48/NGP4t0xgT775ny6YudgwMEOhgT4S0VWGTeNVKLB3l4r46PBJrIrkiYHrCLP7KmptshysoladtHR3ibPHLgUFS0ciSbi9LE7xvqfCfzHXt56QBk/ZYK0w0cNanDSy8WrCLm61Tb09blVBKTvBLN1dFHbYJHv6UTrq8gTBd2968WfjPGzCfzHPj6aoJi8B1JfU42Laz/Z8U4qIl0dNiFhG1qZ84aGeiFbm2zTUnbt3PCLfP/iBP7b/nbwjOLq6isEq5XrqQ9+PfWibq9uXf5/+oN/A9GVF7dbp9A3AAAAAElFTkSuQmCC"},(t,e)=>{const i=new Date;204==Math.floor((i.getTime()-new Date(i.getFullYear(),0,1))/864e5)+1&&(e.parentNode.style.position="relative",e.parentNode.innerHTML=e.parentNode.innerHTML+'',e.onload=()=>{(new x).U(document.querySelector(`#${this.Wt}`))})}).X().it(1,{textContent:this.name}).X().X().nt().X().J({class:"bm-1b"}).Z({id:"bm-p",textContent:"Droplets:"}).X().st().X().Z({id:"bm-i",textContent:"Next level in..."}).X().st().X().Z({textContent:"Charges: "}).It(Date.now(),1e3,{style:"font-weight: 700;"},(t,e)=>{t.W.re=e.id}).X().X().X().nt().X().J({class:"bm-1b"}).J({class:"bm-1b"}).Ct({class:"bm-Z bm-19",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.W?.le;e?.[0]?(t.Ot("bm-v",e?.[0]||""),t.Ot("bm-w",e?.[1]||""),t.Ot("bm-x",e?.[2]||""),t.Ot("bm-y",e?.[3]||"")):t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?")}}).X().kt({type:"number",id:"bm-v",class:"bm-12",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-w",class:"bm-12",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-x",class:"bm-12",placeholder:"Px X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-y",class:"bm-12",placeholder:"Px Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().X().J({class:"bm-1b"}).Lt({class:"bm-1a",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).X().X().J({class:"bm-1b bm-_"}).Ct({textContent:"Disable","data-button-status":"shown"},(t,e)=>{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.W?.Ft?.ce(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.Ut("Disabled templates!")):(t.W?.Ft?.ce(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.Ut("Enabled templates!")),e.disabled=!1}}).X().Ct({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector(`#${this.Wt} .bm-1a`),i=document.querySelector("#bm-v");if(!i.checkValidity())return i.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const n=document.querySelector("#bm-w");if(!n.checkValidity())return n.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-x");if(!s.checkValidity())return s.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-y");if(!o.checkValidity())return o.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(t?.W?.Ft.he(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(i.value),Number(n.value),Number(s.value),Number(o.value)]),t.Ut("Drew to canvas!")):t.Ht("No file selected!")}}).X().Ct({textContent:"Filter"},(t,e)=>{e.onclick=()=>i(this,O,k).call(this)}).X().X().J({class:"bm-1b"}).Nt({id:this.G,placeholder:`Status: Sleeping...\nVersion: ${this.version}`,readOnly:!0}).X().X().J({class:"bm-1b bm-_",style:"margin-bottom: 0;"}).J({class:"bm-_"}).Ct({class:"bm-Z",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).X().Ct({class:"bm-Z",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).X().X().q({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).X().X().X().X().X().R(this.Gt),this.At(`#${this.Wt}.bm-1j`,`#${this.Wt} .bm-1h`))}}(P,A),F=new class{constructor(t,i,n){e(this,d),this.name=t,this.version=i,this.F=n,this.me="1.0.0",this.de=null,this.ue="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.h=1e3,this.S=3,this.L=3,this.N=function(t){const e=f;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const i=new Map;for(const n of e){if(0==n.id||-2==n.id)continue;const e=n.rgb[0],s=n.rgb[1],o=n.rgb[2];for(let a=-t;a<=t;a++)for(let r=-t;r<=t;r++)for(let l=-t;l<=t;l++){const t=e+a,c=s+r,h=o+l;if(t<0||t>255||c<0||c>255||h<0||h>255)continue;const m=(255<<24|h<<16|c<<8|t)>>>0;i.has(m)||i.set(m,n.id)}}return{palette:e,M:i}}(this.L),this.O=null,this.be="",this.C=[],this.T=null,this.pe=!0,this.fe=null,this.B=new Map}async ge(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.me,templates:{}}}async he(t,e,n){this.T||(this.T=await this.ge(),console.log("Creating JSON...")),this.F.Ut(`Creating template at ${n.join(", ")}...`);const s=new g({displayName:e,t:0,i:a(this.de||0,this.ue),file:t,coords:n}),{v:o,$:r}=await s.u(this.h,this.N);s.o=o;const l={total:s.m.total,colors:Object.fromEntries(s.m.colors)};this.T.templates[`${s.t} ${s.i}`]={name:s.displayName,coords:n.join(", "),enabled:!0,pixels:l,tiles:r},this.C=[],this.C.push(s),this.F.Ut(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.T.templates).length),console.log(this.T),console.log(this.C),console.log(JSON.stringify(this.T)),await i(this,d,u).call(this)}we(){}async ye(){this.T||(this.T=await this.ge(),console.log("Creating JSON..."))}async ve(t,e){if(!this.pe)return t;const n=this.h*this.S;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const s=this.C;console.log(s),s.sort((t,e)=>t.t-e.t),console.log(s);const o=s.map(t=>{const i=Object.keys(t.o).filter(t=>t.startsWith(e));if(0===i.length)return null;const n=i.map(e=>{const i=e.split(",");return{xe:t,$e:t.o[e],l:t.l?.[e],Me:[i[0],i[1]],Te:[i[2],i[3]]}});return n?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.F.Ut(`Sleeping\nVersion: ${this.version}`),t;{const t=s.filter(t=>Object.keys(t.o).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.m.total||0),0),i=(new Intl.NumberFormat).format(t);this.F.Ut(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${i}`)}const r=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const h=c.getImageData(0,0,n,n),m=new Uint32Array(h.data.buffer);for(const t of o){console.log("Template:"),console.log(t);const n=!!t.xe.m?.colors?.get(-1);let s=t.l.slice();const o=Number(t.Te[0])*this.S,a=Number(t.Te[1])*this.S;if(0!=this.B.size||n||c.drawImage(t.$e,o,a),!s){const e=c.getImageData(o,a,t.$e.width,t.$e.height);s=new Uint32Array(e.data.buffer)}const r=Date.now(),{I:l,P:h}=i(this,d,p).call(this,{D:m,O:s,k:[o,a,t.$e.width,t.$e.height]});let u=0;const b=0;for(const[t,e]of l)t!=b&&(u+=e);(0!=this.B.size||n)&&(console.log("Colors to filter: ",this.B),c.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(h.buffer),t.$e.width,t.$e.height)),o,a)),console.log(`Finished calculating correct pixels & filtering colors for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${u} correct pixels.`),void 0===t.xe.m.correct&&(t.xe.m.correct={}),t.xe.m.correct[e]=l}return await l.convertToBlob({type:"image/png"})}Se(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&i(this,d,b).call(this,t)}ce(t){this.pe=t}}(P,A,G),E=new class{constructor(t){this.Ft=t,this.Ce=!1,this.re="",this.le=[],this.De=[]}Oe(t){window.addEventListener("message",async e=>{const i=e.data,n=i.jsonData;if(!i||"blue-marble"!==i.source)return;if(!i.endpoint)return;const s=i.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",s),s){case"me":if(n.status&&"2"!=n.status?.toString()[0])return void t.Ht("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(n.level)*Math.pow(30,.65),1/.65)-n.pixelsPainted);if(console.log(n.id),(n.id||0===n.id)&&console.log(a(n.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Ft.de=n.id,0!=this.re.length){const t=document.querySelector("#"+this.re);if(t){const e=n.charges;t.dataset.endDate=Date.now()+(e.max-e.count)*e.cooldownMs}}t.Ot("bm-p",`Droplets: ${(new Intl.NumberFormat).format(n.droplets)}`),t.Ot("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=i.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),l=new URLSearchParams(i.endpoint.split("?")[1]),c=[l.get("x"),l.get("y")];if(this.le.length&&(!s.length||!c.length))return void t.Ht("Coordinates are malformed!\nDid you try clicking the canvas first?");this.le=[...s,...c];const h=(o=s,r=c,[parseInt(o[0])%4*1e3+parseInt(r[0]),parseInt(o[1])%4*1e3+parseInt(r[1])]),m=document.querySelectorAll("span");for(const t of m)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-h");const i=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=i:(e=document.createElement("span"),e.id="bm-h",e.textContent=i,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=i.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const u=i.blobID,b=i.blobData,p=Date.now(),f=await this.Ft.ve(b,d);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:f,blink:i.blink});break;case"robots":this.Ce="false"==n.userscript?.toString().toLowerCase();break}var o,r})}async ke(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const i=navigator.userAgent;let n=await this.Le(i),s=this.Ne(i);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:n,os:s}),onload:t=>{200!==t.status&&o("Failed to send heartbeat:",t.statusText)},onerror:t=>{o("Error sending heartbeat:",t)}})}async Le(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"}Ne(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}}(F);G.j(E);var Y=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(Y),F.Se(Y);var _=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(_),console.log(Object.keys(_).length),0==Object.keys(_).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}setInterval(()=>E.ke(A),18e5);var j=_?.telemetry;if(console.log(`Telemetry is ${!(null==j)}`),null==j||j>1){const t=new class extends D{constructor(t,i,n,s){super(t,i),e(this,N),this.window=null,this.Wt="bm-T",this.Gt=document.body,this.Be=n,this.uuid=s}async ee(){if(document.querySelector(`#${this.Wt}`))return void this.Ht("Telemetry window already exists!");const t=await this.W.Le(navigator.userAgent),e=this.W.Ne(navigator.userAgent);this.window=this.J({id:this.Wt,class:"bm-1j",style:"height: 80vh; z-index: 9998;"}).J({class:"bm-U"}).J({class:"bm-1b bm-Q"}).it(1,{textContent:`${this.name} Telemetry`}).X().X().nt().X().J({class:"bm-1b bm-15",style:"gap: 1.5ch; flex-wrap: wrap;"}).Ct({textContent:"Enable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,N,B).call(this,this.Be);const t=document.getElementById(this.Wt);t?.remove()}}).X().Ct({textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,N,B).call(this,0);const t=document.getElementById(this.Wt);t?.remove()}}).X().Ct({textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).X().X().J({class:"bm-1b bm-17"}).J({class:"bm-1b"}).it(2,{textContent:"Legal"}).X().V({textContent:`We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the "Disable" button, but keeping it on helps us improve features and reliability faster. Thank you for supporting ${this.name}!`}).X().X().nt().X().J({class:"bm-1b"}).it(2,{textContent:"Non-Legal Summary"}).X().V({innerHTML:'You can disable telemetry by pressing the "Disable" button. If you would like to read more about what information we collect, press the "More Information" button.
This is the data stored on our servers:'}).X().bt().gt({innerHTML:`A unique identifier (UUIDv4) generated by Blue Marble. This enables our telemetry to function without tracking your actual user ID.
Your UUID is: ${n(this.uuid)}`}).X().gt({innerHTML:`The version of Blue Marble you are using.
Your version is: ${n(this.version)}`}).X().gt({innerHTML:`Your browser type, which is used to determine Blue Marble outages and browser popularity.
Your browser type is: ${n(t)}`}).X().gt({innerHTML:`Your OS type, which is used to determine Blue Marble outages and OS popularity.
Your OS type is: ${n(e)}`}).X().gt({innerHTML:"The date and time that Blue Marble sent the telemetry information."}).X().X().V({innerHTML:'All of the data mentioned above is aggregated every hour. This means every hour, anything that could even remotly be considered "personal data" is deleted from our server. Here, "aggregated" data means things like "42 people used Blue Marble on Google Chrome this hour", which can\'t be used to identify anyone in particular.'}).X().X().X().X().X().R(this.Gt)}}(P,A,1,_?.uuid);t.j(E),t.ee()}G.ee(),E.Oe(G),new MutationObserver((t,e)=>{const i=document.querySelector("#color-1");if(!i)return;let n=document.querySelector("#bm-t");if(!n){n=document.createElement("button"),n.id="bm-t",n.textContent="Move ↑",n.className="btn btn-soft",n.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=i.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(n)}}).observe(document.body,{childList:!0,subtree:!0}),s(`%c${P}%c (${A}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t=t=>{throw TypeError(t)},e=(e,i,n)=>i.has(e)?t("Cannot add the same private member more than once"):i instanceof WeakSet?i.add(e):i.set(e,n),i=(e,i,n)=>(((e,i)=>{i.has(e)||t("Cannot access private method")})(e,i),n);function n(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function s(...t){(0,console.log)(...t)}function o(...t){(0,console.error)(...t)}function a(t,e){if(0===t)return e[0];let i="";const n=e.length;for(;t>0;)i=e[t%n]+i,t=Math.floor(t/n);return i}function r(t){let e="";for(let i=0;i(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}var h,m,d,u,b,p=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],g=class{constructor({displayName:t="My template",t:i=0,i:n="",url:s="",file:o=null,coords:a=null,o:r=null,l:l={},h:c=1e3}={}){e(this,h),this.displayName=t,this.t=i,this.i=n,this.url=s,this.file=o,this.coords=a,this.o=r,this.l=l,this.h=c,this.m={total:0,colors:new Map}}async u(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),s=n.width,o=n.height;this.h=t;const a={},l={},c=new OffscreenCanvas(this.h,this.h),d=c.getContext("2d",{p:!0});c.width=s,c.height=o,d.imageSmoothingEnabled=!1,d.drawImage(n,0,0);let u=Date.now();const b=i(this,h,m).call(this,d.getImageData(0,0,s,o),e);console.log(`Calculating total pixels took ${(Date.now()-u)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.m={total:p,colors:b},u=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:s.get(e)??-2;const a=o.get(n);o.set(n,a?a+1:1)}return console.log(o),o};var f,w,y=class{constructor(t,i){e(this,d),this.name=t,this.version=i,this.T=null,this.S="bm-o",this.C=null,this.D=null,this.O=[]}k(t){this.T=t}L(){return this.O.length>0&&(this.D=this.O.pop()),this}N(t){t?.appendChild(this.C),this.C=null,this.D=null,this.O=[]}B(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"div",{},t)),this}I(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"p",{},t)),this}P(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"small",{},t)),this}A(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"span",{},t)),this}W(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"details",{},t)),this}H(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"summary",{},t)),this}U(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"img",{},t)),this}G(t,e={},n=()=>{}){return n(this,i(this,d,u).call(this,"h"+t,{},e)),this}F(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"hr",{},t)),this}Y(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"br",{},t)),this}_(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"form",{},t)),this}R(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"fieldset",{},t)),this}j(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"legend",{},t)),this}X(t={},e=()=>{}){const n=i(this,d,u).call(this,"label",{textContent:t.textContent??""});delete t.textContent;const s=i(this,d,u).call(this,"input",{type:"checkbox"},t);return n.insertBefore(s,n.firstChild),this.L(),e(this,n,s),this}J(t={},e=()=>{}){const n=i(this,d,u).call(this,"label",{textContent:t.textContent??"",for:t.id??""});return delete t.textContent,this.L(),e(this,n,i(this,d,u).call(this,"select",{},t)),this}V(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"option",{},t)),this}q(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"ol",{},t)),this}Z(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"ul",{},t)),this}K(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"menu",{},t)),this}tt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"li",{},t)),this}et(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"table",{},t)),this}it(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"caption",{},t)),this}nt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"thead",{},t)),this}st(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tbody",{},t)),this}ot(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tfoot",{},t)),this}rt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tr",{},t)),this}lt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"th",{},t)),this}ct(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"td",{},t)),this}ht(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"button",{},t)),this}dt(t={},e=()=>{}){const n=t.title??t.textContent??"Help: No info";delete t.textContent,t.title=`Help: ${n}`;const s={textContent:"?",className:"bm-D",onclick:()=>{this.ut(this.S,n)}};return e(this,i(this,d,u).call(this,"button",s,t)),this}bt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"input",{},t)),this}gt(t={},e=()=>{}){const n=t.textContent??"";delete t.textContent;const s=i(this,d,u).call(this,"div"),o=i(this,d,u).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true"},t);this.L();const a=i(this,d,u).call(this,"button",{textContent:n});return this.L(),this.L(),a.addEventListener("click",()=>{o.click()}),o.addEventListener("change",()=>{a.style.maxWidth=`${a.offsetWidth}px`,o.files.length>0?a.textContent=o.files[0].name:a.textContent=n}),e(this,s,o,a),this}ft(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"textarea",{},t)),this}wt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"div",{class:"bm-1j"},t)),this}yt(t=Date.now(),e=500,n={},s=()=>{}){const o="bm-1n",a=n?.id||o+"-"+crypto.randomUUID().slice(0,8),r={class:o},l=i(this,d,u).call(this,"time",r,n);return l.id=a,l.dataset.endDate=t,setInterval(()=>{if(!l.isConnected)return;const t=Math.max(l.dataset.endDate-Date.now(),0),e=Math.floor(t/1e3),i=Math.floor(e/3600),n=Math.floor(e%60),s=Math.floor(e%3600/60);l.setAttribute("datetime",`PT${i}H${s}M${n}S`),l.textContent=String(i).padStart(2,"0")+":"+String(s).padStart(2,"0")+":"+String(n).padStart(2,"0")},e),s(this,l),this}ut(t,e,i=!1){const n=document.getElementById(t.replace(/^#/,""));n&&(n instanceof HTMLInputElement?n.value=e:i?n.textContent=e:n.innerHTML=e)}vt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1l"),i=t.closest(".bm-1j"),n=e.querySelector("h1"),s=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){s.style.height=s.scrollHeight+"px",e.style.width=e.scrollWidth+"px",s.style.height="0",s.addEventListener("transitionend",function e(){s.style.display="none",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)});const i=n.cloneNode(!0),o=i.textContent;t.nextElementSibling.appendChild(i),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${o}"`}else{const n=i.querySelector("h1"),o=n.textContent;n.remove(),s.style.display="",s.style.height="0",e.style.width="",s.style.height=s.scrollHeight+"px",s.addEventListener("transitionend",function e(){s.style.height="",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${o}"`}}xt(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.$t(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let i,n=!1,s=0,o=null,a=0,r=0,l=0,c=0,h=null;const m=()=>{if(n){const e=Math.abs(a-l),i=Math.abs(r-c);(e>.5||i>.5)&&(a=l,r=c,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),o=requestAnimationFrame(m)}},d=(d,g)=>{n=!0,h=t.getBoundingClientRect(),i=d-h.left,s=g-h.top;const f=window.getComputedStyle(t).transform;if(f&&"none"!==f){const t=new DOMMatrix(f);a=t.m41,r=t.m42}else a=h.left,r=h.top;l=a,c=r,document.body.style.userSelect="none",e.classList.add("bm-1e"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),o&&cancelAnimationFrame(o),m()},u=()=>{n=!1,o&&(cancelAnimationFrame(o),o=null),document.body.style.userSelect="",e.classList.remove("bm-1e"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{n&&h&&(l=t.clientX-i,c=t.clientY-s)},p=t=>{if(n&&h){const e=t.touches[0];if(!e)return;l=e.clientX-i,c=e.clientY-s,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),d(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(d(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}Mt(t){(0,console.info)(`${this.name}: ${t}`),this.ut(this.S,"Status: "+t,!0)}$t(t){(0,console.error)(`${this.name}: ${t}`),this.ut(this.S,"Error: "+t,!0)}};d=new WeakSet,u=function(t,e={},n={}){const s=document.createElement(t);this.C?(this.D?.appendChild(s),this.O.push(this.D),this.D=s):(this.C=s,this.D=s);for(const[t,n]of Object.entries(e))i(this,d,b).call(this,s,t,n);for(const[t,e]of Object.entries(n))i(this,d,b).call(this,s,t,e);return s},b=function(t,e,i){if("class"==e)t.classList.add(...i.split(/\s+/));else if("for"==e)t.htmlFor=i;else if("tabindex"==e)t.tabIndex=Number(i);else if("readonly"==e)t.readOnly="true"==i||"1"==i;else if("maxlength"==e)t.maxLength=Number(i);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=i;else if(e.startsWith("aria")){const n=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+n[0].toUpperCase()+n.slice(1)]=i}else t[e]=i};var v,x,$,M,T=class extends y{constructor(t,i,n){super(t,i),e(this,f),this.window=null,this.Tt="bm-Y",this.St=document.body,this.Ct=JSON.parse(GM_getValue("bmTemplates","{}")),this.scriptVersion=this.Ct?.scriptVersion,this.schemaVersion=this.Ct?.schemaVersion,this.Dt=void 0,this.Ot=n}kt(){document.querySelector(`#${this.Tt}`)?this.$t("Template Wizard window already exists!"):(this.window=this.B({id:this.Tt,class:"bm-1l",style:"z-index: 9001;"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Template Wizard"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().ht({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Template Wizard"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Tt}`)?.remove()},e.ontouchend=()=>{e.click()}}).L().L().B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:"Template Wizard"}).L().L().F().L().B({class:"bm-1d"}).I({id:"bm--",textContent:"Loading template storage status..."}).L().L().B({class:"bm-1d bm-19"}).A({textContent:"Detected templates:"}).L().L().L().L().N(this.St),i(this,f,w).call(this))}};f=new WeakSet,w=function(){const t=this.schemaVersion.split(/[-\.\+]/),e=this.Ot.split(/[-\.\+]/);let i="";t[0]==e[0]?t[1]==e[1]?(i="Template storage health: Healthy!
No futher action required. (Reason: Semantic version matches)",this.Dt="Good"):(i="Template storage health: Poor!
You can still use your template, but some features may not work. It is recommended that you update Blue Marble's template storage. (Reason: MINOR version mismatch)",this.Dt="Poor"):(i="Template storage health: Dead!
Blue Marble can not load the template storage. (Reason: MAJOR version mismatch)",this.Dt="Dead"),this.ut("#bm--",`${i}
The current schema version (${n(this.schemaVersion)}) was created during Blue Marble version ${n(this.scriptVersion)}.
The current Blue Marble version (${n(this.version)}) requires schema version ${n(this.Ot)}.
If you don't want to upgrade the template storage (schema), then downgrade Blue Marble to version ${n(this.scriptVersion)}.`),("Poor"==this.Dt||"Bad"==this.Dt)&&new y(this.name,this.version).B({class:"bm-1d bm-15 bm-Q"}).ht({textContent:`Update template storage to ${this.Ot}`},(t,e)=>{e.onclick=()=>{}}).L().L().N(document.querySelector("#bm--").parentNode)},v=new WeakSet,x=async function(){GM.setValue("bmTemplates",JSON.stringify(this.Lt))},$=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;console.log(`BlueMarble length: ${Object.keys(e).length}`);const i=t?.schemaVersion,n=i.split(/[-\.\+]/),s=this.schemaVersion.split(/[-\.\+]/),o=t?.scriptVersion;async function a(){if(Object.keys(e).length>0)for(const t in e){const i=t,n=e[t];if(console.log(`Template Key: ${i}`),e.hasOwnProperty(t)){const t=i.split(" "),e=Number(t?.[0]),s=t?.[1]||"0",o=n.name||`Template ${e||""}`,a={total:n.pixels.total,colors:new Map(Object.entries(n.pixels.colors).map(([t,e])=>[Number(t),e]))},r=n.tiles,c={},h={},m=this.h*this.Nt;for(const t in r)if(console.log(t),r.hasOwnProperty(t)){const e=l(r[t]),i=new Blob([e],{type:"image/png"}),n=await createImageBitmap(i);c[t]=n;const s=new OffscreenCanvas(m,m).getContext("2d");s.drawImage(n,0,0);const o=s.getImageData(0,0,n.width,n.height);h[t]=new Uint32Array(o.data.buffer)}const d=new g({displayName:o,t:e||this.Bt?.length||0,i:s||""});d.m=a,d.o=c,d.l=h,this.Bt.push(d),console.log(this.Bt),console.log("^^^ This ^^^")}}}console.log(`BlueMarble Template Schema: ${i}; Script Version: ${o}`),n[0]==s[0]?(n[1]==s[1]||new T(this.name,this.version,this.schemaVersion).kt(),a()):this.C.$t(`Template version ${i} is unsupported.\nUse Blue Marble version ${o} or load a new template.`)},M=function({It:t,Pt:e,At:i}){const n=this.Nt,s=this.h*n,o=i[0],a=i[1],r=i[2],l=i[3],c=this.Wt,{palette:h,M:m}=this.Ht,d=new Map;for(let i=1;i>>24&255,f=b>>>24&255,w=m.get(p)??-2;if(this.Ut.get(w)&&(e[i*r+l]=b),-1==w){const t=536870912;this.Ut.get(w)?e[i*r+l]=0:(h/n&1)==(u/n&1)?(e[i*r+l]=t,e[(i-1)*r+(l-1)]=t,e[(i-1)*r+(l+1)]=t,e[(i+1)*r+(l-1)]=t,e[(i+1)*r+(l+1)]=t):(e[i*r+l]=0,e[(i-1)*r+l]=t,e[(i+1)*r+l]=t,e[i*r+(l-1)]=t,e[i*r+(l+1)]=t)}if(-1==w&&b<=c){const t=d.get(w);d.set(w,t?t+1:1);continue}if(g<=c||f<=c)continue;if((m.get(b)??-2)!=w)continue;const y=d.get(w);d.set(w,y?y+1:1)}return console.log("List of template pixels that match the tile:"),console.log(d),{Gt:d,Ft:e}};var S,C,D,O,k=class{constructor(){this.Yt=Math.ceil(80/1300*window.innerWidth),this._t=p.slice(1)}zt(t){const e=document.createElement("div");for(let t=0;t{t.parentNode.childElementCount<=1?t.parentNode.remove():t.remove()},e.appendChild(t)}t.appendChild(e)}},L=class extends HTMLElement{};customElements.define("confetti-piece",L);var N,B,I,P,A,W=class extends y{constructor(t){super(t.name,t.version),e(this,S),this.window=null,this.Tt="bm-_",this.St=document.body,this.Et=t.T?.Et,this.Rt='',this.jt='',this.Xt=new Intl.NumberFormat,this.Jt=new Intl.NumberFormat(void 0,{style:"percent",Vt:2,qt:2}),this.Qt={Zt:"long",Kt:"numeric",te:"2-digit",ee:"2-digit",ie:"2-digit"};const{palette:i,M:n}=this.Et.Ht;this.palette=i,this.ne=0,this.se=0}kt(){if(document.querySelector(`#${this.Tt}`))return void this.$t("Color Filter window already exists!");this.window=this.B({id:this.Tt,class:"bm-1l"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().ht({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Tt}`)?.remove()},e.ontouchend=()=>{e.click()}}).L().L().B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:"Color Filter"}).L().L().F().L().B({class:"bm-1d bm-11 bm-Q",style:"gap: 1.5ch;"}).ht({textContent:"Select All"},(t,e)=>{e.onclick=()=>i(this,S,O).call(this,!1)}).L().ht({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>i(this,S,O).call(this,!0)}).L().L().B({class:"bm-1d bm-19"}).B({class:"bm-1d",style:"margin-left: 2.5ch; margin-right: 2.5ch;"}).B({class:"bm-1d"}).A({id:"bm-R",innerHTML:"Tiles Loaded: 0 / ???"}).L().Y().L().A({id:"bm-M",innerHTML:"Correct Pixels: ???"}).L().Y().L().A({id:"bm-S",innerHTML:"Total Pixels: ???"}).L().Y().L().A({id:"bm-I",innerHTML:"Complete: ??? (???)"}).L().Y().L().A({id:"bm-J",innerHTML:"??? ???"}).L().L().B({class:"bm-1d"}).I({innerHTML:`Colors with the icon ${this.Rt.replace("{e.onclick=t=>{t.preventDefault();const e=new FormData(document.querySelector(`#${this.Tt} form`)),n={};for(const[t,i]of e)n[t]=i;console.log(`Primary: ${n.sortPrimary}; Secondary: ${n.sortSecondary}; Unused: ${"on"==n.showUnused}`),i(this,S,D).call(this,n.sortPrimary,n.sortSecondary,"on"==n.showUnused)}}).L().L().L().L().L().L().L().N(this.St),this.xt(`#${this.Tt}.bm-1l`,`#${this.Tt} .bm-1j`);const t=document.querySelector(`#${this.Tt} .bm-1d.bm-19`);let e=0,n=0;const s=new Map,o=new Map;for(const t of this.Et.Bt){e+=t.m?.total??0??0;const i=t.m?.colors??new Map;for(const[t,e]of i){const i=Number(e)||0,n=o.get(t)??0;o.set(t,n+i)}const a=t.m?.correct??{};this.ne+=Object.keys(a).length,this.se+=Object.keys(t.o).length;for(const t of Object.values(a))for(const[e,i]of t){const t=Number(i)||0;n+=t;const o=s.get(e)??0;s.set(e,o+t)}}console.log(`Tiles loaded: ${this.ne} / ${this.se}`),n>=e&&e&&this.ne==this.se&&(new k).zt(document.querySelector(`#${this.Tt}`));const a=new Date(30*(e-n)*1e3+Date.now()),r=a.toLocaleString(void 0,this.Qt);this.ut("#bm-R",`Tiles Loaded: ${this.Xt.format(this.ne)} / ${this.Xt.format(this.se)}`),this.ut("#bm-M",`Correct Pixels: ${this.Xt.format(n)}`),this.ut("#bm-S",`Total Pixels: ${this.Xt.format(e)}`),this.ut("#bm-I",`Remaining: ${this.Xt.format((e||0)-(n||0))} (${this.Jt.format(((e||0)-(n||0))/(e||1))})`),this.ut("#bm-J",`Completed at: `),i(this,S,C).call(this,t,s,o),i(this,S,D).call(this,"id","ascending",!1)}};S=new WeakSet,C=function(t,e,i){const n=new y(this.name,this.version);n.B({class:"bm-16"});for(const t of this.palette){const s=c(t.rgb);let o=1.05/(s+.05)>(s+.05)/.05?"white":"black";t.id||(o="transparent");const a="white"==o?"bm-O":"bm-P",r=i.get(t.id)??0,l=this.Xt.format(r);let h=0,m="0",d=this.Jt.format(1);0!=r&&(h=e.get(t.id)??"???","number"!=typeof h&&this.ne==this.se&&t.id&&(h=0),m="string"==typeof h?h:this.Xt.format(h),d=isNaN(h/r)?"???":this.Jt.format(h/r));const u=parseInt(r)-parseInt(h),b=!!this.Et.Ut.get(t.id);n.B({class:"bm-1d bm-12 bm-11","data-id":t.id,"data-name":t.name,"data-premium":+t.premium,"data-correct":Number.isNaN(parseInt(h))?"0":h,"data-total":r,"data-percent":"%"==d.slice(-1)?d.slice(0,-1):"0","data-incorrect":u||0}).B({class:"bm-K",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).ht({class:"bm-13 "+a,"data-state":b?"hidden":"shown","aria-label":b?`Show the color ${t.name||""} on templates.`:`Hide the color ${t.name||""} on templates.`,innerHTML:b?this.jt.replace("{i.onclick=()=>{i.style.textDecoration="none",i.disabled=!0,"shown"==i.dataset.state?(i.innerHTML=this.jt.replace("{const o=n.getAttribute("data-"+t),a=s.getAttribute("data-"+t),r=parseFloat(o),l=parseFloat(a),c=!isNaN(r),h=!isNaN(l);if(i?n.classList.remove("bm-1a"):Number(n.getAttribute("data-total"))||n.classList.add("bm-1a"),c&&h)return"ascending"===e?r-l:l-r;{const t=o.toLowerCase(),i=a.toLowerCase();return ti?"ascending"===e?1:-1:0}}),s.forEach(t=>n.appendChild(t))},O=function(t){const e=document.querySelector(".bm-16"),i=Array.from(e.children);for(const e of i){if(e.classList?.contains("bm-1a"))continue;const i=e.querySelector(".bm-K button");("hidden"!=i.dataset.state||t)&&("shown"==i.dataset.state&&t||i.click())}},N=new WeakSet,B=function(){new W(this).kt()},I=async function(t,e,i){i.preventDefault();const n=await async function(t){let e="";return t&&(e=t.clipboardData.getData("text/plain")),0!=e.length||(await navigator.clipboard.readText().then(t=>{e=t}).catch(t=>{s("Failed to retrieve clipboard data using navigator! Using fallback methods...")}),0!=e.length||(e=window.clipboardData?.getData("Text"))),e}(i),o=n.split(/[^a-zA-Z0-9]+/).filter(t=>t).map(Number).filter(t=>!isNaN(t));2==o.length&&"bm-x"==e.id?(t.ut("bm-x",o?.[0]||""),t.ut("bm-y",o?.[1]||"")):1==o.length?t.ut(e.id,o?.[0]||""):(t.ut("bm-v",o?.[0]||""),t.ut("bm-w",o?.[1]||""),t.ut("bm-x",o?.[2]||""),t.ut("bm-y",o?.[3]||""))},P=new WeakSet,A=function(t){const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=t,GM.setValue("bmUserSettings",JSON.stringify(e))};var H=GM_info.script.name.toString(),U=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",H),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",i=t?.getAttribute("bm-B")||"",n=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${n.size} Recieved IMAGE message about blob "${a}"`,i,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,i,""),console.log(n),console.groupEnd(),"blue-marble"==s&&a&&r&&!o){const t=n.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,i,"",a),n.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const o=await s.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,i,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,i,"",t)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const t=Date.now(),s=await a.blob();return console.log(`%c${e}%c: ${n.size} Sending IMAGE message about endpoint "${r}"`,i,""),new Promise(o=>{const l=crypto.randomUUID();n.set(l,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${n.size} Processed blob "${l}"`,i,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:s,blink:t})}).catch(s=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,i,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,i,""),console.log(`Endpoint: ${r}\nThere are ${n.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",s),console.groupEnd()})}return o}});var G=`div:has(>confetti-piece){position:absolute;inset:0;overflow:hidden;pointer-events:none}confetti-piece{position:absolute;top:-10px;width:var(--size);height:var(--size);background:currentColor;transform:translate3d(var(--x),-10vh,0) rotate(var(--rot));animation:fall var(--duration) linear var(--delay);will-change:transform;pointer-events:none}@keyframes fall{to{transform:translate3d(var(--x),110vh,0) rotate(calc(var(--rot) + 720deg))}}.bm-screenreader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1l{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:fit-content;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-17{max-width:300px}.bm-1j{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1j.bm-1e{cursor:grabbing}.bm-1l:has(.bm-1j.bm-1e){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1j.bm-1e{pointer-events:auto}.bm-1k{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1l h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1j h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1j div:has(h1){display:contents}.bm-1l h2{display:inline-block;font-size:larger;font-weight:700;vertical-align:middle}.bm-1d.bm-Q{width:fit-content;margin-left:auto;margin-right:auto}.bm-1d{margin:.5em 0}.bm-1l button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1l button:hover,.bm-1l button:focus-visible{background-color:#1061e5}.bm-1l button:active,.bm-1l button:disabled{background-color:#2e97ff}.bm-1l button:disabled{text-decoration:line-through}.bm-Z{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-1b{vertical-align:middle}.bm-1b svg{width:50%;margin:0 auto;fill:#111}.bm-1l button.bm-13{background-color:unset}.bm-13.bm-O:hover,.bm-13.bm-O:focus{background-color:#ffffff2b}.bm-13.bm-O:active{background-color:#ffffff38}.bm-13.bm-P:hover,.bm-13.bm-P:focus{background-color:#0000002b}.bm-13.bm-P:active{background-color:#00000038}input[type=number].bm-14{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-14::-webkit-outer-spin-button,input[type=number].bm-14::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-1c)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-1c,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-1l select{color:#fff;background-color:#144eb9;border-radius:1em;padding:0 .5ch}.bm-1l label:has(input[type=checkbox]){display:flex;width:fit-content;gap:1ch}.bm-1l input[type=checkbox]{width:1em}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1l textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1l small{font-size:x-small;color:#d3d3d3}.bm-1l ul li{list-style:disc;margin-left:5ch}.bm-1l .bm-1d.bm-19{max-height:calc(80vh - 150px);overflow:auto}.bm-11{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-15{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-_ p svg{display:inline;height:1em;fill:#fff}.bm-16{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:1em 3ch}.bm-12{width:fit-content;max-width:35ch;background-color:#153063e6;border-radius:1em;padding:.5em;gap:1ch;transition:background-color .3s ease}.bm-12:hover,.bm-12:focus-within{background-color:#112855e6}.bm-K{display:block;border:thick double darkslategray;width:fit-content;height:fit-content;padding:1ch}.bm-12[data-id="-2"] .bm-K{background:conic-gradient(#a00,#aa0 16.6%,#0a0,#0aa 50%,#00a 66.6%,#a0a,#a00)}.bm-12[data-id="-1"] .bm-K{background:url('data:image/svg+xml;utf8,') repeat;background-color:transparent!important}.bm-12[data-id="-1"] .bm-K svg{fill:#fff!important}.bm-12[data-id="0"] .bm-K{background-color:transparent!important}.bm-K button{padding:.75em .5ch}.bm-K svg{width:4ch}.bm-12>.bm-11{flex-direction:column;align-items:flex-start;gap:0}.bm-12 small{font-size:.75em}#bm-_ .bm-12.bm-1a{display:none}`;GM_addStyle(G);var F,Y="@font-face{font-family:'Roboto Mono';font-style:normal;font-weight:400;src:url(data:font/woff2;base64,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)format('woff2');}";Y.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(Y)):((F=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",F.rel="preload",F.as="style",F.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(F)),new class{constructor(){this.oe=null,this.ae=null,this.re="#bm-h"}le(t){return this.ae=t,this.oe=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.re)}),this}ce(){return this.oe}observe(t,e=!1,i=!1){t.observe(this.ae,{childList:e,subtree:i})}};var _=new class extends y{constructor(t,i){super(t,i),e(this,N),this.window=null,this.Tt="bm-17",this.St=document.body}kt(){document.querySelector(`#${this.Tt}`)?this.$t("Main window already exists!"):(this.window=this.B({id:this.Tt,class:"bm-1l",style:"top: 10px; left: unset; right: 75px;"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().L().B({class:"bm-U"}).B({class:"bm-1d"}).U({class:"bm-1k",src:"data:image/png;base64,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"},(t,e)=>{const i=new Date;204==Math.floor((i.getTime()-new Date(i.getFullYear(),0,1))/864e5)+1&&(e.parentNode.style.position="relative",e.parentNode.innerHTML=e.parentNode.innerHTML+'',e.onload=()=>{(new k).zt(document.querySelector(`#${this.Tt}`))})}).L().G(1,{textContent:this.name}).L().L().F().L().B({class:"bm-1d"}).A({id:"bm-p",textContent:"Droplets:"}).L().Y().L().A({id:"bm-i",textContent:"Next level in..."}).L().Y().L().A({textContent:"Charges: "}).yt(Date.now(),1e3,{style:"font-weight: 700;"},(t,e)=>{t.T.he=e.id}).L().L().L().F().L().B({class:"bm-1d"}).B({class:"bm-1d"}).ht({class:"bm-Z bm-1b",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.T?.me;e?.[0]?(t.ut("bm-v",e?.[0]||""),t.ut("bm-w",e?.[1]||""),t.ut("bm-x",e?.[2]||""),t.ut("bm-y",e?.[3]||"")):t.$t("Coordinates are malformed! Did you try clicking on the canvas first?")}}).L().bt({type:"number",id:"bm-v",class:"bm-14",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-w",class:"bm-14",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-x",class:"bm-14",placeholder:"Px X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-y",class:"bm-14",placeholder:"Px Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().L().B({class:"bm-1d"}).gt({class:"bm-1c",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).L().L().B({class:"bm-1d bm-11"}).ht({textContent:"Disable","data-button-status":"shown"},(t,e)=>{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.T?.Et?.de(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.Mt("Disabled templates!")):(t.T?.Et?.de(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.Mt("Enabled templates!")),e.disabled=!1}}).L().ht({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector(`#${this.Tt} .bm-1c`),i=document.querySelector("#bm-v");if(!i.checkValidity())return i.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const n=document.querySelector("#bm-w");if(!n.checkValidity())return n.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-x");if(!s.checkValidity())return s.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-y");if(!o.checkValidity())return o.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(t?.T?.Et.ue(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(i.value),Number(n.value),Number(s.value),Number(o.value)]),t.Mt("Drew to canvas!")):t.$t("No file selected!")}}).L().ht({textContent:"Filter"},(t,e)=>{e.onclick=()=>i(this,N,B).call(this)}).L().L().B({class:"bm-1d"}).ft({id:this.S,placeholder:`Status: Sleeping...\nVersion: ${this.version}`,readOnly:!0}).L().L().B({class:"bm-1d bm-11",style:"margin-bottom: 0;"}).B({class:"bm-11"}).ht({class:"bm-Z",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).L().ht({class:"bm-Z",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).L().L().P({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).L().L().L().L().L().N(this.St),this.xt(`#${this.Tt}.bm-1l`,`#${this.Tt} .bm-1j`))}}(H,U),z=new class{constructor(t,i,n){e(this,v),this.name=t,this.version=i,this.C=n,this.schemaVersion="1.1.0",this.be=null,this.pe="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.h=1e3,this.Nt=3,this.Wt=3,this.Ht=function(t){const e=p;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const i=new Map;for(const n of e){if(0==n.id||-2==n.id)continue;const e=n.rgb[0],s=n.rgb[1],o=n.rgb[2];for(let a=-t;a<=t;a++)for(let r=-t;r<=t;r++)for(let l=-t;l<=t;l++){const t=e+a,c=s+r,h=o+l;if(t<0||t>255||c<0||c>255||h<0||h>255)continue;const m=(255<<24|h<<16|c<<8|t)>>>0;i.has(m)||i.set(m,n.id)}}return{palette:e,M:i}}(this.Wt),this.Pt=null,this.ge="",this.Bt=[],this.Lt=null,this.fe=!0,this.we=null,this.Ut=new Map}async ye(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.schemaVersion,templates:{}}}async ue(t,e,n){this.Lt||(this.Lt=await this.ye(),console.log("Creating JSON...")),this.C.Mt(`Creating template at ${n.join(", ")}...`);const s=new g({displayName:e,t:0,i:a(this.be||0,this.pe),file:t,coords:n}),{v:o,$:r}=await s.u(this.h,this.Ht);s.o=o;const l={total:s.m.total,colors:Object.fromEntries(s.m.colors)};this.Lt.templates[`${s.t} ${s.i}`]={name:s.displayName,coords:n.join(", "),enabled:!0,pixels:l,tiles:r},this.Bt=[],this.Bt.push(s),this.C.Mt(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.Lt.templates).length),console.log(this.Lt),console.log(this.Bt),console.log(JSON.stringify(this.Lt)),await i(this,v,x).call(this)}ve(){}async xe(){this.Lt||(this.Lt=await this.ye(),console.log("Creating JSON..."))}async $e(t,e){if(!this.fe)return t;const n=this.h*this.Nt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const s=this.Bt;console.log(s),s.sort((t,e)=>t.t-e.t),console.log(s);const o=s.map(t=>{const i=Object.keys(t.o).filter(t=>t.startsWith(e));if(0===i.length)return null;const n=i.map(e=>{const i=e.split(",");return{Me:t,Te:t.o[e],l:t.l?.[e],Se:[i[0],i[1]],Ce:[i[2],i[3]]}});return n?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.C.Mt(`Sleeping\nVersion: ${this.version}`),t;{const t=s.filter(t=>Object.keys(t.o).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.m.total||0),0),i=(new Intl.NumberFormat).format(t);this.C.Mt(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${i}`)}const r=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const h=c.getImageData(0,0,n,n),m=new Uint32Array(h.data.buffer);for(const t of o){console.log("Template:"),console.log(t);const n=!!t.Me.m?.colors?.get(-1);let s=t.l.slice();const o=Number(t.Ce[0])*this.Nt,a=Number(t.Ce[1])*this.Nt;if(0!=this.Ut.size||n||c.drawImage(t.Te,o,a),!s){const e=c.getImageData(o,a,t.Te.width,t.Te.height);s=new Uint32Array(e.data.buffer)}const r=Date.now(),{Gt:l,Ft:h}=i(this,v,M).call(this,{It:m,Pt:s,At:[o,a,t.Te.width,t.Te.height]});let d=0;const u=0;for(const[t,e]of l)t!=u&&(d+=e);(0!=this.Ut.size||n)&&(console.log("Colors to filter: ",this.Ut),c.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(h.buffer),t.Te.width,t.Te.height)),o,a)),console.log(`Finished calculating correct pixels & filtering colors for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${d} correct pixels.`),void 0===t.Me.m.correct&&(t.Me.m.correct={}),t.Me.m.correct[e]=l}return await l.convertToBlob({type:"image/png"})}De(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&i(this,v,$).call(this,t)}de(t){this.fe=t}}(H,U,_),E=new class{constructor(t){this.Et=t,this.Oe=!1,this.he="",this.me=[],this.ke=[]}Le(t){window.addEventListener("message",async e=>{const i=e.data,n=i.jsonData;if(!i||"blue-marble"!==i.source)return;if(!i.endpoint)return;const s=i.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",s),s){case"me":if(n.status&&"2"!=n.status?.toString()[0])return void t.$t("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(n.level)*Math.pow(30,.65),1/.65)-n.pixelsPainted);if(console.log(n.id),(n.id||0===n.id)&&console.log(a(n.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Et.be=n.id,0!=this.he.length){const t=document.querySelector("#"+this.he);if(t){const e=n.charges;t.dataset.endDate=Date.now()+(e.max-e.count)*e.cooldownMs}}t.ut("bm-p",`Droplets: ${(new Intl.NumberFormat).format(n.droplets)}`),t.ut("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=i.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),l=new URLSearchParams(i.endpoint.split("?")[1]),c=[l.get("x"),l.get("y")];if(this.me.length&&(!s.length||!c.length))return void t.$t("Coordinates are malformed!\nDid you try clicking the canvas first?");this.me=[...s,...c];const h=(o=s,r=c,[parseInt(o[0])%4*1e3+parseInt(r[0]),parseInt(o[1])%4*1e3+parseInt(r[1])]),m=document.querySelectorAll("span");for(const t of m)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-h");const i=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=i:(e=document.createElement("span"),e.id="bm-h",e.textContent=i,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=i.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const u=i.blobID,b=i.blobData,p=Date.now(),g=await this.Et.$e(b,d);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:g,blink:i.blink});break;case"robots":this.Oe="false"==n.userscript?.toString().toLowerCase();break}var o,r})}async Ne(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const i=navigator.userAgent;let n=await this.Be(i),s=this.Ie(i);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:n,os:s}),onload:t=>{200!==t.status&&o("Failed to send heartbeat:",t.statusText)},onerror:t=>{o("Error sending heartbeat:",t)}})}async Be(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"}Ie(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}}(z);_.k(E);var R=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(R),z.De(R);var j=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(j),console.log(Object.keys(j).length),0==Object.keys(j).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}setInterval(()=>E.Ne(U),18e5);var X=j?.telemetry;if(console.log(`Telemetry is ${!(null==X)}`),null==X||X>1){const t=new class extends y{constructor(t,i,n,s){super(t,i),e(this,P),this.window=null,this.Tt="bm-T",this.St=document.body,this.Pe=n,this.uuid=s}async kt(){if(document.querySelector(`#${this.Tt}`))return void this.$t("Telemetry window already exists!");const t=await this.T.Be(navigator.userAgent),e=this.T.Ie(navigator.userAgent);this.window=this.B({id:this.Tt,class:"bm-1l",style:"height: 80vh; z-index: 9998;"}).B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:`${this.name} Telemetry`}).L().L().F().L().B({class:"bm-1d bm-15",style:"gap: 1.5ch; flex-wrap: wrap;"}).ht({textContent:"Enable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,P,A).call(this,this.Pe);const t=document.getElementById(this.Tt);t?.remove()}}).L().ht({textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,P,A).call(this,0);const t=document.getElementById(this.Tt);t?.remove()}}).L().ht({textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).L().L().B({class:"bm-1d bm-19"}).B({class:"bm-1d"}).G(2,{textContent:"Legal"}).L().I({textContent:`We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the "Disable" button, but keeping it on helps us improve features and reliability faster. Thank you for supporting ${this.name}!`}).L().L().F().L().B({class:"bm-1d"}).G(2,{textContent:"Non-Legal Summary"}).L().I({innerHTML:'You can disable telemetry by pressing the "Disable" button. If you would like to read more about what information we collect, press the "More Information" button.
This is the data stored on our servers:'}).L().Z().tt({innerHTML:`A unique identifier (UUIDv4) generated by Blue Marble. This enables our telemetry to function without tracking your actual user ID.
Your UUID is: ${n(this.uuid)}`}).L().tt({innerHTML:`The version of Blue Marble you are using.
Your version is: ${n(this.version)}`}).L().tt({innerHTML:`Your browser type, which is used to determine Blue Marble outages and browser popularity.
Your browser type is: ${n(t)}`}).L().tt({innerHTML:`Your OS type, which is used to determine Blue Marble outages and OS popularity.
Your OS type is: ${n(e)}`}).L().tt({innerHTML:"The date and time that Blue Marble sent the telemetry information."}).L().L().I({innerHTML:'All of the data mentioned above is aggregated every hour. This means every hour, anything that could even remotly be considered "personal data" is deleted from our server. Here, "aggregated" data means things like "42 people used Blue Marble on Google Chrome this hour", which can\'t be used to identify anyone in particular.'}).L().L().L().L().L().N(this.St)}}(H,U,1,j?.uuid);t.k(E),t.kt()}_.kt(),E.Le(_),new MutationObserver((t,e)=>{const i=document.querySelector("#color-1");if(!i)return;let n=document.querySelector("#bm-t");if(!n){n=document.createElement("button"),n.id="bm-t",n.textContent="Move ↑",n.className="btn btn-soft",n.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=i.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(n)}}).observe(document.body,{childList:!0,subtree:!0}),s(`%c${H}%c (${U}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/dist/BlueMarble.user.css b/dist/BlueMarble.user.css index 8637962..4bca6ec 100644 --- a/dist/BlueMarble.user.css +++ b/dist/BlueMarble.user.css @@ -1 +1 @@ -div:has(>confetti-piece){position:absolute;inset:0;overflow:hidden;pointer-events:none}confetti-piece{position:absolute;top:-10px;width:var(--size);height:var(--size);background:currentColor;transform:translate3d(var(--x),-10vh,0) rotate(var(--rot));animation:fall var(--duration) linear var(--delay);will-change:transform;pointer-events:none}@keyframes fall{to{transform:translate3d(var(--x),110vh,0) rotate(calc(var(--rot) + 720deg))}}.bm-screenreader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1j{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:fit-content;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-14{max-width:300px}.bm-1h{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1h.bm-1c{cursor:grabbing}.bm-1j:has(.bm-1h.bm-1c){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1h.bm-1c{pointer-events:auto}.bm-1i{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1j h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1h h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1h div:has(h1){display:contents}.bm-1j h2{display:inline-block;font-size:larger;font-weight:700;vertical-align:middle}.bm-1b.bm-Q{width:fit-content;margin-left:auto;margin-right:auto}.bm-1b{margin:.5em 0}.bm-1j button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1j button:hover,.bm-1j button:focus-visible{background-color:#1061e5}.bm-1j button:active,.bm-1j button:disabled{background-color:#2e97ff}.bm-1j button:disabled{text-decoration:line-through}.bm-Z{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-19{vertical-align:middle}.bm-19 svg{width:50%;margin:0 auto;fill:#111}.bm-1j button.bm-11{background-color:unset}.bm-11.bm-O:hover,.bm-11.bm-O:focus{background-color:#ffffff2b}.bm-11.bm-O:active{background-color:#ffffff38}.bm-11.bm-P:hover,.bm-11.bm-P:focus{background-color:#0000002b}.bm-11.bm-P:active{background-color:#00000038}input[type=number].bm-12{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-12::-webkit-outer-spin-button,input[type=number].bm-12::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-1a)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-1a,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-1j select{color:#fff;background-color:#144eb9;border-radius:1em;padding:0 .5ch}.bm-1j label:has(input[type=checkbox]){display:flex;width:fit-content;gap:1ch}.bm-1j input[type=checkbox]{width:1em}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1j textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1j small{font-size:x-small;color:#d3d3d3}.bm-1j ul li{list-style:disc;margin-left:5ch}.bm-1j .bm-1b.bm-17{max-height:calc(80vh - 150px);overflow:auto}.bm-_{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-15{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-Y p svg{display:inline;height:1em;fill:#fff}.bm-13{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:1em 3ch}.bm-10{width:fit-content;max-width:35ch;background-color:#153063e6;border-radius:1em;padding:.5em;gap:1ch;transition:background-color .3s ease}.bm-10:hover,.bm-10:focus-within{background-color:#112855e6}.bm-K{display:block;border:thick double darkslategray;width:fit-content;height:fit-content;padding:1ch}.bm-10[data-id="-2"] .bm-K{background:conic-gradient(#a00,#aa0 16.6%,#0a0,#0aa 50%,#00a 66.6%,#a0a,#a00)}.bm-10[data-id="-1"] .bm-K{background:url('data:image/svg+xml;utf8,') repeat;background-color:transparent!important}.bm-10[data-id="-1"] .bm-K svg{fill:#fff!important}.bm-10[data-id="0"] .bm-K{background-color:transparent!important}.bm-K button{padding:.75em .5ch}.bm-K svg{width:4ch}.bm-10>.bm-_{flex-direction:column;align-items:flex-start;gap:0}.bm-10 small{font-size:.75em}#bm-Y .bm-10.bm-18{display:none} +div:has(>confetti-piece){position:absolute;inset:0;overflow:hidden;pointer-events:none}confetti-piece{position:absolute;top:-10px;width:var(--size);height:var(--size);background:currentColor;transform:translate3d(var(--x),-10vh,0) rotate(var(--rot));animation:fall var(--duration) linear var(--delay);will-change:transform;pointer-events:none}@keyframes fall{to{transform:translate3d(var(--x),110vh,0) rotate(calc(var(--rot) + 720deg))}}.bm-screenreader{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.bm-1l{position:fixed;background-color:#153063e6;color:#fff;padding:10px;border-radius:8px;z-index:9000;transition:all .3s ease,transform 0s;top:75px;left:60px;width:auto;max-height:fit-content;max-width:calc(100% - 135px);font-family:Roboto Mono,Courier New,Monaco,DejaVu Sans Mono,monospace,Arial;letter-spacing:.05em}#bm-17{max-width:300px}.bm-1j{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:.5ch;background:url('data:image/svg+xml;utf8,') repeat;cursor:grab;width:100%;height:fit-content}.bm-1j.bm-1e{cursor:grabbing}.bm-1l:has(.bm-1j.bm-1e){pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.bm-1j.bm-1e{pointer-events:auto}.bm-1k{display:inline-block;height:2.5em;margin-right:1ch;vertical-align:middle}.bm-1l h1{display:inline-block;font-size:x-large;font-weight:700;vertical-align:middle}.bm-1j h1{font-size:1.2em;user-select:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-shadow:3px 0px rgba(21,48,99,.5),-3px 0px rgba(21,48,99,.5),0px 3px rgba(21,48,99,.5),0px -3px rgba(21,48,99,.5),3px 3px rgba(21,48,99,.5),-3px 3px rgba(21,48,99,.5),3px -3px rgba(21,48,99,.5),-3px -3px rgba(21,48,99,.5)}.bm-1j div:has(h1){display:contents}.bm-1l h2{display:inline-block;font-size:larger;font-weight:700;vertical-align:middle}.bm-1d.bm-Q{width:fit-content;margin-left:auto;margin-right:auto}.bm-1d{margin:.5em 0}.bm-1l button{background-color:#144eb9;border-radius:1em;padding:0 .75ch}.bm-1l button:hover,.bm-1l button:focus-visible{background-color:#1061e5}.bm-1l button:active,.bm-1l button:disabled{background-color:#2e97ff}.bm-1l button:disabled{text-decoration:line-through}.bm-Z{border:white 1px solid;height:1.5em;width:1.5em;margin-top:2px;text-align:center;line-height:1em;padding:0!important}.bm-1b{vertical-align:middle}.bm-1b svg{width:50%;margin:0 auto;fill:#111}.bm-1l button.bm-13{background-color:unset}.bm-13.bm-O:hover,.bm-13.bm-O:focus{background-color:#ffffff2b}.bm-13.bm-O:active{background-color:#ffffff38}.bm-13.bm-P:hover,.bm-13.bm-P:focus{background-color:#0000002b}.bm-13.bm-P:active{background-color:#00000038}input[type=number].bm-14{appearance:auto;-moz-appearance:textfield;width:5.5ch;margin-left:1ch;background-color:#0003;padding:0 .5ch;font-size:small}input[type=number].bm-14::-webkit-outer-spin-button,input[type=number].bm-14::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}div:has(>.bm-1c)>button{width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bm-1c,input[type=file]{display:none!important;visibility:hidden!important;position:absolute!important;left:-9999px!important;top:-9999px!important;width:0!important;height:0!important;opacity:0!important;z-index:-9999!important;pointer-events:none!important}.bm-1l select{color:#fff;background-color:#144eb9;border-radius:1em;padding:0 .5ch}.bm-1l label:has(input[type=checkbox]){display:flex;width:fit-content;gap:1ch}.bm-1l input[type=checkbox]{width:1em}.bm-U{overflow:hidden;transition:height .3s cubic-bezier(.4,0,.2,1)}.bm-1l textarea{font-size:small;background-color:#0003;padding:0 .5ch;height:5.25em;width:100%}.bm-1l small{font-size:x-small;color:#d3d3d3}.bm-1l ul li{list-style:disc;margin-left:5ch}.bm-1l .bm-1d.bm-19{max-height:calc(80vh - 150px);overflow:auto}.bm-11{display:flex;align-content:center;justify-content:space-between;align-items:center;gap:.5ch}.bm-15{display:flex;align-content:center;justify-content:center;align-items:center;gap:.5ch}#bm-_ p svg{display:inline;height:1em;fill:#fff}.bm-16{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;gap:1em 3ch}.bm-12{width:fit-content;max-width:35ch;background-color:#153063e6;border-radius:1em;padding:.5em;gap:1ch;transition:background-color .3s ease}.bm-12:hover,.bm-12:focus-within{background-color:#112855e6}.bm-K{display:block;border:thick double darkslategray;width:fit-content;height:fit-content;padding:1ch}.bm-12[data-id="-2"] .bm-K{background:conic-gradient(#a00,#aa0 16.6%,#0a0,#0aa 50%,#00a 66.6%,#a0a,#a00)}.bm-12[data-id="-1"] .bm-K{background:url('data:image/svg+xml;utf8,') repeat;background-color:transparent!important}.bm-12[data-id="-1"] .bm-K svg{fill:#fff!important}.bm-12[data-id="0"] .bm-K{background-color:transparent!important}.bm-K button{padding:.75em .5ch}.bm-K svg{width:4ch}.bm-12>.bm-11{flex-direction:column;align-items:flex-start;gap:0}.bm-12 small{font-size:.75em}#bm-_ .bm-12.bm-1a{display:none} diff --git a/dist/BlueMarble.user.js b/dist/BlueMarble.user.js index 84bf716..1753610 100644 --- a/dist/BlueMarble.user.js +++ b/dist/BlueMarble.user.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.433 +// @version 0.88.440 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine @@ -28,4 +28,4 @@ // License --> https://www.mozilla.org/en-US/MPL/2.0/ // Donate --> https://ko-fi.com/swingthevine -(()=>{var t=t=>{throw TypeError(t)},e=(e,i,n)=>i.has(e)?t("Cannot add the same private member more than once"):i instanceof WeakSet?i.add(e):i.set(e,n),i=(e,i,n)=>(((e,i)=>{i.has(e)||t("Cannot access private method")})(e,i),n);function n(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function s(...t){(0,console.log)(...t)}function o(...t){(0,console.error)(...t)}function a(t,e){if(0===t)return e[0];let i="";const n=e.length;for(;t>0;)i=e[t%n]+i,t=Math.floor(t/n);return i}function r(t){let e="";for(let i=0;i(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}var h,m,d,u,b,p,f=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],g=class{constructor({displayName:t="My template",t:i=0,i:n="",url:s="",file:o=null,coords:a=null,o:r=null,l:l={},h:c=1e3}={}){e(this,h),this.displayName=t,this.t=i,this.i=n,this.url=s,this.file=o,this.coords=a,this.o=r,this.l=l,this.h=c,this.m={total:0,colors:new Map}}async u(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),s=n.width,o=n.height;this.h=t;const a={},l={},c=new OffscreenCanvas(this.h,this.h),d=c.getContext("2d",{p:!0});c.width=s,c.height=o,d.imageSmoothingEnabled=!1,d.drawImage(n,0,0);let u=Date.now();const b=i(this,h,m).call(this,d.getImageData(0,0,s,o),e);console.log(`Calculating total pixels took ${(Date.now()-u)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.m={total:p,colors:b},u=Date.now();const f=new OffscreenCanvas(3,3),g=f.getContext("2d");g.clearRect(0,0,3,3),g.fillStyle="white",g.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:s.get(e)??-2;const a=o.get(n);o.set(n,a?a+1:1)}return console.log(o),o},d=new WeakSet,u=async function(){GM.setValue("bmTemplates",JSON.stringify(this.T))},b=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;if(console.log(`BlueMarble length: ${Object.keys(e).length}`),Object.keys(e).length>0)for(const t in e){const i=t,n=e[t];if(console.log(`Template Key: ${i}`),e.hasOwnProperty(t)){const t=i.split(" "),e=Number(t?.[0]),s=t?.[1]||"0",o=n.name||`Template ${e||""}`,a={total:n.pixels.total,colors:new Map(Object.entries(n.pixels.colors).map(([t,e])=>[Number(t),e]))},r=n.tiles,c={},h={},m=this.h*this.S;for(const t in r)if(console.log(t),r.hasOwnProperty(t)){const e=l(r[t]),i=new Blob([e],{type:"image/png"}),n=await createImageBitmap(i);c[t]=n;const s=new OffscreenCanvas(m,m).getContext("2d");s.drawImage(n,0,0);const o=s.getImageData(0,0,n.width,n.height);h[t]=new Uint32Array(o.data.buffer)}const d=new g({displayName:o,t:e||this.C?.length||0,i:s||""});d.m=a,d.o=c,d.l=h,this.C.push(d),console.log(this.C),console.log("^^^ This ^^^")}}},p=function({D:t,O:e,k:i}){const n=this.S,s=this.h*n,o=i[0],a=i[1],r=i[2],l=i[3],c=this.L,{palette:h,M:m}=this.N,d=new Map;for(let i=1;i>>24&255,g=b>>>24&255,w=m.get(p)??-2;if(this.B.get(w)&&(e[i*r+l]=b),-1==w){const t=536870912;this.B.get(w)?e[i*r+l]=0:(h/n&1)==(u/n&1)?(e[i*r+l]=t,e[(i-1)*r+(l-1)]=t,e[(i-1)*r+(l+1)]=t,e[(i+1)*r+(l-1)]=t,e[(i+1)*r+(l+1)]=t):(e[i*r+l]=0,e[(i-1)*r+l]=t,e[(i+1)*r+l]=t,e[i*r+(l-1)]=t,e[i*r+(l+1)]=t)}if(-1==w&&b<=c){const t=d.get(w);d.set(w,t?t+1:1);continue}if(f<=c||g<=c)continue;if((m.get(b)??-2)!=w)continue;const y=d.get(w);d.set(w,y?y+1:1)}return console.log("List of template pixels that match the tile:"),console.log(d),{I:d,P:e}};var w,y,v,x=class{constructor(){this.A=Math.ceil(80/1300*window.innerWidth),this.H=f.slice(1)}U(t){const e=document.createElement("div");for(let t=0;t{t.parentNode.childElementCount<=1?t.parentNode.remove():t.remove()},e.appendChild(t)}t.appendChild(e)}},$=class extends HTMLElement{};customElements.define("confetti-piece",$);var M,T,S,C,D=class{constructor(t,i){e(this,w),this.name=t,this.version=i,this.W=null,this.G="bm-o",this.F=null,this.Y=null,this._=[]}j(t){this.W=t}X(){return this._.length>0&&(this.Y=this._.pop()),this}R(t){t?.appendChild(this.F),this.F=null,this.Y=null,this._=[]}J(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"div",{},t)),this}V(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"p",{},t)),this}q(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"small",{},t)),this}Z(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"span",{},t)),this}K(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"details",{},t)),this}tt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"summary",{},t)),this}et(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"img",{},t)),this}it(t,e={},n=()=>{}){return n(this,i(this,w,y).call(this,"h"+t,{},e)),this}nt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"hr",{},t)),this}st(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"br",{},t)),this}ot(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"form",{},t)),this}rt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"fieldset",{},t)),this}lt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"legend",{},t)),this}ct(t={},e=()=>{}){const n=i(this,w,y).call(this,"label",{textContent:t.textContent??""});delete t.textContent;const s=i(this,w,y).call(this,"input",{type:"checkbox"},t);return n.insertBefore(s,n.firstChild),this.X(),e(this,n,s),this}ht(t={},e=()=>{}){const n=i(this,w,y).call(this,"label",{textContent:t.textContent??"",for:t.id??""});return delete t.textContent,this.X(),e(this,n,i(this,w,y).call(this,"select",{},t)),this}dt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"option",{},t)),this}ut(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"ol",{},t)),this}bt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"ul",{},t)),this}ft(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"menu",{},t)),this}gt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"li",{},t)),this}wt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"table",{},t)),this}yt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"caption",{},t)),this}vt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"thead",{},t)),this}xt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tbody",{},t)),this}$t(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tfoot",{},t)),this}Mt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"tr",{},t)),this}Tt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"th",{},t)),this}St(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"td",{},t)),this}Ct(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"button",{},t)),this}Dt(t={},e=()=>{}){const n=t.title??t.textContent??"Help: No info";delete t.textContent,t.title=`Help: ${n}`;const s={textContent:"?",className:"bm-D",onclick:()=>{this.Ot(this.G,n)}};return e(this,i(this,w,y).call(this,"button",s,t)),this}kt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"input",{},t)),this}Lt(t={},e=()=>{}){const n=t.textContent??"";delete t.textContent;const s=i(this,w,y).call(this,"div"),o=i(this,w,y).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true"},t);this.X();const a=i(this,w,y).call(this,"button",{textContent:n});return this.X(),this.X(),a.addEventListener("click",()=>{o.click()}),o.addEventListener("change",()=>{a.style.maxWidth=`${a.offsetWidth}px`,o.files.length>0?a.textContent=o.files[0].name:a.textContent=n}),e(this,s,o,a),this}Nt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"textarea",{},t)),this}Bt(t={},e=()=>{}){return e(this,i(this,w,y).call(this,"div",{class:"bm-1h"},t)),this}It(t=Date.now(),e=500,n={},s=()=>{}){const o="bm-1l",a=n?.id||o+"-"+crypto.randomUUID().slice(0,8),r={class:o},l=i(this,w,y).call(this,"time",r,n);return l.id=a,l.dataset.endDate=t,setInterval(()=>{if(!l.isConnected)return;const t=Math.max(l.dataset.endDate-Date.now(),0),e=Math.floor(t/1e3),i=Math.floor(e/3600),n=Math.floor(e%60),s=Math.floor(e%3600/60);l.setAttribute("datetime",`PT${i}H${s}M${n}S`),l.textContent=String(i).padStart(2,"0")+":"+String(s).padStart(2,"0")+":"+String(n).padStart(2,"0")},e),s(this,l),this}Ot(t,e,i=!1){const n=document.getElementById(t.replace(/^#/,""));n&&(n instanceof HTMLInputElement?n.value=e:i?n.textContent=e:n.innerHTML=e)}Pt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1j"),i=t.closest(".bm-1h"),n=e.querySelector("h1"),s=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){s.style.height=s.scrollHeight+"px",e.style.width=e.scrollWidth+"px",s.style.height="0",s.addEventListener("transitionend",function e(){s.style.display="none",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)});const i=n.cloneNode(!0),o=i.textContent;t.nextElementSibling.appendChild(i),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${o}"`}else{const n=i.querySelector("h1"),o=n.textContent;n.remove(),s.style.display="",s.style.height="0",e.style.width="",s.style.height=s.scrollHeight+"px",s.addEventListener("transitionend",function e(){s.style.height="",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${o}"`}}At(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.Ht(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let i,n=!1,s=0,o=null,a=0,r=0,l=0,c=0,h=null;const m=()=>{if(n){const e=Math.abs(a-l),i=Math.abs(r-c);(e>.5||i>.5)&&(a=l,r=c,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),o=requestAnimationFrame(m)}},d=(d,f)=>{n=!0,h=t.getBoundingClientRect(),i=d-h.left,s=f-h.top;const g=window.getComputedStyle(t).transform;if(g&&"none"!==g){const t=new DOMMatrix(g);a=t.m41,r=t.m42}else a=h.left,r=h.top;l=a,c=r,document.body.style.userSelect="none",e.classList.add("bm-1c"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),o&&cancelAnimationFrame(o),m()},u=()=>{n=!1,o&&(cancelAnimationFrame(o),o=null),document.body.style.userSelect="",e.classList.remove("bm-1c"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{n&&h&&(l=t.clientX-i,c=t.clientY-s)},p=t=>{if(n&&h){const e=t.touches[0];if(!e)return;l=e.clientX-i,c=e.clientY-s,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),d(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(d(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}Ut(t){(0,console.info)(`${this.name}: ${t}`),this.Ot(this.G,"Status: "+t,!0)}Ht(t){(0,console.error)(`${this.name}: ${t}`),this.Ot(this.G,"Error: "+t,!0)}};w=new WeakSet,y=function(t,e={},n={}){const s=document.createElement(t);this.F?(this.Y?.appendChild(s),this._.push(this.Y),this.Y=s):(this.F=s,this.Y=s);for(const[t,n]of Object.entries(e))i(this,w,v).call(this,s,t,n);for(const[t,e]of Object.entries(n))i(this,w,v).call(this,s,t,e);return s},v=function(t,e,i){if("class"==e)t.classList.add(...i.split(/\s+/));else if("for"==e)t.htmlFor=i;else if("tabindex"==e)t.tabIndex=Number(i);else if("readonly"==e)t.readOnly="true"==i||"1"==i;else if("maxlength"==e)t.maxLength=Number(i);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=i;else if(e.startsWith("aria")){const n=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+n[0].toUpperCase()+n.slice(1)]=i}else t[e]=i};var O,k,L,N,B,I=class extends D{constructor(t){super(t.name,t.version),e(this,M),this.window=null,this.Wt="bm-Y",this.Gt=document.body,this.Ft=t.W?.Ft,this.Et='',this.Yt='',this._t=new Intl.NumberFormat,this.jt=new Intl.NumberFormat(void 0,{style:"percent",Xt:2,Rt:2}),this.Jt={Vt:"long",zt:"numeric",qt:"2-digit",Qt:"2-digit",Zt:"2-digit"};const{palette:i,M:n}=this.Ft.N;this.palette=i,this.Kt=0,this.te=0}ee(){if(document.querySelector(`#${this.Wt}`))return void this.Ht("Color Filter window already exists!");this.window=this.J({id:this.Wt,class:"bm-1j"}).Bt().Ct({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.Pt(e),e.ontouchend=()=>{e.click()}}).X().J().X().Ct({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Wt}`)?.remove()},e.ontouchend=()=>{e.click()}}).X().X().J({class:"bm-U"}).J({class:"bm-1b bm-Q"}).it(1,{textContent:"Color Filter"}).X().X().nt().X().J({class:"bm-1b bm-_ bm-Q",style:"gap: 1.5ch;"}).Ct({textContent:"Select All"},(t,e)=>{e.onclick=()=>i(this,M,C).call(this,!1)}).X().Ct({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>i(this,M,C).call(this,!0)}).X().X().J({class:"bm-1b bm-17"}).J({class:"bm-1b",style:"margin-left: 2.5ch; margin-right: 2.5ch;"}).J({class:"bm-1b"}).Z({id:"bm-R",innerHTML:"Tiles Loaded: 0 / ???"}).X().st().X().Z({id:"bm-M",innerHTML:"Correct Pixels: ???"}).X().st().X().Z({id:"bm-S",innerHTML:"Total Pixels: ???"}).X().st().X().Z({id:"bm-I",innerHTML:"Complete: ??? (???)"}).X().st().X().Z({id:"bm-J",innerHTML:"??? ???"}).X().X().J({class:"bm-1b"}).V({innerHTML:`Colors with the icon ${this.Et.replace("{e.onclick=t=>{t.preventDefault();const e=new FormData(document.querySelector(`#${this.Wt} form`)),n={};for(const[t,i]of e)n[t]=i;console.log(`Primary: ${n.sortPrimary}; Secondary: ${n.sortSecondary}; Unused: ${"on"==n.showUnused}`),i(this,M,S).call(this,n.sortPrimary,n.sortSecondary,"on"==n.showUnused)}}).X().X().X().X().X().X().X().R(this.Gt),this.At(`#${this.Wt}.bm-1j`,`#${this.Wt} .bm-1h`);const t=document.querySelector(`#${this.Wt} .bm-1b.bm-17`);let e=0,n=0;const s=new Map,o=new Map;for(const t of this.Ft.C){e+=t.m?.total??0??0;const i=t.m?.colors??new Map;for(const[t,e]of i){const i=Number(e)||0,n=o.get(t)??0;o.set(t,n+i)}const a=t.m?.correct??{};this.Kt+=Object.keys(a).length,this.te+=Object.keys(t.o).length;for(const t of Object.values(a))for(const[e,i]of t){const t=Number(i)||0;n+=t;const o=s.get(e)??0;s.set(e,o+t)}}console.log(`Tiles loaded: ${this.Kt} / ${this.te}`),n>=e&&e&&this.Kt==this.te&&(new x).U(document.querySelector(`#${this.Wt}`));const a=new Date(30*(e-n)*1e3+Date.now()),r=a.toLocaleString(void 0,this.Jt);this.Ot("#bm-R",`Tiles Loaded: ${this._t.format(this.Kt)} / ${this._t.format(this.te)}`),this.Ot("#bm-M",`Correct Pixels: ${this._t.format(n)}`),this.Ot("#bm-S",`Total Pixels: ${this._t.format(e)}`),this.Ot("#bm-I",`Remaining: ${this._t.format((e||0)-(n||0))} (${this.jt.format(((e||0)-(n||0))/(e||1))})`),this.Ot("#bm-J",`Completed at: `),i(this,M,T).call(this,t,s,o),i(this,M,S).call(this,"id","ascending",!1)}};M=new WeakSet,T=function(t,e,i){const n=new D(this.name,this.version);n.J({class:"bm-13"});for(const t of this.palette){const s=c(t.rgb);let o=1.05/(s+.05)>(s+.05)/.05?"white":"black";t.id||(o="transparent");const a="white"==o?"bm-O":"bm-P",r=i.get(t.id)??0,l=this._t.format(r);let h=0,m="0",d=this.jt.format(1);0!=r&&(h=e.get(t.id)??"???","number"!=typeof h&&this.Kt==this.te&&t.id&&(h=0),m="string"==typeof h?h:this._t.format(h),d=isNaN(h/r)?"???":this.jt.format(h/r));const u=parseInt(r)-parseInt(h),b=!!this.Ft.B.get(t.id);n.J({class:"bm-1b bm-10 bm-_","data-id":t.id,"data-name":t.name,"data-premium":+t.premium,"data-correct":Number.isNaN(parseInt(h))?"0":h,"data-total":r,"data-percent":"%"==d.slice(-1)?d.slice(0,-1):"0","data-incorrect":u||0}).J({class:"bm-K",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).Ct({class:"bm-11 "+a,"data-state":b?"hidden":"shown","aria-label":b?`Show the color ${t.name||""} on templates.`:`Hide the color ${t.name||""} on templates.`,innerHTML:b?this.Yt.replace("{i.onclick=()=>{i.style.textDecoration="none",i.disabled=!0,"shown"==i.dataset.state?(i.innerHTML=this.Yt.replace("{const o=n.getAttribute("data-"+t),a=s.getAttribute("data-"+t),r=parseFloat(o),l=parseFloat(a),c=!isNaN(r),h=!isNaN(l);if(i?n.classList.remove("bm-18"):Number(n.getAttribute("data-total"))||n.classList.add("bm-18"),c&&h)return"ascending"===e?r-l:l-r;{const t=o.toLowerCase(),i=a.toLowerCase();return ti?"ascending"===e?1:-1:0}}),s.forEach(t=>n.appendChild(t))},C=function(t){const e=document.querySelector(".bm-13"),i=Array.from(e.children);for(const e of i){if(e.classList?.contains("bm-18"))continue;const i=e.querySelector(".bm-K button");("hidden"!=i.dataset.state||t)&&("shown"==i.dataset.state&&t||i.click())}},O=new WeakSet,k=function(){new I(this).ee()},L=async function(t,e,i){i.preventDefault();const n=await async function(t){let e="";return t&&(e=t.clipboardData.getData("text/plain")),0!=e.length||(await navigator.clipboard.readText().then(t=>{e=t}).catch(t=>{s("Failed to retrieve clipboard data using navigator! Using fallback methods...")}),0!=e.length||(e=window.clipboardData?.getData("Text"))),e}(i),o=n.split(/[^a-zA-Z0-9]+/).filter(t=>t).map(Number).filter(t=>!isNaN(t));2==o.length&&"bm-x"==e.id?(t.Ot("bm-x",o?.[0]||""),t.Ot("bm-y",o?.[1]||"")):1==o.length?t.Ot(e.id,o?.[0]||""):(t.Ot("bm-v",o?.[0]||""),t.Ot("bm-w",o?.[1]||""),t.Ot("bm-x",o?.[2]||""),t.Ot("bm-y",o?.[3]||""))},N=new WeakSet,B=function(t){const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=t,GM.setValue("bmUserSettings",JSON.stringify(e))};var P=GM_info.script.name.toString(),A=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",P),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",i=t?.getAttribute("bm-B")||"",n=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${n.size} Recieved IMAGE message about blob "${a}"`,i,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,i,""),console.log(n),console.groupEnd(),"blue-marble"==s&&a&&r&&!o){const t=n.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,i,"",a),n.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const o=await s.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,i,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,i,"",t)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const t=Date.now(),s=await a.blob();return console.log(`%c${e}%c: ${n.size} Sending IMAGE message about endpoint "${r}"`,i,""),new Promise(o=>{const l=crypto.randomUUID();n.set(l,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${n.size} Processed blob "${l}"`,i,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:s,blink:t})}).catch(s=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,i,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,i,""),console.log(`Endpoint: ${r}\nThere are ${n.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",s),console.groupEnd()})}return o}});var H=GM_getResourceText("CSS-BM-File");GM_addStyle(H);var U,W="robotoMonoInjectionPoint";W.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(W)):((U=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",U.rel="preload",U.as="style",U.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(U)),new class{constructor(){this.ie=null,this.ne=null,this.se="#bm-h"}oe(t){return this.ne=t,this.ie=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.se)}),this}ae(){return this.ie}observe(t,e=!1,i=!1){t.observe(this.ne,{childList:e,subtree:i})}};var G=new class extends D{constructor(t,i){super(t,i),e(this,O),this.window=null,this.Wt="bm-14",this.Gt=document.body}ee(){document.querySelector(`#${this.Wt}`)?this.Ht("Main window already exists!"):(this.window=this.J({id:this.Wt,class:"bm-1j",style:"top: 10px; left: unset; right: 75px;"}).Bt().Ct({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.Pt(e),e.ontouchend=()=>{e.click()}}).X().J().X().X().J({class:"bm-U"}).J({class:"bm-1b"}).et({class:"bm-1i",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"},(t,e)=>{const i=new Date;204==Math.floor((i.getTime()-new Date(i.getFullYear(),0,1))/864e5)+1&&(e.parentNode.style.position="relative",e.parentNode.innerHTML=e.parentNode.innerHTML+'',e.onload=()=>{(new x).U(document.querySelector(`#${this.Wt}`))})}).X().it(1,{textContent:this.name}).X().X().nt().X().J({class:"bm-1b"}).Z({id:"bm-p",textContent:"Droplets:"}).X().st().X().Z({id:"bm-i",textContent:"Next level in..."}).X().st().X().Z({textContent:"Charges: "}).It(Date.now(),1e3,{style:"font-weight: 700;"},(t,e)=>{t.W.re=e.id}).X().X().X().nt().X().J({class:"bm-1b"}).J({class:"bm-1b"}).Ct({class:"bm-Z bm-19",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.W?.le;e?.[0]?(t.Ot("bm-v",e?.[0]||""),t.Ot("bm-w",e?.[1]||""),t.Ot("bm-x",e?.[2]||""),t.Ot("bm-y",e?.[3]||"")):t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?")}}).X().kt({type:"number",id:"bm-v",class:"bm-12",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-w",class:"bm-12",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-x",class:"bm-12",placeholder:"Px X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().kt({type:"number",id:"bm-y",class:"bm-12",placeholder:"Px Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,O,L).call(this,t,e,n))}).X().X().J({class:"bm-1b"}).Lt({class:"bm-1a",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).X().X().J({class:"bm-1b bm-_"}).Ct({textContent:"Disable","data-button-status":"shown"},(t,e)=>{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.W?.Ft?.ce(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.Ut("Disabled templates!")):(t.W?.Ft?.ce(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.Ut("Enabled templates!")),e.disabled=!1}}).X().Ct({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector(`#${this.Wt} .bm-1a`),i=document.querySelector("#bm-v");if(!i.checkValidity())return i.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const n=document.querySelector("#bm-w");if(!n.checkValidity())return n.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-x");if(!s.checkValidity())return s.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-y");if(!o.checkValidity())return o.reportValidity(),void t.Ht("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(t?.W?.Ft.he(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(i.value),Number(n.value),Number(s.value),Number(o.value)]),t.Ut("Drew to canvas!")):t.Ht("No file selected!")}}).X().Ct({textContent:"Filter"},(t,e)=>{e.onclick=()=>i(this,O,k).call(this)}).X().X().J({class:"bm-1b"}).Nt({id:this.G,placeholder:`Status: Sleeping...\nVersion: ${this.version}`,readOnly:!0}).X().X().J({class:"bm-1b bm-_",style:"margin-bottom: 0;"}).J({class:"bm-_"}).Ct({class:"bm-Z",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).X().Ct({class:"bm-Z",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).X().X().q({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).X().X().X().X().X().R(this.Gt),this.At(`#${this.Wt}.bm-1j`,`#${this.Wt} .bm-1h`))}}(P,A),F=new class{constructor(t,i,n){e(this,d),this.name=t,this.version=i,this.F=n,this.me="1.0.0",this.de=null,this.ue="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.h=1e3,this.S=3,this.L=3,this.N=function(t){const e=f;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const i=new Map;for(const n of e){if(0==n.id||-2==n.id)continue;const e=n.rgb[0],s=n.rgb[1],o=n.rgb[2];for(let a=-t;a<=t;a++)for(let r=-t;r<=t;r++)for(let l=-t;l<=t;l++){const t=e+a,c=s+r,h=o+l;if(t<0||t>255||c<0||c>255||h<0||h>255)continue;const m=(255<<24|h<<16|c<<8|t)>>>0;i.has(m)||i.set(m,n.id)}}return{palette:e,M:i}}(this.L),this.O=null,this.be="",this.C=[],this.T=null,this.pe=!0,this.fe=null,this.B=new Map}async ge(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.me,templates:{}}}async he(t,e,n){this.T||(this.T=await this.ge(),console.log("Creating JSON...")),this.F.Ut(`Creating template at ${n.join(", ")}...`);const s=new g({displayName:e,t:0,i:a(this.de||0,this.ue),file:t,coords:n}),{v:o,$:r}=await s.u(this.h,this.N);s.o=o;const l={total:s.m.total,colors:Object.fromEntries(s.m.colors)};this.T.templates[`${s.t} ${s.i}`]={name:s.displayName,coords:n.join(", "),enabled:!0,pixels:l,tiles:r},this.C=[],this.C.push(s),this.F.Ut(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.T.templates).length),console.log(this.T),console.log(this.C),console.log(JSON.stringify(this.T)),await i(this,d,u).call(this)}we(){}async ye(){this.T||(this.T=await this.ge(),console.log("Creating JSON..."))}async ve(t,e){if(!this.pe)return t;const n=this.h*this.S;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const s=this.C;console.log(s),s.sort((t,e)=>t.t-e.t),console.log(s);const o=s.map(t=>{const i=Object.keys(t.o).filter(t=>t.startsWith(e));if(0===i.length)return null;const n=i.map(e=>{const i=e.split(",");return{xe:t,$e:t.o[e],l:t.l?.[e],Me:[i[0],i[1]],Te:[i[2],i[3]]}});return n?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.F.Ut(`Sleeping\nVersion: ${this.version}`),t;{const t=s.filter(t=>Object.keys(t.o).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.m.total||0),0),i=(new Intl.NumberFormat).format(t);this.F.Ut(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${i}`)}const r=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const h=c.getImageData(0,0,n,n),m=new Uint32Array(h.data.buffer);for(const t of o){console.log("Template:"),console.log(t);const n=!!t.xe.m?.colors?.get(-1);let s=t.l.slice();const o=Number(t.Te[0])*this.S,a=Number(t.Te[1])*this.S;if(0!=this.B.size||n||c.drawImage(t.$e,o,a),!s){const e=c.getImageData(o,a,t.$e.width,t.$e.height);s=new Uint32Array(e.data.buffer)}const r=Date.now(),{I:l,P:h}=i(this,d,p).call(this,{D:m,O:s,k:[o,a,t.$e.width,t.$e.height]});let u=0;const b=0;for(const[t,e]of l)t!=b&&(u+=e);(0!=this.B.size||n)&&(console.log("Colors to filter: ",this.B),c.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(h.buffer),t.$e.width,t.$e.height)),o,a)),console.log(`Finished calculating correct pixels & filtering colors for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${u} correct pixels.`),void 0===t.xe.m.correct&&(t.xe.m.correct={}),t.xe.m.correct[e]=l}return await l.convertToBlob({type:"image/png"})}Se(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&i(this,d,b).call(this,t)}ce(t){this.pe=t}}(P,A,G),E=new class{constructor(t){this.Ft=t,this.Ce=!1,this.re="",this.le=[],this.De=[]}Oe(t){window.addEventListener("message",async e=>{const i=e.data,n=i.jsonData;if(!i||"blue-marble"!==i.source)return;if(!i.endpoint)return;const s=i.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",s),s){case"me":if(n.status&&"2"!=n.status?.toString()[0])return void t.Ht("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(n.level)*Math.pow(30,.65),1/.65)-n.pixelsPainted);if(console.log(n.id),(n.id||0===n.id)&&console.log(a(n.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Ft.de=n.id,0!=this.re.length){const t=document.querySelector("#"+this.re);if(t){const e=n.charges;t.dataset.endDate=Date.now()+(e.max-e.count)*e.cooldownMs}}t.Ot("bm-p",`Droplets: ${(new Intl.NumberFormat).format(n.droplets)}`),t.Ot("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=i.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),l=new URLSearchParams(i.endpoint.split("?")[1]),c=[l.get("x"),l.get("y")];if(this.le.length&&(!s.length||!c.length))return void t.Ht("Coordinates are malformed!\nDid you try clicking the canvas first?");this.le=[...s,...c];const h=(o=s,r=c,[parseInt(o[0])%4*1e3+parseInt(r[0]),parseInt(o[1])%4*1e3+parseInt(r[1])]),m=document.querySelectorAll("span");for(const t of m)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-h");const i=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=i:(e=document.createElement("span"),e.id="bm-h",e.textContent=i,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=i.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const u=i.blobID,b=i.blobData,p=Date.now(),f=await this.Ft.ve(b,d);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:f,blink:i.blink});break;case"robots":this.Ce="false"==n.userscript?.toString().toLowerCase();break}var o,r})}async ke(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const i=navigator.userAgent;let n=await this.Le(i),s=this.Ne(i);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:n,os:s}),onload:t=>{200!==t.status&&o("Failed to send heartbeat:",t.statusText)},onerror:t=>{o("Error sending heartbeat:",t)}})}async Le(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"}Ne(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}}(F);G.j(E);var Y=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(Y),F.Se(Y);var _=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(_),console.log(Object.keys(_).length),0==Object.keys(_).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}setInterval(()=>E.ke(A),18e5);var j=_?.telemetry;if(console.log(`Telemetry is ${!(null==j)}`),null==j||j>1){const t=new class extends D{constructor(t,i,n,s){super(t,i),e(this,N),this.window=null,this.Wt="bm-T",this.Gt=document.body,this.Be=n,this.uuid=s}async ee(){if(document.querySelector(`#${this.Wt}`))return void this.Ht("Telemetry window already exists!");const t=await this.W.Le(navigator.userAgent),e=this.W.Ne(navigator.userAgent);this.window=this.J({id:this.Wt,class:"bm-1j",style:"height: 80vh; z-index: 9998;"}).J({class:"bm-U"}).J({class:"bm-1b bm-Q"}).it(1,{textContent:`${this.name} Telemetry`}).X().X().nt().X().J({class:"bm-1b bm-15",style:"gap: 1.5ch; flex-wrap: wrap;"}).Ct({textContent:"Enable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,N,B).call(this,this.Be);const t=document.getElementById(this.Wt);t?.remove()}}).X().Ct({textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,N,B).call(this,0);const t=document.getElementById(this.Wt);t?.remove()}}).X().Ct({textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).X().X().J({class:"bm-1b bm-17"}).J({class:"bm-1b"}).it(2,{textContent:"Legal"}).X().V({textContent:`We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the "Disable" button, but keeping it on helps us improve features and reliability faster. Thank you for supporting ${this.name}!`}).X().X().nt().X().J({class:"bm-1b"}).it(2,{textContent:"Non-Legal Summary"}).X().V({innerHTML:'You can disable telemetry by pressing the "Disable" button. If you would like to read more about what information we collect, press the "More Information" button.
This is the data stored on our servers:'}).X().bt().gt({innerHTML:`A unique identifier (UUIDv4) generated by Blue Marble. This enables our telemetry to function without tracking your actual user ID.
Your UUID is: ${n(this.uuid)}`}).X().gt({innerHTML:`The version of Blue Marble you are using.
Your version is: ${n(this.version)}`}).X().gt({innerHTML:`Your browser type, which is used to determine Blue Marble outages and browser popularity.
Your browser type is: ${n(t)}`}).X().gt({innerHTML:`Your OS type, which is used to determine Blue Marble outages and OS popularity.
Your OS type is: ${n(e)}`}).X().gt({innerHTML:"The date and time that Blue Marble sent the telemetry information."}).X().X().V({innerHTML:'All of the data mentioned above is aggregated every hour. This means every hour, anything that could even remotly be considered "personal data" is deleted from our server. Here, "aggregated" data means things like "42 people used Blue Marble on Google Chrome this hour", which can\'t be used to identify anyone in particular.'}).X().X().X().X().X().R(this.Gt)}}(P,A,1,_?.uuid);t.j(E),t.ee()}G.ee(),E.Oe(G),new MutationObserver((t,e)=>{const i=document.querySelector("#color-1");if(!i)return;let n=document.querySelector("#bm-t");if(!n){n=document.createElement("button"),n.id="bm-t",n.textContent="Move ↑",n.className="btn btn-soft",n.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=i.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(n)}}).observe(document.body,{childList:!0,subtree:!0}),s(`%c${P}%c (${A}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file +(()=>{var t=t=>{throw TypeError(t)},e=(e,i,n)=>i.has(e)?t("Cannot add the same private member more than once"):i instanceof WeakSet?i.add(e):i.set(e,n),i=(e,i,n)=>(((e,i)=>{i.has(e)||t("Cannot access private method")})(e,i),n);function n(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function s(...t){(0,console.log)(...t)}function o(...t){(0,console.error)(...t)}function a(t,e){if(0===t)return e[0];let i="";const n=e.length;for(;t>0;)i=e[t%n]+i,t=Math.floor(t/n);return i}function r(t){let e="";for(let i=0;i(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4));return.2126*e[0]+.7152*e[1]+.0722*e[2]}var h,m,d,u,b,p=[{id:0,premium:!1,name:"Transparent",rgb:[0,0,0]},{id:1,premium:!1,name:"Black",rgb:[0,0,0]},{id:2,premium:!1,name:"Dark Gray",rgb:[60,60,60]},{id:3,premium:!1,name:"Gray",rgb:[120,120,120]},{id:4,premium:!1,name:"Light Gray",rgb:[210,210,210]},{id:5,premium:!1,name:"White",rgb:[255,255,255]},{id:6,premium:!1,name:"Deep Red",rgb:[96,0,24]},{id:7,premium:!1,name:"Red",rgb:[237,28,36]},{id:8,premium:!1,name:"Orange",rgb:[255,127,39]},{id:9,premium:!1,name:"Gold",rgb:[246,170,9]},{id:10,premium:!1,name:"Yellow",rgb:[249,221,59]},{id:11,premium:!1,name:"Light Yellow",rgb:[255,250,188]},{id:12,premium:!1,name:"Dark Green",rgb:[14,185,104]},{id:13,premium:!1,name:"Green",rgb:[19,230,123]},{id:14,premium:!1,name:"Light Green",rgb:[135,255,94]},{id:15,premium:!1,name:"Dark Teal",rgb:[12,129,110]},{id:16,premium:!1,name:"Teal",rgb:[16,174,166]},{id:17,premium:!1,name:"Light Teal",rgb:[19,225,190]},{id:18,premium:!1,name:"Dark Blue",rgb:[40,80,158]},{id:19,premium:!1,name:"Blue",rgb:[64,147,228]},{id:20,premium:!1,name:"Cyan",rgb:[96,247,242]},{id:21,premium:!1,name:"Indigo",rgb:[107,80,246]},{id:22,premium:!1,name:"Light Indigo",rgb:[153,177,251]},{id:23,premium:!1,name:"Dark Purple",rgb:[120,12,153]},{id:24,premium:!1,name:"Purple",rgb:[170,56,185]},{id:25,premium:!1,name:"Light Purple",rgb:[224,159,249]},{id:26,premium:!1,name:"Dark Pink",rgb:[203,0,122]},{id:27,premium:!1,name:"Pink",rgb:[236,31,128]},{id:28,premium:!1,name:"Light Pink",rgb:[243,141,169]},{id:29,premium:!1,name:"Dark Brown",rgb:[104,70,52]},{id:30,premium:!1,name:"Brown",rgb:[149,104,42]},{id:31,premium:!1,name:"Beige",rgb:[248,178,119]},{id:32,premium:!0,name:"Medium Gray",rgb:[170,170,170]},{id:33,premium:!0,name:"Dark Red",rgb:[165,14,30]},{id:34,premium:!0,name:"Light Red",rgb:[250,128,114]},{id:35,premium:!0,name:"Dark Orange",rgb:[228,92,26]},{id:36,premium:!0,name:"Light Tan",rgb:[214,181,148]},{id:37,premium:!0,name:"Dark Goldenrod",rgb:[156,132,49]},{id:38,premium:!0,name:"Goldenrod",rgb:[197,173,49]},{id:39,premium:!0,name:"Light Goldenrod",rgb:[232,212,95]},{id:40,premium:!0,name:"Dark Olive",rgb:[74,107,58]},{id:41,premium:!0,name:"Olive",rgb:[90,148,74]},{id:42,premium:!0,name:"Light Olive",rgb:[132,197,115]},{id:43,premium:!0,name:"Dark Cyan",rgb:[15,121,159]},{id:44,premium:!0,name:"Light Cyan",rgb:[187,250,242]},{id:45,premium:!0,name:"Light Blue",rgb:[125,199,255]},{id:46,premium:!0,name:"Dark Indigo",rgb:[77,49,184]},{id:47,premium:!0,name:"Dark Slate Blue",rgb:[74,66,132]},{id:48,premium:!0,name:"Slate Blue",rgb:[122,113,196]},{id:49,premium:!0,name:"Light Slate Blue",rgb:[181,174,241]},{id:50,premium:!0,name:"Light Brown",rgb:[219,164,99]},{id:51,premium:!0,name:"Dark Beige",rgb:[209,128,81]},{id:52,premium:!0,name:"Light Beige",rgb:[255,197,165]},{id:53,premium:!0,name:"Dark Peach",rgb:[155,82,73]},{id:54,premium:!0,name:"Peach",rgb:[209,128,120]},{id:55,premium:!0,name:"Light Peach",rgb:[250,182,164]},{id:56,premium:!0,name:"Dark Tan",rgb:[123,99,82]},{id:57,premium:!0,name:"Tan",rgb:[156,132,107]},{id:58,premium:!0,name:"Dark Slate",rgb:[51,57,65]},{id:59,premium:!0,name:"Slate",rgb:[109,117,141]},{id:60,premium:!0,name:"Light Slate",rgb:[179,185,209]},{id:61,premium:!0,name:"Dark Stone",rgb:[109,100,63]},{id:62,premium:!0,name:"Stone",rgb:[148,140,107]},{id:63,premium:!0,name:"Light Stone",rgb:[205,197,158]}],g=class{constructor({displayName:t="My template",t:i=0,i:n="",url:s="",file:o=null,coords:a=null,o:r=null,l:l={},h:c=1e3}={}){e(this,h),this.displayName=t,this.t=i,this.i=n,this.url=s,this.file=o,this.coords=a,this.o=r,this.l=l,this.h=c,this.m={total:0,colors:new Map}}async u(t,e){console.log("Template coordinates:",this.coords);const n=await createImageBitmap(this.file),s=n.width,o=n.height;this.h=t;const a={},l={},c=new OffscreenCanvas(this.h,this.h),d=c.getContext("2d",{p:!0});c.width=s,c.height=o,d.imageSmoothingEnabled=!1,d.drawImage(n,0,0);let u=Date.now();const b=i(this,h,m).call(this,d.getImageData(0,0,s,o),e);console.log(`Calculating total pixels took ${(Date.now()-u)/1e3} seconds`);let p=0;for(const[t,e]of b)0!=t&&(p+=e);this.m={total:p,colors:b},u=Date.now();const g=new OffscreenCanvas(3,3),f=g.getContext("2d");f.clearRect(0,0,3,3),f.fillStyle="white",f.fillRect(1,1,1,1);for(let t=this.coords[3];t>>24==0?0:s.get(e)??-2;const a=o.get(n);o.set(n,a?a+1:1)}return console.log(o),o};var f,w,y=class{constructor(t,i){e(this,d),this.name=t,this.version=i,this.T=null,this.S="bm-o",this.C=null,this.D=null,this.O=[]}k(t){this.T=t}L(){return this.O.length>0&&(this.D=this.O.pop()),this}N(t){t?.appendChild(this.C),this.C=null,this.D=null,this.O=[]}B(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"div",{},t)),this}I(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"p",{},t)),this}P(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"small",{},t)),this}A(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"span",{},t)),this}W(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"details",{},t)),this}H(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"summary",{},t)),this}U(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"img",{},t)),this}G(t,e={},n=()=>{}){return n(this,i(this,d,u).call(this,"h"+t,{},e)),this}F(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"hr",{},t)),this}Y(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"br",{},t)),this}_(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"form",{},t)),this}R(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"fieldset",{},t)),this}j(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"legend",{},t)),this}X(t={},e=()=>{}){const n=i(this,d,u).call(this,"label",{textContent:t.textContent??""});delete t.textContent;const s=i(this,d,u).call(this,"input",{type:"checkbox"},t);return n.insertBefore(s,n.firstChild),this.L(),e(this,n,s),this}J(t={},e=()=>{}){const n=i(this,d,u).call(this,"label",{textContent:t.textContent??"",for:t.id??""});return delete t.textContent,this.L(),e(this,n,i(this,d,u).call(this,"select",{},t)),this}V(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"option",{},t)),this}q(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"ol",{},t)),this}Z(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"ul",{},t)),this}K(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"menu",{},t)),this}tt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"li",{},t)),this}et(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"table",{},t)),this}it(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"caption",{},t)),this}nt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"thead",{},t)),this}st(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tbody",{},t)),this}ot(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tfoot",{},t)),this}rt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"tr",{},t)),this}lt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"th",{},t)),this}ct(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"td",{},t)),this}ht(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"button",{},t)),this}dt(t={},e=()=>{}){const n=t.title??t.textContent??"Help: No info";delete t.textContent,t.title=`Help: ${n}`;const s={textContent:"?",className:"bm-D",onclick:()=>{this.ut(this.S,n)}};return e(this,i(this,d,u).call(this,"button",s,t)),this}bt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"input",{},t)),this}gt(t={},e=()=>{}){const n=t.textContent??"";delete t.textContent;const s=i(this,d,u).call(this,"div"),o=i(this,d,u).call(this,"input",{type:"file",tabindex:"-1","aria-hidden":"true"},t);this.L();const a=i(this,d,u).call(this,"button",{textContent:n});return this.L(),this.L(),a.addEventListener("click",()=>{o.click()}),o.addEventListener("change",()=>{a.style.maxWidth=`${a.offsetWidth}px`,o.files.length>0?a.textContent=o.files[0].name:a.textContent=n}),e(this,s,o,a),this}ft(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"textarea",{},t)),this}wt(t={},e=()=>{}){return e(this,i(this,d,u).call(this,"div",{class:"bm-1j"},t)),this}yt(t=Date.now(),e=500,n={},s=()=>{}){const o="bm-1n",a=n?.id||o+"-"+crypto.randomUUID().slice(0,8),r={class:o},l=i(this,d,u).call(this,"time",r,n);return l.id=a,l.dataset.endDate=t,setInterval(()=>{if(!l.isConnected)return;const t=Math.max(l.dataset.endDate-Date.now(),0),e=Math.floor(t/1e3),i=Math.floor(e/3600),n=Math.floor(e%60),s=Math.floor(e%3600/60);l.setAttribute("datetime",`PT${i}H${s}M${n}S`),l.textContent=String(i).padStart(2,"0")+":"+String(s).padStart(2,"0")+":"+String(n).padStart(2,"0")},e),s(this,l),this}ut(t,e,i=!1){const n=document.getElementById(t.replace(/^#/,""));n&&(n instanceof HTMLInputElement?n.value=e:i?n.textContent=e:n.innerHTML=e)}vt(t){if(t.disabled)return;t.disabled=!0,t.style.textDecoration="none";const e=t.closest(".bm-1l"),i=t.closest(".bm-1j"),n=e.querySelector("h1"),s=e.querySelector(".bm-U");if("expanded"==t.dataset.buttonStatus){s.style.height=s.scrollHeight+"px",e.style.width=e.scrollWidth+"px",s.style.height="0",s.addEventListener("transitionend",function e(){s.style.display="none",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)});const i=n.cloneNode(!0),o=i.textContent;t.nextElementSibling.appendChild(i),t.textContent="▶",t.dataset.buttonStatus="collapsed",t.ariaLabel=`Unminimize window "${o}"`}else{const n=i.querySelector("h1"),o=n.textContent;n.remove(),s.style.display="",s.style.height="0",e.style.width="",s.style.height=s.scrollHeight+"px",s.addEventListener("transitionend",function e(){s.style.height="",t.disabled=!1,t.style.textDecoration="",s.removeEventListener("transitionend",e)}),t.textContent="▼",t.dataset.buttonStatus="expanded",t.ariaLabel=`Minimize window "${o}"`}}xt(t,e){if(t=document.querySelector(t),e=document.querySelector(e),!t||!e)return void this.$t(`Can not drag! ${t?"":"moveMe"} ${t||e?"":"and "}${e?"":"iMoveThings "}was not found!`);let i,n=!1,s=0,o=null,a=0,r=0,l=0,c=0,h=null;const m=()=>{if(n){const e=Math.abs(a-l),i=Math.abs(r-c);(e>.5||i>.5)&&(a=l,r=c,t.style.transform=`translate(${a}px, ${r}px)`,t.style.left="0px",t.style.top="0px",t.style.right=""),o=requestAnimationFrame(m)}},d=(d,g)=>{n=!0,h=t.getBoundingClientRect(),i=d-h.left,s=g-h.top;const f=window.getComputedStyle(t).transform;if(f&&"none"!==f){const t=new DOMMatrix(f);a=t.m41,r=t.m42}else a=h.left,r=h.top;l=a,c=r,document.body.style.userSelect="none",e.classList.add("bm-1e"),document.addEventListener("mousemove",b),document.addEventListener("touchmove",p,{passive:!1}),document.addEventListener("mouseup",u),document.addEventListener("touchend",u),document.addEventListener("touchcancel",u),o&&cancelAnimationFrame(o),m()},u=()=>{n=!1,o&&(cancelAnimationFrame(o),o=null),document.body.style.userSelect="",e.classList.remove("bm-1e"),document.removeEventListener("mousemove",b),document.removeEventListener("touchmove",p),document.removeEventListener("mouseup",u),document.removeEventListener("touchend",u),document.removeEventListener("touchcancel",u)},b=t=>{n&&h&&(l=t.clientX-i,c=t.clientY-s)},p=t=>{if(n&&h){const e=t.touches[0];if(!e)return;l=e.clientX-i,c=e.clientY-s,t.preventDefault()}};e.addEventListener("mousedown",function(t){t.preventDefault(),d(t.clientX,t.clientY)}),e.addEventListener("touchstart",function(t){const e=t?.touches?.[0];e&&(d(e.clientX,e.clientY),t.preventDefault())},{passive:!1})}Mt(t){(0,console.info)(`${this.name}: ${t}`),this.ut(this.S,"Status: "+t,!0)}$t(t){(0,console.error)(`${this.name}: ${t}`),this.ut(this.S,"Error: "+t,!0)}};d=new WeakSet,u=function(t,e={},n={}){const s=document.createElement(t);this.C?(this.D?.appendChild(s),this.O.push(this.D),this.D=s):(this.C=s,this.D=s);for(const[t,n]of Object.entries(e))i(this,d,b).call(this,s,t,n);for(const[t,e]of Object.entries(n))i(this,d,b).call(this,s,t,e);return s},b=function(t,e,i){if("class"==e)t.classList.add(...i.split(/\s+/));else if("for"==e)t.htmlFor=i;else if("tabindex"==e)t.tabIndex=Number(i);else if("readonly"==e)t.readOnly="true"==i||"1"==i;else if("maxlength"==e)t.maxLength=Number(i);else if(e.startsWith("data"))t.dataset[e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("")]=i;else if(e.startsWith("aria")){const n=e.slice(5).split("-").map((t,e)=>0==e?t:t[0].toUpperCase()+t.slice(1)).join("");t["aria"+n[0].toUpperCase()+n.slice(1)]=i}else t[e]=i};var v,x,$,M,T=class extends y{constructor(t,i,n){super(t,i),e(this,f),this.window=null,this.Tt="bm-Y",this.St=document.body,this.Ct=JSON.parse(GM_getValue("bmTemplates","{}")),this.scriptVersion=this.Ct?.scriptVersion,this.schemaVersion=this.Ct?.schemaVersion,this.Dt=void 0,this.Ot=n}kt(){document.querySelector(`#${this.Tt}`)?this.$t("Template Wizard window already exists!"):(this.window=this.B({id:this.Tt,class:"bm-1l",style:"z-index: 9001;"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Template Wizard"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().ht({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Template Wizard"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Tt}`)?.remove()},e.ontouchend=()=>{e.click()}}).L().L().B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:"Template Wizard"}).L().L().F().L().B({class:"bm-1d"}).I({id:"bm--",textContent:"Loading template storage status..."}).L().L().B({class:"bm-1d bm-19"}).A({textContent:"Detected templates:"}).L().L().L().L().N(this.St),i(this,f,w).call(this))}};f=new WeakSet,w=function(){const t=this.schemaVersion.split(/[-\.\+]/),e=this.Ot.split(/[-\.\+]/);let i="";t[0]==e[0]?t[1]==e[1]?(i="Template storage health: Healthy!
No futher action required. (Reason: Semantic version matches)",this.Dt="Good"):(i="Template storage health: Poor!
You can still use your template, but some features may not work. It is recommended that you update Blue Marble's template storage. (Reason: MINOR version mismatch)",this.Dt="Poor"):(i="Template storage health: Dead!
Blue Marble can not load the template storage. (Reason: MAJOR version mismatch)",this.Dt="Dead"),this.ut("#bm--",`${i}
The current schema version (${n(this.schemaVersion)}) was created during Blue Marble version ${n(this.scriptVersion)}.
The current Blue Marble version (${n(this.version)}) requires schema version ${n(this.Ot)}.
If you don't want to upgrade the template storage (schema), then downgrade Blue Marble to version ${n(this.scriptVersion)}.`),("Poor"==this.Dt||"Bad"==this.Dt)&&new y(this.name,this.version).B({class:"bm-1d bm-15 bm-Q"}).ht({textContent:`Update template storage to ${this.Ot}`},(t,e)=>{e.onclick=()=>{}}).L().L().N(document.querySelector("#bm--").parentNode)},v=new WeakSet,x=async function(){GM.setValue("bmTemplates",JSON.stringify(this.Lt))},$=async function(t){console.log("Parsing BlueMarble...");const e=t.templates;console.log(`BlueMarble length: ${Object.keys(e).length}`);const i=t?.schemaVersion,n=i.split(/[-\.\+]/),s=this.schemaVersion.split(/[-\.\+]/),o=t?.scriptVersion;async function a(){if(Object.keys(e).length>0)for(const t in e){const i=t,n=e[t];if(console.log(`Template Key: ${i}`),e.hasOwnProperty(t)){const t=i.split(" "),e=Number(t?.[0]),s=t?.[1]||"0",o=n.name||`Template ${e||""}`,a={total:n.pixels.total,colors:new Map(Object.entries(n.pixels.colors).map(([t,e])=>[Number(t),e]))},r=n.tiles,c={},h={},m=this.h*this.Nt;for(const t in r)if(console.log(t),r.hasOwnProperty(t)){const e=l(r[t]),i=new Blob([e],{type:"image/png"}),n=await createImageBitmap(i);c[t]=n;const s=new OffscreenCanvas(m,m).getContext("2d");s.drawImage(n,0,0);const o=s.getImageData(0,0,n.width,n.height);h[t]=new Uint32Array(o.data.buffer)}const d=new g({displayName:o,t:e||this.Bt?.length||0,i:s||""});d.m=a,d.o=c,d.l=h,this.Bt.push(d),console.log(this.Bt),console.log("^^^ This ^^^")}}}console.log(`BlueMarble Template Schema: ${i}; Script Version: ${o}`),n[0]==s[0]?(n[1]==s[1]||new T(this.name,this.version,this.schemaVersion).kt(),a()):this.C.$t(`Template version ${i} is unsupported.\nUse Blue Marble version ${o} or load a new template.`)},M=function({It:t,Pt:e,At:i}){const n=this.Nt,s=this.h*n,o=i[0],a=i[1],r=i[2],l=i[3],c=this.Wt,{palette:h,M:m}=this.Ht,d=new Map;for(let i=1;i>>24&255,f=b>>>24&255,w=m.get(p)??-2;if(this.Ut.get(w)&&(e[i*r+l]=b),-1==w){const t=536870912;this.Ut.get(w)?e[i*r+l]=0:(h/n&1)==(u/n&1)?(e[i*r+l]=t,e[(i-1)*r+(l-1)]=t,e[(i-1)*r+(l+1)]=t,e[(i+1)*r+(l-1)]=t,e[(i+1)*r+(l+1)]=t):(e[i*r+l]=0,e[(i-1)*r+l]=t,e[(i+1)*r+l]=t,e[i*r+(l-1)]=t,e[i*r+(l+1)]=t)}if(-1==w&&b<=c){const t=d.get(w);d.set(w,t?t+1:1);continue}if(g<=c||f<=c)continue;if((m.get(b)??-2)!=w)continue;const y=d.get(w);d.set(w,y?y+1:1)}return console.log("List of template pixels that match the tile:"),console.log(d),{Gt:d,Ft:e}};var S,C,D,O,k=class{constructor(){this.Yt=Math.ceil(80/1300*window.innerWidth),this._t=p.slice(1)}zt(t){const e=document.createElement("div");for(let t=0;t{t.parentNode.childElementCount<=1?t.parentNode.remove():t.remove()},e.appendChild(t)}t.appendChild(e)}},L=class extends HTMLElement{};customElements.define("confetti-piece",L);var N,B,I,P,A,W=class extends y{constructor(t){super(t.name,t.version),e(this,S),this.window=null,this.Tt="bm-_",this.St=document.body,this.Et=t.T?.Et,this.Rt='',this.jt='',this.Xt=new Intl.NumberFormat,this.Jt=new Intl.NumberFormat(void 0,{style:"percent",Vt:2,qt:2}),this.Qt={Zt:"long",Kt:"numeric",te:"2-digit",ee:"2-digit",ie:"2-digit"};const{palette:i,M:n}=this.Et.Ht;this.palette=i,this.ne=0,this.se=0}kt(){if(document.querySelector(`#${this.Tt}`))return void this.$t("Color Filter window already exists!");this.window=this.B({id:this.Tt,class:"bm-1l"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Color Filter"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().ht({class:"bm-Z",textContent:"🞪","aria-label":'Close window "Color Filter"'},(t,e)=>{e.onclick=()=>{document.querySelector(`#${this.Tt}`)?.remove()},e.ontouchend=()=>{e.click()}}).L().L().B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:"Color Filter"}).L().L().F().L().B({class:"bm-1d bm-11 bm-Q",style:"gap: 1.5ch;"}).ht({textContent:"Select All"},(t,e)=>{e.onclick=()=>i(this,S,O).call(this,!1)}).L().ht({textContent:"Unselect All"},(t,e)=>{e.onclick=()=>i(this,S,O).call(this,!0)}).L().L().B({class:"bm-1d bm-19"}).B({class:"bm-1d",style:"margin-left: 2.5ch; margin-right: 2.5ch;"}).B({class:"bm-1d"}).A({id:"bm-R",innerHTML:"Tiles Loaded: 0 / ???"}).L().Y().L().A({id:"bm-M",innerHTML:"Correct Pixels: ???"}).L().Y().L().A({id:"bm-S",innerHTML:"Total Pixels: ???"}).L().Y().L().A({id:"bm-I",innerHTML:"Complete: ??? (???)"}).L().Y().L().A({id:"bm-J",innerHTML:"??? ???"}).L().L().B({class:"bm-1d"}).I({innerHTML:`Colors with the icon ${this.Rt.replace("{e.onclick=t=>{t.preventDefault();const e=new FormData(document.querySelector(`#${this.Tt} form`)),n={};for(const[t,i]of e)n[t]=i;console.log(`Primary: ${n.sortPrimary}; Secondary: ${n.sortSecondary}; Unused: ${"on"==n.showUnused}`),i(this,S,D).call(this,n.sortPrimary,n.sortSecondary,"on"==n.showUnused)}}).L().L().L().L().L().L().L().N(this.St),this.xt(`#${this.Tt}.bm-1l`,`#${this.Tt} .bm-1j`);const t=document.querySelector(`#${this.Tt} .bm-1d.bm-19`);let e=0,n=0;const s=new Map,o=new Map;for(const t of this.Et.Bt){e+=t.m?.total??0??0;const i=t.m?.colors??new Map;for(const[t,e]of i){const i=Number(e)||0,n=o.get(t)??0;o.set(t,n+i)}const a=t.m?.correct??{};this.ne+=Object.keys(a).length,this.se+=Object.keys(t.o).length;for(const t of Object.values(a))for(const[e,i]of t){const t=Number(i)||0;n+=t;const o=s.get(e)??0;s.set(e,o+t)}}console.log(`Tiles loaded: ${this.ne} / ${this.se}`),n>=e&&e&&this.ne==this.se&&(new k).zt(document.querySelector(`#${this.Tt}`));const a=new Date(30*(e-n)*1e3+Date.now()),r=a.toLocaleString(void 0,this.Qt);this.ut("#bm-R",`Tiles Loaded: ${this.Xt.format(this.ne)} / ${this.Xt.format(this.se)}`),this.ut("#bm-M",`Correct Pixels: ${this.Xt.format(n)}`),this.ut("#bm-S",`Total Pixels: ${this.Xt.format(e)}`),this.ut("#bm-I",`Remaining: ${this.Xt.format((e||0)-(n||0))} (${this.Jt.format(((e||0)-(n||0))/(e||1))})`),this.ut("#bm-J",`Completed at: `),i(this,S,C).call(this,t,s,o),i(this,S,D).call(this,"id","ascending",!1)}};S=new WeakSet,C=function(t,e,i){const n=new y(this.name,this.version);n.B({class:"bm-16"});for(const t of this.palette){const s=c(t.rgb);let o=1.05/(s+.05)>(s+.05)/.05?"white":"black";t.id||(o="transparent");const a="white"==o?"bm-O":"bm-P",r=i.get(t.id)??0,l=this.Xt.format(r);let h=0,m="0",d=this.Jt.format(1);0!=r&&(h=e.get(t.id)??"???","number"!=typeof h&&this.ne==this.se&&t.id&&(h=0),m="string"==typeof h?h:this.Xt.format(h),d=isNaN(h/r)?"???":this.Jt.format(h/r));const u=parseInt(r)-parseInt(h),b=!!this.Et.Ut.get(t.id);n.B({class:"bm-1d bm-12 bm-11","data-id":t.id,"data-name":t.name,"data-premium":+t.premium,"data-correct":Number.isNaN(parseInt(h))?"0":h,"data-total":r,"data-percent":"%"==d.slice(-1)?d.slice(0,-1):"0","data-incorrect":u||0}).B({class:"bm-K",style:`background-color: rgb(${t.rgb?.map(t=>Number(t)||0).join(",")});`}).ht({class:"bm-13 "+a,"data-state":b?"hidden":"shown","aria-label":b?`Show the color ${t.name||""} on templates.`:`Hide the color ${t.name||""} on templates.`,innerHTML:b?this.jt.replace("{i.onclick=()=>{i.style.textDecoration="none",i.disabled=!0,"shown"==i.dataset.state?(i.innerHTML=this.jt.replace("{const o=n.getAttribute("data-"+t),a=s.getAttribute("data-"+t),r=parseFloat(o),l=parseFloat(a),c=!isNaN(r),h=!isNaN(l);if(i?n.classList.remove("bm-1a"):Number(n.getAttribute("data-total"))||n.classList.add("bm-1a"),c&&h)return"ascending"===e?r-l:l-r;{const t=o.toLowerCase(),i=a.toLowerCase();return ti?"ascending"===e?1:-1:0}}),s.forEach(t=>n.appendChild(t))},O=function(t){const e=document.querySelector(".bm-16"),i=Array.from(e.children);for(const e of i){if(e.classList?.contains("bm-1a"))continue;const i=e.querySelector(".bm-K button");("hidden"!=i.dataset.state||t)&&("shown"==i.dataset.state&&t||i.click())}},N=new WeakSet,B=function(){new W(this).kt()},I=async function(t,e,i){i.preventDefault();const n=await async function(t){let e="";return t&&(e=t.clipboardData.getData("text/plain")),0!=e.length||(await navigator.clipboard.readText().then(t=>{e=t}).catch(t=>{s("Failed to retrieve clipboard data using navigator! Using fallback methods...")}),0!=e.length||(e=window.clipboardData?.getData("Text"))),e}(i),o=n.split(/[^a-zA-Z0-9]+/).filter(t=>t).map(Number).filter(t=>!isNaN(t));2==o.length&&"bm-x"==e.id?(t.ut("bm-x",o?.[0]||""),t.ut("bm-y",o?.[1]||"")):1==o.length?t.ut(e.id,o?.[0]||""):(t.ut("bm-v",o?.[0]||""),t.ut("bm-w",o?.[1]||""),t.ut("bm-x",o?.[2]||""),t.ut("bm-y",o?.[3]||""))},P=new WeakSet,A=function(t){const e=JSON.parse(GM_getValue("bmUserSettings","{}"));e.telemetry=t,GM.setValue("bmUserSettings",JSON.stringify(e))};var H=GM_info.script.name.toString(),U=GM_info.script.version.toString();!function(t){const e=document.createElement("script");e.setAttribute("bm-E",H),e.setAttribute("bm-B","color: cornflowerblue;"),e.textContent=`(${t})();`,document.documentElement?.appendChild(e),e.remove()}(()=>{const t=document.currentScript,e=t?.getAttribute("bm-E")||"Blue Marble",i=t?.getAttribute("bm-B")||"",n=new Map;window.addEventListener("message",t=>{const{source:s,endpoint:o,blobID:a,blobData:r,blink:l}=t.data,c=Date.now()-l;if(console.groupCollapsed(`%c${e}%c: ${n.size} Recieved IMAGE message about blob "${a}"`,i,""),console.log(`Blob fetch took %c${String(Math.floor(c/6e4)).padStart(2,"0")}:${String(Math.floor(c/1e3)%60).padStart(2,"0")}.${String(c%1e3).padStart(3,"0")}%c MM:SS.mmm`,i,""),console.log(n),console.groupEnd(),"blue-marble"==s&&a&&r&&!o){const t=n.get(a);"function"==typeof t?t(r):function(...t){(0,console.warn)(...t)}(`%c${e}%c: Attempted to retrieve a blob (%s) from queue, but the blobID was not a function! Skipping...`,i,"",a),n.delete(a)}});const s=window.fetch;window.fetch=async function(...t){const o=await s.apply(this,t),a=o.clone(),r=(t[0]instanceof Request?t[0]?.url:t[0])||"ignore",l=a.headers.get("content-type")||"";if(l.includes("application/json"))console.log(`%c${e}%c: Sending JSON message about endpoint "${r}"`,i,""),a.json().then(t=>{window.postMessage({source:"blue-marble",endpoint:r,jsonData:t},"*")}).catch(t=>{console.error(`%c${e}%c: Failed to parse JSON: `,i,"",t)});else if(l.includes("image/")&&!r.includes("openfreemap")&&!r.includes("maps")){const t=Date.now(),s=await a.blob();return console.log(`%c${e}%c: ${n.size} Sending IMAGE message about endpoint "${r}"`,i,""),new Promise(o=>{const l=crypto.randomUUID();n.set(l,t=>{o(new Response(t,{headers:a.headers,status:a.status,statusText:a.statusText})),console.log(`%c${e}%c: ${n.size} Processed blob "${l}"`,i,"")}),window.postMessage({source:"blue-marble",endpoint:r,blobID:l,blobData:s,blink:t})}).catch(s=>{const o=Date.now();console.error(`%c${e}%c: Failed to Promise blob!`,i,""),console.groupCollapsed(`%c${e}%c: Details of failed blob Promise:`,i,""),console.log(`Endpoint: ${r}\nThere are ${n.size} blobs processing...\nBlink: ${t.toLocaleString()}\nTime Since Blink: ${String(Math.floor(o/6e4)).padStart(2,"0")}:${String(Math.floor(o/1e3)%60).padStart(2,"0")}.${String(o%1e3).padStart(3,"0")} MM:SS.mmm`),console.error("Exception stack:",s),console.groupEnd()})}return o}});var G=GM_getResourceText("CSS-BM-File");GM_addStyle(G);var F,Y="robotoMonoInjectionPoint";Y.indexOf("@font-face")+1?(console.log("Loading Roboto Mono as a file..."),GM_addStyle(Y)):((F=document.createElement("link")).href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap",F.rel="preload",F.as="style",F.onload=function(){this.onload=null,this.rel="stylesheet"},document.head?.appendChild(F)),new class{constructor(){this.oe=null,this.ae=null,this.re="#bm-h"}le(t){return this.ae=t,this.oe=new MutationObserver(t=>{for(const e of t)for(const t of e.addedNodes)t instanceof HTMLElement&&t.matches?.(this.re)}),this}ce(){return this.oe}observe(t,e=!1,i=!1){t.observe(this.ae,{childList:e,subtree:i})}};var _=new class extends y{constructor(t,i){super(t,i),e(this,N),this.window=null,this.Tt="bm-17",this.St=document.body}kt(){document.querySelector(`#${this.Tt}`)?this.$t("Main window already exists!"):(this.window=this.B({id:this.Tt,class:"bm-1l",style:"top: 10px; left: unset; right: 75px;"}).wt().ht({class:"bm-Z",textContent:"▼","aria-label":'Minimize window "Blue Marble"',"data-button-status":"expanded"},(t,e)=>{e.onclick=()=>t.vt(e),e.ontouchend=()=>{e.click()}}).L().B().L().L().B({class:"bm-U"}).B({class:"bm-1d"}).U({class:"bm-1k",src:"https://raw.githubusercontent.com/SwingTheVine/Wplace-BlueMarble/main/dist/assets/Favicon.png"},(t,e)=>{const i=new Date;204==Math.floor((i.getTime()-new Date(i.getFullYear(),0,1))/864e5)+1&&(e.parentNode.style.position="relative",e.parentNode.innerHTML=e.parentNode.innerHTML+'',e.onload=()=>{(new k).zt(document.querySelector(`#${this.Tt}`))})}).L().G(1,{textContent:this.name}).L().L().F().L().B({class:"bm-1d"}).A({id:"bm-p",textContent:"Droplets:"}).L().Y().L().A({id:"bm-i",textContent:"Next level in..."}).L().Y().L().A({textContent:"Charges: "}).yt(Date.now(),1e3,{style:"font-weight: 700;"},(t,e)=>{t.T.he=e.id}).L().L().L().F().L().B({class:"bm-1d"}).B({class:"bm-1d"}).ht({class:"bm-Z bm-1b",style:"margin-top: 0;",innerHTML:''},(t,e)=>{e.onclick=()=>{const e=t.T?.me;e?.[0]?(t.ut("bm-v",e?.[0]||""),t.ut("bm-w",e?.[1]||""),t.ut("bm-x",e?.[2]||""),t.ut("bm-y",e?.[3]||"")):t.$t("Coordinates are malformed! Did you try clicking on the canvas first?")}}).L().bt({type:"number",id:"bm-v",class:"bm-14",placeholder:"Tl X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-w",class:"bm-14",placeholder:"Tl Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-x",class:"bm-14",placeholder:"Px X",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().bt({type:"number",id:"bm-y",class:"bm-14",placeholder:"Px Y",min:0,max:2047,step:1,required:!0},(t,e)=>{e.addEventListener("paste",n=>i(this,N,I).call(this,t,e,n))}).L().L().B({class:"bm-1d"}).gt({class:"bm-1c",textContent:"Upload Template",accept:"image/png, image/jpeg, image/webp, image/bmp, image/gif"}).L().L().B({class:"bm-1d bm-11"}).ht({textContent:"Disable","data-button-status":"shown"},(t,e)=>{e.onclick=()=>{e.disabled=!0,"shown"==e.dataset.buttonStatus?(t.T?.Et?.de(!1),e.dataset.buttonStatus="hidden",e.textContent="Enable",t.Mt("Disabled templates!")):(t.T?.Et?.de(!0),e.dataset.buttonStatus="shown",e.textContent="Disable",t.Mt("Enabled templates!")),e.disabled=!1}}).L().ht({textContent:"Create"},(t,e)=>{e.onclick=()=>{const e=document.querySelector(`#${this.Tt} .bm-1c`),i=document.querySelector("#bm-v");if(!i.checkValidity())return i.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const n=document.querySelector("#bm-w");if(!n.checkValidity())return n.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const s=document.querySelector("#bm-x");if(!s.checkValidity())return s.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");const o=document.querySelector("#bm-y");if(!o.checkValidity())return o.reportValidity(),void t.$t("Coordinates are malformed! Did you try clicking on the canvas first?");e?.files[0]?(t?.T?.Et.ue(e.files[0],e.files[0]?.name.replace(/\.[^/.]+$/,""),[Number(i.value),Number(n.value),Number(s.value),Number(o.value)]),t.Mt("Drew to canvas!")):t.$t("No file selected!")}}).L().ht({textContent:"Filter"},(t,e)=>{e.onclick=()=>i(this,N,B).call(this)}).L().L().B({class:"bm-1d"}).ft({id:this.S,placeholder:`Status: Sleeping...\nVersion: ${this.version}`,readOnly:!0}).L().L().B({class:"bm-1d bm-11",style:"margin-bottom: 0;"}).B({class:"bm-11"}).ht({class:"bm-Z",innerHTML:"🎨",title:"Template Color Converter"},(t,e)=>{e.onclick=()=>{window.open("https://pepoafonso.github.io/color_converter_wplace/","_blank","noopener noreferrer")}}).L().ht({class:"bm-Z",innerHTML:"🌐",title:"Official Blue Marble Website"},(t,e)=>{e.onclick=()=>{window.open("https://bluemarble.lol/","_blank","noopener noreferrer")}}).L().L().P({textContent:"Made by SwingTheVine",style:"margin-top: auto;"}).L().L().L().L().L().N(this.St),this.xt(`#${this.Tt}.bm-1l`,`#${this.Tt} .bm-1j`))}}(H,U),z=new class{constructor(t,i,n){e(this,v),this.name=t,this.version=i,this.C=n,this.schemaVersion="1.1.0",this.be=null,this.pe="!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~",this.h=1e3,this.Nt=3,this.Wt=3,this.Ht=function(t){const e=p;e.unshift({id:-1,premium:!1,name:"Erased",rgb:[222,250,206]}),e.unshift({id:-2,premium:!1,name:"Other",rgb:[0,0,0]});const i=new Map;for(const n of e){if(0==n.id||-2==n.id)continue;const e=n.rgb[0],s=n.rgb[1],o=n.rgb[2];for(let a=-t;a<=t;a++)for(let r=-t;r<=t;r++)for(let l=-t;l<=t;l++){const t=e+a,c=s+r,h=o+l;if(t<0||t>255||c<0||c>255||h<0||h>255)continue;const m=(255<<24|h<<16|c<<8|t)>>>0;i.has(m)||i.set(m,n.id)}}return{palette:e,M:i}}(this.Wt),this.Pt=null,this.ge="",this.Bt=[],this.Lt=null,this.fe=!0,this.we=null,this.Ut=new Map}async ye(){return{whoami:this.name.replace(" ",""),scriptVersion:this.version,schemaVersion:this.schemaVersion,templates:{}}}async ue(t,e,n){this.Lt||(this.Lt=await this.ye(),console.log("Creating JSON...")),this.C.Mt(`Creating template at ${n.join(", ")}...`);const s=new g({displayName:e,t:0,i:a(this.be||0,this.pe),file:t,coords:n}),{v:o,$:r}=await s.u(this.h,this.Ht);s.o=o;const l={total:s.m.total,colors:Object.fromEntries(s.m.colors)};this.Lt.templates[`${s.t} ${s.i}`]={name:s.displayName,coords:n.join(", "),enabled:!0,pixels:l,tiles:r},this.Bt=[],this.Bt.push(s),this.C.Mt(`Template created at ${n.join(", ")}!`),console.log(Object.keys(this.Lt.templates).length),console.log(this.Lt),console.log(this.Bt),console.log(JSON.stringify(this.Lt)),await i(this,v,x).call(this)}ve(){}async xe(){this.Lt||(this.Lt=await this.ye(),console.log("Creating JSON..."))}async $e(t,e){if(!this.fe)return t;const n=this.h*this.Nt;e=e[0].toString().padStart(4,"0")+","+e[1].toString().padStart(4,"0"),console.log(`Searching for templates in tile: "${e}"`);const s=this.Bt;console.log(s),s.sort((t,e)=>t.t-e.t),console.log(s);const o=s.map(t=>{const i=Object.keys(t.o).filter(t=>t.startsWith(e));if(0===i.length)return null;const n=i.map(e=>{const i=e.split(",");return{Me:t,Te:t.o[e],l:t.l?.[e],Se:[i[0],i[1]],Ce:[i[2],i[3]]}});return n?.[0]}).filter(Boolean);console.log(o);const a=o?.length||0;if(console.log(`templateCount = ${a}`),!(a>0))return this.C.Mt(`Sleeping\nVersion: ${this.version}`),t;{const t=s.filter(t=>Object.keys(t.o).filter(t=>t.startsWith(e)).length>0).reduce((t,e)=>t+(e.m.total||0),0),i=(new Intl.NumberFormat).format(t);this.C.Mt(`Displaying ${a} template${1==a?"":"s"}.\nTotal pixels: ${i}`)}const r=await createImageBitmap(t),l=new OffscreenCanvas(n,n),c=l.getContext("2d");c.imageSmoothingEnabled=!1,c.beginPath(),c.rect(0,0,n,n),c.clip(),c.clearRect(0,0,n,n),c.drawImage(r,0,0,n,n);const h=c.getImageData(0,0,n,n),m=new Uint32Array(h.data.buffer);for(const t of o){console.log("Template:"),console.log(t);const n=!!t.Me.m?.colors?.get(-1);let s=t.l.slice();const o=Number(t.Ce[0])*this.Nt,a=Number(t.Ce[1])*this.Nt;if(0!=this.Ut.size||n||c.drawImage(t.Te,o,a),!s){const e=c.getImageData(o,a,t.Te.width,t.Te.height);s=new Uint32Array(e.data.buffer)}const r=Date.now(),{Gt:l,Ft:h}=i(this,v,M).call(this,{It:m,Pt:s,At:[o,a,t.Te.width,t.Te.height]});let d=0;const u=0;for(const[t,e]of l)t!=u&&(d+=e);(0!=this.Ut.size||n)&&(console.log("Colors to filter: ",this.Ut),c.drawImage(await createImageBitmap(new ImageData(new Uint8ClampedArray(h.buffer),t.Te.width,t.Te.height)),o,a)),console.log(`Finished calculating correct pixels & filtering colors for the tile ${e} in ${(Date.now()-r)/1e3} seconds!\nThere are ${d} correct pixels.`),void 0===t.Me.m.correct&&(t.Me.m.correct={}),t.Me.m.correct[e]=l}return await l.convertToBlob({type:"image/png"})}De(t){console.log("Importing JSON..."),console.log(t),"BlueMarble"==t?.whoami&&i(this,v,$).call(this,t)}de(t){this.fe=t}}(H,U,_),E=new class{constructor(t){this.Et=t,this.Oe=!1,this.he="",this.me=[],this.ke=[]}Le(t){window.addEventListener("message",async e=>{const i=e.data,n=i.jsonData;if(!i||"blue-marble"!==i.source)return;if(!i.endpoint)return;const s=i.endpoint?.split("?")[0].split("/").filter(t=>t&&isNaN(Number(t))).filter(t=>t&&!t.includes(".")).pop();switch(console.log('%cBlue Marble%c: Recieved message about "%s"',"color: cornflowerblue;","",s),s){case"me":if(n.status&&"2"!=n.status?.toString()[0])return void t.$t("You are not logged in!\nCould not fetch userdata.");const e=Math.ceil(Math.pow(Math.floor(n.level)*Math.pow(30,.65),1/.65)-n.pixelsPainted);if(console.log(n.id),(n.id||0===n.id)&&console.log(a(n.id,"!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~")),this.Et.be=n.id,0!=this.he.length){const t=document.querySelector("#"+this.he);if(t){const e=n.charges;t.dataset.endDate=Date.now()+(e.max-e.count)*e.cooldownMs}}t.ut("bm-p",`Droplets: ${(new Intl.NumberFormat).format(n.droplets)}`),t.ut("bm-i",`Next level in ${(new Intl.NumberFormat).format(e)} pixel${1==e?"":"s"}`);break;case"pixel":const s=i.endpoint.split("?")[0].split("/").filter(t=>t&&!isNaN(Number(t))),l=new URLSearchParams(i.endpoint.split("?")[1]),c=[l.get("x"),l.get("y")];if(this.me.length&&(!s.length||!c.length))return void t.$t("Coordinates are malformed!\nDid you try clicking the canvas first?");this.me=[...s,...c];const h=(o=s,r=c,[parseInt(o[0])%4*1e3+parseInt(r[0]),parseInt(o[1])%4*1e3+parseInt(r[1])]),m=document.querySelectorAll("span");for(const t of m)if(t.textContent.trim().includes(`${h[0]}, ${h[1]}`)){let e=document.querySelector("#bm-h");const i=`(Tl X: ${s[0]}, Tl Y: ${s[1]}, Px X: ${c[0]}, Px Y: ${c[1]})`;e?e.textContent=i:(e=document.createElement("span"),e.id="bm-h",e.textContent=i,e.style="margin-left: calc(var(--spacing)*3); font-size: small;",t.parentNode.parentNode.insertAdjacentElement("afterend",e))}break;case"tiles":let d=i.endpoint.split("/");d=[parseInt(d[d.length-2]),parseInt(d[d.length-1].replace(".png",""))];const u=i.blobID,b=i.blobData,p=Date.now(),g=await this.Et.$e(b,d);console.log(`Finished loading the tile in ${(Date.now()-p)/1e3} seconds!`),window.postMessage({source:"blue-marble",blobID:u,blobData:g,blink:i.blink});break;case"robots":this.Oe="false"==n.userscript?.toString().toLowerCase();break}var o,r})}async Ne(t){console.log("Sending heartbeat to telemetry server...");let e=GM_getValue("bmUserSettings","{}");if(e=JSON.parse(e),!e||!e.telemetry||!e.uuid)return void console.log("Telemetry is disabled, not sending heartbeat.");const i=navigator.userAgent;let n=await this.Be(i),s=this.Ie(i);GM_xmlhttpRequest({method:"POST",url:"https://telemetry.thebluecorner.net/heartbeat",headers:{"Content-Type":"application/json"},data:JSON.stringify({uuid:e.uuid,version:t,browser:n,os:s}),onload:t=>{200!==t.status&&o("Failed to send heartbeat:",t.statusText)},onerror:t=>{o("Error sending heartbeat:",t)}})}async Be(t=navigator.userAgent){return(t=t||"").includes("OPR/")||t.includes("Opera")?"Opera":t.includes("Edg/")?"Edge":t.includes("Vivaldi")?"Vivaldi":t.includes("YaBrowser")?"Yandex":t.includes("Kiwi")?"Kiwi":t.includes("Brave")?"Brave":t.includes("Firefox/")?"Firefox":t.includes("Chrome/")?"Chrome":t.includes("Safari/")?"Safari":navigator.brave&&"function"==typeof navigator.brave.isBrave&&await navigator.brave.isBrave()?"Brave":"Unknown"}Ie(t=navigator.userAgent){return/Windows NT 11/i.test(t=t||"")?"Windows 11":/Windows NT 10/i.test(t)?"Windows 10":/Windows NT 6\.3/i.test(t)?"Windows 8.1":/Windows NT 6\.2/i.test(t)?"Windows 8":/Windows NT 6\.1/i.test(t)?"Windows 7":/Windows NT 6\.0/i.test(t)?"Windows Vista":/Windows NT 5\.1|Windows XP/i.test(t)?"Windows XP":/Mac OS X 10[_\.]15/i.test(t)?"macOS Catalina":/Mac OS X 10[_\.]14/i.test(t)?"macOS Mojave":/Mac OS X 10[_\.]13/i.test(t)?"macOS High Sierra":/Mac OS X 10[_\.]12/i.test(t)?"macOS Sierra":/Mac OS X 10[_\.]11/i.test(t)?"OS X El Capitan":/Mac OS X 10[_\.]10/i.test(t)?"OS X Yosemite":/Mac OS X 10[_\.]/i.test(t)?"macOS":/Android/i.test(t)?"Android":/iPhone|iPad|iPod/i.test(t)?"iOS":/Linux/i.test(t)?"Linux":"Unknown"}}(z);_.k(E);var R=JSON.parse(GM_getValue("bmTemplates","{}"));console.log(R),z.De(R);var j=JSON.parse(GM_getValue("bmUserSettings","{}"));if(console.log(j),console.log(Object.keys(j).length),0==Object.keys(j).length){const t=crypto.randomUUID();console.log(t),GM.setValue("bmUserSettings",JSON.stringify({uuid:t}))}setInterval(()=>E.Ne(U),18e5);var X=j?.telemetry;if(console.log(`Telemetry is ${!(null==X)}`),null==X||X>1){const t=new class extends y{constructor(t,i,n,s){super(t,i),e(this,P),this.window=null,this.Tt="bm-T",this.St=document.body,this.Pe=n,this.uuid=s}async kt(){if(document.querySelector(`#${this.Tt}`))return void this.$t("Telemetry window already exists!");const t=await this.T.Be(navigator.userAgent),e=this.T.Ie(navigator.userAgent);this.window=this.B({id:this.Tt,class:"bm-1l",style:"height: 80vh; z-index: 9998;"}).B({class:"bm-U"}).B({class:"bm-1d bm-Q"}).G(1,{textContent:`${this.name} Telemetry`}).L().L().F().L().B({class:"bm-1d bm-15",style:"gap: 1.5ch; flex-wrap: wrap;"}).ht({textContent:"Enable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,P,A).call(this,this.Pe);const t=document.getElementById(this.Tt);t?.remove()}}).L().ht({textContent:"Disable Telemetry"},(t,e)=>{e.onclick=()=>{i(this,P,A).call(this,0);const t=document.getElementById(this.Tt);t?.remove()}}).L().ht({textContent:"More Information"},(t,e)=>{e.onclick=()=>{window.open("https://github.com/SwingTheVine/Wplace-TelemetryServer#telemetry-data","_blank","noopener noreferrer")}}).L().L().B({class:"bm-1d bm-19"}).B({class:"bm-1d"}).G(2,{textContent:"Legal"}).L().I({textContent:`We collect anonymous telemetry data such as your browser, OS, and script version to make the experience better for everyone. The data is never shared personally. The data is never sold. You can turn this off by pressing the "Disable" button, but keeping it on helps us improve features and reliability faster. Thank you for supporting ${this.name}!`}).L().L().F().L().B({class:"bm-1d"}).G(2,{textContent:"Non-Legal Summary"}).L().I({innerHTML:'You can disable telemetry by pressing the "Disable" button. If you would like to read more about what information we collect, press the "More Information" button.
This is the data stored on our servers:'}).L().Z().tt({innerHTML:`A unique identifier (UUIDv4) generated by Blue Marble. This enables our telemetry to function without tracking your actual user ID.
Your UUID is: ${n(this.uuid)}`}).L().tt({innerHTML:`The version of Blue Marble you are using.
Your version is: ${n(this.version)}`}).L().tt({innerHTML:`Your browser type, which is used to determine Blue Marble outages and browser popularity.
Your browser type is: ${n(t)}`}).L().tt({innerHTML:`Your OS type, which is used to determine Blue Marble outages and OS popularity.
Your OS type is: ${n(e)}`}).L().tt({innerHTML:"The date and time that Blue Marble sent the telemetry information."}).L().L().I({innerHTML:'All of the data mentioned above is aggregated every hour. This means every hour, anything that could even remotly be considered "personal data" is deleted from our server. Here, "aggregated" data means things like "42 people used Blue Marble on Google Chrome this hour", which can\'t be used to identify anyone in particular.'}).L().L().L().L().L().N(this.St)}}(H,U,1,j?.uuid);t.k(E),t.kt()}_.kt(),E.Le(_),new MutationObserver((t,e)=>{const i=document.querySelector("#color-1");if(!i)return;let n=document.querySelector("#bm-t");if(!n){n=document.createElement("button"),n.id="bm-t",n.textContent="Move ↑",n.className="btn btn-soft",n.onclick=function(){const t=this.parentNode.parentNode.parentNode.parentNode,e="Move ↑"==this.textContent;t.parentNode.className=t.parentNode.className.replace(e?"bottom":"top",e?"top":"bottom"),t.style.borderTopLeftRadius=e?"0px":"var(--radius-box)",t.style.borderTopRightRadius=e?"0px":"var(--radius-box)",t.style.borderBottomLeftRadius=e?"var(--radius-box)":"0px",t.style.borderBottomRightRadius=e?"var(--radius-box)":"0px",this.textContent=e?"Move ↓":"Move ↑"};const t=i.parentNode.parentNode.parentNode.parentNode.querySelector("h2");t.parentNode?.appendChild(n)}}).observe(document.body,{childList:!0,subtree:!0}),s(`%c${H}%c (${U}) userscript has loaded!`,"color: cornflowerblue;","")})(); \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index d544f07..3a97be2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,7 +51,7 @@ Contact Me Blue Marble Website WakaTime -Total Patches +Total Patches Total Lines of Code Total Comments Compression diff --git a/package-lock.json b/package-lock.json index b961be7..bf9309d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wplace-bluemarble", - "version": "0.88.433", + "version": "0.88.440", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wplace-bluemarble", - "version": "0.88.433", + "version": "0.88.440", "devDependencies": { "esbuild": "^0.25.0", "jsdoc": "^4.0.5", diff --git a/package.json b/package.json index fc3e054..698c5a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wplace-bluemarble", - "version": "0.88.433", + "version": "0.88.440", "type": "module", "homepage": "https://bluemarble.lol/", "repository": { diff --git a/src/BlueMarble.meta.js b/src/BlueMarble.meta.js index ef5e95b..ffaffe1 100644 --- a/src/BlueMarble.meta.js +++ b/src/BlueMarble.meta.js @@ -2,7 +2,7 @@ // @name Blue Marble // @name:en Blue Marble // @namespace https://github.com/SwingTheVine/ -// @version 0.88.433 +// @version 0.88.440 // @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @description:en A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA. // @author SwingTheVine diff --git a/src/WindowWizard.js b/src/WindowWizard.js new file mode 100644 index 0000000..117c435 --- /dev/null +++ b/src/WindowWizard.js @@ -0,0 +1,122 @@ +import Overlay from "./Overlay"; +import { escapeHTML } from "./utils"; + +/** Wizard that manages template updates & recovery + * @class WindowWizard + * @since 0.88.434 + * @see {@link Overlay} for examples + */ +export default class WindowWizard extends Overlay { + + /** Constructor for the Template Wizard window + * @param {string} name - The name of the userscript + * @param {string} version - The version of the userscript + * @param {string} schemaVersionBleedingEdge - The bleeding edge of schema versions for Blue Marble + * @since 0.88.434 + * @see {@link Overlay#constructor} for examples + */ + constructor(name, version, schemaVersionBleedingEdge) { + super(name, version); // Executes the code in the Overlay constructor + this.window = null; // Contains the *window* DOM tree + this.windowID = 'bm-window-wizard'; // The ID attribute for this window + this.windowParent = document.body; // The parent of the window DOM tree + + // Retrieves data from storage + this.currentJSON = JSON.parse(GM_getValue('bmTemplates', '{}')); // The current Blue Marble storage + this.scriptVersion = this.currentJSON?.scriptVersion; // Script version when template was created + this.schemaVersion = this.currentJSON?.schemaVersion; // Schema version when template was created + + this.schemaHealth = undefined; // Current schema health. This is: 'Good', 'Poor', 'Bad', or 'Dead' for full match, MINOR mismatch, MAJOR mismatch, and unknown, respectively. + this.schemaVersionBleedingEdge = schemaVersionBleedingEdge; // Latest schema version + } + + /** Spawns a Template Wizard window. + * If another template wizard window already exists, we DON'T spawn another! + * Parent/child relationships in the DOM structure below are indicated by indentation. + * @since 0.88.434 + */ + buildWindow() { + + // If a template wizard window already exists, throw an error and return early + if (document.querySelector(`#${this.windowID}`)) { + this.handleDisplayError('Template Wizard window already exists!'); + return; + } + + // Creates a new template wizard window + this.window = this.addDiv({'id': this.windowID, 'class': 'bm-window', 'style': 'z-index: 9001;'}) + .addDragbar() + .addButton({'class': 'bm-button-circle', 'textContent': '▼', 'aria-label': 'Minimize window "Template Wizard"', 'data-button-status': 'expanded'}, (instance, button) => { + button.onclick = () => instance.handleMinimization(button); + button.ontouchend = () => {button.click()}; // Needed only to negate weird interaction with dragbar + }).buildElement() + .addDiv().buildElement() // Contains the minimized h1 element + .addButton({'class': 'bm-button-circle', 'textContent': '🞪', 'aria-label': 'Close window "Template Wizard"'}, (instance, button) => { + button.onclick = () => {document.querySelector(`#${this.windowID}`)?.remove();}; + button.ontouchend = () => {button.click();}; // Needed only to negate weird interaction with dragbar + }).buildElement() + .buildElement() + .addDiv({'class': 'bm-window-content'}) + .addDiv({'class': 'bm-container bm-center-vertically'}) + .addHeader(1, {'textContent': 'Template Wizard'}).buildElement() + .buildElement() + .addHr().buildElement() + .addDiv({'class': 'bm-container'}) + .addP({'id': 'bm-wizard-status', 'textContent': 'Loading template storage status...'}).buildElement() + .buildElement() + .addDiv({'class': 'bm-container bm-scrollable'}) + .addSpan({'textContent': 'Detected templates:'}).buildElement() + // Detected templates will show up here + .buildElement() + .buildElement() + .buildElement().buildOverlay(this.windowParent); + + this.#displaySchemaHealth(); + } + + /** Determines how "healthy" the template storage is. + * @since 0.88.436 + */ + #displaySchemaHealth() { + + // SemVer -> string[] + const schemaVersionArray = this.schemaVersion.split(/[-\.\+]/); + const schemaVersionBleedingEdgeArray = this.schemaVersionBleedingEdge.split(/[-\.\+]/); + + // Calculates the health that is displayed as a banner + let schemaHealthBanner = ''; + if (schemaVersionArray[0] == schemaVersionBleedingEdgeArray[0]) { + + if (schemaVersionArray[1] == schemaVersionBleedingEdgeArray[1]) { + schemaHealthBanner = 'Template storage health: Healthy!
No futher action required. (Reason: Semantic version matches)'; + this.schemaHealth = 'Good'; + } else { + schemaHealthBanner = 'Template storage health: Poor!
You can still use your template, but some features may not work. It is recommended that you update Blue Marble\'s template storage. (Reason: MINOR version mismatch)'; + this.schemaHealth = 'Poor'; + } + } else { + schemaHealthBanner = 'Template storage health: Dead!
Blue Marble can not load the template storage. (Reason: MAJOR version mismatch)'; + this.schemaHealth = 'Dead'; + } + + // Display schema health to user + this.updateInnerHTML('#bm-wizard-status', `${schemaHealthBanner}
The current schema version (${escapeHTML(this.schemaVersion)}) was created during Blue Marble version ${escapeHTML(this.scriptVersion)}.
The current Blue Marble version (${escapeHTML(this.version)}) requires schema version ${escapeHTML(this.schemaVersionBleedingEdge)}.
If you don't want to upgrade the template storage (schema), then downgrade Blue Marble to version ${escapeHTML(this.scriptVersion)}.`); + + // If the schema health is Poor or Bad, then show update options + if ((this.schemaHealth == 'Poor') || (this.schemaHealth == 'Bad')) { + const buttonOptions = new Overlay(this.name, this.version); + buttonOptions.addDiv({'class': 'bm-container bm-flex-center bm-center-vertically'}) + .addButton({'textContent': 'Recover (download) templates'}, (instance, button) => { + button.onclick = () => { + + } + }).buildElement() + .addButton({'textContent': `Update template storage to ${this.schemaVersionBleedingEdge}`}, (instance, button) => { + button.onclick = () => { + + } + }).buildElement() + .buildElement().buildOverlay(document.querySelector('#bm-wizard-status').parentNode) + } + } +} \ No newline at end of file diff --git a/src/templateManager.js b/src/templateManager.js index 63c4ddb..3efab2e 100644 --- a/src/templateManager.js +++ b/src/templateManager.js @@ -1,5 +1,6 @@ import Template from "./Template"; import { base64ToUint8, colorpaletteForBlueMarble, numberToEncoded } from "./utils"; +import WindowWizard from "./WindowWizard"; /** Manages the template system. * This class handles all external requests for template modification, creation, and analysis. @@ -60,7 +61,7 @@ export default class TemplateManager { this.name = name; // Name of userscript this.version = version; // Version of userscript this.overlay = overlay; // The main instance of the Overlay class - this.templatesVersion = '1.0.0'; // Version of JSON schema + this.schemaVersion = '1.1.0'; // Version of JSON schema this.userID = null; // The ID of the current user this.encodingBase = '!#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~'; // Characters to use for encoding/decoding this.tileSize = 1000; // The number of pixels in a tile. Assumes the tile is square @@ -88,7 +89,7 @@ export default class TemplateManager { return { "whoami": this.name.replace(' ', ''), // Name of userscript without spaces "scriptVersion": this.version, // Version of userscript - "schemaVersion": this.templatesVersion, // Version of JSON schema + "schemaVersion": this.schemaVersion, // Version of JSON schema "templates": {} // The templates }; } @@ -374,68 +375,102 @@ export default class TemplateManager { console.log(`BlueMarble length: ${Object.keys(templates).length}`); - // Run only if there are templates saved - if (Object.keys(templates).length > 0) { + const schemaVersion = json?.schemaVersion; + const schemaVersionArray = schemaVersion.split(/[-\.\+]/); // SemVer -> string[] + const schemaVersionBleedingEdge = this.schemaVersion.split(/[-\.\+]/); // SemVer -> string[] + const scriptVersion = json?.scriptVersion; - // For each template... - for (const template in templates) { + console.log(`BlueMarble Template Schema: ${schemaVersion}; Script Version: ${scriptVersion}`); - const templateKey = template; // The identification key for the template. E.g., "0 $Z" - const templateValue = templates[template]; // The actual content of the template - console.log(`Template Key: ${templateKey}`); + // If 1.x.x + if (schemaVersionArray[0] == schemaVersionBleedingEdge[0]) { - if (templates.hasOwnProperty(template)) { + // If 1.1.x + if (schemaVersionArray[1] == schemaVersionBleedingEdge[1]) { - const templateKeyArray = templateKey.split(' '); // E.g., "0 $Z" -> ["0", "$Z"] - const sortID = Number(templateKeyArray?.[0]); // Sort ID of the template - const authorID = templateKeyArray?.[1] || '0'; // User ID of the person who exported the template - const displayName = templateValue.name || `Template ${sortID || ''}`; // Display name of the template - //const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4] + loadSchemaVersion_1_x_x(); // Load 1.1.x schema + } else { - const pixelCount = { - total: templateValue.pixels.total, - colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value])) - }; + // Spawns a new Template Wizard + const windowWizard = new WindowWizard(this.name, this.version, this.schemaVersion); + windowWizard.buildWindow(); - const tilesbase64 = templateValue.tiles; - const templateTiles = {}; // Stores the template bitmap tiles for each tile. - const templateTiles32 = {}; // Stores the template Uint32Array tiles for each tile. + loadSchemaVersion_1_x_x(); // Load 1.x.x schema with 1.1.x loader, expecting some things to not function + } + } else { + // We don't know what the schema is. Unsupported? - const actualTileSize = this.tileSize * this.drawMult; + this.overlay.handleDisplayError(`Template version ${schemaVersion} is unsupported.\nUse Blue Marble version ${scriptVersion} or load a new template.`); + } - for (const tile in tilesbase64) { - console.log(tile); - if (tilesbase64.hasOwnProperty(tile)) { - const encodedTemplateBase64 = tilesbase64[tile]; - const templateUint8Array = base64ToUint8(encodedTemplateBase64); // Base 64 -> Uint8Array + /** Loads version 1.0.0 of Blue Marble template storage + * @since 0.88.434 + */ + async function loadSchemaVersion_1_x_x() { - const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob - const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap - templateTiles[tile] = templateBitmap; - - // Converts to Uint32Array - const canvas = new OffscreenCanvas(actualTileSize, actualTileSize); - const context = canvas.getContext('2d'); - context.drawImage(templateBitmap, 0, 0); - const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height); - templateTiles32[tile] = new Uint32Array(imageData.data.buffer); + // Run only if there are templates saved + if (Object.keys(templates).length > 0) { + + // For each template... + for (const template in templates) { + + const templateKey = template; // The identification key for the template. E.g., "0 $Z" + const templateValue = templates[template]; // The actual content of the template + console.log(`Template Key: ${templateKey}`); + + if (templates.hasOwnProperty(template)) { + + const templateKeyArray = templateKey.split(' '); // E.g., "0 $Z" -> ["0", "$Z"] + const sortID = Number(templateKeyArray?.[0]); // Sort ID of the template + const authorID = templateKeyArray?.[1] || '0'; // User ID of the person who exported the template + const displayName = templateValue.name || `Template ${sortID || ''}`; // Display name of the template + //const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4] + + const pixelCount = { + total: templateValue.pixels.total, + colors: new Map(Object.entries(templateValue.pixels.colors).map(([key, value]) => [Number(key), value])) + }; + + const tilesbase64 = templateValue.tiles; + const templateTiles = {}; // Stores the template bitmap tiles for each tile. + const templateTiles32 = {}; // Stores the template Uint32Array tiles for each tile. + + const actualTileSize = this.tileSize * this.drawMult; + + for (const tile in tilesbase64) { + console.log(tile); + if (tilesbase64.hasOwnProperty(tile)) { + const encodedTemplateBase64 = tilesbase64[tile]; + const templateUint8Array = base64ToUint8(encodedTemplateBase64); // Base 64 -> Uint8Array + + const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob + const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap + templateTiles[tile] = templateBitmap; + + // Converts to Uint32Array + const canvas = new OffscreenCanvas(actualTileSize, actualTileSize); + const context = canvas.getContext('2d'); + context.drawImage(templateBitmap, 0, 0); + const imageData = context.getImageData(0, 0, templateBitmap.width, templateBitmap.height); + templateTiles32[tile] = new Uint32Array(imageData.data.buffer); + } } + + // Creates a new Template class instance + const template = new Template({ + displayName: displayName, + sortID: sortID || this.templatesArray?.length || 0, + authorID: authorID || '', + //coords: coords, + }); + template.pixelCount = pixelCount; + template.chunked = templateTiles; + template.chunked32 = templateTiles32; + + this.templatesArray.push(template); + console.log(this.templatesArray); + console.log(`^^^ This ^^^`); } - - // Creates a new Template class instance - const template = new Template({ - displayName: displayName, - sortID: sortID || this.templatesArray?.length || 0, - authorID: authorID || '', - //coords: coords, - }); - template.pixelCount = pixelCount; - template.chunked = templateTiles; - template.chunked32 = templateTiles32; - - this.templatesArray.push(template); - console.log(this.templatesArray); - console.log(`^^^ This ^^^`); } } }