From fa85b212d38c912509d90e0cf64a4b13ff0b1301 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:07:15 -0400 Subject: [PATCH 01/54] Add nodes.js extension for Scratch --- static/extensions/EverythingAcc0unt/nodes.js | 397 +++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 static/extensions/EverythingAcc0unt/nodes.js diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js new file mode 100644 index 000000000..0cc80543b --- /dev/null +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -0,0 +1,397 @@ +(async function(Scratch) { + "use strict"; + if (!Scratch.extensions.unsandboxed) { + alert("This extension must be unsandboxed."); + return; + } + const nodes = []; + const links = []; + const blocks = []; + const menus = {}; + let nextId = 1; +const NODE1 = "#56ad57"; +const NODE2 = "#419b42"; +const NODE3 = "#348235"; + +const LINK1 = "#2f8242"; +const LINK2 = "#256e35"; +const LINK3 = "#1c5729"; + function getNode(id) { + return nodes.find(n => n.id === Number(id)); + } + function linkExists(a, b) { + return links.some( + l => + (l.from === Number(a) && l.to === Number(b)) || + (l.from === Number(b) && l.to === Number(a)) + ); + } + function areAdjacent(a, b) { + const dx = Math.abs(a.x - b.x); + const dy = Math.abs(a.y - b.y); + + return ( + (dx === 1 && dy === 0) || + (dx === 0 && dy === 1) + ); + } + blocks.push({ + opcode: "createNode", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "create node at x: [X] y: [Y] with an id of [ID]", + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "deleteNode", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "delete node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "nodeExists", + blockType: Scratch.BlockType.BOOLEAN, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "node [ID] exists?", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + blockType: Scratch.BlockType.XML, + xml: `` + }); + blocks.push({ + opcode: "setNodePosition", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "set node [ID] position x: [X] y: [Y]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "getNodeX", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "x of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "getNodeY", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "y of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "goDirection", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "go [DIR] of node id [ID]", + arguments: { + DIR: { + type: Scratch.ArgumentType.STRING, + menu: "directions" + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }); + blocks.push({ + blockType: Scratch.BlockType.XML, + xml: `` + }); + blocks.push({ + opcode: "allNodes", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "all nodes", + arguments: {}, + disableMonitor: true + }); + blocks.push({ + blockType: Scratch.BlockType.XML, + xml: `` + }); + blocks.push({ + blockType: Scratch.BlockType.LABEL, + text: "Links" + }); + blocks.push({ + opcode: "linkNodes", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "link node [A] to node [B]", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "unlinkNodes", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "unlink node [A] from node [B]", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }); + blocks.push({ + opcode: "nodesLinked", + blockType: Scratch.BlockType.BOOLEAN, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "node [A] linked to node [B]?", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }); + blocks.push({ + blockType: Scratch.BlockType.XML, + xml: `` + }); + blocks.push({ + opcode: "allLinks", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "all links", + arguments: {}, + disableMonitor: true + }); + class Extension { + getInfo() { + return { + id: "nodesystem", + name: "Nodes", + "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", + color1: "#f06681", + color2: "#d6516c", + blocks: blocks, + menus: { + directions: { + acceptReporters: true, + items: [ + "right", + "left", + "up", + "down" + ] + } + } + }; + } +createNode(args) { + nodes.push({ + id: Number(args.ID), + x: Number(args.X), + y: Number(args.Y) + }); +} + deleteNode(args) { + const id = Number(args.ID); + const index = nodes.findIndex( + n => n.id === id + ); + if (index !== -1) { + nodes.splice(index, 1); + } + for (let i = links.length - 1; i >= 0; i--) { + if ( + links[i].from === id || + links[i].to === id + ) { + links.splice(i, 1); + } + } + } + nodeExists(args) { + return !!getNode(args.ID); + } + setNodePosition(args) { + const node = getNode(args.ID); + if (!node) return; + node.x = Number(args.X); + node.y = Number(args.Y); + } + getNodeX(args) { + const node = getNode(args.ID); + if (!node) return 0; + return node.x; + } + getNodeY(args) { + const node = getNode(args.ID); + if (!node) return 0; + return node.y; + } + goDirection(args) { + const node = getNode(args.ID); + if (!node) return ""; + let x = node.x; + let y = node.y; + switch (String(args.DIR)) { + case "right": + x += 1; + break; + case "left": + x -= 1; + break; + case "up": + y += 1; + break; + case "down": + y -= 1; + break; + } + const found = nodes.find( + n => n.x === x && n.y === y + ); + return found ? found.id : ""; + } + linkNodes(args) { + const a = getNode(args.A); + const b = getNode(args.B); + if (!a || !b) return; + if (a.id === b.id) return; + if (!areAdjacent(a, b)) return; + if (linkExists(a.id, b.id)) return; + links.push({ + from: a.id, + to: b.id + }); + } + unlinkNodes(args) { + const a = Number(args.A); + const b = Number(args.B); + for (let i = links.length - 1; i >= 0; i--) { + const l = links[i]; + if ( + (l.from === a && l.to === b) || + (l.from === b && l.to === a) + ) { + links.splice(i, 1); + } + } + } + nodesLinked(args) { + return linkExists(args.A, args.B); + } + allNodes() { + return JSON.stringify(nodes); + } + allLinks() { + return JSON.stringify(links); + } + } + Scratch.extensions.register(new Extension()); +})(Scratch); From e2dea3cb88e7b810bf4dcc32fbef2e1dd2e789f6 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:08:25 -0400 Subject: [PATCH 02/54] Change extension ID from 'nodesystem' to 'ziploxnodesystem' --- static/extensions/EverythingAcc0unt/nodes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 0cc80543b..1e2727546 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -272,7 +272,7 @@ const LINK3 = "#1c5729"; class Extension { getInfo() { return { - id: "nodesystem", + id: "ziploxnodesystem", name: "Nodes", "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", color1: "#f06681", From 40edc5ecaaa9ff091bf9fe289006fd34e514c125 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:23:48 -0400 Subject: [PATCH 03/54] Add new file fdghdg to EverythingAcc0unt directory --- static/images/EverythingAcc0unt/fdghdg | 1 + 1 file changed, 1 insertion(+) create mode 100644 static/images/EverythingAcc0unt/fdghdg diff --git a/static/images/EverythingAcc0unt/fdghdg b/static/images/EverythingAcc0unt/fdghdg new file mode 100644 index 000000000..ff62eb779 --- /dev/null +++ b/static/images/EverythingAcc0unt/fdghdg @@ -0,0 +1 @@ +dfgdfg From 22bfd7048cc1fb733d5fc4ce4e7f5e6891f87d9a Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:24:13 -0400 Subject: [PATCH 04/54] Add files via upload --- static/images/EverythingAcc0unt/Nodes (1).svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 static/images/EverythingAcc0unt/Nodes (1).svg diff --git a/static/images/EverythingAcc0unt/Nodes (1).svg b/static/images/EverythingAcc0unt/Nodes (1).svg new file mode 100644 index 000000000..aba077dcf --- /dev/null +++ b/static/images/EverythingAcc0unt/Nodes (1).svg @@ -0,0 +1 @@ + \ No newline at end of file From 6568d9f5995e30cd4d0d16b78781b6eb5de94fe9 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:25:02 -0400 Subject: [PATCH 05/54] Delete static/images/EverythingAcc0unt/fdghdg --- static/images/EverythingAcc0unt/fdghdg | 1 - 1 file changed, 1 deletion(-) delete mode 100644 static/images/EverythingAcc0unt/fdghdg diff --git a/static/images/EverythingAcc0unt/fdghdg b/static/images/EverythingAcc0unt/fdghdg deleted file mode 100644 index ff62eb779..000000000 --- a/static/images/EverythingAcc0unt/fdghdg +++ /dev/null @@ -1 +0,0 @@ -dfgdfg From 72723e941122995b3e250fd195976d12929e80fe Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:25:30 -0400 Subject: [PATCH 06/54] Rename Nodes (1).svg to Nodes.svg --- static/images/EverythingAcc0unt/Nodes (1).svg | 1 - static/images/EverythingAcc0unt/Nodes.svg | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 static/images/EverythingAcc0unt/Nodes (1).svg create mode 100644 static/images/EverythingAcc0unt/Nodes.svg diff --git a/static/images/EverythingAcc0unt/Nodes (1).svg b/static/images/EverythingAcc0unt/Nodes (1).svg deleted file mode 100644 index aba077dcf..000000000 --- a/static/images/EverythingAcc0unt/Nodes (1).svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/static/images/EverythingAcc0unt/Nodes.svg b/static/images/EverythingAcc0unt/Nodes.svg new file mode 100644 index 000000000..32cc2e292 --- /dev/null +++ b/static/images/EverythingAcc0unt/Nodes.svg @@ -0,0 +1 @@ + From a8a7ed06856d5a132384313caaaae8752eb3f9a8 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:26:58 -0400 Subject: [PATCH 07/54] Create Node-System.md --- src/lib/Documentation/Node-System.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/lib/Documentation/Node-System.md diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/lib/Documentation/Node-System.md @@ -0,0 +1 @@ + From 0c9e42b88ee666fc29a3fd6e1bb582bbca6123e9 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:30:21 -0400 Subject: [PATCH 08/54] Create documentation for Node System Added basic documentation for the Node System with usage instructions. --- src/lib/Documentation/Node-System.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md index 8b1378917..0ea82a8f5 100644 --- a/src/lib/Documentation/Node-System.md +++ b/src/lib/Documentation/Node-System.md @@ -1 +1,8 @@ +

NODE SYSTEM

+so uhh.... there really shouldnt be a document on this but here goes +

so theres this block right?

+```scratch +create node at x: (0) y: (0) with an id of (1) +``` +i recommend you use whole numbers for all of the values there but it's pretty self explanatory okay bye From 9a831397563f9f295f1f088f4511afa91bc6cb95 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:31:55 -0400 Subject: [PATCH 09/54] Update Node-System.md with introduction and example Added a brief introduction and example code for the Node System. --- src/lib/Documentation/Node-System.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md index 0ea82a8f5..58b37797f 100644 --- a/src/lib/Documentation/Node-System.md +++ b/src/lib/Documentation/Node-System.md @@ -1,6 +1,7 @@

NODE SYSTEM

so uhh.... there really shouldnt be a document on this but here goes

so theres this block right?

+ ```scratch create node at x: (0) y: (0) with an id of (1) ``` From 598454257d86effd26165cf8e615bd20943363b7 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:42:53 -0400 Subject: [PATCH 10/54] Add Nodes extension with description and creator Added a new node system extension with relevant details. --- src/lib/extensions.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 24293c6f1..eeb814430 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -20,6 +20,14 @@ export default [ isGitHub: true, creator: "TheShovel", }, + { + name: "Nodes", + description: "A node system that can be utilized for many purposes, such as world maps and more!", + code: "EverythingAcc0unt/nodes.js", + banner: "EverythingAcc0unt/Nodes.svg", + isGitHub: true, + creator: "Ziploxwastaken", + }, { name: "Server Storage", description: "Similar to the server storage blocks in the 'Storage' extension, but with a better server uptime and non-global keys.\nDid you know the server is open source?", From 70bef6e0ec2094112f7df84a61d2ef66fb2366f2 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sat, 9 May 2026 21:43:32 -0400 Subject: [PATCH 11/54] Add tags property to Nodes extension --- src/lib/extensions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index eeb814430..29cffe614 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -23,6 +23,7 @@ export default [ { name: "Nodes", description: "A node system that can be utilized for many purposes, such as world maps and more!", + tags: ["new"], code: "EverythingAcc0unt/nodes.js", banner: "EverythingAcc0unt/Nodes.svg", isGitHub: true, From cb644c68acf5771f4ca161c489874eabec1bd1e8 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:36:01 -0400 Subject: [PATCH 12/54] Remove unused variables from nodes.js Removed unused variables 'menus' and 'nextId' from nodes.js. --- static/extensions/EverythingAcc0unt/nodes.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 1e2727546..04a28111f 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -7,8 +7,6 @@ const nodes = []; const links = []; const blocks = []; - const menus = {}; - let nextId = 1; const NODE1 = "#56ad57"; const NODE2 = "#419b42"; const NODE3 = "#348235"; From 6d76b77fcb3b4b750b6145bd203ee60fedd1b208 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:38:22 -0400 Subject: [PATCH 13/54] Rename class Extension to NodeSystem --- static/extensions/EverythingAcc0unt/nodes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 04a28111f..e73f1f6df 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -267,7 +267,7 @@ const LINK3 = "#1c5729"; arguments: {}, disableMonitor: true }); - class Extension { + class NodeSystem { getInfo() { return { id: "ziploxnodesystem", From ea0e2aeba799396c1629a0e25653729c816b3b30 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:45:13 -0400 Subject: [PATCH 14/54] Refactor node management functions in nodes.js --- static/extensions/EverythingAcc0unt/nodes.js | 458 ++++++++++--------- 1 file changed, 233 insertions(+), 225 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index e73f1f6df..8123ca948 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -33,240 +33,248 @@ const LINK3 = "#1c5729"; (dx === 0 && dy === 1) ); } - blocks.push({ - opcode: "createNode", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "create node at x: [X] y: [Y] with an id of [ID]", - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 +getInfo() { + return { + id: "yourExtensionId", + name: "Your Extension", + blocks: [ + { + opcode: "createNode", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "create node at x: [X] y: [Y] with an id of [ID]", + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 + { + opcode: "deleteNode", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "delete node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "deleteNode", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "delete node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "nodeExists", - blockType: Scratch.BlockType.BOOLEAN, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "node [ID] exists?", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - blockType: Scratch.BlockType.XML, - xml: `` - }); - blocks.push({ - opcode: "setNodePosition", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "set node [ID] position x: [X] y: [Y]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + { + opcode: "nodeExists", + blockType: Scratch.BlockType.BOOLEAN, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "node [ID] exists?", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true }, - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 + { + blockType: Scratch.BlockType.XML, + xml: `` }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "getNodeX", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "x of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "getNodeY", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "y of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "goDirection", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "go [DIR] of node id [ID]", - arguments: { - DIR: { - type: Scratch.ArgumentType.STRING, - menu: "directions" + { + opcode: "setNodePosition", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "set node [ID] position x: [X] y: [Y]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + } + }, + disableMonitor: true }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }); - blocks.push({ - blockType: Scratch.BlockType.XML, - xml: `` - }); - blocks.push({ - opcode: "allNodes", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "all nodes", - arguments: {}, - disableMonitor: true - }); - blocks.push({ - blockType: Scratch.BlockType.XML, - xml: `` - }); - blocks.push({ - blockType: Scratch.BlockType.LABEL, - text: "Links" - }); - blocks.push({ - opcode: "linkNodes", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "link node [A] to node [B]", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + { + opcode: "getNodeX", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "x of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "unlinkNodes", - blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "unlink node [A] from node [B]", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + { + opcode: "getNodeY", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "y of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 - } - }, - disableMonitor: true - }); - blocks.push({ - opcode: "nodesLinked", - blockType: Scratch.BlockType.BOOLEAN, - hideFromPalette: false, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "node [A] linked to node [B]?", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + { + opcode: "goDirection", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "go [DIR] of node id [ID]", + arguments: { + DIR: { + type: Scratch.ArgumentType.STRING, + menu: "directions" + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + disableMonitor: true + }, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, + { + opcode: "allNodes", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "all nodes", + arguments: {}, + disableMonitor: true + }, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, + { + blockType: Scratch.BlockType.LABEL, + text: "Links" }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 + { + opcode: "linkNodes", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "link node [A] to node [B]", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }, + { + opcode: "unlinkNodes", + blockType: Scratch.BlockType.COMMAND, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "unlink node [A] from node [B]", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }, + { + opcode: "nodesLinked", + blockType: Scratch.BlockType.BOOLEAN, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "node [A] linked to node [B]?", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + }, + disableMonitor: true + }, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, + { + opcode: "allLinks", + blockType: Scratch.BlockType.REPORTER, + hideFromPalette: false, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "all links", + arguments: {}, + disableMonitor: true } - }, - disableMonitor: true - }); - blocks.push({ - blockType: Scratch.BlockType.XML, - xml: `` - }); - blocks.push({ - opcode: "allLinks", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "all links", - arguments: {}, - disableMonitor: true - }); + ] + }; +} class NodeSystem { getInfo() { return { From dab63797d79f6786da0a16ac1978c14e07215444 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:53:03 -0400 Subject: [PATCH 15/54] Update extension ID and name in nodes.js --- static/extensions/EverythingAcc0unt/nodes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 8123ca948..64dd5f603 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -35,8 +35,9 @@ const LINK3 = "#1c5729"; } getInfo() { return { - id: "yourExtensionId", - name: "Your Extension", + id: "ziploxxdnodes", + name: "Nodes", + blocks: [ { opcode: "createNode", From eb4cf9f169fe2c43dd34d43751506b0aa84b1e87 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:55:12 -0400 Subject: [PATCH 16/54] Add blockIconURI to node info --- static/extensions/EverythingAcc0unt/nodes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 64dd5f603..bf2abd666 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -37,7 +37,7 @@ getInfo() { return { id: "ziploxxdnodes", name: "Nodes", - + "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", blocks: [ { opcode: "createNode", From 9e3b9b9c693199fd8b94ba21cf87d85aa2c74d22 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 00:59:38 -0400 Subject: [PATCH 17/54] Refactor nodes array to use Map for storage --- static/extensions/EverythingAcc0unt/nodes.js | 68 +++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index bf2abd666..cc940986f 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -4,7 +4,7 @@ alert("This extension must be unsandboxed."); return; } - const nodes = []; + const nodes = new Map(); const links = []; const blocks = []; const NODE1 = "#56ad57"; @@ -15,8 +15,8 @@ const LINK1 = "#2f8242"; const LINK2 = "#256e35"; const LINK3 = "#1c5729"; function getNode(id) { - return nodes.find(n => n.id === Number(id)); - } + return nodes.get(Number(id)); +} function linkExists(a, b) { return links.some( l => @@ -299,32 +299,31 @@ getInfo() { }; } createNode(args) { - nodes.push({ - id: Number(args.ID), + const id = Number(args.ID); + + nodes.set(id, { + id, x: Number(args.X), y: Number(args.Y) }); } - deleteNode(args) { - const id = Number(args.ID); - const index = nodes.findIndex( - n => n.id === id - ); - if (index !== -1) { - nodes.splice(index, 1); - } - for (let i = links.length - 1; i >= 0; i--) { - if ( - links[i].from === id || - links[i].to === id - ) { - links.splice(i, 1); - } - } - } - nodeExists(args) { - return !!getNode(args.ID); +deleteNode(args) { + const id = Number(args.ID); + + nodes.delete(id); + + for (let i = links.length - 1; i >= 0; i--) { + if ( + links[i].from === id || + links[i].to === id + ) { + links.splice(i, 1); } + } +} +nodeExists(args) { + return nodes.has(Number(args.ID)); +} setNodePosition(args) { const node = getNode(args.ID); if (!node) return; @@ -360,10 +359,13 @@ createNode(args) { y -= 1; break; } - const found = nodes.find( - n => n.x === x && n.y === y - ); - return found ? found.id : ""; + for (const found of nodes.values()) { + if (found.x === x && found.y === y) { + return found.id; + } +} + +return ""; } linkNodes(args) { const a = getNode(args.A); @@ -393,12 +395,14 @@ createNode(args) { nodesLinked(args) { return linkExists(args.A, args.B); } - allNodes() { - return JSON.stringify(nodes); - } +allNodes() { + return JSON.stringify( + [...nodes.values()] + ); +} allLinks() { return JSON.stringify(links); } } - Scratch.extensions.register(new Extension()); + Scratch.extensions.register(new NodeSystem()); })(Scratch); From 6b1b2e89a2d9c4256892d3be9c7d3542bbde0b6b Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 01:08:54 -0400 Subject: [PATCH 18/54] Refactor NodeSystem class and update getInfo method --- static/extensions/EverythingAcc0unt/nodes.js | 30 +++++++------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index cc940986f..db4aa0552 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -6,7 +6,6 @@ } const nodes = new Map(); const links = []; - const blocks = []; const NODE1 = "#56ad57"; const NODE2 = "#419b42"; const NODE3 = "#348235"; @@ -33,12 +32,16 @@ const LINK3 = "#1c5729"; (dx === 0 && dy === 1) ); } -getInfo() { - return { - id: "ziploxxdnodes", - name: "Nodes", - "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", - blocks: [ + class NodeSystem { + getInfo() { + return { + id: "ziploxnodesystem", + name: "Nodes", + "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", + color1: "#f06681", + color2: "#d6516c", + blocks: [ + { opcode: "createNode", blockType: Scratch.BlockType.COMMAND, @@ -273,18 +276,7 @@ getInfo() { arguments: {}, disableMonitor: true } - ] - }; -} - class NodeSystem { - getInfo() { - return { - id: "ziploxnodesystem", - name: "Nodes", - "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", - color1: "#f06681", - color2: "#d6516c", - blocks: blocks, + ], menus: { directions: { acceptReporters: true, From 7ac4f421c48ef7ea776846c522f7b24a883ab792 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 01:25:46 -0400 Subject: [PATCH 19/54] Refactor unlinkNodes to improve readability Refactor unlinkNodes method to use filter instead of for loop. --- static/extensions/EverythingAcc0unt/nodes.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index db4aa0552..31911f4a0 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -374,15 +374,13 @@ return ""; unlinkNodes(args) { const a = Number(args.A); const b = Number(args.B); - for (let i = links.length - 1; i >= 0; i--) { - const l = links[i]; - if ( - (l.from === a && l.to === b) || - (l.from === b && l.to === a) - ) { - links.splice(i, 1); - } - } + //stevie shut the hell up dude!!!!!!1!// + links = links.filter(l => + !( + (l.from === a && l.to === b) || + (l.from === b && l.to === a) + ) +); } nodesLinked(args) { return linkExists(args.A, args.B); From f7306ded930652fc20be2c984624ddc2a8dd6447 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 08:53:06 -0400 Subject: [PATCH 20/54] Delete src/lib/Documentation/Node-System.md --- src/lib/Documentation/Node-System.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/lib/Documentation/Node-System.md diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md deleted file mode 100644 index 58b37797f..000000000 --- a/src/lib/Documentation/Node-System.md +++ /dev/null @@ -1,9 +0,0 @@ -

NODE SYSTEM

-so uhh.... there really shouldnt be a document on this but here goes -

so theres this block right?

- -```scratch -create node at x: (0) y: (0) with an id of (1) -``` - -i recommend you use whole numbers for all of the values there but it's pretty self explanatory okay bye From 87385cf25281e5e8992dbd5cd262067c8d2e973d Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 08:55:40 -0400 Subject: [PATCH 21/54] Refactor node search to use find method --- static/extensions/EverythingAcc0unt/nodes.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 31911f4a0..98de79f3e 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -351,13 +351,7 @@ nodeExists(args) { y -= 1; break; } - for (const found of nodes.values()) { - if (found.x === x && found.y === y) { - return found.id; - } -} - -return ""; +return nodes.values().find(n => n.x === x && n.y === y)?.id ?? ""; } linkNodes(args) { const a = getNode(args.A); From dcffc22eb41455cbbfb4d3ce01866f04971e97f7 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:02:02 -0400 Subject: [PATCH 22/54] Remove 'hideFromPalette' and 'disableMonitor' properties --- static/extensions/EverythingAcc0unt/nodes.js | 22 -------------------- 1 file changed, 22 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 98de79f3e..fcfa7553e 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -45,7 +45,6 @@ const LINK3 = "#1c5729"; { opcode: "createNode", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -64,12 +63,10 @@ const LINK3 = "#1c5729"; defaultValue: 1 } }, - disableMonitor: true }, { opcode: "deleteNode", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -85,7 +82,6 @@ const LINK3 = "#1c5729"; { opcode: "nodeExists", blockType: Scratch.BlockType.BOOLEAN, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -96,7 +92,6 @@ const LINK3 = "#1c5729"; defaultValue: 1 } }, - disableMonitor: true }, { blockType: Scratch.BlockType.XML, @@ -105,7 +100,6 @@ const LINK3 = "#1c5729"; { opcode: "setNodePosition", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -124,12 +118,10 @@ const LINK3 = "#1c5729"; defaultValue: 0 } }, - disableMonitor: true }, { opcode: "getNodeX", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -140,12 +132,10 @@ const LINK3 = "#1c5729"; defaultValue: 1 } }, - disableMonitor: true }, { opcode: "getNodeY", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -156,12 +146,10 @@ const LINK3 = "#1c5729"; defaultValue: 1 } }, - disableMonitor: true }, { opcode: "goDirection", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, @@ -176,7 +164,6 @@ const LINK3 = "#1c5729"; defaultValue: 1 } }, - disableMonitor: true }, { blockType: Scratch.BlockType.XML, @@ -185,13 +172,11 @@ const LINK3 = "#1c5729"; { opcode: "allNodes", blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, color1: NODE1, color2: NODE2, color3: NODE3, text: "all nodes", arguments: {}, - disableMonitor: true }, { blockType: Scratch.BlockType.XML, @@ -204,7 +189,6 @@ const LINK3 = "#1c5729"; { opcode: "linkNodes", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, color1: LINK1, color2: LINK2, color3: LINK3, @@ -219,12 +203,10 @@ const LINK3 = "#1c5729"; defaultValue: 2 } }, - disableMonitor: true }, { opcode: "unlinkNodes", blockType: Scratch.BlockType.COMMAND, - hideFromPalette: false, color1: LINK1, color2: LINK2, color3: LINK3, @@ -239,12 +221,10 @@ const LINK3 = "#1c5729"; defaultValue: 2 } }, - disableMonitor: true }, { opcode: "nodesLinked", blockType: Scratch.BlockType.BOOLEAN, - hideFromPalette: false, color1: LINK1, color2: LINK2, color3: LINK3, @@ -259,7 +239,6 @@ const LINK3 = "#1c5729"; defaultValue: 2 } }, - disableMonitor: true }, { blockType: Scratch.BlockType.XML, @@ -274,7 +253,6 @@ const LINK3 = "#1c5729"; color3: LINK3, text: "all links", arguments: {}, - disableMonitor: true } ], menus: { From d35cbf945cac4db7ff60c3347a75964cd7aa57cd Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:06:18 -0400 Subject: [PATCH 23/54] Simplify link removal from nodes Refactor link removal logic to use filter method. --- static/extensions/EverythingAcc0unt/nodes.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index fcfa7553e..eb0089363 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -282,15 +282,10 @@ deleteNode(args) { nodes.delete(id); - for (let i = links.length - 1; i >= 0; i--) { - if ( - links[i].from === id || - links[i].to === id - ) { - links.splice(i, 1); - } - } -} +links = links.filter(link => + link.from !== id && + link.to !== id +); nodeExists(args) { return nodes.has(Number(args.ID)); } From 07df7c8a45c5b44edda7475cc62c753d372b5e1e Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:09:33 -0400 Subject: [PATCH 24/54] Refactor goDirection block with new properties --- static/extensions/EverythingAcc0unt/nodes.js | 40 +++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index eb0089363..600a2980f 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -147,24 +147,6 @@ const LINK3 = "#1c5729"; } }, }, - { - opcode: "goDirection", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "go [DIR] of node id [ID]", - arguments: { - DIR: { - type: Scratch.ArgumentType.STRING, - menu: "directions" - }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, { blockType: Scratch.BlockType.XML, xml: `` @@ -244,6 +226,28 @@ const LINK3 = "#1c5729"; blockType: Scratch.BlockType.XML, xml: `` }, + { + opcode: "goDirection", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "go [DIR] of node id [ID]", + arguments: { + DIR: { + type: Scratch.ArgumentType.STRING, + menu: "directions" + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + }, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, { opcode: "allLinks", blockType: Scratch.BlockType.REPORTER, From 1b811ec43396c826da02bb676b906f1f4c4162a2 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:11:30 -0400 Subject: [PATCH 25/54] Clean up unlinkNodes method by removing comment Removed unnecessary comment from unlinkNodes method. --- static/extensions/EverythingAcc0unt/nodes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 600a2980f..d1c516dc7 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -1,3 +1,5 @@ +//Created by ZiploxZQS and OutsideFlight X3 + (async function(Scratch) { "use strict"; if (!Scratch.extensions.unsandboxed) { @@ -345,7 +347,6 @@ return nodes.values().find(n => n.x === x && n.y === y)?.id ?? ""; unlinkNodes(args) { const a = Number(args.A); const b = Number(args.B); - //stevie shut the hell up dude!!!!!!1!// links = links.filter(l => !( (l.from === a && l.to === b) || From ab631148d6d2aae11d57546f318f0882501169bb Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:21:11 -0400 Subject: [PATCH 26/54] Refactor node ID handling to use Scratch.Cast --- static/extensions/EverythingAcc0unt/nodes.js | 30 +++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index d1c516dc7..f26edf468 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -7,7 +7,7 @@ return; } const nodes = new Map(); - const links = []; + let links = []; const NODE1 = "#56ad57"; const NODE2 = "#419b42"; const NODE3 = "#348235"; @@ -16,13 +16,13 @@ const LINK1 = "#2f8242"; const LINK2 = "#256e35"; const LINK3 = "#1c5729"; function getNode(id) { - return nodes.get(Number(id)); + return nodes.get(Scratch.Cast.toNumber(id)); } function linkExists(a, b) { return links.some( l => - (l.from === Number(a) && l.to === Number(b)) || - (l.from === Number(b) && l.to === Number(a)) + (l.from === Scratch.Cast.toNumber(a) && l.to === Scratch.Cast.toNumber(b)) || + (l.from === Scratch.Cast.toNumber(b) && l.to === Scratch.Cast.toNumber(a)) ); } function areAdjacent(a, b) { @@ -275,16 +275,16 @@ const LINK3 = "#1c5729"; }; } createNode(args) { - const id = Number(args.ID); + const id = Scratch.Cast.toNumber(args.ID); nodes.set(id, { id, - x: Number(args.X), - y: Number(args.Y) + x: Scratch.Cast.toNumber(args.X), + y: Scratch.Cast.toNumber(args.Y) }); } deleteNode(args) { - const id = Number(args.ID); + const id = Scratch.Cast.toNumber(args.ID); nodes.delete(id); @@ -292,14 +292,15 @@ links = links.filter(link => link.from !== id && link.to !== id ); +} nodeExists(args) { - return nodes.has(Number(args.ID)); + return nodes.has(Scratch.Cast.toNumber(args.ID)); } setNodePosition(args) { const node = getNode(args.ID); if (!node) return; - node.x = Number(args.X); - node.y = Number(args.Y); + node.x = Scratch.Cast.toNumber(args.X); + node.y = Scratch.Cast.toNumber(args.Y); } getNodeX(args) { const node = getNode(args.ID); @@ -330,7 +331,8 @@ nodeExists(args) { y -= 1; break; } -return nodes.values().find(n => n.x === x && n.y === y)?.id ?? ""; +return [...nodes.values()] + .find(n => n.x === x && n.y === y)?.id ?? ""; } linkNodes(args) { const a = getNode(args.A); @@ -345,8 +347,8 @@ return nodes.values().find(n => n.x === x && n.y === y)?.id ?? ""; }); } unlinkNodes(args) { - const a = Number(args.A); - const b = Number(args.B); + const a = Scratch.Cast.toNumber(args.A); + const b = Scratch.Cast.toNumber(args.B); links = links.filter(l => !( (l.from === a && l.to === b) || From bb823ab3ff45af0870c70030002be8327e1eac79 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:31:54 -0400 Subject: [PATCH 27/54] Update print statement from 'Hello' to 'Goodbye' --- static/images/EverythingAcc0unt/Nodes.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/images/EverythingAcc0unt/Nodes.svg b/static/images/EverythingAcc0unt/Nodes.svg index 32cc2e292..5424c8d5f 100644 --- a/static/images/EverythingAcc0unt/Nodes.svg +++ b/static/images/EverythingAcc0unt/Nodes.svg @@ -1 +1 @@ - + From cd852c57248f865ef6ddccb133ee15d7210c3671 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 09:33:55 -0400 Subject: [PATCH 28/54] Update print statement from 'Hello' to 'Goodbye' --- static/images/EverythingAcc0unt/Nodes.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/images/EverythingAcc0unt/Nodes.svg b/static/images/EverythingAcc0unt/Nodes.svg index 5424c8d5f..0b6105a25 100644 --- a/static/images/EverythingAcc0unt/Nodes.svg +++ b/static/images/EverythingAcc0unt/Nodes.svg @@ -1 +1 @@ - + From 22e14f27569021f5e15ed555041b0997a45f14b3 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 13:05:54 -0400 Subject: [PATCH 29/54] Add new node operations and commands --- static/extensions/EverythingAcc0unt/nodes.js | 345 +++++++++++++++++-- 1 file changed, 323 insertions(+), 22 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index f26edf468..855e0a939 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -1,4 +1,5 @@ //Created by ZiploxZQS and OutsideFlight X3 +//There will be unneccesary comments because why not (async function(Scratch) { "use strict"; @@ -25,6 +26,15 @@ const LINK3 = "#1c5729"; (l.from === Scratch.Cast.toNumber(b) && l.to === Scratch.Cast.toNumber(a)) ); } +function getNodeNeighbors(id) { + id = Scratch.Cast.toNumber(id); + + return links.flatMap(link => { + if (link.from === id) return [link.to]; + if (link.to === id) return [link.from]; + return []; + }); +} function areAdjacent(a, b) { const dx = Math.abs(a.x - b.x); const dy = Math.abs(a.y - b.y); @@ -82,6 +92,41 @@ const LINK3 = "#1c5729"; disableMonitor: true }, { + opcode: "makeGrid", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "make a grid from x: [X1] y: [Y1] to x: [X2] y: [Y2]", + arguments: { + X1: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: -1 + }, + Y1: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + X2: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + Y2: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: -1 + } + }, +}, + { + opcode: "clearNodes", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "remove all nodes", + arguments: {}, +}, + { opcode: "nodeExists", blockType: Scratch.BlockType.BOOLEAN, color1: NODE1, @@ -149,10 +194,55 @@ const LINK3 = "#1c5729"; } }, }, + { + opcode: "closestNode", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "node closest to x: [X] y: [Y]", + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + } + } +}, { blockType: Scratch.BlockType.XML, xml: `` }, + { + opcode: "lowestNodeID", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "lowest node ID", + arguments: {} +}, +{ + opcode: "highestNodeID", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "highest node ID", + arguments: {} +}, + { + opcode: "nodeCount", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "number of nodes", + arguments: {}, +}, { opcode: "allNodes", blockType: Scratch.BlockType.REPORTER, @@ -206,6 +296,24 @@ const LINK3 = "#1c5729"; } }, }, + { + opcode: "connectNodesAnyWay", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "connect nodes from the range [A] to [B] in any way possible", + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5 + } + }, +}, { opcode: "nodesLinked", blockType: Scratch.BlockType.BOOLEAN, @@ -246,10 +354,69 @@ const LINK3 = "#1c5729"; } }, }, + { + opcode: "getNeighbors", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "neighbors of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, + }, { blockType: Scratch.BlockType.XML, xml: `` }, + { + opcode: "linkCount", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "link count of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, +}, + { + opcode: "linkedNode", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "linked node [INDEX] of node [ID]", + arguments: { + INDEX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + }, +}, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, + { + opcode: "linkCountTotal", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "number of links", + arguments: {}, +}, { opcode: "allLinks", blockType: Scratch.BlockType.REPORTER, @@ -312,28 +479,54 @@ nodeExists(args) { if (!node) return 0; return node.y; } - goDirection(args) { - const node = getNode(args.ID); - if (!node) return ""; - let x = node.x; - let y = node.y; - switch (String(args.DIR)) { - case "right": - x += 1; - break; - case "left": - x -= 1; - break; - case "up": - y += 1; - break; - case "down": - y -= 1; - break; - } -return [...nodes.values()] - .find(n => n.x === x && n.y === y)?.id ?? ""; - } +getNeighbors(args) { + return JSON.stringify(getNodeNeighbors(args.ID)); +} + linkCount(args) { + return getNeighbors(args.ID).length; +} + linkedNode(args) { + const neighbors = getNeighbors(args.ID); + + return ( + neighbors[ + Scratch.Cast.toNumber(args.INDEX) - 1 + ] ?? "" + ); +} +goDirection(args) { + const node = getNode(args.ID); + if (!node) return ""; + + let targetX = node.x; + let targetY = node.y; + + switch (String(args.DIR)) { + case "right": + targetX += 1; + break; + case "left": + targetX -= 1; + break; + case "up": + targetY += 1; + break; + case "down": + targetY -= 1; + break; + } + + const target = [...nodes.values()].find( + n => n.x === targetX && n.y === targetY + ); + + if (!target) return ""; + + // i uhhh forgot to add this back whoops + if (!linkExists(node.id, target.id)) return ""; + + return target.id; +} linkNodes(args) { const a = getNode(args.A); const b = getNode(args.B); @@ -346,6 +539,81 @@ return [...nodes.values()] to: b.id }); } + nodeCount() { + return nodes.size; +} + linkCountTotal() { + return links.length; +} +// its so fucking BUGGY aaaaarrrgghhhhh +connectNodesAnyWay(args) { + const A = Scratch.Cast.toNumber(args.A); + const B = Scratch.Cast.toNumber(args.B); + + const minID = Math.min(A, B); + const maxID = Math.max(A, B); + + const nodesArr = [...nodes.values()]; + + for (const node of nodesArr) { + + if (node.id < minID || node.id > maxID) continue; + + const directions = [ + { dx: 1, dy: 0 }, + { dx: -1, dy: 0 }, + { dx: 0, dy: 1 }, + { dx: 0, dy: -1 } + ]; + + for (const dir of directions) { + + const nx = node.x + dir.dx; + const ny = node.y + dir.dy; + + const neighbor = nodesArr.find( + n => n.x === nx && n.y === ny + ); +//they find their lovers awwwww!!! + if (!neighbor) continue; + + if (neighbor.id < minID || neighbor.id > maxID) continue; + + if (!linkExists(node.id, neighbor.id)) { + links.push({ + from: node.id, + to: neighbor.id + }); + } + } + } +} +makeGrid(args) { + const x1 = Scratch.Cast.toNumber(args.X1); + const y1 = Scratch.Cast.toNumber(args.Y1); + const x2 = Scratch.Cast.toNumber(args.X2); + const y2 = Scratch.Cast.toNumber(args.Y2); + + const minX = Math.min(x1, x2); + const maxX = Math.max(x1, x2); + const minY = Math.min(y1, y2); + const maxY = Math.max(y1, y2); + + let id = 1; + + for (let y = maxY; y >= minY; y--) { + for (let x = minX; x <= maxX; x++) { + + nodes.set(id, { + id, + x, + y + }); + + id++; + } + } +} unlinkNodes(args) { const a = Scratch.Cast.toNumber(args.A); const b = Scratch.Cast.toNumber(args.B); @@ -367,6 +635,39 @@ allNodes() { allLinks() { return JSON.stringify(links); } + clearNodes() { + nodes.clear(); + links = []; +} + closestNode(args) { + const x = Scratch.Cast.toNumber(args.X); + const y = Scratch.Cast.toNumber(args.Y); + + let best = null; + let bestDist = Infinity; + + for (const node of nodes.values()) { + const dx = node.x - x; + const dy = node.y - y; + const dist = dx * dx + dy * dy; // this might be useful since i dont want to keep changing the value when the grid is in the middle + + if (dist < bestDist) { + bestDist = dist; + best = node; + } + } + + return best ? best.id : ""; +} +lowestNodeID() { + if (nodes.size === 0) return ""; + return Math.min(...nodes.keys()); +} + +highestNodeID() { + if (nodes.size === 0) return ""; + return Math.max(...nodes.keys()); +} } Scratch.extensions.register(new NodeSystem()); })(Scratch); From 48b823de3b5c91dfcacf02923d8741310acb0315 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 13:26:33 -0400 Subject: [PATCH 30/54] Implement unlinkAllNeighbors command Added 'unlinkAllNeighbors' command to remove all neighbors of a specified node. --- static/extensions/EverythingAcc0unt/nodes.js | 25 ++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 855e0a939..777415768 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -53,6 +53,10 @@ function getNodeNeighbors(id) { color1: "#f06681", color2: "#d6516c", blocks: [ + { + blockType: Scratch.BlockType.LABEL, + text: "By ZiploxZQS and OutsideFlight" + }, { opcode: "createNode", @@ -297,6 +301,20 @@ function getNodeNeighbors(id) { }, }, { + opcode: "unlinkAllNeighbors", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "unlink all neighbors of node [ID]", + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } +}, + { opcode: "connectNodesAnyWay", blockType: Scratch.BlockType.COMMAND, color1: LINK1, @@ -667,6 +685,13 @@ lowestNodeID() { highestNodeID() { if (nodes.size === 0) return ""; return Math.max(...nodes.keys()); +} + unlinkAllNeighbors(args) { + const id = Scratch.Cast.toNumber(args.ID); + + links = links.filter(l => + !(l.from === id || l.to === id) + ); } } Scratch.extensions.register(new NodeSystem()); From 20032c8202005610c401a33d1c5137bd807e2cd2 Mon Sep 17 00:00:00 2001 From: outsideflight <168139872+outsideflight@users.noreply.github.com> Date: Sun, 10 May 2026 14:19:31 -0400 Subject: [PATCH 31/54] Create Node-System.md --- src/lib/Documentation/Node-System.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/lib/Documentation/Node-System.md diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/lib/Documentation/Node-System.md @@ -0,0 +1 @@ + From e0e998cbaf48e3d4cc8f144bcd5f3527868c47a8 Mon Sep 17 00:00:00 2001 From: outsideflight <168139872+outsideflight@users.noreply.github.com> Date: Sun, 10 May 2026 14:51:29 -0400 Subject: [PATCH 32/54] Update Node-System.md --- src/lib/Documentation/Node-System.md | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md index 8b1378917..cacebe6c3 100644 --- a/src/lib/Documentation/Node-System.md +++ b/src/lib/Documentation/Node-System.md @@ -1 +1,63 @@ +# Node System +Hi! So... Just wanna let you know... this is actually the *second* version of the document. The first one got deleted because I'm pretty sure it was meant to be unused... This is OutsideFlight writing this, by the way. + +Now, you clicked on this markdown so you could learn about our extension about nodes and links, right? Well, without furthur ado, here's the facts! + +

Introduction

+ +The extension itself is pretty self explanatory, but if you need to know how every block works... this is the place to go. + +# Blocks + +These are the blocks that are used for the Node category. + +## Nodes + +### Create node +Here you can enter the coordinates for the node to go, and enter the ID that the code will be from! +### Delete node +Deletes the node with the ID specified. Will create gaps, so be careful! +### Make a grid +Here you can make a grid full of nodes that goes from the coordinates specified. If you don't change the default values it can create 9 nodes, but the links will not be added. I'll talk about this later. +### Remove all nodes +Take a wild guess. +### Node with an ID of _ exists? +This one is a boolean that checks if the node with an exists. Can be useful for filling in gaps between nodes! +### Set Node Position +Moves the node with the specified ID's position to a certain point. +### X of Node +Checks for the X of the node specified. +### Y of Node +Checks for the Y of the node specified. +### Node closest to: ___ +This block checks for the closest node to a specific coordinate. This block is here instead of the "Node at 0, 0 block" because it just kind of works the same way. +### Lowest node ID +Checks for the lowest node ID. Not always equal to 1, so be careful! +### Highest node ID +Checks for the highest node ID. If there's gaps or if the ID goes into the negatives, the highest node ID will not be the same as the number of nodes there are. +### Number of Nodes +Checks for the number of nodes, not always the same as the highest node ID, like I said earlier. +### All nodes +It's just a JSON array of all the existing nodes. Not even readable, so maybe just ignore it... + +## Links + +What, you were expecting a embed link here? These are the link **BLOCKS.** Give me a break. + +### Link node 1 to node 2 +Links nodes together, however they can only be exactly one space apart. Sorry! +### Unlink node 1 from node 2 +Unlinks nodes together, one node at a time. +### Unlink all neighbors of node 1 +Unlinks all neighbors of the specified note. Deleting the node does the same thing as well, however. +### Connect nodes within a range +This one is actually quite interesting! Remember when I said links wouldn't be added to grids automatically? Well, this is your compromise! This block automatically creates pathways for a set range of ID's! Do this to a grid, and it will now have links! +### Node linked to another? +Checks if a node is linked to another. +### Go right of node 1. +It outputs the ID that is to the right of node 1. Keep in mind, this block will only work if there's a link between node 1 and the node next to it, but you can bypass the link check using something I'm gonna share later. +### Neighbors of node +Checks for the direct neighbors of the node specified that are connected via links. + +(unfinished) From 8ff1853c9e449d1a388de31ad4bf28889234d340 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 14:59:46 -0400 Subject: [PATCH 33/54] Refactor node methods and update block texts --- static/extensions/EverythingAcc0unt/nodes.js | 21 ++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/EverythingAcc0unt/nodes.js index 777415768..ecbba2f37 100644 --- a/static/extensions/EverythingAcc0unt/nodes.js +++ b/static/extensions/EverythingAcc0unt/nodes.js @@ -385,10 +385,6 @@ function getNodeNeighbors(id) { defaultValue: 1 } }, - }, - { - blockType: Scratch.BlockType.XML, - xml: `` }, { opcode: "linkCount", @@ -396,7 +392,7 @@ function getNodeNeighbors(id) { color1: LINK1, color2: LINK2, color3: LINK3, - text: "link count of node [ID]", + text: "node [ID] neighbor amount", arguments: { ID: { type: Scratch.ArgumentType.NUMBER, @@ -404,13 +400,17 @@ function getNodeNeighbors(id) { } }, }, + { + blockType: Scratch.BlockType.XML, + xml: `` + }, { opcode: "linkedNode", blockType: Scratch.BlockType.REPORTER, color1: LINK1, color2: LINK2, color3: LINK3, - text: "linked node [INDEX] of node [ID]", + text: "linked node #[INDEX] of node ID [ID]", arguments: { INDEX: { type: Scratch.ArgumentType.NUMBER, @@ -500,11 +500,12 @@ nodeExists(args) { getNeighbors(args) { return JSON.stringify(getNodeNeighbors(args.ID)); } - linkCount(args) { - return getNeighbors(args.ID).length; +linkCount(args) { + return getNodeNeighbors(args.ID).length; } - linkedNode(args) { - const neighbors = getNeighbors(args.ID); + +linkedNode(args) { + const neighbors = getNodeNeighbors(args.ID); return ( neighbors[ From 0be09007a7f80d7e5932c937ac2b0e5b60617ab4 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:05:46 -0400 Subject: [PATCH 34/54] Add nodes.js for ZiploxWasTaken extension --- static/extensions/{EverythingAcc0unt => ZiploxWasTaken}/nodes.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename static/extensions/{EverythingAcc0unt => ZiploxWasTaken}/nodes.js (100%) diff --git a/static/extensions/EverythingAcc0unt/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js similarity index 100% rename from static/extensions/EverythingAcc0unt/nodes.js rename to static/extensions/ZiploxWasTaken/nodes.js From 63e28686b4ec529992a17d224d605d5e61c5e923 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:09:29 -0400 Subject: [PATCH 35/54] Update Nodes extension code and banner references --- src/lib/extensions.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 29cffe614..4ba3e48fd 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -24,10 +24,10 @@ export default [ name: "Nodes", description: "A node system that can be utilized for many purposes, such as world maps and more!", tags: ["new"], - code: "EverythingAcc0unt/nodes.js", - banner: "EverythingAcc0unt/Nodes.svg", + code: "ZiploxWasTaken/nodes.js", + banner: "ZiploxWasTaken/Nodes.svg", isGitHub: true, - creator: "Ziploxwastaken", + creator: ["ZiploxWasTaken", "outsideflight"], }, { name: "Server Storage", From ee2939601324960c84d01f1246fc640778dac064 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:10:58 -0400 Subject: [PATCH 36/54] Add Nodes.svg to ZiploxWasTaken directory --- static/images/{EverythingAcc0unt => ZiploxWasTaken}/Nodes.svg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename static/images/{EverythingAcc0unt => ZiploxWasTaken}/Nodes.svg (100%) diff --git a/static/images/EverythingAcc0unt/Nodes.svg b/static/images/ZiploxWasTaken/Nodes.svg similarity index 100% rename from static/images/EverythingAcc0unt/Nodes.svg rename to static/images/ZiploxWasTaken/Nodes.svg From 3d161d1dd49a2111bc8620caa141d271b2c90fab Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:12:51 -0400 Subject: [PATCH 37/54] Import Node System documentation page --- src/lib/Documentation/pages.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/Documentation/pages.js b/src/lib/Documentation/pages.js index 313b5d162..5cfd0c83e 100644 --- a/src/lib/Documentation/pages.js +++ b/src/lib/Documentation/pages.js @@ -4,7 +4,8 @@ // "./test.md?raw" // "./particle-tools.md?raw" import PageParticleTools from "./particle-tools.md?raw"; - +// Node System +import PageNodeSystem from "./Node-System.md?raw"; // Extra Control (unlisted) import PageExtraControl from "./Extra-Control.md?raw"; // Free Servers From 66841e7e4253d460c3b3f83ddab0a1f077fa3b88 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:16:34 -0400 Subject: [PATCH 38/54] Add NodeSystem page to documentation --- src/lib/Documentation/pages.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/Documentation/pages.js b/src/lib/Documentation/pages.js index 5cfd0c83e..00ac75477 100644 --- a/src/lib/Documentation/pages.js +++ b/src/lib/Documentation/pages.js @@ -66,6 +66,9 @@ export default { // YeetYourFiles "YeetYourFiles": PageYeetYourFiles, + // NodeSystem (hiiiii XD) -Ziplox + "NodeSystem": PageNodeSystems, + "more-types": PageMoreTypes, // Boxed Physics From c254a6de67658298358fd7efe733ee95b9c84e33 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:17:19 -0400 Subject: [PATCH 39/54] Add documentation field to Nodes in extensions.js Added documentation field to Nodes entry. --- src/lib/extensions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 4ba3e48fd..df10d6bec 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -25,6 +25,7 @@ export default [ description: "A node system that can be utilized for many purposes, such as world maps and more!", tags: ["new"], code: "ZiploxWasTaken/nodes.js", + documentation: "nodesystem", banner: "ZiploxWasTaken/Nodes.svg", isGitHub: true, creator: ["ZiploxWasTaken", "outsideflight"], From d9518881c5734fdbd5b40a00b782f2908df7643a Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:17:53 -0400 Subject: [PATCH 40/54] Change 'NodeSystem' key to 'nodesystems' in pages.js --- src/lib/Documentation/pages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Documentation/pages.js b/src/lib/Documentation/pages.js index 00ac75477..8abeca3e2 100644 --- a/src/lib/Documentation/pages.js +++ b/src/lib/Documentation/pages.js @@ -67,7 +67,7 @@ export default { "YeetYourFiles": PageYeetYourFiles, // NodeSystem (hiiiii XD) -Ziplox - "NodeSystem": PageNodeSystems, + "nodesystems": PageNodeSystems, "more-types": PageMoreTypes, From 47894c4b313a970db4b902dd4b65f34df8b7e2c4 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 15:19:09 -0400 Subject: [PATCH 41/54] Correct documentation key from 'nodesystem' to 'nodesystems' --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index df10d6bec..bbb90d4b4 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -25,7 +25,7 @@ export default [ description: "A node system that can be utilized for many purposes, such as world maps and more!", tags: ["new"], code: "ZiploxWasTaken/nodes.js", - documentation: "nodesystem", + documentation: "nodesystems", banner: "ZiploxWasTaken/Nodes.svg", isGitHub: true, creator: ["ZiploxWasTaken", "outsideflight"], From 2bf906461c97638c9d72b8248f6b02bb7e57a35d Mon Sep 17 00:00:00 2001 From: outsideflight <168139872+outsideflight@users.noreply.github.com> Date: Sun, 10 May 2026 15:35:29 -0400 Subject: [PATCH 42/54] Update Node-System.md --- src/lib/Documentation/Node-System.md | 87 ++++++++++++---------------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md index cacebe6c3..6e5d0771d 100644 --- a/src/lib/Documentation/Node-System.md +++ b/src/lib/Documentation/Node-System.md @@ -8,56 +8,43 @@ Now, you clicked on this markdown so you could learn about our extension about n The extension itself is pretty self explanatory, but if you need to know how every block works... this is the place to go. -# Blocks +## Blocks These are the blocks that are used for the Node category. -## Nodes - -### Create node -Here you can enter the coordinates for the node to go, and enter the ID that the code will be from! -### Delete node -Deletes the node with the ID specified. Will create gaps, so be careful! -### Make a grid -Here you can make a grid full of nodes that goes from the coordinates specified. If you don't change the default values it can create 9 nodes, but the links will not be added. I'll talk about this later. -### Remove all nodes -Take a wild guess. -### Node with an ID of _ exists? -This one is a boolean that checks if the node with an exists. Can be useful for filling in gaps between nodes! -### Set Node Position -Moves the node with the specified ID's position to a certain point. -### X of Node -Checks for the X of the node specified. -### Y of Node -Checks for the Y of the node specified. -### Node closest to: ___ -This block checks for the closest node to a specific coordinate. This block is here instead of the "Node at 0, 0 block" because it just kind of works the same way. -### Lowest node ID -Checks for the lowest node ID. Not always equal to 1, so be careful! -### Highest node ID -Checks for the highest node ID. If there's gaps or if the ID goes into the negatives, the highest node ID will not be the same as the number of nodes there are. -### Number of Nodes -Checks for the number of nodes, not always the same as the highest node ID, like I said earlier. -### All nodes -It's just a JSON array of all the existing nodes. Not even readable, so maybe just ignore it... - -## Links - -What, you were expecting a embed link here? These are the link **BLOCKS.** Give me a break. - -### Link node 1 to node 2 -Links nodes together, however they can only be exactly one space apart. Sorry! -### Unlink node 1 from node 2 -Unlinks nodes together, one node at a time. -### Unlink all neighbors of node 1 -Unlinks all neighbors of the specified note. Deleting the node does the same thing as well, however. -### Connect nodes within a range -This one is actually quite interesting! Remember when I said links wouldn't be added to grids automatically? Well, this is your compromise! This block automatically creates pathways for a set range of ID's! Do this to a grid, and it will now have links! -### Node linked to another? -Checks if a node is linked to another. -### Go right of node 1. -It outputs the ID that is to the right of node 1. Keep in mind, this block will only work if there's a link between node 1 and the node next to it, but you can bypass the link check using something I'm gonna share later. -### Neighbors of node -Checks for the direct neighbors of the node specified that are connected via links. - -(unfinished) +### Nodes + +* **Create node**: Here you can enter the coordinates for the node to go, and enter the ID that the code will be from! +* **Delete node**: Deletes the node with the ID specified. Will create gaps, so be careful! +* **Make a grid**: Here you can make a grid full of nodes that goes from the coordinates specified. If you don't change the default values it can create 9 nodes, but the links will not be added. I'll talk about this later. +* **Remove all nodes**: Take a wild guess. +* **Node with an ID of _ exists?**: This one is a boolean that checks if the node with an exists. Can be useful for filling in gaps between nodes! +* **Set Node Position**: Moves the node with the specified ID's position to a certain point. +* **X of Node**: Checks for the X of the node specified. +* **Y of Node**: Checks for the Y of the node specified. +* **Node closest to: ___**: This block checks for the closest node to a specific coordinate. This block is here instead of the "Node at 0, 0 block" because it just kind of works the same way. +* **Lowest node ID**: Checks for the lowest node ID. Not always equal to 1, so be careful! +* **Highest node ID**: Checks for the highest node ID. If there's gaps or if the ID goes into the negatives, the highest node ID will not be the same as the number of nodes there are. +* **Number of Nodes**: Checks for the number of nodes, not always the same as the highest node ID, like I said earlier. +* **All nodes**: It's just a JSON array of all the existing nodes. Not even readable, so maybe just ignore it... + +### Links + +* **Link node 1 to node 2**: Links nodes together, however they can only be exactly one space apart. Sorry! +* **Unlink node 1 from node 2** Unlinks nodes together, one node at a time. +* **Unlink all neighbors of node 1**:Unlinks all neighbors of the specified note. Deleting the node does the same thing as well, however. +* **Connect nodes within a range**: This one is actually quite interesting! Remember when I said links wouldn't be added to grids automatically? Well, this is your compromise! This block automatically creates pathways for a set range of ID's! Do this to a grid, and it will now have links! +* **Node linked to another?** Checks if a node is linked to another. +* **Go right of node 1**: It outputs the ID that is to the right of node 1. Keep in mind, this block will only work if there's a link between node 1 and the node next to it, but you can bypass the link check using something I'm gonna share later. +* **Neighbors of node**: Checks for the direct neighbors of the node specified that are connected via links. +* **Node neighbor amount**: Returns the amount of linked neighbors a node has. +* **Linked node index of node ID**: Returns the index of node ID, in the order of when the nodes were linked. +* **Number of links**: Returns the amount of links. +* **All Links**: Returns every link in the form of an array, slightly more readable. + +## How to use + +Like said in the description, you can use links to create roadmaps and mainly just a grid you can walk across. +Keep in mind you can only link nodes that are one grid space away from each other! +Here's an example project to get you started: +https://studio.penguinmod.com/editor.html?project_url=https://file.garden/Z6ed_EN2XgmRM_ni/Node%20Sample%20Project.pmp From 26f71f6abf3e8ce116c7b447993bf5159ad32fa8 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 19:06:35 -0400 Subject: [PATCH 43/54] Change creator format in extensions.js --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index bbb90d4b4..0719b2cf3 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -28,7 +28,7 @@ export default [ documentation: "nodesystems", banner: "ZiploxWasTaken/Nodes.svg", isGitHub: true, - creator: ["ZiploxWasTaken", "outsideflight"], + creator: "ZiploxWasTaken" }, { name: "Server Storage", From e396a36b7e66fe3097f8363e2986ce0f78378ac2 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 19:06:52 -0400 Subject: [PATCH 44/54] Remove misleading comment in extensions.js Removed unnecessary comment about extra commas in JSON. --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 0719b2cf3..166ac92e1 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -1,4 +1,4 @@ -/* +,/* note to contributors & developers that can read JSON: the extra commas are added at the end of each thing to help copy & pasting work better From f962524536e0f6df4b3c08233f978eb404b8c40d Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 19:07:15 -0400 Subject: [PATCH 45/54] Fix formatting for creator field in extensions.js --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 166ac92e1..9660a774b 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -28,7 +28,7 @@ export default [ documentation: "nodesystems", banner: "ZiploxWasTaken/Nodes.svg", isGitHub: true, - creator: "ZiploxWasTaken" + creator: "ZiploxWasTaken", }, { name: "Server Storage", From ce79704e0ccd416b4536adb08e44b5a098247f1c Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 19:07:46 -0400 Subject: [PATCH 46/54] Update Node-System.md to remove introduction section Removed unnecessary introduction section from documentation. --- src/lib/Documentation/Node-System.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib/Documentation/Node-System.md b/src/lib/Documentation/Node-System.md index 6e5d0771d..9e5d7243b 100644 --- a/src/lib/Documentation/Node-System.md +++ b/src/lib/Documentation/Node-System.md @@ -4,10 +4,6 @@ Hi! So... Just wanna let you know... this is actually the *second* version of th Now, you clicked on this markdown so you could learn about our extension about nodes and links, right? Well, without furthur ado, here's the facts! -

Introduction

- -The extension itself is pretty self explanatory, but if you need to know how every block works... this is the place to go. - ## Blocks These are the blocks that are used for the Node category. From 05c350c8b41b41c9ee2148e047755aa870569b01 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 19:35:05 -0400 Subject: [PATCH 47/54] Update fmt.Println message from 'Hello' to 'Goodbye' --- static/extensions/ZiploxWasTaken/nodes.js | 1347 ++++++++++++--------- 1 file changed, 765 insertions(+), 582 deletions(-) diff --git a/static/extensions/ZiploxWasTaken/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js index ecbba2f37..e8929a78e 100644 --- a/static/extensions/ZiploxWasTaken/nodes.js +++ b/static/extensions/ZiploxWasTaken/nodes.js @@ -1,40 +1,64 @@ -//Created by ZiploxZQS and OutsideFlight X3 -//There will be unneccesary comments because why not +// Created by ZiploxZQS and OutsideFlight X3 +// There will be unnecessary comments because why not -(async function(Scratch) { +(async function (Scratch) { "use strict"; + if (!Scratch.extensions.unsandboxed) { alert("This extension must be unsandboxed."); return; } + const nodes = new Map(); let links = []; -const NODE1 = "#56ad57"; -const NODE2 = "#419b42"; -const NODE3 = "#348235"; -const LINK1 = "#2f8242"; -const LINK2 = "#256e35"; -const LINK3 = "#1c5729"; + const NODE1 = "#56ad57"; + const NODE2 = "#419b42"; + const NODE3 = "#348235"; + + const LINK1 = "#2f8242"; + const LINK2 = "#256e35"; + const LINK3 = "#1c5729"; + function getNode(id) { - return nodes.get(Scratch.Cast.toNumber(id)); -} + id = Scratch.Cast.toNumber(id); + + if (!Number.isFinite(id)) return null; + + return nodes.get(id); + } + function linkExists(a, b) { + a = Scratch.Cast.toNumber(a); + b = Scratch.Cast.toNumber(b); + return links.some( l => - (l.from === Scratch.Cast.toNumber(a) && l.to === Scratch.Cast.toNumber(b)) || - (l.from === Scratch.Cast.toNumber(b) && l.to === Scratch.Cast.toNumber(a)) + (l.from === a && l.to === b) || + (l.from === b && l.to === a) ); } -function getNodeNeighbors(id) { - id = Scratch.Cast.toNumber(id); - - return links.flatMap(link => { - if (link.from === id) return [link.to]; - if (link.to === id) return [link.from]; - return []; - }); -} + + function getNodeNeighbors(id) { + id = Scratch.Cast.toNumber(id); + + return [ + ...new Set( + links.flatMap(link => { + if (link.from === id) { + return [link.to]; + } + + if (link.to === id) { + return [link.from]; + } + + return []; + }) + ) + ]; + } + function areAdjacent(a, b) { const dx = Math.abs(a.x - b.x); const dy = Math.abs(a.y - b.y); @@ -44,411 +68,455 @@ function getNodeNeighbors(id) { (dx === 0 && dy === 1) ); } + + function findNodeAt(x, y) { + for (const node of nodes.values()) { + if (node.x === x && node.y === y) { + return node; + } + } + + return null; + } + class NodeSystem { getInfo() { return { id: "ziploxnodesystem", name: "Nodes", - "blockIconURI": "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My43NSIgaGVpZ2h0PSI4My43NSIgdmlld0JveD0iMCwwLDgzLjc1LDgzLjc1Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjc4LjEyNSwtMTM4LjEyNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTMxNC4zMjg1LDIwMi4xNzUybC0xNi44MzA5LC0xNi44MzA5IiBmaWxsPSIjZmZmZmZmIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjxwYXRoIGQ9Ik0zMTkuNzgxODcsMTUyLjE1MzNsLTIyLjUwMjQsMjIuNTAyNCIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zNTIuOTM3NDIsMTg1LjA5MDcyYy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NWMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDV6IiBmaWxsPSJub25lIiBzdHJva2Utb3BhY2l0eT0iMC4zOTIxNiIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2Utd2lkdGg9IjYiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTMxNC45MDkyOCwyMDIuNzU1OThjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1Yy0yLjgxMTUzLDIuODExNTMgLTcuMzY5OTIsMi44MTE1MyAtMTAuMTgxNDUsMGMtMi44MTE1MywtMi44MTE1MyAtMi44MTE1MywtNy4zNjk5MiAwLC0xMC4xODE0NXoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjM5MjE2IiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iNiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMzkyMTYiIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI2IiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjxwYXRoIGQ9Ik0zMTQuMzI4NSwyMDIuMTc1MmwtMTYuODMwOSwtMTYuODMwOSIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTMxOS43ODE4NywxNTIuMTUzM2wtMjIuNTAyNCwyMi41MDI0IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9IiNmZmZmZmYiIHN0cm9rZS13aWR0aD0iMy41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48cGF0aCBkPSJNMjg3LjA2MjU4LDE3NC45MDkyOGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzUyLjkzNzQyLDE4NS4wOTA3MmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzE0LjkwOTI4LDIwMi43NTU5OGMyLjgxMTUzLC0yLjgxMTUzIDcuMzY5OTIsLTIuODExNTMgMTAuMTgxNDUsMGMyLjgxMTUzLDIuODExNTMgMi44MTE1Myw3LjM2OTkyIDAsMTAuMTgxNDVjLTIuODExNTMsMi44MTE1MyAtNy4zNjk5MiwyLjgxMTUzIC0xMC4xODE0NSwwYy0yLjgxMTUzLC0yLjgxMTUzIC0yLjgxMTUzLC03LjM2OTkyIDAsLTEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMzI1LjA5MDcyLDE1Ny4yNDQwMmMtMi44MTE1MywyLjgxMTUzIC03LjM2OTkyLDIuODExNTMgLTEwLjE4MTQ1LDBjLTIuODExNTMsLTIuODExNTMgLTIuODExNTMsLTcuMzY5OTIgMCwtMTAuMTgxNDVjMi44MTE1MywtMi44MTE1MyA3LjM2OTkyLC0yLjgxMTUzIDEwLjE4MTQ1LDBjMi44MTE1MywyLjgxMTUzIDIuODExNTMsNy4zNjk5MiAwLDEwLjE4MTQ1eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjMuNSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMjc4LjEyNSwyMjEuODc1di04My43NWg4My43NXY4My43NXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIvPjwvZz48L2c+PC9zdmc+PCEtLXJvdGF0aW9uQ2VudGVyOjQxLjg3NTo0MS44NzUtLT4=", + color1: "#f06681", color2: "#d6516c", + blocks: [ - { - blockType: Scratch.BlockType.LABEL, - text: "By ZiploxZQS and OutsideFlight" - }, - - { - opcode: "createNode", - blockType: Scratch.BlockType.COMMAND, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "create node at x: [X] y: [Y] with an id of [ID]", - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 + { + blockType: Scratch.BlockType.LABEL, + text: "By ZiploxZQS and OutsideFlight" }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 + + // ========================= + // NODES + // ========================= + + { + opcode: "createNode", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "create node at x: [X] y: [Y] with an id of [ID]", + + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, - { - opcode: "deleteNode", - blockType: Scratch.BlockType.COMMAND, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "delete node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - disableMonitor: true - }, - { - opcode: "makeGrid", - blockType: Scratch.BlockType.COMMAND, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "make a grid from x: [X1] y: [Y1] to x: [X2] y: [Y2]", - arguments: { - X1: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: -1 - }, - Y1: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - }, - X2: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - }, - Y2: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: -1 - } - }, -}, + { - opcode: "clearNodes", - blockType: Scratch.BlockType.COMMAND, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "remove all nodes", - arguments: {}, -}, - { - opcode: "nodeExists", - blockType: Scratch.BlockType.BOOLEAN, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "node [ID] exists?", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, - { - opcode: "setNodePosition", - blockType: Scratch.BlockType.COMMAND, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "set node [ID] position x: [X] y: [Y]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + opcode: "deleteNode", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "delete node [ID]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } }, - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 + + { + opcode: "clearNodes", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "remove all nodes" }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 - } - }, - }, - { - opcode: "getNodeX", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "x of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, - { - opcode: "getNodeY", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "y of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, - { - opcode: "closestNode", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "node closest to x: [X] y: [Y]", - arguments: { - X: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 - }, - Y: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 0 - } - } -}, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, + { - opcode: "lowestNodeID", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "lowest node ID", - arguments: {} -}, -{ - opcode: "highestNodeID", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "highest node ID", - arguments: {} -}, + opcode: "makeGrid", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "make a grid from x: [X1] y: [Y1] to x: [X2] y: [Y2]", + + arguments: { + X1: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: -1 + }, + + Y1: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + X2: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + Y2: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: -1 + } + } + }, + { - opcode: "nodeCount", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "number of nodes", - arguments: {}, -}, - { - opcode: "allNodes", - blockType: Scratch.BlockType.REPORTER, - color1: NODE1, - color2: NODE2, - color3: NODE3, - text: "all nodes", - arguments: {}, - }, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, - { - blockType: Scratch.BlockType.LABEL, - text: "Links" - }, - { - opcode: "linkNodes", - blockType: Scratch.BlockType.COMMAND, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "link node [A] to node [B]", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + opcode: "nodeExists", + blockType: Scratch.BlockType.BOOLEAN, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "node [ID] exists?", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 - } - }, - }, - { - opcode: "unlinkNodes", - blockType: Scratch.BlockType.COMMAND, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "unlink node [A] from node [B]", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + + { + opcode: "setNodePosition", + blockType: Scratch.BlockType.COMMAND, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "set node [ID] position x: [X] y: [Y]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + } + } }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 - } - }, - }, + { - opcode: "unlinkAllNeighbors", - blockType: Scratch.BlockType.COMMAND, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "unlink all neighbors of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - } -}, + opcode: "getNodeX", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "x of node [ID]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + { - opcode: "connectNodesAnyWay", - blockType: Scratch.BlockType.COMMAND, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "connect nodes from the range [A] to [B] in any way possible", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 5 - } - }, -}, - { - opcode: "nodesLinked", - blockType: Scratch.BlockType.BOOLEAN, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "node [A] linked to node [B]?", - arguments: { - A: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 + opcode: "getNodeY", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "y of node [ID]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } }, - B: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 2 - } - }, - }, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, - { - opcode: "goDirection", - blockType: Scratch.BlockType.REPORTER, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "go [DIR] of node id [ID]", - arguments: { - DIR: { - type: Scratch.ArgumentType.STRING, - menu: "directions" + + { + opcode: "closestNode", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "node closest to x: [X] y: [Y]", + + arguments: { + X: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + }, + + Y: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 0 + } + } }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, - { - opcode: "getNeighbors", - blockType: Scratch.BlockType.REPORTER, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "neighbors of node [ID]", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, - }, + { - opcode: "linkCount", - blockType: Scratch.BlockType.REPORTER, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "node [ID] neighbor amount", - arguments: { - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, -}, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, + opcode: "lowestNodeID", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "lowest node ID" + }, + { - opcode: "linkedNode", - blockType: Scratch.BlockType.REPORTER, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "linked node #[INDEX] of node ID [ID]", - arguments: { - INDEX: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - }, - ID: { - type: Scratch.ArgumentType.NUMBER, - defaultValue: 1 - } - }, -}, - { - blockType: Scratch.BlockType.XML, - xml: `` - }, + opcode: "highestNodeID", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "highest node ID" + }, + { - opcode: "linkCountTotal", - blockType: Scratch.BlockType.REPORTER, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "number of links", - arguments: {}, -}, - { - opcode: "allLinks", - blockType: Scratch.BlockType.REPORTER, - hideFromPalette: false, - color1: LINK1, - color2: LINK2, - color3: LINK3, - text: "all links", - arguments: {}, - } - ], + opcode: "nodeCount", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "number of nodes" + }, + + { + opcode: "allNodes", + blockType: Scratch.BlockType.REPORTER, + color1: NODE1, + color2: NODE2, + color3: NODE3, + text: "all nodes" + }, + + // ========================= + // LINKS + // ========================= + + { + blockType: Scratch.BlockType.LABEL, + text: "Links" + }, + + { + opcode: "linkNodes", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "link node [A] to node [B]", + + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + } + }, + + { + opcode: "unlinkNodes", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "unlink node [A] from node [B]", + + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + } + }, + + { + opcode: "unlinkAllNeighbors", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "unlink all neighbors of node [ID]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + + { + opcode: "connectNodesAnyWay", + blockType: Scratch.BlockType.COMMAND, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "connect nodes from the range [A] to [B] in any way possible", + + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 5 + } + } + }, + + { + opcode: "nodesLinked", + blockType: Scratch.BlockType.BOOLEAN, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "node [A] linked to node [B]?", + + arguments: { + A: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + B: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 2 + } + } + }, + + { + opcode: "goDirection", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "go [DIR] of node id [ID]", + + arguments: { + DIR: { + type: Scratch.ArgumentType.STRING, + menu: "directions" + }, + + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + + { + opcode: "getNeighbors", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "neighbors of node [ID]", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + + { + opcode: "linkCount", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "node [ID] neighbor amount", + + arguments: { + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + + { + opcode: "linkedNode", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "linked node #[INDEX] of node ID [ID]", + + arguments: { + INDEX: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + }, + + ID: { + type: Scratch.ArgumentType.NUMBER, + defaultValue: 1 + } + } + }, + + { + opcode: "linkCountTotal", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "number of links" + }, + + { + opcode: "allLinks", + blockType: Scratch.BlockType.REPORTER, + color1: LINK1, + color2: LINK2, + color3: LINK3, + text: "all links" + } + ], + menus: { directions: { acceptReporters: true, + items: [ "right", "left", @@ -459,241 +527,356 @@ function getNodeNeighbors(id) { } }; } -createNode(args) { - const id = Scratch.Cast.toNumber(args.ID); - - nodes.set(id, { - id, - x: Scratch.Cast.toNumber(args.X), - y: Scratch.Cast.toNumber(args.Y) - }); -} -deleteNode(args) { - const id = Scratch.Cast.toNumber(args.ID); - - nodes.delete(id); - -links = links.filter(link => - link.from !== id && - link.to !== id -); -} -nodeExists(args) { - return nodes.has(Scratch.Cast.toNumber(args.ID)); -} + + createNode(args) { + const id = Scratch.Cast.toNumber(args.ID); + const x = Scratch.Cast.toNumber(args.X); + const y = Scratch.Cast.toNumber(args.Y); + + if (!Number.isFinite(id)) return; + if (!Number.isFinite(x)) return; + if (!Number.isFinite(y)) return; + + const existing = findNodeAt(x, y); + + // no stacking!!! + if (existing && existing.id !== id) { + return; + } + + // remove old links if replacing node + if (nodes.has(id)) { + links = links.filter( + l => + l.from !== id && + l.to !== id + ); + } + + nodes.set(id, { + id, + x, + y + }); + } + + deleteNode(args) { + const id = Scratch.Cast.toNumber(args.ID); + + nodes.delete(id); + + links = links.filter( + link => + link.from !== id && + link.to !== id + ); + } + + clearNodes() { + nodes.clear(); + links = []; + } + + nodeExists(args) { + return nodes.has( + Scratch.Cast.toNumber(args.ID) + ); + } + setNodePosition(args) { const node = getNode(args.ID); + if (!node) return; - node.x = Scratch.Cast.toNumber(args.X); - node.y = Scratch.Cast.toNumber(args.Y); + + const x = Scratch.Cast.toNumber(args.X); + const y = Scratch.Cast.toNumber(args.Y); + + if (!Number.isFinite(x)) return; + if (!Number.isFinite(y)) return; + + const existing = findNodeAt(x, y); + + // don't overlap nodes + if (existing && existing.id !== node.id) { + return; + } + + node.x = x; + node.y = y; } + getNodeX(args) { const node = getNode(args.ID); - if (!node) return 0; - return node.x; + + return node ? node.x : 0; } + getNodeY(args) { const node = getNode(args.ID); - if (!node) return 0; - return node.y; + + return node ? node.y : 0; } -getNeighbors(args) { - return JSON.stringify(getNodeNeighbors(args.ID)); -} -linkCount(args) { - return getNodeNeighbors(args.ID).length; -} - -linkedNode(args) { - const neighbors = getNodeNeighbors(args.ID); - - return ( - neighbors[ - Scratch.Cast.toNumber(args.INDEX) - 1 - ] ?? "" - ); -} -goDirection(args) { - const node = getNode(args.ID); - if (!node) return ""; - - let targetX = node.x; - let targetY = node.y; - - switch (String(args.DIR)) { - case "right": - targetX += 1; - break; - case "left": - targetX -= 1; - break; - case "up": - targetY += 1; - break; - case "down": - targetY -= 1; - break; - } - const target = [...nodes.values()].find( - n => n.x === targetX && n.y === targetY - ); + closestNode(args) { + const x = Scratch.Cast.toNumber(args.X); + const y = Scratch.Cast.toNumber(args.Y); + + let best = null; + let bestDist = Infinity; + + for (const node of nodes.values()) { + const dx = node.x - x; + const dy = node.y - y; + + const dist = dx * dx + dy * dy; + + if (dist < bestDist) { + bestDist = dist; + best = node; + } + } + + return best ? best.id : ""; + } + + lowestNodeID() { + if (nodes.size === 0) return ""; + + return Math.min(...nodes.keys()); + } + + highestNodeID() { + if (nodes.size === 0) return 0; + + return Math.max(...nodes.keys()); + } - if (!target) return ""; + nodeCount() { + return nodes.size; + } - // i uhhh forgot to add this back whoops - if (!linkExists(node.id, target.id)) return ""; + allNodes() { + return JSON.stringify([ + ...nodes.values() + ]); + } - return target.id; -} linkNodes(args) { const a = getNode(args.A); const b = getNode(args.B); + if (!a || !b) return; if (a.id === b.id) return; if (!areAdjacent(a, b)) return; if (linkExists(a.id, b.id)) return; + links.push({ from: a.id, to: b.id }); } - nodeCount() { - return nodes.size; -} - linkCountTotal() { - return links.length; -} -// its so fucking BUGGY aaaaarrrgghhhhh -connectNodesAnyWay(args) { - const A = Scratch.Cast.toNumber(args.A); - const B = Scratch.Cast.toNumber(args.B); - const minID = Math.min(A, B); - const maxID = Math.max(A, B); - - const nodesArr = [...nodes.values()]; + unlinkNodes(args) { + const a = Scratch.Cast.toNumber(args.A); + const b = Scratch.Cast.toNumber(args.B); - for (const node of nodesArr) { + links = links.filter( + l => + !( + (l.from === a && + l.to === b) || + (l.from === b && + l.to === a) + ) + ); + } - if (node.id < minID || node.id > maxID) continue; + unlinkAllNeighbors(args) { + const id = Scratch.Cast.toNumber(args.ID); + + links = links.filter( + l => + !( + l.from === id || + l.to === id + ) + ); + } - const directions = [ - { dx: 1, dy: 0 }, - { dx: -1, dy: 0 }, - { dx: 0, dy: 1 }, - { dx: 0, dy: -1 } - ]; + nodesLinked(args) { + return linkExists(args.A, args.B); + } - for (const dir of directions) { + connectNodesAnyWay(args) { + const A = Scratch.Cast.toNumber(args.A); + const B = Scratch.Cast.toNumber(args.B); + + const minID = Math.min(A, B); + const maxID = Math.max(A, B); + + const directions = [ + { dx: 1, dy: 0 }, + { dx: -1, dy: 0 }, + { dx: 0, dy: 1 }, + { dx: 0, dy: -1 } + ]; + + for (const node of nodes.values()) { + if ( + node.id < minID || + node.id > maxID + ) { + continue; + } - const nx = node.x + dir.dx; - const ny = node.y + dir.dy; + for (const dir of directions) { + const neighbor = findNodeAt( + node.x + dir.dx, + node.y + dir.dy + ); - const neighbor = nodesArr.find( - n => n.x === nx && n.y === ny - ); -//they find their lovers awwwww!!! - if (!neighbor) continue; + // they find their lovers awwwww!!! + if (!neighbor) continue; - if (neighbor.id < minID || neighbor.id > maxID) continue; + if ( + neighbor.id < minID || + neighbor.id > maxID + ) { + continue; + } - if (!linkExists(node.id, neighbor.id)) { - links.push({ - from: node.id, - to: neighbor.id - }); + if ( + neighbor.id !== node.id && + !linkExists( + node.id, + neighbor.id + ) + ) { + links.push({ + from: node.id, + to: neighbor.id + }); + } + } } } - } -} -makeGrid(args) { - const x1 = Scratch.Cast.toNumber(args.X1); - const y1 = Scratch.Cast.toNumber(args.Y1); - const x2 = Scratch.Cast.toNumber(args.X2); - const y2 = Scratch.Cast.toNumber(args.Y2); - const minX = Math.min(x1, x2); - const maxX = Math.max(x1, x2); - const minY = Math.min(y1, y2); - const maxY = Math.max(y1, y2); + getNeighbors(args) { + return JSON.stringify( + getNodeNeighbors(args.ID) + ); + } + + linkCount(args) { + return getNodeNeighbors(args.ID).length; + } - let id = 1; + linkedNode(args) { + const neighbors = + getNodeNeighbors(args.ID); - for (let y = maxY; y >= minY; y--) { - for (let x = minX; x <= maxX; x++) { + const index = + Math.floor( + Scratch.Cast.toNumber(args.INDEX) + ) - 1; - nodes.set(id, { - id, - x, - y - }); + if (index < 0) return ""; - id++; + return neighbors[index] ?? ""; } - } -} - unlinkNodes(args) { - const a = Scratch.Cast.toNumber(args.A); - const b = Scratch.Cast.toNumber(args.B); - links = links.filter(l => - !( - (l.from === a && l.to === b) || - (l.from === b && l.to === a) - ) -); + + goDirection(args) { + const node = getNode(args.ID); + + if (!node) return ""; + + let targetX = node.x; + let targetY = node.y; + + switch ( + String(args.DIR).toLowerCase() + ) { + case "right": + targetX += 1; + break; + + case "left": + targetX -= 1; + break; + + case "up": + targetY += 1; + break; + + case "down": + targetY -= 1; + break; + + default: + return ""; + } + + const target = findNodeAt( + targetX, + targetY + ); + + if (!target) return ""; + + if ( + !linkExists(node.id, target.id) + ) { + return ""; + } + + return target.id; } - nodesLinked(args) { - return linkExists(args.A, args.B); + + linkCountTotal() { + return links.length; } -allNodes() { - return JSON.stringify( - [...nodes.values()] - ); -} + allLinks() { return JSON.stringify(links); } - clearNodes() { - nodes.clear(); - links = []; -} - closestNode(args) { - const x = Scratch.Cast.toNumber(args.X); - const y = Scratch.Cast.toNumber(args.Y); - let best = null; - let bestDist = Infinity; + makeGrid(args) { + const x1 = Scratch.Cast.toNumber(args.X1); + const y1 = Scratch.Cast.toNumber(args.Y1); + const x2 = Scratch.Cast.toNumber(args.X2); + const y2 = Scratch.Cast.toNumber(args.Y2); + + const minX = Math.min(x1, x2); + const maxX = Math.max(x1, x2); + + const minY = Math.min(y1, y2); + const maxY = Math.max(y1, y2); + + let id = this.highestNodeID() + 1; - for (const node of nodes.values()) { - const dx = node.x - x; - const dy = node.y - y; - const dist = dx * dx + dy * dy; // this might be useful since i dont want to keep changing the value when the grid is in the middle + for (let y = maxY; y >= minY; y--) { + for ( + let x = minX; + x <= maxX; + x++ + ) { + if (findNodeAt(x, y)) { + continue; + } + + nodes.set(id, { + id, + x, + y + }); - if (dist < bestDist) { - bestDist = dist; - best = node; + id++; + } + } } } - return best ? best.id : ""; -} -lowestNodeID() { - if (nodes.size === 0) return ""; - return Math.min(...nodes.keys()); -} - -highestNodeID() { - if (nodes.size === 0) return ""; - return Math.max(...nodes.keys()); -} - unlinkAllNeighbors(args) { - const id = Scratch.Cast.toNumber(args.ID); - - links = links.filter(l => - !(l.from === id || l.to === id) + Scratch.extensions.register( + new NodeSystem() ); -} - } - Scratch.extensions.register(new NodeSystem()); })(Scratch); From bb78f26d70d24cbe99a19f79a738b67803e6b3e2 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 20:29:09 -0400 Subject: [PATCH 48/54] Fix comment formatting in extensions.js --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 9660a774b..70a0323e1 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -1,4 +1,4 @@ -,/* +/* note to contributors & developers that can read JSON: the extra commas are added at the end of each thing to help copy & pasting work better From 25a08bb53b363e61a8471310e73ebd685510a587 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:27:01 -0400 Subject: [PATCH 49/54] Update node colors and remove comments --- static/extensions/ZiploxWasTaken/nodes.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/static/extensions/ZiploxWasTaken/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js index e8929a78e..a7f7bd7a4 100644 --- a/static/extensions/ZiploxWasTaken/nodes.js +++ b/static/extensions/ZiploxWasTaken/nodes.js @@ -84,20 +84,15 @@ return { id: "ziploxnodesystem", name: "Nodes", - - color1: "#f06681", - color2: "#d6516c", + menuIconURI: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI5Ny41IiBoZWlnaHQ9Ijk3LjUiIHZpZXdCb3g9IjAsMCw5Ny41LDk3LjUiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xOTEuMjUsLTEzMS4yNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIyMi4yOTI4NSwyMDEuNDQwOGMyLjU3NzI5LDAuNDkxMzEgMy42OTgzOSwxLjY5ODM3IDUuMTY3NjUsMy44MDQzMWMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMwLjczODYxLC0yLjIxNTgxIDEuMzU4MzEsLTMuMDIxOCAzLjMwOTAzLC00LjM1Mzk5YzIuNDAxMywtMC40NDIxMyA0LjU2Njc2LC0wLjQ1NzQ0IDYuOTY2MzksMGMyLjE3Njk5LDEuNjEwOTggMi4xNzY5OSwxLjYxMDk4IDMuNDgzMiwzLjQ4MzJjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2YzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzEuNDczOTUsLTQuNDIxODUgNC4zNDE3LC00LjgzODI5IDguNTkwOTcsLTQuNjc1MXpNMjE3LjAxMDkxLDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTIzNi41MTY4LDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTI1Ni4wMjI3LDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTIyMi4yOTI4NSwxNDguNDk2MjNjMi41NzcyOSwwLjQ5MTMxIDMuNjk4MzksMS42OTgzNyA1LjE2NzY1LDMuODA0MzFjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMxLjQ3Mzk1LC00LjQyMTg1IDQuMzQxNywtNC44MzgyOSA4LjU5MDk3LC00LjY3NTF6TTIxNy4wMTA5MSwxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yMzYuNTE2OCwxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yNTYuMDIyNywxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yODAuNDA1MDYsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yNzQuODMxOTUsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yMDIuMzgxNDksMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0xOTYuODA4MzgsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yODAuNDA1MDYsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yNzQuODMxOTUsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yMDIuMzgxNDksMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0xOTYuODA4MzgsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMjMxMzciIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI1Ii8+PGcgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiPjxwYXRoIGQ9Ik0yMjIuMjkyODUsMjAxLjQ0MDhjMi41NzcyOSwwLjQ5MTMxIDMuNjk4MzksMS42OTgzNyA1LjE2NzY1LDMuODA0MzFjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMxLjQ3Mzk1LC00LjQyMTg1IDQuMzQxNywtNC44MzgyOSA4LjU5MDk3LC00LjY3NTF6TTIxNy4wMTA5MSwyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yMzYuNTE2OCwyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yNTYuMDIyNywyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0eiIvPjxwYXRoIGQ9Ik0yMjIuMjkyODUsMTQ4LjQ5NjIzYzIuNTc3MjksMC40OTEzMSAzLjY5ODM5LDEuNjk4MzcgNS4xNjc2NSwzLjgwNDMxYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMwLjczODYxLC0yLjIxNTgxIDEuMzU4MzEsLTMuMDIxOCAzLjMwOTAzLC00LjM1Mzk5YzIuNDAxMywtMC40NDIxMyA0LjU2Njc2LC0wLjQ1NzQ0IDYuOTY2MzksMGMyLjE3Njk5LDEuNjEwOTggMi4xNzY5OSwxLjYxMDk4IDMuNDgzMiwzLjQ4MzJjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMCwwLjkxOTU2IDAsMS44MzkxMyAwLDIuNzg2NTZjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjMCwtMC45MTk1NiAwLC0xLjgzOTEzIDAsLTIuNzg2NTZjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMS40NzM5NSwtNC40MjE4NSA0LjM0MTcsLTQuODM4MjkgOC41OTA5NywtNC42NzUxek0yMTcuMDEwOTEsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHpNMjM2LjUxNjgsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHpNMjU2LjAyMjcsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHoiLz48cGF0aCBkPSJNMjgwLjQwNTA2LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjc0LjgzMTk1LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjAyLjM4MTQ5LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMTk2LjgwODM4LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjgwLjQwNTA2LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjc0LjgzMTk1LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjAyLjM4MTQ5LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMTk2LjgwODM4LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48L2c+PHBhdGggZD0iTTE5MS4yNSwyMjguNzV2LTk3LjVoOTcuNXY5Ny41eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjAiLz48L2c+PC9nPjwvc3ZnPjwhLS1yb3RhdGlvbkNlbnRlcjo0OC43NTAwMDAwMDAwMDAwMzo0OC43NS0tPg==", + color1: NODE1, + color2: NODE2, blocks: [ { blockType: Scratch.BlockType.LABEL, text: "By ZiploxZQS and OutsideFlight" }, - - // ========================= - // NODES - // ========================= - { opcode: "createNode", blockType: Scratch.BlockType.COMMAND, @@ -310,11 +305,6 @@ color3: NODE3, text: "all nodes" }, - - // ========================= - // LINKS - // ========================= - { blockType: Scratch.BlockType.LABEL, text: "Links" From 2b9be24dd697217897d3b4856b2c7b9ee330b26c Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:28:08 -0400 Subject: [PATCH 50/54] Update banner image for node system --- src/lib/extensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/extensions.js b/src/lib/extensions.js index 70a0323e1..87f718361 100644 --- a/src/lib/extensions.js +++ b/src/lib/extensions.js @@ -26,7 +26,7 @@ export default [ tags: ["new"], code: "ZiploxWasTaken/nodes.js", documentation: "nodesystems", - banner: "ZiploxWasTaken/Nodes.svg", + banner: "ZiploxWasTaken/Nodes NEW!.svg", isGitHub: true, creator: "ZiploxWasTaken", }, From 88927c7bd5b9aa65917d1ff629a2fbaf7a4b0474 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:28:53 -0400 Subject: [PATCH 51/54] Update print statement from 'Hello' to 'Goodbye' --- static/images/ZiploxWasTaken/Nodes New!.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 static/images/ZiploxWasTaken/Nodes New!.svg diff --git a/static/images/ZiploxWasTaken/Nodes New!.svg b/static/images/ZiploxWasTaken/Nodes New!.svg new file mode 100644 index 000000000..f27441166 --- /dev/null +++ b/static/images/ZiploxWasTaken/Nodes New!.svg @@ -0,0 +1 @@ + From 3b89d92ae159c3897ab7af0de7f799235d325e49 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:30:45 -0400 Subject: [PATCH 52/54] Update block text to include update notice --- static/extensions/ZiploxWasTaken/nodes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/extensions/ZiploxWasTaken/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js index a7f7bd7a4..95e0fd594 100644 --- a/static/extensions/ZiploxWasTaken/nodes.js +++ b/static/extensions/ZiploxWasTaken/nodes.js @@ -91,7 +91,7 @@ blocks: [ { blockType: Scratch.BlockType.LABEL, - text: "By ZiploxZQS and OutsideFlight" + text: "By ZiploxZQS and OutsideFlight, may be updated later" }, { opcode: "createNode", From 57afa485711260485c2e4f4b7f8f216ad48804a9 Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:47:24 -0400 Subject: [PATCH 53/54] Update print statement from 'Hello' to 'Goodbye' --- static/extensions/ZiploxWasTaken/nodes.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/extensions/ZiploxWasTaken/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js index 95e0fd594..89195d7cb 100644 --- a/static/extensions/ZiploxWasTaken/nodes.js +++ b/static/extensions/ZiploxWasTaken/nodes.js @@ -84,7 +84,8 @@ return { id: "ziploxnodesystem", name: "Nodes", - menuIconURI: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI5Ny41IiBoZWlnaHQ9Ijk3LjUiIHZpZXdCb3g9IjAsMCw5Ny41LDk3LjUiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xOTEuMjUsLTEzMS4yNSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIyMi4yOTI4NSwyMDEuNDQwOGMyLjU3NzI5LDAuNDkxMzEgMy42OTgzOSwxLjY5ODM3IDUuMTY3NjUsMy44MDQzMWMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMwLjczODYxLC0yLjIxNTgxIDEuMzU4MzEsLTMuMDIxOCAzLjMwOTAzLC00LjM1Mzk5YzIuNDAxMywtMC40NDIxMyA0LjU2Njc2LC0wLjQ1NzQ0IDYuOTY2MzksMGMyLjE3Njk5LDEuNjEwOTggMi4xNzY5OSwxLjYxMDk4IDMuNDgzMiwzLjQ4MzJjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2YzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzEuNDczOTUsLTQuNDIxODUgNC4zNDE3LC00LjgzODI5IDguNTkwOTcsLTQuNjc1MXpNMjE3LjAxMDkxLDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTIzNi41MTY4LDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTI1Ni4wMjI3LDIwNi42MzgzOGMtMC4yMzIyMSwyLjA4OTkyIC0wLjIzMjIxLDIuMDg5OTIgMCw0LjE3OTg0YzEuMzEzMTcsMS42MTMxNiAxLjMxMzE3LDEuNjEzMTYgMy40ODMyLDEuNTY3NDRjMi4xNzAwMywwLjA0NTcyIDIuMTcwMDMsMC4wNDU3MiAzLjQ4MzIsLTEuNTY3NDRjMC4yMzIyMSwtMi4wODk5MiAwLjIzMjIxLC0yLjA4OTkyIDAsLTQuMTc5ODRjLTEuMzEzMTcsLTEuNjEzMTYgLTEuMzEzMTcsLTEuNjEzMTYgLTMuNDgzMiwtMS41Njc0NGMtMi4xNzAwMywtMC4wNDU3MiAtMi4xNzAwMywtMC4wNDU3MiAtMy40ODMyLDEuNTY3NDR6TTIyMi4yOTI4NSwxNDguNDk2MjNjMi41NzcyOSwwLjQ5MTMxIDMuNjk4MzksMS42OTgzNyA1LjE2NzY1LDMuODA0MzFjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMxLjQ3Mzk1LC00LjQyMTg1IDQuMzQxNywtNC44MzgyOSA4LjU5MDk3LC00LjY3NTF6TTIxNy4wMTA5MSwxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yMzYuNTE2OCwxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yNTYuMDIyNywxNTMuNjkzODFjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yODAuNDA1MDYsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yNzQuODMxOTUsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yMDIuMzgxNDksMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0xOTYuODA4MzgsMjA3LjMzNTAyYzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yODAuNDA1MDYsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yNzQuODMxOTUsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0yMDIuMzgxNDksMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2ek0xOTYuODA4MzgsMTU0LjM5MDQ1YzAuOTE5NTYsMCAxLjgzOTEzLDAgMi43ODY1NiwwYzAsMC45MTk1NiAwLDEuODM5MTMgMCwyLjc4NjU2Yy0wLjkxOTU2LDAgLTEuODM5MTMsMCAtMi43ODY1NiwwYzAsLTAuOTE5NTYgMCwtMS44MzkxMyAwLC0yLjc4NjU2eiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlLW9wYWNpdHk9IjAuMjMxMzciIHN0cm9rZT0iIzAwMDAwMCIgc3Ryb2tlLXdpZHRoPSI1Ii8+PGcgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiPjxwYXRoIGQ9Ik0yMjIuMjkyODUsMjAxLjQ0MDhjMi41NzcyOSwwLjQ5MTMxIDMuNjk4MzksMS42OTgzNyA1LjE2NzY1LDMuODA0MzFjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMC43Mzg2MSwtMi4yMTU4MSAxLjM1ODMxLC0zLjAyMTggMy4zMDkwMywtNC4zNTM5OWMyLjQwMTMsLTAuNDQyMTMgNC41NjY3NiwtMC40NTc0NCA2Ljk2NjM5LDBjMi4xNzY5OSwxLjYxMDk4IDIuMTc2OTksMS42MTA5OCAzLjQ4MzIsMy40ODMyYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMxLjQ3Mzk1LC00LjQyMTg1IDQuMzQxNywtNC44MzgyOSA4LjU5MDk3LC00LjY3NTF6TTIxNy4wMTA5MSwyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yMzYuNTE2OCwyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0ek0yNTYuMDIyNywyMDYuNjM4MzhjLTAuMjMyMjEsMi4wODk5MiAtMC4yMzIyMSwyLjA4OTkyIDAsNC4xNzk4NGMxLjMxMzE3LDEuNjEzMTYgMS4zMTMxNywxLjYxMzE2IDMuNDgzMiwxLjU2NzQ0YzIuMTcwMDMsMC4wNDU3MiAyLjE3MDAzLDAuMDQ1NzIgMy40ODMyLC0xLjU2NzQ0YzAuMjMyMjEsLTIuMDg5OTIgMC4yMzIyMSwtMi4wODk5MiAwLC00LjE3OTg0Yy0xLjMxMzE3LC0xLjYxMzE2IC0xLjMxMzE3LC0xLjYxMzE2IC0zLjQ4MzIsLTEuNTY3NDRjLTIuMTcwMDMsLTAuMDQ1NzIgLTIuMTcwMDMsLTAuMDQ1NzIgLTMuNDgzMiwxLjU2NzQ0eiIvPjxwYXRoIGQ9Ik0yMjIuMjkyODUsMTQ4LjQ5NjIzYzIuNTc3MjksMC40OTEzMSAzLjY5ODM5LDEuNjk4MzcgNS4xNjc2NSwzLjgwNDMxYzAsMC42ODk2NyAwLDEuMzc5MzUgMCwyLjA4OTkyYzEuODM5MTMsMCAzLjY3ODI1LDAgNS41NzMxMSwwYzAuMDU3NDcsLTAuNDAyMzEgMC4xMTQ5NSwtMC44MDQ2MiAwLjE3NDE2LC0xLjIxOTEyYzAuNzM4NjEsLTIuMjE1ODEgMS4zNTgzMSwtMy4wMjE4IDMuMzA5MDMsLTQuMzUzOTljMi40MDEzLC0wLjQ0MjEzIDQuNTY2NzYsLTAuNDU3NDQgNi45NjYzOSwwYzIuMTc2OTksMS42MTA5OCAyLjE3Njk5LDEuNjEwOTggMy40ODMyLDMuNDgzMmMwLDAuNjg5NjcgMCwxLjM3OTM1IDAsMi4wODk5MmMxLjgzOTEzLDAgMy42NzgyNSwwIDUuNTczMTEsMGMwLjA1NzQ3LC0wLjQwMjMxIDAuMTE0OTUsLTAuODA0NjIgMC4xNzQxNiwtMS4yMTkxMmMwLjczODYxLC0yLjIxNTgxIDEuMzU4MzEsLTMuMDIxOCAzLjMwOTAzLC00LjM1Mzk5YzIuNDAxMywtMC40NDIxMyA0LjU2Njc2LC0wLjQ1NzQ0IDYuOTY2MzksMGMyLjE3Njk5LDEuNjEwOTggMi4xNzY5OSwxLjYxMDk4IDMuNDgzMiwzLjQ4MzJjMCwwLjY4OTY3IDAsMS4zNzkzNSAwLDIuMDg5OTJjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMCwwLjkxOTU2IDAsMS44MzkxMyAwLDIuNzg2NTZjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjLTAuMDU3NDcsMC40MDIzMSAtMC4xMTQ5NSwwLjgwNDYyIC0wLjE3NDE2LDEuMjE5MTJjLTAuNzM4NjEsMi4yMTU4MSAtMS4zNTgzMSwzLjAyMTggLTMuMzA5MDMsNC4zNTM5OWMtMi40MDEzLDAuNDQyMTMgLTQuNTY2NzYsMC40NTc0NCAtNi45NjYzOSwwYy0yLjE3Njk5LC0xLjYxMDk4IC0yLjE3Njk5LC0xLjYxMDk4IC0zLjQ4MzIsLTMuNDgzMmMwLC0wLjY4OTY3IDAsLTEuMzc5MzUgMCwtMi4wODk5MmMtMS44MzkxMywwIC0zLjY3ODI1LDAgLTUuNTczMTEsMGMtMC4wNTc0NywwLjQwMjMxIC0wLjExNDk1LDAuODA0NjIgLTAuMTc0MTYsMS4yMTkxMmMtMC43Mzg2MSwyLjIxNTgxIC0xLjM1ODMxLDMuMDIxOCAtMy4zMDkwMyw0LjM1Mzk5Yy0yLjQwMTMsMC40NDIxMyAtNC41NjY3NiwwLjQ1NzQ0IC02Ljk2NjM5LDBjLTIuMTc2OTksLTEuNjEwOTggLTIuMTc2OTksLTEuNjEwOTggLTMuNDgzMiwtMy40ODMyYzAsLTAuNjg5NjcgMCwtMS4zNzkzNSAwLC0yLjA4OTkyYy0xLjgzOTEzLDAgLTMuNjc4MjUsMCAtNS41NzMxMSwwYy0wLjA1NzQ3LDAuNDAyMzEgLTAuMTE0OTUsMC44MDQ2MiAtMC4xNzQxNiwxLjIxOTEyYy0wLjczODYxLDIuMjE1ODEgLTEuMzU4MzEsMy4wMjE4IC0zLjMwOTAzLDQuMzUzOTljLTIuNDAxMywwLjQ0MjEzIC00LjU2Njc2LDAuNDU3NDQgLTYuOTY2MzksMGMtMi4xNzY5OSwtMS42MTA5OCAtMi4xNzY5OSwtMS42MTA5OCAtMy40ODMyLC0zLjQ4MzJjMCwtMC42ODk2NyAwLC0xLjM3OTM1IDAsLTIuMDg5OTJjLTEuODM5MTMsMCAtMy42NzgyNSwwIC01LjU3MzExLDBjMCwtMC45MTk1NiAwLC0xLjgzOTEzIDAsLTIuNzg2NTZjMS44MzkxMywwIDMuNjc4MjUsMCA1LjU3MzExLDBjMC4wNTc0NywtMC40MDIzMSAwLjExNDk1LC0wLjgwNDYyIDAuMTc0MTYsLTEuMjE5MTJjMS40NzM5NSwtNC40MjE4NSA0LjM0MTcsLTQuODM4MjkgOC41OTA5NywtNC42NzUxek0yMTcuMDEwOTEsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHpNMjM2LjUxNjgsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHpNMjU2LjAyMjcsMTUzLjY5MzgxYy0wLjIzMjIxLDIuMDg5OTIgLTAuMjMyMjEsMi4wODk5MiAwLDQuMTc5ODRjMS4zMTMxNywxLjYxMzE2IDEuMzEzMTcsMS42MTMxNiAzLjQ4MzIsMS41Njc0NGMyLjE3MDAzLDAuMDQ1NzIgMi4xNzAwMywwLjA0NTcyIDMuNDgzMiwtMS41Njc0NGMwLjIzMjIxLC0yLjA4OTkyIDAuMjMyMjEsLTIuMDg5OTIgMCwtNC4xNzk4NGMtMS4zMTMxNywtMS42MTMxNiAtMS4zMTMxNywtMS42MTMxNiAtMy40ODMyLC0xLjU2NzQ0Yy0yLjE3MDAzLC0wLjA0NTcyIC0yLjE3MDAzLC0wLjA0NTcyIC0zLjQ4MzIsMS41Njc0NHoiLz48cGF0aCBkPSJNMjgwLjQwNTA2LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjc0LjgzMTk1LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjAyLjM4MTQ5LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMTk2LjgwODM4LDIwNy4zMzUwMmMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjgwLjQwNTA2LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjc0LjgzMTk1LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMjAyLjM4MTQ5LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48cGF0aCBkPSJNMTk2LjgwODM4LDE1NC4zOTA0NWMwLjkxOTU2LDAgMS44MzkxMywwIDIuNzg2NTYsMGMwLDAuOTE5NTYgMCwxLjgzOTEzIDAsMi43ODY1NmMtMC45MTk1NiwwIC0xLjgzOTEzLDAgLTIuNzg2NTYsMGMwLC0wLjkxOTU2IDAsLTEuODM5MTMgMCwtMi43ODY1NnoiLz48L2c+PHBhdGggZD0iTTE5MS4yNSwyMjguNzV2LTk3LjVoOTcuNXY5Ny41eiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjAiLz48L2c+PC9nPjwvc3ZnPjwhLS1yb3RhdGlvbkNlbnRlcjo0OC43NTAwMDAwMDAwMDAwMzo0OC43NS0tPg==", + menuIconURI: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMC40MTY2NiIgaGVpZ2h0PSIzMC40MTY2NiIgdmlld0JveD0iMCwwLDMwLjQxNjY2LDMwLjQxNjY2Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMjIzLjgxNzM3LC0xNTIuNTE2NTgpIj48ZyBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiPjxwYXRoIGQ9Ik0yMjQuMTkyMzcsMTY3LjcyNDkxYzAsLTguMTkyMjIgNi42NDExMSwtMTQuODMzMzMgMTQuODMzMzMsLTE0LjgzMzMzYzguMTkyMjIsMCAxNC44MzMzMyw2LjY0MTExIDE0LjgzMzMzLDE0LjgzMzMzYzAsOC4xOTIyMiAtNi42NDExMSwxNC44MzMzMyAtMTQuODMzMzMsMTQuODMzMzNjLTguMTkyMjIsMCAtMTQuODMzMzMsLTYuNjQxMTEgLTE0LjgzMzMzLC0xNC44MzMzM3oiIGZpbGw9IiM1NmFkNTciIHN0cm9rZT0iIzI1NmUzNSIgc3Ryb2tlLXdpZHRoPSIwLjUiLz48cGF0aCBkPSJNMjQ5LjUxNDQ1LDE1Ny4yMzYxNmM1Ljc5Mjc4LDUuNzkyNzggNS43OTI3OCwxNS4xODQ3MiAwLDIwLjk3NzVjLTUuNzkyNzgsNS43OTI3OCAtMTUuMTg0NzMsNS43OTI3OCAtMjAuOTc3NSwwYy0wLjA0MDUxLC0wLjA0MDUxIDIwLjkxMzY1LC0yMS4wNDEzNSAyMC45Nzc1LC0yMC45Nzc1eiIgZmlsbD0iIzJmODI0MiIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjI0LjE5MjM3LDE2Ny43MjQ5MWMwLC04LjE5MjIyIDYuNjQxMTEsLTE0LjgzMzMzIDE0LjgzMzMzLC0xNC44MzMzM2M4LjE5MjIyLDAgMTQuODMzMzMsNi42NDExMSAxNC44MzMzMywxNC44MzMzM2MwLDguMTkyMjIgLTYuNjQxMTEsMTQuODMzMzMgLTE0LjgzMzMzLDE0LjgzMzMzYy04LjE5MjIyLDAgLTE0LjgzMzMzLC02LjY0MTExIC0xNC44MzMzMywtMTQuODMzMzN6IiBmaWxsPSJub25lIiBzdHJva2U9IiMzNDgyMzUiIHN0cm9rZS13aWR0aD0iMC43NSIvPjxwYXRoIGQ9Ik0yNDkuNTE0NDMsMTU3LjIzNjE0YzEuMzY2MjgsMS4zNjYyOCAyLjQ2NzI3LDIuOTk3ODUgMy4yMTkwNyw0LjgxMDgxYzEuNTAwNzEsMy42MjcxMSAxLjUwMDcxLDcuNzI4OCAwLDExLjM1NTkxYy0xLjUwMzU5LDMuNjI1OTEgLTQuNDAzOTMsNi41MjYyNSAtOC4wMjk4NCw4LjAyOTg0Yy0zLjYyNzEsMS41MDA3MSAtNy43Mjg4LDEuNTAwNzEgLTExLjM1NTkxLDBjLTEuODEyOTYsLTAuNzUxNzkgLTMuNDQ0NTMsLTEuODUyNzggLTQuODEwODEsLTMuMjE5MDYiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFjNTcyOSIgc3Ryb2tlLXdpZHRoPSIwLjc1Ii8+PHBhdGggZD0iTTIzMS40NzUyMywxNzAuODcyNTJjMC45MjY5NywtMC42MzAxMyAxLjYzMDI3LC0wLjYwNDE3IDIuNzEwMjcsLTAuNDExODRjMC4yMDgzNCwwLjIwODM0IDAuNDE2NjcsMC40MTY2NyAwLjYzMTMzLDAuNjMxMzNjMC41NTU1NywtMC41NTU1NyAxLjExMTE0LC0xLjExMTE0IDEuNjgzNTUsLTEuNjgzNTVjLTAuMTA0MTcsLTAuMTM4ODkgLTAuMjA4MzQsLTAuMjc3NzggLTAuMzE1NjYsLTAuNDIwODhjLTAuNDQ2MjQsLTAuODkyNDggLTAuNTAyNTIsLTEuMzIzMTYgLTAuMzE1NjcsLTIuMzE0ODhjMC41OTE4MywtMC44NTg5NSAxLjI0MTM2LC0xLjUxNzczIDIuMTA0NDQsLTIuMTA0NDNjMS4xNDQyOCwtMC4xNzA5OSAxLjE0NDI3LC0wLjE3MDk5IDIuMTA0NDIsMGMwLjIwODM0LDAuMjA4MzQgMC40MTY2NywwLjQxNjY3IDAuNjMxMzMsMC42MzEzM2MwLjU1NTU3LC0wLjU1NTU3IDEuMTExMTQsLTEuMTExMTQgMS42ODM1NSwtMS42ODM1NWMtMC4xMDQxNywtMC4xMzg4OSAtMC4yMDgzMywtMC4yNzc3NyAtMC4zMTU2NiwtMC40MjA4OGMtMC40NDYyNCwtMC44OTI0OCAtMC41MDI1MSwtMS4zMjMxNiAtMC4zMTU2NiwtMi4zMTQ4OGMwLjU5MTgzLC0wLjg1ODk1IDEuMjQxMzYsLTEuNTE3NzMgMi4xMDQ0MywtMi4xMDQ0M2MxLjE0NDI4LC0wLjE3MDk5IDEuMTQ0MjcsLTAuMTcwOTkgMi4xMDQ0MiwwYzAuMjA4MzQsMC4yMDgzNCAwLjQxNjY4LDAuNDE2NjcgMC42MzEzMywwLjYzMTMzYzAuNTU1NTcsLTAuNTU1NTcgMS4xMTExNCwtMS4xMTExNCAxLjY4MzU0LC0xLjY4MzU1YzAuMjc3NzgsMC4yNzc3OCAwLjU1NTU4LDAuNTU1NTggMC44NDE3OCwwLjg0MTc4Yy0wLjU1NTU3LDAuNTU1NTcgLTEuMTExMTQsMS4xMTExNCAtMS42ODM1NSwxLjY4MzU1YzAuMTA0MTcsMC4xMzg4OSAwLjIwODM0LDAuMjc3NzcgMC4zMTU2NiwwLjQyMDg4YzAuNDQ2MjQsMC44OTI0OCAwLjUwMjUyLDEuMzIzMTYgMC4zMTU2NywyLjMxNDg4Yy0wLjU5MTgzLDAuODU4OTUgLTEuMjQxMzUsMS41MTc3MyAtMi4xMDQ0MywyLjEwNDQ0Yy0xLjE0NDI4LDAuMTcwOTkgLTEuMTQ0MjgsMC4xNzA5OSAtMi4xMDQ0MywwYy0wLjIwODM0LC0wLjIwODM0IC0wLjQxNjY3LC0wLjQxNjY4IC0wLjYzMTMzLC0wLjYzMTMzYy0wLjU1NTU3LDAuNTU1NTcgLTEuMTExMTQsMS4xMTExNCAtMS42ODM1NSwxLjY4MzU1YzAuMTA0MTcsMC4xMzg4OSAwLjIwODM0LDAuMjc3NzggMC4zMTU2NiwwLjQyMDg4YzAuNDQ2MjQsMC44OTI0OCAwLjUwMjUxLDEuMzIzMTYgMC4zMTU2NiwyLjMxNDg4Yy0wLjU5MTgzLDAuODU4OTUgLTEuMjQxMzUsMS41MTc3MyAtMi4xMDQ0MiwyLjEwNDQzYy0xLjE0NDI4LDAuMTcwOTkgLTEuMTQ0MjgsMC4xNzA5OSAtMi4xMDQ0MywwYy0wLjIwODM0LC0wLjIwODM0IC0wLjQxNjY4LC0wLjQxNjY3IC0wLjYzMTMzLC0wLjYzMTMzYy0wLjU1NTU3LDAuNTU1NTcgLTEuMTExMTQsMS4xMTExNCAtMS42ODM1NCwxLjY4MzU1YzAuMTA0MTcsMC4xMzg4OSAwLjIwODM0LDAuMjc3NzcgMC4zMTU2NiwwLjQyMDg4YzAuNDQ2MjQsMC44OTI0OCAwLjUwMjUxLDEuMzIzMTYgMC4zMTU2NiwyLjMxNDg4Yy0wLjU5MTgzLDAuODU4OTUgLTEuMjQxMzUsMS41MTc3MyAtMi4xMDQ0MywyLjEwNDQzYy0xLjE0NDI4LDAuMTcwOTkgLTEuMTQ0MjgsMC4xNzA5OSAtMi4xMDQ0MywwYy0wLjIwODM0LC0wLjIwODM0IC0wLjQxNjY3LC0wLjQxNjY3IC0wLjYzMTMzLC0wLjYzMTMzYy0wLjU1NTU3LDAuNTU1NTcgLTEuMTExMTQsMS4xMTExNCAtMS42ODM1NSwxLjY4MzU1Yy0wLjI3Nzc4LC0wLjI3Nzc4IC0wLjU1NTU3LC0wLjU1NTU4IC0wLjg0MTc3LC0wLjg0MTc4YzAuNTU1NTcsLTAuNTU1NTcgMS4xMTExMywtMS4xMTExNCAxLjY4MzU0LC0xLjY4MzU1Yy0wLjEwNDE3LC0wLjEzODg5IC0wLjIwODM0LC0wLjI3Nzc3IC0wLjMxNTY2LC0wLjQyMDg4Yy0wLjg5MDUxLC0xLjc4MTAyIC0wLjE1LC0yLjc3MzEzIDEuMTgyOTMsLTQuMDA3NDd6TTIzMS40NDk3NCwxNzQuMDM4MjFjMC41NjExOCwwLjcwMTQ3IDAuNTYxMTksMC43MDE0OCAxLjI2MjY2LDEuMjYyNjZjMC44ODM5OSwwLjA5MDYyIDAuODgzOTgsMC4wOTA2MiAxLjUyNTcxLC0wLjU3ODcyYzAuNjY5MzQsLTAuNjQxNzMgMC42NjkzNCwtMC42NDE3MiAwLjU3ODcyLC0xLjUyNTcxYy0wLjU2MTE4LC0wLjcwMTQ3IC0wLjU2MTE5LC0wLjcwMTQ4IC0xLjI2MjY2LC0xLjI2MjY2Yy0wLjg4Mzk5LC0wLjA5MDYyIC0wLjg4Mzk4LC0wLjA5MDYyIC0xLjUyNTcxLDAuNTc4NzJjLTAuNjY5MzQsMC42NDE3MyAtMC42NjkzNSwwLjY0MTcyIC0wLjU3ODczLDEuNTI1NzF6TTIzNy4zNDIxNiwxNjguMTQ1OGMwLjU2MTE4LDAuNzAxNDcgMC41NjExOSwwLjcwMTQ3IDEuMjYyNjYsMS4yNjI2NWMwLjg4Mzk5LDAuMDkwNjIgMC44ODM5OCwwLjA5MDYyIDEuNTI1NzEsLTAuNTc4NzJjMC42NjkzNCwtMC42NDE3MyAwLjY2OTM1LC0wLjY0MTcyIDAuNTc4NzIsLTEuNTI1NzJjLTAuNTYxMTgsLTAuNzAxNDcgLTAuNTYxMTksLTAuNzAxNDcgLTEuMjYyNjYsLTEuMjYyNjVjLTAuODgzOTksLTAuMDkwNjIgLTAuODgzOTgsLTAuMDkwNjMgLTEuNTI1NzEsMC41Nzg3MWMtMC42NjkzNCwwLjY0MTczIC0wLjY2OTM0LDAuNjQxNzMgLTAuNTc4NzIsMS41MjU3MnpNMjQzLjIzNDU3LDE2Mi4yNTMzOWMwLjU2MTE4LDAuNzAxNDcgMC41NjExOCwwLjcwMTQ3IDEuMjYyNjUsMS4yNjI2NWMwLjg4Mzk5LDAuMDkwNjIgMC44ODM5OSwwLjA5MDYyIDEuNTI1NzIsLTAuNTc4NzJjMC42NjkzNCwtMC42NDE3MyAwLjY2OTM0LC0wLjY0MTcyIDAuNTc4NzEsLTEuNTI1NzFjLTAuNTYxMTgsLTAuNzAxNDcgLTAuNTYxMTgsLTAuNzAxNDcgLTEuMjYyNjUsLTEuMjYyNjVjLTAuODgzOTksLTAuMDkwNjIgLTAuODgzOTksLTAuMDkwNjMgLTEuNTI1NzIsMC41Nzg3MWMtMC42NjkzNCwwLjY0MTczIC0wLjY2OTM0LDAuNjQxNzMgLTAuNTc4NzEsMS41MjU3MnoiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48L2c+PC9nPjwvc3ZnPjwhLS1yb3RhdGlvbkNlbnRlcjoxNi4xODI2Mjk5OTk5OTk5OToyNy40ODM0MTk5OTk5OTk5OTUtLT4=", + blockIconURI: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSI4My41IiBoZWlnaHQ9IjgzLjUiIHZpZXdCb3g9IjAsMCw4My41LDgzLjUiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xOTguMjUsLTEzOC4yNTAwMSkiPjxnIHN0cm9rZS1taXRlcmxpbWl0PSIxMCI+PHBhdGggZD0iTTIxNi4zNzg3OSwxODkuODQ3MDhjMi44OTk5NywtMS45NzEzMyA1LjEwMDIxLC0xLjg5MDExIDguNDc4OTMsLTEuMjg4NDJjMC42NTE3OCwwLjY1MTc4IDEuMzAzNTMsMS4zMDM1MyAxLjk3NTA4LDEuOTc1MDhjMS43MzgwNywtMS43MzgwNyAzLjQ3NjE0LC0zLjQ3NjE0IDUuMjY2ODksLTUuMjY2ODljLTAuMzI1ODksLTAuNDM0NTEgLTAuNjUxNzgsLTAuODY5MDIgLTAuOTg3NTIsLTEuMzE2N2MtMS4zOTYwNCwtMi43OTIwNyAtMS41NzIxMSwtNC4xMzk0MyAtMC45ODc1NiwtNy4yNDE5N2MxLjg1MTUxLC0yLjY4NzE4IDMuODgzNTMsLTQuNzQ4MTMgNi41ODM2MiwtNi41ODM1OWMzLjU3OTgyLC0wLjUzNDkzIDMuNTc5NzgsLTAuNTM0OTMgNi41ODM1NiwwYzAuNjUxNzgsMC42NTE3OCAxLjMwMzUzLDEuMzAzNTMgMS45NzUwOCwxLjk3NTA4YzEuNzM4MDcsLTEuNzM4MDcgMy40NzYxNCwtMy40NzYxNCA1LjI2Njg5LC01LjI2Njg5Yy0wLjMyNTg5LC0wLjQzNDUxIC0wLjY1MTc1LC0wLjg2ODk5IC0wLjk4NzUyLC0xLjMxNjdjLTEuMzk2MDQsLTIuNzkyMDcgLTEuNTcyMDcsLTQuMTM5NDMgLTAuOTg3NTIsLTcuMjQxOTdjMS44NTE1MSwtMi42ODcxOCAzLjg4MzUzLC00Ljc0ODEzIDYuNTgzNTksLTYuNTgzNTljMy41Nzk4MiwtMC41MzQ5MyAzLjU3OTc4LC0wLjUzNDkzIDYuNTgzNTYsMGMwLjY1MTc4LDAuNjUxNzggMS4zMDM1NiwxLjMwMzUzIDEuOTc1MDgsMS45NzUwOGMxLjczODA3LC0xLjczODA3IDMuNDc2MTQsLTMuNDc2MTQgNS4yNjY4NiwtNS4yNjY4OWMwLjg2OTAyLDAuODY5MDIgMS43MzgxLDEuNzM4MSAyLjYzMzQ2LDIuNjMzNDZjLTEuNzM4MDcsMS43MzgwNyAtMy40NzYxNCwzLjQ3NjE0IC01LjI2Njg5LDUuMjY2ODljMC4zMjU4OSwwLjQzNDUxIDAuNjUxNzgsMC44Njg5OSAwLjk4NzUyLDEuMzE2N2MxLjM5NjA0LDIuNzkyMDcgMS41NzIxMSw0LjEzOTQzIDAuOTg3NTYsNy4yNDE5N2MtMS44NTE1MSwyLjY4NzE4IC0zLjg4MzQ5LDQuNzQ4MTMgLTYuNTgzNTksNi41ODM2MmMtMy41Nzk4MiwwLjUzNDkzIC0zLjU3OTgyLDAuNTM0OTMgLTYuNTgzNTksMGMtMC42NTE3OCwtMC42NTE3OCAtMS4zMDM1MywtMS4zMDM1NiAtMS45NzUwOCwtMS45NzUwOGMtMS43MzgwNywxLjczODA3IC0zLjQ3NjE0LDMuNDc2MTQgLTUuMjY2ODksNS4yNjY4OWMwLjMyNTg5LDAuNDM0NTEgMC42NTE3OCwwLjg2OTAyIDAuOTg3NTIsMS4zMTY3YzEuMzk2MDQsMi43OTIwNyAxLjU3MjA3LDQuMTM5NDMgMC45ODc1Miw3LjI0MTk3Yy0xLjg1MTUxLDIuNjg3MTggLTMuODgzNDksNC43NDgxMyAtNi41ODM1Niw2LjU4MzU5Yy0zLjU3OTgyLDAuNTM0OTMgLTMuNTc5ODIsMC41MzQ5MyAtNi41ODM1OSwwYy0wLjY1MTc4LC0wLjY1MTc4IC0xLjMwMzU2LC0xLjMwMzUzIC0xLjk3NTA4LC0xLjk3NTA4Yy0xLjczODA3LDEuNzM4MDcgLTMuNDc2MTQsMy40NzYxNCAtNS4yNjY4Niw1LjI2Njg5YzAuMzI1ODksMC40MzQ1MSAwLjY1MTc4LDAuODY4OTkgMC45ODc1MiwxLjMxNjdjMS4zOTYwNCwyLjc5MjA3IDEuNTcyMDcsNC4xMzk0MyAwLjk4NzUyLDcuMjQxOTdjLTEuODUxNTEsMi42ODcxOCAtMy44ODM0OSw0Ljc0ODEzIC02LjU4MzU5LDYuNTgzNTljLTMuNTc5ODIsMC41MzQ5MyAtMy41Nzk4MiwwLjUzNDkzIC02LjU4MzU5LDBjLTAuNjUxNzgsLTAuNjUxNzggLTEuMzAzNTMsLTEuMzAzNTMgLTEuOTc1MDgsLTEuOTc1MDhjLTEuNzM4MDcsMS43MzgwNyAtMy40NzYxNCwzLjQ3NjE0IC01LjI2Njg5LDUuMjY2ODljLTAuODY5MDIsLTAuODY5MDIgLTEuNzM4MDcsLTEuNzM4MSAtMi42MzM0MywtMi42MzM0NmMxLjczODA3LC0xLjczODA3IDMuNDc2MTEsLTMuNDc2MTQgNS4yNjY4NiwtNS4yNjY4OWMtMC4zMjU4OSwtMC40MzQ1MSAtMC42NTE3OCwtMC44Njg5OSAtMC45ODc1MiwtMS4zMTY3Yy0yLjc4NTkxLC01LjU3MTgyIC0wLjQ2OTI3LC04LjY3NTU4IDMuNzAwNzMsLTEyLjUzNzE1ek0yMTYuMjk5MDUsMTk5Ljc1MDc2YzEuNzU1NjIsMi4xOTQ1MSAxLjc1NTY1LDIuMTk0NTQgMy45NTAxNiwzLjk1MDE2YzIuNzY1NTEsMC4yODM1IDIuNzY1NDgsMC4yODM1IDQuNzczMSwtMS44MTA0OWMyLjA5Mzk5LC0yLjAwNzYyIDIuMDkzOTksLTIuMDA3NTkgMS44MTA0OSwtNC43NzMxYy0xLjc1NTYyLC0yLjE5NDUxIC0xLjc1NTY1LC0yLjE5NDU0IC0zLjk1MDE2LC0zLjk1MDE2Yy0yLjc2NTUxLC0wLjI4MzUgLTIuNzY1NDgsLTAuMjgzNSAtNC43NzMxLDEuODEwNDljLTIuMDkzOTksMi4wMDc2MiAtMi4wOTQwMiwyLjAwNzU5IC0xLjgxMDUyLDQuNzczMXpNMjM0LjczMzE1LDE4MS4zMTY2OGMxLjc1NTYyLDIuMTk0NTEgMS43NTU2NSwyLjE5NDUxIDMuOTUwMTYsMy45NTAxM2MyLjc2NTUxLDAuMjgzNSAyLjc2NTQ4LDAuMjgzNSA0Ljc3MzEsLTEuODEwNDljMi4wOTM5OSwtMi4wMDc2MiAyLjA5NDAyLC0yLjAwNzU5IDEuODEwNDksLTQuNzczMTNjLTEuNzU1NjIsLTIuMTk0NTEgLTEuNzU1NjUsLTIuMTk0NTEgLTMuOTUwMTYsLTMuOTUwMTNjLTIuNzY1NTEsLTAuMjgzNSAtMi43NjU0OCwtMC4yODM1MyAtNC43NzMxLDEuODEwNDZjLTIuMDkzOTksMi4wMDc2MiAtMi4wOTM5OSwyLjAwNzYyIC0xLjgxMDQ5LDQuNzczMTN6TTI1My4xNjcyMywxNjIuODgyNjFjMS43NTU2MiwyLjE5NDUxIDEuNzU1NjIsMi4xOTQ1MSAzLjk1MDEzLDMuOTUwMTNjMi43NjU1MSwwLjI4MzUgMi43NjU1MSwwLjI4MzUgNC43NzMxMywtMS44MTA0OWMyLjA5Mzk5LC0yLjAwNzYyIDIuMDkzOTksLTIuMDA3NTkgMS44MTA0NiwtNC43NzMxYy0xLjc1NTYyLC0yLjE5NDUxIC0xLjc1NTYyLC0yLjE5NDUxIC0zLjk1MDEzLC0zLjk1MDEzYy0yLjc2NTUxLC0wLjI4MzUgLTIuNzY1NTEsLTAuMjgzNTMgLTQuNzczMTMsMS44MTA0NmMtMi4wOTM5OSwyLjAwNzYyIC0yLjA5Mzk5LDIuMDA3NjIgLTEuODEwNDYsNC43NzMxM3oiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZS1vcGFjaXR5PSIwLjEyOTQxIiBzdHJva2U9IiMwMDAwMDAiIHN0cm9rZS13aWR0aD0iMyIvPjxwYXRoIGQ9Ik0yMTYuMzc4NzksMTg5Ljg0NzA4YzIuODk5OTcsLTEuOTcxMzMgNS4xMDAyMSwtMS44OTAxMSA4LjQ3ODkzLC0xLjI4ODQyYzAuNjUxNzgsMC42NTE3OCAxLjMwMzUzLDEuMzAzNTMgMS45NzUwOCwxLjk3NTA4YzEuNzM4MDcsLTEuNzM4MDcgMy40NzYxNCwtMy40NzYxNCA1LjI2Njg5LC01LjI2Njg5Yy0wLjMyNTg5LC0wLjQzNDUxIC0wLjY1MTc4LC0wLjg2OTAyIC0wLjk4NzUyLC0xLjMxNjdjLTEuMzk2MDQsLTIuNzkyMDcgLTEuNTcyMTEsLTQuMTM5NDMgLTAuOTg3NTYsLTcuMjQxOTdjMS44NTE1MSwtMi42ODcxOCAzLjg4MzUzLC00Ljc0ODEzIDYuNTgzNjIsLTYuNTgzNTljMy41Nzk4MiwtMC41MzQ5MyAzLjU3OTc4LC0wLjUzNDkzIDYuNTgzNTYsMGMwLjY1MTc4LDAuNjUxNzggMS4zMDM1MywxLjMwMzUzIDEuOTc1MDgsMS45NzUwOGMxLjczODA3LC0xLjczODA3IDMuNDc2MTQsLTMuNDc2MTQgNS4yNjY4OSwtNS4yNjY4OWMtMC4zMjU4OSwtMC40MzQ1MSAtMC42NTE3NSwtMC44Njg5OSAtMC45ODc1MiwtMS4zMTY3Yy0xLjM5NjA0LC0yLjc5MjA3IC0xLjU3MjA3LC00LjEzOTQzIC0wLjk4NzUyLC03LjI0MTk3YzEuODUxNTEsLTIuNjg3MTggMy44ODM1MywtNC43NDgxMyA2LjU4MzU5LC02LjU4MzU5YzMuNTc5ODIsLTAuNTM0OTMgMy41Nzk3OCwtMC41MzQ5MyA2LjU4MzU2LDBjMC42NTE3OCwwLjY1MTc4IDEuMzAzNTYsMS4zMDM1MyAxLjk3NTA4LDEuOTc1MDhjMS43MzgwNywtMS43MzgwNyAzLjQ3NjE0LC0zLjQ3NjE0IDUuMjY2ODYsLTUuMjY2ODljMC44NjkwMiwwLjg2OTAyIDEuNzM4MSwxLjczODEgMi42MzM0NiwyLjYzMzQ2Yy0xLjczODA3LDEuNzM4MDcgLTMuNDc2MTQsMy40NzYxNCAtNS4yNjY4OSw1LjI2Njg5YzAuMzI1ODksMC40MzQ1MSAwLjY1MTc4LDAuODY4OTkgMC45ODc1MiwxLjMxNjdjMS4zOTYwNCwyLjc5MjA3IDEuNTcyMTEsNC4xMzk0MyAwLjk4NzU2LDcuMjQxOTdjLTEuODUxNTEsMi42ODcxOCAtMy44ODM0OSw0Ljc0ODEzIC02LjU4MzU5LDYuNTgzNjJjLTMuNTc5ODIsMC41MzQ5MyAtMy41Nzk4MiwwLjUzNDkzIC02LjU4MzU5LDBjLTAuNjUxNzgsLTAuNjUxNzggLTEuMzAzNTMsLTEuMzAzNTYgLTEuOTc1MDgsLTEuOTc1MDhjLTEuNzM4MDcsMS43MzgwNyAtMy40NzYxNCwzLjQ3NjE0IC01LjI2Njg5LDUuMjY2ODljMC4zMjU4OSwwLjQzNDUxIDAuNjUxNzgsMC44NjkwMiAwLjk4NzUyLDEuMzE2N2MxLjM5NjA0LDIuNzkyMDcgMS41NzIwNyw0LjEzOTQzIDAuOTg3NTIsNy4yNDE5N2MtMS44NTE1MSwyLjY4NzE4IC0zLjg4MzQ5LDQuNzQ4MTMgLTYuNTgzNTYsNi41ODM1OWMtMy41Nzk4MiwwLjUzNDkzIC0zLjU3OTgyLDAuNTM0OTMgLTYuNTgzNTksMGMtMC42NTE3OCwtMC42NTE3OCAtMS4zMDM1NiwtMS4zMDM1MyAtMS45NzUwOCwtMS45NzUwOGMtMS43MzgwNywxLjczODA3IC0zLjQ3NjE0LDMuNDc2MTQgLTUuMjY2ODYsNS4yNjY4OWMwLjMyNTg5LDAuNDM0NTEgMC42NTE3OCwwLjg2ODk5IDAuOTg3NTIsMS4zMTY3YzEuMzk2MDQsMi43OTIwNyAxLjU3MjA3LDQuMTM5NDMgMC45ODc1Miw3LjI0MTk3Yy0xLjg1MTUxLDIuNjg3MTggLTMuODgzNDksNC43NDgxMyAtNi41ODM1OSw2LjU4MzU5Yy0zLjU3OTgyLDAuNTM0OTMgLTMuNTc5ODIsMC41MzQ5MyAtNi41ODM1OSwwYy0wLjY1MTc4LC0wLjY1MTc4IC0xLjMwMzUzLC0xLjMwMzUzIC0xLjk3NTA4LC0xLjk3NTA4Yy0xLjczODA3LDEuNzM4MDcgLTMuNDc2MTQsMy40NzYxNCAtNS4yNjY4OSw1LjI2Njg5Yy0wLjg2OTAyLC0wLjg2OTAyIC0xLjczODA3LC0xLjczODEgLTIuNjMzNDMsLTIuNjMzNDZjMS43MzgwNywtMS43MzgwNyAzLjQ3NjExLC0zLjQ3NjE0IDUuMjY2ODYsLTUuMjY2ODljLTAuMzI1ODksLTAuNDM0NTEgLTAuNjUxNzgsLTAuODY4OTkgLTAuOTg3NTIsLTEuMzE2N2MtMi43ODU5MSwtNS41NzE4MiAtMC40NjkyNywtOC42NzU1OCAzLjcwMDczLC0xMi41MzcxNXpNMjE2LjI5OTA1LDE5OS43NTA3NmMxLjc1NTYyLDIuMTk0NTEgMS43NTU2NSwyLjE5NDU0IDMuOTUwMTYsMy45NTAxNmMyLjc2NTUxLDAuMjgzNSAyLjc2NTQ4LDAuMjgzNSA0Ljc3MzEsLTEuODEwNDljMi4wOTM5OSwtMi4wMDc2MiAyLjA5Mzk5LC0yLjAwNzU5IDEuODEwNDksLTQuNzczMWMtMS43NTU2MiwtMi4xOTQ1MSAtMS43NTU2NSwtMi4xOTQ1NCAtMy45NTAxNiwtMy45NTAxNmMtMi43NjU1MSwtMC4yODM1IC0yLjc2NTQ4LC0wLjI4MzUgLTQuNzczMSwxLjgxMDQ5Yy0yLjA5Mzk5LDIuMDA3NjIgLTIuMDk0MDIsMi4wMDc1OSAtMS44MTA1Miw0Ljc3MzF6TTIzNC43MzMxNSwxODEuMzE2NjhjMS43NTU2MiwyLjE5NDUxIDEuNzU1NjUsMi4xOTQ1MSAzLjk1MDE2LDMuOTUwMTNjMi43NjU1MSwwLjI4MzUgMi43NjU0OCwwLjI4MzUgNC43NzMxLC0xLjgxMDQ5YzIuMDkzOTksLTIuMDA3NjIgMi4wOTQwMiwtMi4wMDc1OSAxLjgxMDQ5LC00Ljc3MzEzYy0xLjc1NTYyLC0yLjE5NDUxIC0xLjc1NTY1LC0yLjE5NDUxIC0zLjk1MDE2LC0zLjk1MDEzYy0yLjc2NTUxLC0wLjI4MzUgLTIuNzY1NDgsLTAuMjgzNTMgLTQuNzczMSwxLjgxMDQ2Yy0yLjA5Mzk5LDIuMDA3NjIgLTIuMDkzOTksMi4wMDc2MiAtMS44MTA0OSw0Ljc3MzEzek0yNTMuMTY3MjMsMTYyLjg4MjYxYzEuNzU1NjIsMi4xOTQ1MSAxLjc1NTYyLDIuMTk0NTEgMy45NTAxMywzLjk1MDEzYzIuNzY1NTEsMC4yODM1IDIuNzY1NTEsMC4yODM1IDQuNzczMTMsLTEuODEwNDljMi4wOTM5OSwtMi4wMDc2MiAyLjA5Mzk5LC0yLjAwNzU5IDEuODEwNDYsLTQuNzczMWMtMS43NTU2MiwtMi4xOTQ1MSAtMS43NTU2MiwtMi4xOTQ1MSAtMy45NTAxMywtMy45NTAxM2MtMi43NjU1MSwtMC4yODM1IC0yLjc2NTUxLC0wLjI4MzUzIC00Ljc3MzEzLDEuODEwNDZjLTIuMDkzOTksMi4wMDc2MiAtMi4wOTM5OSwyLjAwNzYyIC0xLjgxMDQ2LDQuNzczMTN6IiBmaWxsPSIjZmZmZmZmIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xOTguMjUsMjIxLjc1MDAxdi04My41aDgzLjV2ODMuNXoiIGZpbGw9Im5vbmUiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIwIi8+PC9nPjwvZz48L3N2Zz48IS0tcm90YXRpb25DZW50ZXI6NDEuNzUwMDAwNjg3MTE5Mjc6NDEuNzQ5OTkwMTIxMTQ5MzgtLT4=", color1: NODE1, color2: NODE2, From f942eab4ae9d012cfd285a5cc95c7ac85c4f22ea Mon Sep 17 00:00:00 2001 From: ziplox Date: Sun, 10 May 2026 22:49:38 -0400 Subject: [PATCH 54/54] Update credits text in nodes.js --- static/extensions/ZiploxWasTaken/nodes.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/static/extensions/ZiploxWasTaken/nodes.js b/static/extensions/ZiploxWasTaken/nodes.js index 89195d7cb..734ac04a8 100644 --- a/static/extensions/ZiploxWasTaken/nodes.js +++ b/static/extensions/ZiploxWasTaken/nodes.js @@ -92,7 +92,11 @@ blocks: [ { blockType: Scratch.BlockType.LABEL, - text: "By ZiploxZQS and OutsideFlight, may be updated later" + text: "Credits: Ziplox and OutF" + }, + { + blockType: Scratch.BlockType.LABEL, + text: "May be updated later" }, { opcode: "createNode",