{"version":3,"file":"js/addon-entry-debugger.js","sources":["webpack://GUI/./src/addons/addons/debugger/style.css","webpack://GUI/./src/addons/addons/editor-theme3/compatibility.css","webpack://GUI/./src/addons/addons/debugger/icons/close.svg","webpack://GUI/./src/addons/addons/debugger/icons/debug.svg","webpack://GUI/./src/addons/addons/debugger/icons/delete.svg","webpack://GUI/./src/addons/addons/debugger/icons/download-white.svg","webpack://GUI/./src/addons/addons/debugger/icons/error.svg","webpack://GUI/./src/addons/addons/debugger/icons/logs.svg","webpack://GUI/./src/addons/addons/debugger/icons/performance.svg","webpack://GUI/./src/addons/addons/debugger/icons/play.svg","webpack://GUI/./src/addons/addons/debugger/icons/step.svg","webpack://GUI/./src/addons/addons/debugger/icons/subthread.svg","webpack://GUI/./src/addons/addons/debugger/icons/threads.svg","webpack://GUI/./src/addons/addons/debugger/icons/warning.svg","webpack://GUI/./src/addons/addons/debugger/_runtime_entry.js","webpack://GUI/./src/addons/addons/debugger/icons/error.svg?da6a","webpack://GUI/./src/addons/addons/debugger/icons/subthread.svg?0c21","webpack://GUI/./src/addons/addons/debugger/icons/warning.svg?78a8","webpack://GUI/./src/addons/addons/debugger/log-view.js","webpack://GUI/./src/addons/addons/debugger/logs.js","webpack://GUI/./src/addons/addons/debugger/module.js","webpack://GUI/./src/addons/addons/debugger/performance.js","webpack://GUI/./src/addons/addons/debugger/threads.js","webpack://GUI/./src/addons/addons/debugger/userscript.js","webpack://GUI/./src/addons/addons/editor-stepping/highlighter.js","webpack://GUI/./src/addons/libraries/common/cs/download-blob.js"],"sourcesContent":["var escape = require(\"../../../../node_modules/css-loader/lib/url/escape.js\");\nexports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\nexports.i(require(\"-!../../../../node_modules/css-loader/index.js!../editor-theme3/compatibility.css\"), \"\");\n\n// module\nexports.push([module.id, \"[dir=\\\"ltr\\\"] .sa-debugger-container {\\n margin-right: 0.2rem;\\n}\\n\\n[dir=\\\"rtl\\\"] .sa-debugger-container {\\n margin-left: 0.2rem;\\n}\\n\\n.sa-debugger-small .sa-debugger-container {\\n display: none !important;\\n}\\n\\n.sa-debugger-container [class*=\\\"button_content_\\\"] {\\n position: relative;\\n}\\n\\n.sa-debugger-unread::after {\\n content: \\\"\\\";\\n position: absolute;\\n top: 1px;\\n right: 0;\\n display: block;\\n width: 6px;\\n height: 6px;\\n background-color: var(--editorDarkMode-highlightText, #4d97ff);\\n border-radius: 50%;\\n}\\n\\n.sa-debugger-interface {\\n display: none;\\n position: absolute;\\n z-index: 492;\\n background-color: white;\\n width: 565px;\\n height: 25rem;\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-interface {\\n background: var(--ui-primary);\\n}\\n\\n.sa-debugger-interface [class*=\\\"card_header-buttons_\\\"] {\\n background-color: #29beb8;\\n border-color: #3aa8a4;\\n}\\n\\n.sa-debugger-interface h1 {\\n padding: 10px;\\n z-index: 10;\\n width: calc(100% - 20px);\\n font-size: 20px;\\n}\\n\\n.sa-debugger-tabs {\\n margin: 0;\\n display: flex;\\n align-items: center;\\n padding: 0 15px;\\n font-size: 0.75rem;\\n}\\n.sa-debugger-tabs li {\\n margin: 0;\\n display: flex;\\n align-items: center;\\n padding: 0.5em 1em;\\n background-color: rgba(0, 0, 0, 0.1);\\n border: 1px solid rgba(0, 0, 0, 0.15);\\n border-radius: 1rem;\\n color: white;\\n cursor: pointer;\\n}\\n.sa-debugger-tabs li + li {\\n margin-inline-start: 10px;\\n}\\n.sa-debugger-tabs li:hover {\\n background-color: rgba(0, 0, 0, 0.15);\\n}\\n.sa-debugger-tabs li.sa-debugger-tab-selected {\\n background-color: white;\\n background-clip: padding-box;\\n border-color: rgba(0, 0, 0, 0.25);\\n color: #4d97ff;\\n}\\n.sa-debugger-tabs li img {\\n margin: 0;\\n margin-right: 0.25rem;\\n width: 1rem;\\n filter: brightness(0) invert(1);\\n}\\n.sa-debugger-tabs li.sa-debugger-tab-selected img {\\n filter: none;\\n}\\n\\n.sa-debugger-header-buttons img {\\n width: 20px;\\n height: 20px;\\n}\\n\\n.sa-debugger-unpause {\\n animation: saDebuggerUnpause 2s infinite alternate;\\n}\\n\\n@keyframes saDebuggerUnpause {\\n 0% {\\n background-color: rgba(0, 0, 0, 0.15);\\n }\\n 100% {\\n background-color: rgba(0, 0, 0, 0);\\n }\\n}\\n\\n.sa-debugger-tab-content {\\n width: 100%;\\n height: 100%;\\n overflow: auto;\\n cursor: auto;\\n}\\n\\n.sa-debugger-chart {\\n width: 100%;\\n height: 100%;\\n}\\n\\n.sa-performance-tab-content {\\n padding: 15px;\\n}\\n\\n.sa-debugger-log-outer {\\n height: 100%;\\n}\\n\\n.sa-debugger-log-inner {\\n position: relative;\\n overflow-y: auto;\\n font-size: 12px;\\n line-height: 1.2;\\n height: 100%;\\n contain: strict;\\n}\\n\\n.sa-debugger-log-empty {\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n width: 100%;\\n height: 100%;\\n font-size: 20px;\\n font-style: italic;\\n}\\n\\n.sa-debugger-log-end {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 1px;\\n height: 1px;\\n}\\n\\n.sa-debugger-log {\\n position: absolute;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 20px;\\n box-sizing: border-box;\\n display: flex;\\n align-items: center;\\n border-bottom: 1px solid rgba(0, 0, 0, 0.15);\\n padding-left: 4px;\\n font-family: monospace;\\n color: #000;\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-log {\\n color: var(--text-primary);\\n border-color: rgba(255, 255, 255, 0.15);\\n}\\n.sa-debugger-log[data-type=\\\"warn\\\"] {\\n border-color: hsl(50deg, 100%, 75%);\\n color: hsl(39deg 100% 18%);\\n background-color: hsl(50deg 100% 95%);\\n}\\n.sa-debugger-log[data-type=\\\"error\\\"] {\\n border-color: hsl(0deg 100% 92%);\\n color: red;\\n background-color: hsl(0deg 100% 95%);\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-log[data-type=\\\"warn\\\"] {\\n border-color: hsl(50deg, 100%, 15%);\\n color: hsl(39deg 100% 90%);\\n background-color: hsl(50deg 100% 10%);\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-log[data-type=\\\"error\\\"] {\\n border-color: hsl(0deg 100% 15%);\\n color: hsl(0deg 100% 77%);\\n background-color: hsl(0deg 100% 10%);\\n}\\n\\n.sa-debugger-log-repeats {\\n background-color: hsla(163, 85%, 40%, 1);\\n color: white;\\n border-radius: 100px;\\n padding: 1px 6px;\\n margin-right: 4px;\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-log-repeats {\\n color: var(--ui-primary);\\n}\\n\\n.sa-debugger-log-icon {\\n width: 16px;\\n height: 16px;\\n margin-right: 4px;\\n}\\n[data-type=\\\"warn\\\"] .sa-debugger-log-icon {\\n background-image: url(\" + escape(require(\"./icons/warning.svg\")) + \");\\n}\\n[data-type=\\\"error\\\"] .sa-debugger-log-icon {\\n background-image: url(\" + escape(require(\"./icons/error.svg\")) + \");\\n}\\n.sa-debugger-threads .sa-debugger-log-icon {\\n background-image: url(\" + escape(require(\"./icons/subthread.svg\")) + \");\\n}\\n\\n.sa-debugger-log-link {\\n color: inherit;\\n cursor: pointer;\\n opacity: 0.5;\\n text-decoration: underline;\\n float: right;\\n text-align: right;\\n max-width: 100%;\\n padding-left: 4px;\\n margin-right: 4px;\\n margin-left: auto;\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-log-link {\\n color: inherit;\\n}\\n.sa-debugger-log-link:hover {\\n text-decoration: underline;\\n color: #4d97ff;\\n opacity: 1;\\n}\\n.sa-debugger-log-link-unknown {\\n pointer-events: none;\\n}\\n\\n.sa-debugger-log-text {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: pre;\\n}\\n.sa-debugger-log-text-empty {\\n font-style: italic;\\n}\\n.sa-debugger-log-internal .sa-debugger-log-text {\\n font-style: italic;\\n}\\n\\n.sa-debugger-thread-indent {\\n width: calc(16px * var(--level));\\n margin-right: 4px;\\n}\\n.sa-debugger-thread-title .sa-debugger-thread-indent {\\n margin: 0;\\n}\\n.sa-debugger-thread-target-name {\\n font-weight: bold;\\n margin-right: 8px;\\n}\\n.sa-debugger-thread-running {\\n background-color: rgba(255, 187, 0, 0.233);\\n font-weight: bold;\\n}\\n\\n.sa-debugger-block-preview {\\n padding: 1px 6px;\\n margin-right: 4px;\\n background-color: var(--sa-block-colored-background);\\n color: var(--sa-block-text);\\n}\\n.sa-debugger-block-preview[data-shape=\\\"round\\\"] {\\n border-radius: 100px;\\n}\\n.sa-debugger-block-preview[data-shape=\\\"stacked\\\"] {\\n border-radius: 3px;\\n}\\n\\n.sa-debugger-thread-compiled {\\n font-style: italic;\\n}\\n\\n.sa-debugger-compiler-warning {\\n position: relative;\\n display: block;\\n text-align: center;\\n height: 24px;\\n color: #2121bf;\\n}\\n.sa-debugger-compiler-warning[hidden] {\\n display: none;\\n}\\n[theme=\\\"dark\\\"] .sa-debugger-compiler-warning {\\n color: #bdbdf9;\\n}\\n\", \"\"]);\n\n// exports\n","exports = module.exports = require(\"../../../../node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.id, \"/* 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: white;\\n --sa-block-gray-text: white;\\n --sa-block-colored-text: var(--sa-block-background-primary);\\n --sa-block-text-on-bright-background: white;\\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-sa-primary, #29beb8);\\n --sa-block-background-secondary: var(--editorTheme3-sa-secondary, #3aa8a4);\\n --sa-block-background-tertiary: var(--editorTheme3-sa-tertiary, #3aa8a4);\\n --sa-block-field-background: var(--editorTheme3-sa-field, #3aa8a4);\\n}\\n\\n.sa-block-color-TurboWarp {\\n --sa-block-background-primary: var(--editorTheme3-tw-primary, #ff4c4c);\\n --sa-block-background-secondary: var(--editorTheme3-tw-secondary, #e64444);\\n --sa-block-background-tertiary: var(--editorTheme3-tw-tertiary, #e64444);\\n --sa-block-field-background: var(--editorTheme3-tw-field, #e64444);\\n}\\n\", \"\"]);\n\n// exports\n","export default \"data:image/svg+xml;base64,PHN2ZyBkYXRhLW5hbWU9IkxheWVyIDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDcuNDggNy40OCIgc3R5bGU9InRyYW5zZm9ybTpyb3RhdGUoNDVkZWcpIj48cGF0aCBkPSJNMy43NCA2LjQ4VjFNMSAzLjc0aDUuNDgiIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmY7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS13aWR0aDoycHgiLz48L3N2Zz4=\"","export default \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgc3Ryb2tlPSIjNEM5N0ZGIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MTtwYWludC1vcmRlcjptYXJrZXJzIHN0cm9rZSBmaWxsIiBkPSJNNCAzLjVjLS44MzEgMC0xLjUuNjY5LTEuNSAxLjV2MTBjMCAuODMxLjY2OSAxLjUgMS41IDEuNWgxMmMuODMxIDAgMS41LS42NjkgMS41LTEuNVY1YzAtLjgzMS0uNjY5LTEuNS0xLjUtMS41Wm0wIDFoMTJjLjI3NyAwIC41LjIyMy41LjV2MTBjMCAuMjc3LS4yMjMuNS0uNS41SDRhLjQ5OS40OTkgMCAwIDEtLjUtLjVWNWMwLS4yNzcuMjIzLS41LjUtLjVaIiBzdHJva2U9Im5vbmUiLz48cGF0aCBkPSJtNS40MTcgNy41IDMuNzUgMi41LTMuNzUgMi41bTUgMGg0LjE2NiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzhmOGY4ZjtzdHJva2Utd2lkdGg6MTtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIi8+PC9nPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik00LjU0OCA3aDEwLjkwNGEuNS41IDAgMCAxIC40OTguNTQ1bC0uNzg1IDguNjM1QTIgMiAwIDAgMSAxMy4xNzQgMThINi44MjdhMiAyIDAgMCAxLTEuOTkyLTEuODJMNC4wNSA3LjU0NkEuNS41IDAgMCAxIDQuNTQ4IDd6bTIuNzg1LTMgLjU1My0xLjY1OEEuNS41IDAgMCAxIDguMzYgMmgzLjI4YS41LjUgMCAwIDEgLjQ3NC4zNDJMMTIuNjY3IDRIMTYuNWEuNS41IDAgMCAxIC41LjV2MWEuNS41IDAgMCAxLS41LjVoLTEzYS41LjUgMCAwIDEtLjUtLjV2LTFhLjUuNSAwIDAgMSAuNS0uNWgzLjgzM3ptMS4wNTQgMGgzLjIyNmwtLjMzNC0xSDguNzIxbC0uMzM0IDF6TTEwIDExLjcybDEuNTk1LTEuNTk1YS41LjUgMCAwIDEgLjcwNyAwbC4wNzMuMDczYS41LjUgMCAwIDEgMCAuNzA3TDEwLjc4IDEyLjVsMS41OTUgMS41OTVhLjUuNSAwIDAgMSAwIC43MDdsLS4wNzMuMDczYS41LjUgMCAwIDEtLjcwNyAwTDEwIDEzLjI4bC0xLjU5NSAxLjU5NWEuNS41IDAgMCAxLS43MDcgMGwtLjA3My0uMDczYS41LjUgMCAwIDEgMC0uNzA3TDkuMjIgMTIuNWwtMS41OTUtMS41OTVhLjUuNSAwIDAgMSAwLS43MDdsLjA3My0uMDczYS41LjUgMCAwIDEgLjcwNyAwTDEwIDExLjcyeiIgaWQ9ImEiLz48L2RlZnM+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48bWFzayBpZD0iYiIgZmlsbD0iI2ZmZiI+PHVzZSB4bGluazpocmVmPSIjYSIvPjwvbWFzaz48ZyBtYXNrPSJ1cmwoI2IpIiBmaWxsPSIjRkZGIj48cGF0aCBkPSJNMCAwaDIwdjIwSDB6Ii8+PC9nPjwvZz48L3N2Zz4=\"","export default \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0ibTE0LjczIDguNzc5LTQuMjUzIDQuMjY0YS42MTkuNjE5IDAgMCAxLS44OSAwTDUuMzM2IDguNzc5QS42My42MyAwIDAgMSA1Ljc4OCA3LjdoMi4xMTdsMS4yNjMtNS4wMTZhLjkxMi45MTIgMCAwIDEgMS4xMDYtLjY1Ni44OS44OSAwIDAgMSAuNjY4LjY1NkwxMi4yMDYgNy43aDIuMDcyYy41NTkgMCAuODU2LjY3LjQ1MSAxLjA3OHpNMTggMTEuODEydjIuNTc5QzE4IDE2LjM3NSAxNi4zOTUgMTggMTQuNDE3IDE4SDUuNkEzLjYwNyAzLjYwNyAwIDAgMSAyIDE0LjM5di0yLjU3OGExLjE3IDEuMTcgMCAxIDEgMi4zMzcgMHYyLjU3OUExLjI3IDEuMjcgMCAwIDAgNS42IDE1LjY1Nmg4LjgxN2MuNjg2IDAgMS4yNDYtLjU3OCAxLjI0Ni0xLjI2NXYtMi41NzljMC0uNjU2LjUzLTEuMTcyIDEuMTY5LTEuMTcyLjY1NCAwIDEuMTY4LjUxNiAxLjE2OCAxLjE3MnoiIGZpbGw9IiNGRkYiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHN0eWxlPSItbXMtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoMzYwZGVnKSI+PHBhdGggZD0iTTEyIDE0YTEuMjUgMS4yNSAwIDEgMCAxLjI1IDEuMjVBMS4yNSAxLjI1IDAgMCAwIDEyIDE0em0wLTEuNWExIDEgMCAwIDAgMS0xdi0zYTEgMSAwIDAgMC0yIDB2M2ExIDEgMCAwIDAgMSAxek0xMiAyYTEwIDEwIDAgMSAwIDEwIDEwQTEwLjAxMSAxMC4wMTEgMCAwIDAgMTIgMnptMCAxOGE4IDggMCAxIDEgOC04IDguMDEgOC4wMSAwIDAgMS04IDh6IiBmaWxsPSJyZWQiLz48L3N2Zz4=\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHN0eWxlPSItbXMtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoMzYwZGVnKSI+PHBhdGggZD0iTTMgN2gxOGExIDEgMCAwIDAgMC0ySDNhMSAxIDAgMCAwIDAgMnptMCA0aDE0YTEgMSAwIDAgMCAwLTJIM2ExIDEgMCAwIDAgMCAyem0xOCAySDNhMSAxIDAgMCAwIDAgMmgxOGExIDEgMCAwIDAgMC0yem0tNCA0SDNhMSAxIDAgMCAwIDAgMmgxNGExIDEgMCAwIDAgMC0yeiIgZmlsbD0iIzUxMDBmZiIvPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiPjxwYXRoIHN0cm9rZT0iIzRjOTdmZiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2Utd2lkdGg9IjIiIGQ9Ik05IDE5di02YTIgMiAwIDAgMC0yLTJINWEyIDIgMCAwIDAtMiAydjZhMiAyIDAgMCAwIDIgMmgyYTIgMiAwIDAgMCAyLTJ6bTAgMFY5YTIgMiAwIDAgMSAyLTJoMmEyIDIgMCAwIDEgMiAydjEwbS02IDBhMiAyIDAgMCAwIDIgMmgyYTIgMiAwIDAgMCAyLTJtMCAwVjVhMiAyIDAgMCAxIDItMmgyYTIgMiAwIDAgMSAyIDJ2MTRhMiAyIDAgMCAxLTIgMmgtMmEyIDIgMCAwIDEtMi0yeiIvPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDkiIGhlaWdodD0iNTIiIHZpZXdCb3g9Ii01IDAgNDkgNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxwYXRoIGQ9Ik0xNy4yMjEgOC4zNDVjMi41NTYtNC4yNTkgNi43MDItNC4yNTIgOS4yNTQgMGwxMy42NzcgMjIuNzk2YzIuNTU1IDQuMjU4LjU5NyA3LjcxLTQuMzggNy43MUg3LjkyNGMtNC45NzMgMC02LjkzLTMuNDU4LTQuMzgtNy43MUwxNy4yMjIgOC4zNDV6IiBpZD0iYSIvPjwvZGVmcz48dXNlIHN0cm9rZT0iI0ZGRiIgZmlsbD0iI0ZGRiIgeGxpbms6aHJlZj0iI2EiIHRyYW5zZm9ybT0icm90YXRlKDkwIDIwLjg1IDIzLjAwMykiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMjIuNjggMTIuMmExLjYgMS42IDAgMCAxLTEuMjcuNjNoLTcuNjlhMS41OSAxLjU5IDAgMCAxLTEuMTYtMi41OGwxLjEyLTEuNDFhNC44MiA0LjgyIDAgMCAwLTMuMTQtLjc3IDQuMzEgNC4zMSAwIDAgMC0yIC44QTQuMjUgNC4yNSAwIDAgMCA3LjIgMTAuNmE1LjA2IDUuMDYgMCAwIDAgLjU0IDQuNjJBNS41OCA1LjU4IDAgMCAwIDEyIDE3Ljc0YTIuMjYgMi4yNiAwIDAgMS0uMTYgNC41MkExMC4yNSAxMC4yNSAwIDAgMSAzLjc0IDE4YTEwLjE0IDEwLjE0IDAgMCAxLTEuNDktOS4yMiA5LjcgOS43IDAgMCAxIDIuODMtNC4xNEE5LjkyIDkuOTIgMCAwIDEgOS42NiAyLjVhMTAuNjYgMTAuNjYgMCAwIDEgNy43MiAxLjY4bDEuMDgtMS4zNWExLjU3IDEuNTcgMCAwIDEgMS4yNC0uNiAxLjYgMS42IDAgMCAxIDEuNTQgMS4yMWwxLjcgNy4zN2ExLjU3IDEuNTcgMCAwIDEtLjI2IDEuMzlaIiBzdHlsZT0iZmlsbDojZmZmIi8+PHBhdGggZD0iTTIxLjM4IDExLjgzaC03LjYxYS41OS41OSAwIDAgMS0uNDMtMWwxLjc1LTIuMTlhNS45IDUuOSAwIDAgMC00LjctMS41OCA1LjA3IDUuMDcgMCAwIDAtNC4xMSAzLjE3QTYgNiAwIDAgMCA3IDE1Ljc3YTYuNTEgNi41MSAwIDAgMCA1IDIuOTIgMS4zMSAxLjMxIDAgMCAxLS4wOCAyLjYyIDkuMyA5LjMgMCAwIDEtNy4zNS0zLjgyIDkuMTYgOS4xNiAwIDAgMS0xLjQtOC4zN0E4LjUxIDguNTEgMCAwIDEgNS43MSA1LjRhOC43NiA4Ljc2IDAgMCAxIDQuMTEtMS45MiA5LjcxIDkuNzEgMCAwIDEgNy43NSAyLjA3bDEuNjctMi4xYS41OS41OSAwIDAgMSAxIC4yMUwyMiAxMS4wOGEuNTkuNTkgMCAwIDEtLjYyLjc1WiIgc3R5bGU9ImZpbGw6I2ZmZiIvPjwvc3ZnPg==\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHN0eWxlPSItbXMtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoMzYwZGVnKSI+PHBhdGggZD0iTTIwLjkyIDEyLjYyYTEgMSAwIDAgMC0uMjEtLjMzbC0zLTNhMSAxIDAgMCAwLTEuNDIgMS40MmwxLjMgMS4yOUg4YTEgMSAwIDAgMS0xLTFWN2ExIDEgMCAwIDAtMiAwdjRhMyAzIDAgMCAwIDMgM2g5LjU5bC0xLjMgMS4yOWExIDEgMCAwIDAgMCAxLjQyIDEgMSAwIDAgMCAxLjQyIDBsMy0zYTEgMSAwIDAgMCAuMjEtLjMzIDEgMSAwIDAgMCAwLS43NnoiIGZpbGw9ImdyYXkiLz48L3N2Zz4=\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHN0eWxlPSItbXMtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoMzYwZGVnKSI+PHBhdGggZD0iTTE5IDJIOWEzIDMgMCAwIDAtMyAzdjFINWEzIDMgMCAwIDAtMyAzdjEwYTMgMyAwIDAgMCAzIDNoMTBhMyAzIDAgMCAwIDMtM3YtMWgxYTMgMyAwIDAgMCAzLTNWNWEzIDMgMCAwIDAtMy0zem0tMyAxN2ExIDEgMCAwIDEtMSAxSDVhMSAxIDAgMCAxLTEtMXYtN2gxMnptMC05SDRWOWExIDEgMCAwIDEgMS0xaDEwYTEgMSAwIDAgMSAxIDF6bTQgNWExIDEgMCAwIDEtMSAxaC0xVjlhMyAzIDAgMCAwLS4xOC0xSDIwem0wLTlIOFY1YTEgMSAwIDAgMSAxLTFoMTBhMSAxIDAgMCAxIDEgMXoiIGZpbGw9IiM0Yzk3ZmYiLz48L3N2Zz4=\"","export default \"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHN0eWxlPSItbXMtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgzNjBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoMzYwZGVnKSI+PHBhdGggZD0iTTEyIDE2YTEgMSAwIDEgMCAxIDEgMSAxIDAgMCAwLTEtMXptMTAuNjcgMS40Ny04LjA1LTE0YTMgMyAwIDAgMC01LjI0IDBsLTggMTRBMyAzIDAgMCAwIDMuOTQgMjJoMTYuMTJhMyAzIDAgMCAwIDIuNjEtNC41M3ptLTEuNzMgMmExIDEgMCAwIDEtLjg4LjUxSDMuOTRhMSAxIDAgMCAxLS44OC0uNTEgMSAxIDAgMCAxIDAtMWw4LTE0YTEgMSAwIDAgMSAxLjc4IDBsOC4wNSAxNGExIDEgMCAwIDEgLjA1IDEuMDJ6TTEyIDhhMSAxIDAgMCAwLTEgMXY0YTEgMSAwIDAgMCAyIDBWOWExIDEgMCAwIDAtMS0xeiIgZmlsbD0iI2UwYmIwMCIvPjwvc3ZnPg==\"","/* generated by pull.js */\nimport _js from \"./userscript.js\";\nimport _css from \"!css-loader!./style.css\";\nimport _asset from \"!url-loader!./icons/close.svg\";\nimport _asset2 from \"!url-loader!./icons/debug.svg\";\nimport _asset3 from \"!url-loader!./icons/delete.svg\";\nimport _asset4 from \"!url-loader!./icons/download-white.svg\";\nimport _asset5 from \"!url-loader!./icons/error.svg\";\nimport _asset6 from \"!url-loader!./icons/logs.svg\";\nimport _asset7 from \"!url-loader!./icons/performance.svg\";\nimport _asset8 from \"!url-loader!./icons/play.svg\";\nimport _asset9 from \"!url-loader!./icons/step.svg\";\nimport _asset10 from \"!url-loader!./icons/subthread.svg\";\nimport _asset11 from \"!url-loader!./icons/threads.svg\";\nimport _asset12 from \"!url-loader!./icons/warning.svg\";\nexport const resources = {\n \"userscript.js\": _js,\n \"style.css\": _css,\n \"icons/close.svg\": _asset,\n \"icons/debug.svg\": _asset2,\n \"icons/delete.svg\": _asset3,\n \"icons/download-white.svg\": _asset4,\n \"icons/error.svg\": _asset5,\n \"icons/logs.svg\": _asset6,\n \"icons/performance.svg\": _asset7,\n \"icons/play.svg\": _asset8,\n \"icons/step.svg\": _asset9,\n \"icons/subthread.svg\": _asset10,\n \"icons/threads.svg\": _asset11,\n \"icons/warning.svg\": _asset12,\n};\n","var _path;\nfunction _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\nimport * as React from \"react\";\nfunction SvgError(props) {\n return /*#__PURE__*/React.createElement(\"svg\", _extends({\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n viewBox: \"0 0 24 24\",\n style: {\n msTransform: \"rotate(360deg)\",\n WebkitTransform: \"rotate(360deg)\"\n },\n transform: \"rotate(360)\"\n }, props), _path || (_path = /*#__PURE__*/React.createElement(\"path\", {\n d: \"M12 14a1.25 1.25 0 101.25 1.25A1.25 1.25 0 0012 14zm0-1.5a1 1 0 001-1v-3a1 1 0 00-2 0v3a1 1 0 001 1zM12 2a10 10 0 1010 10A10.011 10.011 0 0012 2zm0 18a8 8 0 118-8 8.01 8.01 0 01-8 8z\",\n fill: \"red\"\n })));\n}\nexport default __webpack_public_path__ + \"static/assets/76b6cb627b95d79705c0b41664064f0e.svg\";\nexport { SvgError as ReactComponent };","var _path;\nfunction _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\nimport * as React from \"react\";\nfunction SvgSubthread(props) {\n return /*#__PURE__*/React.createElement(\"svg\", _extends({\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n viewBox: \"0 0 24 24\",\n style: {\n msTransform: \"rotate(360deg)\",\n WebkitTransform: \"rotate(360deg)\"\n },\n transform: \"rotate(360)\"\n }, props), _path || (_path = /*#__PURE__*/React.createElement(\"path\", {\n d: \"M20.92 12.62a1 1 0 00-.21-.33l-3-3a1 1 0 00-1.42 1.42l1.3 1.29H8a1 1 0 01-1-1V7a1 1 0 00-2 0v4a3 3 0 003 3h9.59l-1.3 1.29a1 1 0 000 1.42 1 1 0 001.42 0l3-3a1 1 0 00.21-.33 1 1 0 000-.76z\",\n fill: \"gray\"\n })));\n}\nexport default __webpack_public_path__ + \"static/assets/c846a442121113b1d04f6b9d50912038.svg\";\nexport { SvgSubthread as ReactComponent };","var _path;\nfunction _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\nimport * as React from \"react\";\nfunction SvgWarning(props) {\n return /*#__PURE__*/React.createElement(\"svg\", _extends({\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"1em\",\n height: \"1em\",\n viewBox: \"0 0 24 24\",\n style: {\n msTransform: \"rotate(360deg)\",\n WebkitTransform: \"rotate(360deg)\"\n },\n transform: \"rotate(360)\"\n }, props), _path || (_path = /*#__PURE__*/React.createElement(\"path\", {\n d: \"M12 16a1 1 0 101 1 1 1 0 00-1-1zm10.67 1.47l-8.05-14a3 3 0 00-5.24 0l-8 14A3 3 0 003.94 22h16.12a3 3 0 002.61-4.53zm-1.73 2a1 1 0 01-.88.51H3.94a1 1 0 01-.88-.51 1 1 0 010-1l8-14a1 1 0 011.78 0l8.05 14a1 1 0 01.05 1.02zM12 8a1 1 0 00-1 1v4a1 1 0 002 0V9a1 1 0 00-1-1z\",\n fill: \"#e0bb00\"\n })));\n}\nexport default __webpack_public_path__ + \"static/assets/0e009d6e684951615b31a267baa37636.svg\";\nexport { SvgWarning as ReactComponent };","const clamp = (i, min, max) => Math.max(min, Math.min(max, i));\n\nconst appendSortedElement = (parent, newChild) => {\n const newChildIndex = +newChild.dataset.index;\n let foundSpot = false;\n for (const existingChild of parent.children) {\n const existingChildIndex = +existingChild.dataset.index;\n if (existingChildIndex > newChildIndex) {\n foundSpot = true;\n parent.insertBefore(newChild, existingChild);\n break;\n }\n }\n if (!foundSpot) {\n parent.appendChild(newChild);\n }\n};\n\n/**\n * LogView: A virtualized row viewer.\n * It efficiently manages row rendering and scrolling.\n *\n * 1. .logs is the place where all the rows live. This is an array of any arbitrary object.\n * 2. Implement generateRow(row). This takes a row from .logs as an argument. This should return\n * an object with a bunch of DOM elements on it. The \"root\" property must be set, nothing else\n * is required. This is called when a row becomes visible. It can be called any number of times.\n * This is where you should setup elements that are immutable for a given row. LogView will\n * move the root element to the right spot for you.\n * 3. Implement renderRow(elements, row). This will be called with the result returned by\n * generateRow() and the row in .logs any time a row is changed, including the first render.\n * It can be called any number of times. This is where you should update any dynamic elements.\n * 4. Whenever you update .logs without using the helper methods such as append(), call\n * queueUpdateContent().\n */\nclass LogView {\n constructor() {\n this.rows = [];\n this.canAutoScrollToEnd = true;\n this.rowHeight = 20;\n\n this.outerElement = document.createElement(\"div\");\n this.outerElement.className = \"sa-debugger-log-outer\";\n\n this.innerElement = document.createElement(\"div\");\n this.innerElement.className = \"sa-debugger-log-inner\";\n this.outerElement.appendChild(this.innerElement);\n this.innerElement.addEventListener(\"scroll\", this._handleScroll.bind(this), { passive: true });\n this.innerElement.addEventListener(\"wheel\", this._handleWheel.bind(this), { passive: true });\n\n this.endElement = document.createElement(\"div\");\n this.endElement.className = \"sa-debugger-log-end\";\n this.endElement.dataset.index = \"-1\";\n this.innerElement.appendChild(this.endElement);\n\n this.placeholderElement = document.createElement(\"div\");\n this.placeholderElement.className = \"sa-debugger-log-empty\";\n\n this.visible = false;\n this.isScrolledToEnd = true;\n this.scrollTopWhenHidden = \"end\";\n this.scrollTop = 0;\n this.updateContentQueued = false;\n this.scrollToEndQueued = false;\n this.oldLength = -1;\n this.rowToMetadata = new Map();\n }\n\n append(log) {\n this.queueUpdateContent();\n this._queueScrollToEnd();\n\n this.rows.push(log);\n\n const MAX_LOGS = 200000;\n while (this.rows.length > MAX_LOGS) {\n this.rows.shift();\n }\n }\n\n clear() {\n this.rows.length = 0;\n this.scrollTop = 0;\n this.isScrolledToEnd = true;\n this.queueUpdateContent();\n }\n\n show() {\n this.visible = true;\n this.height = this.innerElement.offsetHeight;\n this.queueUpdateContent();\n if (this.scrollTopWhenHidden === \"end\") {\n this._queueScrollToEnd();\n } else {\n this.innerElement.scrollTop = this.scrollTopWhenHidden;\n }\n }\n\n hide() {\n this.visible = false;\n this.scrollTopWhenHidden = this.isScrolledToEnd ? \"end\" : this.scrollTop;\n }\n\n _handleScroll(e) {\n this.scrollTop = e.target.scrollTop;\n this.isScrolledToEnd = e.target.scrollTop + 5 >= e.target.scrollHeight - e.target.clientHeight;\n this.queueUpdateContent();\n }\n\n _handleWheel(e) {\n if (e.deltaY < 0) {\n this.isScrolledToEnd = false;\n }\n }\n\n scrollIntoView(index) {\n const distanceFromTop = index * this.rowHeight;\n const viewportStart = this.scrollTop;\n const viewportEnd = this.scrollTop + this.height;\n const isInView = distanceFromTop > viewportStart && distanceFromTop < viewportEnd;\n if (!isInView) {\n this.scrollTop = distanceFromTop;\n this.innerElement.scrollTop = distanceFromTop;\n }\n }\n\n _queueScrollToEnd() {\n if (this.visible && this.canAutoScrollToEnd && this.isScrolledToEnd && !this.scrollToEndQueued) {\n this.scrollToEndQueued = true;\n queueMicrotask(() => {\n this.scrollToEndQueued = false;\n if (this.isScrolledToEnd) {\n const scrollEnd = this.innerElement.scrollHeight - this.innerElement.offsetHeight;\n this.innerElement.scrollTop = scrollEnd;\n this.scrollTop = scrollEnd;\n }\n });\n }\n }\n\n queueUpdateContent() {\n if (this.visible && !this.updateContentQueued) {\n this.updateContentQueued = true;\n queueMicrotask(() => {\n this.updateContentQueued = false;\n this.updateContent();\n });\n }\n }\n\n generateRow(row) {\n // to be implemented by users\n }\n\n renderRow(elements, row) {\n // to be implemented by users\n }\n\n updateContent() {\n if (this.rows.length !== this.oldLength) {\n this.oldLength = this.rows.length;\n\n const totalHeight = this.rows.length * this.rowHeight;\n this.endElement.style.transform = `translateY(${totalHeight}px)`;\n\n if (this.rows.length) {\n this.placeholderElement.remove();\n } else {\n this.innerElement.appendChild(this.placeholderElement);\n\n for (const metadata of this.rowToMetadata.values()) {\n metadata.elements.root.remove();\n }\n this.rowToMetadata.clear();\n }\n }\n\n if (this.rows.length === 0) {\n return;\n }\n\n // For better compatibility with asynchronous scrolling, we'll render a few extra rows in either direction.\n const EXTRA_ROWS_ABOVE = 5;\n const EXTRA_ROWS_BELOW = 5;\n\n const scrollStartIndex = Math.floor(this.scrollTop / this.rowHeight);\n const rowsVisible = Math.ceil(this.height / this.rowHeight);\n const startIndex = clamp(scrollStartIndex - EXTRA_ROWS_BELOW, 0, this.rows.length);\n const endIndex = clamp(scrollStartIndex + rowsVisible + EXTRA_ROWS_ABOVE, 0, this.rows.length);\n\n const allVisibleRows = new Set();\n const newElements = [];\n for (let i = startIndex; i < endIndex; i++) {\n const row = this.rows[i];\n allVisibleRows.add(row);\n\n let metadata = this.rowToMetadata.get(row);\n if (!metadata) {\n const elements = this.generateRow(row);\n newElements.push(elements.root);\n metadata = {\n stringify: null,\n elements,\n };\n this.rowToMetadata.set(row, metadata);\n }\n\n const currentStringify = JSON.stringify(row);\n if (currentStringify !== metadata.stringify) {\n metadata.stringify = currentStringify;\n this.renderRow(metadata.elements, row);\n }\n\n const root = metadata.elements.root;\n root.style.transform = `translateY(${i * this.rowHeight}px)`;\n root.dataset.index = i;\n }\n\n for (const [row, metadata] of this.rowToMetadata.entries()) {\n if (!allVisibleRows.has(row)) {\n metadata.elements.root.remove();\n this.rowToMetadata.delete(row);\n }\n }\n\n for (const root of newElements) {\n appendSortedElement(this.innerElement, root);\n }\n }\n}\n\nexport default LogView;\n","import downloadBlob from \"../../libraries/common/cs/download-blob.js\";\nimport LogView from \"./log-view.js\";\n\nexport default async function createLogsTab({ debug, addon, console, msg }) {\n const vm = addon.tab.traps.vm;\n\n const tab = debug.createHeaderTab({\n text: msg(\"tab-logs\"),\n icon: addon.self.getResource(\"/icons/logs.svg\") /* rewritten by pull.js */,\n });\n\n const logView = new LogView();\n logView.placeholderElement.textContent = msg(\"no-logs\");\n\n const getInputOfBlock = (targetId, blockId) => {\n const target = vm.runtime.getTargetById(targetId);\n if (!target) {\n return null;\n }\n const block = debug.getBlock(target, blockId);\n if (!block) {\n return null;\n }\n return Object.values(block.inputs)[0]?.block;\n };\n\n logView.generateRow = (row) => {\n const root = document.createElement(\"div\");\n root.className = \"sa-debugger-log\";\n if (row.internal) {\n root.classList.add(\"sa-debugger-log-internal\");\n }\n root.dataset.type = row.type;\n\n const icon = document.createElement(\"div\");\n icon.className = \"sa-debugger-log-icon\";\n if (row.type === \"warn\" || row.type === \"error\") {\n icon.title = msg(\"icon-\" + row.type);\n }\n root.appendChild(icon);\n\n const repeats = document.createElement(\"div\");\n repeats.className = \"sa-debugger-log-repeats\";\n repeats.style.display = \"none\";\n root.appendChild(repeats);\n\n if (row.preview && row.blockId && row.targetInfo) {\n const originalId = row.targetInfo.originalId;\n const inputBlock = getInputOfBlock(originalId, row.blockId);\n if (inputBlock) {\n const preview = debug.createBlockPreview(originalId, inputBlock);\n if (preview) {\n root.appendChild(preview);\n }\n }\n }\n\n const text = document.createElement(\"div\");\n text.className = \"sa-debugger-log-text\";\n if (row.text.length === 0) {\n text.classList.add(\"sa-debugger-log-text-empty\");\n text.textContent = msg(\"empty-string\");\n } else {\n text.textContent = row.text;\n text.title = row.text;\n }\n root.appendChild(text);\n\n if (row.targetInfo && row.blockId) {\n root.appendChild(debug.createBlockLink(row.targetInfo, row.blockId));\n }\n\n return {\n root,\n repeats,\n };\n };\n\n logView.renderRow = (elements, row) => {\n const { repeats } = elements;\n if (row.count > 1) {\n repeats.style.display = \"\";\n repeats.textContent = row.count;\n }\n };\n\n const exportButton = debug.createHeaderButton({\n text: msg(\"export\"),\n icon: addon.self.getResource(\"/icons/download-white.svg\") /* rewritten by pull.js */,\n description: msg(\"export-desc\"),\n });\n const downloadText = (filename, text) => {\n downloadBlob(filename, new Blob([text], { type: \"text/plain\" }));\n };\n exportButton.element.addEventListener(\"click\", async (e) => {\n const defaultFormat = \"{sprite}: {content} ({type})\";\n const exportFormat = e.shiftKey\n ? await addon.tab.prompt(msg(\"export\"), msg(\"enter-format\"), defaultFormat, { useEditorClasses: true })\n : defaultFormat;\n if (!exportFormat) return;\n const file = logView.rows\n .map(({ text, targetInfo, type, count }) =>\n (\n exportFormat.replace(\n /\\{(sprite|type|content)\\}/g,\n (_, match) =>\n ({\n sprite: targetInfo ? targetInfo.name : msg(\"unknown-sprite\"),\n type,\n content: text,\n }[match])\n ) + \"\\n\"\n ).repeat(count)\n )\n .join(\"\");\n downloadText(\"logs.txt\", file);\n });\n\n const trashButton = debug.createHeaderButton({\n text: msg(\"clear\"),\n icon: addon.self.getResource(\"/icons/delete.svg\") /* rewritten by pull.js */,\n });\n trashButton.element.addEventListener(\"click\", () => {\n clearLogs();\n });\n\n const areLogsEqual = (a, b) =>\n a.text === b.text &&\n a.type === b.type &&\n a.internal === b.internal &&\n a.blockId === b.blockId &&\n a.targetId === b.targetId;\n\n const addLog = (text, thread, type) => {\n const log = {\n text,\n type,\n count: 1,\n preview: true,\n };\n if (thread) {\n log.blockId = thread.peekStack ? thread.peekStack() : thread.thread.peekStack();\n const targetId = thread.target.id;\n log.targetId = targetId;\n log.targetInfo = debug.getTargetInfoById(targetId);\n }\n if (type === \"internal\") {\n log.internal = true;\n log.preview = false;\n log.type = \"log\";\n }\n if (type === \"internal-warn\") {\n log.internal = true;\n log.type = \"warn\";\n }\n\n const previousLog = logView.rows[logView.rows.length - 1];\n if (previousLog && areLogsEqual(log, previousLog)) {\n previousLog.count++;\n logView.queueUpdateContent();\n } else {\n logView.append(log);\n }\n\n if (!logView.visible && !log.internal) {\n debug.setHasUnreadMessage(true);\n }\n };\n\n const clearLogs = () => {\n logView.clear();\n };\n\n const show = () => {\n logView.show();\n debug.setHasUnreadMessage(false);\n };\n const hide = () => {\n logView.hide();\n };\n\n return {\n tab,\n content: logView.outerElement,\n buttons: [exportButton, trashButton],\n show,\n hide,\n addLog,\n clearLogs,\n };\n}\n","import EventTarget from \"../../event-target.js\"; /* inserted by pull.js */\n\n// https://github.com/LLK/scratch-vm/blob/bb352913b57991713a5ccf0b611fda91056e14ec/src/engine/thread.js#L198\nconst STATUS_RUNNING = 0;\nconst STATUS_PROMISE_WAIT = 1;\nconst STATUS_YIELD = 2;\nconst STATUS_YIELD_TICK = 3;\nconst STATUS_DONE = 4;\n\nlet vm;\n\nlet paused = false;\nlet pausedThreadState = new WeakMap();\nlet pauseNewThreads = false;\n\nlet steppingThread = null;\n\nconst eventTarget = new EventTarget();\n\nlet audioContextStateChange = Promise.resolve();\n\nexport const isPaused = () => paused;\n\nconst pauseThread = (thread) => {\n if (thread.updateMonitor || pausedThreadState.has(thread)) {\n // Thread is already paused or shouldn't be paused.\n return;\n }\n\n const pauseState = {\n time: vm.runtime.currentMSecs,\n status: thread.status,\n };\n pausedThreadState.set(thread, pauseState);\n\n // Pausing a thread now works by just setting its status to STATUS_PROMISE_WAIT.\n // At the start of each frame, we make sure each paused thread is still paused.\n // This is really the best way to implement this.\n // Converting thread.status into a getter/setter causes Scratch's sequencer to permanently\n // perform significantly slower in some projects. I think this is because it causes some\n // very hot functions to be deoptimized.\n // Trapping sequencer.stepThread to no-op for a paused thread causes Scratch's sequencer\n // to waste 24ms of CPU time every frame because it thinks a thread is running.\n thread.status = STATUS_PROMISE_WAIT;\n};\n\nconst ensurePausedThreadIsStillPaused = (thread) => {\n if (thread.status === STATUS_DONE) {\n // If a paused thread is finished by single stepping, let it keep being done.\n return;\n }\n const pauseState = pausedThreadState.get(thread);\n if (pauseState) {\n if (thread.status !== STATUS_PROMISE_WAIT) {\n // We'll record the change so we can properly resume the thread, but the thread must still be paused for now.\n pauseState.status = thread.status;\n thread.status = STATUS_PROMISE_WAIT;\n }\n }\n};\n\nconst setSteppingThread = (thread) => {\n steppingThread = thread;\n};\n\nconst compensateForTimePassedWhilePaused = (thread, pauseState) => {\n // TW: Compiled threads store their timer in a different place.\n if (thread.timer) {\n thread.timer.startTime += vm.runtime.currentMSecs - pauseState.time;\n }\n const stackFrame = thread.peekStackFrame();\n if (stackFrame && stackFrame.executionContext && stackFrame.executionContext.timer) {\n stackFrame.executionContext.timer.startTime += vm.runtime.currentMSecs - pauseState.time;\n }\n};\n\nconst stepUnsteppedThreads = (lastSteppedThread) => {\n // If we paused in the middle of a tick, we need to make sure to step the scripts that didn't get\n // stepped in that tick to avoid affecting project behavior.\n const threads = vm.runtime.threads;\n const startingIndex = getThreadIndex(lastSteppedThread);\n if (startingIndex !== -1) {\n for (let i = startingIndex; i < threads.length; i++) {\n const thread = threads[i];\n const status = thread.status;\n if (status === STATUS_RUNNING || status === STATUS_YIELD || status === STATUS_YIELD_TICK) {\n vm.runtime.sequencer.activeThread = thread;\n vm.runtime.sequencer.stepThread(thread);\n }\n }\n }\n};\n\nexport const setPaused = (_paused) => {\n const didChange = paused !== _paused;\n if (didChange) {\n paused = _paused;\n eventTarget.dispatchEvent(new CustomEvent(\"change\"));\n }\n\n // Don't check didChange as new threads could've started that we need to pause.\n if (paused) {\n audioContextStateChange = audioContextStateChange.then(() => {\n return vm.runtime.audioEngine.audioContext.suspend();\n });\n if (!vm.runtime.ioDevices.clock._paused) {\n vm.runtime.ioDevices.clock.pause();\n }\n vm.runtime.threads.forEach(pauseThread);\n\n const activeThread = vm.runtime.sequencer.activeThread;\n if (activeThread) {\n setSteppingThread(activeThread);\n eventTarget.dispatchEvent(new CustomEvent(\"step\"));\n }\n }\n\n // Only run unpausing logic when pause state changed to avoid unnecessary work\n if (!paused && didChange) {\n audioContextStateChange = audioContextStateChange.then(() => {\n return vm.runtime.audioEngine.audioContext.resume();\n });\n vm.runtime.ioDevices.clock.resume();\n for (const thread of vm.runtime.threads) {\n const pauseState = pausedThreadState.get(thread);\n if (pauseState) {\n compensateForTimePassedWhilePaused(thread, pauseState);\n thread.status = pauseState.status;\n }\n }\n pausedThreadState = new WeakMap();\n\n const lastSteppedThread = steppingThread;\n // This must happen after the \"change\" event is fired to fix https://github.com/ScratchAddons/ScratchAddons/issues/4281\n stepUnsteppedThreads(lastSteppedThread);\n steppingThread = null;\n }\n};\n\nexport const onPauseChanged = (listener) => {\n eventTarget.addEventListener(\"change\", () => listener(paused));\n};\n\nexport const onSingleStep = (listener) => {\n eventTarget.addEventListener(\"step\", listener);\n};\n\nexport const getRunningThread = () => steppingThread;\n\n// A modified version of this function\n// https://github.com/LLK/scratch-vm/blob/0e86a78a00db41af114df64255e2cd7dd881329f/src/engine/sequencer.js#L179\n// Returns if we should continue executing this thread.\nconst singleStepThread = (thread) => {\n if (thread.status === STATUS_DONE) {\n return false;\n }\n // TW: Can't single-step compiled threads\n if (thread.isCompiled) {\n return false;\n }\n\n const currentBlockId = thread.peekStack();\n if (!currentBlockId) {\n thread.popStack();\n\n if (thread.stack.length === 0) {\n thread.status = STATUS_DONE;\n return false;\n }\n }\n\n pauseNewThreads = true;\n vm.runtime.sequencer.activeThread = thread;\n\n /*\n We need to call execute(this, thread) like the original sequencer. We don't\n have access to that method, so we need to force the original stepThread to run\n execute for us then exit before it tries to run more blocks.\n So, we make `thread.blockGlowInFrame = ...` throw an exception, so this line:\n https://github.com/LLK/scratch-vm/blob/bb352913b57991713a5ccf0b611fda91056e14ec/src/engine/sequencer.js#L214\n will end the function early. We then have to set it back to normal afterward.\n\n Why are we here just to suffer?\n */\n const specialError = [\"special error used by Scratch Addons for implementing single-stepping\"];\n Object.defineProperty(thread, \"blockGlowInFrame\", {\n set(_block) {\n throw specialError;\n },\n });\n\n try {\n thread.status = STATUS_RUNNING;\n\n // Restart the warp timer on each step.\n // If we don't do this, Scratch will think a lot of time has passed and may yield this thread.\n if (thread.warpTimer) {\n thread.warpTimer.start();\n }\n\n try {\n vm.runtime.sequencer.stepThread(thread);\n } catch (err) {\n if (err !== specialError) throw err;\n }\n\n if (thread.status !== STATUS_RUNNING) {\n return false;\n }\n\n if (thread.peekStack() === currentBlockId) {\n thread.goToNextBlock();\n }\n\n while (!thread.peekStack()) {\n thread.popStack();\n\n if (thread.stack.length === 0) {\n thread.status = STATUS_DONE;\n return false;\n }\n\n const stackFrame = thread.peekStackFrame();\n\n if (stackFrame.isLoop) {\n if (thread.peekStackFrame().warpMode) {\n continue;\n } else {\n return false;\n }\n } else if (stackFrame.waitingReporter) {\n return false;\n }\n\n thread.goToNextBlock();\n }\n\n return true;\n } finally {\n pauseNewThreads = false;\n vm.runtime.sequencer.activeThread = null;\n Object.defineProperty(thread, \"blockGlowInFrame\", {\n value: currentBlockId,\n configurable: true,\n enumerable: true,\n writable: true,\n });\n\n // Strictly this doesn't seem to be necessary, but let's make sure the thread is still paused after we step it.\n if (thread.status !== STATUS_DONE) {\n thread.status = STATUS_PROMISE_WAIT;\n }\n }\n};\n\nconst getRealStatus = (thread) => {\n const pauseState = pausedThreadState.get(thread);\n if (pauseState) {\n return pauseState.status;\n }\n return thread.status;\n};\n\nconst getThreadIndex = (thread) => {\n // We can't use vm.runtime.threads.indexOf(thread) because threads can be restarted.\n // This can happens when, for example, a \"when I receive message1\" script broadcasts message1.\n // The object in runtime.threads is replaced when this happens.\n if (!thread) return -1;\n return vm.runtime.threads.findIndex(\n (otherThread) =>\n otherThread.target === thread.target &&\n otherThread.topBlock === thread.topBlock &&\n otherThread.stackClick === thread.stackClick &&\n otherThread.updateMonitor === thread.updateMonitor\n );\n};\n\nconst findNewSteppingThread = (startingIndex) => {\n const threads = vm.runtime.threads;\n for (let i = startingIndex; i < threads.length; i++) {\n const possibleNewThread = threads[i];\n if (possibleNewThread.updateMonitor) {\n // Never single-step monitor update threads.\n continue;\n }\n // TW: Can't single-step compiled threads\n if (possibleNewThread.isCompiled) {\n continue;\n }\n const status = getRealStatus(possibleNewThread);\n if (status === STATUS_RUNNING || status === STATUS_YIELD || status === STATUS_YIELD_TICK) {\n // Thread must not be running for single stepping to work.\n pauseThread(possibleNewThread);\n return possibleNewThread;\n }\n }\n return null;\n};\n\nexport const singleStep = () => {\n if (steppingThread) {\n const pauseState = pausedThreadState.get(steppingThread);\n // We can assume pauseState is defined as any single stepping threads must already be paused.\n\n // Make it look like no time has passed\n compensateForTimePassedWhilePaused(steppingThread, pauseState);\n pauseState.time = vm.runtime.currentMSecs;\n\n // Execute the block\n const continueExecuting = singleStepThread(steppingThread);\n\n if (!continueExecuting) {\n // Try to move onto the next thread\n steppingThread = findNewSteppingThread(getThreadIndex(steppingThread) + 1);\n }\n }\n\n // If we don't have a thread, than we are between VM steps and should search for a new thread\n if (!steppingThread) {\n setSteppingThread(findNewSteppingThread(0));\n\n // End of VM step, emulate one frame of time passing.\n vm.runtime.ioDevices.clock._pausedTime += vm.runtime.currentStepTime;\n // Skip all sounds forward by vm.runtime.currentStepTime milliseconds so it's as\n // if they where playing for one frame.\n const audioContext = vm.runtime.audioEngine.audioContext;\n for (const target of vm.runtime.targets) {\n for (const soundId of Object.keys(target.sprite.soundBank.soundPlayers)) {\n const soundPlayer = target.sprite.soundBank.soundPlayers[soundId];\n if (soundPlayer.outputNode) {\n soundPlayer.outputNode.stop(audioContext.currentTime);\n soundPlayer._createSource();\n soundPlayer.outputNode.start(\n audioContext.currentTime,\n audioContext.currentTime - soundPlayer.startingUntil + vm.runtime.currentStepTime / 1000\n );\n soundPlayer.startingUntil -= vm.runtime.currentStepTime / 1000;\n }\n }\n }\n // Move all threads forward one frame in time. For blocks like `wait () seconds`\n for (const thread of vm.runtime.threads) {\n if (pausedThreadState.has(thread)) {\n pausedThreadState.get(thread).time += vm.runtime.currentStepTime;\n }\n }\n\n // Try to run edge activated hats\n pauseNewThreads = true;\n\n const hats = vm.runtime._hats;\n for (const hatType in hats) {\n if (!Object.prototype.hasOwnProperty.call(hats, hatType)) continue;\n const hat = hats[hatType];\n if (hat.edgeActivated) {\n vm.runtime.startHats(hatType);\n }\n }\n\n pauseNewThreads = false;\n }\n\n eventTarget.dispatchEvent(new CustomEvent(\"step\"));\n};\n\nexport const setup = (_vm) => {\n if (vm) {\n return;\n }\n\n vm = _vm;\n\n const originalStepThreads = vm.runtime.sequencer.stepThreads;\n vm.runtime.sequencer.stepThreads = function () {\n if (isPaused()) {\n for (const thread of this.runtime.threads) {\n ensurePausedThreadIsStillPaused(thread);\n }\n }\n return originalStepThreads.call(this);\n };\n\n // Unpause when green flag\n const originalGreenFlag = vm.runtime.greenFlag;\n vm.runtime.greenFlag = function () {\n setPaused(false);\n return originalGreenFlag.call(this);\n };\n\n // Disable edge-activated hats and hats like \"when key pressed\" while paused.\n const originalStartHats = vm.runtime.startHats;\n vm.runtime.startHats = function (...args) {\n const hat = args[0];\n // These hats can be manually started by the user when paused or while single stepping.\n const isUserInitiated = hat === \"event_whenbroadcastreceived\" || hat === \"control_start_as_clone\";\n if (pauseNewThreads) {\n if (!isUserInitiated && !this.getIsEdgeActivatedHat(hat)) {\n return [];\n }\n const newThreads = originalStartHats.apply(this, args);\n for (const thread of newThreads) {\n pauseThread(thread);\n }\n return newThreads;\n } else if (paused && !isUserInitiated) {\n return [];\n }\n return originalStartHats.apply(this, args);\n };\n\n // Paused threads should not be counted as running when updating GUI state.\n const originalGetMonitorThreadCount = vm.runtime._getMonitorThreadCount;\n vm.runtime._getMonitorThreadCount = function (threads) {\n let count = originalGetMonitorThreadCount.call(this, threads);\n if (paused) {\n for (const thread of threads) {\n if (pausedThreadState.has(thread)) {\n count++;\n }\n }\n }\n return count;\n };\n};\n","import { onPauseChanged, isPaused } from \"./module.js\";\n\nexport default async function createPerformanceTab({ debug, addon, console, msg }) {\n const vm = addon.tab.traps.vm;\n\n await addon.tab.loadScript(addon.self.getResource(\"/thirdparty/cs/chart.min.js\")) /* rewritten by pull.js */;\n\n const tab = debug.createHeaderTab({\n text: msg(\"tab-performance\"),\n icon: addon.self.getResource(\"/icons/performance.svg\") /* rewritten by pull.js */,\n });\n\n const content = Object.assign(document.createElement(\"div\"), {\n className: \"sa-performance-tab-content\",\n });\n\n const createChart = ({ title }) => {\n const titleElement = Object.assign(document.createElement(\"h2\"), {\n textContent: title,\n });\n const canvas = Object.assign(document.createElement(\"canvas\"), {\n className: \"sa-debugger-chart\",\n });\n return {\n title: titleElement,\n canvas,\n };\n };\n\n const now = () => performance.now();\n\n const getMaxFps = () => Math.round(1000 / vm.runtime.currentStepTime);\n\n const NUMBER_OF_POINTS = 20;\n // An array like [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]\n const labels = Array.from(Array(NUMBER_OF_POINTS).keys()).reverse();\n\n const fpsElements = createChart({\n title: msg(\"performance-framerate-title\"),\n });\n const fpsChart = new Chart(fpsElements.canvas.getContext(\"2d\"), {\n type: \"line\",\n data: {\n labels,\n datasets: [\n {\n data: Array(NUMBER_OF_POINTS).fill(-1),\n borderWidth: 1,\n fill: true,\n backgroundColor: \"#29beb8\",\n },\n ],\n },\n options: {\n scales: {\n y: {\n max: getMaxFps(),\n min: 0,\n },\n },\n plugins: {\n legend: {\n display: false,\n },\n tooltip: {\n callbacks: {\n label: (context) => msg(\"performance-framerate-graph-tooltip\", { fps: context.parsed.y }),\n },\n },\n },\n },\n });\n\n const clonesElements = createChart({\n title: msg(\"performance-clonecount-title\"),\n });\n const performanceClonesChart = new Chart(clonesElements.canvas.getContext(\"2d\"), {\n type: \"line\",\n data: {\n labels,\n datasets: [\n {\n data: Array(NUMBER_OF_POINTS).fill(-1),\n borderWidth: 1,\n fill: true,\n backgroundColor: \"#29beb8\",\n },\n ],\n },\n options: {\n scales: {\n y: {\n max: 300,\n min: 0,\n },\n },\n plugins: {\n legend: {\n display: false,\n },\n tooltip: {\n callbacks: {\n label: (context) => msg(\"performance-clonecount-graph-tooltip\", { clones: context.parsed.y }),\n },\n },\n },\n },\n });\n\n // Holds the times of each frame drawn in the last second.\n // The length of this list is effectively the FPS.\n const renderTimes = [];\n\n // The last time we pushed a new datapoint to the graph\n let lastFpsTime = now() + 3000;\n\n debug.addAfterStepCallback(() => {\n if (isPaused()) {\n return;\n }\n const time = now();\n\n // Remove all frame times older than 1 second in renderTimes\n while (renderTimes.length > 0 && renderTimes[0] <= time - 1000) renderTimes.shift();\n renderTimes.push(time);\n\n if (time - lastFpsTime > 1000) {\n lastFpsTime = time;\n\n const maxFps = getMaxFps();\n const fpsData = fpsChart.data.datasets[0].data;\n fpsData.shift();\n fpsData.push(Math.min(renderTimes.length, maxFps));\n // Incase we switch between 30FPS and 60FPS, update the max height of the chart.\n fpsChart.options.scales.y.max = maxFps;\n\n const clonesData = performanceClonesChart.data.datasets[0].data;\n clonesData.shift();\n clonesData.push(vm.runtime._cloneCounter);\n\n if (isVisible) {\n fpsChart.update();\n performanceClonesChart.update();\n }\n }\n });\n\n content.appendChild(fpsElements.title);\n content.appendChild(fpsElements.canvas);\n content.appendChild(clonesElements.title);\n content.appendChild(clonesElements.canvas);\n\n let pauseTime = 0;\n onPauseChanged((paused) => {\n if (paused) {\n pauseTime = now();\n } else {\n const dt = now() - pauseTime;\n lastFpsTime += dt;\n for (var i = 0; i < renderTimes.length; i++) {\n renderTimes[i] += dt;\n }\n }\n });\n\n let isVisible = false;\n const show = () => {\n isVisible = true;\n };\n const hide = () => {\n isVisible = false;\n };\n\n return {\n tab,\n content,\n buttons: [],\n show,\n hide,\n };\n}\n","import { onPauseChanged, isPaused, singleStep, onSingleStep, getRunningThread } from \"./module.js\";\nimport LogView from \"./log-view.js\";\nimport Highlighter from \"../editor-stepping/highlighter.js\";\n\nconst concatInPlace = (copyInto, copyFrom) => {\n for (const i of copyFrom) {\n copyInto.push(i);\n }\n};\n\nexport default async function createThreadsTab({ debug, addon, console, msg }) {\n const vm = addon.tab.traps.vm;\n\n const tab = debug.createHeaderTab({\n text: msg(\"tab-threads\"),\n icon: addon.self.getResource(\"/icons/threads.svg\") /* rewritten by pull.js */,\n });\n\n const logView = new LogView();\n logView.canAutoScrollToEnd = false;\n logView.outerElement.classList.add(\"sa-debugger-threads\");\n logView.placeholderElement.textContent = msg(\"no-threads-running\");\n\n const highlighter = new Highlighter(10, \"#ff0000\");\n\n logView.generateRow = (row) => {\n const root = document.createElement(\"div\");\n root.className = \"sa-debugger-log\";\n\n const isHeader = row.type === \"thread-header\";\n const indenter = document.createElement(\"div\");\n indenter.className = \"sa-debugger-thread-indent\";\n indenter.style.setProperty(\"--level\", isHeader ? row.depth : row.depth + 1);\n root.appendChild(indenter);\n\n if (isHeader) {\n root.classList.add(\"sa-debugger-thread-title\");\n\n if (row.depth > 0) {\n const icon = document.createElement(\"div\");\n icon.className = \"sa-debugger-log-icon\";\n root.appendChild(icon);\n }\n\n const name = document.createElement(\"div\");\n name.textContent = row.targetName;\n name.className = \"sa-debugger-thread-target-name\";\n root.appendChild(name);\n\n const id = document.createElement(\"div\");\n id.className = \"sa-debugger-thread-id\";\n id.textContent = msg(\"thread\", {\n id: row.id,\n });\n root.appendChild(id);\n }\n\n if (row.type === \"thread-stack\") {\n const preview = debug.createBlockPreview(row.targetId, row.blockId);\n if (preview) {\n root.appendChild(preview);\n }\n }\n\n // pm: this isnt very useful if every thread will be compiled\n // if (row.type === \"compiled\") {\n // const el = document.createElement('div');\n // el.className = \"sa-debugger-thread-compiled\";\n // el.textContent = \"Compiled threads can't be stepped and have no stack information.\";\n // root.appendChild(el);\n // }\n\n if (row.targetId && row.blockId) {\n root.appendChild(debug.createBlockLink(debug.getTargetInfoById(row.targetId), row.blockId));\n }\n\n return {\n root,\n };\n };\n\n logView.renderRow = (elements, row) => {\n const { root } = elements;\n root.classList.toggle(\"sa-debugger-thread-running\", !!row.running);\n };\n\n let threadInfoCache = new WeakMap();\n\n const allThreadIds = new WeakMap();\n let nextThreadId = 1;\n const getThreadId = (thread) => {\n if (!allThreadIds.has(thread)) {\n allThreadIds.set(thread, nextThreadId++);\n }\n return allThreadIds.get(thread);\n };\n\n const updateContent = () => {\n if (!logView.visible) {\n return;\n }\n\n const newRows = [];\n const threads = vm.runtime.threads;\n const visitedThreads = new Set();\n\n const createThreadInfo = (thread, depth) => {\n if (visitedThreads.has(thread)) {\n return [];\n }\n visitedThreads.add(thread);\n\n const id = getThreadId(thread);\n const target = thread.target;\n\n if (!threadInfoCache.has(thread)) {\n threadInfoCache.set(thread, {\n headerItem: {\n type: \"thread-header\",\n depth,\n targetName: target.getName(),\n id,\n },\n compiledItem: thread.isCompiled ? {\n type: \"compiled\",\n depth: 1,\n } : null,\n blockCache: new WeakMap(),\n });\n }\n const cacheInfo = threadInfoCache.get(thread);\n\n const runningThread = getRunningThread();\n const createBlockInfo = (block, stackFrameIdx) => {\n const blockId = block.id;\n if (!block) return;\n\n const stackFrame = thread.stackFrames[stackFrameIdx];\n\n if (!cacheInfo.blockCache.has(block)) {\n cacheInfo.blockCache.set(block, {});\n }\n\n const blockInfoMap = cacheInfo.blockCache.get(block);\n let blockInfo = blockInfoMap[stackFrameIdx];\n\n if (!blockInfo) {\n blockInfo = blockInfoMap[stackFrameIdx] = {\n type: \"thread-stack\",\n depth,\n targetId: target.id,\n blockId,\n };\n }\n\n blockInfo.running =\n thread === runningThread && (\n thread.isCompiled || (\n blockId === runningThread.peekStack() &&\n stackFrameIdx === runningThread.stackFrames.length - 1\n )\n );\n\n const result = [blockInfo];\n if (stackFrame && stackFrame.executionContext && stackFrame.executionContext.startedThreads) {\n for (const thread of stackFrame.executionContext.startedThreads) {\n concatInPlace(result, createThreadInfo(thread, depth + 1));\n }\n }\n\n return result;\n };\n\n const topBlock = debug.getBlock(thread.target, thread.topBlock);\n const result = [cacheInfo.headerItem];\n if (topBlock) {\n concatInPlace(result, createBlockInfo(topBlock, 0));\n for (let i = 0; i < thread.stack.length; i++) {\n const blockId = thread.stack[i];\n if (blockId === topBlock.id) continue;\n const block = debug.getBlock(thread.target, blockId);\n if (block) {\n concatInPlace(result, createBlockInfo(block, i));\n }\n }\n }\n\n if (cacheInfo.compiledItem) {\n result.push(cacheInfo.compiledItem);\n }\n\n return result;\n };\n\n for (let i = 0; i < threads.length; i++) {\n const thread = threads[i];\n // Do not display threads used to update variable and list monitors.\n if (thread.updateMonitor) {\n continue;\n }\n concatInPlace(newRows, createThreadInfo(thread, 0));\n }\n\n logView.rows = newRows;\n logView.queueUpdateContent();\n };\n\n debug.addAfterStepCallback(() => {\n updateContent();\n\n const runningThread = getRunningThread();\n if (runningThread) {\n highlighter.setGlowingThreads([runningThread]);\n } else {\n highlighter.setGlowingThreads([]);\n }\n });\n\n const stepButton = debug.createHeaderButton({\n text: msg(\"step\"),\n icon: addon.self.getResource(\"/icons/step.svg\") /* rewritten by pull.js */,\n description: msg(\"step-desc\"),\n });\n stepButton.element.addEventListener(\"click\", () => {\n singleStep();\n });\n\n const handlePauseChanged = (paused) => {\n stepButton.element.style.display = paused ? \"\" : \"none\";\n updateContent();\n };\n handlePauseChanged(isPaused());\n onPauseChanged(handlePauseChanged);\n\n onSingleStep(updateContent);\n\n const show = () => {\n logView.show();\n updateContent();\n };\n const hide = () => {\n logView.hide();\n };\n\n return {\n tab,\n content: logView.outerElement,\n buttons: [stepButton],\n show,\n hide,\n };\n}\n","import { isPaused, setPaused, onPauseChanged, setup } from \"./module.js\";\nimport createLogsTab from \"./logs.js\";\nimport createThreadsTab from \"./threads.js\";\nimport createPerformanceTab from \"./performance.js\";\nimport Utils from \"../find-bar/blockly/Utils.js\";\n\nconst removeAllChildren = (element) => {\n while (element.firstChild) {\n element.removeChild(element.firstChild);\n }\n};\n\nexport default async function ({ addon, console, msg }) {\n setup(addon.tab.traps.vm);\n\n let logsTab;\n const messagesLoggedBeforeLogsTabLoaded = [];\n const logMessage = (...args) => {\n if (logsTab) {\n logsTab.addLog(...args);\n } else {\n messagesLoggedBeforeLogsTabLoaded.push(args);\n }\n };\n\n let hasLoggedPauseError = false;\n const pause = (_, thread) => {\n if (addon.tab.redux.state.scratchGui.mode.isPlayerOnly) {\n if (!hasLoggedPauseError) {\n logMessage(msg(\"cannot-pause-player\"), thread, \"error\");\n hasLoggedPauseError = true;\n }\n return;\n }\n setPaused(true);\n setInterfaceVisible(true);\n };\n addon.tab.addBlock(\"\\u200B\\u200Bbreakpoint\\u200B\\u200B\", {\n args: [],\n displayName: msg(\"block-breakpoint\"),\n callback: pause,\n });\n addon.tab.addBlock(\"\\u200B\\u200Blog\\u200B\\u200B %s\", {\n args: [\"content\"],\n displayName: msg(\"block-log\"),\n callback: ({ content }, thread) => {\n logMessage(content, thread, \"log\");\n },\n });\n addon.tab.addBlock(\"\\u200B\\u200Bwarn\\u200B\\u200B %s\", {\n args: [\"content\"],\n displayName: msg(\"block-warn\"),\n callback: ({ content }, thread) => {\n logMessage(content, thread, \"warn\");\n },\n });\n addon.tab.addBlock(\"\\u200B\\u200Berror\\u200B\\u200B %s\", {\n args: [\"content\"],\n displayName: msg(\"block-error\"),\n callback: ({ content }, thread) => {\n logMessage(content, thread, \"error\");\n },\n });\n\n const vm = addon.tab.traps.vm;\n await new Promise((resolve, reject) => {\n if (vm.editingTarget) return resolve();\n vm.runtime.once(\"PROJECT_LOADED\", resolve);\n });\n const ScratchBlocks = await addon.tab.traps.getBlockly();\n\n const debuggerButtonOuter = document.createElement(\"div\");\n debuggerButtonOuter.className = \"sa-debugger-container\";\n const debuggerButton = document.createElement(\"div\");\n debuggerButton.className = addon.tab.scratchClass(\"button_outlined-button\", \"stage-header_stage-button\");\n const debuggerButtonContent = document.createElement(\"div\");\n debuggerButtonContent.className = addon.tab.scratchClass(\"button_content\");\n const debuggerButtonImage = document.createElement(\"img\");\n debuggerButtonImage.className = addon.tab.scratchClass(\"stage-header_stage-button-icon\");\n debuggerButtonImage.draggable = false;\n debuggerButtonImage.src = addon.self.getResource(\"/icons/debug.svg\") /* rewritten by pull.js */;\n debuggerButtonContent.appendChild(debuggerButtonImage);\n debuggerButton.appendChild(debuggerButtonContent);\n debuggerButtonOuter.appendChild(debuggerButton);\n debuggerButton.addEventListener(\"click\", () => setInterfaceVisible(true));\n\n const setHasUnreadMessage = (unreadMessage) => {\n debuggerButtonContent.classList.toggle(\"sa-debugger-unread\", unreadMessage);\n };\n\n const interfaceContainer = Object.assign(document.createElement(\"div\"), {\n className: addon.tab.scratchClass(\"card_card\", { others: \"sa-debugger-interface\" }),\n });\n const interfaceHeader = Object.assign(document.createElement(\"div\"), {\n className: addon.tab.scratchClass(\"card_header-buttons\"),\n });\n const tabListElement = Object.assign(document.createElement(\"ul\"), {\n className: \"sa-debugger-tabs\",\n });\n const buttonContainerElement = Object.assign(document.createElement(\"div\"), {\n className: addon.tab.scratchClass(\"card_header-buttons-right\", { others: \"sa-debugger-header-buttons\" }),\n });\n const tabContentContainer = Object.assign(document.createElement(\"div\"), {\n className: \"sa-debugger-tab-content\",\n });\n\n const compilerWarning = document.createElement(\"a\");\n compilerWarning.addEventListener(\"click\", () => {\n addon.tab.redux.dispatch({\n type: \"scratch-gui/modals/OPEN_MODAL\",\n modal: \"settingsModal\"\n });\n });\n compilerWarning.className = \"sa-debugger-log sa-debugger-compiler-warning\";\n compilerWarning.textContent = \"The debugger works best when the compiler is disabled.\";\n const updateCompilerWarningVisibility = () => {\n // compilerWarning.hidden = !vm.runtime.compilerOptions.enabled;\n compilerWarning.hidden = true;\n };\n vm.on(\"COMPILER_OPTIONS_CHANGED\", updateCompilerWarningVisibility);\n updateCompilerWarningVisibility();\n\n let isInterfaceVisible = false;\n const setInterfaceVisible = (_isVisible) => {\n isInterfaceVisible = _isVisible;\n interfaceContainer.style.display = isInterfaceVisible ? \"flex\" : \"\";\n if (isInterfaceVisible) {\n activeTab.show();\n } else {\n activeTab.hide();\n }\n };\n\n let mouseOffsetX = 0;\n let mouseOffsetY = 0;\n let lastX = 0;\n let lastY = 0;\n const handleStartDrag = (e) => {\n e.preventDefault();\n mouseOffsetX = e.clientX - interfaceContainer.offsetLeft;\n mouseOffsetY = e.clientY - interfaceContainer.offsetTop;\n lastX = e.clientX;\n lastY = e.clientY;\n document.addEventListener(\"mouseup\", handleStopDrag);\n document.addEventListener(\"mousemove\", handleDragInterface);\n };\n const handleStopDrag = () => {\n document.removeEventListener(\"mouseup\", handleStopDrag);\n document.removeEventListener(\"mousemove\", handleDragInterface);\n };\n const moveInterface = (x, y) => {\n lastX = x;\n lastY = y;\n const width = (document.documentElement.clientWidth || document.body.clientWidth) - 1;\n const height = (document.documentElement.clientHeight || document.body.clientHeight) - 1;\n const clampedX = Math.max(0, Math.min(x - mouseOffsetX, width - interfaceContainer.offsetWidth));\n const clampedY = Math.max(0, Math.min(y - mouseOffsetY, height - interfaceContainer.offsetHeight));\n interfaceContainer.style.left = clampedX + \"px\";\n interfaceContainer.style.top = clampedY + \"px\";\n };\n const handleDragInterface = (e) => {\n e.preventDefault();\n moveInterface(e.clientX, e.clientY);\n };\n window.addEventListener(\"resize\", () => {\n moveInterface(lastX, lastY);\n });\n interfaceHeader.addEventListener(\"mousedown\", handleStartDrag);\n\n interfaceHeader.append(tabListElement, buttonContainerElement);\n interfaceContainer.append(interfaceHeader, compilerWarning, tabContentContainer);\n document.body.append(interfaceContainer);\n\n const createHeaderButton = ({ text, icon, description }) => {\n const button = Object.assign(document.createElement(\"div\"), {\n className: addon.tab.scratchClass(\"card_shrink-expand-button\"),\n draggable: false,\n });\n if (description) {\n button.title = description;\n }\n const imageElement = Object.assign(document.createElement(\"img\"), {\n src: icon,\n draggable: false,\n });\n const textElement = Object.assign(document.createElement(\"span\"), {\n textContent: text,\n });\n button.appendChild(imageElement);\n button.appendChild(textElement);\n return {\n element: button,\n image: imageElement,\n text: textElement,\n };\n };\n\n const createHeaderTab = ({ text, icon }) => {\n const tab = document.createElement(\"li\");\n const imageElement = Object.assign(document.createElement(\"img\"), {\n src: icon,\n draggable: false,\n });\n const textElement = Object.assign(document.createElement(\"span\"), {\n textContent: text,\n });\n tab.appendChild(imageElement);\n tab.appendChild(textElement);\n return {\n element: tab,\n image: imageElement,\n text: textElement,\n };\n };\n\n const unpauseButton = createHeaderButton({\n text: msg(\"unpause\"),\n icon: addon.self.getResource(\"/icons/play.svg\") /* rewritten by pull.js */,\n });\n unpauseButton.element.classList.add(\"sa-debugger-unpause\");\n unpauseButton.element.addEventListener(\"click\", () => setPaused(false));\n const updateUnpauseVisibility = (paused) => {\n unpauseButton.element.style.display = paused ? \"\" : \"none\";\n };\n updateUnpauseVisibility(isPaused());\n onPauseChanged(updateUnpauseVisibility);\n\n const closeButton = createHeaderButton({\n text: msg(\"close\"),\n icon: addon.self.getResource(\"/icons/close.svg\") /* rewritten by pull.js */,\n });\n closeButton.element.addEventListener(\"click\", () => setInterfaceVisible(false));\n\n const originalStep = vm.runtime._step;\n const afterStepCallbacks = [];\n vm.runtime._step = function (...args) {\n const ret = originalStep.call(this, ...args);\n for (const cb of afterStepCallbacks) {\n cb();\n }\n return ret;\n };\n const addAfterStepCallback = (cb) => {\n afterStepCallbacks.push(cb);\n };\n\n const getBlock = (target, id) => target.blocks.getBlock(id) || vm.runtime.flyoutBlocks.getBlock(id);\n\n const getTargetInfoById = (id) => {\n const target = vm.runtime.getTargetById(id);\n if (target) {\n let name = target.getName();\n let original = target;\n if (!target.isOriginal) {\n name = msg(\"clone-of\", {\n sprite: name,\n });\n original = target.sprite.clones[0];\n }\n return {\n exists: true,\n originalId: original.id,\n name,\n };\n }\n return {\n exists: false,\n original: null,\n name: msg(\"unknown-sprite\"),\n };\n };\n\n const createBlockLink = (targetInfo, blockId) => {\n const link = document.createElement(\"a\");\n link.className = \"sa-debugger-log-link\";\n\n const { exists, name, originalId } = targetInfo;\n link.textContent = name;\n if (exists) {\n // We use mousedown instead of click so that you can still go to blocks when logs are rapidly scrolling\n link.addEventListener(\"mousedown\", () => {\n switchToSprite(originalId);\n activateCodeTab();\n goToBlock(blockId);\n });\n } else {\n link.classList.add(\"sa-debugger-log-link-unknown\");\n }\n\n return link;\n };\n\n const switchToSprite = (targetId) => {\n if (targetId !== vm.editingTarget.id) {\n if (vm.runtime.getTargetById(targetId)) {\n vm.setEditingTarget(targetId);\n }\n }\n };\n\n const activateCodeTab = () => {\n const redux = addon.tab.redux;\n if (redux.state.scratchGui.editorTab.activeTabIndex !== 0) {\n redux.dispatch({\n type: \"scratch-gui/navigation/ACTIVATE_TAB\",\n activeTabIndex: 0,\n });\n }\n };\n\n const goToBlock = (blockId) => {\n const workspace = Blockly.getMainWorkspace();\n const block = workspace.getBlockById(blockId);\n if (!block) return;\n\n // Don't scroll to blocks in the flyout\n if (block.workspace.isFlyout) return;\n\n new Utils(addon).scrollBlockIntoView(blockId);\n };\n\n /**\n * @param {string} procedureCode\n * @returns {string}\n */\n const formatProcedureCode = (procedureCode) => {\n const customBlock = addon.tab.getCustomBlock(procedureCode);\n if (customBlock) {\n procedureCode = customBlock.displayName;\n }\n // May be slightly incorrect in some edge cases.\n return procedureCode.replace(/%[nbs]/g, \"()\");\n };\n\n // May be slightly incorrect in some edge cases.\n const formatBlocklyBlockData = (jsonData) => {\n // For sample jsonData, see:\n // https://github.com/LLK/scratch-blocks/blob/0bd1a17e66a779ec5d11f4a00c43784e3ac7a7b8/blocks_vertical/motion.js\n // https://github.com/LLK/scratch-blocks/blob/0bd1a17e66a779ec5d11f4a00c43784e3ac7a7b8/blocks_vertical/control.js\n\n const processSegment = (index) => {\n const message = jsonData[`message${index}`];\n const args = jsonData[`args${index}`];\n if (!message) {\n return null;\n }\n const parts = message.split(/%\\d+/g);\n let formattedMessage = \"\";\n for (let i = 0; i < parts.length; i++) {\n formattedMessage += parts[i];\n const argInfo = args && args[i];\n if (argInfo) {\n const type = argInfo.type;\n if (type === \"field_vertical_separator\") {\n // no-op\n } else if (type === \"field_image\") {\n const src = argInfo.src;\n if (src.endsWith(\"rotate-left.svg\")) {\n formattedMessage += \"↩\";\n } else if (src.endsWith(\"rotate-right.svg\")) {\n formattedMessage += \"↪\";\n }\n } else {\n formattedMessage += \"()\";\n }\n }\n }\n return formattedMessage;\n };\n\n const parts = [];\n let i = 0;\n // The jsonData doesn't directly tell us how many segments it has, so we have to\n // just keep looping until one doesn't exist.\n while (true) {\n const nextSegment = processSegment(i);\n if (nextSegment) {\n parts.push(nextSegment);\n } else {\n break;\n }\n i++;\n }\n return parts.join(\" \");\n };\n\n const createBlockPreview = (targetId, blockId) => {\n const target = vm.runtime.getTargetById(targetId);\n if (!target) {\n return null;\n }\n\n const block = getBlock(target, blockId);\n if (!block || block.opcode === \"text\") {\n return null;\n }\n\n let text;\n let category;\n let shape;\n if (\n block.opcode === \"data_variable\" ||\n block.opcode === \"data_listcontents\" ||\n block.opcode === \"argument_reporter_string_number\" ||\n block.opcode === \"argument_reporter_boolean\"\n ) {\n text = Object.values(block.fields)[0].value;\n if (block.opcode === \"data_variable\") {\n category = \"data\";\n } else if (block.opcode === \"data_listcontents\") {\n category = \"list\";\n } else {\n category = \"more\";\n }\n shape = \"round\";\n } else if (block.opcode === \"procedures_call\") {\n const proccode = block.mutation.proccode;\n text = formatProcedureCode(proccode);\n const customBlock = addon.tab.getCustomBlock(proccode);\n if (customBlock) {\n category = \"addon-custom-block\";\n } else {\n category = \"more\";\n }\n } else if (block.opcode === \"procedures_definition\" || block.opcode === \"procedures_definition_return\") {\n const prototypeBlockId = block.inputs.custom_block.block;\n const prototypeBlock = getBlock(target, prototypeBlockId);\n const proccode = prototypeBlock.mutation.proccode;\n text = ScratchBlocks.ScratchMsgs.translate(\"PROCEDURES_DEFINITION\", \"define %1\").replace(\n \"%1\",\n formatProcedureCode(proccode)\n );\n category = \"more\";\n } else {\n // Try to call things like https://github.com/LLK/scratch-blocks/blob/0bd1a17e66a779ec5d11f4a00c43784e3ac7a7b8/blocks_vertical/operators.js#L36\n var jsonData;\n const fakeBlock = {\n jsonInit(data) {\n jsonData = data;\n },\n };\n const blockConstructor = ScratchBlocks.Blocks[block.opcode];\n if (blockConstructor) {\n try {\n blockConstructor.init.call(fakeBlock);\n } catch (e) {\n // ignore\n }\n }\n if (!jsonData) {\n return null;\n }\n text = formatBlocklyBlockData(jsonData);\n if (!text) {\n return null;\n }\n // jsonData.extensions is not guaranteed to exist\n category = jsonData.extensions?.includes(\"scratch_extension\") ? \"pen\" : jsonData.category;\n const isStatement =\n (jsonData.extensions &&\n (jsonData.extensions.includes(\"shape_statement\") ||\n jsonData.extensions.includes(\"shape_hat\") ||\n jsonData.extensions.includes(\"shape_end\"))) ||\n \"previousStatement\" in jsonData ||\n \"nextStatement\" in jsonData;\n shape = isStatement ? \"stacked\" : \"round\";\n }\n if (!text || !category) {\n return null;\n }\n\n const element = document.createElement(\"span\");\n element.className = \"sa-debugger-block-preview sa-block-color\";\n element.textContent = text;\n element.dataset.shape = shape;\n\n element.classList.add(`sa-block-color-${category}`);\n\n return element;\n };\n\n const api = {\n debug: {\n createHeaderButton,\n createHeaderTab,\n setHasUnreadMessage,\n addAfterStepCallback,\n getBlock,\n getTargetInfoById,\n createBlockLink,\n createBlockPreview,\n },\n addon,\n msg,\n console,\n };\n logsTab = await createLogsTab(api);\n const threadsTab = await createThreadsTab(api);\n const allTabs = [logsTab, threadsTab];\n\n for (const message of messagesLoggedBeforeLogsTabLoaded) {\n logsTab.addLog(...message);\n }\n messagesLoggedBeforeLogsTabLoaded.length = 0;\n\n let activeTab;\n const setActiveTab = (tab) => {\n if (tab === activeTab) return;\n const selectedClass = \"sa-debugger-tab-selected\";\n if (activeTab) {\n activeTab.hide();\n activeTab.tab.element.classList.remove(selectedClass);\n }\n tab.tab.element.classList.add(selectedClass);\n activeTab = tab;\n\n removeAllChildren(tabContentContainer);\n tabContentContainer.appendChild(tab.content);\n\n removeAllChildren(buttonContainerElement);\n buttonContainerElement.appendChild(unpauseButton.element);\n for (const button of tab.buttons) {\n buttonContainerElement.appendChild(button.element);\n }\n buttonContainerElement.appendChild(closeButton.element);\n\n if (isInterfaceVisible) {\n activeTab.show();\n }\n };\n for (const tab of allTabs) {\n tab.tab.element.addEventListener(\"click\", () => {\n setActiveTab(tab);\n });\n tabListElement.appendChild(tab.tab.element);\n }\n setActiveTab(allTabs[0]);\n\n if (addon.tab.redux.state && addon.tab.redux.state.scratchGui.stageSize.stageSize === \"small\") {\n document.body.classList.add(\"sa-debugger-small\");\n }\n document.addEventListener(\n \"click\",\n (e) => {\n if (e.target.closest(\"[class*='stage-header_stage-button-first']:not(.sa-hide-stage-button)\")) {\n document.body.classList.add(\"sa-debugger-small\");\n } else if (\n e.target.closest(\"[class*='stage-header_stage-button-last']\") ||\n e.target.closest(\".sa-hide-stage-button\")\n ) {\n document.body.classList.remove(\"sa-debugger-small\");\n }\n },\n { capture: true }\n );\n\n const ogGreenFlag = vm.runtime.greenFlag;\n vm.runtime.greenFlag = function (...args) {\n if (addon.settings.get(\"log_clear_greenflag\")) {\n logsTab.clearLogs();\n }\n if (addon.settings.get(\"log_greenflag\")) {\n logsTab.addLog(msg(\"log-msg-flag-clicked\"), null, \"internal\");\n }\n return ogGreenFlag.call(this, ...args);\n };\n\n const ogMakeClone = vm.runtime.targets[0].constructor.prototype.makeClone;\n vm.runtime.targets[0].constructor.prototype.makeClone = function (...args) {\n if (addon.settings.get(\"log_failed_clone_creation\") && !vm.runtime.clonesAvailable()) {\n logsTab.addLog(\n msg(\"log-msg-clone-cap\", { sprite: this.getName() }),\n vm.runtime.sequencer.activeThread,\n \"internal-warn\"\n );\n }\n var clone = ogMakeClone.call(this, ...args);\n if (addon.settings.get(\"log_clone_create\") && clone) {\n logsTab.addLog(\n msg(\"log-msg-clone-created\", { sprite: this.getName() }),\n vm.runtime.sequencer.activeThread,\n \"internal\"\n );\n }\n return clone;\n };\n\n const ogStartHats = vm.runtime.startHats;\n vm.runtime.startHats = function (hat, optMatchFields, ...args) {\n if (addon.settings.get(\"log_broadcasts\") && hat === \"event_whenbroadcastreceived\") {\n logsTab.addLog(\n msg(\"log-msg-broadcasted\", { broadcast: optMatchFields.BROADCAST_OPTION }),\n vm.runtime.sequencer.activeThread,\n \"internal\"\n );\n }\n return ogStartHats.call(this, hat, optMatchFields, ...args);\n };\n\n while (true) {\n await addon.tab.waitForElement('[class*=\"stage-header_stage-size-row\"]', {\n markAsSeen: true,\n reduxEvents: [\n \"scratch-gui/mode/SET_PLAYER\",\n \"scratch-gui/mode/SET_FULL_SCREEN\",\n \"fontsLoaded/SET_FONTS_LOADED\",\n \"scratch-gui/locales/SELECT_LOCALE\",\n ],\n });\n if (addon.tab.editorMode === \"editor\") {\n addon.tab.appendToSharedSpace({ space: \"stageHeader\", element: debuggerButtonOuter, order: 0 });\n } else {\n setInterfaceVisible(false);\n }\n }\n}\n","const SVG_NS = \"http://www.w3.org/2000/svg\";\n\nconst containerSvg = document.createElementNS(SVG_NS, \"svg\");\n// unfortunately we can't use display: none on this as that breaks filters\ncontainerSvg.style.position = \"fixed\";\ncontainerSvg.style.top = \"-999999px\";\ncontainerSvg.style.width = \"0\";\ncontainerSvg.style.height = \"0\";\ndocument.body.appendChild(containerSvg);\n\nlet nextGlowerId = 0;\n\nconst highlightsPerElement = new WeakMap();\n\nconst getHighlightersForElement = (element) => {\n if (!highlightsPerElement.get(element)) {\n highlightsPerElement.set(element, new Set());\n }\n return highlightsPerElement.get(element);\n};\n\nconst updateHighlight = (element, highlighters) => {\n let result;\n for (const i of highlighters) {\n if (!result || i.priority > result.priority) {\n result = i;\n }\n }\n if (result) {\n element.style.filter = result.filter;\n } else {\n element.style.filter = \"\";\n }\n};\n\nconst addHighlight = (element, highlighter) => {\n const highlighters = getHighlightersForElement(element);\n highlighters.add(highlighter);\n updateHighlight(element, highlighters);\n};\n\nconst removeHighlight = (element, highlighter) => {\n const highlighters = getHighlightersForElement(element);\n highlighters.delete(highlighter);\n updateHighlight(element, highlighters);\n};\n\nclass Highlighter {\n constructor(priority, color) {\n this.priority = priority;\n\n const id = `sa_glower_filter${nextGlowerId++}`;\n this.filter = `url(\"#${id}\")`;\n\n this.previousElements = new Set();\n\n const filterElement = document.createElementNS(SVG_NS, \"filter\");\n filterElement.id = id;\n filterElement.setAttribute(\"width\", \"180%\");\n filterElement.setAttribute(\"height\", \"160%\");\n filterElement.setAttribute(\"x\", \"-40%\");\n filterElement.setAttribute(\"y\", \"-30%\");\n\n const filterBlur = document.createElementNS(SVG_NS, \"feGaussianBlur\");\n filterBlur.setAttribute(\"in\", \"SourceGraphic\");\n filterBlur.setAttribute(\"stdDeviation\", \"4\");\n filterElement.appendChild(filterBlur);\n\n const filterTransfer = document.createElementNS(SVG_NS, \"feComponentTransfer\");\n filterTransfer.setAttribute(\"result\", \"outBlur\");\n filterElement.appendChild(filterTransfer);\n\n const filterTransferTable = document.createElementNS(SVG_NS, \"feFuncA\");\n filterTransferTable.setAttribute(\"type\", \"table\");\n filterTransferTable.setAttribute(\"tableValues\", \"0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\");\n filterTransfer.appendChild(filterTransferTable);\n\n const filterFlood = document.createElementNS(SVG_NS, \"feFlood\");\n filterFlood.setAttribute(\"flood-opacity\", \"1\");\n filterFlood.setAttribute(\"result\", \"outColor\");\n filterElement.appendChild(filterFlood);\n this.filterFlood = filterFlood;\n\n const filterComposite = document.createElementNS(SVG_NS, \"feComposite\");\n filterComposite.setAttribute(\"in\", \"outColor\");\n filterComposite.setAttribute(\"in2\", \"outBlur\");\n filterComposite.setAttribute(\"operator\", \"in\");\n filterComposite.setAttribute(\"result\", \"outGlow\");\n filterElement.appendChild(filterComposite);\n\n const filterFinalComposite = document.createElementNS(SVG_NS, \"feComposite\");\n filterFinalComposite.setAttribute(\"in\", \"SourceGraphic\");\n filterFinalComposite.setAttribute(\"in2\", \"outGlow\");\n filterFinalComposite.setAttribute(\"operator\", \"over\");\n filterElement.appendChild(filterFinalComposite);\n\n containerSvg.appendChild(filterElement);\n this.setColor(color);\n }\n\n setColor(color) {\n this.filterFlood.setAttribute(\"flood-color\", color);\n }\n\n setGlowingThreads(threads) {\n const elementsToHighlight = new Set();\n const workspace = Blockly.getMainWorkspace();\n\n if (workspace) {\n for (const thread of threads) {\n thread.stack.forEach((blockId) => {\n const block = workspace.getBlockById(blockId);\n if (!block) {\n return;\n }\n const childblock = thread.stack.find((i) => {\n let b = block;\n while (b.childBlocks_.length) {\n b = b.childBlocks_[b.childBlocks_.length - 1];\n if (i === b.id) return true;\n }\n return false;\n });\n if (!childblock && block.svgPath_) {\n const svgPath = block.svgPath_;\n elementsToHighlight.add(svgPath);\n }\n });\n }\n }\n\n for (const element of this.previousElements) {\n if (!elementsToHighlight.has(element)) {\n removeHighlight(element, this);\n }\n }\n for (const element of elementsToHighlight) {\n if (!this.previousElements.has(element)) {\n addHighlight(element, this);\n }\n }\n this.previousElements = elementsToHighlight;\n }\n}\n\nexport default Highlighter;\n","// From https://github.com/LLK/scratch-gui/blob/develop/src/lib/download-blob.js\nexport default (filename, blob) => {\n const downloadLink = document.createElement(\"a\");\n document.body.appendChild(downloadLink);\n\n // Use special ms version if available to get it working on Edge.\n if (navigator.msSaveOrOpenBlob) {\n navigator.msSaveOrOpenBlob(blob, filename);\n return;\n }\n\n if (\"download\" in HTMLAnchorElement.prototype) {\n const url = window.URL.createObjectURL(blob);\n downloadLink.href = url;\n downloadLink.download = filename;\n downloadLink.type = blob.type;\n downloadLink.click();\n // remove the link after a timeout to prevent a crash on iOS 13 Safari\n window.setTimeout(() => {\n document.body.removeChild(downloadLink);\n window.URL.revokeObjectURL(url);\n }, 1000);\n } else {\n // iOS 12 Safari, open a new page and set href to data-uri\n let popup = window.open(\"\", \"_blank\");\n const reader = new FileReader();\n reader.onloadend = function () {\n popup.location.href = reader.result;\n popup = null;\n };\n reader.readAsDataURL(blob);\n }\n};\n"],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACPA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC9BA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACnBA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACnBA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;ACnBA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAGA;AACA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;ACtOA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAEA;AAGA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC9LA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAEA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAOA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvaA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACpLA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAQA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC3PA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAGA;AACA;AACA;AAIA;AACA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AANA;AAAA;AAOA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AAPA;AAAA;AAQA;AACA;AACA;AACA;AAAA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAIA;AAAA;AAPA;AAAA;AAQA;AACA;AAEA;AACA;AACA;AACA;AAMA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvmBA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;;;;;;;;;;;;ACjJA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;A","sourceRoot":""}