{"code":"(window.webpackJsonpGUI=window.webpackJsonpGUI||[]).push([[4],{1382:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,\"/* Imported by other addons */\\n\\n.sa-block-color {\\n --sa-block-colored-background: var(--sa-block-background-primary);\\n --sa-block-colored-background-secondary: var(--sa-block-field-background);\\n --sa-block-bright-background: var(--sa-block-background-primary);\\n --sa-block-text: var(--editorTheme3-blockText, white);\\n --sa-block-gray-text: white;\\n --sa-block-colored-text: var(--sa-block-background-primary);\\n --sa-block-text-on-bright-background: var(--editorTheme3-blockText, white);\\n --sa-block-input-color: var(--editorTheme3-inputColor, white);\\n --sa-block-input-text: var(--editorTheme3-inputColor-text, #575e75);\\n}\\n\\n.sa-block-color-motion {\\n --sa-block-background-primary: var(--editorTheme3-motion-primary, #4c97ff);\\n --sa-block-background-secondary: var(--editorTheme3-motion-secondary, #4280d7);\\n --sa-block-background-tertiary: var(--editorTheme3-motion-tertiary, #3373cc);\\n --sa-block-field-background: var(--editorTheme3-motion-field, #3373cc);\\n}\\n\\n.sa-block-color-looks {\\n --sa-block-background-primary: var(--editorTheme3-looks-primary, #9966ff);\\n --sa-block-background-secondary: var(--editorTheme3-looks-secondary, #855cd6);\\n --sa-block-background-tertiary: var(--editorTheme3-looks-tertiary, #774dcb);\\n --sa-block-field-background: var(--editorTheme3-looks-field, #774dcb);\\n}\\n\\n.sa-block-color-sounds {\\n --sa-block-background-primary: var(--editorTheme3-sounds-primary, #cf63cf);\\n --sa-block-background-secondary: var(--editorTheme3-sounds-secondary, #c94fc9);\\n --sa-block-background-tertiary: var(--editorTheme3-sounds-tertiary, #bd42bd);\\n --sa-block-field-background: var(--editorTheme3-sounds-field, #bd42bd);\\n}\\n\\n.sa-block-color-events {\\n --sa-block-background-primary: var(--editorTheme3-event-primary, #ffbf00);\\n --sa-block-background-secondary: var(--editorTheme3-event-secondary, #e6ac00);\\n --sa-block-background-tertiary: var(--editorTheme3-event-tertiary, #cc9900);\\n --sa-block-field-background: var(--editorTheme3-event-field, #cc9900);\\n}\\n\\n.sa-block-color-control {\\n --sa-block-background-primary: var(--editorTheme3-control-primary, #ffab19);\\n --sa-block-background-secondary: var(--editorTheme3-control-secondary, #ec9c13);\\n --sa-block-background-tertiary: var(--editorTheme3-control-tertiary, #cf8b17);\\n --sa-block-field-background: var(--editorTheme3-control-field, #cf8b17);\\n}\\n\\n.sa-block-color-sensing {\\n --sa-block-background-primary: var(--editorTheme3-sensing-primary, #5cb1d6);\\n --sa-block-background-secondary: var(--editorTheme3-sensing-secondary, #47a8d1);\\n --sa-block-background-tertiary: var(--editorTheme3-sensing-tertiary, #2e8eb8);\\n --sa-block-field-background: var(--editorTheme3-sensing-field, #2e8eb8);\\n}\\n\\n.sa-block-color-operators {\\n --sa-block-background-primary: var(--editorTheme3-operators-primary, #59c059);\\n --sa-block-background-secondary: var(--editorTheme3-operators-secondary, #46b946);\\n --sa-block-background-tertiary: var(--editorTheme3-operators-tertiary, #389438);\\n --sa-block-field-background: var(--editorTheme3-operators-field, #389438);\\n}\\n\\n.sa-block-color-data {\\n --sa-block-background-primary: var(--editorTheme3-data-primary, #ff8c1a);\\n --sa-block-background-secondary: var(--editorTheme3-data-secondary, #ff8000);\\n --sa-block-background-tertiary: var(--editorTheme3-data-tertiary, #db6e00);\\n --sa-block-field-background: var(--editorTheme3-data-field, #db6e00);\\n}\\n\\n.sa-block-color-data-lists,\\n.sa-block-color-list {\\n --sa-block-background-primary: var(--editorTheme3-data_lists-primary, #ff661a);\\n --sa-block-background-secondary: var(--editorTheme3-data_lists-secondary, #ff5500);\\n --sa-block-background-tertiary: var(--editorTheme3-data_lists-tertiary, #e64d00);\\n --sa-block-field-background: var(--editorTheme3-data_lists-field, #e64d00);\\n}\\n\\n.sa-block-color-more,\\n.sa-block-color-null {\\n --sa-block-background-primary: var(--editorTheme3-more-primary, #ff6680);\\n --sa-block-background-secondary: var(--editorTheme3-more-secondary, #ff4d6a);\\n --sa-block-background-tertiary: var(--editorTheme3-more-tertiary, #ff3355);\\n --sa-block-field-background: var(--editorTheme3-more-field, #ff3355);\\n}\\n\\n.sa-block-color-pen {\\n --sa-block-background-primary: var(--editorTheme3-pen-primary, #0fbd8c);\\n --sa-block-background-secondary: var(--editorTheme3-pen-secondary, #0da57a);\\n --sa-block-background-tertiary: var(--editorTheme3-pen-tertiary, #0b8e69);\\n --sa-block-field-background: var(--editorTheme3-pen-field, #0b8e69);\\n}\\n\\n.sa-block-color-addon-custom-block {\\n --sa-block-background-primary: var(--editorTheme3-addons-primary, #29beb8);\\n --sa-block-background-secondary: var(--editorTheme3-addons-secondary, #3aa8a4);\\n --sa-block-background-tertiary: var(--editorTheme3-addons-tertiary, #3aa8a4);\\n --sa-block-field-background: var(--editorTheme3-addons-field, #3aa8a4);\\n}\\n\",\"\"])},1383:function(e,t,o){\"use strict\";o.d(t,\"b\",(function(){return c})),o.d(t,\"a\",(function(){return l})),o.d(t,\"c\",(function(){return d}));var n=o(709);const s=new Map,r=1e3,i=new n.a,a=\"clearTextCache\";function c(e){let t=e.innerHTML;if(0===t.length)return 0;let o=s.get(t);return o||(o=e.getBoundingClientRect().width,s.set(t,o),s.size>r&&s.delete(s.keys().next()),o)}function l(){s.clear(),i.dispatchEvent(new CustomEvent(a))}function d(e){i.addEventListener(a,e)}},1388:function(e,t,o){\"use strict\";o.d(t,\"a\",(function(){return n})),o.d(t,\"b\",(function(){return s}));const n=()=>/^#?[0-9a-fA-F]{3,8}$/,s=e=>{let t=String(e);if(!n().test(t))return\"#000000\";if(t.startsWith(\"#\")||(t=\"#\".concat(t)),4===t.length){const[e,o,n,s]=t;t=\"#\".concat(o).concat(o).concat(n).concat(n).concat(s).concat(s)}return t.toLowerCase()}},1389:function(e,t,o){\"use strict\";o.d(t,\"a\",(function(){return n}));class n{constructor(e){this.timeout=null,this.callback=null,this.wait=e}abort(){let e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.timeout&&(clearTimeout(this.timeout),e&&this.callback(),this.timeout=this.callback=null)}limit(e){this.abort(!1),this.callback=e,this.timeout=setTimeout((()=>{this.timeout=this.callback=null,e()}),this.wait)}}},1390:function(e,t,o){\"use strict\";o.d(t,\"a\",(function(){return s})),o.d(t,\"b\",(function(){return r}));let n=!1;const s={paintSkew:null,paintSnap:null};function r(e,t){if(n)return;n=!0;const o=t.prototype.onMouseDrag;t.prototype.onMouseDrag=function(e){if(!this.active)return;const t=()=>{s.paintSnap?s.paintSnap.call(this,e):o.call(this,e)};s.paintSkew?s.paintSkew.call(this,e,t):t()}}},1395:function(e,t,o){\"use strict\";o.d(t,\"b\",(function(){return r})),o.d(t,\"c\",(function(){return a})),o.d(t,\"a\",(function(){return u}));let n=!1,s=!1;function r(e,t){n=e,s=e&&t}let i=!1;function a(e){i=e}let c=!1,l=!1;document.addEventListener(\"mousedown\",(function(e){c=e.ctrlKey||e.metaKey,l=e.altKey}),{capture:!0});let d=!1;async function u(e){if(d)return;d=!0;const t=await e.tab.traps.getBlockly(),o=t.Gesture.prototype.startDraggingBlock_;t.Gesture.prototype.startDraggingBlock_=function(){let e=this.targetBlock_;const r=!(this.mostRecentEvent_ instanceof MouseEvent),a=i&&l&&!r&&!this.flyout_&&!this.shouldDuplicateOnDrag_&&\"procedures_definition\"!==this.targetBlock_.type,d=s&&!r&&e.getParent(),u=(n||a)&&c===!d&&!e.isShadow();if((a||u)&&(t.Events.getGroup()||t.Events.setGroup(!0)),a){let o;this.startWorkspace_.setResizesEnabled(!1),t.Events.disable();try{const n=t.Xml.blockToDom(e);o=t.Xml.domToBlock(n,this.startWorkspace_),t.scratchBlocksUtils.changeObscuredShadowIds(o);const s=e.getRelativeToSurfaceXY();o.moveBy(s.x,s.y)}catch(e){console.error(e)}t.Events.enable(),o&&(e=o,this.targetBlock_=o,t.Events.isEnabled()&&t.Events.fire(new t.Events.BlockCreate(o)))}if(u){if(r||a){const t=e.getNextBlock();t&&t.dispose()}e.unplug(!0)}for(var p=arguments.length,h=new Array(p),g=0;g .sa-find-dropdown {\\n display: block;\\n}\\n\\n.sa-find-dropdown > li {\\n display: block;\\n padding: 0.5em 0.3em;\\n white-space: nowrap;\\n margin: 0;\\n font-weight: bold;\\n text-overflow: ellipsis;\\n overflow: hidden;\\n}\\n\\n.sa-find-dropdown > li > b {\\n background-color: #aaffaa;\\n color: black;\\n}\\n\\n/* Drop down items */\\n.sa-find-dropdown > li:hover,\\n.sa-find-dropdown > li.sel {\\n color: var(--sa-block-text-on-bright-background);\\n cursor: pointer;\\n}\\n\\n.sa-find-dropdown > li::before {\\n content: \"\\\\25CF \"; /* ● */\\n}\\n\\n.sa-find-flag {\\n color: #4cbf56;\\n}\\n/* .sa-find-dropdown added for specificity */\\n.sa-find-dropdown > .sa-find-flag:hover,\\n.sa-find-dropdown > .sa-find-flag.sel {\\n background-color: #4cbf56;\\n color: white;\\n}\\n\\n.sa-find-dropdown .sa-block-color {\\n color: var(--sa-block-colored-text);\\n}\\n.sa-find-dropdown .sa-block-color:hover,\\n.sa-find-dropdown .sa-block-color.sel {\\n background-color: var(--sa-block-bright-background);\\n}\\n\\n.sa-find-carousel {\\n font-weight: normal;\\n position: absolute;\\n right: 0;\\n white-space: nowrap;\\n background-color: inherit;\\n z-index: 1;\\n padding: 0;\\n}\\n\\n.sa-find-carousel-control {\\n padding: 0 6px;\\n}\\n\\n.sa-find-carousel-control:hover {\\n color: #ffff80;\\n}\\n',\"\"])},1435:function(e,t,o){(t=e.exports=o(9)(!1)).i(o(1382),\"\"),t.push([e.i,'.sa-mcp-root {\\n display: flex;\\n white-space: nowrap;\\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\\n\\n position: absolute;\\n min-width: 100px;\\n background-color: var(--ui-modal-background);\\n border-radius: 4px;\\n box-shadow:\\n rgba(0, 0, 0, 0.3) 0 0 3px,\\n rgba(0, 0, 0, 0.2) 0 3px 10px;\\n\\n z-index: 999;\\n}\\n\\n.sa-mcp-container {\\n display: flex;\\n flex-flow: column;\\n top: -6px;\\n z-index: 100;\\n position: absolute;\\n box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.3);\\n background-color: var(--ui-modal-background);\\n outline: 1px solid var(--ui-black-transparent);\\n border: none;\\n border-radius: 4px;\\n}\\n\\n.sa-mcp-input-wrapper {\\n position: relative;\\n margin: 4px;\\n /* !important required for extension, because CSS injection method (and hence order) differs from addon */\\n box-sizing: border-box !important;\\n height: 1.5rem;\\n min-height: 1.5rem;\\n\\n /* Change Scratch default styles */\\n border-radius: 0.25rem;\\n font-size: 0.75rem;\\n padding-left: 0.2rem;\\n padding-right: 0.2rem;\\n}\\n\\n.sa-mcp-input-wrapper:focus {\\n /* Change Scratch default styles */\\n box-shadow: none;\\n}\\n\\n.sa-mcp-input-wrapper[data-error=\"true\"] {\\n border-color: red;\\n}\\n\\n.sa-mcp-input-wrapper > input {\\n position: absolute;\\n border: 0;\\n background-color: transparent;\\n outline: none;\\n width: 100%;\\n height: 100%;\\n line-height: 100%;\\n box-sizing: border-box;\\n}\\n\\n.sa-mcp-input-suggestion {\\n color: hsla(225, 15%, 40%, 0.65);\\n}\\n\\n.sa-mcp-preview-container {\\n flex: auto;\\n overflow-y: scroll;\\n}\\n\\n.sa-mcp-root /* <-- specificity */ .sa-mcp-preview-container {\\n scrollbar-width: none;\\n}\\n\\n.sa-mcp-preview-container::-webkit-scrollbar {\\n width: 0;\\n height: 0;\\n}\\n\\n.sa-mcp-preview-blocks {\\n width: 100%;\\n min-height: 100%;\\n /* https://stackoverflow.com/a/22166728/8448397 */\\n float: left;\\n}\\n\\n.sa-mcp-preview-scrollbar {\\n position: absolute;\\n width: 11px;\\n right: 0;\\n bottom: 0;\\n}\\n\\n.sa-mcp-preview-block-bg {\\n width: 100%;\\n fill: transparent;\\n cursor: grab;\\n}\\n\\n.sa-mcp-preview-block {\\n filter: brightness(95%);\\n cursor: grab;\\n}\\n\\n.sa-mcp-preview-block-selection {\\n filter: brightness(103%);\\n}\\n\\n.sa-mcp-preview-block-bg-selection {\\n fill: #7774;\\n}\\n',\"\"])},1436:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,\".blocklyTextShiftArrow {\\n position: absolute;\\n top: -50px;\\n left: 50%;\\n margin-left: -12.5px;\\n cursor: pointer;\\n}\\n\",\"\"])},1437:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,\".u-dropdown-searchbar {\\n width: 100%;\\n box-sizing: border-box;\\n /* based on styles for the title input */\\n color: white;\\n background-color: hsla(0, 100%, 100%, 0.25);\\n border: 1px solid hsla(0, 0%, 0%, 0.15);\\n padding: 0.5rem;\\n outline: none;\\n transition: 0.25s ease-out;\\n font-size: 13px;\\n font-weight: bold;\\n border-radius: 4px;\\n}\\n.u-dropdown-searchbar:hover {\\n background-color: hsla(0, 100%, 100%, 0.5);\\n}\\n.u-dropdown-searchbar:focus {\\n background-color: white;\\n color: black;\\n}\\n.blocklyDropDownDiv .goog-menu {\\n overflow-x: hidden;\\n}\\n\",\"\"])},1465:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,'.sa-color-picker {\\n display: flex;\\n}\\n\\n.sa-color-picker-code {\\n margin: 8px 0;\\n}\\n\\n.sa-color-picker-paint {\\n margin-top: 16px;\\n margin-bottom: 4px;\\n}\\n\\n.sa-color-picker > .sa-color-picker-color {\\n border: none;\\n border-top-left-radius: 1rem;\\n border-bottom-left-radius: 1rem;\\n padding: 0;\\n padding-left: 0.6rem;\\n padding-right: 0.4rem;\\n margin-left: 0.5rem;\\n outline: none;\\n box-sizing: border-box;\\n width: 3rem;\\n height: 2rem;\\n}\\n\\n.sa-color-picker > .sa-color-picker-text {\\n box-sizing: border-box;\\n width: calc(150px - 3rem);\\n border-top-left-radius: 0;\\n border-bottom-left-radius: 0;\\n}\\n\\n[dir=\"rtl\"] .sa-color-picker > .sa-color-picker-color {\\n border-top-left-radius: 0;\\n border-bottom-left-radius: 0;\\n border-top-right-radius: 1rem;\\n border-bottom-right-radius: 1rem;\\n margin-left: 0;\\n margin-right: 0.5rem;\\n}\\n\\n[dir=\"rtl\"] .sa-color-picker > .sa-color-picker-text {\\n border-top-left-radius: 1rem;\\n border-bottom-left-radius: 1rem;\\n border-top-right-radius: 0;\\n border-bottom-right-radius: 0;\\n}\\n\\nbody.sa-hide-eye-dropper-background div[class*=\"stage_color-picker-background\"] {\\n /* Do not show eye dropper background if the color picker is \"fake\" */\\n display: none;\\n}\\n',\"\"])},1466:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,'.sa-onion-button {\\n position: relative;\\n}\\n.sa-onion-button:focus-within {\\n background-color: var(--editorDarkMode-primary-transparent35, hsla(260, 60%, 60%, 0.35));\\n}\\n.sa-onion-image[data-image=\"toggle\"] {\\n filter: var(--filter-icon-white);\\n}\\n.sa-onion-image[data-image=\"settings\"] {\\n filter: var(--filter-icon-black);\\n}\\n.sa-onion-button[data-enabled=\"true\"] .sa-onion-image {\\n filter: brightness(0) invert(1);\\n}\\n.sa-onion-button[data-enabled=\"true\"] {\\n color: white;\\n background-color: var(--looks-secondary);\\n}\\n\\n.sa-onion-group {\\n position: relative;\\n flex-direction: row;\\n}\\n\\n.sa-onion-settings-wrapper {\\n position: absolute;\\n justify-items: center;\\n left: 50%;\\n width: 1.95rem;\\n height: 1.95rem;\\n display: grid;\\n}\\n\\n.sa-onion-settings {\\n position: absolute;\\n bottom: 100%;\\n /* based on the styles for the color dropdown */\\n padding: 4px;\\n border-radius: 4px;\\n border: 1px solid #ddd;\\n border: 1px solid var(--ui-black-transparent);\\n transition-property: bottom, opacity;\\n transition-duration: 500ms;\\n transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);\\n opacity: 0;\\n pointer-events: none;\\n background: var(--ui-modal-background);\\n color: var(--ui-text-primary);\\n min-height: 100%;\\n min-width: 100%;\\n display: flex;\\n flex-direction: column;\\n gap: 0.25em;\\n}\\n.sa-onion-settings[data-visible=\"true\"] {\\n bottom: calc(100% + 22px);\\n pointer-events: auto;\\n opacity: 1;\\n}\\n\\n.sa-onion-settings-line {\\n display: flex;\\n justify-content: flex-end;\\n align-items: baseline;\\n gap: 0.25em;\\n}\\n\\n.sa-onion-settings-input {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n box-sizing: border-box;\\n text-align: center;\\n border: 0;\\n background: transparent;\\n -moz-appearance: textfield;\\n border: 0;\\n outline: 0;\\n}\\n\\n.sa-onion-settings-input::-webkit-outer-spin-button,\\n.sa-onion-settings-input::-webkit-inner-spin-button {\\n -webkit-appearance: none;\\n margin: 0;\\n}\\n\\n.sa-onion-settings-tip {\\n position: absolute;\\n bottom: 0;\\n transform: translateY(100%);\\n right: calc(50% - 7px);\\n}\\n.sa-onion-settings-polygon {\\n fill: var(--ui-modal-background);\\n stroke: var(--ui-black-transparent);\\n}\\n\\n.sa-onion-settings-label {\\n white-space: nowrap;\\n}\\n',\"\"])},1470:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,'.sa-stage-color-picker-picking [class^=\"stage_color-picker-background_\"] {\\n display: none;\\n}\\n',\"\"])},1494:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,'.sa-folders-contextmenu-item {\\n max-width: 250px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n[sa-folders-context-type=\"folder\"] .react-contextmenu > :not(.sa-ctx-menu) {\\n display: none;\\n}\\n',\"\"])},1506:function(e,t,o){(e.exports=o(9)(!1)).push([e.i,\".sa-comment-preview-outer {\\n position: fixed;\\n top: 0;\\n left: 0;\\n z-index: 100000000;\\n pointer-events: none;\\n}\\n\\n.sa-comment-preview-inner {\\n width: calc(200px - 16px);\\n max-height: calc(132px - 8px);\\n padding: 8px;\\n overflow: hidden;\\n\\n font-size: 12px;\\n white-space: pre-wrap;\\n pointer-events: none;\\n\\n color: rgb(87, 94, 117);\\n background-color: rgb(255 255 255 / 90%);\\n border-style: none;\\n border-radius: 8px;\\n filter: drop-shadow(0px 5px 5px rgb(0 0 0 / 10%));\\n\\n transform: perspective(200px);\\n}\\n\\n@supports (backdrop-filter: blur(16px)) {\\n .sa-comment-preview-inner {\\n background-color: rgb(255 255 255 / 75%);\\n backdrop-filter: blur(16px);\\n }\\n}\\n\\n.sa-comment-preview-fade {\\n transition:\\n opacity 0.1s,\\n filter 0.1s,\\n transform 0.1s linear;\\n}\\n\\n.sa-comment-preview-hidden {\\n opacity: 0;\\n filter: none;\\n transform: perspective(200px) translateZ(-20px);\\n}\\n\\n.sa-comment-preview-reduce-transparency {\\n background-color: rgb(255 255 255);\\n backdrop-filter: none;\\n}\\n\",\"\"])},1523:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return c}));class n{constructor(e){this.addon=e,this.vm=e.tab.traps.vm,this.events=[]}triggerDragAndDrop(e,t,o,n){n=n||!1;let s=function(e,t,o,s){let r=document.createEvent(\"MouseEvents\");r.initMouseEvent(e,!0,!0,window,1,1,1,o,s,n,!1,!1,!1,0,t),t.dispatchEvent(r)},r=e,i=t;if(!r)return!1;let a=r.getBoundingClientRect(),c=Math.floor((a.left+a.right)/2),l=Math.floor((a.top+a.bottom)/2);if(s(\"mouseover\",r,c,l),s(\"mousedown\",r,c,l),s(\"dragstart\",r,c,l),s(\"drag\",r,c,l),s(\"mousemove\",r,c,l),!i){if(o){let e=o.x,t=o.y;s(\"drag\",r,e,t),s(\"mousemove\",r,e,t)}return!1}a=i.getBoundingClientRect();let d=Math.floor((a.left+a.right)/2),u=Math.floor((a.top+a.bottom)/2);return s(\"drag\",r,d,u),s(\"mousemove\",i,d,u),s(\"mouseenter\",i,d,u),s(\"dragenter\",i,d,u),s(\"mouseover\",i,d,u),s(\"dragover\",i,d,u),s(\"drop\",i,d,u),s(\"dragend\",r,d,u),s(\"mouseup\",r,d,u),!0}bindOnce(e,t,o,n){n=!!n,e.removeEventListener(t,o,n),e.addEventListener(t,o,n),this.events.push(new s(e,t,o,n))}unbindAllEvents(){for(const e of this.events)e.dom.removeEventListener(e.event,e.func,e.capture);this.events=[]}}class s{constructor(e,t,o,n){this.dom=e,this.event=t,this.func=o,this.capture=n}}class r{static startUndoGroup(e){const t=e.undoStack_;t.length&&(t[t.length-1]._devtoolsLastUndo=!0)}static endUndoGroup(e){const t=e.undoStack_;setTimeout((()=>{const e=function(){const e=\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%()*+,-./:;=?@[]^_`{|}~\";let t=\"\";for(let o=0;o<20;o++)t+=e[Math.floor(Math.random()*e.length)];return t}();for(let o=t.length-1;o>=0&&!t[o]._devtoolsLastUndo;o--)t[o].group=e}),0)}}class i{constructor(e,t,o){this.addon=e,this.msg=t,this.m=o,this.domHelpers=new n(e),this.codeTab=null,this.costTab=null,this.costTabBody=null,this.selVarID=null,this.canShare=!1,this.mouseXY={x:0,y:0}}async init(){for(this.addContextMenus();;){const e=await this.addon.tab.waitForElement(\"ul[class*=gui_tab-list_]\",{markAsSeen:!0,reduxEvents:[\"scratch-gui/mode/SET_PLAYER\",\"fontsLoaded/SET_FONTS_LOADED\",\"scratch-gui/locales/SELECT_LOCALE\"],reduxCondition:e=>!e.scratchGui.mode.isPlayerOnly});this.initInner(e)}}async addContextMenus(){const e=await this.addon.tab.traps.getBlockly(),t=e.WorkspaceSvg.prototype.cleanUp,o=this;e.WorkspaceSvg.prototype.cleanUp=function(){o.addon.settings.get(\"enableCleanUpPlus\")?o.doCleanUp():t.call(this)};let n=e.Msg.CLEAN_UP;this.addon.settings.get(\"enableCleanUpPlus\")&&(e.Msg.CLEAN_UP=this.m(\"clean-plus\")),this.addon.settings.addEventListener(\"change\",(()=>{this.addon.settings.get(\"enableCleanUpPlus\")?e.Msg.CLEAN_UP=this.m(\"clean-plus\"):e.Msg.CLEAN_UP=n})),this.addon.tab.createBlockContextMenu(((t,o)=>(t.push({enabled:e.clipboardXml_,text:this.m(\"paste\"),separator:!0,_isDevtoolsFirstItem:!0,callback:()=>{let e=this.getTopBlockIDs();document.dispatchEvent(new KeyboardEvent(\"keydown\",{keyCode:86,ctrlKey:!0,griff:!0})),setTimeout((()=>{this.beginDragOfNewBlocksNotInIDs(e)}),10)}}),t)),{workspace:!0}),this.addon.tab.createBlockContextMenu(((e,t)=>(e.push({enabled:!0,text:this.m(\"make-space\"),_isDevtoolsFirstItem:!0,callback:()=>{this.doCleanUp(t)},separator:!0},{enabled:!0,text:this.m(\"copy-all\"),callback:()=>{this.eventCopyClick(t)},separator:!0},{enabled:!0,text:this.m(\"copy-block\"),callback:()=>{this.eventCopyClick(t,1)}},{enabled:!0,text:this.m(\"cut-block\"),callback:()=>{this.eventCopyClick(t,2)}}),e)),{blocks:!0}),this.addon.tab.createBlockContextMenu(((e,t)=>(\"data\"!==t.getCategory()&&\"data-lists\"!==t.getCategory()||(this.selVarID=t.getVars()[0],e.push({enabled:!0,text:this.m(\"swap\",{var:\"data\"===t.getCategory()?this.m(\"variables\"):this.m(\"lists\")}),callback:async()=>{let e=this.getWorkspace().getVariableById(this.selVarID),t=await window.prompt(this.msg(\"replace\",{name:e.name}));t&&this.doReplaceVariable(this.selVarID,t,e.type)},separator:!0})),e)),{blocks:!0,flyout:!0})}getWorkspace(){return Blockly.getMainWorkspace()}isCostumeEditor(){return this.costTab.className.indexOf(\"gui_is-selected\")>=0}getTopBlocks(){let e=this.getOrderedTopBlockColumns().cols,t=[];for(const o of e)t=t.concat(o.blocks);return t}doCleanUp(e){let t=this.getWorkspace(),o=e&&e.getRootBlock();r.startUndoGroup(t);let n=this.getOrderedTopBlockColumns(!0),s=n.cols,i=n.orphans.blocks.length;if(i>0&&!e){let e=this.msg(\"orphaned\",{count:i});if(confirm(e))for(const e of n.orphans.blocks)e.dispose();else s.unshift(n.orphans)}let a=48,c=n.maxWidths;for(const e of s){let t=64,n=0;for(const s of e.blocks){let e=s===o?380:0,r=s===o?480:72,i=s.getRelativeToSurfaceXY();a-i.x===0&&t-i.y===0||s.moveBy(a-i.x,t-i.y);let l=s.getHeightWidth();t+=l.height+r;let d=c[s.id]||0;n=Math.max(n,Math.max(l.width+e,d))}a+=n+96}let l=t.getTopComments();for(const e of l)e.setVisible&&(e.setVisible(!1),e.needsAutoPositioning_=!0,e.setVisible(!0));setTimeout((()=>{let e=this.getWorkspace(),t=e.getVariableMap(),o=t.getVariablesOfType(\"\"),n=[];for(const e of o)if(e.isLocal){let o=t.getVariableUsesById(e.getId());o&&0!==o.length||n.push(e)}if(n.length>0){const t=n.length;let o=this.msg(\"unused-var\",{count:t});for(let e=0;e0&&(o+=\", \"),o+=n[e].name}if(confirm(o))for(const t of n)e.deleteVariableById(t.getId())}let s=t.getVariablesOfType(\"list\"),i=[];for(const e of s)if(e.isLocal){let o=t.getVariableUsesById(e.getId());o&&0!==o.length||i.push(e)}if(i.length>0){const t=i.length;let o=this.msg(\"unused-list\",{count:t});for(let e=0;e0&&(o+=\", \"),o+=i[e].name}if(confirm(o))for(const t of i)e.deleteVariableById(t.getId())}r.endUndoGroup(e)}),100)}isBlockAnOrphan(e){return!!e.outputConnection}getOrderedTopBlockColumns(e){let t=this.getWorkspace(),o=t.getTopBlocks(),n={};if(e){let e=t.getTopComments();for(const t of e)if(t.setVisible){t.setVisible(!1),t.needsAutoPositioning_=!0,t.setVisible(!0);let e=t.getBoundingRectangle().bottomRight.x,o=t.block_.getRootBlock(),s=o.getBoundingRectangle().topLeft.x;n[o.id]=Math.max(e-s,n[o.id]||0)}}let s=[];let r={x:-999999,count:0,blocks:[]};for(const t of o){let o=t.getRelativeToSurfaceXY(),n=null,i=256;if(e&&this.isBlockAnOrphan(t))r.blocks.push(t);else{for(const e of s){let t=Math.abs(o.x-e.x);te.x-t.x));for(const e of s)e.blocks.sort(((e,t)=>e.getRelativeToSurfaceXY().y-t.getRelativeToSurfaceXY().y));return{cols:s,orphans:r,maxWidths:n}}getVariableUsesById(e){let t=[],o=this.getTopBlocks(!0);for(const n of o){let o=n.getDescendants();for(const n of o){let o=n.getVarModels();if(o)for(const s of o)s.getId()===e&&t.push(n)}}return t}doReplaceVariable(e,t,o){let n=this.getWorkspace(),s=n.getVariable(t,o);if(!s)return void alert(this.msg(\"var-not-exist\"));let i=s.getId();r.startUndoGroup(n);let a=this.getVariableUsesById(e);for(const e of a)try{\"\"===o?e.getField(\"VARIABLE\").setValue(i):e.getField(\"LIST\").setValue(i)}catch(e){}r.endUndoGroup(n)}getTopBlockIDs(){let e=this.getWorkspace().getTopBlocks(),t=new Set;for(const o of e)t.add(o.id);return t}beginDragOfNewBlocksNotInIDs(e){if(!this.addon.settings.get(\"enablePasteBlocksAtMouse\"))return;let t=this.getWorkspace().getTopBlocks();for(const o of t)if(!e.has(o.id)){let e={x:this.mouseXY.x,y:this.mouseXY.y};o.setIntersects(!0),this.domHelpers.triggerDragAndDrop(o.svgPath_,null,e)}}updateMousePosition(e){this.mouseXY.x=e.clientX,this.mouseXY.y=e.clientY}eventMouseMove(e){this.updateMousePosition(e)}eventKeyDown(e){const t=e=>{let t=this.costTabBody.querySelector(\"div[class*='sprite-selector-item_is-selected']\"),o=e?t.parentNode.previousSibling:t.parentNode.nextSibling;if(o){let e=o.closest(\"div[class*=gui_flex-wrapper]\");o.querySelector(\"div[class^='sprite-selector-item_sprite-name']\").click(),o.scrollIntoView({behavior:\"auto\",block:\"center\",inline:\"start\"}),e.scrollTop=0}};if(document.URL.indexOf(\"editor\")<=0)return;let o=e.ctrlKey||e.metaKey;if(\"ArrowLeft\"===e.key&&o){if(\"INPUT\"===document.activeElement.tagName)return;if(this.isCostumeEditor())return t(!0),e.cancelBubble=!0,e.preventDefault(),!0}if(\"ArrowRight\"===e.key&&o){if(\"INPUT\"===document.activeElement.tagName)return;if(this.isCostumeEditor())return t(!1),e.cancelBubble=!0,e.preventDefault(),!0}if(86===e.keyCode&&o&&!e.griff){let e=this.getTopBlockIDs();setTimeout((()=>{this.beginDragOfNewBlocksNotInIDs(e)}),10)}}eventCopyClick(e,t){let o=this.getWorkspace();if(e){e.select();let n=t?e.getNextBlock():null;n&&n.unplug(!1),document.dispatchEvent(new KeyboardEvent(\"keydown\",{keyCode:67,ctrlKey:!0})),(n||2===t)&&setTimeout((()=>{n&&o.undo(),2===t&&(r.startUndoGroup(o),e.dispose(!0),r.endUndoGroup(o))}),0)}}eventMouseDown(e){this.updateMousePosition(e)}eventMouseUp(e){this.updateMousePosition(e)}initInner(e){var t=this;let o=e.childNodes;this.codeTab&&o[0]!==this.codeTab&&this.domHelpers.unbindAllEvents(),this.codeTab=o[0],this.costTab=o[1],this.costTabBody=document.querySelector(\"div[aria-labelledby=\"+this.costTab.id+\"]\"),this.domHelpers.bindOnce(document,\"keydown\",(function(){return t.eventKeyDown(...arguments)}),!0),this.domHelpers.bindOnce(document,\"mousemove\",(function(){return t.eventMouseMove(...arguments)}),!0),this.domHelpers.bindOnce(document,\"mousedown\",(function(){return t.eventMouseDown(...arguments)}),!0),this.domHelpers.bindOnce(document,\"mouseup\",(function(){return t.eventMouseUp(...arguments)}),!0)}}class a{constructor(e,t,o){this.x=e,this.count=t,this.blocks=o}}const c={\"userscript.js\":async function(e){let{addon:t,console:o,msg:n,safeMsg:s}=e;new i(t,n,s).init()},\"icon--close.svg\":\"data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3LjQ4IDcuNDgiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MnB4O308L3N0eWxlPjwvZGVmcz48dGl0bGU+aWNvbi0tYWRkPC90aXRsZT48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIzLjc0IiB5MT0iNi40OCIgeDI9IjMuNzQiIHkyPSIxIi8+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iMSIgeTE9IjMuNzQiIHgyPSI2LjQ4IiB5Mj0iMy43NCIvPjwvc3ZnPg==\"}},1524:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return r}));var n=o(81),s=o(1466);const r={\"userscript.js\":async function(e){let{addon:t,console:o,msg:s}=e;const r=await t.tab.traps.getPaper(),i=await t.tab.waitForElement(\"[class^='paint-editor_canvas-container']\");try{if(!(\"colorIndex\"in t.tab.redux.state.scratchPaint.fillMode))return void o.error(\"Detected new paint editor; this will be supported in future versions.\")}catch(e){}const a=i[t.tab.traps.getInternalKey(i)].child.child.child.stateNode,c=[],l=e=>{const t=e.substr(1),o=parseInt(t,16);return[o>>16&255,o>>8&255,255&o]},d={enabled:t.settings.get(\"default\")&&!t.self.disabled,previous:+t.settings.get(\"previous\"),next:+t.settings.get(\"next\"),opacity:+t.settings.get(\"opacity\"),opacityStep:+t.settings.get(\"opacityStep\"),layering:t.settings.get(\"layering\"),mode:t.settings.get(\"mode\"),beforeTint:l(t.settings.get(\"beforeTint\")),afterTint:l(t.settings.get(\"afterTint\"))},u=()=>r.project.layers.find((e=>e.data.isBackgroundGuideLayer)).children[0].position;let p=0;const h=()=>++p,g=()=>{h();const e=r.project;if(!e)return;c.length=0;const t=e.layers;for(let e=t.length-1;e>=0;e--){const o=t[e];o.data.sa_isOnionLayer&&o.remove()}},m=()=>{const e=r.project;if(!e)return;const t=e.layers.find((e=>e.data.sa_isOnionLayer));if(t)if(\"front\"===d.layering)e.addLayer(t);else{0===e.layers.find((e=>e.data.isRasterLayer)).index?e.insertLayer(0,t):e.insertLayer(1,t)}},f=(e,t)=>{if(e.children)for(const o of e.children)f(o,t);t(e)},b=(e,t,o,n)=>{const s=n?d.beforeTint:d.afterTint,r=(e+t+o)/3/255/1.5+(1-1/1.5);return[s[0]*r,s[1]*r,s[2]*r]},y=(e,t)=>(e=>{let[t,o,n]=e;const s=Math.round(t).toString(16).padStart(2,\"0\"),r=Math.round(o).toString(16).padStart(2,\"0\"),i=Math.round(n).toString(16).padStart(2,\"0\");return\"#\".concat(s).concat(r).concat(i)})(b(255*e.red,255*e.green,255*e.blue,t)),k=(e,t)=>{const{width:o,height:n}=e.canvas,s=e.context,r=s.getImageData(0,0,o,n),i=r.data;for(let e=0;e{const t=e.strokeBounds,{width:o,height:n}=t,s=Math.min(3e3/o,3e3/n),i=new r.Raster(new r.Size(o,n));i.remove(),i.smoothing=!0,i.guide=!0,i.locked=!0;let a=0;const c=i.draw;return i.draw=function(){const i=this.getView().getZoom()*window.devicePixelRatio,l=Math.max(1,Math.min(s,2**Math.ceil(Math.log2(i))));if(l>a){a=l;const s=this.canvas,i=this.context,c=o*l,d=n*l;s.width=c,s.height=d,this._size=new r.Size(c,d);const u=t.getTopLeft(),p=t.getBottomRight(),h=new r.Size(p.subtract(u)),g=(new r.Matrix).scale(l).translate(u.negate());i.save(),g.applyToContext(i),e.draw(i,new r.Base({matrices:[g]})),i.restore(),this.matrix.reset(),this.transform((new r.Matrix).translate(u.add(h.divide(2))).scale(1/l))}for(var d=arguments.length,u=new Array(d),p=0;pnew Promise(((i,a)=>{o=n.sanitizeSvg.sanitizeSvgText(o);const{rotationCenterX:c,rotationCenterY:l}=t,p=(o=(o=o.split(/<\\s*svg:/).join(\"<\")).split(/<\\/\\s*svg:/).join(\"]*>/);p&&-1===p[0].indexOf(\"xmlns=\")&&(o=o.replace(\"{t?i((e=>{const t=[];return f(e,(e=>{e instanceof r.Raster&&t.push(new Promise(((t,o)=>{e.on(\"load\",(()=>t())),e.on(\"error\",(()=>o(new Error(\"Raster inside SVG failed to load\"))))})))})),Promise.all(t)})(t).then((()=>(t=>{if(t.opacity=e,f(t,(e=>{\"PathItem\"===e.className&&(e.clockwise=!0),\"PointText\"===e.className||e.children||e.strokeWidth&&(e.strokeWidth=2*e.strokeWidth),e.locked=!0,e.guide=!0})),t.scale(2,new r.Point(0,0)),\"tint\"===d.mode){const e=new Set;f(t,(t=>{if(t.strokeColor&&(t.strokeColor=y(t.strokeColor,s)),t.fillColor){const o=t.fillColor.gradient;if(o){if(e.has(o))return;e.add(o);for(const e of o.stops)e.color=y(e.color,s)}else t.fillColor=y(t.fillColor,s)}t.canvas&&k(t,s)}))}const o=u();if(void 0!==c&&void 0!==l){let e=new r.Point(c,l);g&&g.length>=2&&!isNaN(g[0])&&!isNaN(g[1])&&(e=e.subtract(g[0],g[1])),t.translate(o.subtract(e.multiply(2)))}else t.translate(o.subtract(t.bounds.width,t.bounds.height));return v(t)})(t)))):a(new Error(\"could not load onion skin\"))}})})),I=async()=>{const e=r.project;if(!e)return;const n=(()=>{const e=document.querySelector(\"[class*='selector_list-item'][class*='sprite-selector-item_is-selected']\");if(!e)return-1;const t=e.querySelector(\"[class*='sprite-selector-item_number']\");return t?+t.textContent-1:-1})();if(-1===n)return;g();const s=h(),i=t.tab.traps.vm;if(!i)return;const a=e.activeLayer,c=i.editingTarget.sprite.costumes,l=Math.max(0,n-d.previous),f=Math.min(c.length-1,n+d.next);try{const e=[];for(let t=l;t<=f;t++){if(t===n)continue;const o=t{let{index:t,isBefore:o,opacity:n}=e;const s=c[t],a=i.getCostume(t);if(\"svg\"===s.dataFormat)return w(n,s,a,o);if(\"png\"===s.dataFormat||\"jpg\"===s.dataFormat)return((e,t,o,n)=>new Promise(((s,i)=>{let{rotationCenterX:a,rotationCenterY:c}=t;const l=new Image;l.onload=()=>{const t=u(),o=Math.min(2*t.x,l.width),i=Math.min(2*t.y,l.height);void 0===a&&(a=o/2),void 0===c&&(c=i/2);const p=new r.Raster(l);p.opacity=e,p.guide=!0,p.locked=!0;const h=o/2+(t.x-a),g=i/2+(t.y-c);p.position=new r.Point(h,g),p.remove(),\"tint\"===d.mode&&k(p,n),s(p)},l.onerror=()=>{i(new Error(\"could not load image\"))},l.src=o})))(n,s,a,o);throw new Error(\"Unknown data format: \".concat(s.dataFormat))})));if(p===s){const e=(()=>{const e=new r.Layer;return e.locked=!0,e.guide=!0,e.data.sa_isOnionLayer=!0,e})();for(const o of t)e.addChild(o);m()}}catch(e){o.error(e)}a.activate()},T=e=>{d.enabled!==e&&(d.enabled=e,d.enabled?(0===d.next&&0===d.previous&&(d.previous=1,j.previous.value=d.previous),0===d.opacity&&(d.opacity=25,j.opacity.value=d.opacity),I()):g(),D.dataset.enabled=d.enabled)},x=e=>{0===d.previous&&0===d.next||0===d.opacity?T(!1):d.enabled?e?m():I():(d.previous>0||d.next>0)&&T(!0)},M=()=>{const e=document.createElement(\"div\");return e.className=\"sa-onion-group\",e},N=function(){let{useButtonTag:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};const t=document.createElement(e?\"button\":\"span\");return t.className=\"sa-onion-button\",t.setAttribute(\"role\",\"button\"),t},L=e=>{const o=document.createElement(\"img\");return o.className=\"sa-onion-image\",o.draggable=!1,o.dataset.image=e,o.loading=\"lazy\",o.src=t.self.getResource(\"/\"+e+\".svg\"),o},S=M();t.tab.displayNoneWhileDisabled(S,{display:\"flex\"});const D=N();D.dataset.enabled=d.enabled,D.addEventListener(\"click\",(()=>T(!d.enabled))),D.title=s(\"toggle\"),D.appendChild(L(\"toggle\"));const C=N();C.addEventListener(\"click\",(()=>A(!O()))),C.title=s(\"settings\"),C.appendChild(L(\"settings\")),document.body.addEventListener(\"click\",(e=>{O()&&!e.target.matches(\".sa-onion-group *\")&&A(!1)}));const _=document.createElement(\"div\");_.className=\"sa-onion-settings-wrapper\",S.append(_,D,C);const E=document.createElement(\"div\");E.className=\"sa-onion-settings\";const A=e=>{C.dataset.enabled=e,E.dataset.visible=e},O=()=>\"true\"===E.dataset.visible,j={};for(const e of[\"previous\",\"next\",\"opacity\",\"opacityStep\"]){const t=document.createElement(\"label\");t.className=\"sa-onion-settings-line\";const o=document.createElement(\"div\");o.className=\"sa-onion-settings-label\",o.textContent=s(e),t.appendChild(o);const n=M(),r=N(),i=document.createElement(\"div\");i.style.width=\"20px\",r.appendChild(i);const a=document.createElement(\"input\");j[e]=a,a.className=\"sa-onion-settings-input\",a.type=\"number\",a.step=\"1\",a.min=\"0\",a.max=\"100\",a.value=d[e],a.addEventListener(\"input\",(t=>{if(0===a.value.length)return d[e]=0,void x();let o=+a.value;o>+a.max?o=+a.max:o<0&&(o=0),a.value=o,d[e]=o,x()})),a.addEventListener(\"blur\",(()=>{a.value||(a.value=\"0\")})),r.appendChild(a);const c=N();c.appendChild(L(\"decrement\")),c.addEventListener(\"click\",(()=>{d[e]>0&&(d[e]--,a.value=d[e],x())}));const l=N();l.appendChild(L(\"increment\")),l.addEventListener(\"click\",(()=>{d[e]<+a.max&&(d[e]++,a.value=d[e],x())})),n.appendChild(c),n.appendChild(r),n.appendChild(l),t.appendChild(n),E.appendChild(t)}const z=document.createElement(\"div\");z.className=\"sa-onion-settings-line\";const B=document.createElement(\"div\");B.className=\"sa-onion-settings-label\",B.textContent=s(\"mode\");const R=M();z.appendChild(B);const W=N({useButtonTag:!0});W.appendChild(document.createTextNode(s(\"merge\"))),R.appendChild(W),W.addEventListener(\"click\",(e=>{d.mode=\"merge\",Z.dataset.enabled=!1,W.dataset.enabled=!0,x()})),W.dataset.enabled=\"merge\"===d.mode;const Z=N({useButtonTag:!0});Z.appendChild(document.createTextNode(s(\"tint\"))),R.appendChild(Z),Z.addEventListener(\"click\",(e=>{d.mode=\"tint\",Z.dataset.enabled=!0,W.dataset.enabled=!1,x()})),Z.dataset.enabled=\"tint\"===d.mode,z.appendChild(R),E.appendChild(z);const G=document.createElement(\"div\");G.className=\"sa-onion-settings-line\";const U=document.createElement(\"div\");U.className=\"sa-onion-settings-label\",U.textContent=s(\"layering\");const P=M();G.appendChild(U);const H=N({useButtonTag:!0});H.appendChild(document.createTextNode(s(\"front\"))),P.appendChild(H),H.addEventListener(\"click\",(e=>{d.layering=\"front\",Y.dataset.enabled=!1,H.dataset.enabled=!0,x(!0)})),H.dataset.enabled=\"front\"===d.layering;const Y=N({useButtonTag:!0});Y.appendChild(document.createTextNode(s(\"behind\"))),P.appendChild(Y),Y.addEventListener(\"click\",(e=>{d.layering=\"behind\",Y.dataset.enabled=!0,H.dataset.enabled=!1,x(!0)})),Y.dataset.enabled=\"behind\"===d.layering,G.appendChild(P),E.appendChild(G);const F=\"http://www.w3.org/2000/svg\",V=document.createElementNS(F,\"svg\");V.setAttribute(\"class\",\"sa-onion-settings-tip\"),V.setAttribute(\"width\",\"14\"),V.setAttribute(\"height\",\"7\");const X=document.createElementNS(F,\"polygon\");X.setAttribute(\"class\",\"sa-onion-settings-polygon\"),X.setAttribute(\"points\",\"0,0 7,7, 14,0\"),V.appendChild(X),E.appendChild(V);let J=null;t.self.addEventListener(\"disabled\",(()=>{A(!1),J=d.enabled,T(!1)})),t.self.addEventListener(\"reenabled\",(()=>{T(J)}));(()=>{const e=r.Project.prototype.addLayer;r.Project.prototype.addLayer=function(t){const o=e.call(this,t);if(t.data.isBackgroundGuideLayer){let t;for(;t=c.shift();)e.call(this,t);m()}return o};const t=r.Project.prototype.importJSON;r.Project.prototype.importJSON=function(e){const o=t.call(this,e);return d.enabled&&I(),o};const o=r.Layer.prototype.remove;r.Layer.prototype.remove=function(){if(this.data.isBackgroundGuideLayer){for(const e of r.project.layers)e.data.sa_isOnionLayer&&c.push(e);for(const e of c)e.remove()}return o.call(this)}})(),(()=>{let e=!1;const t=a.constructor,o=t.prototype.importImage;t.prototype.importImage=function(){e=!0,g();for(var t=arguments.length,n=new Array(t),s=0;s{t&&t(),e&&(e=!1,d.enabled&&I())}))},a.recalibrateSize=t.prototype.recalibrateSize.bind(a),a.importImage=t.prototype.importImage.bind(a)})(),(async()=>{let e=!1;for(;;){const o=(await t.tab.waitForElement(\"[class^='paint-editor_canvas-controls']\",{markAsSeen:!0,reduxEvents:[\"scratch-gui/navigation/ACTIVATE_TAB\",\"scratch-gui/mode/SET_PLAYER\",\"fontsLoaded/SET_FONTS_LOADED\",\"scratch-gui/locales/SELECT_LOCALE\",\"scratch-gui/targets/UPDATE_TARGET_LIST\"],reduxCondition:e=>1===e.scratchGui.editorTab.activeTabIndex&&!e.scratchGui.mode.isPlayerOnly})).querySelector(\"[class^='paint-editor_zoom-controls']\");if(t.tab.appendToSharedSpace({space:\"paintEditorZoomControls\",element:S,order:1}),_.appendChild(E),!e){e=!0;const t=o.firstChild.className,n=o.firstChild.firstChild.className,s=o.firstChild.firstChild.firstChild.className;for(const e of document.querySelectorAll(\".sa-onion-group\"))e.className+=\" \"+t;for(const e of document.querySelectorAll(\".sa-onion-button\"))e.className+=\" \"+n;for(const e of document.querySelectorAll(\".sa-onion-image\"))e.className+=\" \"+s}d.enabled&&I()}})()},\"style.css\":o.n(s).a,\"decrement.svg\":\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg==\",\"increment.svg\":\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjxwYXRoIHRyYW5zZm9ybT0icm90YXRlKDkwKSIgc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUtMTIuNjQyaDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg==\",\"settings.svg\":\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9Im9wYWNpdHk6Ljc1O2ZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgZD0iTTU2IDE2djk2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMi4zNzYgLTIuMzc2KSBzY2FsZSguMjI0NjIpIi8+PHBhdGggc3R5bGU9Im9wYWNpdHk6LjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNDAgMzJ2NjQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouMjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNMjQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNzU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNzIgMTZ2OTYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik04OCAzMnY2NCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIuMzc2IC0yLjM3Nikgc2NhbGUoLjIyNDYyKSIvPjxwYXRoIHN0eWxlPSJvcGFjaXR5Oi4yNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik0xMDQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48L3N2Zz4=\",\"toggle.svg\":\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggZmlsbD0iI2JmYmZiZiIgZD0iTTM5LjYzMi0uNTc2Yy4wNy0uMDQ2LjE4Ny0uMDIzLjIxLjA3bC42MDYgMi40OTJzMS40OSAxLjA5NSAxLjkzMyAxLjg2M2MuNzQ1IDEuMjgxLjc2OCAyLjMzLjc2OCAyLjMzczEuNjU0LjQ4OCAxLjkzMyAxLjgxNmMuMjggMS4zMjctLjc0NSAzLjg0My01LjEyMyA0LjcwNS00LjM3OS44NjEtNy44OTYtLjMyNy05LjU1LTIuOTgyLTEuNjUzLTIuNjU1Ljk1Ni01LjgyMi44MTYtNS42MzZsLS40OS00LjE2OWMtLjAyMy0uMDkzLjA5NC0uMTYzLjE4Ny0uMTE2bDIuODE4IDEuODRzMS4wNDgtLjM5NiAyLjE0My0uNDQzYTcuMDEgNy4wMSAwIDAgMSAxLjc0Ny4wOTN6IiBzdHlsZT0ib3BhY2l0eTouNTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTQ3LjM2NSA2LjUyOGMtMS4wOTUuODg1LTIuNzcyLjkwOC0yLjc3Mi45MDhtMi40NjkgMS43Yy0xLjQ2Ny4xMTctMi4zNzYtLjMyNi0yLjM3Ni0uMzI2TTI4LjY2MyA2LjQ1OHMyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNWMtMS4wMDIuMzk2LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ib3BhY2l0eTouNTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9IiNiZmJmYmYiIGQ9Ik00MS45NjEgMS43NTNjLjA3LS4wNDYuMTg3LS4wMjMuMjEuMDdsLjYwNiAyLjQ5MnMxLjQ5IDEuMDk1IDEuOTMzIDEuODYzYy43NDUgMS4yODEuNzY4IDIuMzMuNzY4IDIuMzNzMS42NTQuNDg4IDEuOTMzIDEuODE2Yy4yOCAxLjMyNy0uNzQ1IDMuODQzLTUuMTIzIDQuNzA1LTQuMzc5Ljg2MS03Ljg5Ni0uMzI3LTkuNTUtMi45ODItMS42NTMtMi42NTUuOTU2LTUuODIyLjgxNi01LjYzNmwtLjQ5LTQuMTY5Yy0uMDIzLS4wOTMuMDk0LS4xNjMuMTg3LS4xMTZsMi44MTggMS44NHMxLjA0OC0uMzk2IDIuMTQzLS40NDNhNy4wMSA3LjAxIDAgMCAxIDEuNzQ3LjA5M3oiIHN0eWxlPSJvcGFjaXR5Oi43NTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTQ5LjY5NCA4Ljg1N2MtMS4wOTUuODg1LTIuNzcyLjkwOC0yLjc3Mi45MDhtMi40NjkgMS43Yy0xLjQ2Ny4xMTctMi4zNzYtLjMyNi0yLjM3Ni0uMzI2TTMwLjk5MiA4Ljc4N3MyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNWMtMS4wMDIuMzk2LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ib3BhY2l0eTouNzU7bWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMTY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiLz48cGF0aCBmaWxsPSIjYmZiZmJmIiBkPSJNNDQuMjkgNC4wODJjLjA3LS4wNDcuMTg2LS4wMjQuMjEuMDdsLjYwNSAyLjQ5MnMxLjQ5IDEuMDk0IDEuOTMzIDEuODYzYy43NDUgMS4yOC43NjkgMi4zMjkuNzY5IDIuMzI5czEuNjUzLjQ4OSAxLjkzMyAxLjgxNmMuMjggMS4zMjgtLjc0NSAzLjg0My01LjEyNCA0LjcwNS00LjM3OC44NjItNy44OTUtLjMyNi05LjU0OS0yLjk4MS0xLjY1My0yLjY1NS45NTUtNS44MjMuODE1LTUuNjM2bC0uNDg5LTQuMTdjLS4wMjMtLjA5Mi4wOTMtLjE2Mi4xODctLjExNmwyLjgxOCAxLjg0czEuMDQ4LS4zOTYgMi4xNDItLjQ0MmE3LjAxIDcuMDEgMCAwIDEgMS43NDcuMDkzeiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiNmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDEwMjY7c3Ryb2tlLXdpZHRoOi45MzE2O3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNTIuMDIyIDExLjE4NWMtMS4wOTQuODg1LTIuNzcxLjkwOC0yLjc3MS45MDhtMi40NjggMS43Yy0xLjQ2Ny4xMTctMi4zNzUtLjMyNS0yLjM3NS0uMzI1TTMzLjMyIDExLjExNXMyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNmMtMS4wMDEuMzk1LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMTY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiLz48ZyBzdHlsZT0ib3BhY2l0eTouMTg5ODU0Ij48cGF0aCBkPSJNMS4yNDMgOC41YS42MzcuNjM3IDAgMCAwLS40NSAxLjA4NmwuMy4zYy4yNDItLjM1Mi41NDYtLjY1OC44OTgtLjlsLS4yOTctLjNhLjYzNi42MzYgMCAwIDAtLjQ1LS4xODVaIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC4wNCAtMi42NDcpIi8+PHBhdGggZD0iTTE1LjExNCAxOS41MDZhMy41MDEgMy41MDEgMCAxIDEtNy4wMDMgMCAzLjUwMSAzLjUwMSAwIDAgMSA3LjAwMyAwem0tNy4zOTItNy4zMThhMy41IDMuNSAwIDEgMCAuNDA2IDYuOTg1IDMuNSAzLjUgMCAwIDEgMy4xNS0zLjE1IDMuNSAzLjUgMCAwIDAtMy41NTYtMy44MzV6bS0zLjc0Ni0zLjgyYTMuNTAxIDMuNTAxIDAgMSAwIC4zMzYgNi45ODQgMy41MDIgMy41MDIgMCAwIDEgMy4xNDgtMy4xNDggMy41IDMuNSAwIDAgMC0zLjQ4NC0zLjgzNnoiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjA0IC0yLjY0NykiLz48cGF0aCBkPSJNMTQuNDk3IDIxLjQ5MWMtLjI0My4zNTItLjU1LjY1Ni0uOTAyLjg5OWwzLjA4NCAzLjA4NGEuNjM4LjYzOCAwIDAgMCAuOSAwIC42MzcuNjM3IDAgMCAwIDAtLjl6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC4wNCAtMi42NDcpIi8+PC9nPjxnIHN0eWxlPSJvcGFjaXR5Oi44MDU1MyI+PGcgc3R5bGU9Im9wYWNpdHk6LjU4NTkyOCI+PHBhdGggZD0iTTEuMjQzIDguNWEuNjM3LjYzNyAwIDAgMC0uNDUgMS4wODZsLjMuM2MuMjQyLS4zNTIuNTQ2LS42NTguODk4LS45bC0uMjk3LS4zYS42MzYuNjM2IDAgMCAwLS40NS0uMTg1WiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiMwMDEwMjY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOi4xOTY0OTI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzQ5NiAwIDAgMS4wMzQ5NiAyLjc3NSAtNS4xNykiLz48cGF0aCBkPSJNMTUuMTE0IDE5LjUwNmEzLjUwMSAzLjUwMSAwIDEgMS03LjAwMyAwIDMuNTAxIDMuNTAxIDAgMCAxIDcuMDAzIDB6bS03LjM5Mi03LjMxOGEzLjUgMy41IDAgMSAwIC40MDYgNi45ODUgMy41IDMuNSAwIDAgMSAzLjE1LTMuMTUgMy41IDMuNSAwIDAgMC0zLjU1Ni0zLjgzNXptLTMuNzQ2LTMuODJhMy41MDEgMy41MDEgMCAxIDAgLjMzNiA2Ljk4NCAzLjUwMiAzLjUwMiAwIDAgMSAzLjE0OC0zLjE0OCAzLjUgMy41IDAgMCAwLTMuNDg0LTMuODM2eiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiMwMDEwMjY7c3Ryb2tlLXdpZHRoOi45MzI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzQ5NiAwIDAgMS4wMzQ5NiAyLjc3NSAtNS4xNykiLz48cGF0aCBkPSJNMTQuNDk3IDIxLjQ5MWMtLjI0My4zNTItLjU1LjY1Ni0uOTAyLjg5OWwzLjA4NCAzLjA4NGEuNjM4LjYzOCAwIDAgMCAuOSAwIC42MzcuNjM3IDAgMCAwIDAtLjl6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IDIuNzc1IC01LjE3KSIvPjwvZz48L2c+PHBhdGggZmlsbD0iI2Q5OWU4MiIgZD0iTTIxLjkwNyAxOS4xM2EuNjM2LjYzNiAwIDAgMS0uNDUtLjE4NUw1LjU3MiAzLjA1OGEuNjM3LjYzNyAwIDAgMSAuOS0uOWwxNS44ODUgMTUuODg2YS42MzcuNjM3IDAgMCAxLS40NSAxLjA4N3oiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojMDAxMDI2O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDouMTk2NDkyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjYxNyAtMS4zMykiLz48cGF0aCBmaWxsPSIjZmNiMWUzIiBkPSJNMTIuMjUzIDUuMzRhMy41IDMuNSAwIDEgMS03IDAgMy41IDMuNSAwIDAgMSA3IDB6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6I2ZlZmVmZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PHBhdGggZmlsbD0iI2ZmZDk4MyIgZD0iTTExLjc2OCAxMi41NjZhMy41IDMuNSAwIDEgMSAxLjYxLTYuODEzIDMuNSAzLjUgMCAwIDEtMS42MSA2LjgxM3oiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojZmVmZWZkO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjYxNyAtMS4zMykiLz48cGF0aCBmaWxsPSIjYTZkMzg4IiBkPSJNMTkuODkyIDEyLjk3N2EzLjUwMSAzLjUwMSAwIDEgMS03LjAwMyAwIDMuNTAxIDMuNTAxIDAgMCAxIDcuMDAzIDB6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6I2ZlZmVmZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PHBhdGggZmlsbD0iI2Q5OWU4MiIgZD0iTTIxLjkwNyAxOS4xM2EuNjM2LjYzNiAwIDAgMS0uNDUtLjE4NWwtMy44OTgtMy45YS42MzYuNjM2IDAgMSAxIC45LS45bDMuODk4IDMuOWEuNjM3LjYzNyAwIDAgMS0uNDUgMS4wODZ6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PC9zdmc+\"}},1525:function(e,t,o){\"use strict\";var n;function s(e,t,o){return(t=function(e){var t=function(e,t){if(\"object\"!=typeof e||!e)return e;var o=e[Symbol.toPrimitive];if(void 0!==o){var n=o.call(e,t||\"default\");if(\"object\"!=typeof n)return n;throw new TypeError(\"@@toPrimitive must return a primitive value.\")}return(\"string\"===t?String:Number)(e)}(e,\"string\");return\"symbol\"==typeof t?t:t+\"\"}(t))in e?Object.defineProperty(e,t,{value:o,enumerable:!0,configurable:!0,writable:!0}):e[t]=o,e}o.r(t),o.d(t,\"resources\",(function(){return $}));const r=0,i=1,a=2,c=3,l=4,d=5;class u{constructor(e,t,o){if(this.constructor===u)throw new Error(\"Abstract classes can't be instantiated.\");this.type=e,this.inputIdx=t,this.fieldIdx=o,this.defaultValue=null}setValue(e,t){throw new Error(\"Sub-class must override abstract method.\")}getInput(e){return e.inputList[this.inputIdx]}getField(e){return-1===this.fieldIdx?this.getInput(e).connection.targetBlock().inputList[0].fieldRow[0]:this.getInput(e).fieldRow[this.fieldIdx]}}class p extends u{constructor(e,t,o,n){if(super(e,t,o),this.constructor===p)throw new Error(\"Abstract classes can't be instantiated.\");this.defaultValue=n}setValue(e,t){if(t instanceof k){const o=t.createWorkspaceForm();if(!o.outputConnection)throw new Error('Cannot put block \"'+o.typeInfo.id+'\" into a round type input.');o.outputConnection.connect(this.getInput(e).connection)}else this.getField(e).setValue(this._toFieldValue(t))}_toFieldValue(e){throw new Error(\"Sub-class must override abstract method.\")}}class h extends p{constructor(e,t,o){super(r,e,t,o)}_toFieldValue(e){const t=typeof e;if(\"number\"===t)return e;if(\"string\"===t)return e;throw new Error(\"Cannot set round type input to value of type \"+t)}}class g extends p{constructor(e,t,o){super(i,e,t,o)}_toFieldValue(e){const t=typeof e;if(\"number\"===t)return e;if(\"string\"===t){if(0===e.length)return e;const t=parseFloat(e);if(isNaN(t))throw new Error('Cannot set numeric type input to string \"'+e+'\".');return e}throw new Error(\"Cannot set round type input to value of type \"+t)}}class m extends u{constructor(e,t){super(a,e,t)}setValue(e,t){if(!(t instanceof k))throw new Error(\"Boolean type inputs can only contain blocks.\");{const o=t.createWorkspaceForm();if(!o.outputConnection||t.typeInfo.shape!==v.Boolean)throw new Error('Cannot put block \"'+t.typeInfo.id+'\" into a boolean type input.');o.outputConnection.connect(this.getInput(e).connection)}}}class f extends u{constructor(e,t){super(c,e,t)}setValue(e,t){if(\"string\"!=typeof t)throw new Error(\"Cannot set color type input to value of type \"+typeof type);if(!t.match(/^#[0-9a-fA-F]{6}$/))throw new Error('Invalid color \"'+t+'\".');this.getField(e).setValue(t)}}class b extends u{constructor(e,t,o,n){super(l,t,o),this.values=[];for(let t=0;t1?t-1:0),n=1;n{i.push(e),a.push(e)},l=(e,t,s)=>{if(\"blocklyText blocklyDropdownText\"===e.className_){const o=e.getOptions();c(new b(o,t,s,-1===s))}else if(e instanceof o.FieldImage)switch(e.src_.split(\"/\").pop()){case\"green-flag.svg\":i.push(n(\"/_general/blocks/green-flag\"));break;case\"rotate-right.svg\":i.push(n(\"/_general/blocks/clockwise\"));break;case\"rotate-left.svg\":i.push(n(\"/_general/blocks/anticlockwise\"))}else e.argType_?\"colour\"===e.argType_[0]?c(new f(t,s)):\"number\"===e.argType_[1]?c(new g(t,s,e.text_)):c(new h(t,s,e.text_)):0!==e.getText().trim().length&&i.push(e.getText())};for(let e=0;e<(null===(d=s.inputList)||void 0===d?void 0:d.length);e++){var d;const t=s.inputList[e];for(let o=0;o[e,e])).concat(g)}else{f=t.runtime.getSpriteTargetByName(a.value).getAllVariableNamesInScopeByType(\"\",!0).map((e=>[e,e])).concat(m)}const k=[];k[n]=new b(f,d.inputIdx,d.fieldIdx,!1),k[c]=new b([[a.string,a.value]],u.inputIdx,u.fieldIdx,y);const v=[...i];v[p]=k[n],v[h]=k[c],l.push(new w(e,o,t,s,r,v,k))}return l}if(\"control_stop\"===s.id){const n=a[0],c=n.values.findIndex((e=>\"other scripts in sprite\"===e.string)),l=n.values.splice(c,1)[0],d=new b([[l.string,l.value]],n.inputIdx,n.fieldIdx,n.isRound),u=[...i];return u[i.indexOf(n)]=d,[new w(e,o,t,s,r,i,a,v.End),new w(e,o,t,s,r,u,[d],v.Stack)]}return[new w(e,o,t,s,r,i,a)]}constructor(e,t,o,n,s,r,i,a){this.id=n.id,this.workspaceForm=n,this.domForm=s,this.shape=null!=a?a:v.getBlockShape(this.workspaceForm),this.category=w.getBlockCategory(this.workspaceForm,o),this.workspace=e,this.Blockly=t,this.parts=r,this.inputs=i}createBlock(){for(var e=arguments.length,t=new Array(e),o=0;o4&&void 0!==arguments[4]?arguments[4]:{};this.start=e,this.end=t,this.type=o,this.value=n,this.precedence=s,this.isProper=r,this.isTruncated=i,this.isLegal=a,this.isDefiningFeature=c}createBlockValue(e){return this.type.createBlockValue(this,e)}}class N{constructor(e){if(this.constructor===N)throw new Error(\"Abstract classes can't be instantiated.\");this.shouldCache=e}*parseTokens(e,t,o){throw new Error(\"Sub-class must override abstract method.\")}}class L extends N{constructor(e){super(e.shouldCache),this.inner=e}*parseTokens(e,t,o){yield _.INSTANCE.createToken(t),yield*this.inner.parseTokens(e,t,o)}}class S extends N{constructor(e){super(!1),this.inner=e,this.inner.shouldCache&&(this.cache=[],this.cacheQueryID=null)}*parseTokens(e,t,o){if(!this.inner.shouldCache)return void(yield*this.inner.parseTokens(e,t,o));this.cacheQueryID!==e.id&&(this.cache=[],this.cacheQueryID=e.id);let n=this.cache[t];if(n)yield*n;else{this.cache[t]=n=[];for(const s of this.inner.parseTokens(e,t,o))n.push(s),yield s}}}class D extends N{constructor(){super(!1),this.providers=[],this.illegalProviders=[],this.cache=null,this.cacheQueryID=null,this.hasCacheable=!1}pushProviders(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];if(!this.hasCacheable)for(const t of e)if(t.shouldCache){this.hasCacheable=!0;break}t?this.providers.push(...e):this.illegalProviders.push(...e)}*parseTokens(e,t,o){if(!this.hasCacheable){for(const n of this.providers)yield*n.parseTokens(e,t,o);return}if(this.cacheQueryID!==e.id)this.cache=[],this.cacheQueryID=e.id;else{const n=this.cache[t];if(n){const s=n.tokenCaches,r=n.providerCaches;for(let n=0;n0&&void 0!==arguments[0]&&arguments[0])),this.constructor===C)throw new Error(\"Abstract classes can't be instantiated.\");this.isConstant=!1}createBlockValue(e,t){return e.value}createText(e,t,o){throw new Error(\"Sub-class must override abstract method.\")}getSubtokens(e,t){}}class _ extends C{constructor(){super(),this.isConstant=!0}*parseTokens(e,t,o){yield this.createToken(t)}createToken(e){return new M(e,e,this,null)}createText(e,t){return\"\"}}x(_,\"INSTANCE\",new _);class E extends C{constructor(e){super(),this.isConstant=1===e.length,this.values=[];for(const t of e){let e=t.string.toLowerCase();const o=[];{let t=0;for(let n=0;n<=e.length;n++){const s=e[n];-1===W.IGNORABLE_CHARS.indexOf(s)&&s||(o.push(e.substring(t,n)),n=W.skipIgnorable(e,n),t=n)}}this.values.push({lower:e,parts:o,value:t})}}*parseTokens(e,t,o){for(let o=0;o\",\")\"]);class O extends C{static isValidNumber(e){return!isNaN(+e)||!isNaN(parseFloat(+e))}*parseTokens(e,t,o){for(let o=t;o<=e.length;o++)if(A.isTerminator(e.str[o])&&o!==t){const n=e.str.substring(t,o);if(O.isValidNumber(n)){yield new M(t,o,this,n);break}}}createText(e,t,o){return t.str.substring(e.start,e.end)}}class j extends C{*parseTokens(e,t,o){if(e.str.startsWith(\"#\",t)){for(let o=0;o<6;o++)if(-1===j.HEX_CHARS.indexOf(e.lowercase[t+o+1]))return;yield new M(t,t+7,this,e.str.substring(t,t+7))}}createText(e,t,o){return t.query.substring(e.start,e.end)}}x(j,\"INSTANCE\",new L(new j)),x(j,\"HEX_CHARS\",[\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]);class z extends C{constructor(e){super(),this.tokenProvider=e}*parseTokens(e,t,o){const n=t;if(\"(\"===e.str[t++]){t=e.skipIgnorable(t);for(const r of this.tokenProvider.parseTokens(e,t,o)){if(r.type instanceof _)continue;var s=e.skipIgnorable(r.end);let t=r.isTruncated;if(!t)if(s===e.length)t=!0;else{if(\")\"!==e.str[s])continue;++s}const o=new M(n,s,this,r.value,{precedence:0,isTruncated:t,isLegal:r.isLegal});o.innerToken=r,yield o}}}createBlockValue(e,t){return e.innerToken.createBlockValue(e.innerToken,t)}createText(e,t,o){let n=\"(\";return n+=t.str.substring(e.start+1,e.innerToken.start),n+=e.innerToken.type.createText(e.innerToken,t,o),e.innerToken.end!==e.end&&(n+=t.str.substring(e.innerToken.end,e.end-1)),n+=\")\",n}getSubtokens(e,t){return[e.innerToken]}}class B extends C{constructor(e,t){var o;super(),o=this,this.block=t,this.hasSubTokens=!0,this.fullTokenProviders=[];for(const o of t.parts){let t;if(\"string\"==typeof o)t=new E([{value:null,string:o}]);else switch(o.type){case l:if(t=new E(o.values),o.isRound){const o=new D;o.pushProviders([t,e.tokenGroupRoundBlocks]),t=o}break;case r:t=e.tokenGroupString;break;case i:t=e.tokenGroupNumber;break;case c:t=j.INSTANCE;break;case a:t=e.tokenGroupBoolean;break;case d:t=e.tokenGroupStack}this.fullTokenProviders.push(t)}this.stringForms=[];const n=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0;for(;e=Z.MAX_RESULTS)return;n(e+1,[...s,...t.string.toLowerCase().split(\" \")],[...r,t],i+t.string.length)}return}r.push(null)}}o.stringForms.push({strings:s,inputs:r,length:i})};n(),this.stringForms.length>=Z.MAX_STRING_FORMS&&(console.warn(\"Warning: Block '\"+this.block.id+\"' has too many string forms. Search results may not be very good.\"),this.stringForms.length=0)}*parseTokens(e,t,o){if(0!==o&&!e.canCreateMoreNestedBlocks())return;let n=!1;for(const o of this._parseSubtokens(e,t,this.fullTokenProviders)){let s=this._createToken(e,t,this.fullTokenProviders,o);s&&(yield s,n=!0)}if(!n)e:for(const o of this.stringForms){let n=-1,s=t,r=!1;for(;;){s=e.skipIgnorable(s);const i=e.skipUnignorable(s);if(i===s){r&&(yield new M(t,i,this,{stringForm:o,lastPartIdx:-1},{isProper:!1}));break}{const a=e.lowercase.substring(s,i);let c=-1;for(let e=n+1;e4&&void 0!==arguments[4]?arguments[4]:0,i=!(arguments.length>5&&void 0!==arguments[5])||arguments[5];return function*(){t=e.skipIgnorable(t);let a=o[r];for(const c of a.parseTokens(e,t,n+1)){if(++e.tokenCount,!e.canCreateMoreTokens())break;if(0!==n&&!e.canCreateMoreNestedBlocks())break;if(-1!==s.block.precedence){if(c.precedence>s.block.precedence&&(0===r||!(c.type instanceof B)||\"operator_not\"!==c.type.block.id))continue;if(c.precedence===s.block.precedence){if(0!==s.block.parts[r].inputIdx)continue}}if(i&&c.isLegal&&r!==o.length-1)for(const t of s._parseSubtokens(e,c.end,o,n,r+1,!c.isTruncated))t.push(c),yield t;else yield[c]}}()}createBlockValue(e,t){if(!e.isLegal)throw new Error(\"Cannot create a block from an illegal token.\");let o;if(e.value.stringForm)o=e.value.stringForm.inputs;else{const n=e.value.subtokens;o=[];for(let e=0;e=t.length)break;const c=null!==(i=a.type.createText(a,t,o))&&void 0!==i?i:\"\";if(r+=c,s!==n.length-1){const e=n[s+1].start;e!==a.end?r+=t.str.substring(a.end,e):(!o||e>=t.length)&&0!==c.length&&-1===W.IGNORABLE_CHARS.indexOf(c.at(-1))&&(r+=\" \")}}return r}getSubtokens(e,t){return e.value.subtokens}}class R{constructor(e,t){this.query=e,this.token=t}get isTruncated(){return this.token.isTruncated}toText(e){var t;return null!==(t=this.token.type.createText(this.token,this.query,e))&&void 0!==t?t:\"\"}getBlock(){return this.block||(this.block=this.token.createBlockValue(this.query)),this.block}getLengths(){if(this.lengths)return this.lengths;let e=0,t=0;const o=n=>{let s=0;for(const r of n.typeInfo.parts)if(++t,\"string\"==typeof r)e+=r.length;else{const t=n.inputs[s++];t instanceof k?o(t):r instanceof b?e+=t.string.length:r instanceof h&&t!==r.defaultValue?e+=100*(\"\"+t).length:null!=t&&(e+=(\"\"+t).length)}e+=n.typeInfo.parts.length-1};return o(this.getBlock()),this.lengths={stringLength:e,tokenLength:t}}}class W{constructor(e,t,o){this.querier=e,this.str=t.replace(/\\u00a0/g,\" \"),this.lowercase=this.str.toLowerCase(),this.id=o,this.tokenCount=0,this.resultCount=0}static skipIgnorable(e,t){for(;-1!==W.IGNORABLE_CHARS.indexOf(e[t]);)++t;return t}skipIgnorable(e){return W.skipIgnorable(this.lowercase,e)}static skipUnignorable(e,t){for(;-1===W.IGNORABLE_CHARS.indexOf(e[t])&&t=e.length)if(i.isLegal)o.push(new R(t,i));else{const e=i.type.createText(i,t,!0);(!s||e.length=Z.MAX_RESULTS&&(console.warn(\"Warning: Workspace query exceeded maximum result count.\"),n=!0),!t.canCreateMoreTokens()){console.warn(\"Warning: Workspace query exceeded maximum token count.\"),n=!0;break}}const i=Array(e.length).fill(!0);function a(e){const o=e.type.getSubtokens(e,t);if(o)for(const e of o)a(e);else if(!(e.type instanceof A)&&e.isProper&&!e.isTruncated)for(let t=e.start;t{const o=e.getLengths(),n=t.getLengths();return o.stringLength!=n.stringLength?o.stringLength-n.stringLength:o.tokenLength-n.tokenLength})),{results:l,illegalResult:0===l.length?s:null,limited:n}}_createTokenGroups(){this.tokenTypeStringLiteral=new S(new A),this.tokenTypeNumberLiteral=new S(new O),this.tokenGroupRoundBlocks=new D,this.tokenGroupBooleanBlocks=new D,this.tokenGroupStackBlocks=new D,this.tokenGroupHatBlocks=new D,this.tokenGroupBoolean=new L(new D),this.tokenGroupBoolean.inner.pushProviders([this.tokenGroupBooleanBlocks,new z(this.tokenGroupBoolean)]),this.tokenGroupBoolean.inner.pushProviders([this.tokenGroupRoundBlocks],!1),this.tokenGroupNumber=new L(new D),this.tokenGroupNumber.inner.pushProviders([this.tokenTypeNumberLiteral,this.tokenGroupRoundBlocks,this.tokenGroupBooleanBlocks,new z(this.tokenGroupNumber)]),this.tokenGroupString=new L(new D),this.tokenGroupString.inner.pushProviders([this.tokenTypeStringLiteral,this.tokenGroupRoundBlocks,this.tokenGroupBooleanBlocks,new z(this.tokenGroupString)]),this.tokenGroupStack=new L(this.tokenGroupStackBlocks),this.tokenGroupBlocks=new D,this.tokenGroupBlocks.pushProviders([this.tokenGroupStackBlocks,this.tokenGroupBooleanBlocks,this.tokenGroupRoundBlocks,this.tokenGroupHatBlocks])}_populateTokenGroups(e){for(const t of e)t.precedence=Z.ORDER_OF_OPERATIONS.indexOf(t.id);for(let t=e.length-1;t>=0;t--){const o=e[t];if(-1!==o.precedence){const n=e.length-(Z.ORDER_OF_OPERATIONS.length-(o.precedence-1));if(t!==n){const s=e[n];e[n]=o,e[t]=s}}}for(const t of e){const e=new B(this,t);switch(t.shape){case v.Round:this.tokenGroupRoundBlocks.pushProviders([e]);break;case v.Boolean:this.tokenGroupBooleanBlocks.pushProviders([e]);break;case v.Stack:case v.End:this.tokenGroupStackBlocks.pushProviders([e]);break;case v.Hat:this.tokenGroupHatBlocks.pushProviders([e])}}}clearWorkspaceIndex(){this.workspaceIndexed=!1,this._destroyTokenGroups()}_destroyTokenGroups(){this.tokenTypeStringLiteral=null,this.tokenTypeNumberLiteral=null,this.tokenGroupBooleanBlocks=null,this.tokenGroupRoundBlocks=null,this.tokenGroupStackBlocks=null,this.tokenGroupHatBlocks=null,this.tokenGroupBoolean=null,this.tokenGroupNumber=null,this.tokenGroupString=null,this.tokenGroupStack=null,this.tokenGroupBlocks=null}}x(Z,\"ORDER_OF_OPERATIONS\",[null,\"operator_join\",\"operator_round\",\"operator_mathop\",\"operator_mod\",\"operator_divide\",\"operator_multiply\",\"operator_subtract\",\"operator_add\",\"operator_equals\",\"operator_lt\",\"operator_gt\",\"operator_or\",\"operator_and\",\"operator_not\"]),x(Z,\"MAX_RESULTS\",2e3),x(Z,\"MAX_TOKENS\",1e5),x(Z,\"MAX_STRING_FORMS\",500);var G=o(1383);const U=\"http://www.w3.org/2000/svg\",P={Round:{padding:12,minWidth:20,backgroundPath:e=>\"m -12 -20 m 20 0 h \".concat(e-16,\" a 20 20 0 0 1 0 40 H 8 a 20 20 0 0 1 0 -40 z\"),snugglePadding:0,get snuggleWith(){return[P.Round]}},Boolean:{padding:20,minWidth:20,backgroundPath:e=>\"m -20 -20 m 20 0 h \".concat(e,\" l 20 20 l -20 20 H 0 l -20 -20 l 20 -20 z\"),snugglePadding:0,get snuggleWith(){return[P.Boolean]}},SquareInput:{padding:8,minWidth:20,backgroundPath:e=>\"m -2 -16 h \".concat(e+4,\" a 4 4 0 0 1 4 4 V 12 a 4 4 0 0 1 -4 4 H -2 a 4 4 0 0 1 -4 -4 V -12 a 4 4 0 0 1 4 -4\")},Stack:{padding:8,minWidth:60,backgroundPath:e=>\"m -8 -20 A 4 4 0 0 1 -4 -24 H 4 c 2 0 3 1 4 2 l 4 4 c 1 1 2 2 4 2 h 12 c 2 0 3 -1 4 -2 l 4 -4 C 37 -23 38 -24 40 -24 H \".concat(e,\" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H 40 c -2 0 -3 1 -4 2 l -4 4 c -1 1 -2 2 -4 2 h -12 c -2 0 -3 -1 -4 -2 l -4 -4 c -1 -1 -2 -2 -4 -2 H -4 a 4 4 0 0 1 -4 -4 z\")},Hat:{padding:8,minWidth:60,backgroundPath:e=>\"m -8 -20 A 4 4 0 0 1 -4 -24 H \".concat(e,\" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H 40 c -2 0 -3 1 -4 2 l -4 4 c -1 1 -2 2 -4 2 h -12 c -2 0 -3 -1 -4 -2 l -4 -4 c -1 -1 -2 -2 -4 -2 H -4 a 4 4 0 0 1 -4 -4 z\")},End:{padding:8,minWidth:60,backgroundPath:e=>\"m -8 -20 A 4 4 0 0 1 -4 -24 H 4 c 2 0 3 1 4 2 l 4 4 c 1 1 2 2 4 2 h 12 c 2 0 3 -1 4 -2 l 4 -4 C 37 -23 38 -24 40 -24 H \".concat(e,\" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H -4 a 4 4 0 0 1 -4 -4 z\")},TextInput:{padding:12,minWidth:16,backgroundPath:e=>\"m -12 -16 m 16 0 h \".concat(e-8,\" a 16 16 0 0 1 0 32 H 4 a 16 16 0 0 1 0 -32 z\"),snugglePadding:4,get snuggleWith(){return[P.Round]}},BooleanInput:{padding:16,minWidth:16,backgroundPath:e=>\"m 0 -16 h \".concat(e,\" l 16 16 l -16 16 h -16 l -16 -16 l 16 -16 z\"),snugglePadding:6,get snuggleWith(){return[P.Boolean]}},HorizontalBlock:{padding:16,minWidth:45,backgroundPath:e=>\"M -4 -20 a 4 4 0 0 1 4 -4 H \".concat(e+8,\" a 4 4 0 0 1 4 4 v 2 c 0 2 -1 3 -2 4 l -4 4 c -1 1 -2 2 -2 4 v 12 c 0 2 1 3 2 4 l 4 4 c 1 1 2 2 2 4 v 2 a 4 4 0 0 1 -4 4 H 0 a 4 4 0 0 1 -4 -4 v -2 c 0 -2 -1 -3 -2 -4 l -4 -4 c -1 -1 -2 -2 -2 -4 v -12 c 0 -2 1 -3 2 -4 l 4 -4 c 1 -1 2 -2 2 -4 z\")},HorizontalBlockEnd:{padding:16,minWidth:45,backgroundPath:e=>\"M -4 -20 a 4 4 0 0 1 4 -4 H \".concat(e+8,\" a 4 4 0 0 1 4 4 V 20 a 4 4 0 0 1 -4 4 H 0 a 4 4 0 0 1 -4 -4 v -2 c 0 -2 -1 -3 -2 -4 l -4 -4 c -1 -1 -2 -2 -2 -4 v -12 c 0 -2 1 -3 2 -4 l 4 -4 c 1 -1 2 -2 2 -4 z\")}};function H(e){switch(e.typeInfo.shape){case v.End:case v.Hat:case v.Stack:return 62;case v.Boolean:case v.Round:return 48}return 0}class Y{constructor(e,t,o,n,s){this.dom=e,this.padding=t,this.width=o,this.snuggleWith=n,this.snugglePadding=s}}function F(e,t,o){let n=o.appendChild(document.createElementNS(U,\"text\"));return n.setAttribute(\"class\",\"blocklyText\"),n.style.fill=\"var(\".concat(t,\")\"),n.setAttribute(\"dominant-baseline\",\"middle\"),n.setAttribute(\"dy\",1),n.appendChild(document.createTextNode(e)),new Y(n,0,Object(G.b)(n))}function V(){let e=document.createElementNS(U,\"g\"),t=document.createElementNS(U,\"path\");return t.setAttribute(\"class\",\"blocklyPath\"),e.appendChild(t),e}function X(e,t,o,n,s,r){r{b={x:e.clientX,y:e.clientY}})),document.addEventListener(\"mousedown\",(e=>{b={x:e.clientX,y:e.clientY}}),{capture:!0}),Object(G.c)(E);let y=[],k=null,v=0,I=null,T=!1,x=!0,M=null,N=null,L=0,S=0,D=0,C=0;function _(){t.self.disabled||\"editor\"===t.tab.editorMode&&0===t.tab.redux.state.scratchGui.editorTab.activeTabIndex&&(I=w.getBlocks(s,r,s.getMainWorkspace(),o),f.indexWorkspace([...I]),I.sort(((e,t)=>{const o=e=>[\"operators\",\"data\"].indexOf(e.category.name)-e.id.startsWith(\"data_\");return o(t)-o(e)})),D=5e-5*window.innerWidth+t.settings.get(\"popup_scale\")/100,L=window.innerWidth*t.settings.get(\"popup_width\")/100,C=window.innerHeight*t.settings.get(\"popup_max_height\")/100,a.style.width=L+\"px\",N={x:b.x,y:b.y},i.style.display=\"\",d.value=\"\",d.focus(),A())}function E(){x&&(N=null,M=null,i.style.display=\"none\",I=null,f.clearWorkspaceIndex())}function A(){const e=[];if(0===d.value.trim().length){if(k=null,I)for(const t of I)e.push({block:t.createBlock()});T=!1}else{const t=f.queryWorkspace(d.value),o=t.results;k=t.illegalResult,T=t.limited,o.length>50&&(o.length=50);for(const t of o)e.push({block:t.getBlock(),autocompleteFactory:e=>t.toText(e)})}for(;m.firstChild;)m.removeChild(m.lastChild);y.length=0;let t=0;for(let n=0;n{O(n)},i=e=>{e.stopPropagation(),e.preventDefault(),O(n),x=!e.shiftKey,B(),x=!0,e.shiftKey&&d.focus()},a=m.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\",\"rect\")),c=H(s.block);a.setAttribute(\"transform\",\"translate(0, \".concat((t+c/10)*D,\")\")),a.setAttribute(\"height\",c*D+\"px\"),a.classList.add(\"sa-mcp-preview-block-bg\"),a.addEventListener(\"mousemove\",r),a.addEventListener(\"mousedown\",i);const l=m.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\",\"g\"));l.addEventListener(\"mousemove\",r),l.addEventListener(\"mousedown\",i),l.classList.add(\"sa-mcp-preview-block\");const u=Q(s.block,l);y.push({block:s.block,autocompleteFactory:null!==(o=s.autocompleteFactory)&&void 0!==o?o:null,renderedBlock:u,svgBlock:l,svgBackground:a}),t+=c}const n=(t+8)*D;S=n<0?0:n>C?C:n,m.setAttribute(\"height\",\"\".concat(n,\"px\")),u.style.height=S+\"px\",p.style.height=S+\"px\",h.setAttribute(\"height\",\"\"+S),c.dataset.error=\"\"+T,M={x:N.x+16,y:N.y-8};const s=a.getBoundingClientRect().height,r=M.y+s;r>window.innerHeight&&(M.y-=r-window.innerHeight),i.style.top=M.y+\"px\",i.style.left=M.x+\"px\",v=-1,O(0),j(),z()}function O(e){if(v===e)return;const t=y[v];if(t&&(t.svgBackground.classList.remove(\"sa-mcp-preview-block-bg-selection\"),t.svgBlock.classList.remove(\"sa-mcp-preview-block-selection\")),0===y.length&&k)return void(l.value=d.value+k.toText(!0).substring(d.value.length));const o=y[e];o&&o.autocompleteFactory?(o.svgBackground.classList.add(\"sa-mcp-preview-block-bg-selection\"),o.svgBlock.classList.add(\"sa-mcp-preview-block-selection\"),o.svgBackground.scrollIntoView({block:\"nearest\",behavior:Math.abs(e-v)>1?\"smooth\":\"auto\"}),l.value=d.value+o.autocompleteFactory(!0).substring(d.value.length)):l.value=\"\",v=e}function j(){var e;const t=null!==(e=d.selectionStart)&&void 0!==e?e:0,o=0===d.value.length?0:t/d.value.length;let n=0;for(let e=0;eL/D&&(s+=(L/D-s-t.renderedBlock.width)*D*o);var r=(n+30)*D;t.svgBlock.setAttribute(\"transform\",\"translate(\".concat(s,\", \").concat(r,\") scale(\").concat(D,\")\")),n+=H(t.block)}l.scrollLeft=d.scrollLeft}function z(){const e=u.scrollTop,t=u.scrollHeight;if(t<=S)return void(p.style.display=\"none\");const o=S/t*S,n=e/t*S;p.style.display=\"\",g.setAttribute(\"height\",\"\"+o),g.setAttribute(\"y\",\"\"+n)}function B(){const e=y[v];if(!e)return;const t=s.getMainWorkspace();let o;t.setResizesEnabled(!1),s.Events.disable();try{if(o=e.block.createWorkspaceForm(),s.scratchBlocksUtils.changeObscuredShadowIds(o),!o.getSvgRoot())throw new Error(\"newBlock is not rendered.\");let n=o.svgPath_.getBoundingClientRect(),r=Math.floor((b.x-(n.left+n.right)/2)/t.scale),i=Math.floor((b.y-(n.top+n.bottom)/2)/t.scale);o.moveBy(r,i)}finally{s.Events.enable()}s.Events.isEnabled()&&s.Events.fire(new s.Events.BlockCreate(o));let n={clientX:b.x,clientY:b.y,type:\"mousedown\",stopPropagation:function(){},preventDefault:function(){},target:e.svgBlock};t.getGesture(n)&&t.startDragWithFakeEvent(n,o)}d.addEventListener(\"input\",A),document.addEventListener(\"selectionchange\",j),u.addEventListener(\"scroll\",z),d.addEventListener(\"keydown\",(e=>{switch(e.key){case\"Escape\":d.value.length>0?(d.value=\"\",A()):E(),e.stopPropagation(),e.preventDefault();break;case\"Tab\":!function(){let e;e=y[v]?y[v].autocompleteFactory:()=>l.value,0!==l.value.length&&e&&(d.value=e(!1),d.selectionStart=d.value.length+1,A())}(),e.stopPropagation(),e.preventDefault();break;case\"Enter\":B(),E(),e.stopPropagation(),e.preventDefault();break;case\"ArrowDown\":v+1>=y.length?O(0):O(v+1),e.stopPropagation(),e.preventDefault();break;case\"ArrowUp\":O(v-1<0?y.length-1:v-1),e.stopPropagation(),e.preventDefault()}})),d.addEventListener(\"focusout\",E),document.addEventListener(\"keydown\",(e=>{\" \"===e.key&&(e.ctrlKey||e.metaKey)&&(_(),e.preventDefault(),e.stopPropagation())}));const R=s.Gesture.prototype.doWorkspaceClick_;s.Gesture.prototype.doWorkspaceClick_=function(){(1===this.mostRecentEvent_.button||this.mostRecentEvent_.shiftKey)&&_(),b={x:this.mostRecentEvent_.clientX,y:this.mostRecentEvent_.clientY},R.call(this)};const W=s.WorkspaceSvg.prototype.isDeleteArea;s.WorkspaceSvg.prototype.isDeleteArea=function(e){return M&&e.clientX>M.x&&e.clientXM.y&&e.clientY(this.onItemClick(t),e.preventDefault(),e.cancelBubble=!0,!1))),this.items.push(t),this.el.appendChild(t),t}onItemClick(e,o){this.selected&&this.selected!==e&&(this.selected.classList.remove(\"sel\"),this.selected=null),this.selected!==e&&(e.classList.add(\"sel\"),this.selected=e);let n=e.data.cls;if(\"costume\"===n||\"sound\"===n){const o=document.querySelector(\"[class^=asset-panel_wrapper]\");if(o){o[t.tab.traps.getInternalKey(o)].child.stateNode.props.onItemClick(e.data.y);o.firstChild.firstChild.children[e.data.y].scrollIntoView({behavior:\"auto\",block:\"center\",inline:\"start\"}),o.closest(\"div[class*=gui_flex-wrapper]\").scrollTop=0}}else if(\"var\"===n||\"VAR\"===n||\"list\"===n||\"LIST\"===n){let t=this.getVariableUsesById(e.data.labelID);this.carousel.build(e,t,o)}else if(\"define\"===n){let t=this.getCallsToProcedureById(e.data.labelID);this.carousel.build(e,t,o)}else if(\"receive\"===n){let t=this.getCallsToEventsByName(e.data.eventName);if(!o){const e=this.utils.getEditingTarget().id;for(const n of t)if(n.targetId===e){o=n;break}}this.carousel.build(e,t,o)}else if(e.data.clones){let t=[this.workspace.getBlockById(e.data.labelID)];for(const o of e.data.clones)t.push(this.workspace.getBlockById(o));this.carousel.build(e,t,o)}else this.utils.scrollBlockIntoView(e.data.labelID),this.carousel.remove()}getVariableUsesById(e){let t=[],o=this.workspace.getTopBlocks();for(const n of o){let o=n.getDescendants();for(const n of o){let o=n.getVarModels();if(o)for(const s of o)s.getId()===e&&t.push(n)}}return t}getCallsToProcedureById(e){let t=this.workspace.getBlockById(e),o=t.getChildren()[0].getProcCode(),n=[t],s=this.workspace.getTopBlocks();for(const e of s){let t=e.getDescendants();for(const e of t)\"procedures_call\"===e.type&&e.getProcCode()===o&&n.push(e)}return n}getCallsToEventsByName(e){let n=[];const r=t.tab.traps.vm.runtime.targets;for(const t of r){if(!t.isOriginal)continue;const r=t.blocks;if(r._blocks)for(const i of Object.keys(r._blocks)){const a=r._blocks[i];if(\"event_whenbroadcastreceived\"===a.opcode&&a.fields.BROADCAST_OPTION.value===e)n.push(new s.a(t,a));else if(\"event_broadcast\"===a.opcode||\"event_broadcastandwait\"===a.opcode){const i=a.inputs.BROADCAST_INPUT.block,c=r._blocks[i];if(c){let r;r=\"event_broadcast_menu\"===c.opcode?c.fields.BROADCAST_OPTION.value:o(\"complex-broadcast\"),r===e&&n.push(new s.a(t,a))}}}}return n}empty(){for(const e of this.items)this.el.contains(e)&&this.el.removeChild(e);this.items=[],this.selected=null}}class l{constructor(e){this.utils=e,this.el=null,this.count=null,this.blocks=[],this.idx=0}build(e,t,o){if(this.el&&this.el.parentNode===e)this.navRight();else{if(this.remove(),this.blocks=t,e.appendChild(this.createDom()),this.idx=0,o)for(const e of Object.keys(this.blocks)){if(this.blocks[e].id===o.id){this.idx=Number(e);break}}this.idxthis.navLeft(e))),this.count=this.el.appendChild(document.createElement(\"span\")),this.count.innerText=this.blocks.length>0?this.idx+1+\" / \"+this.blocks.length:\"0\";const t=this.el.appendChild(document.createElement(\"span\"));return t.className=\"sa-find-carousel-control\",t.textContent=\"▶\",t.addEventListener(\"mousedown\",(e=>this.navRight(e))),this.el}inputKeyDown(e){\"ArrowLeft\"===e.key&&this.el&&this.blocks&&this.navLeft(e),\"ArrowRight\"===e.key&&this.el&&this.blocks&&this.navRight(e)}navLeft(e){return this.navSideways(e,-1)}navRight(e){return this.navSideways(e,1)}navSideways(e,t){this.blocks.length>0&&(this.idx=(this.idx+t+this.blocks.length)%this.blocks.length,this.count.innerText=this.idx+1+\" / \"+this.blocks.length,this.utils.scrollBlockIntoView(this.blocks[this.idx])),e&&(e.cancelBubble=!0,e.preventDefault())}remove(){this.el&&(this.el.remove(),this.blocks=[],this.idx=0)}}const d=new class{constructor(){this.utils=new r.a(t),this.prevValue=\"\",this.findBarOuter=null,this.findWrapper=null,this.findInput=null,this.dropdownOut=null,this.dropdown=new c(this.utils),document.addEventListener(\"keydown\",(e=>this.eventKeyDown(e)),!0)}get workspace(){return a.getMainWorkspace()}createDom(e){this.findBarOuter=document.createElement(\"div\"),this.findBarOuter.className=\"sa-find-bar\",t.tab.displayNoneWhileDisabled(this.findBarOuter,{display:\"flex\"}),e.appendChild(this.findBarOuter),this.findWrapper=this.findBarOuter.appendChild(document.createElement(\"span\")),this.findWrapper.className=\"sa-find-wrapper\",this.dropdownOut=this.findWrapper.appendChild(document.createElement(\"label\")),this.dropdownOut.className=\"sa-find-dropdown-out\",this.findInput=this.dropdownOut.appendChild(document.createElement(\"input\")),this.findInput.className=t.tab.scratchClass(\"input_input-form\",{others:\"sa-find-input\"}),this.findInput.id=\"sa-find-input\",this.findInput.type=\"search\",this.findInput.placeholder=o(\"find-placeholder\"),this.findInput.autocomplete=\"off\",this.dropdownOut.appendChild(this.dropdown.createDom()),this.bindEvents(),this.tabChanged()}bindEvents(){this.findInput.addEventListener(\"focus\",(()=>this.inputChange())),this.findInput.addEventListener(\"keydown\",(e=>this.inputKeyDown(e))),this.findInput.addEventListener(\"keyup\",(()=>this.inputChange())),this.findInput.addEventListener(\"focusout\",(()=>this.hideDropDown()))}tabChanged(){if(!this.findBarOuter)return;const e=t.tab.redux.state.scratchGui.editorTab.activeTabIndex,o=0===e||1===e||2===e;this.findBarOuter.hidden=!o}inputChange(){this.showDropDown();let e=(this.findInput.value||\"\").toLowerCase();if(e===this.prevValue)return;this.prevValue=e,this.dropdown.blocks=null;let t=this.dropdown.items;for(const o of t){let t=o.data.procCode,n=o.data.lower.indexOf(e);if(n>=0){for(o.style.display=\"block\";o.firstChild;)o.removeChild(o.firstChild);n>0&&o.appendChild(document.createTextNode(t.substring(0,n)));let s=document.createElement(\"b\");s.appendChild(document.createTextNode(t.substr(n,e.length))),o.appendChild(s),n+e.length0?(this.findInput.value=\"\",this.inputChange()):this.findInput.blur(),void e.preventDefault()):void 0;this.findInput.blur()}eventKeyDown(e){if(t.self.disabled||!this.findBarOuter)return;let o=e.ctrlKey||e.metaKey;if(\"f\"===e.key.toLowerCase()&&o&&!e.shiftKey)return this.findInput.focus(),this.findInput.select(),e.cancelBubble=!0,e.preventDefault(),!0;if(\"ArrowLeft\"===e.key&&o){if(\"INPUT\"===document.activeElement.tagName)return;if(0===this.selectedTab)return this.utils.navigationHistory.goBack(),e.cancelBubble=!0,e.preventDefault(),!0}if(\"ArrowRight\"===e.key&&o){if(\"INPUT\"===document.activeElement.tagName)return;if(0===this.selectedTab)return this.utils.navigationHistory.goForward(),e.cancelBubble=!0,e.preventDefault(),!0}}showDropDown(e,t){if(!e&&this.dropdownOut.classList.contains(\"visible\"))return;this.prevValue=e?\"\":null,this.dropdownOut.classList.add(\"visible\");let o=0===this.selectedTab?this.getScratchBlocks():1===this.selectedTab?this.getScratchCostumes():2===this.selectedTab?this.getScratchSounds():[];this.dropdown.empty();for(const n of o){let o=this.dropdown.addItem(n);e&&(n.matchesID(e)?this.dropdown.onItemClick(o,t):o.style.display=\"none\")}this.utils.offsetX=this.dropdownOut.getBoundingClientRect().width+32,this.utils.offsetY=32}hideDropDown(){this.dropdownOut.classList.remove(\"visible\")}get selectedTab(){return t.tab.redux.state.scratchGui.editorTab.activeTabIndex}getScratchBlocks(){let e=[],t={},s=this.workspace.getTopBlocks();function r(o,s,r){let i=r.id?r.id:r.getId?r.getId():null,a=t[s];if(a)return a.clones||(a.clones=[]),a.clones.push(i),a;let c=new n(o,s,i,0);return c.y=r.getRelativeToSurfaceXY?r.getRelativeToSurfaceXY().y:null,e.push(c),t[s]=c,c}function i(e){let t,n=e.inputList[0];for(const e of n.fieldRow)t=t?t+\" \":\"\",e instanceof a.FieldImage&&e.src_.endsWith(\"green-flag.svg\")?t+=o(\"/_general/blocks/green-flag\"):t+=e.getText();return t}for(const e of s)if(\"procedures_definition\"!==e.type)if(\"event_whenflagclicked\"!==e.type)if(\"event_whenbroadcastreceived\"!==e.type)\"event_when\"!==e.type.substr(0,10)&&\"control_start_as_clone\"!==e.type||r(\"event\",i(e),e);else{let t=e.inputList[0].fieldRow.find((e=>\"BROADCAST_OPTION\"===e.name)).getText();r(\"receive\",o(\"event\",{name:t}),e).eventName=t}else r(\"flag\",i(e),e);else{const t=e.getChildren()[0].getProcCode();if(!t)continue;const o=e.inputList.findIndex((e=>e.fieldRow.length>0));if(-1===o)continue;const n=e.inputList[o].fieldRow[0].getText();r(\"define\",0===o?\"\".concat(n,\" \").concat(t):\"\".concat(t,\" \").concat(n),e)}let c=this.workspace.getVariableMap(),l=c.getVariablesOfType(\"\");for(const e of l)r(e.isLocal?\"var\":\"VAR\",e.isLocal?o(\"var-local\",{name:e.name}):o(\"var-global\",{name:e.name}),e);let d=c.getVariablesOfType(\"list\");for(const e of d)r(e.isLocal?\"list\":\"LIST\",e.isLocal?o(\"list-local\",{name:e.name}):o(\"list-global\",{name:e.name}),e);const u=this.getCallsToEvents();for(const e of u)r(\"receive\",o(\"event\",{name:e.eventName}),e.block).eventName=e.eventName;const p={flag:0,receive:1,event:2,define:3,var:4,VAR:5,list:6,LIST:7};return e.sort(((e,t)=>{let o=p[e.cls]-p[t.cls];return 0!==o?o:e.lowert.lower?1:e.y-t.y})),e}getScratchCostumes(){let e=this.utils.getEditingTarget().getCostumes(),t=[],o=0;for(const s of e){let e=new n(\"costume\",s.name,s.assetId,o);t.push(e),o++}return t}getScratchSounds(){let e=this.utils.getEditingTarget().getSounds(),t=[],o=0;for(const s of e){let e=new n(\"sound\",s.name,s.assetId,o);t.push(e),o++}return t}getCallsToEvents(){const e=[],t=new Set;for(const n of this.workspace.getAllBlocks()){if(\"event_broadcast\"!==n.type&&\"event_broadcastandwait\"!==n.type)continue;const s=n.getChildren()[0];if(!s)continue;let r=\"\";r=\"event_broadcast_menu\"===s.type?s.inputList[0].fieldRow[0].getText():o(\"complex-broadcast\"),t.has(r)||(t.add(r),e.push({eventName:r,block:n}))}return e}},u=a.Gesture.prototype.doBlockClick_;for(a.Gesture.prototype.doBlockClick_=function(){if(!t.self.disabled&&(1===this.mostRecentEvent_.button||this.mostRecentEvent_.shiftKey)){let e=this.startBlock_;for(;e;e=e.getSurroundParent()){if(\"procedures_definition\"===e.type||!this.jumpToDef&&\"procedures_call\"===e.type){let t=e.id?e.id:e.getId?e.getId():null;return d.findInput.focus(),void d.showDropDown(t)}if(\"data_variable\"===e.type||\"data_changevariableby\"===e.type||\"data_setvariableto\"===e.type){let t=e.getVars()[0];return d.findInput.focus(),d.showDropDown(t,e),void(d.selVarID=t)}if(\"event_whenbroadcastreceived\"===e.type||\"event_broadcastandwait\"===e.type||\"event_broadcast\"===e.type){let t=e.id;return d.findInput.focus(),d.showDropDown(t,e),void(d.selVarID=t)}}}u.call(this)},t.tab.redux.initialize(),t.tab.redux.addEventListener(\"statechanged\",(e=>{\"scratch-gui/navigation/ACTIVATE_TAB\"===e.detail.action.type&&d.tabChanged()}));;){const e=await t.tab.waitForElement(\"ul[class*=gui_tab-list_]\",{markAsSeen:!0,reduxEvents:[\"scratch-gui/mode/SET_PLAYER\",\"fontsLoaded/SET_FONTS_LOADED\",\"scratch-gui/locales/SELECT_LOCALE\"],reduxCondition:e=>!e.scratchGui.mode.isPlayerOnly});d.createDom(e)}},\"userstyle.css\":o.n(i).a}},1536:function(e,t,o){\"use strict\";function n(e){var t=this.procCode_.split(/(?=[^\\\\]%[nbsl])/);t=t.map((function(e){return e.trim()}));for(var o,n=0,s=0;o=t[s];s++){var r;if(\"%\"==o.substring(0,1)&&\"l\"!==o.substring(1,2)){var i=o.substring(1,2);if(\"n\"!=i&&\"b\"!=i&&\"s\"!=i)throw new Error(\"Found an custom procedure with an invalid type: \"+i);r=o.substring(2).trim();var a=this.argumentIds_[n],c=this.appendValueInput(a);\"b\"==i&&c.setCheck(\"Boolean\"),this.populateArgument_(i,n,e,a,c),n++}else r=\"%l\"==o?\" \":o.replace(\"%l\",\"\").trim();this.addProcedureLabel_(r.replace(/\\\\%/,\"%\"))}this.procCode_=this.procCode_.replace(/%l /g,\"\")}function s(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.procCode_=\"\",this.displayNames_=[],this.argumentIds_=[];for(var t=0;t\\n \\n ')),m.WidgetDiv.DIV.lastChild.addEventListener(\"click\",t)}function i(e){if(1!==this.inputList.length){for(var t=null,o=0;o=0&&o<=n))return!1;const s=e.inputList.findIndex((e=>e.name===t)),r=e.inputList.splice(s,1)[0];e.inputList.splice(o,0,r),m.Events.disable();try{e.onChangeFn(!0),e.updateDisplay_()}finally{m.Events.enable()}!function(e){if(!e)return;if(e.type===m.DUMMY_INPUT)e.fieldRow[0].showEditor_();else if(e.type===m.INPUT_VALUE){e.connection.targetBlock().getField(\"TEXT\").showEditor_()}}(e.inputList[o])}function d(e,t,o){const n=e.parentBlock_?e.parentBlock_:e;if(n.inputList.length<=1)return;const{name:s,index:r}=c(t,n.inputList);l(n,s,\"left\"===o?r-1:r+1)}function u(e){let t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];e.createAllInputs_=n,e.onChangeFn=s,e.removeFieldCallback=i;for(const o of[\"addLabelExternal\",\"addBooleanExternal\",\"addStringNumberExternal\"])t&&(v[o]=e[o]),e[o]=a(e[o],o)}function p(e){e.createAllInputs_=f,e.onChangeFn=b,e.removeFieldCallback=y;for(const[t,o]of Object.entries(v))e[t]=o}function h(){return m.getMainWorkspace().getAllBlocks().find((e=>\"procedures_declaration\"===e.type))}function g(){u(m.Blocks.procedures_declaration),t.tab.redux.state.scratchGui.customProcedures.active&&u(h(),!1),m.FieldTextInputRemovable.prototype.showEditor_=function(){k.call(this),r(\"left\",(()=>d(this.sourceBlock_,this,\"left\"))),r(\"right\",(()=>d(this.sourceBlock_,this,\"right\"))),w=this}}const m=await t.tab.traps.getBlockly(),f=m.Blocks.procedures_declaration.createAllInputs_,b=m.Blocks.procedures_declaration.onChangeFn,y=m.Blocks.procedures_declaration.removeFieldCallback,k=m.FieldTextInputRemovable.prototype.showEditor_;let v={},w=null;t.self.addEventListener(\"disabled\",(function(){p(m.Blocks.procedures_declaration),t.tab.redux.state.scratchGui.customProcedures.active&&p(h()),m.FieldTextInputRemovable.prototype.showEditor_=k,m.WidgetDiv.DIV.querySelectorAll(\".blocklyTextShiftArrow\").forEach((e=>e.remove()))})),t.self.addEventListener(\"reenabled\",g),g()},\"arrows.css\":o.n(r).a}},1537:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return a}));var n=o(1388),s=o(1389),r=async e=>{let{addon:t,console:o,msg:r}=e;const i=new s.a(250),a=(e,o)=>{if(e=Object(n.b)(e),!t.tab.redux.state||!t.tab.redux.state.scratchGui)return;const s=e=>{let{detail:o}=e;\"scratch-gui/color-picker/DEACTIVATE_COLOR_PICKER\"===o.action.type&&(t.tab.redux.removeEventListener(\"statechanged\",s),setTimeout((()=>{document.body.classList.remove(\"sa-hide-eye-dropper-background\")}),50))},r=o=>{let{detail:n}=o;\"scratch-gui/color-picker/ACTIVATE_COLOR_PICKER\"===n.action.type&&(t.tab.redux.removeEventListener(\"statechanged\",r),t.tab.redux.addEventListener(\"statechanged\",s),setTimeout((()=>{t.tab.redux.dispatch({type:\"scratch-gui/color-picker/DEACTIVATE_COLOR_PICKER\",color:e})}),50))};t.tab.redux.addEventListener(\"statechanged\",r),document.body.classList.add(\"sa-hide-eye-dropper-background\"),o.click()},c=await t.tab.traps.getBlockly(),l=c.FieldColourSlider.prototype.showEditor_;c.FieldColourSlider.prototype.showEditor_=function(){for(var e=arguments.length,o=new Array(e),s=0;s{const o=document.querySelector(\"button.scratchEyedropper\");i.abort(!1),t.tab.redux.initialize();const s=e.getValue(),c=Object.assign(document.createElement(\"div\"),{className:\"sa-color-picker sa-color-picker-code\"});t.tab.displayNoneWhileDisabled(c,{display:\"flex\"});const l=Object.assign(document.createElement(\"input\"),{className:\"sa-color-picker-color sa-color-picker-code-color\",type:\"color\",value:s||\"#000000\"}),d=Object.assign(document.createElement(\"input\"),{className:t.tab.scratchClass(\"input_input-form\",{others:\"sa-color-picker-text sa-color-picker-code-text\"}),type:\"text\",pattern:\"^#?([0-9a-fA-F]{3}){1,2}$\",placeholder:r(\"hex\"),value:s||\"\"});l.addEventListener(\"input\",(()=>i.limit((()=>a(d.value=l.value,o))))),d.addEventListener(\"change\",(()=>{const{value:e}=d;Object(n.a)().test(e)&&a(l.value=Object(n.b)(e),o)})),c.appendChild(l),c.appendChild(d),o.parentElement.insertBefore(c,o)})(this),c};const d=c.FieldColourSlider.prototype.sliderCallbackFactory_;c.FieldColourSlider.prototype.sliderCallbackFactory_=function(){for(var e=arguments.length,t=new Array(e),o=0;o{const t=n(e),o=c.DropDownDiv.getContentDiv();if(o){const e=o.querySelector(\".sa-color-picker-color.sa-color-picker-code-color\"),n=o.querySelector(\".sa-color-picker-text.sa-color-picker-code-text\");if(!e||!n)return t;const s=this.getValue();e.value=s||\"#000000\",n.value=s||\"\"}return t}}},i=o(1465);const a={\"userscript.js\":async e=>{r(e)},\"style.css\":o.n(i).a}},1539:function(e,t,o){\"use strict\";function n(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function s(e){for(var t=1;t{const t=e.indexOf(i);return-1===t||0===t?null:e.substr(0,t)},c=e=>{const t=e.indexOf(i);return-1===t||0===t?e:e.substr(t+2)},l=(e,t)=>{const o=c(e);return t?\"\".concat(t).concat(i).concat(o):o},d=e=>!e.includes(i)&&!e.endsWith(\"/\"),u=[\"_mouse_\",\"_stage_\",\"_edge_\",\"_myself_\",\"_random_\"],p=e=>\"\"===e?\"2\":u.includes(e)?\"\".concat(e,\"2\"):e;let h=null,g=null;const m=e=>{e&&null!==g&&\"string\"!=typeof a(e.name)&&(e.name=l(e.name,g))};var f=o(1494);const b={\"userscript.js\":async function(e){let{addon:t,console:o,msg:n}=e;let r,i,u,f;const b=e=>{const t=e.closest(\"[class*='sprite-selector_sprite-selector']\");if(t)return t[i].child.sibling.child.stateNode;const o=e.closest('[class*=\"asset-panel_wrapper\"]');if(o)return o[i].child.child.stateNode;throw new Error(\"cannot find SortableHOC\")},y=(e,t,o)=>Math.min(Math.max(e,t),o),k=e=>e&&e.name&&\"object\"==typeof e.name?e.name:null,v={assetId:\"&__sa_folders_folder\",encodeDataURI:()=>t.self.getResource(\"/folder.svg\")},w=\"data:image/svg+xml;base64,\".concat(btoa('\\n\\n \\n \\n \\n'));let I=null;const T=Object.create(null),x=e=>{const t=e=>{const t=(e=>{let t=0;for(let o=0;o>>15,1|e),(((e^=e+Math.imul(e^e>>>7,61|e))^e>>>14)>>>0)/4294967296});var n;return o(),o(),o(),o(),o()};if(!T[e]){I||(I=document.createElement(\"style\"),document.head.appendChild(I));const o=360*t(e),n=\"hsla(\".concat(o,\"deg, 100%, 85%, 0.5)\"),s=Object.keys(T).length,r=\"sa-folders-color-\".concat(s);T[e]=r,I.textContent+=\".\".concat(r,\"{background-color:\").concat(n,\" !important;}\"),I.textContent+=\".\".concat(r,'[class*=\"sprite-selector_raised\"]:not([class*=\"sa-folders-folder\"]){background-color:hsla(').concat(o,\"deg, 100%, 77%, 1) !important;}\")}return T[e]},M=e=>{const t=Object.create(null),o=[];for(const n of e){const e=n.getName?n.getName():n.name,s=a(e);\"string\"==typeof s?(t[s]||(t[s]=[],o.push(t[s])),t[s].push(n)):o.push(n)}const n=o.flat();for(let t=0;t{const{items:e,changed:t}=M(r.runtime.targets);t&&(r.runtime.targets=e,r.emitTargetsUpdate())},L=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:r.editingTarget;const{items:t,changed:o}=M(e.sprite.costumes);o&&(e.sprite.costumes=t,r.emitTargetsUpdate())},S=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:r.editingTarget;const{items:t,changed:o}=M(e.sprite.sounds);o&&(e.sprite.sounds=t,r.emitTargetsUpdate())},D=e=>{const t=e.constructor;if(!Array.isArray(e.props.items)||\"string\"!=typeof e.props.selectedId&&\"number\"!=typeof e.props.selectedItemIndex||void 0===e.containerBox||void 0!==t.prototype.componentDidMount||void 0!==t.prototype.componentDidUpdate||\"function\"!=typeof t.prototype.handleAddSortable||\"function\"!=typeof t.prototype.handleRemoveSortable||\"function\"!=typeof t.prototype.setRef)throw new Error(\"Can not comprehend SortableHOC\")};class C{constructor(){this.cache=new Map,this.usedThisTick=new Set}has(e){return this.cache.has(e)}get(e){return this.usedThisTick.add(e),this.cache.get(e)}set(e,t){this.usedThisTick.add(e),this.cache.set(e,t)}startTick(){this.usedThisTick.clear()}endTick(){for(const e of Array.from(this.cache.keys()))this.usedThisTick.has(e)||this.cache.delete(e)}clear(){this.usedThisTick.clear(),this.cache.clear()}}const _=(e,t)=>{const o=new C,n=new C,r=new C,i=80,c=[[0,0],[40,0],[0,40],[40,40]],l=e=>{let t='data:image/svg+xml;,');for(let o=0;o'))}return t+=\"\",t},d=e=>{let t=\"sa_folder&&\";for(let o=0;o{if(1===t){return e.props.items.find((t=>t.id===e.props.selectedId))}if(2===t){return e.props.items[e.props.selectedItemIndex]}return null};e.prototype.saInitialSetup=function(){o.clear(),n.clear(),r.clear();const e=[],s=p(this);if(s&&!s.isStage){const o=a(s.name);e.push(o),1===t?h=o:2===t&&(g=o)}this.setState({folders:e})},e.prototype.componentDidMount=function(){const e=p(this);if(e){const o=a(e.name);1===t?h=o:2===t&&(g=o)}this.saInitialSetup()},e.prototype.componentDidUpdate=function(e,o){const n=p(this);if(n){const o=a(n.name),s=this.state.folders.includes(o)?o:null;let r;1===t?h=s:2===t&&(g=s),r=this.props.selectedId?this.props.selectedId!==e.selectedId:this.props.items[this.props.selectedItemIndex]&&e.items[e.selectedItemIndex]&&this.props.items[this.props.selectedItemIndex].name!==e.items[e.selectedItemIndex].name,r&&(n.isStage||\"string\"!=typeof o||this.state.folders.includes(o)||this.setState((e=>({folders:[...e.folders,o]}))))}};const m=e.prototype.render;e.prototype.render=function(){const e=this.props;this.props=s(s({},this.props),((e,s)=>{const i=e=>{const t=e.name;let n,s;o.has(t)?(n=o.get(t),s=n.name):(s={toString:()=>\"_\".concat(e.name)},n={},o.set(t,n));const r=a(e.name);return Object.assign(n,e),s.realName=e.name,s.realIndex=h,s.inFolder=r,n.name=s,{newItem:n,itemData:s}};o.startTick(),n.startTick(),r.startTick();const c=new Map,u=[],p={items:u};let h=0;for(;hk}},T={toString:()=>k},n.set(y,I)),T.folder=g,T.folderOpen=o,I.items=m,I.name=T,o?x=v:r.has(w)?x=r.get(w):(x={assetId:w,encodeDataURI:()=>l(m)},r.set(w,x)),1===t?(I.costume||(I.costume={}),I.costume.asset=x,I.id||(I.id={}),I.id.sa_folder_items=m,I.id.toString=()=>k):(I.asset=x,I.dragPayload||(I.dragPayload={}),I.dragPayload.sa_folder_items=m),u.push(I),o)for(const e of m)u.push(e)}h++}return o.endTick(),n.endTick(),r.endTick(),p})(this.state&&this.state.folders||[],this.props)),1===t?u=this.props.items:2===t&&(f=this.props.items);const i=m.call(this);return this.props=e,i}},E=(e,t)=>{const o=b(e.ref);return(o.state&&o.state.folders||[]).includes(t)},A=(e,t,o)=>{b(e.ref).setState((e=>{let n=e&&e.folders||[];return n=n.filter((e=>e!==t)),o?{folders:[...n,t]}:{folders:n}}))};await t.tab.scratchClassReady(),t.tab.createEditorContextMenu(((e,o)=>{if(\"sprite\"!==e&&\"costume\"!==e&&\"sound\"!==e)return;const s=o.target[t.tab.traps.getInternalKey(o.target)].return.return.return.stateNode,i=k(s.props);if(i){if(\"string\"==typeof i.folder){o.target.setAttribute(\"sa-folders-context-type\",\"folder\");const e=e=>{const t=E(s,i.folder);if(A(s,i.folder,!1),t&&\"string\"==typeof e&&A(s,e,!0),\"SPRITE\"===s.props.dragType){for(const t of r.runtime.targets)t.isOriginal&&a(t.getName())===i.folder&&r.renameSprite(t.id,p(l(t.getName(),e)));r.emitWorkspaceUpdate(),N()}else if(\"COSTUME\"===s.props.dragType){for(let t=0;t{let o=await t.tab.prompt(n(\"rename-folder-prompt-title\"),n(\"rename-folder-prompt\"),i.folder,{useEditorClasses:!0});null!==o&&(d(o)?(o||(o=null),e(o)):alert(n(\"name-not-allowed\")))},u=()=>{e(null)};return[{className:\"sa-folders-rename-folder\",label:n(\"rename-folder\"),callback:c,position:\"assetContextMenuAfterDelete\",order:10},{className:\"sa-folders-remove-folder\",label:n(\"remove-folder\"),callback:u,position:\"assetContextMenuAfterDelete\",order:11}]}{o.target.setAttribute(\"sa-folders-context-type\",\"asset\");const e=e=>{if(\"SPRITE\"===s.props.dragType){const t=r.runtime.getTargetById(s.props.id);r.renameSprite(s.props.id,p(l(t.getName(),e))),N(),r.emitWorkspaceUpdate()}else if(\"COSTUME\"===s.props.dragType){const t=k(s.props).realIndex,o=r.editingTarget.sprite.costumes[t];r.renameCostume(r.editingTarget.sprite.costumes.indexOf(o),l(o.name,e)),L()}else if(\"SOUND\"===s.props.dragType){const t=k(s.props).realIndex,o=r.editingTarget.sprite.sounds[t];r.renameSound(r.editingTarget.sprite.sounds.indexOf(o),l(o.name,e)),S()}},a=async()=>{const o=await t.tab.prompt(n(\"name-prompt-title\"),n(\"name-prompt\"),c(i.realName),{useEditorClasses:!0});null!==o&&(d(o)?e(o):alert(n(\"name-not-allowed\")))},h=[{border:!0,className:\"sa-folders-create-folder\",label:n(\"create-folder\"),callback:a,position:\"assetContextMenuAfterDelete\",order:13}],g=i.inFolder;return\"string\"==typeof g&&h.push({className:\"sa-folders-remove-from-folder\",label:n(\"remove-from-folder\"),callback:()=>e(null),position:\"assetContextMenuAfterDelete\",order:14}),h.concat((e=>{const t=new Set;let o;o=\"SPRITE\"===e.props.dragType?u:f;for(const e of o){const o=k(e);\"string\"==typeof o.folder&&t.add(o.folder)}return Array.from(t)})(s).filter((e=>e!==g)).map(((t,o)=>({className:\"sa-folders-add-to-folder\",label:n(\"add-to-folder\",{folder:t}),callback:()=>e(t),position:\"assetContextMenuAfterDelete\",order:20+o}))))}}}));const O=e=>{for(const t of[\"handleDelete\",\"handleDuplicate\",\"handleExport\"]){const o=e.prototype[t];e.prototype[t]=function(){for(var e=arguments.length,t=new Array(e),n=0;n{const e=r.runtime.targets[0].constructor,t=r.installTargets;r.installTargets=function(){for(var e=arguments.length,o=new Array(e),n=0;n(N(),e)))};const n=r.duplicateSprite;r.duplicateSprite=function(){for(var e=arguments.length,t=new Array(e),o=0;o(N(),e)))};const s=e.prototype.addCostume;e.prototype.addCostume=function(){for(var e=arguments.length,t=new Array(e),o=0;o{let{guiItems:s,getAll:r,set:i,rename:a,getVMItemFromGUIItem:c,zeroIndexed:d,onFolderChanged:u}=e;if((t=y(t,d?0:1,d?s.length-1:s.length))===(n=y(n,d?0:1,d?s.length-1:s.length)))return!1;let p=r();const h=r(),g=s[t-(d?0:1)],m=s[n-(d?0:1)],f=k(g),b=k(m);if(!f||!b)return o.warn(\"should never happen\"),!1;const v=(\"string\"==typeof f.folder?g.items:[g]).map((e=>c(e,p))).filter((e=>e));if(\"number\"==typeof b.realIndex){const e=c(m,p);if(!e||v.includes(e))return!1}let w,I=null;if(p=p.filter((e=>!v.includes(e))),n===(d?0:1))w=d?0:1;else if(n===s.length-(d?1:0))w=p.length;else if(\"number\"==typeof b.realIndex){I=\"string\"==typeof b.inFolder?b.inFolder:null;let e=c(m,p);if(!e)return o.warn(\"should never happen\"),!1;w=p.indexOf(e),n>t&&w++}else{if(\"string\"!=typeof b.folder)return o.warn(\"should never happen\"),!1;{let e,s=0;np.length)return o.warn(\"should never happen\"),!1;if(p.splice(w,0,...v),i(p),\"string\"!=typeof f.folder&&f.inFolder!==I){for(const e of v){const t=e.getName?e.getName():e.name;a(e,l(t,I))}u&&u()}return!0}};r.constructor.prototype.reorderTarget=function(e,t){return a({getAll:()=>this.runtime.targets,set:e=>{this.runtime.targets=e,this.emitTargetsUpdate()},rename:(e,t)=>{this.renameSprite(e.id,p(t))},getVMItemFromGUIItem:(e,t)=>t.find((t=>t.id===e.id)),onFolderChanged:()=>{this.emitWorkspaceUpdate()},guiItems:u,zeroIndexed:!1},e,t)},e.prototype.reorderCostume=function(e,t){return a({getAll:()=>this.sprite.costumes,set:e=>{this.sprite.costumes=e},rename:(e,t)=>{this.renameCostume(this.sprite.costumes.indexOf(e),t)},getVMItemFromGUIItem:(e,t)=>{const o=k(e);return t.find((e=>e.name===o.realName))},guiItems:f,zeroIndexed:!0},e,t)},e.prototype.reorderSound=function(e,t){return a({getAll:()=>this.sprite.sounds,set:e=>{this.sprite.sounds=e},rename:(e,t)=>{this.renameSound(this.sprite.sounds.indexOf(e),t)},getVMItemFromGUIItem:(e,t)=>{const o=k(e);return t.find((e=>e.name===o.realName))},guiItems:f,zeroIndexed:!0},e,t)};const c=r.shareSoundToTarget;r.shareSoundToTarget=function(){for(var e=arguments.length,t=new Array(e),o=0;o{const o=e.constructor;o.prototype.sa_loadNextItem=function(){if(!this.sa_queuedItems)return;const e=this.sa_queuedItems.pop();if(e){let t,o;e.dragPayload?(o=e.url?\"SOUND\":\"COSTUME\",t=e.dragPayload):e.id&&(o=\"SPRITE\",t=e.id),o&&t&&s.call(this,{dragType:o,payload:t})}},o.prototype.componentDidUpdate=function(e,t){this.state.loading||!t.loading||this.state.error||this.sa_loadNextItem()};const s=o.prototype.handleDrop;o.prototype.handleDrop=function(){for(var e=arguments.length,o=new Array(e),r=0;r{e&&(this.sa_queuedItems=a,this.sa_loadNextItem())}))},e.handleDrop=o.prototype.handleDrop.bind(e)};{const e=t=>{t.target.closest('[class*=\"backpack_backpack-header_\"]')&&setTimeout((()=>{const t=document.querySelector(\"[class^='backpack_backpack-list_']\");if(!t)return;document.removeEventListener(\"click\",e);const o=(e=>{const t=e.closest('[class*=\"gui_editor-wrapper\"]');if(!t)throw new Error(\"cannot find Backpack\");return t[i].child.sibling.child.child.stateNode})(t);(e=>{const t=e.constructor;if(\"function\"!=typeof t.prototype.handleDrop||void 0!==t.prototype.componentDidUpdate)throw new Error(\"Can not comprehend Backpack\")})(o),z(o)}))};document.addEventListener(\"click\",e,!0)}{const e=await t.tab.waitForElement(\"[class^='sprite-selector_sprite-wrapper']\",{reduxCondition:e=>!e.scratchGui.mode.isPlayerOnly});r=t.tab.traps.vm,i=Object.keys(e).find((e=>e.startsWith(\"__reactInternalInstance$\")));const o=b(e),n=e[i].child.child.child.stateNode;D(o),(e=>{const t=e.constructor;if(\"object\"!=typeof e.props.asset||\"string\"!=typeof e.props.name||\"string\"!=typeof e.props.dragType||\"function\"!=typeof t.prototype.handleClick||\"function\"!=typeof t.prototype.setRef||\"function\"!=typeof t.prototype.handleDrag||\"function\"!=typeof t.prototype.handleDragEnd||\"function\"!=typeof t.prototype.handleDelete||\"function\"!=typeof t.prototype.handleDuplicate||\"function\"!=typeof t.prototype.handleExport)throw new Error(\"Can not comprehend SpriteSelectorItem\")})(n),(e=>{const t=e.runtime.targets[0];if(\"function\"!=typeof e.installTargets||\"function\"!=typeof e.reorderTarget||\"function\"!=typeof t.reorderCostume||\"function\"!=typeof t.reorderSound||\"function\"!=typeof t.addCostume||\"function\"!=typeof t.addSound)throw new Error(\"Can not comprehend VM\")})(r),_(o.constructor,1),O(n.constructor),o.saInitialSetup(),j()}{const e=await t.tab.waitForElement(\"[class*='selector_list-item']\",{reduxCondition:e=>0!==e.scratchGui.editorTab.activeTabIndex&&!e.scratchGui.mode.isPlayerOnly}),o=b(e);D(o),_(o.constructor,2),o.saInitialSetup()}},\"style.css\":o.n(f).a,\"folder.svg\":\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xMCA0SDRjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMiAxOGMwIDEuMS45IDIgMiAyaDE2YzEuMSAwIDItLjkgMi0yVjhjMC0xLjEtLjktMi0yLTJoLThsLTItMnoiLz48L3N2Zz4=\"}},1545:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return s}));var n=o(1437);const s={\"userscript.js\":async function(e){let{addon:t,console:o,msg:n}=e;const s=await t.tab.traps.getBlockly(),r=t.tab.traps.vm,i=[\"RENAME_VARIABLE_ID\",\"DELETE_VARIABLE_ID\",\"NEW_BROADCAST_MESSAGE_ID\",\"RENAME_BROADCAST_MESSAGE_ID\"],a=(e,t)=>!r.runtime.getAllVarNamesOfType(t).includes(e),c=(e,t)=>!r.editingTarget.lookupVariableByNameAndType(e,t),l={createGlobalVariable:{enabled:e=>a(e,\"\"),createVariable:(e,t)=>e.createVariable(t)},createLocalVariable:{enabled:e=>c(e,\"\"),createVariable:(e,t)=>e.createVariable(t,\"\",null,!0)},createGlobalList:{enabled:e=>a(e,\"list\"),createVariable:(e,t)=>e.createVariable(t,\"list\")},createLocalList:{enabled:e=>c(e,\"list\"),createVariable:(e,t)=>e.createVariable(t,\"list\",null,!0)},createBroadcast:{enabled:e=>a(e,\"broadcast_msg\"),createVariable:(e,t)=>e.createVariable(t,\"broadcast_msg\")}};let d=null,u=null,p=null,h=[],g=[],m=[],f=[];const b=s.DropDownDiv.show;s.DropDownDiv.show=function(){u=document.querySelector(\".blocklyDropdownMenu\");for(var e=arguments.length,o=new Array(e),n=0;n{},p=document.createElement(\"input\"),t.tab.displayNoneWhileDisabled(p,{display:\"flex\"}),p.type=\"text\",p.addEventListener(\"input\",I),p.addEventListener(\"keydown\",T),p.classList.add(\"u-dropdown-searchbar\"),u.insertBefore(p,u.firstChild),h=Array.from(u.children).filter((e=>\"INPUT\"!==e.tagName)).map((e=>({element:e,text:e.textContent}))),m=f,I();const r=b.call(this,...o);return d=s.DropDownDiv.getContentDiv(),d.style.width=getComputedStyle(d).width,d.style.height=getComputedStyle(d).height,u.insertBefore(p,u.firstChild),p.focus(),r};const y=s.DropDownDiv.clearContent;s.DropDownDiv.clearContent=function(){y.call(this),h=[],g=[],s.DropDownDiv.content_.style.height=\"\"};const k=s.FieldDropdown.prototype.getOptions;s.FieldDropdown.prototype.getOptions=function(){const e=k.call(this),t=this.sourceBlock_,o=r.editingTarget&&r.editingTarget.isStage;return t&&(\"data\"===t.category_?(e.push(x(\"createGlobalVariable\")),o||e.push(x(\"createLocalVariable\"))):\"data-lists\"===t.category_?(e.push(x(\"createGlobalList\")),o||e.push(x(\"createLocalList\"))):\"event_broadcast_menu\"!==t.type&&\"event_whenbroadcastreceived\"!==t.type||e.push(x(\"createBroadcast\"))),f=e,e};const v=s.FieldVariable.prototype.onItemSelected;function w(e,t){e.dispatchEvent(new MouseEvent(\"mousedown\",{relatedTarget:e,bubbles:!0})),t&&e.dispatchEvent(new MouseEvent(\"mouseup\",{relatedTarget:e,bubbles:!0}));const o=e.offsetTop,n=o+e.offsetHeight,s=d.scrollTop,r=d.offsetHeight,i=s+r;s>o?d.scrollTop=o:n>i&&(d.scrollTop=n-r)}function I(){const e=g;g=function(){const e=p.value.trim(),t=e.trim().toLowerCase(),o=(o,n)=>{const s=m[n][1];if(i.includes(s))return t?-1:0;if(Object.prototype.hasOwnProperty.call(l,s))return t&&l[s].enabled(e)?(o.element.lastChild.lastChild.textContent=x(s)[0],0):-1;const r=o.text.toLowerCase();return t===r?2:r.startsWith(t)?1:r.includes(t)?0:-1};return h.map(((e,t)=>({item:e,score:o(e,t)}))).sort(((e,t)=>{let{score:o}=e,{score:n}=t;return Math.max(0,n)-Math.max(0,o)}))}();let t=e.length!==g.length;if(!t)for(let o=0;o0){for(const{item:t}of e)t.element.remove();for(const{item:e}of g)u.appendChild(e.element)}for(const{item:e,score:t}of g)e.element.hidden=t<0}function T(e){if(\"Enter\"===e.key){e.stopPropagation(),e.preventDefault();const t=document.querySelector(\".goog-menuitem-highlight\");if(t&&!t.hidden)return void w(t,!0);const o=s.selected;if(\"\"===p.value&&o&&(\"event_broadcast\"===o.type||\"event_broadcastandwait\"===o.type||\"event_whenbroadcastreceived\"===o.type))return void s.DropDownDiv.hide();for(const{item:e}of g)if(!e.element.hidden){w(e.element,!0);break}}else if(\"Escape\"===e.key)s.DropDownDiv.hide();else if(\"ArrowDown\"===e.key||\"ArrowUp\"===e.key){e.preventDefault(),e.stopPropagation();const t=g.filter((e=>e.score>=0)).map((e=>e.item));if(0===t.length)return;let o=-1;for(let e=0;e{let{addon:t,console:o}=e;if(!t.tab.redux.state)return o.warn(\"Redux is not available!\");t.tab.redux.initialize(),t.tab.redux.addEventListener(\"statechanged\",(e=>{let{detail:n}=e;if(t.self.disabled)return;const s=n;if(!s.action||\"scratch-paint/clipboard/SET\"!==s.action.type)return;const r=s.next.scratchPaint.clipboard.items;if(1!==r.length)return;const i=r[0];if(!Array.isArray(i)||\"Raster\"!==i[0])return o.log(\"copied element is vector\");const a=i[1].source;t.tab.copyImage(a).then((()=>o.log(\"Image successfully copied\"))).catch((e=>o.error(\"Image could not be copied: \".concat(e))))}))}}},1553:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return s}));var n=o(1390);const s={\"userscript.js\":async function(e){let{addon:t}=e;const o=await t.tab.traps.getPaper(),s=function(){var e,s;if(!o.tool||!o.tool.boundingBoxTool)return;const r=null===(e=o.tool.boundingBoxTool._modeMap)||void 0===e||null===(s=e.SCALE)||void 0===s?void 0:s.constructor;if(!r||r.hasSkew)return;r.hasSkew=!0;const i=r.prototype.onMouseDown;r.prototype.onMouseDown=function(e,t,o){this.active||(this.index=e.item.data.index,i.call(this,e,t,o),this.skewCenter=!1,this.lastSkx=0,this.lastSky=0,this.skewBounds=this.itemGroup.bounds.clone())},n.a.paintSkew=function(e,n){if(!this.active)return;if(t.self.disabled)return n();const s=this.skewBounds,r=(e,t)=>{if(0===e&&0===t)return;let n;if(!this.skewCenter)switch(this._getRectCornerNameByIndex(this.index)){case\"topCenter\":case\"leftCenter\":n=this.itemGroup.position.add(new o.Point(s.width/2,s.height/2));break;case\"bottomCenter\":case\"rightCenter\":n=this.itemGroup.position.subtract(new o.Point(s.width/2,s.height/2))}const r=this.skewCenter?this.itemGroup.position:n,i=this.skewCenter?2:1,a=e/s.height*i,c=t/s.width*i;this.itemGroup.shear(a,c,r),this.selectionAnchor&&this.selectionAnchor.shear(-a,-c)};r(-this.lastSkx,-this.lastSky),this.skewCenter=e.modifiers.alt;let i=0,a=0;if(this.lastSkx=0,this.lastSky=0,!e.modifiers.control&&!e.modifiers.command||this.isCorner)n();else{this.centered=!1,this.itemGroup.scale(1/this.lastSx,1/this.lastSy,this.pivot),this.selectionAnchor&&this.selectionAnchor.scale(this.lastSx,this.lastSy),this.lastSx=1,this.lastSy=1;const t=e.point.subtract(this.pivot);switch(this._getRectCornerNameByIndex(this.index)){case\"topCenter\":t.x*=-1,t.y=0;break;case\"bottomCenter\":t.y=0;break;case\"leftCenter\":t.y*=-1,t.x=0;break;case\"rightCenter\":t.x=0;break;default:t.x=0,t.y=0}i=t.x,a=t.y,r(i,a)}this.lastSkx=i,this.lastSky=a},Object(n.b)(o,r)};t.tab.redux.initialize(),t.tab.redux.addEventListener(\"statechanged\",(e=>{const t=e.detail.action;\"scratch-paint/modes/CHANGE_MODE\"!==t.type||\"BIT_SELECT\"!==t.mode&&\"SELECT\"!==t.mode||s()})),s()}}},1554:function(e,t,o){\"use strict\";function n(e,t){var o=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),o.push.apply(o,n)}return o}function s(e){for(var t=1;tdocument.body.classList.toggle(\"sa-stage-color-picker-picking\",e);let a=!1;document.addEventListener(\"click\",(e=>{a=e.isTrusted}),{capture:!0}),t.tab.redux.initialize(),t.tab.redux.addEventListener(\"statechanged\",(e=>{const o=e.detail.action;o[r]||(!t.self.disabled&&a&&\"scratch-paint/eye-dropper/ACTIVATE_COLOR_PICKER\"===o.type&&(i(!0),t.tab.redux.dispatch({type:\"scratch-gui/color-picker/ACTIVATE_COLOR_PICKER\",callback:e=>{queueMicrotask((()=>{t.tab.redux.dispatch(s(s({},o),{},{[r]:!0})),o.callback(e),o.previousMode&&o.previousMode.activate(),t.tab.redux.dispatch({type:\"scratch-paint/eye-dropper/DEACTIVATE_COLOR_PICKER\",[r]:!0}),i(!1)}))}})),\"scratch-paint/eye-dropper/DEACTIVATE_COLOR_PICKER\"===o.type&&(i(!1),t.tab.redux.state.scratchGui.colorPicker.active&&t.tab.redux.dispatch({type:\"scratch-gui/color-picker/DEACTIVATE_COLOR_PICKER\",[r]:!0})))}))},\"style.css\":o.n(i).a}},1563:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return n}));const n={\"userscript.js\":async function(e){let{addon:t,console:o,msg:n}=e;const s=await t.tab.traps.getBlockly(),r=t.tab.traps.vm;let i={},a={};const c={isNoop:!0},l=()=>{const e=Math.floor(256*Math.random()*256*256);return\"#\".concat(e.toString(16).padStart(6,\"0\"))},d=()=>{if(i={},a={},t.settings.get(\"motion\")&&(i.motion_turnright=[c,{opcode:\"motion_turnleft\"}],i.motion_turnleft=[{opcode:\"motion_turnright\"},c],i.motion_setx=[c,{opcode:\"motion_changexby\",remapInputName:{X:\"DX\"}},{opcode:\"motion_sety\",remapInputName:{X:\"Y\"}},{opcode:\"motion_changeyby\",remapInputName:{X:\"DY\"}}],i.motion_changexby=[{opcode:\"motion_setx\",remapInputName:{DX:\"X\"}},c,{opcode:\"motion_sety\",remapInputName:{DX:\"Y\"}},{opcode:\"motion_changeyby\",remapInputName:{DX:\"DY\"}}],i.motion_sety=[{opcode:\"motion_setx\",remapInputName:{Y:\"X\"}},{opcode:\"motion_changexby\",remapInputName:{Y:\"DX\"}},c,{opcode:\"motion_changeyby\",remapInputName:{Y:\"DY\"}}],i.motion_changeyby=[{opcode:\"motion_setx\",remapInputName:{DY:\"X\"}},{opcode:\"motion_changexby\",remapInputName:{DY:\"DX\"}},{opcode:\"motion_sety\",remapInputName:{DY:\"Y\"}},c],i.motion_xposition=[c,{opcode:\"motion_yposition\"}],i.motion_yposition=[{opcode:\"motion_xposition\"},c]),t.settings.get(\"looks\")&&(i.looks_seteffectto=[c,{opcode:\"looks_changeeffectby\",remapInputName:{VALUE:\"CHANGE\"}}],i.looks_changeeffectby=[{opcode:\"looks_seteffectto\",remapInputName:{CHANGE:\"VALUE\"}},c],i.looks_setsizeto=[c,{opcode:\"looks_changesizeby\",remapInputName:{SIZE:\"CHANGE\"}}],i.looks_changesizeby=[{opcode:\"looks_setsizeto\",remapInputName:{CHANGE:\"SIZE\"}},c],i.looks_costumenumbername=[c,{opcode:\"looks_backdropnumbername\"}],i.looks_backdropnumbername=[{opcode:\"looks_costumenumbername\"},c],i.looks_show=[c,{opcode:\"looks_hide\"}],i.looks_hide=[{opcode:\"looks_show\"},c],i.looks_nextcostume=[c,{opcode:\"looks_nextbackdrop\"}],i.looks_nextbackdrop=[{opcode:\"looks_nextcostume\"},c],i.looks_say=[c,{opcode:\"looks_sayforsecs\",createInputs:{SECS:{shadowType:\"math_number\",value:\"2\"}}},{opcode:\"looks_think\"},{opcode:\"looks_thinkforsecs\",createInputs:{SECS:{shadowType:\"math_number\",value:\"2\"}}}],i.looks_think=[{opcode:\"looks_say\"},{opcode:\"looks_sayforsecs\",createInputs:{SECS:{shadowType:\"math_number\",value:\"2\"}}},c,{opcode:\"looks_thinkforsecs\",createInputs:{SECS:{shadowType:\"math_number\",value:\"2\"}}}],i.looks_sayforsecs=[{opcode:\"looks_say\",splitInputs:[\"SECS\"]},{opcode:\"looks_think\",splitInputs:[\"SECS\"]},c,{opcode:\"looks_thinkforsecs\"}],i.looks_thinkforsecs=[{opcode:\"looks_say\",splitInputs:[\"SECS\"]},{opcode:\"looks_think\",splitInputs:[\"SECS\"]},{opcode:\"looks_sayforsecs\"},c],i.looks_switchbackdropto=[c,{opcode:\"looks_switchbackdroptoandwait\"}],i.looks_switchbackdroptoandwait=[{opcode:\"looks_switchbackdropto\"},c],i.looks_gotofrontback=[c,{opcode:\"looks_goforwardbackwardlayers\",remapInputName:{FRONT_BACK:\"FORWARD_BACKWARD\"},mapFieldValues:{FRONT_BACK:{front:\"forward\",back:\"backward\"}},createInputs:{NUM:{shadowType:\"math_integer\",value:\"1\"}}}],i.looks_goforwardbackwardlayers=[{opcode:\"looks_gotofrontback\",splitInputs:[\"NUM\"],remapInputName:{FORWARD_BACKWARD:\"FRONT_BACK\"},mapFieldValues:{FORWARD_BACKWARD:{forward:\"front\",backward:\"back\"}}},c]),t.settings.get(\"sound\")&&(i.sound_play=[c,{opcode:\"sound_playuntildone\"}],i.sound_playuntildone=[{opcode:\"sound_play\"},c],i.sound_seteffectto=[c,{opcode:\"sound_changeeffectby\"}],i.sound_changeeffectby=[{opcode:\"sound_seteffectto\"},c],i.sound_setvolumeto=[c,{opcode:\"sound_changevolumeby\"}],i.sound_changevolumeby=[{opcode:\"sound_setvolumeto\"},c]),t.settings.get(\"event\")&&(i.event_broadcast=[c,{opcode:\"event_broadcastandwait\"}],i.event_broadcastandwait=[{opcode:\"event_broadcast\"},c]),t.settings.get(\"control\")&&(i.control_if=[c,{opcode:\"control_if_else\"}],i.control_if_else=[{opcode:\"control_if\",splitInputs:[\"SUBSTACK2\"]},c],i.control_repeat_until=[c,{opcode:\"control_wait_until\",splitInputs:[\"SUBSTACK\"]},{opcode:\"control_forever\",splitInputs:[\"CONDITION\"]}],i.control_forever=[{opcode:\"control_repeat_until\"},c],i.control_wait_until=[{opcode:\"control_repeat_until\"},c]),t.settings.get(\"operator\")&&(i.operator_equals=[{opcode:\"operator_gt\"},c,{opcode:\"operator_lt\"}],i.operator_gt=[c,{opcode:\"operator_equals\"},{opcode:\"operator_lt\"}],i.operator_lt=[{opcode:\"operator_gt\"},{opcode:\"operator_equals\"},c],i.operator_add=[c,{opcode:\"operator_subtract\"},{opcode:\"operator_multiply\"},{opcode:\"operator_divide\"},{opcode:\"operator_mod\"}],i.operator_subtract=[{opcode:\"operator_add\"},c,{opcode:\"operator_multiply\"},{opcode:\"operator_divide\"},{opcode:\"operator_mod\"}],i.operator_multiply=[{opcode:\"operator_add\"},{opcode:\"operator_subtract\"},c,{opcode:\"operator_divide\"},{opcode:\"operator_mod\"}],i.operator_divide=[{opcode:\"operator_add\"},{opcode:\"operator_subtract\"},{opcode:\"operator_multiply\"},c,{opcode:\"operator_mod\"}],i.operator_mod=[{opcode:\"operator_add\"},{opcode:\"operator_subtract\"},{opcode:\"operator_multiply\"},{opcode:\"operator_divide\"},c],i.operator_and=[c,{opcode:\"operator_or\"}],i.operator_or=[{opcode:\"operator_and\"},c]),t.settings.get(\"sensing\")&&(i.sensing_mousex=[c,{opcode:\"sensing_mousey\"}],i.sensing_mousey=[{opcode:\"sensing_mousex\"},c],i.sensing_touchingcolor=[c,{opcode:\"sensing_coloristouchingcolor\",createInputs:{COLOR2:{shadowType:\"colour_picker\",value:l}}}],i.sensing_coloristouchingcolor=[{opcode:\"sensing_touchingcolor\",splitInputs:[\"COLOR2\"]},c]),t.settings.get(\"data\")&&(i.data_setvariableto=[c,{opcode:\"data_changevariableby\",remapShadowType:{VALUE:\"math_number\"}}],i.data_changevariableby=[{opcode:\"data_setvariableto\",remapShadowType:{VALUE:\"text\"}},c],i.data_showvariable=[c,{opcode:\"data_hidevariable\"}],i.data_hidevariable=[{opcode:\"data_showvariable\"},c],i.data_showlist=[c,{opcode:\"data_hidelist\"}],i.data_hidelist=[{opcode:\"data_showlist\"},c],i.data_replaceitemoflist=[c,{opcode:\"data_insertatlist\"}],i.data_insertatlist=[{opcode:\"data_replaceitemoflist\"},c],i.data_deleteoflist=[c,{opcode:\"data_deletealloflist\",splitInputs:[\"INDEX\"]}],i.data_deletealloflist=[{opcode:\"data_deleteoflist\",createInputs:{INDEX:{shadowType:\"math_integer\",value:\"1\"}}},c]),t.settings.get(\"extension\")&&(i.pen_penDown=[c,{opcode:\"pen_penUp\"}],i.pen_penUp=[{opcode:\"pen_penDown\"},c],i.pen_setPenColorParamTo=[c,{opcode:\"pen_changePenColorParamBy\"}],i.pen_changePenColorParamBy=[{opcode:\"pen_setPenColorParamTo\"},c],i.pen_setPenHueToNumber=[c,{opcode:\"pen_changePenHueBy\"}],i.pen_changePenHueBy=[{opcode:\"pen_setPenHueToNumber\"},c],i.pen_setPenShadeToNumber=[c,{opcode:\"pen_changePenShadeBy\"}],i.pen_changePenShadeBy=[{opcode:\"pen_setPenShadeToNumber\"},c],i.pen_setPenSizeTo=[c,{opcode:\"pen_changePenSizeBy\"}],i.pen_changePenSizeBy=[{opcode:\"pen_setPenSizeTo\"},c],i.music_setTempo=[c,{opcode:\"music_changeTempo\"}],i.music_changeTempo=[{opcode:\"music_setTempo\"},c]),t.settings.get(\"sa\")){const e=\"​​log​​ %s\",t=\"​​warn​​ %s\",o=\"​​error​​ %s\",s=n(\"debugger_log\"),r=n(\"debugger_warn\"),i=n(\"debugger_error\"),c={mutate:{proccode:e},msg:s},l={mutate:{proccode:t},msg:r},d={mutate:{proccode:o},msg:i};a[e]=[{msg:s,isNoop:!0},l,d],a[t]=[c,{msg:r,isNoop:!0},d],a[o]=[c,l,{msg:i,isNoop:!0}]}i.data_variable=[],i.data_listcontents=[]};d(),t.settings.addEventListener(\"change\",d);const u=e=>\"text\"===e?\"TEXT\":\"colour_picker\"===e?\"COLOUR\":\"NUM\",p=(e,t)=>()=>{var o;if(!t.isNoop)if(t.fieldValue)e.setFieldValue(t.fieldValue,\"VALUE\");else try{s.Events.setGroup(!0);const n=e.workspace,r=[];if(t.splitInputs)for(const o of t.splitInputs){const t=e.getInput(o);if(!t)continue;const n=t.connection;if(n&&n.isConnected()){const e=n.targetBlock();e.isShadow()||(n.disconnect(),r.push(e))}}const i=s.Xml.blockToDom(e),a=e.getRelativeToSurfaceXY();i.setAttribute(\"x\",a.x),i.setAttribute(\"y\",a.y),t.opcode&&i.setAttribute(\"type\",t.opcode);const c=e.getParent();let l,d;if(c){l=c.getConnections_().find((t=>t.targetConnection&&t.targetConnection.sourceBlock_===e));const t=e.getConnections_().find((e=>e.targetConnection&&e.targetConnection.sourceBlock_===c));d=t.type}for(const e of Array.from(i.children)){const o=e.getAttribute(\"name\");if(t.splitInputs&&t.splitInputs.includes(o)){i.removeChild(e);continue}const n=t.remapInputName&&t.remapInputName[o];n&&e.setAttribute(\"name\",n);const s=t.remapShadowType&&t.remapShadowType[o];if(s){const t=e.firstChild,o=t.firstChild;t.setAttribute(\"type\",s),o.setAttribute(\"name\",u(s))}const r=t.mapFieldValues&&t.mapFieldValues[o];if(r&&\"FIELD\"===e.tagName){const t=r[e.innerText];\"string\"==typeof t&&(e.innerText=t)}}if(t.mutate){const e=i.querySelector(\"mutation\");for(const[o,n]of Object.entries(t.mutate))e.setAttribute(o,n)}if(t.createInputs)for(const[e,n]of Object.entries(t.createInputs)){const t=document.createElement(\"value\");t.setAttribute(\"name\",e);const s=document.createElement(\"shadow\");s.setAttribute(\"type\",n.shadowType);const r=document.createElement(\"field\");r.setAttribute(\"name\",u(n.shadowType)),r.innerText=\"function\"==typeof(o=n.value)?o():o,s.appendChild(r),t.appendChild(s),i.appendChild(t)}e.dispose();const p=((e,t)=>{const o=s.Xml.domToBlock(t,e),n=+t.getAttribute(\"x\"),r=+t.getAttribute(\"y\");return o.moveBy(n,r),o})(n,i);if(l){const e=p.getConnections_();e.find((e=>e.type===d)).connect(l)}for(const e of r){const t=e.getSvgRoot();t.parentNode.appendChild(t)}}finally{s.Events.setGroup(!1)}};t.tab.createBlockContextMenu(((e,o)=>{if(!t.self.disabled){const c=o.type;let l=i[o.type]||[];const d=t.settings.get(\"customargs\")?t.settings.get(\"customargsmode\"):\"off\";if(\"off\"!==d&&[\"argument_reporter_boolean\",\"argument_reporter_string_number\"].includes(c)&&!o.isShadow()){const t=h();if(\"all\"===d)switch(c){case\"argument_reporter_string_number\":l=Object.values(t).map((e=>e.stringArgs)).flat(1);break;case\"argument_reporter_boolean\":l=Object.values(t).map((e=>e.boolArgs)).flat(1)}else if(\"defOnly\"===d){const n=o.getRootBlock();if(\"procedures_definition\"!==n.type)return e;const s=t[n.getChildren(!0)[0].getProcCode()];switch(c){case\"argument_reporter_string_number\":l=s.stringArgs;break;case\"argument_reporter_boolean\":l=s.boolArgs}}const n=o.getFieldValue(\"VALUE\");l=(r=l,[...new Set(r)]).map((e=>({isNoop:e===n,fieldValue:e,msg:e})))}if(\"procedures_call\"===o.type){const e=o.getProcCode();a[e]&&(l=a[e])}if(t.settings.get(\"noop\")||(l=l.filter((e=>!e.isNoop))),l.forEach(((t,s)=>{const r=e.findIndex((e=>e._isDevtoolsFirstItem)),i=-1!==r?r:e.length,a=t.msg?t.msg:t.opcode?n(t.opcode):n(o.type);e.splice(i,0,{enabled:!0,text:a,callback:p(o,t),separator:0===s})})),\"data_variable\"===o.type||\"data_listcontents\"===o.type){const t=e.findIndex((e=>e.text===s.Msg.DELETE_BLOCK)),o=e[t+1];o&&(o.separator=!0)}}var r;return e}),{blocks:!0});const h=()=>{const e={},t=r.editingTarget;return Object.values(t.blocks._blocks).filter((e=>\"procedures_prototype\"===e.opcode)).forEach((t=>{const o=t.mutation.proccode,n=JSON.parse(t.mutation.argumentnames),s=o.split(/(?=[^\\\\]%[nbs])/g).map((e=>e.trim())).filter((e=>\"%\"===e.charAt(0))).map((e=>e.substring(0,2)));const r=[],i=[];for(let e=0;e{n.b(!t.self.disabled,t.settings.get(\"invertDrag\"))};t.self.addEventListener(\"disabled\",s),t.self.addEventListener(\"reenabled\",s),t.settings.addEventListener(\"change\",s),s(),n.a(t)}}},1574:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return n}));const n={\"userscript.js\":async e=>{let{addon:t,console:o,msg:n}=e;const s=[\"sound\",\"costume\"];t.tab.createEditorContextMenu((e=>{const o=t.tab.traps.vm.editingTarget;\"sound\"===e.type?o.reorderSound(e.index,0):o.reorderCostume(e.index,0),queueMicrotask((()=>{t.tab.traps.vm.emitTargetsUpdate(),t.tab.traps.vm.runtime.emitProjectChanged(),e.target.click()}))}),{types:s,position:\"assetContextMenuAfterExport\",order:1,label:n(\"top\"),condition:e=>0!==e.index}),t.tab.createEditorContextMenu((e=>{const o=t.tab.traps.vm.editingTarget;\"sound\"===e.type?o.reorderSound(e.index,1/0):o.reorderCostume(e.index,1/0),queueMicrotask((()=>{t.tab.traps.vm.emitTargetsUpdate(),t.tab.traps.vm.runtime.emitProjectChanged(),e.target.click()}))}),{types:s,position:\"assetContextMenuAfterExport\",order:2,label:n(\"bottom\"),condition:e=>e.index!==e.target.parentNode.parentNode.childElementCount-1})}}},1577:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return s}));var n=o(1395);const s={\"userscript.js\":async function(e){let{addon:t,console:o}=e;const s=()=>{n.c(!t.self.disabled)};t.self.addEventListener(\"disabled\",s),t.self.addEventListener(\"reenabled\",s),s(),n.a(t)}}},1578:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return n}));const n={\"userscript.js\":async function(e){let{addon:t,msg:o,console:n}=e;const s=t.tab.traps.vm,r=await t.tab.traps.getBlockly(),i=\"RENAME_BROADCAST_MESSAGE_ID\",a=r.BROADCAST_MESSAGE_VARIABLE_TYPE,c=r.FieldVariable.dropdownCreate;r.FieldVariable.dropdownCreate=function(){const e=c.call(this);return!t.self.disabled&&this.defaultType_===a&&this.sourceBlock_.workspace.getVariableTypes().includes(\"broadcast_msg\")&&e.push([o(\"RENAME_BROADCAST\"),i]),e};const l=r.FieldVariable.prototype.onItemSelected;r.FieldVariable.prototype.onItemSelected=function(e,t){const o=this.sourceBlock_.workspace;if(!this.sourceBlock_||!o||t.getValue()!==i)return l.call(this,e,t);h(o,this.variable_)};const d=()=>{const e=new Set(s.runtime.targets.map((e=>e.blocks)));for(const t of e)t.resetCache()},u=e=>{const t=r.Events.FIRE_QUEUE_[0],o=t.run;t.run=function(t){o.call(this,t),e(t)}},p=(e,t)=>{const o=s.runtime.getTargetForStage().variables[e];o.name=t,o.value=t;const n=new Set(s.runtime.targets.map((e=>e.blocks)));for(const o of n)for(const n of Object.values(o._blocks)){const o=n.fields&&n.fields.BROADCAST_OPTION;o&&o.id===e&&(o.value=t)}d()},h=(e,t)=>{const n=o(\"RENAME_BROADCAST_MODAL_TITLE\"),i=t.name,c=t.getId(),l=o(\"RENAME_BROADCAST_TITLE\",{name:i}),h=i;r.prompt(l,h,(function(t){if(!(t=r.Variables.trimName_(t)))return;!!e.getVariable(t,a)?((e,t,o,n)=>{const i=s.runtime.getTargetForStage().lookupBroadcastByInputValue(n).id;r.Events.setGroup(!0);for(const o of e.getAllBlocks())for(const e of o.inputList)for(const o of e.fieldRow)\"BROADCAST_OPTION\"===o.name&&o.getValue()===t&&o.setValue(i);e.deleteVariableById(t),r.Events.setGroup(!1);const a=[],c=new Set(s.runtime.targets.map((e=>e.blocks)));for(const e of c)for(const o of Object.values(e._blocks)){const e=o.fields&&o.fields.BROADCAST_OPTION;e&&e.id===t&&a.push(o)}const l=e=>{const s=e?i:t,r=e?n:o;for(const e of a){const t=e.fields.BROADCAST_OPTION;t.id=s,t.value=r}d()};l(!0),u((e=>{l(e)}))})(e,c,i,t):((e,t,o,n)=>{e.renameVariableById(t,n),p(t,n),u((e=>{p(t,e?n:o)}))})(e,c,i,t)}),n,a)};(()=>{const e=r.getMainWorkspace(),t=e&&e.getFlyout();if(e&&t){const o=[...e.getAllBlocks(),...t.getWorkspace().getAllBlocks()];for(const e of o)for(const t of e.inputList)for(const e of t.fieldRow)e instanceof r.FieldVariable&&(e.menuGenerator_=r.FieldVariable.dropdownCreate)}})()}}},1580:function(e,t,o){\"use strict\";o.r(t),o.d(t,\"resources\",(function(){return s}));var n=o(1506);const s={\"userscript.js\":async function(e){let{addon:t,console:o}=e;const n=t.tab.traps.vm,s=()=>{u.classList.toggle(\"sa-comment-preview-delay\",\"none\"!==t.settings.get(\"delay\")),u.classList.toggle(\"sa-comment-preview-reduce-transparency\",t.settings.get(\"reduce-transparency\")),u.classList.toggle(\"sa-comment-preview-fade\",!t.settings.get(\"reduce-animation\"))};let r=null,i=null,a=0,c=0,l=!1;const d=document.createElement(\"div\");d.classList.add(\"sa-comment-preview-outer\");const u=document.createElement(\"div\");u.classList.add(\"sa-comment-preview-inner\"),u.classList.add(\"sa-comment-preview-hidden\"),s(),t.settings.addEventListener(\"change\",s),t.tab.displayNoneWhileDisabled(d),d.appendChild(u),document.body.appendChild(d);const p=e=>n.editingTarget.blocks.getBlock(e)||n.runtime.flyoutBlocks.getBlock(e),h=e=>e&&e.comment&&n.editingTarget.comments[e.comment],g=()=>{d.style.transform=\"translate(\".concat(a+8,\"px, \").concat(c+8,\"px)\")},m=()=>{r&&(r=null,u.classList.add(\"sa-comment-preview-hidden\"))};document.addEventListener(\"mouseover\",(e=>{if(t.self.disabled)return;if(clearTimeout(i),l)return;const o=e.target.closest(\".blocklyBubbleCanvas > g, .blocklyBlockCanvas .blocklyDraggable[data-id]\");if(o===r)return;if(!o)return void m();let s=null;if(t.settings.get(\"hover-view\")&&e.target.closest(\".blocklyBubbleCanvas > g\")&&!e.target.closest(\"line\")){if(\"none\"!==o.querySelector(\"text.scratchCommentText\").getAttribute(\"display\")){const e=o.querySelector(\"textarea\");s=e.value}}else if(e.target.closest(\".blocklyBlockCanvas .blocklyDraggable[data-id]\")){const e=o.dataset.id,r=p(e),i=h(r);if(t.settings.get(\"hover-view-block\")&&i)s=i.text;else if(r&&\"procedures_call\"===r.opcode&&t.settings.get(\"hover-view-procedure\")){const e=(e=>{const t=Object.values(n.editingTarget.blocks._blocks).find((t=>\"procedures_prototype\"===t.opcode&&t.mutation.proccode===e));if(t){if(t.parent)return p(t.parent);const e=t.id;return Object.values(n.editingTarget.blocks._blocks).find((t=>\"procedures_definition\"===t.opcode&&t.inputs.custom_block&&t.inputs.custom_block.block===e))}return null})(r.mutation.proccode),t=h(e);t&&(s=t.text)}}null!==s&&\"\"!==s.trim()?i=(e=>{if(!u.classList.contains(\"sa-comment-preview-hidden\"))return void e();const o=t.settings.get(\"delay\");return\"long\"===o?setTimeout(e,500):\"short\"===o?setTimeout(e,300):void e()})((()=>{r=o,(e=>{u.innerText=e,u.classList.remove(\"sa-comment-preview-hidden\"),g()})(s)})):m()})),document.addEventListener(\"mousemove\",(e=>{a=e.clientX,c=e.clientY,l=!1,t.settings.get(\"follow-mouse\")&&!u.classList.contains(\"sa-comment-preview-hidden\")&&g()})),document.addEventListener(\"mousedown\",(()=>{m(),l=!0}),{capture:!0})},\"userstyle.css\":o.n(n).a}}}]);","name":"js/pentapod/addon-default-entry.d3f27afe57fe32a8f692.js","input":"(window[\"webpackJsonpGUI\"] = window[\"webpackJsonpGUI\"] || []).push([[4],{\n\n/***/ 1382:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \"/* Imported by other addons */\\n\\n.sa-block-color {\\n --sa-block-colored-background: var(--sa-block-background-primary);\\n --sa-block-colored-background-secondary: var(--sa-block-field-background);\\n --sa-block-bright-background: var(--sa-block-background-primary);\\n --sa-block-text: var(--editorTheme3-blockText, white);\\n --sa-block-gray-text: white;\\n --sa-block-colored-text: var(--sa-block-background-primary);\\n --sa-block-text-on-bright-background: var(--editorTheme3-blockText, white);\\n --sa-block-input-color: var(--editorTheme3-inputColor, white);\\n --sa-block-input-text: var(--editorTheme3-inputColor-text, #575e75);\\n}\\n\\n.sa-block-color-motion {\\n --sa-block-background-primary: var(--editorTheme3-motion-primary, #4c97ff);\\n --sa-block-background-secondary: var(--editorTheme3-motion-secondary, #4280d7);\\n --sa-block-background-tertiary: var(--editorTheme3-motion-tertiary, #3373cc);\\n --sa-block-field-background: var(--editorTheme3-motion-field, #3373cc);\\n}\\n\\n.sa-block-color-looks {\\n --sa-block-background-primary: var(--editorTheme3-looks-primary, #9966ff);\\n --sa-block-background-secondary: var(--editorTheme3-looks-secondary, #855cd6);\\n --sa-block-background-tertiary: var(--editorTheme3-looks-tertiary, #774dcb);\\n --sa-block-field-background: var(--editorTheme3-looks-field, #774dcb);\\n}\\n\\n.sa-block-color-sounds {\\n --sa-block-background-primary: var(--editorTheme3-sounds-primary, #cf63cf);\\n --sa-block-background-secondary: var(--editorTheme3-sounds-secondary, #c94fc9);\\n --sa-block-background-tertiary: var(--editorTheme3-sounds-tertiary, #bd42bd);\\n --sa-block-field-background: var(--editorTheme3-sounds-field, #bd42bd);\\n}\\n\\n.sa-block-color-events {\\n --sa-block-background-primary: var(--editorTheme3-event-primary, #ffbf00);\\n --sa-block-background-secondary: var(--editorTheme3-event-secondary, #e6ac00);\\n --sa-block-background-tertiary: var(--editorTheme3-event-tertiary, #cc9900);\\n --sa-block-field-background: var(--editorTheme3-event-field, #cc9900);\\n}\\n\\n.sa-block-color-control {\\n --sa-block-background-primary: var(--editorTheme3-control-primary, #ffab19);\\n --sa-block-background-secondary: var(--editorTheme3-control-secondary, #ec9c13);\\n --sa-block-background-tertiary: var(--editorTheme3-control-tertiary, #cf8b17);\\n --sa-block-field-background: var(--editorTheme3-control-field, #cf8b17);\\n}\\n\\n.sa-block-color-sensing {\\n --sa-block-background-primary: var(--editorTheme3-sensing-primary, #5cb1d6);\\n --sa-block-background-secondary: var(--editorTheme3-sensing-secondary, #47a8d1);\\n --sa-block-background-tertiary: var(--editorTheme3-sensing-tertiary, #2e8eb8);\\n --sa-block-field-background: var(--editorTheme3-sensing-field, #2e8eb8);\\n}\\n\\n.sa-block-color-operators {\\n --sa-block-background-primary: var(--editorTheme3-operators-primary, #59c059);\\n --sa-block-background-secondary: var(--editorTheme3-operators-secondary, #46b946);\\n --sa-block-background-tertiary: var(--editorTheme3-operators-tertiary, #389438);\\n --sa-block-field-background: var(--editorTheme3-operators-field, #389438);\\n}\\n\\n.sa-block-color-data {\\n --sa-block-background-primary: var(--editorTheme3-data-primary, #ff8c1a);\\n --sa-block-background-secondary: var(--editorTheme3-data-secondary, #ff8000);\\n --sa-block-background-tertiary: var(--editorTheme3-data-tertiary, #db6e00);\\n --sa-block-field-background: var(--editorTheme3-data-field, #db6e00);\\n}\\n\\n.sa-block-color-data-lists,\\n.sa-block-color-list {\\n --sa-block-background-primary: var(--editorTheme3-data_lists-primary, #ff661a);\\n --sa-block-background-secondary: var(--editorTheme3-data_lists-secondary, #ff5500);\\n --sa-block-background-tertiary: var(--editorTheme3-data_lists-tertiary, #e64d00);\\n --sa-block-field-background: var(--editorTheme3-data_lists-field, #e64d00);\\n}\\n\\n.sa-block-color-more,\\n.sa-block-color-null {\\n --sa-block-background-primary: var(--editorTheme3-more-primary, #ff6680);\\n --sa-block-background-secondary: var(--editorTheme3-more-secondary, #ff4d6a);\\n --sa-block-background-tertiary: var(--editorTheme3-more-tertiary, #ff3355);\\n --sa-block-field-background: var(--editorTheme3-more-field, #ff3355);\\n}\\n\\n.sa-block-color-pen {\\n --sa-block-background-primary: var(--editorTheme3-pen-primary, #0fbd8c);\\n --sa-block-background-secondary: var(--editorTheme3-pen-secondary, #0da57a);\\n --sa-block-background-tertiary: var(--editorTheme3-pen-tertiary, #0b8e69);\\n --sa-block-field-background: var(--editorTheme3-pen-field, #0b8e69);\\n}\\n\\n.sa-block-color-addon-custom-block {\\n --sa-block-background-primary: var(--editorTheme3-addons-primary, #29beb8);\\n --sa-block-background-secondary: var(--editorTheme3-addons-secondary, #3aa8a4);\\n --sa-block-background-tertiary: var(--editorTheme3-addons-tertiary, #3aa8a4);\\n --sa-block-field-background: var(--editorTheme3-addons-field, #3aa8a4);\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1383:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return getTextWidth; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return clearTextWidthCache; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"c\", function() { return onClearTextWidthCache; });\n/* harmony import */ var _event_target_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(709);\n /* inserted by pull.js */\n\nconst textWidthCache = new Map();\nconst textWidthCacheSize = 1000;\nconst eventTarget = new _event_target_js__WEBPACK_IMPORTED_MODULE_0__[/* default */ \"a\"]();\nconst eventClearTextCache = \"clearTextCache\";\n\n/**\n * Gets the width of an svg text element, with caching.\n * @param {SVGTextElement} textElement\n */\nfunction getTextWidth(textElement) {\n let string = textElement.innerHTML;\n if (string.length === 0) return 0;\n let width = textWidthCache.get(string);\n if (width) return width;\n width = textElement.getBoundingClientRect().width;\n textWidthCache.set(string, width);\n if (textWidthCache.size > textWidthCacheSize) {\n textWidthCache.delete(textWidthCache.keys().next());\n }\n return width;\n}\n\n/**\n * Clears the text width cache of the middle click popup.\n */\nfunction clearTextWidthCache() {\n textWidthCache.clear();\n eventTarget.dispatchEvent(new CustomEvent(eventClearTextCache));\n}\n\n/**\n * @param {() => void} func\n */\nfunction onClearTextWidthCache(func) {\n eventTarget.addEventListener(eventClearTextCache, func);\n}\n\n/***/ }),\n\n/***/ 1388:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return getHexRegex; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return normalizeHex; });\nconst getHexRegex = () => /^#?[0-9a-fA-F]{3,8}$/;\nconst normalizeHex = input => {\n let hex = String(input);\n if (!getHexRegex().test(hex)) return \"#000000\";\n if (!hex.startsWith(\"#\")) hex = \"#\".concat(hex);\n if (hex.length === 4) {\n const [_, r, g, b] = hex;\n hex = \"#\".concat(r).concat(r).concat(g).concat(g).concat(b).concat(b);\n }\n return hex.toLowerCase();\n};\n\n/***/ }),\n\n/***/ 1389:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return RateLimiter; });\nclass RateLimiter {\n constructor(wait) {\n this.timeout = null;\n this.callback = null;\n this.wait = wait;\n }\n abort() {\n let call = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n if (this.timeout) {\n clearTimeout(this.timeout);\n if (call) this.callback();\n this.timeout = this.callback = null;\n }\n }\n limit(callback) {\n this.abort(false);\n this.callback = callback;\n this.timeout = setTimeout(() => {\n this.timeout = this.callback = null;\n callback();\n }, this.wait);\n }\n}\n\n/***/ }),\n\n/***/ 1390:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return addons; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return initialize; });\nlet overridden = false;\nconst addons = {\n paintSkew: null,\n paintSnap: null\n};\nfunction initialize(paper, ScaleTool) {\n if (overridden) return;\n overridden = true;\n const ogMouseDrag = ScaleTool.prototype.onMouseDrag;\n ScaleTool.prototype.onMouseDrag = function (event) {\n if (!this.active) return;\n const callSnap = () => {\n if (addons.paintSnap) addons.paintSnap.call(this, event);else ogMouseDrag.call(this, event);\n };\n if (addons.paintSkew) {\n addons.paintSkew.call(this, event, callSnap);\n } else {\n callSnap();\n }\n };\n}\n\n/***/ }),\n\n/***/ 1395:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return setCherryPicking; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"c\", function() { return setDuplication; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return load; });\nlet enableCherryPicking = false;\nlet invertCherryPicking = false;\nfunction setCherryPicking(newEnabled, newInverted) {\n enableCherryPicking = newEnabled;\n // If cherry picking is disabled, also disable invert. Duplicating blocks can still cause\n // this setting to be used.\n invertCherryPicking = newEnabled && newInverted;\n}\nlet enableDuplication = false;\nfunction setDuplication(newEnabled) {\n enableDuplication = newEnabled;\n}\n\n// mostRecentEvent_ is sometimes a fake event, so we can't rely on reading its properties.\nlet ctrlOrMetaPressed = false;\nlet altPressed = false;\ndocument.addEventListener(\"mousedown\", function (e) {\n ctrlOrMetaPressed = e.ctrlKey || e.metaKey;\n altPressed = e.altKey;\n}, {\n capture: true\n});\nlet loaded = false;\nasync function load(addon) {\n if (loaded) {\n return;\n }\n loaded = true;\n const ScratchBlocks = await addon.tab.traps.getBlockly();\n\n // https://github.com/scratchfoundation/scratch-blocks/blob/912b8cc728bea8fd91af85078c64fcdbfe21c87a/core/gesture.js#L454\n const originalStartDraggingBlock = ScratchBlocks.Gesture.prototype.startDraggingBlock_;\n ScratchBlocks.Gesture.prototype.startDraggingBlock_ = function () {\n let block = this.targetBlock_;\n\n // Scratch uses fake mouse events to implement right click > duplicate\n const isRightClickDuplicate = !(this.mostRecentEvent_ instanceof MouseEvent);\n const isDuplicating = enableDuplication && altPressed && !isRightClickDuplicate && !this.flyout_ && !this.shouldDuplicateOnDrag_ && this.targetBlock_.type !== \"procedures_definition\";\n const isCherryPickingInverted = invertCherryPicking && !isRightClickDuplicate && block.getParent();\n const canCherryPick = enableCherryPicking || isDuplicating;\n const isCherryPicking = canCherryPick && ctrlOrMetaPressed === !isCherryPickingInverted && !block.isShadow();\n if (isDuplicating || isCherryPicking) {\n if (!ScratchBlocks.Events.getGroup()) {\n // Scratch will disable grouping on its own later.\n ScratchBlocks.Events.setGroup(true);\n }\n }\n if (isDuplicating) {\n // Based on https://github.com/scratchfoundation/scratch-blocks/blob/feda366947432b9d82a4f212f43ff6d4ab6f252f/core/scratch_blocks_utils.js#L171\n // Setting this.shouldDuplicateOnDrag_ = true does NOT work because it doesn't call changeObscuredShadowIds\n this.startWorkspace_.setResizesEnabled(false);\n ScratchBlocks.Events.disable();\n let newBlock;\n try {\n const xmlBlock = ScratchBlocks.Xml.blockToDom(block);\n newBlock = ScratchBlocks.Xml.domToBlock(xmlBlock, this.startWorkspace_);\n ScratchBlocks.scratchBlocksUtils.changeObscuredShadowIds(newBlock);\n const xy = block.getRelativeToSurfaceXY();\n newBlock.moveBy(xy.x, xy.y);\n } catch (e) {\n console.error(e);\n }\n ScratchBlocks.Events.enable();\n if (newBlock) {\n block = newBlock;\n this.targetBlock_ = newBlock;\n if (ScratchBlocks.Events.isEnabled()) {\n ScratchBlocks.Events.fire(new ScratchBlocks.Events.BlockCreate(newBlock));\n }\n }\n }\n if (isCherryPicking) {\n if (isRightClickDuplicate || isDuplicating) {\n const nextBlock = block.getNextBlock();\n if (nextBlock) {\n nextBlock.dispose();\n }\n }\n block.unplug(true);\n }\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n return originalStartDraggingBlock.call(this, ...args);\n };\n}\n\n/***/ }),\n\n/***/ 1434:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\nexports.i(__webpack_require__(1382), \"\");\n\n// module\nexports.push([module.i, \".sa-find-bar {\\n display: flex;\\n align-items: center;\\n white-space: nowrap;\\n font-family: \\\"Helvetica Neue\\\", Helvetica, Arial, sans-serif;\\n width: 100%;\\n height: 100%;\\n margin-left: 1em;\\n}\\n.sa-find-bar[hidden] {\\n /* !important to override displayNoneWhileDisabled */\\n display: none !important;\\n}\\n\\n.sa-find-wrapper {\\n overflow: visible;\\n position: relative;\\n height: 2rem;\\n width: 100%;\\n max-width: 16em;\\n}\\n\\n.sa-find-dropdown-out {\\n display: block;\\n top: -6px;\\n z-index: 100;\\n width: 100%;\\n max-width: 16em;\\n position: relative;\\n padding: 4px;\\n border: none;\\n border-radius: 4px;\\n margin-top: 6px;\\n}\\n\\n.sa-find-dropdown-out.visible {\\n position: absolute;\\n width: 16em;\\n box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.3);\\n background-color: var(--ui-modal-background);\\n outline: 1px solid var(--ui-black-transparent);\\n}\\n\\n/* We need to modify Scratch styles so that the place where the find bar is injected */\\n/* has actually correct size information, which is used to make the find bar not cover up controls */\\n[class*=\\\"gui_tab-list_\\\"] {\\n width: 100%;\\n}\\n[class*=\\\"gui_tab_\\\"] {\\n flex-grow: 0;\\n}\\n\\n.sa-find-input {\\n width: 100%;\\n box-sizing: border-box !important;\\n /* !important required for extension, because CSS injection method (and hence order) differs from addon */\\n height: 1.5rem;\\n\\n /* Change Scratch default styles */\\n border-radius: 0.25rem;\\n font-size: 0.75rem;\\n padding-left: 0.4em;\\n}\\n\\n.sa-find-input:focus {\\n /* Change Scratch default styles */\\n box-shadow: none;\\n}\\n\\n.sa-find-dropdown {\\n display: none;\\n position: relative;\\n padding: 0.2em 0;\\n font-size: 0.75rem;\\n line-height: 1;\\n overflow-y: auto;\\n min-height: 128px;\\n max-height: 65vh;\\n user-select: none;\\n max-width: 100%;\\n margin-top: 6px;\\n border: none;\\n}\\n\\n.sa-find-dropdown-out.visible > .sa-find-dropdown {\\n display: block;\\n}\\n\\n.sa-find-dropdown > li {\\n display: block;\\n padding: 0.5em 0.3em;\\n white-space: nowrap;\\n margin: 0;\\n font-weight: bold;\\n text-overflow: ellipsis;\\n overflow: hidden;\\n}\\n\\n.sa-find-dropdown > li > b {\\n background-color: #aaffaa;\\n color: black;\\n}\\n\\n/* Drop down items */\\n.sa-find-dropdown > li:hover,\\n.sa-find-dropdown > li.sel {\\n color: var(--sa-block-text-on-bright-background);\\n cursor: pointer;\\n}\\n\\n.sa-find-dropdown > li::before {\\n content: \\\"\\\\25CF \\\"; /* ● */\\n}\\n\\n.sa-find-flag {\\n color: #4cbf56;\\n}\\n/* .sa-find-dropdown added for specificity */\\n.sa-find-dropdown > .sa-find-flag:hover,\\n.sa-find-dropdown > .sa-find-flag.sel {\\n background-color: #4cbf56;\\n color: white;\\n}\\n\\n.sa-find-dropdown .sa-block-color {\\n color: var(--sa-block-colored-text);\\n}\\n.sa-find-dropdown .sa-block-color:hover,\\n.sa-find-dropdown .sa-block-color.sel {\\n background-color: var(--sa-block-bright-background);\\n}\\n\\n.sa-find-carousel {\\n font-weight: normal;\\n position: absolute;\\n right: 0;\\n white-space: nowrap;\\n background-color: inherit;\\n z-index: 1;\\n padding: 0;\\n}\\n\\n.sa-find-carousel-control {\\n padding: 0 6px;\\n}\\n\\n.sa-find-carousel-control:hover {\\n color: #ffff80;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1435:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\nexports.i(__webpack_require__(1382), \"\");\n\n// module\nexports.push([module.i, \".sa-mcp-root {\\n display: flex;\\n white-space: nowrap;\\n font-family: \\\"Helvetica Neue\\\", Helvetica, Arial, sans-serif;\\n\\n position: absolute;\\n min-width: 100px;\\n background-color: var(--ui-modal-background);\\n border-radius: 4px;\\n box-shadow:\\n rgba(0, 0, 0, 0.3) 0 0 3px,\\n rgba(0, 0, 0, 0.2) 0 3px 10px;\\n\\n z-index: 999;\\n}\\n\\n.sa-mcp-container {\\n display: flex;\\n flex-flow: column;\\n top: -6px;\\n z-index: 100;\\n position: absolute;\\n box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.3);\\n background-color: var(--ui-modal-background);\\n outline: 1px solid var(--ui-black-transparent);\\n border: none;\\n border-radius: 4px;\\n}\\n\\n.sa-mcp-input-wrapper {\\n position: relative;\\n margin: 4px;\\n /* !important required for extension, because CSS injection method (and hence order) differs from addon */\\n box-sizing: border-box !important;\\n height: 1.5rem;\\n min-height: 1.5rem;\\n\\n /* Change Scratch default styles */\\n border-radius: 0.25rem;\\n font-size: 0.75rem;\\n padding-left: 0.2rem;\\n padding-right: 0.2rem;\\n}\\n\\n.sa-mcp-input-wrapper:focus {\\n /* Change Scratch default styles */\\n box-shadow: none;\\n}\\n\\n.sa-mcp-input-wrapper[data-error=\\\"true\\\"] {\\n border-color: red;\\n}\\n\\n.sa-mcp-input-wrapper > input {\\n position: absolute;\\n border: 0;\\n background-color: transparent;\\n outline: none;\\n width: 100%;\\n height: 100%;\\n line-height: 100%;\\n box-sizing: border-box;\\n}\\n\\n.sa-mcp-input-suggestion {\\n color: hsla(225, 15%, 40%, 0.65);\\n}\\n\\n.sa-mcp-preview-container {\\n flex: auto;\\n overflow-y: scroll;\\n}\\n\\n.sa-mcp-root /* <-- specificity */ .sa-mcp-preview-container {\\n scrollbar-width: none;\\n}\\n\\n.sa-mcp-preview-container::-webkit-scrollbar {\\n width: 0;\\n height: 0;\\n}\\n\\n.sa-mcp-preview-blocks {\\n width: 100%;\\n min-height: 100%;\\n /* https://stackoverflow.com/a/22166728/8448397 */\\n float: left;\\n}\\n\\n.sa-mcp-preview-scrollbar {\\n position: absolute;\\n width: 11px;\\n right: 0;\\n bottom: 0;\\n}\\n\\n.sa-mcp-preview-block-bg {\\n width: 100%;\\n fill: transparent;\\n cursor: grab;\\n}\\n\\n.sa-mcp-preview-block {\\n filter: brightness(95%);\\n cursor: grab;\\n}\\n\\n.sa-mcp-preview-block-selection {\\n filter: brightness(103%);\\n}\\n\\n.sa-mcp-preview-block-bg-selection {\\n fill: #7774;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1436:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".blocklyTextShiftArrow {\\n position: absolute;\\n top: -50px;\\n left: 50%;\\n margin-left: -12.5px;\\n cursor: pointer;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1437:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".u-dropdown-searchbar {\\n width: 100%;\\n box-sizing: border-box;\\n /* based on styles for the title input */\\n color: white;\\n background-color: hsla(0, 100%, 100%, 0.25);\\n border: 1px solid hsla(0, 0%, 0%, 0.15);\\n padding: 0.5rem;\\n outline: none;\\n transition: 0.25s ease-out;\\n font-size: 13px;\\n font-weight: bold;\\n border-radius: 4px;\\n}\\n.u-dropdown-searchbar:hover {\\n background-color: hsla(0, 100%, 100%, 0.5);\\n}\\n.u-dropdown-searchbar:focus {\\n background-color: white;\\n color: black;\\n}\\n.blocklyDropDownDiv .goog-menu {\\n overflow-x: hidden;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1465:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".sa-color-picker {\\n display: flex;\\n}\\n\\n.sa-color-picker-code {\\n margin: 8px 0;\\n}\\n\\n.sa-color-picker-paint {\\n margin-top: 16px;\\n margin-bottom: 4px;\\n}\\n\\n.sa-color-picker > .sa-color-picker-color {\\n border: none;\\n border-top-left-radius: 1rem;\\n border-bottom-left-radius: 1rem;\\n padding: 0;\\n padding-left: 0.6rem;\\n padding-right: 0.4rem;\\n margin-left: 0.5rem;\\n outline: none;\\n box-sizing: border-box;\\n width: 3rem;\\n height: 2rem;\\n}\\n\\n.sa-color-picker > .sa-color-picker-text {\\n box-sizing: border-box;\\n width: calc(150px - 3rem);\\n border-top-left-radius: 0;\\n border-bottom-left-radius: 0;\\n}\\n\\n[dir=\\\"rtl\\\"] .sa-color-picker > .sa-color-picker-color {\\n border-top-left-radius: 0;\\n border-bottom-left-radius: 0;\\n border-top-right-radius: 1rem;\\n border-bottom-right-radius: 1rem;\\n margin-left: 0;\\n margin-right: 0.5rem;\\n}\\n\\n[dir=\\\"rtl\\\"] .sa-color-picker > .sa-color-picker-text {\\n border-top-left-radius: 1rem;\\n border-bottom-left-radius: 1rem;\\n border-top-right-radius: 0;\\n border-bottom-right-radius: 0;\\n}\\n\\nbody.sa-hide-eye-dropper-background div[class*=\\\"stage_color-picker-background\\\"] {\\n /* Do not show eye dropper background if the color picker is \\\"fake\\\" */\\n display: none;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1466:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".sa-onion-button {\\n position: relative;\\n}\\n.sa-onion-button:focus-within {\\n background-color: var(--editorDarkMode-primary-transparent35, hsla(260, 60%, 60%, 0.35));\\n}\\n.sa-onion-image[data-image=\\\"toggle\\\"] {\\n filter: var(--filter-icon-white);\\n}\\n.sa-onion-image[data-image=\\\"settings\\\"] {\\n filter: var(--filter-icon-black);\\n}\\n.sa-onion-button[data-enabled=\\\"true\\\"] .sa-onion-image {\\n filter: brightness(0) invert(1);\\n}\\n.sa-onion-button[data-enabled=\\\"true\\\"] {\\n color: white;\\n background-color: var(--looks-secondary);\\n}\\n\\n.sa-onion-group {\\n position: relative;\\n flex-direction: row;\\n}\\n\\n.sa-onion-settings-wrapper {\\n position: absolute;\\n justify-items: center;\\n left: 50%;\\n width: 1.95rem;\\n height: 1.95rem;\\n display: grid;\\n}\\n\\n.sa-onion-settings {\\n position: absolute;\\n bottom: 100%;\\n /* based on the styles for the color dropdown */\\n padding: 4px;\\n border-radius: 4px;\\n border: 1px solid #ddd;\\n border: 1px solid var(--ui-black-transparent);\\n transition-property: bottom, opacity;\\n transition-duration: 500ms;\\n transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);\\n opacity: 0;\\n pointer-events: none;\\n background: var(--ui-modal-background);\\n color: var(--ui-text-primary);\\n min-height: 100%;\\n min-width: 100%;\\n display: flex;\\n flex-direction: column;\\n gap: 0.25em;\\n}\\n.sa-onion-settings[data-visible=\\\"true\\\"] {\\n bottom: calc(100% + 22px);\\n pointer-events: auto;\\n opacity: 1;\\n}\\n\\n.sa-onion-settings-line {\\n display: flex;\\n justify-content: flex-end;\\n align-items: baseline;\\n gap: 0.25em;\\n}\\n\\n.sa-onion-settings-input {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n box-sizing: border-box;\\n text-align: center;\\n border: 0;\\n background: transparent;\\n -moz-appearance: textfield;\\n border: 0;\\n outline: 0;\\n}\\n\\n.sa-onion-settings-input::-webkit-outer-spin-button,\\n.sa-onion-settings-input::-webkit-inner-spin-button {\\n -webkit-appearance: none;\\n margin: 0;\\n}\\n\\n.sa-onion-settings-tip {\\n position: absolute;\\n bottom: 0;\\n transform: translateY(100%);\\n right: calc(50% - 7px);\\n}\\n.sa-onion-settings-polygon {\\n fill: var(--ui-modal-background);\\n stroke: var(--ui-black-transparent);\\n}\\n\\n.sa-onion-settings-label {\\n white-space: nowrap;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1470:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".sa-stage-color-picker-picking [class^=\\\"stage_color-picker-background_\\\"] {\\n display: none;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1494:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".sa-folders-contextmenu-item {\\n max-width: 250px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n[sa-folders-context-type=\\\"folder\\\"] .react-contextmenu > :not(.sa-ctx-menu) {\\n display: none;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1506:\n/***/ (function(module, exports, __webpack_require__) {\n\nexports = module.exports = __webpack_require__(9)(false);\n// imports\n\n\n// module\nexports.push([module.i, \".sa-comment-preview-outer {\\n position: fixed;\\n top: 0;\\n left: 0;\\n z-index: 100000000;\\n pointer-events: none;\\n}\\n\\n.sa-comment-preview-inner {\\n width: calc(200px - 16px);\\n max-height: calc(132px - 8px);\\n padding: 8px;\\n overflow: hidden;\\n\\n font-size: 12px;\\n white-space: pre-wrap;\\n pointer-events: none;\\n\\n color: rgb(87, 94, 117);\\n background-color: rgb(255 255 255 / 90%);\\n border-style: none;\\n border-radius: 8px;\\n filter: drop-shadow(0px 5px 5px rgb(0 0 0 / 10%));\\n\\n transform: perspective(200px);\\n}\\n\\n@supports (backdrop-filter: blur(16px)) {\\n .sa-comment-preview-inner {\\n background-color: rgb(255 255 255 / 75%);\\n backdrop-filter: blur(16px);\\n }\\n}\\n\\n.sa-comment-preview-fade {\\n transition:\\n opacity 0.1s,\\n filter 0.1s,\\n transform 0.1s linear;\\n}\\n\\n.sa-comment-preview-hidden {\\n opacity: 0;\\n filter: none;\\n transform: perspective(200px) translateZ(-20px);\\n}\\n\\n.sa-comment-preview-reduce-transparency {\\n background-color: rgb(255 255 255);\\n backdrop-filter: none;\\n}\\n\", \"\"]);\n\n// exports\n\n\n/***/ }),\n\n/***/ 1523:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, \"resources\", function() { return /* binding */ resources; });\n\n// CONCATENATED MODULE: ./src/addons/addons/editor-devtools/DomHelpers.js\nclass DomHelpers {\n constructor(addon) {\n this.addon = addon;\n this.vm = addon.tab.traps.vm;\n /**\n * @type {eventDetails[]}\n */\n this.events = [];\n }\n\n /**\n * Simulate a drag and drop programmatically through javascript\n * @param selectorDrag\n * @param selectorDrop\n * @param mouseXY\n * @param [shiftKey=false]\n * @returns {boolean}\n */\n triggerDragAndDrop(selectorDrag, selectorDrop, mouseXY, shiftKey) {\n // function for triggering mouse events\n shiftKey = shiftKey || false;\n let fireMouseEvent = function fireMouseEvent(type, elem, centerX, centerY) {\n let evt = document.createEvent(\"MouseEvents\");\n evt.initMouseEvent(type, true, true, window, 1, 1, 1, centerX, centerY, shiftKey, false, false, false, 0, elem);\n elem.dispatchEvent(evt);\n };\n\n // fetch target elements\n let elemDrag = selectorDrag; // document.querySelector(selectorDrag);\n let elemDrop = selectorDrop; // document.querySelector(selectorDrop);\n if (!elemDrag /* || !elemDrop*/) {\n return false;\n }\n\n // calculate positions\n let pos = elemDrag.getBoundingClientRect();\n let center1X = Math.floor((pos.left + pos.right) / 2);\n let center1Y = Math.floor((pos.top + pos.bottom) / 2);\n\n // mouse over dragged element and mousedown\n fireMouseEvent(\"mouseover\", elemDrag, center1X, center1Y);\n fireMouseEvent(\"mousedown\", elemDrag, center1X, center1Y);\n\n // start dragging process over to drop target\n fireMouseEvent(\"dragstart\", elemDrag, center1X, center1Y);\n fireMouseEvent(\"drag\", elemDrag, center1X, center1Y);\n fireMouseEvent(\"mousemove\", elemDrag, center1X, center1Y);\n if (!elemDrop) {\n if (mouseXY) {\n // console.log(mouseXY);\n let center2X = mouseXY.x;\n let center2Y = mouseXY.y;\n fireMouseEvent(\"drag\", elemDrag, center2X, center2Y);\n fireMouseEvent(\"mousemove\", elemDrag, center2X, center2Y);\n }\n return false;\n }\n pos = elemDrop.getBoundingClientRect();\n let center2X = Math.floor((pos.left + pos.right) / 2);\n let center2Y = Math.floor((pos.top + pos.bottom) / 2);\n fireMouseEvent(\"drag\", elemDrag, center2X, center2Y);\n fireMouseEvent(\"mousemove\", elemDrop, center2X, center2Y);\n\n // trigger dragging process on top of drop target\n fireMouseEvent(\"mouseenter\", elemDrop, center2X, center2Y);\n fireMouseEvent(\"dragenter\", elemDrop, center2X, center2Y);\n fireMouseEvent(\"mouseover\", elemDrop, center2X, center2Y);\n fireMouseEvent(\"dragover\", elemDrop, center2X, center2Y);\n\n // release dragged element on top of drop target\n fireMouseEvent(\"drop\", elemDrop, center2X, center2Y);\n fireMouseEvent(\"dragend\", elemDrag, center2X, center2Y);\n fireMouseEvent(\"mouseup\", elemDrag, center2X, center2Y);\n return true;\n }\n bindOnce(dom, event, func, capture) {\n capture = !!capture;\n dom.removeEventListener(event, func, capture);\n dom.addEventListener(event, func, capture);\n this.events.push(new eventDetails(dom, event, func, capture));\n }\n unbindAllEvents() {\n for (const event of this.events) {\n event.dom.removeEventListener(event.event, event.func, event.capture);\n }\n this.events = [];\n }\n}\n\n/**\n * A record of an event\n */\nclass eventDetails {\n constructor(dom, event, func, capture) {\n this.dom = dom;\n this.event = event;\n this.func = func;\n this.capture = capture;\n }\n}\n// CONCATENATED MODULE: ./src/addons/addons/editor-devtools/UndoGroup.js\n/**\n * This class is dedicated to maintaining the Undo stack of Blockly\n * It allows us to initiate an undo group such that all subsequent operations are recorded as a single\n * undoable transaction.\n */\nclass UndoGroup {\n /**\n * Start an Undo group - begin recording\n * @param workspace the workspace\n */\n static startUndoGroup(workspace) {\n const undoStack = workspace.undoStack_;\n if (undoStack.length) {\n undoStack[undoStack.length - 1]._devtoolsLastUndo = true;\n }\n }\n\n /**\n * End an Undo group - stops recording\n * @param workspace the workspace\n */\n static endUndoGroup(workspace) {\n const undoStack = workspace.undoStack_;\n // Events (responsible for undoStack updates) are delayed with a setTimeout(f, 0)\n // https://github.com/scratchfoundation/scratch-blocks/blob/f159a1779e5391b502d374fb2fdd0cb5ca43d6a2/core/events.js#L182\n setTimeout(() => {\n const group = generateUID();\n for (let i = undoStack.length - 1; i >= 0 && !undoStack[i]._devtoolsLastUndo; i--) {\n undoStack[i].group = group;\n }\n }, 0);\n }\n}\n\n/**\n * https://github.com/scratchfoundation/scratch-blocks/blob/f159a1779e5391b502d374fb2fdd0cb5ca43d6a2/core/events.js#L182\n * @returns {string}\n * @private\n */\nfunction generateUID() {\n const CHARACTERS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%()*+,-./:;=?@[]^_`{|}~\";\n let result = \"\";\n for (let i = 0; i < 20; i++) {\n result += CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)];\n }\n return result;\n}\n// CONCATENATED MODULE: ./src/addons/addons/editor-devtools/DevTools.js\n// import ShowBroadcast from \"./show-broadcast.js\";\n\n\nclass DevTools_DevTools {\n constructor(addon, msg, m) {\n this.addon = addon;\n this.msg = msg;\n this.m = m;\n /**\n * @type {VirtualMachine}\n */\n this.domHelpers = new DomHelpers(addon);\n this.codeTab = null;\n this.costTab = null;\n this.costTabBody = null;\n this.selVarID = null;\n this.canShare = false;\n this.mouseXY = {\n x: 0,\n y: 0\n };\n }\n async init() {\n this.addContextMenus();\n while (true) {\n const root = await this.addon.tab.waitForElement(\"ul[class*=gui_tab-list_]\", {\n markAsSeen: true,\n reduxEvents: [\"scratch-gui/mode/SET_PLAYER\", \"fontsLoaded/SET_FONTS_LOADED\", \"scratch-gui/locales/SELECT_LOCALE\"],\n reduxCondition: state => !state.scratchGui.mode.isPlayerOnly\n });\n this.initInner(root);\n }\n }\n async addContextMenus() {\n const blockly = await this.addon.tab.traps.getBlockly();\n const oldCleanUpFunc = blockly.WorkspaceSvg.prototype.cleanUp;\n const self = this;\n blockly.WorkspaceSvg.prototype.cleanUp = function () {\n if (self.addon.settings.get(\"enableCleanUpPlus\")) {\n self.doCleanUp();\n } else {\n oldCleanUpFunc.call(this);\n }\n };\n let originalMsg = blockly.Msg.CLEAN_UP;\n if (this.addon.settings.get(\"enableCleanUpPlus\")) blockly.Msg.CLEAN_UP = this.m(\"clean-plus\");\n this.addon.settings.addEventListener(\"change\", () => {\n if (this.addon.settings.get(\"enableCleanUpPlus\")) blockly.Msg.CLEAN_UP = this.m(\"clean-plus\");else blockly.Msg.CLEAN_UP = originalMsg;\n });\n this.addon.tab.createBlockContextMenu((items, block) => {\n items.push({\n enabled: blockly.clipboardXml_,\n text: this.m(\"paste\"),\n separator: true,\n _isDevtoolsFirstItem: true,\n callback: () => {\n let ids = this.getTopBlockIDs();\n document.dispatchEvent(new KeyboardEvent(\"keydown\", {\n keyCode: 86,\n ctrlKey: true,\n griff: true\n }));\n setTimeout(() => {\n this.beginDragOfNewBlocksNotInIDs(ids);\n }, 10);\n }\n });\n return items;\n }, {\n workspace: true\n });\n this.addon.tab.createBlockContextMenu((items, block) => {\n items.push({\n enabled: true,\n text: this.m(\"make-space\"),\n _isDevtoolsFirstItem: true,\n callback: () => {\n this.doCleanUp(block);\n },\n separator: true\n }, {\n enabled: true,\n text: this.m(\"copy-all\"),\n callback: () => {\n this.eventCopyClick(block);\n },\n separator: true\n }, {\n enabled: true,\n text: this.m(\"copy-block\"),\n callback: () => {\n this.eventCopyClick(block, 1);\n }\n }, {\n enabled: true,\n text: this.m(\"cut-block\"),\n callback: () => {\n this.eventCopyClick(block, 2);\n }\n });\n // const BROADCAST_BLOCKS = [\"event_whenbroadcastreceived\", \"event_broadcast\", \"event_broadcastandwait\"];\n // if (BROADCAST_BLOCKS.includes(block.type)) {\n // // Show Broadcast\n // const broadcastId = this.showBroadcastSingleton.getAssociatedBroadcastId(block.id);\n // if (broadcastId) {\n // [\"Senders\", \"Receivers\"].forEach((showKey, i) => {\n // items.push({\n // enabled: true,\n // text: this.msg(`show-${showKey}`.toLowerCase()),\n // callback: () => {\n // this.showBroadcastSingleton[`show${showKey}`](broadcastId);\n // },\n // separator: i == 0,\n // });\n // });\n // }\n // }\n return items;\n }, {\n blocks: true\n });\n this.addon.tab.createBlockContextMenu((items, block) => {\n if (block.getCategory() === \"data\" || block.getCategory() === \"data-lists\") {\n this.selVarID = block.getVars()[0];\n items.push({\n enabled: true,\n text: this.m(\"swap\", {\n var: block.getCategory() === \"data\" ? this.m(\"variables\") : this.m(\"lists\")\n }),\n callback: async () => {\n let wksp = this.getWorkspace();\n let v = wksp.getVariableById(this.selVarID);\n // prompt() returns Promise in desktop app\n let varName = await window.prompt(this.msg(\"replace\", {\n name: v.name\n }));\n if (varName) {\n this.doReplaceVariable(this.selVarID, varName, v.type);\n }\n },\n separator: true\n });\n }\n return items;\n }, {\n blocks: true,\n flyout: true\n });\n }\n getWorkspace() {\n return Blockly.getMainWorkspace();\n }\n isCostumeEditor() {\n return this.costTab.className.indexOf(\"gui_is-selected\") >= 0;\n }\n\n /**\n * A nicely ordered version of the top blocks\n * @returns {[Blockly.Block]}\n */\n getTopBlocks() {\n let result = this.getOrderedTopBlockColumns();\n let columns = result.cols;\n /**\n * @type {[[Blockly.Block]]}\n */\n let topBlocks = [];\n for (const col of columns) {\n topBlocks = topBlocks.concat(col.blocks);\n }\n return topBlocks;\n }\n\n /**\n * A much nicer way of laying out the blocks into columns\n */\n doCleanUp(block) {\n let workspace = this.getWorkspace();\n let makeSpaceForBlock = block && block.getRootBlock();\n UndoGroup.startUndoGroup(workspace);\n let result = this.getOrderedTopBlockColumns(true);\n let columns = result.cols;\n let orphanCount = result.orphans.blocks.length;\n if (orphanCount > 0 && !block) {\n let message = this.msg(\"orphaned\", {\n count: orphanCount\n });\n if (confirm(message)) {\n for (const block of result.orphans.blocks) {\n block.dispose();\n }\n } else {\n columns.unshift(result.orphans);\n }\n }\n let cursorX = 48;\n let maxWidths = result.maxWidths;\n for (const column of columns) {\n let cursorY = 64;\n let maxWidth = 0;\n for (const block of column.blocks) {\n let extraWidth = block === makeSpaceForBlock ? 380 : 0;\n let extraHeight = block === makeSpaceForBlock ? 480 : 72;\n let xy = block.getRelativeToSurfaceXY();\n if (cursorX - xy.x !== 0 || cursorY - xy.y !== 0) {\n block.moveBy(cursorX - xy.x, cursorY - xy.y);\n }\n let heightWidth = block.getHeightWidth();\n cursorY += heightWidth.height + extraHeight;\n let maxWidthWithComments = maxWidths[block.id] || 0;\n maxWidth = Math.max(maxWidth, Math.max(heightWidth.width + extraWidth, maxWidthWithComments));\n }\n cursorX += maxWidth + 96;\n }\n let topComments = workspace.getTopComments();\n for (const comment of topComments) {\n if (comment.setVisible) {\n comment.setVisible(false);\n comment.needsAutoPositioning_ = true;\n comment.setVisible(true);\n }\n }\n setTimeout(() => {\n // Locate unused local variables...\n let workspace = this.getWorkspace();\n let map = workspace.getVariableMap();\n let vars = map.getVariablesOfType(\"\");\n let unusedLocals = [];\n for (const row of vars) {\n if (row.isLocal) {\n let usages = map.getVariableUsesById(row.getId());\n if (!usages || usages.length === 0) {\n unusedLocals.push(row);\n }\n }\n }\n if (unusedLocals.length > 0) {\n const unusedCount = unusedLocals.length;\n let message = this.msg(\"unused-var\", {\n count: unusedCount\n });\n for (let i = 0; i < unusedLocals.length; i++) {\n let orphan = unusedLocals[i];\n if (i > 0) {\n message += \", \";\n }\n message += orphan.name;\n }\n if (confirm(message)) {\n for (const orphan of unusedLocals) {\n workspace.deleteVariableById(orphan.getId());\n }\n }\n }\n\n // Locate unused local lists...\n let lists = map.getVariablesOfType(\"list\");\n let unusedLists = [];\n for (const row of lists) {\n if (row.isLocal) {\n let usages = map.getVariableUsesById(row.getId());\n if (!usages || usages.length === 0) {\n unusedLists.push(row);\n }\n }\n }\n if (unusedLists.length > 0) {\n const unusedCount = unusedLists.length;\n let message = this.msg(\"unused-list\", {\n count: unusedCount\n });\n for (let i = 0; i < unusedLists.length; i++) {\n let orphan = unusedLists[i];\n if (i > 0) {\n message += \", \";\n }\n message += orphan.name;\n }\n if (confirm(message)) {\n for (const orphan of unusedLists) {\n workspace.deleteVariableById(orphan.getId());\n }\n }\n }\n UndoGroup.endUndoGroup(workspace);\n }, 100);\n }\n\n /**\n * Badly Orphaned - might want to delete these!\n * @param topBlock\n * @returns {boolean}\n */\n isBlockAnOrphan(topBlock) {\n return !!topBlock.outputConnection;\n }\n\n /**\n * Split the top blocks into ordered columns\n * @param separateOrphans true to keep all orphans separate\n * @returns {{orphans: {blocks: [Block], x: number, count: number}, cols: [Col]}}\n */\n getOrderedTopBlockColumns(separateOrphans) {\n let w = this.getWorkspace();\n let topBlocks = w.getTopBlocks();\n let maxWidths = {};\n if (separateOrphans) {\n let topComments = w.getTopComments();\n\n // todo: tie comments to blocks... find widths and width of block stack row...\n for (const comment of topComments) {\n // comment.autoPosition_();\n // Hiding and showing repositions the comment right next to it's block - nice!\n if (comment.setVisible) {\n comment.setVisible(false);\n comment.needsAutoPositioning_ = true;\n comment.setVisible(true);\n\n // let bb = comment.block_.svgPath_.getBBox();\n let right = comment.getBoundingRectangle().bottomRight.x;\n\n // Get top block for stack...\n let root = comment.block_.getRootBlock();\n let left = root.getBoundingRectangle().topLeft.x;\n maxWidths[root.id] = Math.max(right - left, maxWidths[root.id] || 0);\n }\n }\n }\n\n // Default scratch ordering is horrid... Lets try something more clever.\n\n /**\n * @type {Col[]}\n */\n let cols = [];\n const TOLERANCE = 256;\n let orphans = {\n x: -999999,\n count: 0,\n blocks: []\n };\n for (const topBlock of topBlocks) {\n // let r = b.getBoundingRectangle();\n let position = topBlock.getRelativeToSurfaceXY();\n /**\n * @type {Col}\n */\n let bestCol = null;\n let bestError = TOLERANCE;\n if (separateOrphans && this.isBlockAnOrphan(topBlock)) {\n orphans.blocks.push(topBlock);\n continue;\n }\n\n // Find best columns\n for (const col of cols) {\n let err = Math.abs(position.x - col.x);\n if (err < bestError) {\n bestError = err;\n bestCol = col;\n }\n }\n if (bestCol) {\n // We found a column that we fitted into\n bestCol.x = (bestCol.x * bestCol.count + position.x) / ++bestCol.count; // re-average the columns as more items get added...\n bestCol.blocks.push(topBlock);\n } else {\n // Create a new column\n cols.push(new Col(position.x, 1, [topBlock]));\n }\n }\n\n // if (orphans.blocks.length > 0) {\n // cols.push(orphans);\n // }\n\n // Sort columns, then blocks inside the columns\n cols.sort((a, b) => a.x - b.x);\n for (const col of cols) {\n col.blocks.sort((a, b) => a.getRelativeToSurfaceXY().y - b.getRelativeToSurfaceXY().y);\n }\n return {\n cols: cols,\n orphans: orphans,\n maxWidths: maxWidths\n };\n }\n\n /**\n * Find all the uses of a named variable.\n * @param {string} id ID of the variable to find.\n * @return {!Array.} Array of block usages.\n */\n getVariableUsesById(id) {\n let uses = [];\n let topBlocks = this.getTopBlocks(true); // todo: Confirm this was the right getTopBlocks?\n for (const topBlock of topBlocks) {\n /** @type {!Array} */\n let kids = topBlock.getDescendants();\n for (const block of kids) {\n /** @type {!Array} */\n let blockVariables = block.getVarModels();\n if (blockVariables) {\n for (const blockVar of blockVariables) {\n if (blockVar.getId() === id) {\n uses.push(block);\n }\n }\n }\n }\n }\n return uses;\n }\n\n /**\n * Quick and dirty replace all instances of one variable / list with another variable / list\n * @param varId original variable name\n * @param newVarName new variable name\n * @param type type of variable (\"\" = variable, anything else is a list?\n */\n doReplaceVariable(varId, newVarName, type) {\n let wksp = this.getWorkspace();\n let v = wksp.getVariable(newVarName, type);\n if (!v) {\n alert(this.msg(\"var-not-exist\"));\n return;\n }\n let newVId = v.getId();\n UndoGroup.startUndoGroup(wksp);\n let blocks = this.getVariableUsesById(varId);\n for (const block of blocks) {\n try {\n if (type === \"\") {\n block.getField(\"VARIABLE\").setValue(newVId);\n } else {\n block.getField(\"LIST\").setValue(newVId);\n }\n } catch (e) {\n // ignore\n }\n }\n UndoGroup.endUndoGroup(wksp);\n }\n\n /*\n function doInjectScripts(codeString) {\n let w = getWorkspace();\n let xml = new XML(); // document.implementation.createDocument(null, \"xml\");\n let x = xml.xmlDoc.firstChild;\n let tree = math.parse(codeString);\n console.log(tree);\n const binaryOperatorTypes = {\n add: \"operator_add\",\n subtract: \"operator_subtract\",\n this.multiply: \"operator_multiply\",\n divide: \"operator_divide\",\n };\n const BLOCK_TYPE = {\n number: \"math_number\",\n text: \"text\",\n };\n function translateMathToXml(x, tree, shadowType) {\n let xShadowField = null;\n if (shadowType) {\n let xShadow = xml.newXml(x, \"shadow\", { type: shadowType });\n if (shadowType === BLOCK_TYPE.number) {\n xShadowField = xml.newXml(xShadow, \"field\", { name: \"NUM\" });\n } else if (shadowType === BLOCK_TYPE.text) {\n xShadowField = xml.newXml(xShadow, \"field\", { name: \"TEXT\" });\n }\n }\n if (!tree || !tree.type) {\n return;\n }\n if (tree.type === \"OperatorNode\") {\n let operatorType = binaryOperatorTypes[tree.fn];\n if (operatorType) {\n let xOp = newXml(x, \"block\", { type: operatorType });\n translateMathToXml(xml.newXml(xOp, \"value\", { name: \"NUM1\" }), tree.args[0], BLOCK_TYPE.number);\n translateMathToXml(xml.newXml(xOp, \"value\", { name: \"NUM2\" }), tree.args[1], BLOCK_TYPE.number);\n return;\n }\n return;\n }\n if (tree.type === \"ConstantNode\") {\n // number or text in quotes\n if (xShadowField) {\n xml.setAttr(xShadowField, { text: tree.value });\n }\n return;\n }\n if (tree.type === \"SymbolNode\") {\n // variable\n let xVar = xml.newXml(x, \"block\", { type: \"data_variable\" });\n xml.newXml(xVar, \"field\", { name: \"VARIABLE\", text: tree.name });\n return;\n }\n if (tree.type === \"FunctionNode\") {\n // Method Call\n if (tree.fn.name === \"join\") {\n let xOp = newXml(x, \"block\", { type: \"operator_join\" });\n translateMathToXml(xml.newXml(xOp, \"value\", { name: \"STRING1\" }), tree.args[0], BLOCK_TYPE.text);\n translateMathToXml(xml.newXml(xOp, \"value\", { name: \"STRING2\" }), tree.args[1], BLOCK_TYPE.text);\n return;\n }\n }\n }\n translateMathToXml(x, tree);\n console.log(x);\n let ids = Blockly.Xml.domToWorkspace(x, w);\n console.log(ids);\n }\n */\n /*\n function clickInject(e) {\n let codeString = window.prompt(\"Griffpatch: Enter an expression (i.e. a+2*3)\");\n if (codeString) {\n doInjectScripts(codeString);\n }\n e.preventDefault();\n return false;\n }\n */\n\n /**\n * Returns a Set of the top blocks in this workspace / sprite\n * @returns {Set} Set of top blocks\n */\n getTopBlockIDs() {\n let wksp = this.getWorkspace();\n let topBlocks = wksp.getTopBlocks();\n let ids = new Set();\n for (const block of topBlocks) {\n ids.add(block.id);\n }\n return ids;\n }\n\n /**\n * Initiates a drag event for all block stacks except those in the set of ids.\n * But why? - Because we know all the ids of the existing stacks before we paste / duplicate - so we can find the\n * new stack by excluding all the known ones.\n * @param ids Set of previously known ids\n */\n beginDragOfNewBlocksNotInIDs(ids) {\n if (!this.addon.settings.get(\"enablePasteBlocksAtMouse\")) {\n return;\n }\n let wksp = this.getWorkspace();\n let topBlocks = wksp.getTopBlocks();\n for (const block of topBlocks) {\n if (!ids.has(block.id)) {\n // console.log(\"I found a new block!!! - \" + block.id);\n // todo: move the block to the mouse pointer?\n let mouseXYClone = {\n x: this.mouseXY.x,\n y: this.mouseXY.y\n };\n block.setIntersects(true); // fixes offscreen block pasting in TurboWarp\n this.domHelpers.triggerDragAndDrop(block.svgPath_, null, mouseXYClone);\n }\n }\n }\n updateMousePosition(e) {\n this.mouseXY.x = e.clientX;\n this.mouseXY.y = e.clientY;\n }\n eventMouseMove(e) {\n this.updateMousePosition(e);\n }\n eventKeyDown(e) {\n const switchCostume = up => {\n // todo: select previous costume\n let selected = this.costTabBody.querySelector(\"div[class*='sprite-selector-item_is-selected']\");\n let node = up ? selected.parentNode.previousSibling : selected.parentNode.nextSibling;\n if (node) {\n let wrapper = node.closest(\"div[class*=gui_flex-wrapper]\");\n node.querySelector(\"div[class^='sprite-selector-item_sprite-name']\").click();\n node.scrollIntoView({\n behavior: \"auto\",\n block: \"center\",\n inline: \"start\"\n });\n wrapper.scrollTop = 0;\n }\n };\n if (document.URL.indexOf(\"editor\") <= 0) {\n return;\n }\n let ctrlKey = e.ctrlKey || e.metaKey;\n if (e.key === \"ArrowLeft\" && ctrlKey) {\n // Ctrl + Left Arrow Key\n if (document.activeElement.tagName === \"INPUT\") {\n return;\n }\n if (this.isCostumeEditor()) {\n switchCostume(true);\n e.cancelBubble = true;\n e.preventDefault();\n return true;\n }\n }\n if (e.key === \"ArrowRight\" && ctrlKey) {\n // Ctrl + Right Arrow Key\n if (document.activeElement.tagName === \"INPUT\") {\n return;\n }\n if (this.isCostumeEditor()) {\n switchCostume(false);\n e.cancelBubble = true;\n e.preventDefault();\n return true;\n }\n }\n if (e.keyCode === 86 && ctrlKey && !e.griff) {\n // Ctrl + V\n // Set a timeout so we can take control of the paste after the event\n let ids = this.getTopBlockIDs();\n setTimeout(() => {\n this.beginDragOfNewBlocksNotInIDs(ids);\n }, 10);\n }\n\n // if (e.keyCode === 220 && (!document.activeElement || document.activeElement.tagName === 'INPUT')) {\n //\n // }\n }\n eventCopyClick(block, blockOnly) {\n let wksp = this.getWorkspace();\n if (block) {\n block.select();\n let next = blockOnly ? block.getNextBlock() : null;\n if (next) {\n next.unplug(false); // setParent(null);\n }\n\n // separate child temporarily\n document.dispatchEvent(new KeyboardEvent(\"keydown\", {\n keyCode: 67,\n ctrlKey: true\n }));\n if (next || blockOnly === 2) {\n setTimeout(() => {\n if (next) {\n wksp.undo(); // undo the unplug above...\n }\n if (blockOnly === 2) {\n UndoGroup.startUndoGroup(wksp);\n block.dispose(true);\n UndoGroup.endUndoGroup(wksp);\n }\n }, 0);\n }\n }\n }\n eventMouseDown(e) {\n this.updateMousePosition(e);\n }\n eventMouseUp(e) {\n this.updateMousePosition(e);\n }\n initInner(root) {\n var _this = this;\n let guiTabs = root.childNodes;\n if (this.codeTab && guiTabs[0] !== this.codeTab) {\n // We have been CHANGED!!! - Happens when going to project page, and then back inside again!!!\n this.domHelpers.unbindAllEvents();\n }\n this.codeTab = guiTabs[0];\n this.costTab = guiTabs[1];\n this.costTabBody = document.querySelector(\"div[aria-labelledby=\" + this.costTab.id + \"]\");\n this.domHelpers.bindOnce(document, \"keydown\", function () {\n return _this.eventKeyDown(...arguments);\n }, true);\n this.domHelpers.bindOnce(document, \"mousemove\", function () {\n return _this.eventMouseMove(...arguments);\n }, true);\n this.domHelpers.bindOnce(document, \"mousedown\", function () {\n return _this.eventMouseDown(...arguments);\n }, true); // true to capture all mouse downs 'before' the dom events handle them\n this.domHelpers.bindOnce(document, \"mouseup\", function () {\n return _this.eventMouseUp(...arguments);\n }, true);\n }\n}\nclass Col {\n /**\n * @param x {Number} x position (for ordering)\n * @param count {Number}\n * @param blocks {[Block]}\n */\n constructor(x, count, blocks) {\n /**\n * x position (for ordering)\n * @type {Number}\n */\n this.x = x;\n /**\n * @type {Number}\n */\n this.count = count;\n /**\n * @type {[Blockly.Block]}\n */\n this.blocks = blocks;\n }\n}\n// CONCATENATED MODULE: ./src/addons/addons/editor-devtools/userscript.js\n\n/* harmony default export */ var userscript = (async function (_ref) {\n let {\n addon,\n console,\n msg,\n safeMsg: m\n } = _ref;\n const devTools = new DevTools_DevTools(addon, msg, m);\n devTools.init();\n});\n// CONCATENATED MODULE: ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/editor-devtools/icon--close.svg\n/* harmony default export */ var icon_close = (\"data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3LjQ4IDcuNDgiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MnB4O308L3N0eWxlPjwvZGVmcz48dGl0bGU+aWNvbi0tYWRkPC90aXRsZT48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIzLjc0IiB5MT0iNi40OCIgeDI9IjMuNzQiIHkyPSIxIi8+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iMSIgeTE9IjMuNzQiIHgyPSI2LjQ4IiB5Mj0iMy43NCIvPjwvc3ZnPg==\");\n// CONCATENATED MODULE: ./src/addons/addons/editor-devtools/_runtime_entry.js\n/* generated by pull.js */\n\n\nconst resources = {\n \"userscript.js\": userscript,\n \"icon--close.svg\": icon_close\n};\n\n/***/ }),\n\n/***/ 1524:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, \"resources\", function() { return /* binding */ resources; });\n\n// EXTERNAL MODULE: ./node_modules/@turbowarp/scratch-svg-renderer/src/index.js\nvar src = __webpack_require__(81);\n\n// CONCATENATED MODULE: ./src/addons/addons/onion-skinning/userscript.js\n\n/* harmony default export */ var userscript = (async function (_ref) {\n let {\n addon,\n console,\n msg\n } = _ref;\n const paper = await addon.tab.traps.getPaper();\n const paintEditorCanvasContainer = await addon.tab.waitForElement(\"[class^='paint-editor_canvas-container']\");\n try {\n if (!(\"colorIndex\" in addon.tab.redux.state.scratchPaint.fillMode)) {\n console.error(\"Detected new paint editor; this will be supported in future versions.\");\n return;\n }\n } catch (_) {\n // The check can technically fail when Redux isn't supported (rare cases)\n // Just ignore in this case\n }\n const paperCanvas = paintEditorCanvasContainer[addon.tab.traps.getInternalKey(paintEditorCanvasContainer)].child.child.child.stateNode;\n const storedOnionLayers = [];\n const parseHexColor = color => {\n const hexString = color.substr(1);\n const hexNumber = parseInt(hexString, 16);\n return [hexNumber >> 16 & 0xff,\n // R\n hexNumber >> 8 & 0xff,\n // G\n hexNumber & 0xff // B\n ];\n };\n const settings = {\n enabled: addon.settings.get(\"default\") && !addon.self.disabled,\n previous: +addon.settings.get(\"previous\"),\n next: +addon.settings.get(\"next\"),\n opacity: +addon.settings.get(\"opacity\"),\n opacityStep: +addon.settings.get(\"opacityStep\"),\n layering: addon.settings.get(\"layering\"),\n mode: addon.settings.get(\"mode\"),\n beforeTint: parseHexColor(addon.settings.get(\"beforeTint\")),\n afterTint: parseHexColor(addon.settings.get(\"afterTint\"))\n };\n const getPaperCenter = () => {\n const backgroundGuideLayer = paper.project.layers.find(i => i.data.isBackgroundGuideLayer);\n return backgroundGuideLayer.children[0].position;\n };\n const injectPaper = () => {\n // When background guide layer is added, show onion layers.\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/helper/layer.js#L145\n const originalAddLayer = paper.Project.prototype.addLayer;\n paper.Project.prototype.addLayer = function (layer) {\n const result = originalAddLayer.call(this, layer);\n if (layer.data.isBackgroundGuideLayer) {\n let onion;\n while (onion = storedOnionLayers.shift()) {\n originalAddLayer.call(this, onion);\n }\n relayerOnionLayers();\n }\n return result;\n };\n\n // Scratch uses importJSON to undo or redo\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/helper/undo.js#L37\n // The code prior to this will remove our onion layers, so we have to manually add them back.\n const originalImportJSON = paper.Project.prototype.importJSON;\n paper.Project.prototype.importJSON = function (json) {\n const result = originalImportJSON.call(this, json);\n if (settings.enabled) {\n updateOnionLayers();\n }\n return result;\n };\n\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/helper/layer.js#L114\n // When background guide layer is removed, hide onion layers.\n const originalRemoveLayer = paper.Layer.prototype.remove;\n paper.Layer.prototype.remove = function () {\n if (this.data.isBackgroundGuideLayer) {\n for (const layer of paper.project.layers) {\n if (layer.data.sa_isOnionLayer) {\n storedOnionLayers.push(layer);\n }\n }\n for (const layer of storedOnionLayers) {\n layer.remove();\n }\n }\n return originalRemoveLayer.call(this);\n };\n };\n const injectPaperCanvas = () => {\n let expectingImport = false;\n const PaperCanvas = paperCanvas.constructor;\n\n // importImage is called to start loading an image.\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L124\n const originalImportImage = PaperCanvas.prototype.importImage;\n PaperCanvas.prototype.importImage = function () {\n expectingImport = true;\n removeOnionLayers();\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n return originalImportImage.call(this, ...args);\n };\n\n // recalibrateSize is called when the canvas finishes loading an image.\n // all paths of importImage will result in a call to this method.\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L310-L327\n // We use this to know when to add layers.\n const originalRecalibrateSize = PaperCanvas.prototype.recalibrateSize;\n PaperCanvas.prototype.recalibrateSize = function (callback) {\n return originalRecalibrateSize.call(this, () => {\n if (callback) callback();\n if (expectingImport) {\n expectingImport = false;\n if (settings.enabled) {\n updateOnionLayers();\n }\n }\n });\n };\n\n // Prototype overrides will work for all future instances, but Scratch manually binds some methods to `this`\n // so we have to manually copy them for the current instance (but not future instances)\n paperCanvas.recalibrateSize = PaperCanvas.prototype.recalibrateSize.bind(paperCanvas);\n paperCanvas.importImage = PaperCanvas.prototype.importImage.bind(paperCanvas);\n };\n const createOnionLayer = () => {\n const layer = new paper.Layer();\n layer.locked = true;\n layer.guide = true;\n layer.data.sa_isOnionLayer = true;\n return layer;\n };\n\n // Each onion layer update is given an ID\n // Because updating layers is async, we need this to cancel all but the most recent update\n let globalUpdateId = 0;\n const cancelOngoingUpdatesAndGetNewId = () => ++globalUpdateId;\n const removeOnionLayers = () => {\n cancelOngoingUpdatesAndGetNewId();\n const project = paper.project;\n if (!project) {\n return;\n }\n storedOnionLayers.length = 0;\n const layers = project.layers;\n // Iterate downward because we remove items mid-iteration\n for (let i = layers.length - 1; i >= 0; i--) {\n const layer = layers[i];\n if (layer.data.sa_isOnionLayer) {\n layer.remove();\n }\n }\n };\n const relayerOnionLayers = () => {\n const project = paper.project;\n if (!project) {\n return;\n }\n const onionLayer = project.layers.find(i => i.data.sa_isOnionLayer);\n if (!onionLayer) {\n return;\n }\n if (settings.layering === \"front\") {\n project.addLayer(onionLayer);\n } else {\n const rasterLayer = project.layers.find(i => i.data.isRasterLayer);\n if (rasterLayer.index === 0) {\n project.insertLayer(0, onionLayer);\n } else {\n project.insertLayer(1, onionLayer);\n }\n }\n };\n const recursePaperItem = (item, callback) => {\n if (item.children) {\n for (const child of item.children) {\n recursePaperItem(child, callback);\n }\n }\n callback(item);\n };\n const getTint = (red, green, blue, isBefore) => {\n const referenceColor = isBefore ? settings.beforeTint : settings.afterTint;\n const colorAverage = (red + green + blue) / 3 / 255;\n const WEIGHT = 1.5;\n const weighted = colorAverage / WEIGHT + (1 - 1 / WEIGHT);\n return [referenceColor[0] * weighted, referenceColor[1] * weighted, referenceColor[2] * weighted];\n };\n const toHexColor = _ref2 => {\n let [red, green, blue] = _ref2;\n const r = Math.round(red).toString(16).padStart(2, \"0\");\n const g = Math.round(green).toString(16).padStart(2, \"0\");\n const b = Math.round(blue).toString(16).padStart(2, \"0\");\n return \"#\".concat(r).concat(g).concat(b);\n };\n const getPaperColorTint = (color, isBefore) => toHexColor(getTint(color.red * 255, color.green * 255, color.blue * 255, isBefore));\n const tintRaster = (raster, isBefore) => {\n const {\n width,\n height\n } = raster.canvas;\n const context = raster.context;\n // TODO: check to see if this is a performance issue\n const imageData = context.getImageData(0, 0, width, height);\n const data = imageData.data;\n for (let i = 0; i < data.length; i += 4 /* RGBA */) {\n const red = data[i + 0];\n const green = data[i + 1];\n const blue = data[i + 2];\n const alpha = data[i + 3];\n if (alpha === 0) {\n continue;\n }\n const newTint = getTint(red, green, blue, isBefore);\n data[i + 0] = newTint[0];\n data[i + 1] = newTint[1];\n data[i + 2] = newTint[2];\n }\n context.putImageData(imageData, 0, 0);\n };\n const waitForAllRastersToLoad = root => {\n const promises = [];\n recursePaperItem(root, item => {\n if (item instanceof paper.Raster) {\n promises.push(new Promise((resolve, reject) => {\n item.on(\"load\", () => resolve());\n item.on(\"error\", () => reject(new Error(\"Raster inside SVG failed to load\")));\n }));\n }\n });\n return Promise.all(promises);\n };\n const rasterizeVector = root => {\n const bounds = root.strokeBounds;\n const {\n width,\n height\n } = bounds;\n\n // Some browsers experience extremely poor performance when this value exceeds 3840.\n const MAX_SIZE = 3000;\n const maxScale = Math.min(MAX_SIZE / width, MAX_SIZE / height);\n const raster = new paper.Raster(new paper.Size(width, height));\n raster.remove();\n raster.smoothing = true;\n raster.guide = true;\n raster.locked = true;\n let renderedAtScale = 0;\n const originalDraw = raster.draw;\n raster.draw = function () {\n const displayedSize = this.getView().getZoom() * window.devicePixelRatio;\n const newScale = Math.max(1, Math.min(maxScale, 2 ** Math.ceil(Math.log2(displayedSize))));\n if (newScale > renderedAtScale) {\n renderedAtScale = newScale;\n const canvas = this.canvas;\n const ctx = this.context;\n\n // Based on https://github.com/scratchfoundation/paper.js/blob/16d5ff0267e3a0ef647c25e58182a27300afad20/src/item/Item.js#L1761\n const scaledWidth = width * newScale;\n const scaledHeight = height * newScale;\n canvas.width = scaledWidth;\n canvas.height = scaledHeight;\n this._size = new paper.Size(scaledWidth, scaledHeight);\n const topLeft = bounds.getTopLeft();\n const bottomRight = bounds.getBottomRight();\n const size = new paper.Size(bottomRight.subtract(topLeft));\n const matrix = new paper.Matrix().scale(newScale).translate(topLeft.negate());\n ctx.save();\n matrix.applyToContext(ctx);\n root.draw(ctx, new paper.Base({\n matrices: [matrix]\n }));\n ctx.restore();\n this.matrix.reset();\n this.transform(new paper.Matrix().translate(topLeft.add(size.divide(2))).scale(1 / newScale));\n }\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n return originalDraw.call(this, ...args);\n };\n return raster;\n };\n const makeVectorOnion = (opacity, costume, asset, isBefore) => new Promise((resolve, reject) => {\n asset = src[\"sanitizeSvg\"].sanitizeSvgText(asset);\n const {\n rotationCenterX,\n rotationCenterY\n } = costume;\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L196-L218\n asset = asset.split(/<\\s*svg:/).join(\"<\");\n asset = asset.split(/<\\/\\s*svg:/).join(\"]*>/);\n if (svgAttrs && svgAttrs[0].indexOf(\"xmlns=\") === -1) {\n asset = asset.replace(\" {\n root.opacity = opacity;\n\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L274-L275\n recursePaperItem(root, i => {\n if (i.className === \"PathItem\") {\n i.clockwise = true;\n }\n if (i.className !== \"PointText\" && !i.children) {\n if (i.strokeWidth) {\n i.strokeWidth = i.strokeWidth * 2;\n }\n }\n i.locked = true;\n i.guide = true;\n });\n root.scale(2, new paper.Point(0, 0));\n if (settings.mode === \"tint\") {\n const gradients = new Set();\n recursePaperItem(root, i => {\n if (i.strokeColor) {\n i.strokeColor = getPaperColorTint(i.strokeColor, isBefore);\n }\n if (i.fillColor) {\n const gradient = i.fillColor.gradient;\n if (gradient) {\n if (gradients.has(gradient)) return;\n gradients.add(gradient);\n for (const stop of gradient.stops) {\n stop.color = getPaperColorTint(stop.color, isBefore);\n }\n } else {\n i.fillColor = getPaperColorTint(i.fillColor, isBefore);\n }\n }\n if (i.canvas) {\n tintRaster(i, isBefore);\n }\n });\n }\n const paperCenter = getPaperCenter();\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L277-L287\n if (typeof rotationCenterX !== \"undefined\" && typeof rotationCenterY !== \"undefined\") {\n let rotationPoint = new paper.Point(rotationCenterX, rotationCenterY);\n if (viewBox && viewBox.length >= 2 && !isNaN(viewBox[0]) && !isNaN(viewBox[1])) {\n rotationPoint = rotationPoint.subtract(viewBox[0], viewBox[1]);\n }\n root.translate(paperCenter.subtract(rotationPoint.multiply(2)));\n } else {\n root.translate(paperCenter.subtract(root.bounds.width, root.bounds.height));\n }\n return rasterizeVector(root);\n };\n paper.project.importSVG(asset, {\n expandShapes: true,\n insert: false,\n onLoad: root => {\n if (!root) {\n reject(new Error(\"could not load onion skin\"));\n return;\n }\n resolve(waitForAllRastersToLoad(root).then(() => handleLoad(root)));\n }\n });\n });\n const makeRasterOnion = (opacity, costume, asset, isBefore) => new Promise((resolve, reject) => {\n let {\n rotationCenterX,\n rotationCenterY\n } = costume;\n const image = new Image();\n image.onload = () => {\n const paperCenter = getPaperCenter();\n const width = Math.min(paperCenter.x * 2, image.width);\n const height = Math.min(paperCenter.y * 2, image.height);\n\n // https://github.com/scratchfoundation/scratch-paint/blob/cdf0afc217633e6cfb8ba90ea4ae38b79882cf6c/src/containers/paper-canvas.jsx#L151-L156\n if (typeof rotationCenterX === \"undefined\") {\n rotationCenterX = width / 2;\n }\n if (typeof rotationCenterY === \"undefined\") {\n rotationCenterY = height / 2;\n }\n const raster = new paper.Raster(image);\n raster.opacity = opacity;\n raster.guide = true;\n raster.locked = true;\n const x = width / 2 + (paperCenter.x - rotationCenterX);\n const y = height / 2 + (paperCenter.y - rotationCenterY);\n raster.position = new paper.Point(x, y);\n raster.remove();\n if (settings.mode === \"tint\") {\n tintRaster(raster, isBefore);\n }\n resolve(raster);\n };\n image.onerror = () => {\n reject(new Error(\"could not load image\"));\n };\n image.src = asset;\n });\n const getSelectedCostumeIndex = () => {\n const item = document.querySelector(\"[class*='selector_list-item'][class*='sprite-selector-item_is-selected']\");\n if (!item) return -1;\n const numberEl = item.querySelector(\"[class*='sprite-selector-item_number']\");\n if (!numberEl) return -1;\n return +numberEl.textContent - 1;\n };\n const updateOnionLayers = async () => {\n const project = paper.project;\n if (!project) {\n return;\n }\n const selectedCostumeIndex = getSelectedCostumeIndex();\n if (selectedCostumeIndex === -1) {\n return;\n }\n removeOnionLayers();\n const localUpdateId = cancelOngoingUpdatesAndGetNewId();\n const vm = addon.tab.traps.vm;\n if (!vm) {\n return;\n }\n const originalActiveLayer = project.activeLayer;\n const costumes = vm.editingTarget.sprite.costumes;\n const startIndex = Math.max(0, selectedCostumeIndex - settings.previous);\n const endIndex = Math.min(costumes.length - 1, selectedCostumeIndex + settings.next);\n try {\n const layersToCreate = [];\n for (let i = startIndex; i <= endIndex; i++) {\n if (i === selectedCostumeIndex) {\n continue;\n }\n const isBefore = i < selectedCostumeIndex;\n const distance = Math.abs(i - selectedCostumeIndex) - 1;\n const opacity = (settings.opacity - settings.opacityStep * distance) / 100;\n if (opacity <= 0) {\n continue;\n }\n layersToCreate.push({\n index: i,\n isBefore,\n opacity\n });\n }\n const onions = await Promise.all(layersToCreate.map(_ref3 => {\n let {\n index,\n isBefore,\n opacity\n } = _ref3;\n const onionCostume = costumes[index];\n const onionAsset = vm.getCostume(index);\n if (onionCostume.dataFormat === \"svg\") {\n return makeVectorOnion(opacity, onionCostume, onionAsset, isBefore);\n } else if (onionCostume.dataFormat === \"png\" || onionCostume.dataFormat === \"jpg\") {\n return makeRasterOnion(opacity, onionCostume, onionAsset, isBefore);\n } else {\n throw new Error(\"Unknown data format: \".concat(onionCostume.dataFormat));\n }\n }));\n\n // Make sure we haven't been cancelled\n if (globalUpdateId === localUpdateId) {\n const layer = createOnionLayer();\n for (const item of onions) {\n layer.addChild(item);\n }\n relayerOnionLayers();\n }\n } catch (e) {\n console.error(e);\n }\n\n // We must make sure to always reset the active layer to avoid corruption.\n originalActiveLayer.activate();\n };\n const setEnabled = _enabled => {\n if (settings.enabled === _enabled) {\n return;\n }\n settings.enabled = _enabled;\n if (settings.enabled) {\n if (settings.next === 0 && settings.previous === 0) {\n settings.previous = 1;\n layerInputs.previous.value = settings.previous;\n }\n if (settings.opacity === 0) {\n settings.opacity = 25;\n layerInputs.opacity.value = settings.opacity;\n }\n updateOnionLayers();\n } else {\n removeOnionLayers();\n }\n toggleButton.dataset.enabled = settings.enabled;\n };\n\n //\n // Controls below editor\n //\n\n const settingsChanged = onlyRelayerNeeded => {\n if (settings.previous === 0 && settings.next === 0 || settings.opacity === 0) {\n setEnabled(false);\n return;\n }\n if (settings.enabled) {\n if (onlyRelayerNeeded) {\n relayerOnionLayers();\n } else {\n updateOnionLayers();\n }\n } else if (settings.previous > 0 || settings.next > 0) {\n setEnabled(true);\n }\n };\n const createGroup = () => {\n const el = document.createElement(\"div\");\n el.className = \"sa-onion-group\";\n return el;\n };\n const createButton = function createButton() {\n let {\n useButtonTag\n } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n const el = document.createElement(useButtonTag ? \"button\" : \"span\");\n el.className = \"sa-onion-button\";\n el.setAttribute(\"role\", \"button\");\n return el;\n };\n const createButtonImage = name => {\n const el = document.createElement(\"img\");\n el.className = \"sa-onion-image\";\n el.draggable = false;\n el.dataset.image = name;\n el.loading = \"lazy\";\n el.src = addon.self.getResource(\"/\" + name + \".svg\") /* rewritten by pull.js */;\n return el;\n };\n const toggleControlsGroup = createGroup();\n addon.tab.displayNoneWhileDisabled(toggleControlsGroup, {\n display: \"flex\"\n });\n const toggleButton = createButton();\n toggleButton.dataset.enabled = settings.enabled;\n toggleButton.addEventListener(\"click\", () => setEnabled(!settings.enabled));\n toggleButton.title = msg(\"toggle\");\n toggleButton.appendChild(createButtonImage(\"toggle\"));\n const settingButton = createButton();\n settingButton.addEventListener(\"click\", () => setSettingsOpen(!areSettingsOpen()));\n settingButton.title = msg(\"settings\");\n settingButton.appendChild(createButtonImage(\"settings\"));\n document.body.addEventListener(\"click\", e => {\n if (areSettingsOpen() && !e.target.matches(\".sa-onion-group *\")) setSettingsOpen(false);\n });\n\n //\n // Settings page\n //\n\n const settingPageWrapper = document.createElement(\"div\");\n settingPageWrapper.className = \"sa-onion-settings-wrapper\";\n toggleControlsGroup.append(settingPageWrapper, toggleButton, settingButton);\n const settingsPage = document.createElement(\"div\");\n settingsPage.className = \"sa-onion-settings\";\n const setSettingsOpen = open => {\n settingButton.dataset.enabled = open;\n settingsPage.dataset.visible = open;\n };\n const areSettingsOpen = () => settingsPage.dataset.visible === \"true\";\n const layerInputs = {};\n for (const type of [\"previous\", \"next\", \"opacity\", \"opacityStep\"]) {\n const container = document.createElement(\"label\");\n container.className = \"sa-onion-settings-line\";\n const label = document.createElement(\"div\");\n label.className = \"sa-onion-settings-label\";\n label.textContent = msg(type);\n container.appendChild(label);\n const group = createGroup();\n const currentButton = createButton();\n const filler = document.createElement(\"div\");\n filler.style.width = \"20px\";\n currentButton.appendChild(filler);\n const currentInput = document.createElement(\"input\");\n layerInputs[type] = currentInput;\n currentInput.className = \"sa-onion-settings-input\";\n currentInput.type = \"number\";\n currentInput.step = \"1\";\n currentInput.min = \"0\";\n currentInput.max = \"100\";\n currentInput.value = settings[type];\n currentInput.addEventListener(\"input\", e => {\n if (currentInput.value.length === 0) {\n settings[type] = 0;\n settingsChanged();\n return;\n }\n let value = +currentInput.value;\n if (value > +currentInput.max) {\n value = +currentInput.max;\n } else if (value < 0) {\n value = 0;\n }\n currentInput.value = value;\n settings[type] = value;\n settingsChanged();\n });\n currentInput.addEventListener(\"blur\", () => {\n if (!currentInput.value) {\n currentInput.value = \"0\";\n }\n });\n currentButton.appendChild(currentInput);\n const decrementButton = createButton();\n decrementButton.appendChild(createButtonImage(\"decrement\"));\n decrementButton.addEventListener(\"click\", () => {\n if (settings[type] > 0) {\n settings[type]--;\n currentInput.value = settings[type];\n settingsChanged();\n }\n });\n const incrementButton = createButton();\n incrementButton.appendChild(createButtonImage(\"increment\"));\n incrementButton.addEventListener(\"click\", () => {\n if (settings[type] < +currentInput.max) {\n settings[type]++;\n currentInput.value = settings[type];\n settingsChanged();\n }\n });\n group.appendChild(decrementButton);\n group.appendChild(currentButton);\n group.appendChild(incrementButton);\n container.appendChild(group);\n settingsPage.appendChild(container);\n }\n const modeContainer = document.createElement(\"div\");\n modeContainer.className = \"sa-onion-settings-line\";\n const modeLabel = document.createElement(\"div\");\n modeLabel.className = \"sa-onion-settings-label\";\n modeLabel.textContent = msg(\"mode\");\n const modeGroup = createGroup();\n modeContainer.appendChild(modeLabel);\n const modeMergeButton = createButton({\n useButtonTag: true\n });\n modeMergeButton.appendChild(document.createTextNode(msg(\"merge\")));\n modeGroup.appendChild(modeMergeButton);\n modeMergeButton.addEventListener(\"click\", e => {\n settings.mode = \"merge\";\n modeTintButton.dataset.enabled = false;\n modeMergeButton.dataset.enabled = true;\n settingsChanged();\n });\n modeMergeButton.dataset.enabled = settings.mode === \"merge\";\n const modeTintButton = createButton({\n useButtonTag: true\n });\n modeTintButton.appendChild(document.createTextNode(msg(\"tint\")));\n modeGroup.appendChild(modeTintButton);\n modeTintButton.addEventListener(\"click\", e => {\n settings.mode = \"tint\";\n modeTintButton.dataset.enabled = true;\n modeMergeButton.dataset.enabled = false;\n settingsChanged();\n });\n modeTintButton.dataset.enabled = settings.mode === \"tint\";\n modeContainer.appendChild(modeGroup);\n settingsPage.appendChild(modeContainer);\n const layeringContainer = document.createElement(\"div\");\n layeringContainer.className = \"sa-onion-settings-line\";\n const layeringLabel = document.createElement(\"div\");\n layeringLabel.className = \"sa-onion-settings-label\";\n layeringLabel.textContent = msg(\"layering\");\n const layeringGroup = createGroup();\n layeringContainer.appendChild(layeringLabel);\n const layeringFrontButton = createButton({\n useButtonTag: true\n });\n layeringFrontButton.appendChild(document.createTextNode(msg(\"front\")));\n layeringGroup.appendChild(layeringFrontButton);\n layeringFrontButton.addEventListener(\"click\", e => {\n settings.layering = \"front\";\n layeringBehindButton.dataset.enabled = false;\n layeringFrontButton.dataset.enabled = true;\n settingsChanged(true);\n });\n layeringFrontButton.dataset.enabled = settings.layering === \"front\";\n const layeringBehindButton = createButton({\n useButtonTag: true\n });\n layeringBehindButton.appendChild(document.createTextNode(msg(\"behind\")));\n layeringGroup.appendChild(layeringBehindButton);\n layeringBehindButton.addEventListener(\"click\", e => {\n settings.layering = \"behind\";\n layeringBehindButton.dataset.enabled = true;\n layeringFrontButton.dataset.enabled = false;\n settingsChanged(true);\n });\n layeringBehindButton.dataset.enabled = settings.layering === \"behind\";\n layeringContainer.appendChild(layeringGroup);\n settingsPage.appendChild(layeringContainer);\n const SVG_NS = \"http://www.w3.org/2000/svg\";\n const settingsTip = document.createElementNS(SVG_NS, \"svg\");\n settingsTip.setAttribute(\"class\", \"sa-onion-settings-tip\");\n settingsTip.setAttribute(\"width\", \"14\");\n settingsTip.setAttribute(\"height\", \"7\");\n const settingsTipShape = document.createElementNS(SVG_NS, \"polygon\");\n settingsTipShape.setAttribute(\"class\", \"sa-onion-settings-polygon\");\n settingsTipShape.setAttribute(\"points\", \"0,0 7,7, 14,0\");\n settingsTip.appendChild(settingsTipShape);\n settingsPage.appendChild(settingsTip);\n let oldEnabled = null;\n addon.self.addEventListener(\"disabled\", () => {\n setSettingsOpen(false);\n oldEnabled = settings.enabled;\n setEnabled(false);\n });\n addon.self.addEventListener(\"reenabled\", () => {\n setEnabled(oldEnabled);\n });\n const controlsLoop = async () => {\n let hasRunOnce = false;\n while (true) {\n const canvasControls = await addon.tab.waitForElement(\"[class^='paint-editor_canvas-controls']\", {\n markAsSeen: true,\n reduxEvents: [\"scratch-gui/navigation/ACTIVATE_TAB\", \"scratch-gui/mode/SET_PLAYER\", \"fontsLoaded/SET_FONTS_LOADED\", \"scratch-gui/locales/SELECT_LOCALE\", \"scratch-gui/targets/UPDATE_TARGET_LIST\"],\n reduxCondition: state => state.scratchGui.editorTab.activeTabIndex === 1 && !state.scratchGui.mode.isPlayerOnly\n });\n const zoomControlsContainer = canvasControls.querySelector(\"[class^='paint-editor_zoom-controls']\");\n addon.tab.appendToSharedSpace({\n space: \"paintEditorZoomControls\",\n element: toggleControlsGroup,\n order: 1\n });\n settingPageWrapper.appendChild(settingsPage);\n if (!hasRunOnce) {\n hasRunOnce = true;\n const groupClass = zoomControlsContainer.firstChild.className;\n const buttonClass = zoomControlsContainer.firstChild.firstChild.className;\n const imageClass = zoomControlsContainer.firstChild.firstChild.firstChild.className;\n for (const el of document.querySelectorAll(\".sa-onion-group\")) {\n el.className += \" \" + groupClass;\n }\n for (const el of document.querySelectorAll(\".sa-onion-button\")) {\n el.className += \" \" + buttonClass;\n }\n for (const el of document.querySelectorAll(\".sa-onion-image\")) {\n el.className += \" \" + imageClass;\n }\n }\n if (settings.enabled) {\n updateOnionLayers();\n }\n }\n };\n injectPaper();\n injectPaperCanvas();\n controlsLoop();\n});\n// EXTERNAL MODULE: ./node_modules/css-loader!./src/addons/addons/onion-skinning/style.css\nvar style = __webpack_require__(1466);\nvar style_default = /*#__PURE__*/__webpack_require__.n(style);\n\n// CONCATENATED MODULE: ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/decrement.svg\n/* harmony default export */ var decrement = (\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg==\");\n// CONCATENATED MODULE: ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/increment.svg\n/* harmony default export */ var increment = (\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjxwYXRoIHRyYW5zZm9ybT0icm90YXRlKDkwKSIgc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUtMTIuNjQyaDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg==\");\n// CONCATENATED MODULE: ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/settings.svg\n/* harmony default export */ var onion_skinning_settings = (\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9Im9wYWNpdHk6Ljc1O2ZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgZD0iTTU2IDE2djk2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMi4zNzYgLTIuMzc2KSBzY2FsZSguMjI0NjIpIi8+PHBhdGggc3R5bGU9Im9wYWNpdHk6LjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNDAgMzJ2NjQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouMjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNMjQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNzU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNzIgMTZ2OTYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik04OCAzMnY2NCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIuMzc2IC0yLjM3Nikgc2NhbGUoLjIyNDYyKSIvPjxwYXRoIHN0eWxlPSJvcGFjaXR5Oi4yNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik0xMDQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48L3N2Zz4=\");\n// CONCATENATED MODULE: ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/toggle.svg\n/* harmony default export */ var toggle = (\"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggZmlsbD0iI2JmYmZiZiIgZD0iTTM5LjYzMi0uNTc2Yy4wNy0uMDQ2LjE4Ny0uMDIzLjIxLjA3bC42MDYgMi40OTJzMS40OSAxLjA5NSAxLjkzMyAxLjg2M2MuNzQ1IDEuMjgxLjc2OCAyLjMzLjc2OCAyLjMzczEuNjU0LjQ4OCAxLjkzMyAxLjgxNmMuMjggMS4zMjctLjc0NSAzLjg0My01LjEyMyA0LjcwNS00LjM3OS44NjEtNy44OTYtLjMyNy05LjU1LTIuOTgyLTEuNjUzLTIuNjU1Ljk1Ni01LjgyMi44MTYtNS42MzZsLS40OS00LjE2OWMtLjAyMy0uMDkzLjA5NC0uMTYzLjE4Ny0uMTE2bDIuODE4IDEuODRzMS4wNDgtLjM5NiAyLjE0My0uNDQzYTcuMDEgNy4wMSAwIDAgMSAxLjc0Ny4wOTN6IiBzdHlsZT0ib3BhY2l0eTouNTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTQ3LjM2NSA2LjUyOGMtMS4wOTUuODg1LTIuNzcyLjkwOC0yLjc3Mi45MDhtMi40NjkgMS43Yy0xLjQ2Ny4xMTctMi4zNzYtLjMyNi0yLjM3Ni0uMzI2TTI4LjY2MyA2LjQ1OHMyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNWMtMS4wMDIuMzk2LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ib3BhY2l0eTouNTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9IiNiZmJmYmYiIGQ9Ik00MS45NjEgMS43NTNjLjA3LS4wNDYuMTg3LS4wMjMuMjEuMDdsLjYwNiAyLjQ5MnMxLjQ5IDEuMDk1IDEuOTMzIDEuODYzYy43NDUgMS4yODEuNzY4IDIuMzMuNzY4IDIuMzNzMS42NTQuNDg4IDEuOTMzIDEuODE2Yy4yOCAxLjMyNy0uNzQ1IDMuODQzLTUuMTIzIDQuNzA1LTQuMzc5Ljg2MS03Ljg5Ni0uMzI3LTkuNTUtMi45ODItMS42NTMtMi42NTUuOTU2LTUuODIyLjgxNi01LjYzNmwtLjQ5LTQuMTY5Yy0uMDIzLS4wOTMuMDk0LS4xNjMuMTg3LS4xMTZsMi44MTggMS44NHMxLjA0OC0uMzk2IDIuMTQzLS40NDNhNy4wMSA3LjAxIDAgMCAxIDEuNzQ3LjA5M3oiIHN0eWxlPSJvcGFjaXR5Oi43NTttaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMxNjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIvPjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTQ5LjY5NCA4Ljg1N2MtMS4wOTUuODg1LTIuNzcyLjkwOC0yLjc3Mi45MDhtMi40NjkgMS43Yy0xLjQ2Ny4xMTctMi4zNzYtLjMyNi0yLjM3Ni0uMzI2TTMwLjk5MiA4Ljc4N3MyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNWMtMS4wMDIuMzk2LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ib3BhY2l0eTouNzU7bWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMTY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiLz48cGF0aCBmaWxsPSIjYmZiZmJmIiBkPSJNNDQuMjkgNC4wODJjLjA3LS4wNDcuMTg2LS4wMjQuMjEuMDdsLjYwNSAyLjQ5MnMxLjQ5IDEuMDk0IDEuOTMzIDEuODYzYy43NDUgMS4yOC43NjkgMi4zMjkuNzY5IDIuMzI5czEuNjUzLjQ4OSAxLjkzMyAxLjgxNmMuMjggMS4zMjgtLjc0NSAzLjg0My01LjEyNCA0LjcwNS00LjM3OC44NjItNy44OTUtLjMyNi05LjU0OS0yLjk4MS0xLjY1My0yLjY1NS45NTUtNS44MjMuODE1LTUuNjM2bC0uNDg5LTQuMTdjLS4wMjMtLjA5Mi4wOTMtLjE2Mi4xODctLjExNmwyLjgxOCAxLjg0czEuMDQ4LS4zOTYgMi4xNDItLjQ0MmE3LjAxIDcuMDEgMCAwIDEgMS43NDcuMDkzeiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiNmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwMDEwMjY7c3Ryb2tlLXdpZHRoOi45MzE2O3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIi8+PHBhdGggZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNTIuMDIyIDExLjE4NWMtMS4wOTQuODg1LTIuNzcxLjkwOC0yLjc3MS45MDhtMi40NjggMS43Yy0xLjQ2Ny4xMTctMi4zNzUtLjMyNS0yLjM3NS0uMzI1TTMzLjMyIDExLjExNXMyLjAwMy42NTIgMi44MTggMS4zNzRtLjA3LjgxNmMtMS4wMDEuMzk1LTIuNzI1LjE0LTIuNzI1LjE0IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMTY7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjAiLz48ZyBzdHlsZT0ib3BhY2l0eTouMTg5ODU0Ij48cGF0aCBkPSJNMS4yNDMgOC41YS42MzcuNjM3IDAgMCAwLS40NSAxLjA4NmwuMy4zYy4yNDItLjM1Mi41NDYtLjY1OC44OTgtLjlsLS4yOTctLjNhLjYzNi42MzYgMCAwIDAtLjQ1LS4xODVaIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC4wNCAtMi42NDcpIi8+PHBhdGggZD0iTTE1LjExNCAxOS41MDZhMy41MDEgMy41MDEgMCAxIDEtNy4wMDMgMCAzLjUwMSAzLjUwMSAwIDAgMSA3LjAwMyAwem0tNy4zOTItNy4zMThhMy41IDMuNSAwIDEgMCAuNDA2IDYuOTg1IDMuNSAzLjUgMCAwIDEgMy4xNS0zLjE1IDMuNSAzLjUgMCAwIDAtMy41NTYtMy44MzV6bS0zLjc0Ni0zLjgyYTMuNTAxIDMuNTAxIDAgMSAwIC4zMzYgNi45ODQgMy41MDIgMy41MDIgMCAwIDEgMy4xNDgtMy4xNDggMy41IDMuNSAwIDAgMC0zLjQ4NC0zLjgzNnoiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjA0IC0yLjY0NykiLz48cGF0aCBkPSJNMTQuNDk3IDIxLjQ5MWMtLjI0My4zNTItLjU1LjY1Ni0uOTAyLjg5OWwzLjA4NCAzLjA4NGEuNjM4LjYzOCAwIDAgMCAuOSAwIC42MzcuNjM3IDAgMCAwIDAtLjl6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC4wNCAtMi42NDcpIi8+PC9nPjxnIHN0eWxlPSJvcGFjaXR5Oi44MDU1MyI+PGcgc3R5bGU9Im9wYWNpdHk6LjU4NTkyOCI+PHBhdGggZD0iTTEuMjQzIDguNWEuNjM3LjYzNyAwIDAgMC0uNDUgMS4wODZsLjMuM2MuMjQyLS4zNTIuNTQ2LS42NTguODk4LS45bC0uMjk3LS4zYS42MzYuNjM2IDAgMCAwLS40NS0uMTg1WiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOiMwMDEwMjY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOi4xOTY0OTI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzQ5NiAwIDAgMS4wMzQ5NiAyLjc3NSAtNS4xNykiLz48cGF0aCBkPSJNMTUuMTE0IDE5LjUwNmEzLjUwMSAzLjUwMSAwIDEgMS03LjAwMyAwIDMuNTAxIDMuNTAxIDAgMCAxIDcuMDAzIDB6bS03LjM5Mi03LjMxOGEzLjUgMy41IDAgMSAwIC40MDYgNi45ODUgMy41IDMuNSAwIDAgMSAzLjE1LTMuMTUgMy41IDMuNSAwIDAgMC0zLjU1Ni0zLjgzNXptLTMuNzQ2LTMuODJhMy41MDEgMy41MDEgMCAxIDAgLjMzNiA2Ljk4NCAzLjUwMiAzLjUwMiAwIDAgMSAzLjE0OC0zLjE0OCAzLjUgMy41IDAgMCAwLTMuNDg0LTMuODM2eiIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbDtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiMwMDEwMjY7c3Ryb2tlLXdpZHRoOi45MzI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MSIgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMzQ5NiAwIDAgMS4wMzQ5NiAyLjc3NSAtNS4xNykiLz48cGF0aCBkPSJNMTQuNDk3IDIxLjQ5MWMtLjI0My4zNTItLjU1LjY1Ni0uOTAyLjg5OWwzLjA4NCAzLjA4NGEuNjM4LjYzOCAwIDAgMCAuOSAwIC42MzcuNjM3IDAgMCAwIDAtLjl6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IDIuNzc1IC01LjE3KSIvPjwvZz48L2c+PHBhdGggZmlsbD0iI2Q5OWU4MiIgZD0iTTIxLjkwNyAxOS4xM2EuNjM2LjYzNiAwIDAgMS0uNDUtLjE4NUw1LjU3MiAzLjA1OGEuNjM3LjYzNyAwIDAgMSAuOS0uOWwxNS44ODUgMTUuODg2YS42MzcuNjM3IDAgMCAxLS40NSAxLjA4N3oiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojMDAxMDI2O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDouMTk2NDkyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjYxNyAtMS4zMykiLz48cGF0aCBmaWxsPSIjZmNiMWUzIiBkPSJNMTIuMjUzIDUuMzRhMy41IDMuNSAwIDEgMS03IDAgMy41IDMuNSAwIDAgMSA3IDB6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6I2ZlZmVmZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PHBhdGggZmlsbD0iI2ZmZDk4MyIgZD0iTTExLjc2OCAxMi41NjZhMy41IDMuNSAwIDEgMSAxLjYxLTYuODEzIDMuNSAzLjUgMCAwIDEtMS42MSA2LjgxM3oiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDojZmVmZWZkO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojMDAxMDI2O3N0cm9rZS13aWR0aDouOTMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjEiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDM0OTYgMCAwIDEuMDM0OTYgLjYxNyAtMS4zMykiLz48cGF0aCBmaWxsPSIjYTZkMzg4IiBkPSJNMTkuODkyIDEyLjk3N2EzLjUwMSAzLjUwMSAwIDEgMS03LjAwMyAwIDMuNTAxIDMuNTAxIDAgMCAxIDcuMDAzIDB6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6I2ZlZmVmZDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzAwMTAyNjtzdHJva2Utd2lkdGg6LjkzMjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PHBhdGggZmlsbD0iI2Q5OWU4MiIgZD0iTTIxLjkwNyAxOS4xM2EuNjM2LjYzNiAwIDAgMS0uNDUtLjE4NWwtMy44OTgtMy45YS42MzYuNjM2IDAgMSAxIC45LS45bDMuODk4IDMuOWEuNjM3LjYzNyAwIDAgMS0uNDUgMS4wODZ6IiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6IzAwMTAyNjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6LjE5NjQ5MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiB0cmFuc2Zvcm09Im1hdHJpeCgxLjAzNDk2IDAgMCAxLjAzNDk2IC42MTcgLTEuMzMpIi8+PC9zdmc+\");\n// CONCATENATED MODULE: ./src/addons/addons/onion-skinning/_runtime_entry.js\n/* generated by pull.js */\n\n\n\n\n\n\nconst resources = {\n \"userscript.js\": userscript,\n \"style.css\": style_default.a,\n \"decrement.svg\": decrement,\n \"increment.svg\": increment,\n \"settings.svg\": onion_skinning_settings,\n \"toggle.svg\": toggle\n};\n\n/***/ }),\n\n/***/ 1525:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, \"resources\", function() { return /* binding */ resources; });\n\n// CONCATENATED MODULE: ./src/addons/addons/middle-click-popup/BlockTypeInfo.js\nvar _BlockShape;\nfunction _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }\nfunction _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : i + \"\"; }\nfunction _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\n/**\n * @file Contains the code for enumerating the different types of blocks in a workspace,\n * and provides a more friendly way to create instances blocks with some inputs.\n */\n\n/**\n * A numeric value to represent the type of an {@link BlockInput}\n * @readonly\n * @enum {number}\n */\nconst BlockInputType = {\n STRING: 0,\n NUMBER: 1,\n BOOLEAN: 2,\n COLOUR: 3,\n ENUM: 4,\n BLOCK: 5\n};\n\n/**\n * @abstract\n */\nclass BlockInput {\n /**\n * @param {BlockInputType} type\n * @param {number} inputIdx\n * @param {number} fieldIdx\n */\n constructor(type, inputIdx, fieldIdx) {\n if (this.constructor === BlockInput) throw new Error(\"Abstract classes can't be instantiated.\");\n /** @type {BlockInputType} */\n this.type = type;\n /** @type {number} The index of this input in the workspace version of the block's input array. */\n this.inputIdx = inputIdx;\n /**\n * The index of this input in the workspace version of the block's field array.\n * The special case of -1 means that in the workspace version, this input is inside a sub-block,\n * that has been abstracted away.\n * @type {number}\n */\n this.fieldIdx = fieldIdx;\n /** @type {*} The default value to set this input to, or null to not set it to anything. */\n this.defaultValue = null;\n }\n\n /**\n * Sets the field this input refers to on a block to a value.\n * @param {BlockInstance} block\n * @param {*} value\n * @abstract\n */\n setValue(block, value) {\n throw new Error(\"Sub-class must override abstract method.\");\n }\n\n /**\n * Gets the input this block input refers to on block.\n * @param {BlockInstance} block\n * @returns {*}\n * @protected\n */\n getInput(block) {\n return block.inputList[this.inputIdx];\n }\n\n /**\n * Gets the field this block input refers to on block.\n * @param {BlockInstance} block\n * @returns {*}\n * @protected\n */\n getField(block) {\n if (this.fieldIdx === -1) {\n return this.getInput(block).connection.targetBlock().inputList[0].fieldRow[0];\n } else {\n return this.getInput(block).fieldRow[this.fieldIdx];\n }\n }\n}\n\n/**\n * The base class for any round input.\n * @abstract\n */\nclass BlockInputRound extends BlockInput {\n constructor(type, inputIdx, fieldIdx, defaultValue) {\n super(type, inputIdx, fieldIdx);\n if (this.constructor === BlockInputRound) throw new Error(\"Abstract classes can't be instantiated.\");\n this.defaultValue = defaultValue;\n }\n setValue(block, value) {\n if (value instanceof BlockInstance) {\n const subblock = value.createWorkspaceForm();\n if (!subblock.outputConnection) throw new Error('Cannot put block \"' + subblock.typeInfo.id + '\" into a round type input.');\n subblock.outputConnection.connect(this.getInput(block).connection);\n } else {\n this.getField(block).setValue(this._toFieldValue(value));\n }\n }\n\n /**\n * Converts a value passed in to setValue to a value we can set the block's field to.\n * @param {*} value\n * @protected\n */\n _toFieldValue(value) {\n throw new Error(\"Sub-class must override abstract method.\");\n }\n}\nclass BlockInputString extends BlockInputRound {\n constructor(inputIdx, fieldIdx, defaultValue) {\n super(BlockInputType.STRING, inputIdx, fieldIdx, defaultValue);\n }\n _toFieldValue(value) {\n const type = typeof value;\n if (type === \"number\") return value;\n if (type === \"string\") return value;\n throw new Error(\"Cannot set round type input to value of type \" + type);\n }\n}\nclass BlockInputNumber extends BlockInputRound {\n constructor(inputIdx, fieldIdx, defaultValue) {\n super(BlockInputType.NUMBER, inputIdx, fieldIdx, defaultValue);\n }\n _toFieldValue(value) {\n const type = typeof value;\n if (type === \"number\") return value;\n if (type === \"string\") {\n if (value.length === 0) return value;\n const number = parseFloat(value);\n if (isNaN(number)) throw new Error('Cannot set numeric type input to string \"' + value + '\".');\n return value;\n }\n throw new Error(\"Cannot set round type input to value of type \" + type);\n }\n}\nclass BlockInputBoolean extends BlockInput {\n constructor(inputIdx, fieldIdx) {\n super(BlockInputType.BOOLEAN, inputIdx, fieldIdx);\n }\n setValue(block, value) {\n if (value instanceof BlockInstance) {\n const subblock = value.createWorkspaceForm();\n if (!subblock.outputConnection || value.typeInfo.shape !== BlockShape.Boolean) throw new Error('Cannot put block \"' + value.typeInfo.id + '\" into a boolean type input.');\n subblock.outputConnection.connect(this.getInput(block).connection);\n } else {\n throw new Error(\"Boolean type inputs can only contain blocks.\");\n }\n }\n}\nclass BlockInputColour extends BlockInput {\n constructor(inputIdx, fieldIdx) {\n super(BlockInputType.COLOUR, inputIdx, fieldIdx);\n }\n setValue(block, value) {\n if (typeof value !== \"string\") throw new Error(\"Cannot set color type input to value of type \" + typeof type);\n if (!value.match(/^#[0-9a-fA-F]{6}$/)) throw new Error('Invalid color \"' + value + '\".');\n this.getField(block).setValue(value);\n }\n}\n\n/**\n * @typedef BlockInputEnumOption\n * @property {string} value The internal name of this input option\n * @property {string} string The localized name of this input option.\n */\n\n/**\n * A block input that can be one of a list of values.\n * Usually represented by a dropdown menu in Scratch.\n */\nclass BlockInputEnum extends BlockInput {\n /**\n * @param {Array} options\n * @param {number} inputIdx\n * @param {number} fieldIdx\n */\n constructor(options, inputIdx, fieldIdx, isRound) {\n super(BlockInputType.ENUM, inputIdx, fieldIdx);\n /** @type {BlockInputEnumOption[]} */\n this.values = [];\n for (let i = 0; i < options.length; i++) {\n if (typeof options[i][1] === \"string\" && BlockInputEnum.INVALID_VALUES.indexOf(options[i][1]) === -1) {\n this.values.push({\n value: options[i][1],\n string: options[i][0].replace(/\\u00a0/g, \" \")\n });\n }\n }\n this.isRound = isRound;\n this.defaultValue = this.values[0];\n }\n\n /**\n * @param {BlockInputEnumOption} value\n */\n setValue(block, value) {\n if (this.isRound && value instanceof BlockInstance) {\n value.createWorkspaceForm().outputConnection.connect(this.getInput(block).connection);\n } else {\n if (this.values.indexOf(value) === -1) throw new Error(\"Invalid enum value. Expected item from the values list.\");\n this.getField(block).setValue(value.value);\n }\n }\n}\n\n/**\n * A block input that is a stack of blocks.\n * The 'if' block has a single block input, the 'if else' block has two block inputs.\n */\n_defineProperty(BlockInputEnum, \"INVALID_VALUES\", [\"DELETE_VARIABLE_ID\", \"RENAME_VARIABLE_ID\", \"NEW_BROADCAST_MESSAGE_ID\", \"NEW_BROADCAST_MESSAGE_ID\",\n// editor-searchable-dropdowns compatibility\n\"createGlobalVariable\", \"createLocalVariable\", \"createGlobalList\", \"createLocalList\", \"createBroadcast\",\n// rename-broadcasts compatibility\n\"RENAME_BROADCAST_MESSAGE_ID\"]);\nclass BlockInputBlock extends BlockInput {\n constructor(inputIdx, fieldIdx) {\n super(BlockInputType.BLOCK, inputIdx, fieldIdx);\n }\n setValue(block, value) {\n if (value instanceof BlockInstance) {\n const subblock = value.createWorkspaceForm();\n if (!subblock.previousConnection || !value.typeInfo.shape.canStackUp) throw new Error('Cannot put block \"' + value.typeInfo.id + '\" into a block type input.');\n subblock.previousConnection.connect(this.getInput(block).connection);\n } else {\n throw new Error(\"Block type inputs can only contain blocks.\");\n }\n }\n}\n\n/**\n * Because everyone was thinking \"You know what Scratch really needs, ANOTHER way to represent blocks!\"\n *\n * Another way to represent a Scratch block.\n */\nclass BlockInstance {\n constructor(typeInfo) {\n /** @type {BlockTypeInfo} */\n this.typeInfo = typeInfo;\n /** @type {Array} */\n for (var _len = arguments.length, inputs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n inputs[_key - 1] = arguments[_key];\n }\n this.inputs = inputs;\n for (let i = 0; i < this.typeInfo.inputs.length; i++) {\n if (this.inputs[i] == null) this.inputs[i] = this.typeInfo.inputs[i].defaultValue;\n }\n }\n\n /**\n * Creates a real Scratch block from this imaginary representation.\n * @returns {*} A 'workspace form' block.\n */\n createWorkspaceForm() {\n if (this.typeInfo.id === \"control_stop\") {\n this.typeInfo.domForm.querySelector(\"mutation\").setAttribute(\"hasnext\", \"\" + (this.inputs[0].value === \"other scripts in sprite\"));\n }\n const block = this.typeInfo.Blockly.Xml.domToBlock(this.typeInfo.domForm, this.typeInfo.workspace);\n for (let i = 0; i < this.typeInfo.inputs.length; i++) {\n const inputValue = this.inputs[i];\n if (inputValue != null) this.typeInfo.inputs[i].setValue(block, inputValue);\n }\n return block;\n }\n}\n\n/**\n * An enum for the different shapes of blocks.\n * Contains information on what each type of block can do.\n */\nclass BlockShape {\n static getBlockShape(workspaceBlock) {\n if (workspaceBlock.edgeShape_ === 2) {\n return BlockShape.Round;\n } else if (workspaceBlock.edgeShape_ === 1) {\n return BlockShape.Boolean;\n } else if (workspaceBlock.startHat_) {\n return BlockShape.Hat;\n } else if (!workspaceBlock.nextConnection) {\n return BlockShape.End;\n } else {\n return BlockShape.Stack;\n }\n }\n constructor(canStackUp, canStackDown, canBeRound) {\n /** @type {boolean} Can blocks be stacked above this block? */\n this.canStackUp = canStackUp;\n /** @type {boolean} Can blocks be stacked below this block? */\n this.canStackDown = canStackDown;\n /** @type {boolean} Does this block fit into a round hole? */\n this.canBeRound = canBeRound;\n }\n}\n\n/**\n * @typedef BlockCategory\n * @property {string} name\n * @property {string} colorPrimary\n * @property {string} colorSecondary\n * @property {string} colorTertiary\n */\n\n/**\n * A type of Scratch block, like 'move () steps'. Every instance of the 'move () steps'\n * block shares this type info.\n */\n_BlockShape = BlockShape;\n_defineProperty(BlockShape, \"Round\", new _BlockShape(false, false, true));\n_defineProperty(BlockShape, \"Boolean\", new _BlockShape(false, false, true));\n_defineProperty(BlockShape, \"Hat\", new _BlockShape(false, true, false));\n_defineProperty(BlockShape, \"End\", new _BlockShape(true, false, false));\n_defineProperty(BlockShape, \"Stack\", new _BlockShape(true, true, false));\nclass BlockTypeInfo {\n /**\n * @param {*} block Block in workspace form\n * @param {*} vm\n * @returns {BlockCategory} The block's category\n */\n static getBlockCategory(block, vm) {\n let name;\n if (block.type === \"procedures_call\") {\n if (vm.getAddonBlock(block.getProcCode())) name = \"addon-custom-block\";else name = \"more\";\n } else if (block.usesDefaultExtensionColors) name = \"pen\";else if (block.type === \"sensing_of\") name = \"sensing\";else if (block.type === \"event_whenbackdropswitchesto\") name = \"events\";else name = block.category_;\n return {\n name,\n colorPrimary: block.colour_,\n colorSecondary: block.colourSecondary_,\n colorTertiary: block.colourTertiary_\n };\n }\n\n /**\n * Enumerates all the different types of blocks, given a workspace.\n * @param {Blockly} Blockly\n * @param {*} vm\n * @param {*} workspace\n * @param {(string) => string} locale The translations used for converting icons into text\n * @returns {BlockTypeInfo[]}\n */\n static getBlocks(Blockly, vm, workspace, locale) {\n var _workspace$getToolbox;\n const flyoutWorkspace = (_workspace$getToolbox = workspace.getToolbox()) === null || _workspace$getToolbox === void 0 ? void 0 : _workspace$getToolbox.flyout_.getWorkspace();\n if (!flyoutWorkspace) return [];\n const blocks = [];\n const flyoutDom = Blockly.Xml.workspaceToDom(flyoutWorkspace);\n const flyoutDomBlockMap = {};\n for (const blockDom of flyoutDom.children) {\n if (blockDom.tagName === \"BLOCK\") {\n let id = blockDom.getAttribute(\"id\");\n flyoutDomBlockMap[id] = blockDom;\n }\n }\n for (const workspaceBlock of flyoutWorkspace.getTopBlocks()) {\n blocks.push(...BlockTypeInfo._createBlocks(workspace, vm, Blockly, locale, workspaceBlock, flyoutDomBlockMap[workspaceBlock.id]));\n }\n return blocks;\n }\n static _createBlocks(workspace, vm, Blockly, locale, workspaceForm, domForm) {\n let parts = [];\n let inputs = [];\n const addInput = input => {\n parts.push(input);\n inputs.push(input);\n };\n const addFieldInputs = (field, inputIdx, fieldIdx) => {\n if (field.className_ === \"blocklyText blocklyDropdownText\") {\n const options = field.getOptions();\n addInput(new BlockInputEnum(options, inputIdx, fieldIdx, fieldIdx === -1));\n } else if (field instanceof Blockly.FieldImage) {\n switch (field.src_.split(\"/\").pop()) {\n case \"green-flag.svg\":\n parts.push(locale(\"/_general/blocks/green-flag\"));\n break;\n case \"rotate-right.svg\":\n parts.push(locale(\"/_general/blocks/clockwise\"));\n break;\n case \"rotate-left.svg\":\n parts.push(locale(\"/_general/blocks/anticlockwise\"));\n break;\n }\n } else {\n if (!field.argType_) {\n if (field.getText().trim().length !== 0) parts.push(field.getText());\n } else if (field.argType_[0] === \"colour\") {\n addInput(new BlockInputColour(inputIdx, fieldIdx));\n } else if (field.argType_[1] === \"number\") {\n addInput(new BlockInputNumber(inputIdx, fieldIdx, field.text_));\n } else {\n addInput(new BlockInputString(inputIdx, fieldIdx, field.text_));\n }\n }\n };\n for (let inputIdx = 0; inputIdx < ((_workspaceForm$inputL = workspaceForm.inputList) === null || _workspaceForm$inputL === void 0 ? void 0 : _workspaceForm$inputL.length); inputIdx++) {\n var _workspaceForm$inputL;\n const input = workspaceForm.inputList[inputIdx];\n for (let fieldIdx = 0; fieldIdx < input.fieldRow.length; fieldIdx++) {\n addFieldInputs(input.fieldRow[fieldIdx], inputIdx, fieldIdx);\n }\n if (input.connection) {\n const innerBlock = input.connection.targetBlock();\n if (innerBlock) {\n if (innerBlock.inputList.length !== 1 || innerBlock.inputList[0].fieldRow.length !== 1) throw new Error(\"This should never happen.\");\n let innerField = innerBlock.inputList[0].fieldRow[0];\n addFieldInputs(innerField, inputIdx, -1);\n } else {\n if (input.outlinePath) {\n addInput(new BlockInputBoolean(inputIdx, -1));\n } else {\n addInput(new BlockInputBlock(inputIdx, -1));\n }\n }\n }\n }\n if (workspaceForm.id === \"of\") {\n let blocks = [];\n let baseVarInputIdx, baseTargetInputIdx;\n // In most languages, the 'of' block inputs are: [variable] of [sprite], and in others\n // it's the opposite (sprite then variable). We can tell that the variable comes first\n // if the first input is round.\n if (inputs[0].isRound) {\n baseVarInputIdx = 1;\n baseTargetInputIdx = 0;\n } else {\n baseVarInputIdx = 0;\n baseTargetInputIdx = 1;\n }\n let baseVarInput = inputs[baseVarInputIdx];\n let baseTargetInput = inputs[baseTargetInputIdx];\n const baseVarPartIdx = parts.indexOf(baseVarInput);\n const baseTargetPartIdx = parts.indexOf(baseTargetInput);\n\n // Adapted from https://github.com/scratchfoundation/scratch-gui/blob/cc6e6324064493cf1788f3c7c0ff31e4057964ee/src/lib/blocks.js#L230\n const stageOptions = [[Blockly.Msg.SENSING_OF_BACKDROPNUMBER, \"backdrop #\"], [Blockly.Msg.SENSING_OF_BACKDROPNAME, \"backdrop name\"], [Blockly.Msg.SENSING_OF_VOLUME, \"volume\"]];\n const spriteOptions = [[Blockly.Msg.SENSING_OF_XPOSITION, \"x position\"], [Blockly.Msg.SENSING_OF_YPOSITION, \"y position\"], [Blockly.Msg.SENSING_OF_DIRECTION, \"direction\"], [Blockly.Msg.SENSING_OF_COSTUMENUMBER, \"costume #\"], [Blockly.Msg.SENSING_OF_COSTUMENAME, \"costume name\"], [Blockly.Msg.SENSING_OF_SIZE, \"size\"], [Blockly.Msg.SENSING_OF_VOLUME, \"volume\"]];\n for (const targetInput of baseTargetInput.values) {\n let options;\n const isStage = targetInput.value === \"_stage_\";\n if (isStage) {\n const stageVariableOptions = vm.runtime.getTargetForStage().getAllVariableNamesInScopeByType(\"\");\n options = stageVariableOptions.map(variable => [variable, variable]).concat(stageOptions);\n } else {\n const sprite = vm.runtime.getSpriteTargetByName(targetInput.value);\n const spriteVariableOptions = sprite.getAllVariableNamesInScopeByType(\"\", true);\n options = spriteVariableOptions.map(variable => [variable, variable]).concat(spriteOptions);\n }\n const ofInputs = [];\n ofInputs[baseVarInputIdx] = new BlockInputEnum(options, baseVarInput.inputIdx, baseVarInput.fieldIdx, false);\n ofInputs[baseTargetInputIdx] = new BlockInputEnum([[targetInput.string, targetInput.value]], baseTargetInput.inputIdx, baseTargetInput.fieldIdx, isStage);\n const ofParts = [...parts];\n ofParts[baseVarPartIdx] = ofInputs[baseVarInputIdx];\n ofParts[baseTargetPartIdx] = ofInputs[baseTargetInputIdx];\n blocks.push(new BlockTypeInfo(workspace, Blockly, vm, workspaceForm, domForm, ofParts, ofInputs));\n }\n return blocks;\n } else if (workspaceForm.id === \"control_stop\") {\n // This block is special because when \"other scripts in sprite\" is selected the block\n // needs to be BlockShape.End.\n const oldInput = inputs[0];\n const otherScriptsOptionIdx = oldInput.values.findIndex(option => option.string === \"other scripts in sprite\");\n const otherScriptsOption = oldInput.values.splice(otherScriptsOptionIdx, 1)[0];\n const newInput = new BlockInputEnum([[otherScriptsOption.string, otherScriptsOption.value]], oldInput.inputIdx, oldInput.fieldIdx, oldInput.isRound);\n const newBlockParts = [...parts];\n newBlockParts[parts.indexOf(oldInput)] = newInput;\n return [new BlockTypeInfo(workspace, Blockly, vm, workspaceForm, domForm, parts, inputs, BlockShape.End), new BlockTypeInfo(workspace, Blockly, vm, workspaceForm, domForm, newBlockParts, [newInput], BlockShape.Stack)];\n } else {\n return [new BlockTypeInfo(workspace, Blockly, vm, workspaceForm, domForm, parts, inputs)];\n }\n }\n constructor(workspace, Blockly, vm, workspaceForm, domForm, parts, inputs, shape) {\n /** @type {string} */\n this.id = workspaceForm.id;\n this.workspaceForm = workspaceForm;\n this.domForm = domForm;\n /** @type {BlockShape} */\n this.shape = shape !== null && shape !== void 0 ? shape : BlockShape.getBlockShape(this.workspaceForm);\n /** @type {BlockCategory} */\n this.category = BlockTypeInfo.getBlockCategory(this.workspaceForm, vm);\n this.workspace = workspace;\n this.Blockly = Blockly;\n\n /**\n * A list of all the 'parts' of this block. Each part is either an instance\n * of BlockInput or a string for some text which is a part of a block.\n *\n * For example, for the 'say' block, the first element of the array would be\n * the string 'say', and the second element would be a BlockInput of type\n * BlockInputString.\n * @type {(BlockInput | string)[]}\n */\n this.parts = parts;\n /**\n * A list of all this block's inputs. The same as this.parts, but with the\n * strings omitted.\n * @type {BlockInput[]}\n */\n this.inputs = inputs;\n }\n\n /**\n * Creates a block of this type with the given inputs\n * @param {...any} inputs\n * @returns {BlockInstance}\n */\n createBlock() {\n for (var _len2 = arguments.length, inputs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n inputs[_key2] = arguments[_key2];\n }\n return new BlockInstance(this, ...inputs);\n }\n}\n// CONCATENATED MODULE: ./src/addons/addons/middle-click-popup/WorkspaceQuerier.js\nvar _TokenTypeBlank, _TokenTypeColor;\nfunction ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }\nfunction _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { WorkspaceQuerier_defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }\nfunction WorkspaceQuerier_defineProperty(e, r, t) { return (r = WorkspaceQuerier_toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }\nfunction WorkspaceQuerier_toPropertyKey(t) { var i = WorkspaceQuerier_toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : i + \"\"; }\nfunction WorkspaceQuerier_toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\n/**\n * @file Contains all the logic for the parsing of queries by the {@link WorkspaceQuerier}.\n * I'm really sorry if somebody other than me ever has to debug this.\n * Wish you luck <3\n *\n * Once you *think* you understand the function of the major classes, read the docs on\n * {@link WorkspaceQuerier._createTokenGroups} for some more specifics on the algorithm works,\n * and to achieve maximum enlightenment.\n *\n * @author Tacodiva\n */\n\n\n\n/**\n *\n * A token is a part of a query that is interpreted in a specific way.\n *\n * In the query 'say 1 = Hello World', the base tokens are 'say', '1', '=, and 'Hello World'.\n * Each token contains where in the query it is located and what {@link TokenType} it is.\n *\n * Sometimes the same section of a query has multiple tokens because there are different\n * interpretations of what type of token it is. For example, imagine you had a variable named\n * 'x'. The query 'set x to 10', is ambiguous because you could be referring to the motion block\n * `set x to ()` or the data block `set [x] to ()`. This ambiguity results in two different\n * tokens being creating for 'x', one is 'set x to' referring to the motion block, and the other\n * is just 'x', referring to the variable.\n *\n * Calling this a 'token' is somewhat misleading, often language interpreters will have a 'parse tree'\n * with tokens and an 'abstract syntax tree' with higher level elements, but I have chosen to make these\n * two trees one in the same. Because of this, every token represents a logical part of a block.\n * Going back to the 'say 1 = Hello World' example, there are two 'parent' tokens, both are of type\n * {@link TokenTypeBlock}. The first is for the equals block, which contains three subtokens; '1',\n * '=' and 'Hello World'. The second is the say block, whos first child is 'say' and second child is\n * the token for the equals block (which itself has three children). For a query result to be valid,\n * it must have a token which encapsulates the entire query, in this case the say block token starts\n * at the first letter and ends at the last letter, so it's a valid interpretation. The token which\n * encapsulates the whole query is referred to as the root token.\n */\nclass Token {\n /**\n * @param {number} start\n * @param {number} end\n * @param {TokenType} type\n * @param {*} value\n * @param {number} precedence\n * @param {boolean} isTruncated\n * @param {boolean} isLegal\n */\n constructor(start, end, type, value) {\n let {\n precedence = -1,\n isProper = true,\n isTruncated = false,\n isLegal = true,\n isDefiningFeature = false\n } = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};\n /** @type {number} The index of the first letter of this token in the query */\n this.start = start;\n /** @type {number} The index of the last letter of this token in the query */\n this.end = end;\n /** @type {TokenType} The type of this token. */\n this.type = type;\n /** @type {*} Additional information about this token, controlled and interpreted by the token type. */\n this.value = value;\n /**\n * The precedence of this token, used to implement order of operations. Tokens with a higher\n * precedence should be evaluated *after* those with a lower precedence. Brackets have a\n * precedence of 0 so they are always evaluated first. A precedence of -1 means that precedence\n * is not specified and the parser makes no guarantees about the order of operations.\n * @type {number}\n */\n this.precedence = precedence;\n /**\n * True if this token is fully written out. For example, in the query \"m v = 10\" where \"m v\"\n * expands to \"my variable\", the token \"m v\" is not proper, as it is not fully written.\n * Note that unlike trauncation, parent tokens do not inherit this property (so in the above\n * example, the '=' block token would still be proper).\n */\n this.isProper = isProper;\n /**\n * Sometimes, tokens are truncated. Imagine the query 'say Hello for 10 se', here the last\n * token should be 'seconds', but it's truncated. For this token, the isTruncated value is set\n * to true. Additionally, the token for the whole block (which contains the tokens 'say', 'Hello',\n * 'for', '10' and 'se') also has it's isTruncated value set to true, because it contains a\n * truncated token.\n * @type {boolean}\n */\n this.isTruncated = isTruncated;\n /**\n * Used to generate autocomplete text, even if that autocomplete text doesn't make a valid query\n * by itself. For example in the query 'if my varia', we want to autocomplete to 'my variable',\n * but the query 'if my variable' is still not valid, because my variable is not a boolean. In\n * this case, the 'my variable' token would still be emitted as the second child of the 'if' token,\n * but it would be marked as illegal.\n */\n this.isLegal = isLegal;\n /**\n * If we see this token, should we know what block it's connected to?\n *\n * For example, in the query 'say Hi', 'say' is a defining feature because\n * we can narrow down what block it's from based only the fact that it's present.\n * 'Hi', however, is not a defining feature as it could be a part of lots of\n * different blocks.\n *\n * This is used to help eliminate some dodgey interpretations of queries, if a block\n * has no subtokens marked a defining feature it's disguarded.\n * @type {boolean}\n */\n this.isDefiningFeature = isDefiningFeature;\n }\n\n /**\n * @see {TokenType.createBlockValue}\n * @param {QueryInfo} query\n * @returns\n */\n createBlockValue(query) {\n return this.type.createBlockValue(this, query);\n }\n}\n\n/**\n * The parent of any class that can enumerate tokens given a query and a location within that\n * query to search.\n *\n * As the same position in a query can have multiple interpretations (see {@link Token}), every\n * token provider's {@link parseTokens} method can return multiple tokens for the same index.\n *\n * Like tokens, there is a token provider tree. See {@link WorkspaceQuerier._createTokenGroups}\n * for more info on this tree.\n *\n * @abstract\n */\nclass TokenProvider {\n constructor(shouldCache) {\n if (this.constructor === TokenProvider) throw new Error(\"Abstract classes can't be instantiated.\");\n /**\n * Can the results of this token provider be stored? True\n * if {@link parseTokens} will always return the same thing for the same inputs or if\n * this token provider already caches it's result, so caching it again is redundant.\n * @type {boolean}\n */\n this.shouldCache = shouldCache;\n }\n\n /**\n * Return the tokens found by this token provider in `query` at character `idx`.\n * @param {QueryInfo} query The query to search\n * @param {number} idx The index to start the search at\n * @param {number} depth The number of blocks this token is inside of.\n * For the query 1 + 1, the `+` block token would have a depth of 0 and the `1` tokens would have a depth of 1.\n * @yields {Token} All the tokens found\n * @abstract\n */\n // eslint-disable-next-line require-yield\n *parseTokens(query, idx, depth) {\n throw new Error(\"Sub-class must override abstract method.\");\n }\n}\n\n/**\n * A token provider which wraps around another token provider, always returning a blank token in\n * addition to whatever the inner token provider returns.\n *\n * Used for tokens that can possibility be omitted, like numbers. For example, the '+' block always\n * needs three inputs, but the user could query '1 +'. In this case its subtokens are '1', '+' and\n * a {@link TokenTypeBlank}, provided by this provider.\n */\nclass TokenProviderOptional extends TokenProvider {\n /**\n * @param {TokenProvider} inner\n */\n constructor(inner) {\n super(inner.shouldCache);\n /** @type {TokenProvider} The inner token provider to return along with the blank token. */\n this.inner = inner;\n }\n *parseTokens(query, idx, depth) {\n yield TokenTypeBlank.INSTANCE.createToken(idx);\n yield* this.inner.parseTokens(query, idx, depth);\n }\n}\n\n/**\n * Caches the output of an inner token provider.\n * Used for tokens that are a part of multiple token provider groups.\n */\nclass TokenProviderSingleCache extends TokenProvider {\n /**\n * @param {TokenProvider} inner\n */\n constructor(inner) {\n super(false);\n /** @type {TokenProvider} */\n this.inner = inner;\n if (this.inner.shouldCache) {\n /** @type {Token[]?} */\n this.cache = [];\n /** @type {number?} */\n this.cacheQueryID = null;\n }\n }\n *parseTokens(query, idx, depth) {\n if (!this.inner.shouldCache) {\n yield* this.inner.parseTokens(query, idx, depth);\n return;\n }\n if (this.cacheQueryID !== query.id) {\n this.cache = [];\n this.cacheQueryID = query.id;\n }\n let cacheEntry = this.cache[idx];\n if (cacheEntry) {\n yield* cacheEntry;\n return;\n }\n this.cache[idx] = cacheEntry = [];\n for (const token of this.inner.parseTokens(query, idx, depth)) {\n cacheEntry.push(token);\n yield token;\n }\n }\n}\n\n/**\n * Collects multiple inner token providers into one token provider group.\n * Additionally, caches the results of all the cacheable inner token providers.\n */\nclass TokenProviderGroup extends TokenProvider {\n constructor() {\n // No need to cache this as it already caches it's own output.\n super(false);\n /** @type {TokenProvider[]} The providers that make up this group */\n this.providers = [];\n /** @type {TokenProvider[]} Providers that are a part of the group, but tokens they produce are illegal */\n this.illegalProviders = [];\n /** @type {Object?} The cache */\n this.cache = null;\n /** @type {number?} The query ID of the query whos results are currently cached */\n this.cacheQueryID = null;\n /** @type {boolean} Are any of our inner tokens cacheable? */\n this.hasCacheable = false;\n }\n\n /**\n * @typedef CacheEntry\n * @property {Token[][]} tokenCaches\n * @property {TokenProvider[][]} providerCaches\n */\n\n /**\n * Adds token providers to this token provider group.\n * @param {TokenProvider[]} providers\n * @param {boolean} legal Are the results of this provider legal in the current context?\n */\n pushProviders(providers) {\n let legal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n if (!this.hasCacheable) for (const provider of providers) {\n if (provider.shouldCache) {\n this.hasCacheable = true;\n break;\n }\n }\n if (legal) this.providers.push(...providers);else this.illegalProviders.push(...providers);\n }\n *parseTokens(query, idx, depth) {\n // If none of our providers are cacheable, just parse all the tokens again\n if (!this.hasCacheable) {\n for (const provider of this.providers) yield* provider.parseTokens(query, idx, depth);\n return;\n }\n\n // If the query ID has changed, the cache is no longer valid\n if (this.cacheQueryID !== query.id) {\n this.cache = [];\n this.cacheQueryID = query.id;\n } else {\n // Otherwise, search for a cache entry for idx\n const cacheEntry = this.cache[idx];\n if (cacheEntry) {\n // If we find one, yield all the cached results\n const tokenCaches = cacheEntry.tokenCaches;\n const providerCaches = cacheEntry.providerCaches;\n for (let i = 0; i < tokenCaches.length; i++) {\n const tokenCache = tokenCaches[i];\n const providerCache = providerCaches[i];\n for (const provider of providerCache) yield* provider.parseTokens(query, idx, depth);\n yield* tokenCache;\n }\n return;\n }\n }\n\n // No applicable cache entry was found :(\n // Call all our child token providers and create a new cache entry\n\n let tokenCache = [];\n let providerCache = [];\n const tokenCaches = [tokenCache];\n const providerCaches = [providerCache];\n this.cache[idx] = {\n tokenCaches,\n providerCaches\n };\n for (const provider of this.providers) {\n if (provider.shouldCache) {\n for (const token of provider.parseTokens(query, idx, depth)) {\n tokenCache.push(token);\n yield token;\n }\n } else {\n if (tokenCache.length !== 0) {\n tokenCache = [];\n providerCache = [];\n tokenCaches.push(tokenCache);\n providerCaches.push(providerCache);\n }\n providerCache.push(provider);\n yield* provider.parseTokens(query, idx, depth);\n }\n }\n for (const provider of this.illegalProviders) {\n for (let token of provider.parseTokens(query, idx, depth)) {\n token = _objectSpread(_objectSpread({}, token), {}, {\n isLegal: false\n });\n tokenCache.push(token);\n yield token;\n }\n }\n }\n}\n\n/**\n * A class representing the type of a token (see {@link Token.type})\n *\n * All token types extend from {@link TokenProvider} and they provide all the tokens\n * of their type they can find.\n *\n * @abstract\n */\nclass TokenType extends TokenProvider {\n constructor() {\n let dontCache = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n super(!dontCache);\n if (this.constructor === TokenType) throw new Error(\"Abstract classes can't be instantiated.\");\n\n /** @type {boolean} Is this token type always represented by the same string of characters? */\n this.isConstant = false;\n }\n\n /**\n * Turns `token` into a value which can be passed into the {@link BlockInstance} constructor.\n * For example, in string literal tokens, this gets the string value of the token which can then\n * be used to create a block.\n * @param {Token} token\n * @param {QueryInfo} query\n * @returns {*}\n */\n createBlockValue(token, query) {\n return token.value;\n }\n\n /**\n * Creates the string form of this token in the same format that was used in the query.\n * If the token was only partially typed in the query, creating the text will complete the token.\n * @param {Token} token\n * @param {QueryInfo} query\n * @param {boolean} endOnly Should we only append to the end of the query. If this is false, we\n * can create text in the middle of the query that wasn't there. This is used to autocomplete\n * {@link StringEnum.GriffTokenType} tokens in the middle of a query.\n * @returns {string}\n */\n createText(token, query, endOnly) {\n throw new Error(\"Sub-class must override abstract method.\");\n }\n\n /**\n * @param {Token} token\n * @param {QueryInfo} query\n * @returns {Token[]}\n */\n getSubtokens(token, query) {\n return undefined;\n }\n}\n\n/**\n * The type for tokens that represent an omitted field.\n * Used by {@link TokenProviderOptional}\n */\nclass TokenTypeBlank extends TokenType {\n constructor() {\n super();\n this.isConstant = true;\n }\n *parseTokens(query, idx, depth) {\n yield this.createToken(idx);\n }\n\n /**\n * Create a new blank token\n * @param {number} idx The position of the blank token\n * @returns {Token}\n */\n createToken(idx) {\n return new Token(idx, idx, this, null);\n }\n createText(token, query) {\n return \"\";\n }\n}\n\n/**\n * Represents a token whos value must be one of a predetermined set of strings.\n * For example, a token for a dropdown menu (like the one in `set [my variable] to x`) is a\n * string enum, because the value must be one of a set of strings.\n *\n * String enums are also used for values that can only be one specific value (like the 'set' from\n * `set [my variable] to x`). These cases are just string enums with one possible value.\n */\n_TokenTypeBlank = TokenTypeBlank;\nWorkspaceQuerier_defineProperty(TokenTypeBlank, \"INSTANCE\", new _TokenTypeBlank());\nclass TokenTypeStringEnum extends TokenType {\n /**\n * @typedef StringEnumValue\n * @property {string} value The string that needs to be in the query\n * @property {string} lower Cached value.toLowerCase()\n * @property {string[]} parts lower, split up by ignoreable characters.\n */\n\n /**\n * @param {(import(\"./BlockTypeInfo\").BlockInputEnumOption[]} values\n */\n constructor(values) {\n super();\n this.isConstant = values.length === 1;\n\n /** @type {StringEnumValue[]} */\n this.values = [];\n for (const value of values) {\n let lower = value.string.toLowerCase();\n const parts = [];\n {\n let lastPart = 0;\n for (let i = 0; i <= lower.length; i++) {\n const char = lower[i];\n if (QueryInfo.IGNORABLE_CHARS.indexOf(char) !== -1 || !char) {\n parts.push(lower.substring(lastPart, i));\n i = QueryInfo.skipIgnorable(lower, i);\n lastPart = i;\n }\n }\n }\n this.values.push({\n lower,\n parts,\n value\n });\n }\n }\n *parseTokens(query, idx, depth) {\n for (let valueIdx = 0; valueIdx < this.values.length; valueIdx++) {\n const valueInfo = this.values[valueIdx];\n let yieldedToken = false;\n const remainingChar = query.length - idx;\n const substr = query.lowercase.substring(idx);\n\n // If all we have is a string which could be a number, it doesn't count as a defining feature.\n // This is to get rid of \"10\" constantly suggesting \"10 ^ of ()\"\n let isDefiningFeature = !TokenTypeNumberLiteral.isValidNumber(substr);\n if (remainingChar < valueInfo.lower.length) {\n if (valueInfo.lower.startsWith(substr)) {\n const end = remainingChar < 0 ? 0 : query.length;\n yield new Token(idx, end, this, valueInfo, {\n isTruncated: true,\n isDefiningFeature\n });\n yieldedToken = true;\n }\n } else {\n if (query.lowercase.startsWith(valueInfo.lower, idx)) {\n yield new Token(idx, idx + valueInfo.lower.length, this, valueInfo, {\n isDefiningFeature\n });\n yieldedToken = true;\n }\n }\n }\n }\n createBlockValue(token, query) {\n return token.value.value;\n }\n createText(token, query, endOnly) {\n if (!token) return this.values[0].lower;\n return token.value.lower;\n }\n}\n\n/**\n * The token type for a literal string, like 'Hello World' in the query `say Hello World`\n */\nclass TokenTypeStringLiteral extends TokenType {\n static isTerminator(char) {\n return this.TERMINATORS.includes(char);\n }\n\n /**\n * Each time we encounter a 'terminator' we have to return the string we've read so far as a\n * possible interpretation. If we didn't, when looking for a string at index 4 of 'say Hello\n * World for 10 seconds' we would just return 'Hello World for 10 seconds', leading to the\n * only result being `say \"Hello World for 10 seconds\"`. This also means in addition to\n * 'Hello World' we also return 'Hello', 'Hello World for', 'Hello World for 10' and '\n * Hello World for 10 seconds', but that's just the price we pay for trying to enumerate every\n * interpretation.\n */\n *parseTokens(query, idx, depth) {\n // First, look for strings in quotes\n let quoteEnd = -1;\n if (query.str[idx] === '\"' || query.str[idx] === \"'\") {\n const quote = query.str[idx];\n let value = \"\";\n let valueStart = idx + 1;\n for (let i = idx + 1; i <= query.length; i++) {\n if (query.str[i] === \"\\\\\") {\n value += query.str.substring(valueStart, i);\n valueStart = ++i;\n } else if (query.str[i] === quote) {\n yield new Token(idx, i + 1, this, value + query.str.substring(valueStart, i));\n quoteEnd = i + 1;\n break;\n }\n }\n }\n // Then all the other strings\n let wasTerminator = false;\n let wasIgnorable = false;\n for (let i = idx; i <= query.length; i++) {\n const isTerminator = TokenTypeStringLiteral.isTerminator(query.str[i]);\n const isIgnorable = QueryInfo.IGNORABLE_CHARS.includes(query.str[i]);\n if ((wasTerminator !== isTerminator || i == query.length) && !wasIgnorable && i !== idx && i !== quoteEnd) {\n const value = query.str.substring(idx, i);\n yield new Token(idx, i, this, value);\n }\n wasTerminator = isTerminator;\n wasIgnorable = isIgnorable;\n }\n }\n createText(token, query, endOnly) {\n return query.str.substring(token.start, token.end);\n }\n}\n\n/**\n * The token type for a literal number, like 69 in the query 'Hello + 69'\n * This token type also supports numbers in formats scratch doesn't let you type,\n * but accepts like '0xFF', 'Infinity' or '1e3'.\n */\nWorkspaceQuerier_defineProperty(TokenTypeStringLiteral, \"TERMINATORS\", [undefined, \" \", \"+\", \"-\", \"*\", \"/\", \"=\", \"<\", \">\", \")\"]);\nclass TokenTypeNumberLiteral extends TokenType {\n static isValidNumber(str) {\n return !isNaN(+str) || !isNaN(parseFloat(+str));\n }\n *parseTokens(query, idx, depth) {\n for (let i = idx; i <= query.length; i++) {\n if (TokenTypeStringLiteral.isTerminator(query.str[i]) && i !== idx) {\n const value = query.str.substring(idx, i);\n if (TokenTypeNumberLiteral.isValidNumber(value)) {\n yield new Token(idx, i, this, value);\n break;\n }\n }\n }\n }\n createText(token, query, endOnly) {\n return query.str.substring(token.start, token.end);\n }\n}\n\n/**\n * A token type for literal colors, like '#ffffff' for white.\n */\nclass TokenTypeColor extends TokenType {\n *parseTokens(query, idx, depth) {\n if (!query.str.startsWith(\"#\", idx)) return;\n for (let i = 0; i < 6; i++) {\n if (TokenTypeColor.HEX_CHARS.indexOf(query.lowercase[idx + i + 1]) === -1) return;\n }\n yield new Token(idx, idx + 7, this, query.str.substring(idx, idx + 7));\n }\n createText(token, query, endOnly) {\n return query.query.substring(token.start, token.end);\n }\n}\n\n/**\n * A token type for tokens that are in brackets, like (1 + 1) in '(1 + 1) * 2'.\n */\n_TokenTypeColor = TokenTypeColor;\nWorkspaceQuerier_defineProperty(TokenTypeColor, \"INSTANCE\", new TokenProviderOptional(new _TokenTypeColor()));\nWorkspaceQuerier_defineProperty(TokenTypeColor, \"HEX_CHARS\", [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]);\nclass TokenTypeBrackets extends TokenType {\n /**\n * @param {TokenProvider} tokenProvider\n */\n constructor(tokenProvider) {\n super();\n /** @type {TokenProvider} The tokens to look for between the brackets */\n this.tokenProvider = tokenProvider;\n }\n *parseTokens(query, idx, depth) {\n const start = idx;\n if (query.str[idx++] !== \"(\") return;\n idx = query.skipIgnorable(idx);\n for (const token of this.tokenProvider.parseTokens(query, idx, depth)) {\n if (token.type instanceof TokenTypeBlank) continue; // Do not allow empty brackets like '()'\n var tokenEnd = query.skipIgnorable(token.end);\n let isTruncated = token.isTruncated;\n if (!isTruncated) {\n if (tokenEnd === query.length) isTruncated = true;else if (query.str[tokenEnd] === \")\") ++tokenEnd;else continue;\n }\n // Note that for bracket tokens, precedence = 0\n const newToken = new Token(start, tokenEnd, this, token.value, {\n precedence: 0,\n isTruncated,\n isLegal: token.isLegal\n });\n newToken.innerToken = token;\n yield newToken;\n }\n }\n createBlockValue(token, query) {\n return token.innerToken.createBlockValue(token.innerToken, query);\n }\n createText(token, query, endOnly) {\n let text = \"(\";\n text += query.str.substring(token.start + 1, token.innerToken.start);\n text += token.innerToken.type.createText(token.innerToken, query, endOnly);\n if (token.innerToken.end !== token.end) text += query.str.substring(token.innerToken.end, token.end - 1);\n text += \")\";\n return text;\n }\n getSubtokens(token, query) {\n return [token.innerToken];\n }\n}\n\n/**\n * The token type for a block, like 'say Hello' or '1 + 1'.\n */\nclass WorkspaceQuerier_TokenTypeBlock extends TokenType {\n /**\n * @param {WorkspaceQuerier} querier\n * @param {BlockTypeInfo} block\n * @private\n */\n constructor(querier, block) {\n var _this;\n super();\n _this = this;\n this.block = block;\n this.hasSubTokens = true;\n /**\n * The list of token types that make up this block.\n *\n * For example, for the non-griff version of the 'say' block this array would contains two\n * providers, the first is a {@link StringEnum.FullTokenType} containing only the value 'say'\n * and the second is equal to querier.tokenGroupString.\n *\n * @type {TokenProvider[]}\n */\n this.fullTokenProviders = [];\n for (const blockPart of block.parts) {\n let fullTokenProvider;\n if (typeof blockPart === \"string\") {\n fullTokenProvider = new TokenTypeStringEnum([{\n value: null,\n string: blockPart\n }]);\n } else {\n switch (blockPart.type) {\n case BlockInputType.ENUM:\n fullTokenProvider = new TokenTypeStringEnum(blockPart.values);\n if (blockPart.isRound) {\n const enumGroup = new TokenProviderGroup();\n enumGroup.pushProviders([fullTokenProvider, querier.tokenGroupRoundBlocks]);\n fullTokenProvider = enumGroup;\n }\n break;\n case BlockInputType.STRING:\n fullTokenProvider = querier.tokenGroupString;\n break;\n case BlockInputType.NUMBER:\n fullTokenProvider = querier.tokenGroupNumber;\n break;\n case BlockInputType.COLOUR:\n fullTokenProvider = TokenTypeColor.INSTANCE;\n break;\n case BlockInputType.BOOLEAN:\n fullTokenProvider = querier.tokenGroupBoolean;\n break;\n case BlockInputType.BLOCK:\n fullTokenProvider = querier.tokenGroupStack;\n break;\n }\n }\n this.fullTokenProviders.push(fullTokenProvider);\n }\n\n /**\n * @type {{strings: string[], inputs: [], length: number}[]}\n */\n this.stringForms = [];\n const _enumerateStringForms = function enumerateStringForms() {\n let partIdx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;\n let strings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n let inputs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];\n let length = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;\n for (; partIdx < block.parts.length; partIdx++) {\n let blockPart = block.parts[partIdx];\n if (typeof blockPart === \"string\") {\n length += blockPart.length;\n strings.push(...blockPart.toLowerCase().split(\" \"));\n } else if (blockPart.type === BlockInputType.ENUM) {\n for (const enumValue of blockPart.values) {\n if (_this.stringForms.length >= WorkspaceQuerier_WorkspaceQuerier.MAX_RESULTS) return;\n _enumerateStringForms(partIdx + 1, [...strings, ...enumValue.string.toLowerCase().split(\" \")], [...inputs, enumValue], length + enumValue.string.length);\n }\n return;\n } else {\n inputs.push(null);\n }\n }\n _this.stringForms.push({\n strings,\n inputs,\n length\n });\n };\n _enumerateStringForms();\n if (this.stringForms.length >= WorkspaceQuerier_WorkspaceQuerier.MAX_STRING_FORMS) {\n console.warn(\"Warning: Block '\" + this.block.id + \"' has too many string forms. Search results may not be very good.\");\n this.stringForms.length = 0;\n }\n }\n\n /**\n * @param {QueryInfo} query\n * @param {number} idx\n * @param {number} depth\n * @returns\n */\n *parseTokens(query, idx, depth) {\n if (depth !== 0 && !query.canCreateMoreNestedBlocks()) return;\n let yieldedTokens = false;\n for (const subtokens of this._parseSubtokens(query, idx, this.fullTokenProviders)) {\n let token = this._createToken(query, idx, this.fullTokenProviders, subtokens);\n if (token) {\n yield token;\n yieldedTokens = true;\n }\n }\n if (yieldedTokens) return;\n outer: for (const stringForm of this.stringForms) {\n let lastPartIdx = -1;\n let i = idx;\n let hasDefiningFeature = false;\n while (true) {\n i = query.skipIgnorable(i);\n const wordEnd = query.skipUnignorable(i);\n if (wordEnd === i) {\n if (hasDefiningFeature) yield new Token(idx, wordEnd, this, {\n stringForm,\n lastPartIdx: -1\n }, {\n isProper: false\n });\n break;\n } else {\n const word = query.lowercase.substring(i, wordEnd);\n let match = -1;\n for (let formPartIdx = lastPartIdx + 1; formPartIdx < stringForm.strings.length; formPartIdx++) {\n const stringFormPart = stringForm.strings[formPartIdx];\n if (stringFormPart.startsWith(word)) {\n match = formPartIdx;\n break;\n }\n }\n if (match === -1) continue outer;\n lastPartIdx = match;\n hasDefiningFeature || (hasDefiningFeature = !TokenTypeNumberLiteral.isValidNumber(word));\n if (query.skipIgnorable(wordEnd) < query.length) {\n if (hasDefiningFeature) yield new Token(idx, wordEnd, this, {\n stringForm,\n lastPartIdx,\n i\n }, {\n isProper: false\n });\n }\n i = wordEnd;\n }\n }\n }\n }\n\n /**\n * @private\n * @param {QueryInfo} query\n * @param {number} idx\n * @param {TokenProvider[]} subtokenProviders\n * @param {Token[]} subtokens\n * @returns {Token?}\n */\n _createToken(query, idx, subtokenProviders, subtokens) {\n subtokens.reverse();\n let isLegal = true;\n let isTruncated = subtokens.length < subtokenProviders.length;\n let hasDefiningFeature = false;\n for (const subtoken of subtokens) {\n isTruncated |= subtoken.isTruncated; // If any of our kids are truncated, so are we\n isLegal && (isLegal = subtoken.isLegal); // If any of our kids are illegal, so are we\n if (subtoken.isDefiningFeature && subtoken.start < query.length) hasDefiningFeature = true;\n }\n\n /** See {@link Token.isDefiningFeature} */\n if (!hasDefiningFeature) return null;\n const end = query.skipIgnorable(subtokens[subtokens.length - 1].end);\n return new Token(idx, end, this, {\n subtokens\n }, {\n precedence: this.block.precedence,\n isTruncated,\n isLegal\n });\n }\n\n /**\n * Parse all the tokens from this.tokenProviders[tokenProviderIdx] then\n * recursively call this for the next token. Returns a list of tokens for\n * each combination of possible interpretations of the subtokens.\n *\n * Note that the tokens in the returned token arrays are in reverse to the\n * order of their providers in this.tokenProviders, just to confuse you :P\n *\n * @private\n * @param {QueryInfo} query\n * @param {number} idx\n * @param {TokenProvider[]} subtokenProviders\n * @param {number} depth\n * @param {number} tokenProviderIdx\n * @param {boolean} parseNextToken\n * @yields {Token[]}\n */\n _parseSubtokens(query, idx, subtokenProviders, depth) {\n var _this2 = this;\n let tokenProviderIdx = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;\n let parseNextToken = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true;\n return function* () {\n idx = query.skipIgnorable(idx);\n let tokenProvider = subtokenProviders[tokenProviderIdx];\n for (const token of tokenProvider.parseTokens(query, idx, depth + 1)) {\n ++query.tokenCount;\n if (!query.canCreateMoreTokens()) break;\n if (depth !== 0 && !query.canCreateMoreNestedBlocks()) break;\n if (_this2.block.precedence !== -1) {\n if (\n // If we care about the precedence of this block\n // Discard this token if its precedence is higher than ours, meaning it should be calculated\n // before us not afterward.\n token.precedence > _this2.block.precedence && (\n // See https://github.com/ScratchAddons/ScratchAddons/issues/5981\n tokenProviderIdx === 0 || !(token.type instanceof WorkspaceQuerier_TokenTypeBlock) || token.type.block.id !== \"operator_not\")) continue;\n /**\n * This check eliminates thousands of results by making sure blocks with equal precedence\n * can only contain themselves as their own first input. Without this, the query '1 + 2 + 3'\n * would have two interpretations '(1 + 2) + 3' and '1 + (2 + 3)'. This rule makes the second\n * of those invalid because the root '+' block contains itself as its third token.\n */\n if (token.precedence === _this2.block.precedence) {\n const inputIndex = _this2.block.parts[tokenProviderIdx].inputIdx;\n if (inputIndex !== 0) continue;\n }\n }\n if (!parseNextToken || !token.isLegal || tokenProviderIdx === subtokenProviders.length - 1) {\n yield [token];\n } else {\n for (const subTokenArr of _this2._parseSubtokens(query, token.end, subtokenProviders, depth, tokenProviderIdx + 1, !token.isTruncated)) {\n subTokenArr.push(token);\n yield subTokenArr;\n }\n }\n }\n }();\n }\n createBlockValue(token, query) {\n if (!token.isLegal) throw new Error(\"Cannot create a block from an illegal token.\");\n let blockInputs;\n if (token.value.stringForm) {\n blockInputs = token.value.stringForm.inputs;\n } else {\n const subtokens = token.value.subtokens;\n blockInputs = [];\n for (let i = 0; i < subtokens.length; i++) {\n const blockPart = this.block.parts[i];\n if (typeof blockPart !== \"string\") blockInputs.push(subtokens[i].createBlockValue(query));\n }\n while (blockInputs.length < this.block.inputs.length) blockInputs.push(null);\n }\n return this.block.createBlock(...blockInputs);\n }\n createText(token, query, endOnly) {\n if (token.value.stringForm) {\n if (endOnly) {\n if (token.value.lastPartIdx === -1 || token.end <= query.length) {\n return query.str.substring(token.start, token.end);\n } else {\n return query.str.substring(token.start, token.end) + token.value.stringForm.strings[token.value.lastPartIdx].substring(token.end - token.value.i) + \" \" + token.value.stringForm.strings.slice(token.value.lastPartIdx + 1).join(\" \");\n }\n }\n return token.value.stringForm.strings.join(\" \");\n }\n if (!token.isTruncated && endOnly) return query.str.substring(token.start, token.end);\n const subtokens = token.value.subtokens;\n let text = \"\";\n if (token.start !== subtokens[0].start) {\n text += query.str.substring(token.start, subtokens[0].start);\n }\n let i;\n for (i = 0; i < subtokens.length; i++) {\n var _subtoken$type$create;\n const subtoken = subtokens[i];\n if (!token.isLegal && subtoken.start >= query.length) break;\n const subtokenText = (_subtoken$type$create = subtoken.type.createText(subtoken, query, endOnly)) !== null && _subtoken$type$create !== void 0 ? _subtoken$type$create : \"\";\n text += subtokenText;\n if (i !== subtokens.length - 1) {\n const next = subtokens[i + 1];\n const nextStart = next.start;\n if (nextStart !== subtoken.end) {\n text += query.str.substring(subtoken.end, nextStart);\n } else {\n if ((!endOnly || nextStart >= query.length) && subtokenText.length !== 0 && QueryInfo.IGNORABLE_CHARS.indexOf(subtokenText.at(-1)) === -1) text += \" \";\n }\n }\n }\n return text;\n }\n getSubtokens(token, query) {\n return token.value.subtokens;\n }\n}\n\n/**\n * A single interpretation of a query.\n */\nclass WorkspaceQuerier_QueryResult {\n constructor(query, token) {\n /**\n * The query that this is a result of.\n * @type {QueryInfo}\n */\n this.query = query;\n /**\n * The root token of this result.\n *\n * The root token is a token which encapsules the entire query.\n * @type {Token}\n */\n this.token = token;\n }\n get isTruncated() {\n return this.token.isTruncated;\n }\n\n /**\n * @param {boolean} endOnly\n * @returns {string}\n */\n toText(endOnly) {\n var _this$token$type$crea;\n return (_this$token$type$crea = this.token.type.createText(this.token, this.query, endOnly)) !== null && _this$token$type$crea !== void 0 ? _this$token$type$crea : \"\";\n }\n\n /**\n * @returns {BlockInstance}\n */\n getBlock() {\n if (!this.block) this.block = this.token.createBlockValue(this.query);\n return this.block;\n }\n\n /**\n * @returns {{stringLength: number, tokenLength: number}}\n */\n getLengths() {\n if (this.lengths) return this.lengths;\n let stringLength = 0;\n let tokenLength = 0;\n\n /** @type {(block: BlockInstance) => void} */\n const getBlockLengths = block => {\n let inputIdx = 0;\n for (const part of block.typeInfo.parts) {\n ++tokenLength;\n if (typeof part === \"string\") {\n stringLength += part.length;\n } else {\n const input = block.inputs[inputIdx++];\n if (input instanceof BlockInstance) {\n getBlockLengths(input);\n } else if (part instanceof BlockInputEnum) {\n stringLength += input.string.length;\n } else if (part instanceof BlockInputString && input !== part.defaultValue) {\n // Make string inputs 100x their real length so they appear at the bottom\n stringLength += (\"\" + input).length * 100;\n } else if (input != null) {\n stringLength += (\"\" + input).length;\n }\n }\n }\n\n // Account for the spaces between inputs\n stringLength += block.typeInfo.parts.length - 1;\n };\n getBlockLengths(this.getBlock());\n return this.lengths = {\n stringLength,\n tokenLength\n };\n }\n}\n\n/**\n * Information on the current query being executed, with some utility\n * functions for helping out token providers.\n */\nclass QueryInfo {\n constructor(querier, query, id) {\n /** @type {WorkspaceQuerier} */\n this.querier = querier;\n /** @type {string} The query */\n this.str = query.replace(/\\u00a0/g, \" \");\n /** @type {string} A lowercase version of the query. Used for case insensitive comparisons. */\n this.lowercase = this.str.toLowerCase();\n /** @type {number} A unique identifier for this query */\n this.id = id;\n /** @type {number} The number of tokens we've found so far */\n this.tokenCount = 0;\n /** @type {number} The number of query results we've found so far */\n this.resultCount = 0;\n }\n\n /**\n * @param {string} str\n * @param {number} idx The index to start at.\n * @returns {number} The index of the next non-ignorable character in str, after idx.\n */\n static skipIgnorable(str, idx) {\n while (QueryInfo.IGNORABLE_CHARS.indexOf(str[idx]) !== -1) ++idx;\n return idx;\n }\n\n /**\n * @param {number} idx The index to start at.\n * @returns {number} The index of the next non-ignorable character in the query, after idx.\n */\n skipIgnorable(idx) {\n return QueryInfo.skipIgnorable(this.lowercase, idx);\n }\n\n /**\n * @param {string} str\n * @param {number} idx The index to start at.\n * @returns {number} The index of the next ignorable character in str, after idx.\n */\n static skipUnignorable(str, idx) {\n while (QueryInfo.IGNORABLE_CHARS.indexOf(str[idx]) === -1 && idx < str.length) ++idx;\n return idx;\n }\n\n /**\n * @param {number} idx The index to start at.\n * @returns {number} The index of the next ignorable character in the query, after idx.\n */\n skipUnignorable(idx) {\n return QueryInfo.skipUnignorable(this.lowercase, idx);\n }\n\n /** @type {number} The length in characters of the query. */\n get length() {\n return this.str.length;\n }\n canCreateMoreTokens() {\n return this.tokenCount < WorkspaceQuerier_WorkspaceQuerier.MAX_TOKENS;\n }\n canCreateMoreNestedBlocks() {\n return this.canCreateMoreTokens() && this.resultCount < WorkspaceQuerier_WorkspaceQuerier.MAX_RESULTS;\n }\n}\n\n/**\n * Workspace queriers keep track of all the data needed to query a given workspace (referred to as\n * the 'workspace index') and provides the methods to execute queries on the indexed workspace.\n */\n/** Characters that can be safely skipped over. */\nWorkspaceQuerier_defineProperty(QueryInfo, \"IGNORABLE_CHARS\", [\" \"]);\nclass WorkspaceQuerier_WorkspaceQuerier {\n /**\n * Indexes a workspace in preparation for querying it.\n * @param {BlockTypeInfo[]} blocks The list of blocks in the workspace.\n */\n indexWorkspace(blocks) {\n this._queryCounter = 0;\n this._createTokenGroups();\n this._populateTokenGroups(blocks);\n this.workspaceIndexed = true;\n }\n\n /**\n * Queries the indexed workspace for blocks matching the query string.\n * @param {string} queryStr The query.\n * @returns {{results: QueryResult[], illegalResult: QueryResult | null, limited: boolean}} A list of the results of the query, sorted by their relevance.\n */\n queryWorkspace(queryStr) {\n if (!this.workspaceIndexed) throw new Error(\"A workspace must be indexed before it can be queried!\");\n if (queryStr.trim().length === 0) return {\n results: [],\n illegalResult: null,\n limited: false\n };\n const query = new QueryInfo(this, queryStr, this._queryCounter++);\n const results = [];\n let foundTokenCount = 0;\n let limited = false;\n let bestIllegalResult = null;\n let bestIllegalResultText = \"\";\n for (const option of this.tokenGroupBlocks.parseTokens(query, 0, 0)) {\n if (option.end >= queryStr.length) {\n if (option.isLegal) {\n results.push(new WorkspaceQuerier_QueryResult(query, option));\n } else {\n const text = option.type.createText(option, query, true);\n if (!bestIllegalResult || text.length < text) {\n bestIllegalResult = new WorkspaceQuerier_QueryResult(query, option);\n bestIllegalResultText = text;\n }\n }\n }\n ++query.resultCount;\n if (!limited && query.resultCount >= WorkspaceQuerier_WorkspaceQuerier.MAX_RESULTS) {\n console.warn(\"Warning: Workspace query exceeded maximum result count.\");\n limited = true;\n }\n if (!query.canCreateMoreTokens()) {\n console.warn(\"Warning: Workspace query exceeded maximum token count.\");\n limited = true;\n break;\n }\n }\n\n // Used to eliminate blocks whos strings can be parsed as something else.\n // This step removes silly suggestions like `if <(1 + 1) = \"2 then\"> then`\n const canBeString = Array(queryStr.length).fill(true);\n function searchToken(token) {\n const subtokens = token.type.getSubtokens(token, query);\n if (subtokens) for (const subtoken of subtokens) searchToken(subtoken);else if (!(token.type instanceof TokenTypeStringLiteral) && token.isProper && !token.isTruncated) for (let i = token.start; i < token.end; i++) {\n canBeString[i] = false;\n }\n }\n for (const result of results) searchToken(result.token);\n function checkValidity(token) {\n const subtokens = token.type.getSubtokens(token, query);\n if (subtokens) {\n for (const subtoken of subtokens) if (!checkValidity(subtoken)) return false;\n } else if (token.type instanceof TokenTypeStringLiteral && !TokenTypeNumberLiteral.isValidNumber(token.value)) {\n for (let i = token.start; i < token.end; i++) if (!canBeString[i]) return false;\n }\n return true;\n }\n let validResults = [];\n for (const result of results) if (checkValidity(result.token)) validResults.push(result);\n validResults = validResults.sort((a, b) => {\n const aLengths = a.getLengths();\n const bLengths = b.getLengths();\n if (aLengths.stringLength != bLengths.stringLength) return aLengths.stringLength - bLengths.stringLength;\n return aLengths.tokenLength - bLengths.tokenLength;\n });\n return {\n results: validResults,\n illegalResult: validResults.length === 0 ? bestIllegalResult : null,\n limited\n };\n }\n\n /**\n * Creates the token group hierarchy used by this querier.\n *\n * Each of these token groups represents a list of all the tokens that could be encountered\n * when we're looking for a specific type of input. For example, tokenGroupString contains all\n * the tokens that could be encountered when we're looking for a string input (like after the\n * word 'say' for the `say ()` block). tokenGroupBlocks is an interesting one, it contains all\n * the tokens that could be the root token of a query result. In practice, this just means all\n * the stackable blocks (like 'say') and all the reporter blocks (like '+').\n *\n * But wait, there's a problem. Blocks like `() + ()` have two inputs, both of which are numbers.\n * The issue arises when you realize the block '+' itself also returns a number. So when we\n * try to call parseTokens on the '+' block, it will try to look for it's first parameter thus\n * calling parseTokens on tokenGroupNumber, which will call parseTokens on the '+' block again\n * (because + can return a number) which will call tokenGroupNumber again... and we're in an\n * infinite loop. We can't just exclude blocks from being their own first parameter because then\n * queries like '1 + 2 + 3' wouldn't work. The solution is something you might have only thought\n * of as a performance boost; caching. When tokenGroupNumber gets queried for the second time,\n * it's mid way though building its cache from the first query. If this happens, it just returns\n * all the tokens it had already found, but no more. So in the example above, when the + block calls\n * tokenGroupNumber for the second time it finds only the number literal '1'. It then finds the\n * second number literal '2' and yields the block '1 + 2' which gets added to tokenGroupNumber's\n * cache. '1 + 2' then gets disguarded by the queryWorkspace function because it doesn't cover the\n * whole query. But the '+' block's query to tokenGroupNumber never finished, so it will continue\n * and, because the first one we found is now a part of the cache, tokenGroupNumber will yield\n * '1 + 2' as a result. The + block will continue parsing, find the second '+' and the number '3'\n * and yield '(1 + 2) + 3'. No infinite loops!\n *\n * A consequence of this system is something I implicitly implied in the above paragraph \"when the\n * + block calls tokenGroupNumber for the second time it finds only the number literal '1'\" This\n * is only true if 'TokenTypeNumberLiteral' is searched before the '+' block. This is why the order\n * the token providers are in is critically important. I'll leave it as an exercise to the reader to\n * work out why, but the same parsing order problems crops up when implementing order of operations.\n * If a suggestion that should show up isn't showing up, it's probably because the token providers\n * in one of the groups is in the wrong order. Ordering the providers within the base groups is dealt\n * with by {@link _populateTokenGroups} and the inter-group ordering is dealt with below, by the\n * order they are passed into pushProviders.\n *\n * @private\n */\n _createTokenGroups() {\n this.tokenTypeStringLiteral = new TokenProviderSingleCache(new TokenTypeStringLiteral());\n this.tokenTypeNumberLiteral = new TokenProviderSingleCache(new TokenTypeNumberLiteral());\n this.tokenGroupRoundBlocks = new TokenProviderGroup(); // Round blocks like (() + ()) or (my variable)\n this.tokenGroupBooleanBlocks = new TokenProviderGroup(); // Boolean blocks like \n this.tokenGroupStackBlocks = new TokenProviderGroup(); // Stackable blocks like `move (10) steps`\n this.tokenGroupHatBlocks = new TokenProviderGroup(); // Hat block like `when green flag clicked`\n\n // Anything that fits into a boolean hole. (Boolean blocks + Brackets)\n this.tokenGroupBoolean = new TokenProviderOptional(new TokenProviderGroup());\n this.tokenGroupBoolean.inner.pushProviders([this.tokenGroupBooleanBlocks, new TokenTypeBrackets(this.tokenGroupBoolean)]);\n this.tokenGroupBoolean.inner.pushProviders([this.tokenGroupRoundBlocks], false);\n\n // Anything that fits into a number hole. (Round blocks + Boolean blocks + Number Literals + Brackets)\n this.tokenGroupNumber = new TokenProviderOptional(new TokenProviderGroup());\n this.tokenGroupNumber.inner.pushProviders([this.tokenTypeNumberLiteral, this.tokenGroupRoundBlocks, this.tokenGroupBooleanBlocks, new TokenTypeBrackets(this.tokenGroupNumber)]);\n\n // Anything that fits into a string hole (Round blocks + Boolean blocks + String Literals + Brackets)\n this.tokenGroupString = new TokenProviderOptional(new TokenProviderGroup());\n this.tokenGroupString.inner.pushProviders([this.tokenTypeStringLiteral, this.tokenGroupRoundBlocks, this.tokenGroupBooleanBlocks, new TokenTypeBrackets(this.tokenGroupString)]);\n\n // Anything that fits into a c shaped hole (Stackable blocks)\n this.tokenGroupStack = new TokenProviderOptional(this.tokenGroupStackBlocks);\n\n // Anything you can spawn using the menu (All blocks)\n this.tokenGroupBlocks = new TokenProviderGroup();\n this.tokenGroupBlocks.pushProviders([this.tokenGroupStackBlocks, this.tokenGroupBooleanBlocks, this.tokenGroupRoundBlocks, this.tokenGroupHatBlocks]);\n }\n\n /**\n * Populates the token groups created by {@link _createTokenGroups} with the blocks\n * found in the workspace.\n * @param {BlockTypeInfo[]} blocks The list of blocks in the workspace.\n * @private\n */\n _populateTokenGroups(blocks) {\n // Apply order of operations\n for (const block of blocks) {\n block.precedence = WorkspaceQuerier_WorkspaceQuerier.ORDER_OF_OPERATIONS.indexOf(block.id);\n }\n for (let i = blocks.length - 1; i >= 0; i--) {\n const block = blocks[i];\n if (block.precedence !== -1) {\n const target = blocks.length - (WorkspaceQuerier_WorkspaceQuerier.ORDER_OF_OPERATIONS.length - (block.precedence - 1));\n if (i !== target) {\n const oldBlock = blocks[target];\n blocks[target] = block;\n blocks[i] = oldBlock;\n }\n }\n }\n for (const block of blocks) {\n const blockTokenType = new WorkspaceQuerier_TokenTypeBlock(this, block);\n switch (block.shape) {\n case BlockShape.Round:\n this.tokenGroupRoundBlocks.pushProviders([blockTokenType]);\n break;\n case BlockShape.Boolean:\n this.tokenGroupBooleanBlocks.pushProviders([blockTokenType]);\n break;\n case BlockShape.Stack:\n case BlockShape.End:\n this.tokenGroupStackBlocks.pushProviders([blockTokenType]);\n break;\n case BlockShape.Hat:\n this.tokenGroupHatBlocks.pushProviders([blockTokenType]);\n break;\n }\n }\n }\n\n /**\n * Clears the memory used by the workspace index.\n */\n clearWorkspaceIndex() {\n this.workspaceIndexed = false;\n this._destroyTokenGroups();\n }\n\n /**\n * @private\n */\n _destroyTokenGroups() {\n this.tokenTypeStringLiteral = null;\n this.tokenTypeNumberLiteral = null;\n this.tokenGroupBooleanBlocks = null;\n this.tokenGroupRoundBlocks = null;\n this.tokenGroupStackBlocks = null;\n this.tokenGroupHatBlocks = null;\n this.tokenGroupBoolean = null;\n this.tokenGroupNumber = null;\n this.tokenGroupString = null;\n this.tokenGroupStack = null;\n this.tokenGroupBlocks = null;\n }\n}\nWorkspaceQuerier_defineProperty(WorkspaceQuerier_WorkspaceQuerier, \"ORDER_OF_OPERATIONS\", [null,\n// brackets\n\"operator_join\", \"operator_round\", \"operator_mathop\", \"operator_mod\", \"operator_divide\", \"operator_multiply\", \"operator_subtract\", \"operator_add\", \"operator_equals\", \"operator_lt\", \"operator_gt\", \"operator_or\", \"operator_and\", \"operator_not\"]);\n/**\n * The maximum number of results to find before we give up searching sub-blocks.\n */\nWorkspaceQuerier_defineProperty(WorkspaceQuerier_WorkspaceQuerier, \"MAX_RESULTS\", 2000);\n/**\n * The maximum number of tokens to find before giving up.\n */\nWorkspaceQuerier_defineProperty(WorkspaceQuerier_WorkspaceQuerier, \"MAX_TOKENS\", 100000);\n/**\n * The maximum number of string forms a block can have before we give up.\n */\nWorkspaceQuerier_defineProperty(WorkspaceQuerier_WorkspaceQuerier, \"MAX_STRING_FORMS\", 500);\n// EXTERNAL MODULE: ./src/addons/addons/middle-click-popup/module.js\nvar middle_click_popup_module = __webpack_require__(1383);\n\n// CONCATENATED MODULE: ./src/addons/addons/middle-click-popup/BlockRenderer.js\n/**\n * @file Contains the code for rendering the blocks in the middle click dropdown.\n * Main function is {@link renderBlock} which takes in a block and returns a renderer SVG element.\n * @author Tacodiva\n */\n\n\n\nconst SVG_NS = \"http://www.w3.org/2000/svg\";\nconst BlockShapes = {\n // eg (my variable)\n Round: {\n padding: 12,\n minWidth: 20,\n backgroundPath: width => \"m -12 -20 m 20 0 h \".concat(width - 16, \" a 20 20 0 0 1 0 40 H 8 a 20 20 0 0 1 0 -40 z\"),\n /**\n * 'Snuggling' is my wholesome term for when a block can sit extra close to a block\n * of the same shape as it. Take a look at the blocks ( ( \"\" + \"\" ) - \"\" ) and\n * ( < \"\" = \"\" > - \"\" ), observe how there's a lot more blank space in the outer\n * block in the second example, this is because in the first example the '+' block\n * can snuggle with the '-' block.\n */\n snugglePadding: 0,\n get snuggleWith() {\n // Don't feel bad BlockShapes.Round, I only snuggle with myself too :_(\n return [BlockShapes.Round];\n }\n },\n // eg <() = ()>\n Boolean: {\n padding: 20,\n minWidth: 20,\n backgroundPath: width => \"m -20 -20 m 20 0 h \".concat(width, \" l 20 20 l -20 20 H 0 l -20 -20 l 20 -20 z\"),\n snugglePadding: 0,\n get snuggleWith() {\n return [BlockShapes.Boolean];\n }\n },\n // Square dropdowns like variables\n SquareInput: {\n padding: 8,\n minWidth: 20,\n backgroundPath: width => \"m -2 -16 h \".concat(width + 4, \" a 4 4 0 0 1 4 4 V 12 a 4 4 0 0 1 -4 4 H -2 a 4 4 0 0 1 -4 -4 V -12 a 4 4 0 0 1 4 -4\")\n },\n // eg show\n Stack: {\n padding: 8,\n minWidth: 60,\n backgroundPath: width => \"m -8 -20 A 4 4 0 0 1 -4 -24 H 4 c 2 0 3 1 4 2 l 4 4 c 1 1 2 2 4 2 h 12 c 2 0 3 -1 4 -2 l 4 -4 C 37 -23 38 -24 40 -24 H \".concat(width, \" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H 40 c -2 0 -3 1 -4 2 l -4 4 c -1 1 -2 2 -4 2 h -12 c -2 0 -3 -1 -4 -2 l -4 -4 c -1 -1 -2 -2 -4 -2 H -4 a 4 4 0 0 1 -4 -4 z\")\n },\n // eg when I start as a clone\n Hat: {\n padding: 8,\n minWidth: 60,\n backgroundPath: width => \"m -8 -20 A 4 4 0 0 1 -4 -24 H \".concat(width, \" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H 40 c -2 0 -3 1 -4 2 l -4 4 c -1 1 -2 2 -4 2 h -12 c -2 0 -3 -1 -4 -2 l -4 -4 c -1 -1 -2 -2 -4 -2 H -4 a 4 4 0 0 1 -4 -4 z\")\n },\n // eg delete this clone\n End: {\n padding: 8,\n minWidth: 60,\n backgroundPath: width => \"m -8 -20 A 4 4 0 0 1 -4 -24 H 4 c 2 0 3 1 4 2 l 4 4 c 1 1 2 2 4 2 h 12 c 2 0 3 -1 4 -2 l 4 -4 C 37 -23 38 -24 40 -24 H \".concat(width, \" a 4 4 0 0 1 4 4 v 40 a 4 4 0 0 1 -4 4 H -4 a 4 4 0 0 1 -4 -4 z\")\n },\n // The white oval for text or number inputs\n TextInput: {\n padding: 12,\n minWidth: 16,\n backgroundPath: width => \"m -12 -16 m 16 0 h \".concat(width - 8, \" a 16 16 0 0 1 0 32 H 4 a 16 16 0 0 1 0 -32 z\"),\n snugglePadding: 4,\n get snuggleWith() {\n return [BlockShapes.Round];\n }\n },\n BooleanInput: {\n padding: 16,\n minWidth: 16,\n backgroundPath: width => \"m 0 -16 h \".concat(width, \" l 16 16 l -16 16 h -16 l -16 -16 l 16 -16 z\"),\n snugglePadding: 6,\n get snuggleWith() {\n return [BlockShapes.Boolean];\n }\n },\n HorizontalBlock: {\n padding: 16,\n minWidth: 45,\n backgroundPath: width => \"M -4 -20 a 4 4 0 0 1 4 -4 H \".concat(width + 8, \" a 4 4 0 0 1 4 4 v 2 c 0 2 -1 3 -2 4 l -4 4 c -1 1 -2 2 -2 4 v 12 c 0 2 1 3 2 4 l 4 4 c 1 1 2 2 2 4 v 2 a 4 4 0 0 1 -4 4 H 0 a 4 4 0 0 1 -4 -4 v -2 c 0 -2 -1 -3 -2 -4 l -4 -4 c -1 -1 -2 -2 -2 -4 v -12 c 0 -2 1 -3 2 -4 l 4 -4 c 1 -1 2 -2 2 -4 z\")\n },\n HorizontalBlockEnd: {\n padding: 16,\n minWidth: 45,\n backgroundPath: width => \"M -4 -20 a 4 4 0 0 1 4 -4 H \".concat(width + 8, \" a 4 4 0 0 1 4 4 V 20 a 4 4 0 0 1 -4 4 H 0 a 4 4 0 0 1 -4 -4 v -2 c 0 -2 -1 -3 -2 -4 l -4 -4 c -1 -1 -2 -2 -2 -4 v -12 c 0 -2 1 -3 2 -4 l 4 -4 c 1 -1 2 -2 2 -4 z\")\n }\n};\n\n/**\n * Gets the block shape info from {@link BlockShapes} given a {@link BlockShape}.\n * @param {BlockShape} shape\n */\nfunction getShapeInfo(shape, isVertical) {\n if (shape === BlockShape.Round) return BlockShapes.Round;\n if (shape === BlockShape.Boolean) return BlockShapes.Boolean;\n if (shape === BlockShape.Stack) return isVertical ? BlockShapes.Stack : BlockShapes.HorizontalBlock;\n if (shape === BlockShape.Hat) return BlockShapes.Hat;\n if (shape === BlockShape.End) return isVertical ? BlockShapes.End : BlockShapes.HorizontalBlockEnd;\n throw new Error(shape);\n}\n\n/**\n * @param {BlockInstance} block\n * @returns {number}\n */\nfunction getBlockHeight(block) {\n switch (block.typeInfo.shape) {\n case BlockShape.End:\n case BlockShape.Hat:\n case BlockShape.Stack:\n return 62;\n case BlockShape.Boolean:\n case BlockShape.Round:\n return 48;\n }\n return 0;\n}\nconst BLOCK_ELEMENT_SPACING = 8;\n\n/**\n * A part of a block. Think of these like the different parts in the 'make a block' menu.\n */\nclass BlockComponent {\n constructor(element, padding, width, snuggleWith, snugglePadding) {\n this.dom = element;\n this.padding = padding;\n this.width = width;\n this.snuggleWith = snuggleWith;\n this.snugglePadding = snugglePadding;\n }\n}\n\n/**\n * Creates a BlockComponent with some text. Like the 'label' element in the make a block menu.\n * @param {string} text The contents of the component.\n * @param {SVGElement} container The element to add the text to.\n * @returns {BlockComponent} The BlockComponent.\n */\nfunction createTextComponent(text, fillVar, container) {\n let textElement = container.appendChild(document.createElementNS(SVG_NS, \"text\"));\n textElement.setAttribute(\"class\", \"blocklyText\");\n textElement.style.fill = \"var(\".concat(fillVar, \")\");\n textElement.setAttribute(\"dominant-baseline\", \"middle\");\n textElement.setAttribute(\"dy\", 1);\n textElement.appendChild(document.createTextNode(text));\n return new BlockComponent(textElement, 0, Object(middle_click_popup_module[\"b\" /* getTextWidth */])(textElement));\n}\n\n/**\n * Creates a DOM element to hold all the contents of a block.\n * A block could be the top level block, or it could be a block like (() + ()) that's inside\n * another block.\n * @returns {SVGElement} The SVGElement which will contain all the block's components.\n */\nfunction createBlockContainer() {\n let container = document.createElementNS(SVG_NS, \"g\");\n let background = document.createElementNS(SVG_NS, \"path\");\n background.setAttribute(\"class\", \"blocklyPath\");\n container.appendChild(background);\n return container;\n}\n\n/**\n * Creates a block component from a container containing all its components.\n * @param {SVGElement} container The block container, created by {@link createBlockContainer}.\n * @param {object} shape An object containing information of the shape of the block to be created. From the {@link BlockShapes} object.\n * @param {string|null} categoryClass The category of the block, used for filling the background.\n * @param {string} fill\n * @param {string} stroke\n * @param {number} width The width of the background of the block.\n */\nfunction createBlockComponent(container, shape, categoryClass, fill, stroke, width) {\n if (width < shape.minWidth) width = shape.minWidth;\n container.classList.add(\"sa-block-color\");\n if (categoryClass) {\n container.classList.add(categoryClass);\n }\n const background = container.children[0];\n let style = \"\";\n if (fill) style += \"fill: var(\".concat(fill, \");\");\n if (stroke) style += \"stroke: var(\".concat(stroke, \");\");\n background.setAttribute(\"style\", style);\n background.setAttribute(\"d\", shape.backgroundPath(width));\n return new BlockComponent(container, shape.padding, width + shape.padding * 2, shape.snuggleWith, shape.snugglePadding);\n}\nfunction createBackedTextedComponent(text, container, shape, categoryClass, fill, stroke, textVar) {\n const blockContainer = createBlockContainer();\n container.appendChild(blockContainer);\n const textElement = createTextComponent(text, textVar, blockContainer);\n if (textElement.width < shape.minWidth) {\n textElement.dom.setAttribute(\"x\", (shape.minWidth - textElement.width) / 2);\n }\n const blockElement = createBlockComponent(blockContainer, shape, categoryClass, fill, stroke, textElement.width);\n return blockElement;\n}\n\n/**\n * Renders a block, with the center of it's leftmost side located at 0, 0.\n * @param {BlockInstance} block\n * @param {SVGElement} container\n * @returns {BlockComponent} The rendered block\n */\nfunction renderBlock(block, container) {\n var blockComponent = _renderBlock(block, container, block.typeInfo.category, true);\n blockComponent.dom.classList.add(\"sa-block-color\");\n blockComponent.dom.setAttribute(\"transform\", \"translate(\".concat(blockComponent.padding, \", 0)\"));\n return blockComponent;\n}\n\n/**\n * Renders a block, with the center of it's leftmost side located at 0, 0.\n * @param {BlockInstance} block\n * @param {SVGAElement} container\n * @param {string} parentCategory The category of this blocks parent. If no parent, than this blocks category.\n * @returns {BlockComponent} The rendered component.\n */\nfunction _renderBlock(block, container, parentCategory, isVertical) {\n const blockContainer = container.appendChild(createBlockContainer());\n const shape = getShapeInfo(block.typeInfo.shape, isVertical);\n const category = block.typeInfo.category;\n const COLOR_CLASSES = [\"motion\", \"looks\", \"sounds\", \"events\", \"control\", \"sensing\", \"operators\", \"data\", \"data-lists\", \"list\", \"more\", \"pen\", \"addon-custom-block\"];\n const categoryClass = COLOR_CLASSES.includes(category.name) ? \"sa-block-color-\" + category.name : null;\n let xOffset = 0;\n let inputIdx = 0;\n for (let partIdx = 0; partIdx < block.typeInfo.parts.length; partIdx++) {\n const blockPart = block.typeInfo.parts[partIdx];\n let component;\n if (typeof blockPart === \"string\") {\n component = createTextComponent(blockPart, \"--sa-block-text\", blockContainer);\n } else {\n const blockInput = block.inputs[inputIdx++];\n if (blockInput instanceof BlockInstance) {\n component = _renderBlock(blockInput, blockContainer, block.typeInfo.category, false);\n } else if (blockPart instanceof BlockInputEnum) {\n if (blockPart.isRound) {\n component = createBackedTextedComponent(blockInput.string, blockContainer, BlockShapes.TextInput, categoryClass, \"--sa-block-background-secondary, \".concat(category.colorSecondary), \"--sa-block-background-tertiary, \".concat(category.colorTertiary), \"--sa-block-text\");\n } else {\n component = createBackedTextedComponent(blockInput.string, blockContainer, BlockShapes.SquareInput, categoryClass, \"--sa-block-background-primary, \".concat(category.colorPrimary), \"--sa-block-background-tertiary, \".concat(category.colorTertiary), \"--sa-block-text\");\n }\n } else if (blockPart instanceof BlockInputBoolean) {\n component = createBackedTextedComponent(\"\", blockContainer, BlockShapes.BooleanInput, categoryClass, \"--sa-block-field-background, \".concat(category.colorTertiary), \"--sa-block-field-background, \".concat(category.colorTertiary), \"--sa-block-text\");\n } else if (blockPart instanceof BlockInputBlock) {\n component = createBackedTextedComponent(\"\", blockContainer, BlockShapes.HorizontalBlock, categoryClass, \"--sa-block-field-background, \".concat(category.colorTertiary), \"--sa-block-field-background, \".concat(category.colorTertiary), \"--sa-block-text\");\n } else {\n var _ref, _blockInput$toString;\n component = createBackedTextedComponent((_ref = (_blockInput$toString = blockInput === null || blockInput === void 0 ? void 0 : blockInput.toString()) !== null && _blockInput$toString !== void 0 ? _blockInput$toString : blockPart.defaultValue) !== null && _ref !== void 0 ? _ref : \"\", blockContainer, BlockShapes.TextInput, categoryClass, \"--sa-block-input-color, \".concat(category.colorColor), \"--sa-block-background-tertiary, \".concat(category.colorTertiary), \"--sa-block-input-text\");\n component.dom.classList.add(\"blocklyNonEditableText\");\n }\n }\n let xTranslation = xOffset + component.padding;\n if (partIdx === 0 || partIdx === block.typeInfo.parts.length - 1) {\n if (component.snuggleWith && component.snuggleWith.indexOf(shape) !== -1) {\n const positionDelta = component.snugglePadding - component.padding;\n component.width += positionDelta;\n if (partIdx === 0) {\n xTranslation += positionDelta;\n }\n }\n }\n component.dom.setAttribute(\"transform\", \"translate(\".concat(xTranslation, \", 0)\"));\n xOffset += BLOCK_ELEMENT_SPACING + component.width;\n }\n return createBlockComponent(blockContainer, shape, categoryClass, \"--sa-block-background-primary, \".concat(category.colorPrimary), \"--sa-block-background-tertiary, \".concat(category.colorTertiary), xOffset - BLOCK_ELEMENT_SPACING);\n}\n// CONCATENATED MODULE: ./src/addons/addons/middle-click-popup/userscript.js\n//@ts-check\n\n\n\n\n\n/* harmony default export */ var userscript = (async function (_ref) {\n let {\n addon,\n msg,\n console\n } = _ref;\n const Blockly = await addon.tab.traps.getBlockly();\n const vm = addon.tab.traps.vm;\n const PREVIEW_LIMIT = 50;\n const popupRoot = document.body.appendChild(document.createElement(\"div\"));\n popupRoot.classList.add(\"sa-mcp-root\");\n popupRoot.dir = addon.tab.direction;\n popupRoot.style.display = \"none\";\n const popupContainer = popupRoot.appendChild(document.createElement(\"div\"));\n popupContainer.classList.add(\"sa-mcp-container\");\n const popupInputContainer = popupContainer.appendChild(document.createElement(\"div\"));\n popupInputContainer.classList.add(addon.tab.scratchClass(\"input_input-form\"));\n popupInputContainer.classList.add(\"sa-mcp-input-wrapper\");\n const popupInputSuggestion = popupInputContainer.appendChild(document.createElement(\"input\"));\n popupInputSuggestion.classList.add(\"sa-mcp-input-suggestion\");\n const popupInput = popupInputContainer.appendChild(document.createElement(\"input\"));\n popupInput.classList.add(\"sa-mcp-input\");\n popupInput.setAttribute(\"autocomplete\", \"off\");\n const popupPreviewContainer = popupContainer.appendChild(document.createElement(\"div\"));\n popupPreviewContainer.classList.add(\"sa-mcp-preview-container\");\n const popupPreviewScrollbarSVG = popupContainer.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\"));\n popupPreviewScrollbarSVG.classList.add(\"sa-mcp-preview-scrollbar\", \"blocklyScrollbarVertical\", \"blocklyMainWorkspaceScrollbar\");\n popupPreviewScrollbarSVG.style.display = \"none\";\n const popupPreviewScrollbarBackground = popupPreviewScrollbarSVG.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"rect\"));\n popupPreviewScrollbarBackground.setAttribute(\"width\", \"11\");\n popupPreviewScrollbarBackground.classList.add(\"blocklyScrollbarBackground\");\n const popupPreviewScrollbarHandle = popupPreviewScrollbarSVG.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"rect\"));\n popupPreviewScrollbarHandle.setAttribute(\"rx\", \"3\");\n popupPreviewScrollbarHandle.setAttribute(\"ry\", \"3\");\n popupPreviewScrollbarHandle.setAttribute(\"width\", \"6\");\n popupPreviewScrollbarHandle.setAttribute(\"x\", \"2.5\");\n popupPreviewScrollbarHandle.classList.add(\"blocklyScrollbarHandle\");\n const popupPreviewBlocks = popupPreviewContainer.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\"));\n popupPreviewBlocks.classList.add(\"sa-mcp-preview-blocks\");\n const querier = new WorkspaceQuerier_WorkspaceQuerier();\n let mousePosition = {\n x: 0,\n y: 0\n };\n document.addEventListener(\"mousemove\", e => {\n mousePosition = {\n x: e.clientX,\n y: e.clientY\n };\n });\n document.addEventListener(\"mousedown\", e => {\n mousePosition = {\n x: e.clientX,\n y: e.clientY\n };\n }, {\n capture: true\n });\n Object(middle_click_popup_module[\"c\" /* onClearTextWidthCache */])(closePopup);\n\n /**\n * @typedef ResultPreview\n * @property {BlockInstance} block\n * @property {((endOnly: boolean) => string)?} autocompleteFactory\n * @property {BlockComponent} renderedBlock\n * @property {SVGGElement} svgBlock\n * @property {SVGRectElement} svgBackground\n */\n /** @type {ResultPreview[]} */\n let queryPreviews = [];\n /** @type {QueryResult | null} */\n let queryIllegalResult = null;\n let selectedPreviewIdx = 0;\n /** @type {BlockTypeInfo[]?} */\n let blockTypes = null;\n let limited = false;\n let allowMenuClose = true;\n let popupPosition = null;\n let popupOrigin = null;\n let previewWidth = 0;\n let previewHeight = 0;\n let previewScale = 0;\n let previewMinHeight = 0;\n let previewMaxHeight = 0;\n function openPopup() {\n if (addon.self.disabled) return;\n\n // Don't show the menu if we're not in the code editor\n if (addon.tab.editorMode !== \"editor\") return;\n if (addon.tab.redux.state.scratchGui.editorTab.activeTabIndex !== 0) return;\n blockTypes = BlockTypeInfo.getBlocks(Blockly, vm, Blockly.getMainWorkspace(), msg);\n querier.indexWorkspace([...blockTypes]);\n blockTypes.sort((a, b) => {\n const prio = block => [\"operators\", \"data\"].indexOf(block.category.name) - block.id.startsWith(\"data_\");\n return prio(b) - prio(a);\n });\n previewScale = window.innerWidth * 0.00005 + addon.settings.get(\"popup_scale\") / 100;\n previewWidth = window.innerWidth * addon.settings.get(\"popup_width\") / 100;\n previewMaxHeight = window.innerHeight * addon.settings.get(\"popup_max_height\") / 100;\n popupContainer.style.width = previewWidth + \"px\";\n popupOrigin = {\n x: mousePosition.x,\n y: mousePosition.y\n };\n popupRoot.style.display = \"\";\n popupInput.value = \"\";\n popupInput.focus();\n updateInput();\n }\n function closePopup() {\n if (allowMenuClose) {\n popupOrigin = null;\n popupPosition = null;\n popupRoot.style.display = \"none\";\n blockTypes = null;\n querier.clearWorkspaceIndex();\n }\n }\n popupInput.addEventListener(\"input\", updateInput);\n function updateInput() {\n /**\n * @typedef MenuItem\n * @property {BlockInstance} block\n * @property {(endOnly: boolean) => string} [autocompleteFactory]\n */\n /** @type {MenuItem[]} */\n const blockList = [];\n if (popupInput.value.trim().length === 0) {\n queryIllegalResult = null;\n if (blockTypes) for (const blockType of blockTypes) {\n blockList.push({\n block: blockType.createBlock()\n });\n }\n limited = false;\n } else {\n // Get the list of blocks to display using the input content\n const queryResultObj = querier.queryWorkspace(popupInput.value);\n const queryResults = queryResultObj.results;\n queryIllegalResult = queryResultObj.illegalResult;\n limited = queryResultObj.limited;\n if (queryResults.length > PREVIEW_LIMIT) queryResults.length = PREVIEW_LIMIT;\n for (const queryResult of queryResults) {\n blockList.push({\n block: queryResult.getBlock(),\n autocompleteFactory: endOnly => queryResult.toText(endOnly)\n });\n }\n }\n\n // @ts-ignore Delete the old previews\n while (popupPreviewBlocks.firstChild) popupPreviewBlocks.removeChild(popupPreviewBlocks.lastChild);\n\n // Create the new previews\n queryPreviews.length = 0;\n let y = 0;\n for (let resultIdx = 0; resultIdx < blockList.length; resultIdx++) {\n var _result$autocompleteF;\n const result = blockList[resultIdx];\n const mouseMoveListener = () => {\n updateSelection(resultIdx);\n };\n const mouseDownListener = e => {\n e.stopPropagation();\n e.preventDefault();\n updateSelection(resultIdx);\n allowMenuClose = !e.shiftKey;\n selectBlock();\n allowMenuClose = true;\n if (e.shiftKey) popupInput.focus();\n };\n const svgBackground = popupPreviewBlocks.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"rect\"));\n const height = getBlockHeight(result.block);\n svgBackground.setAttribute(\"transform\", \"translate(0, \".concat((y + height / 10) * previewScale, \")\"));\n svgBackground.setAttribute(\"height\", height * previewScale + \"px\");\n svgBackground.classList.add(\"sa-mcp-preview-block-bg\");\n svgBackground.addEventListener(\"mousemove\", mouseMoveListener);\n svgBackground.addEventListener(\"mousedown\", mouseDownListener);\n const svgBlock = popupPreviewBlocks.appendChild(document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\"));\n svgBlock.addEventListener(\"mousemove\", mouseMoveListener);\n svgBlock.addEventListener(\"mousedown\", mouseDownListener);\n svgBlock.classList.add(\"sa-mcp-preview-block\");\n const renderedBlock = renderBlock(result.block, svgBlock);\n queryPreviews.push({\n block: result.block,\n autocompleteFactory: (_result$autocompleteF = result.autocompleteFactory) !== null && _result$autocompleteF !== void 0 ? _result$autocompleteF : null,\n renderedBlock,\n svgBlock,\n svgBackground\n });\n y += height;\n }\n const height = (y + 8) * previewScale;\n if (height < previewMinHeight) previewHeight = previewMinHeight;else if (height > previewMaxHeight) previewHeight = previewMaxHeight;else previewHeight = height;\n popupPreviewBlocks.setAttribute(\"height\", \"\".concat(height, \"px\"));\n popupPreviewContainer.style.height = previewHeight + \"px\";\n popupPreviewScrollbarSVG.style.height = previewHeight + \"px\";\n popupPreviewScrollbarBackground.setAttribute(\"height\", \"\" + previewHeight);\n popupInputContainer.dataset[\"error\"] = \"\" + limited;\n popupPosition = {\n x: popupOrigin.x + 16,\n y: popupOrigin.y - 8\n };\n const popupHeight = popupContainer.getBoundingClientRect().height;\n const popupBottom = popupPosition.y + popupHeight;\n if (popupBottom > window.innerHeight) {\n popupPosition.y -= popupBottom - window.innerHeight;\n }\n popupRoot.style.top = popupPosition.y + \"px\";\n popupRoot.style.left = popupPosition.x + \"px\";\n selectedPreviewIdx = -1;\n updateSelection(0);\n updateCursor();\n updateScrollbar();\n }\n function updateSelection(newIdx) {\n if (selectedPreviewIdx === newIdx) return;\n const oldSelection = queryPreviews[selectedPreviewIdx];\n if (oldSelection) {\n oldSelection.svgBackground.classList.remove(\"sa-mcp-preview-block-bg-selection\");\n oldSelection.svgBlock.classList.remove(\"sa-mcp-preview-block-selection\");\n }\n if (queryPreviews.length === 0 && queryIllegalResult) {\n popupInputSuggestion.value = popupInput.value + queryIllegalResult.toText(true).substring(popupInput.value.length);\n return;\n }\n const newSelection = queryPreviews[newIdx];\n if (newSelection && newSelection.autocompleteFactory) {\n newSelection.svgBackground.classList.add(\"sa-mcp-preview-block-bg-selection\");\n newSelection.svgBlock.classList.add(\"sa-mcp-preview-block-selection\");\n newSelection.svgBackground.scrollIntoView({\n block: \"nearest\",\n behavior: Math.abs(newIdx - selectedPreviewIdx) > 1 ? \"smooth\" : \"auto\"\n });\n popupInputSuggestion.value = popupInput.value + newSelection.autocompleteFactory(true).substring(popupInput.value.length);\n } else {\n popupInputSuggestion.value = \"\";\n }\n selectedPreviewIdx = newIdx;\n }\n\n // @ts-ignore\n document.addEventListener(\"selectionchange\", updateCursor);\n function updateCursor() {\n var _popupInput$selection;\n const cursorPos = (_popupInput$selection = popupInput.selectionStart) !== null && _popupInput$selection !== void 0 ? _popupInput$selection : 0;\n const cursorPosRel = popupInput.value.length === 0 ? 0 : cursorPos / popupInput.value.length;\n let y = 0;\n for (let previewIdx = 0; previewIdx < queryPreviews.length; previewIdx++) {\n const preview = queryPreviews[previewIdx];\n var blockX = 5;\n if (blockX + preview.renderedBlock.width > previewWidth / previewScale) blockX += (previewWidth / previewScale - blockX - preview.renderedBlock.width) * previewScale * cursorPosRel;\n var blockY = (y + 30) * previewScale;\n preview.svgBlock.setAttribute(\"transform\", \"translate(\".concat(blockX, \", \").concat(blockY, \") scale(\").concat(previewScale, \")\"));\n y += getBlockHeight(preview.block);\n }\n popupInputSuggestion.scrollLeft = popupInput.scrollLeft;\n }\n popupPreviewContainer.addEventListener(\"scroll\", updateScrollbar);\n function updateScrollbar() {\n const scrollTop = popupPreviewContainer.scrollTop;\n const scrollY = popupPreviewContainer.scrollHeight;\n if (scrollY <= previewHeight) {\n popupPreviewScrollbarSVG.style.display = \"none\";\n return;\n }\n const scrollbarHeight = previewHeight / scrollY * previewHeight;\n const scrollbarY = scrollTop / scrollY * previewHeight;\n popupPreviewScrollbarSVG.style.display = \"\";\n popupPreviewScrollbarHandle.setAttribute(\"height\", \"\" + scrollbarHeight);\n popupPreviewScrollbarHandle.setAttribute(\"y\", \"\" + scrollbarY);\n }\n function selectBlock() {\n const selectedPreview = queryPreviews[selectedPreviewIdx];\n if (!selectedPreview) return;\n const workspace = Blockly.getMainWorkspace();\n // This is mostly copied from https://github.com/scratchfoundation/scratch-blocks/blob/893c7e7ad5bfb416eaed75d9a1c93bdce84e36ab/core/scratch_blocks_utils.js#L171\n // Some bits were removed or changed to fit our needs.\n workspace.setResizesEnabled(false);\n let newBlock;\n Blockly.Events.disable();\n try {\n newBlock = selectedPreview.block.createWorkspaceForm();\n Blockly.scratchBlocksUtils.changeObscuredShadowIds(newBlock);\n var svgRootNew = newBlock.getSvgRoot();\n if (!svgRootNew) {\n throw new Error(\"newBlock is not rendered.\");\n }\n let blockBounds = newBlock.svgPath_.getBoundingClientRect();\n let newBlockX = Math.floor((mousePosition.x - (blockBounds.left + blockBounds.right) / 2) / workspace.scale);\n let newBlockY = Math.floor((mousePosition.y - (blockBounds.top + blockBounds.bottom) / 2) / workspace.scale);\n newBlock.moveBy(newBlockX, newBlockY);\n } finally {\n Blockly.Events.enable();\n }\n if (Blockly.Events.isEnabled()) {\n Blockly.Events.fire(new Blockly.Events.BlockCreate(newBlock));\n }\n let fakeEvent = {\n clientX: mousePosition.x,\n clientY: mousePosition.y,\n type: \"mousedown\",\n stopPropagation: function stopPropagation() {},\n preventDefault: function preventDefault() {},\n target: selectedPreview.svgBlock\n };\n if (workspace.getGesture(fakeEvent)) {\n workspace.startDragWithFakeEvent(fakeEvent, newBlock);\n }\n }\n function acceptAutocomplete() {\n let factory;\n if (queryPreviews[selectedPreviewIdx]) factory = queryPreviews[selectedPreviewIdx].autocompleteFactory;else factory = () => popupInputSuggestion.value;\n if (popupInputSuggestion.value.length === 0 || !factory) return;\n popupInput.value = factory(false);\n // Move cursor to the end of the newly inserted text\n popupInput.selectionStart = popupInput.value.length + 1;\n updateInput();\n }\n popupInput.addEventListener(\"keydown\", e => {\n switch (e.key) {\n case \"Escape\":\n // If there's something in the input, clear it\n if (popupInput.value.length > 0) {\n popupInput.value = \"\";\n updateInput();\n } else {\n // If not, close the menu\n closePopup();\n }\n e.stopPropagation();\n e.preventDefault();\n break;\n case \"Tab\":\n acceptAutocomplete();\n e.stopPropagation();\n e.preventDefault();\n break;\n case \"Enter\":\n selectBlock();\n closePopup();\n e.stopPropagation();\n e.preventDefault();\n break;\n case \"ArrowDown\":\n if (selectedPreviewIdx + 1 >= queryPreviews.length) updateSelection(0);else updateSelection(selectedPreviewIdx + 1);\n e.stopPropagation();\n e.preventDefault();\n break;\n case \"ArrowUp\":\n if (selectedPreviewIdx - 1 < 0) updateSelection(queryPreviews.length - 1);else updateSelection(selectedPreviewIdx - 1);\n e.stopPropagation();\n e.preventDefault();\n break;\n }\n });\n popupInput.addEventListener(\"focusout\", closePopup);\n\n // Open on ctrl + space\n document.addEventListener(\"keydown\", e => {\n if (e.key === \" \" && (e.ctrlKey || e.metaKey)) {\n openPopup();\n e.preventDefault();\n e.stopPropagation();\n }\n });\n\n // Open on mouse wheel button\n const _doWorkspaceClick_ = Blockly.Gesture.prototype.doWorkspaceClick_;\n Blockly.Gesture.prototype.doWorkspaceClick_ = function () {\n if (this.mostRecentEvent_.button === 1 || this.mostRecentEvent_.shiftKey) openPopup();\n mousePosition = {\n x: this.mostRecentEvent_.clientX,\n y: this.mostRecentEvent_.clientY\n };\n _doWorkspaceClick_.call(this);\n };\n\n // The popup should delete blocks dragged ontop of it\n const _isDeleteArea = Blockly.WorkspaceSvg.prototype.isDeleteArea;\n Blockly.WorkspaceSvg.prototype.isDeleteArea = function (e) {\n if (popupPosition) {\n if (e.clientX > popupPosition.x && e.clientX < popupPosition.x + previewWidth && e.clientY > popupPosition.y && e.clientY < popupPosition.y + previewHeight) {\n return Blockly.DELETE_AREA_TOOLBOX;\n }\n }\n return _isDeleteArea.call(this, e);\n };\n});\n// EXTERNAL MODULE: ./node_modules/css-loader!./src/addons/addons/middle-click-popup/userstyle.css\nvar userstyle = __webpack_require__(1435);\nvar userstyle_default = /*#__PURE__*/__webpack_require__.n(userstyle);\n\n// CONCATENATED MODULE: ./src/addons/addons/middle-click-popup/_runtime_entry.js\n/* generated by pull.js */\n\n\nconst resources = {\n \"userscript.js\": userscript,\n \"userstyle.css\": userstyle_default.a\n};\n\n/***/ }),\n\n/***/ 1535:\n/***/ (function(module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n// ESM COMPAT FLAG\n__webpack_require__.r(__webpack_exports__);\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, \"resources\", function() { return /* binding */ resources; });\n\n// CONCATENATED MODULE: ./src/addons/addons/find-bar/blockly/BlockItem.js\nclass BlockItem {\n constructor(cls, procCode, labelID, y) {\n this.cls = cls;\n this.procCode = procCode;\n this.labelID = labelID;\n this.y = y;\n this.lower = procCode.toLowerCase();\n /**\n * An Array of block ids\n * @type {Array.}\n */\n this.clones = null;\n this.eventName = null;\n }\n\n /**\n * True if the blockID matches a black represented by this BlockItem\n * @param id\n * @returns {boolean}\n */\n matchesID(id) {\n if (this.labelID === id) {\n return true;\n }\n if (this.clones) {\n for (const cloneID of this.clones) {\n if (cloneID === id) {\n return true;\n }\n }\n }\n return false;\n }\n}\n// EXTERNAL MODULE: ./src/addons/addons/find-bar/blockly/BlockInstance.js\nvar BlockInstance = __webpack_require__(1393);\n\n// EXTERNAL MODULE: ./src/addons/addons/find-bar/blockly/Utils.js + 1 modules\nvar Utils = __webpack_require__(1391);\n\n// CONCATENATED MODULE: ./src/addons/addons/find-bar/userscript.js\n\n\n\n/* harmony default export */ var userscript = (async function (_ref) {\n let {\n addon,\n msg,\n console\n } = _ref;\n const Blockly = await addon.tab.traps.getBlockly();\n class FindBar {\n constructor() {\n this.utils = new Utils[\"a\" /* default */](addon);\n this.prevValue = \"\";\n this.findBarOuter = null;\n this.findWrapper = null;\n this.findInput = null;\n this.dropdownOut = null;\n this.dropdown = new Dropdown(this.utils);\n document.addEventListener(\"keydown\", e => this.eventKeyDown(e), true);\n }\n get workspace() {\n return Blockly.getMainWorkspace();\n }\n createDom(root) {\n this.findBarOuter = document.createElement(\"div\");\n this.findBarOuter.className = \"sa-find-bar\";\n addon.tab.displayNoneWhileDisabled(this.findBarOuter, {\n display: \"flex\"\n });\n root.appendChild(this.findBarOuter);\n this.findWrapper = this.findBarOuter.appendChild(document.createElement(\"span\"));\n this.findWrapper.className = \"sa-find-wrapper\";\n this.dropdownOut = this.findWrapper.appendChild(document.createElement(\"label\"));\n this.dropdownOut.className = \"sa-find-dropdown-out\";\n this.findInput = this.dropdownOut.appendChild(document.createElement(\"input\"));\n this.findInput.className = addon.tab.scratchClass(\"input_input-form\", {\n others: \"sa-find-input\"\n });\n // for