"+n.content+""+n.tag+">"},!g.document)return g.addEventListener&&(C.disableWorkerMessageHandler||g.addEventListener("message",function(e){var a=JSON.parse(e.data),n=a.language,t=a.code,r=a.immediateClose;g.postMessage(C.highlight(t,C.languages[n],n)),r&&g.close()},!1)),C;var e=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return e&&(C.filename=e.src,C.manual||e.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(C.highlightAll):window.setTimeout(C.highlightAll,16):document.addEventListener("DOMContentLoaded",C.highlightAll))),C}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism);
4 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,boolean:/\b(?:true|false)\b/,function:/\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/};
5 | Prism.languages.wasm={comment:[/\(;[\s\S]*?;\)/,{pattern:/;;.*/,greedy:!0}],string:{pattern:/"(?:\\[\s\S]|[^"\\])*"/,greedy:!0},keyword:[{pattern:/\b(?:align|offset)=/,inside:{operator:/=/}},{pattern:/\b(?:(?:f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))?|memory\.(?:grow|size))\b/,inside:{punctuation:/\./}},/\b(?:anyfunc|block|br(?:_if|_table)?|call(?:_indirect)?|data|drop|elem|else|end|export|func|get_(?:global|local)|global|if|import|local|loop|memory|module|mut|nop|offset|param|result|return|select|set_(?:global|local)|start|table|tee_local|then|type|unreachable)\b/],variable:/\$[\w!#$%&'*+\-./:<=>?@\\^_`|~]+/i,number:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/,punctuation:/[()]/};
6 |
--------------------------------------------------------------------------------
/extension/css/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /* Document
4 | ========================================================================== */
5 |
6 | /**
7 | * 1. Correct the line height in all browsers.
8 | * 2. Prevent adjustments of font size after orientation changes in iOS.
9 | */
10 |
11 | html {
12 | line-height: 1.15;
13 | /* 1 */
14 | -webkit-text-size-adjust: 100%;
15 | /* 2 */
16 | }
17 |
18 | /* Sections
19 | ========================================================================== */
20 |
21 | /**
22 | * Remove the margin in all browsers.
23 | */
24 |
25 | body {
26 | margin: 0;
27 | }
28 |
29 | /**
30 | * Render the `main` element consistently in IE.
31 | */
32 |
33 | main {
34 | display: block;
35 | }
36 |
37 | /**
38 | * Correct the font size and margin on `h1` elements within `section` and
39 | * `article` contexts in Chrome, Firefox, and Safari.
40 | */
41 |
42 | h1 {
43 | font-size: 2em;
44 | margin: 0.67em 0;
45 | }
46 |
47 | /* Grouping content
48 | ========================================================================== */
49 |
50 | /**
51 | * 1. Add the correct box sizing in Firefox.
52 | * 2. Show the overflow in Edge and IE.
53 | */
54 |
55 | hr {
56 | box-sizing: content-box;
57 | /* 1 */
58 | height: 0;
59 | /* 1 */
60 | overflow: visible;
61 | /* 2 */
62 | }
63 |
64 | /**
65 | * 1. Correct the inheritance and scaling of font size in all browsers.
66 | * 2. Correct the odd `em` font sizing in all browsers.
67 | */
68 |
69 | pre {
70 | font-family: monospace, monospace;
71 | /* 1 */
72 | font-size: 1em;
73 | /* 2 */
74 | }
75 |
76 | /* Text-level semantics
77 | ========================================================================== */
78 |
79 | /**
80 | * Remove the gray background on active links in IE 10.
81 | */
82 |
83 | a {
84 | background-color: transparent;
85 | }
86 |
87 | /**
88 | * 1. Remove the bottom border in Chrome 57-
89 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
90 | */
91 |
92 | abbr[title] {
93 | border-bottom: none;
94 | /* 1 */
95 | text-decoration: underline;
96 | /* 2 */
97 | text-decoration: underline dotted;
98 | /* 2 */
99 | }
100 |
101 | /**
102 | * Add the correct font weight in Chrome, Edge, and Safari.
103 | */
104 |
105 | b, strong {
106 | font-weight: bolder;
107 | }
108 |
109 | /**
110 | * 1. Correct the inheritance and scaling of font size in all browsers.
111 | * 2. Correct the odd `em` font sizing in all browsers.
112 | */
113 |
114 | code, kbd, samp {
115 | font-family: monospace, monospace;
116 | /* 1 */
117 | font-size: 1em;
118 | /* 2 */
119 | }
120 |
121 | /**
122 | * Add the correct font size in all browsers.
123 | */
124 |
125 | small {
126 | font-size: 80%;
127 | }
128 |
129 | /**
130 | * Prevent `sub` and `sup` elements from affecting the line height in
131 | * all browsers.
132 | */
133 |
134 | sub, sup {
135 | font-size: 75%;
136 | line-height: 0;
137 | position: relative;
138 | vertical-align: baseline;
139 | }
140 |
141 | sub {
142 | bottom: -0.25em;
143 | }
144 |
145 | sup {
146 | top: -0.5em;
147 | }
148 |
149 | /* Embedded content
150 | ========================================================================== */
151 |
152 | /**
153 | * Remove the border on images inside links in IE 10.
154 | */
155 |
156 | img {
157 | border-style: none;
158 | }
159 |
160 | /* Forms
161 | ========================================================================== */
162 |
163 | /**
164 | * 1. Change the font styles in all browsers.
165 | * 2. Remove the margin in Firefox and Safari.
166 | */
167 |
168 | button, input, optgroup, select, textarea {
169 | font-family: inherit;
170 | /* 1 */
171 | font-size: 100%;
172 | /* 1 */
173 | line-height: 1.15;
174 | /* 1 */
175 | margin: 0;
176 | /* 2 */
177 | }
178 |
179 | /**
180 | * Show the overflow in IE.
181 | * 1. Show the overflow in Edge.
182 | */
183 |
184 | button, input {
185 | /* 1 */
186 | overflow: visible;
187 | }
188 |
189 | /**
190 | * Remove the inheritance of text transform in Edge, Firefox, and IE.
191 | * 1. Remove the inheritance of text transform in Firefox.
192 | */
193 |
194 | button, select {
195 | /* 1 */
196 | text-transform: none;
197 | }
198 |
199 | /**
200 | * Correct the inability to style clickable types in iOS and Safari.
201 | */
202 |
203 | button, [type='button'], [type='reset'], [type='submit'] {
204 | -webkit-appearance: button;
205 | }
206 |
207 | /**
208 | * Remove the inner border and padding in Firefox.
209 | */
210 |
211 | button::-moz-focus-inner, [type='button']::-moz-focus-inner, [type='reset']::-moz-focus-inner, [type='submit']::-moz-focus-inner {
212 | border-style: none;
213 | padding: 0;
214 | }
215 |
216 | /**
217 | * Restore the focus styles unset by the previous rule.
218 | */
219 |
220 | button:-moz-focusring, [type='button']:-moz-focusring, [type='reset']:-moz-focusring, [type='submit']:-moz-focusring {
221 | outline: 1px dotted ButtonText;
222 | }
223 |
224 | /**
225 | * Correct the padding in Firefox.
226 | */
227 |
228 | fieldset {
229 | padding: 0.35em 0.75em 0.625em;
230 | }
231 |
232 | /**
233 | * 1. Correct the text wrapping in Edge and IE.
234 | * 2. Correct the color inheritance from `fieldset` elements in IE.
235 | * 3. Remove the padding so developers are not caught out when they zero out
236 | * `fieldset` elements in all browsers.
237 | */
238 |
239 | legend {
240 | box-sizing: border-box;
241 | /* 1 */
242 | color: inherit;
243 | /* 2 */
244 | display: table;
245 | /* 1 */
246 | max-width: 100%;
247 | /* 1 */
248 | padding: 0;
249 | /* 3 */
250 | white-space: normal;
251 | /* 1 */
252 | }
253 |
254 | /**
255 | * Add the correct vertical alignment in Chrome, Firefox, and Opera.
256 | */
257 |
258 | progress {
259 | vertical-align: baseline;
260 | }
261 |
262 | /**
263 | * Remove the default vertical scrollbar in IE 10+.
264 | */
265 |
266 | textarea {
267 | overflow: auto;
268 | }
269 |
270 | /**
271 | * 1. Add the correct box sizing in IE 10.
272 | * 2. Remove the padding in IE 10.
273 | */
274 |
275 | [type='checkbox'], [type='radio'] {
276 | box-sizing: border-box;
277 | /* 1 */
278 | padding: 0;
279 | /* 2 */
280 | }
281 |
282 | /**
283 | * Correct the cursor style of increment and decrement buttons in Chrome.
284 | */
285 |
286 | [type='number']::-webkit-inner-spin-button, [type='number']::-webkit-outer-spin-button {
287 | height: auto;
288 | }
289 |
290 | /**
291 | * 1. Correct the odd appearance in Chrome and Safari.
292 | * 2. Correct the outline style in Safari.
293 | */
294 |
295 | [type='search'] {
296 | -webkit-appearance: textfield;
297 | /* 1 */
298 | outline-offset: -2px;
299 | /* 2 */
300 | }
301 |
302 | /**
303 | * Remove the inner padding in Chrome and Safari on macOS.
304 | */
305 |
306 | [type='search']::-webkit-search-decoration {
307 | -webkit-appearance: none;
308 | }
309 |
310 | /**
311 | * 1. Correct the inability to style clickable types in iOS and Safari.
312 | * 2. Change font properties to `inherit` in Safari.
313 | */
314 |
315 | ::-webkit-file-upload-button {
316 | -webkit-appearance: button;
317 | /* 1 */
318 | font: inherit;
319 | /* 2 */
320 | }
321 |
322 | /* Interactive
323 | ========================================================================== */
324 |
325 | /*
326 | * Add the correct display in Edge, IE 10+, and Firefox.
327 | */
328 |
329 | details {
330 | display: block;
331 | }
332 |
333 | /*
334 | * Add the correct display in all browsers.
335 | */
336 |
337 | summary {
338 | display: list-item;
339 | }
340 |
341 | /* Misc
342 | ========================================================================== */
343 |
344 | /**
345 | * Add the correct display in IE 10+.
346 | */
347 |
348 | template {
349 | display: none;
350 | }
351 |
352 | /**
353 | * Add the correct display in IE 10.
354 | */
355 |
356 | [hidden] {
357 | display: none;
358 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/extension/extension.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2020 Jack Baker
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | const MAX_STACKTRACES = 10;
18 |
19 | class PopupExtension {
20 | constructor() {
21 | if (typeof chrome.extension.connect !== "undefined") {
22 | this._bgChannel = chrome.extension.connect({ name: "Cetus Background Page"});
23 |
24 | this._bgChannel.onMessage.addListener(bgMessageListener);
25 | this.sendBGMessage("popupConnected");
26 | }
27 | else {
28 | this._bgChannel = browser.runtime.connect({ name: "Cetus Background Page"});
29 |
30 | this._bgChannel.onMessage.addListener(bgMessageListener);
31 | this.sendBGMessage("popupConnected");
32 | }
33 |
34 | this._patches = [];
35 | this._loadPatchesFromStorage();
36 |
37 | this._stackTraces = [];
38 |
39 | this.symbols = {};
40 |
41 | this.unlocked = false;
42 |
43 | let _this = this;
44 | loadOptions(function(savedOptions) {
45 | _this.options = savedOptions;
46 | });
47 | }
48 |
49 | sendBGMessage(type, msgBody) {
50 | if (this._bgChannel !== null) {
51 | const msg = {
52 | type: type
53 | };
54 |
55 | if (typeof msgBody !== "undefined") {
56 | msg.body = msgBody;
57 | }
58 |
59 | // TODO Actually handle port closed error
60 | try {
61 | this._bgChannel.postMessage(msg);
62 | }
63 | catch (err) {
64 | return;
65 | }
66 | }
67 | }
68 |
69 | unlock() {
70 | const overlay = document.getElementById("lockOverlay");
71 | overlay.classList.remove("overlay");
72 | const button = document.getElementById("overlayLoadPatchModalButton");
73 | button.style.display = "none";
74 | this.unlocked = true;
75 | }
76 |
77 | reset() {
78 | updateBookmarkTable({}, this.options.enableWatchpoints);
79 |
80 | document.getElementById("restartBtn").click();
81 |
82 | document.getElementById("functionInput").value = "";
83 | document.getElementById("codeDisassembly").innerText = "";
84 |
85 | const textArea = document.querySelector("textarea.prism-live");
86 | textArea.value = "";
87 |
88 | // Prism Live only updates the text area on an input event
89 | // So we issue a fake input event to make it update
90 | textArea.dispatchEvent(new Event("input"));
91 |
92 | const overlay = document.getElementById("lockOverlay");
93 | overlay.classList.add("overlay");
94 | const button = document.getElementById("overlayLoadPatchModalButton");
95 | button.style.display = "block";
96 |
97 | closeLoadPatchModal();
98 | closeSavePatchModal();
99 | closeStackTraceModal();
100 |
101 | this.unlocked = false;
102 |
103 | let _this = this;
104 | loadOptions(function(savedOptions) {
105 | _this.options = savedOptions;
106 | });
107 | }
108 |
109 | addBookmark(memAddr, memType) {
110 | const msgBody = {
111 | memAddr: memAddr,
112 | memType: memType
113 | };
114 |
115 | this.sendBGMessage("addBookmark", msgBody);
116 | }
117 |
118 | removeBookmark(memAddr) {
119 | this.sendBGMessage("removeBookmark", {
120 | memAddr: memAddr,
121 | });
122 | }
123 |
124 | _loadPatchesFromStorage() {
125 | chrome.storage.local.get("savedPatches", function(result) {
126 | if (result !== null) {
127 | if (typeof result.savedPatches !== "undefined") {
128 | extension._patches = result.savedPatches;
129 | }
130 | }
131 | });
132 | }
133 |
134 | _updatePatches() {
135 | chrome.storage.local.set({ savedPatches: this._patches });
136 | }
137 |
138 | // TODO Remove backwards compatibility code once we've stopped supporting the old patch spec
139 | savePatch(options) {
140 | const patchName = options.name;
141 |
142 | let functionPatches;
143 |
144 | if (typeof options.version === "undefined" && typeof options.index !== "undefined" && typeof options.bytes !== "undefined") {
145 | const funcIndex = options.index;
146 | const funcBytes = options.bytes;
147 |
148 | functionPatches = [
149 | {
150 | index: funcIndex,
151 | bytes: funcBytes,
152 | }
153 | ];
154 | }
155 | else {
156 | functionPatches = options.functionPatches;
157 | }
158 |
159 | const binaryUrl = options.url;
160 |
161 | const newPatchBody = {
162 | name: patchName,
163 | url: binaryUrl,
164 | version: options.version,
165 | enabled: true,
166 | functionPatches: functionPatches,
167 | callbacks: options.callbacks,
168 | };
169 |
170 | this._patches.push(newPatchBody);
171 | this._updatePatches();
172 | }
173 |
174 | getPatches() {
175 | return this._patches;
176 | }
177 |
178 | getPatchesByUrl(url) {
179 | const allPatches = this.getPatches();
180 |
181 | const results = [];
182 |
183 | for (let i = 0; i < allPatches.length; i++) {
184 | const thisPatch = allPatches[i];
185 |
186 | if (thisPatch.url === url) {
187 | results.push(thisPatch);
188 | }
189 | }
190 |
191 | return results;
192 | }
193 |
194 | getPatchByName(patchName) {
195 | if (typeof patchName !== 'string') {
196 | return;
197 | }
198 |
199 | const allPatches = this.getPatches();
200 |
201 | for (let i = 0; i < allPatches.length; i++) {
202 | const thisPatch = allPatches[i];
203 |
204 | if (thisPatch.name === patchName) {
205 | return thisPatch;
206 | }
207 | }
208 | }
209 |
210 | enablePatchByName(patchName) {
211 | if (typeof patchName !== 'string') {
212 | return;
213 | }
214 |
215 | const allPatches = this.getPatches();
216 |
217 | for (let i = 0; i < allPatches.length; i++) {
218 | const thisPatch = allPatches[i];
219 |
220 | if (thisPatch.name === patchName) {
221 | this._patches[i].enabled = true;
222 |
223 | this._updatePatches();
224 |
225 | break;
226 | }
227 | }
228 | }
229 |
230 | disablePatchByName(patchName) {
231 | if (typeof patchName !== 'string') {
232 | return;
233 | }
234 |
235 | const allPatches = this.getPatches();
236 |
237 | for (let i = 0; i < allPatches.length; i++) {
238 | const thisPatch = allPatches[i];
239 |
240 | if (thisPatch.name === patchName) {
241 | this._patches[i].enabled = false;
242 |
243 | this._updatePatches();
244 |
245 | break;
246 | }
247 | }
248 | }
249 |
250 | exportPatchByName(patchName) {
251 | if (typeof patchName !== 'string') {
252 | return false;
253 | }
254 |
255 | const allPatches = this.getPatches();
256 |
257 | for (let i = 0; i < allPatches.length; i++) {
258 | const thisPatch = allPatches[i];
259 |
260 | if (thisPatch.name === patchName) {
261 | return JSON.stringify(thisPatch);
262 | }
263 | }
264 | }
265 |
266 | downloadPatchByName(patchName) {
267 | const patchFilename = patchName + ".json";
268 | const patchString = this.exportPatchByName(patchName);
269 |
270 | downloadText(patchFilename, patchString);
271 | }
272 |
273 | deletePatchByName(patchName) {
274 | if (typeof patchName !== 'string') {
275 | return false;
276 | }
277 |
278 | const allPatches = this.getPatches();
279 |
280 | for (let i = 0; i < allPatches.length; i++) {
281 | const thisPatch = allPatches[i];
282 |
283 | if (thisPatch.name === patchName) {
284 | this._patches.splice(i, 1);
285 |
286 | this._updatePatches();
287 |
288 | break;
289 | }
290 | }
291 | }
292 |
293 | clearPatches() {
294 | this._patches = [];
295 |
296 | this._updatePatches();
297 | }
298 |
299 | getStackTraces() {
300 | return this._stackTraces;
301 | }
302 |
303 | addStackTrace(newStackTrace) {
304 | this._stackTraces.push(newStackTrace);
305 |
306 | while (this._stackTraces.length > MAX_STACKTRACES) {
307 | this._stackTraces.shift();
308 | }
309 | }
310 | }
311 |
312 | const bgMessageListener = function(msgRaw) {
313 | const msg = bigintJsonParse(msgRaw);
314 |
315 | const type = msg.type;
316 | const msgBody = msg.body;
317 | const instanceId = msg.id;
318 |
319 | switch (type) {
320 | case "init":
321 | if (!extension.unlocked) {
322 | extension.unlock();
323 |
324 | extension.url = msgBody.url;
325 | extension.symbols = msgBody.symbols;
326 |
327 | updateInstances({
328 | url: msgBody.url,
329 | id: instanceId,
330 | });
331 | }
332 | else {
333 | addNewInstanceSelector(msgBody.url, instanceId);
334 | }
335 |
336 | break;
337 | case "popupRestore":
338 | if (!extension.unlocked) {
339 | extension.unlock();
340 | }
341 |
342 | const instanceData = msgBody.instanceData;
343 |
344 | extension.url = instanceData.url;
345 | extension.symbols = instanceData.symbols;
346 | extension.searchMemType = instanceData.searchForm.valueType;
347 |
348 | updateSearchForm(instanceData.searchForm);
349 | updateStringSearchForm(instanceData.stringForm);
350 | updateSpeedhackForm(instanceData.speedhack);
351 | updateStackTraceTable(instanceData.stackTraces);
352 | updateBookmarkTable(instanceData.bookmarks, extension.options.enableWatchpoints);
353 |
354 | updateInstances(msgBody.instances);
355 |
356 | break;
357 | case "searchResult":
358 | const resultCount = msgBody.count;
359 | const resultObject = msgBody.results;
360 | const resultMemType = msgBody.memType;
361 |
362 | if (typeof resultCount !== "number" || typeof resultObject !== "object") {
363 | return true;
364 | }
365 |
366 | updateSearchResults(resultCount, resultObject, resultMemType);
367 |
368 | break;
369 | case "updateBookmarks":
370 | const bookmarks = msgBody.bookmarks;
371 |
372 | updateBookmarkTable(bookmarks, extension.options.enableWatchpoints);
373 |
374 | break;
375 | case "updateMemView":
376 | const memData = msgBody.data;
377 | const memDataStartAddress = msgBody.startAddress;
378 |
379 | let len = Object.keys(memData).length;
380 | document.getElementById("memViewData").value = "";
381 |
382 | let counter = 0;
383 | let row = "";
384 | let txt = "";
385 | let c = 0;
386 | for (let i=0; i<32; i++)
387 | {
388 | row += toHex(memDataStartAddress+16*i) + " ";
389 | txt = "";
390 | for (let k=0; k<16; k++)
391 | {
392 | row += toHexByte(memData[c]) + " ";
393 | if (memData[c] > 32 && memData[c] < 127)
394 | txt += String.fromCharCode(memData[c]);
395 | else
396 | txt += ".";
397 |
398 | c++;
399 | }
400 | row += " " + txt + "\n";
401 | }
402 | document.getElementById("memViewData").value = row;
403 |
404 | break;
405 | case "stringSearchResult":
406 | const strResultCount = msgBody.count;
407 | const strResultObj = msgBody.results;
408 |
409 | updateStringSearchResults(strResultCount, strResultObj);
410 |
411 | break;
412 | case "queryFunctionResult":
413 | if (typeof msgBody.bytes !== "object") {
414 | return true;
415 | }
416 |
417 | const funcIndex = msgBody.funcIndex;
418 | const funcArray = Object.values(msgBody.bytes);
419 | const funcBytes = new Uint8Array(funcArray);
420 |
421 | const givenLineNum = msgBody.lineNum;
422 |
423 | const disassembly = disassembleFunction(funcBytes);
424 | const funcText = disassembly.text;
425 |
426 | const realLineNum = disassembly.lineNums[givenLineNum];
427 |
428 | updatePatchWindow(funcIndex, funcText, realLineNum);
429 |
430 | changeTab("tabPatchButton");
431 |
432 | break;
433 | case "watchPointHit":
434 | const stackTrace = msgBody.stackTrace;
435 |
436 | extension.addStackTrace(stackTrace);
437 |
438 | updateStackTraceTable(extension.getStackTraces());
439 |
440 | break;
441 | case "reset":
442 | extension.reset();
443 |
444 | break;
445 | }
446 |
447 | return true;
448 | };
449 |
450 | // TODO Rename this variable (Maybe "popup"?)
451 | extension = new PopupExtension();
452 |
--------------------------------------------------------------------------------
/extension/css/styles.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --brand: #5352ed;
3 | --background: #1f2430;
4 | --lightBackground: #232934;
5 | --text: #ffffff;
6 | --textGray: #d8d8d8;
7 | --grayInactive: #2a303e;
8 | --placeholder: rgba(255, 255, 255, 0.8);
9 | --label: rgba(255, 255, 255, 0.4);
10 | --toggleColorBackground: #fff;
11 | --toggleColorFill: #a4b0be;
12 | --inputBorder: #434b5b;
13 | --caretColor: rgb(0, 0, 0);
14 | }
15 |
16 | * {
17 | font-family: 'Proxima Nova', sans-serif;
18 | box-sizing: border-box;
19 | -webkit-font-smoothing: antialiased;
20 | margin: 0;
21 | outline: none;
22 | padding: 0;
23 | }
24 |
25 | html {
26 | border-radius: 4px;
27 | }
28 |
29 | .modal {
30 | width: 100%;
31 | height: 100%;
32 | left: 0;
33 | top: 0;
34 | z-index: 999;
35 | display: flex;
36 | flex-flow: column nowrap;
37 | justify-content: flex-end;
38 | }
39 |
40 | .modal-hidden {
41 | display: none;
42 | }
43 |
44 | .modal-inner {
45 | position: relative;
46 | z-index: 5;
47 | background: var(--lightBackground);
48 | padding: 16px;
49 | /*
50 | z-index: 5;
51 | background: var(--lightBackground);
52 | padding: 16px;
53 | overflow-y:scroll;
54 | overflow-x:hidden;
55 | */
56 | }
57 |
58 | .modal-hidden .modal-inner {
59 | transform: translateY(100%);
60 | }
61 |
62 | .modal-space {
63 | flex: 1;
64 | width: 100%;
65 | }
66 |
67 | .modal-overlay {
68 | height: 100%;
69 | width: 100%;
70 | background: #000;
71 | opacity: 0.6;
72 | position: absolute;
73 | top: 0;
74 | left: 0;
75 | }
76 |
77 | .modal-row {
78 | display: flex;
79 | flex-flow: row nowrap;
80 | justify-content: space-between;
81 | align-items: center;
82 | }
83 |
84 | .modal-title {
85 | font-style: normal;
86 | font-weight: 600;
87 | font-size: 18px;
88 | line-height: 24px;
89 | align-items: center;
90 | letter-spacing: 0.01em;
91 | }
92 |
93 | .modal-close {
94 | cursor: pointer;
95 | }
96 |
97 | .modal .input {
98 | margin: 16px 0 24px;
99 | }
100 |
101 | .modal .button {
102 | margin: 0;
103 | }
104 |
105 | .modal-table {
106 | margin-top: 16px;
107 | }
108 |
109 | .modal-table td:nth-child(2) {
110 | width: 100%;
111 | overflow:scroll;
112 | }
113 |
114 | .modal-table .load-button,
115 | .modal-table .remove-button {
116 | width: 32px;
117 | height: 32px;
118 | cursor: pointer;
119 | opacity: 0.7;
120 | transition: opacity 0.2s ease;
121 | will-change: opacity;
122 | display: flex;
123 | flex-flow: column nowrap;
124 | justify-content: center;
125 | align-items: center;
126 | }
127 |
128 | .modal-table .load-button:hover,
129 | .modal-table .remove-button:hover {
130 | opacity: 1;
131 | }
132 |
133 | .toggleColorScheme {
134 | position: absolute;
135 | right: 14px;
136 | top: 11px;
137 | cursor: pointer;
138 | width: 24px;
139 | height: 24px;
140 | border-radius: 16px;
141 | display: flex;
142 | flex-flow: column nowrap;
143 | justify-content: center;
144 | align-items: center;
145 | background: var(--toggleColorBackground);
146 | box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2);
147 | }
148 |
149 | .toggleColorScheme svg {
150 | width: 80%;
151 | height: 80%;
152 | }
153 |
154 | .toggleColorScheme path {
155 | fill: var(--toggleColorFill);
156 | }
157 |
158 | .container {
159 | width: 100%;
160 | padding: 16px;
161 | background: var(--background);
162 | }
163 |
164 | .select {
165 | position: fixed;
166 | z-index: 5;
167 | top: 0;
168 | left: 0;
169 | width: 100%;
170 | background: var(--lightBackground);
171 | padding: 0 16px;
172 | outline: none;
173 | }
174 |
175 | .select select {
176 | -moz-appearance: none;
177 | -webkit-appearance: none;
178 | appearance: none;
179 | text-decoration: none;
180 | }
181 |
182 | .tabs {
183 | position: fixed;
184 | z-index: 5;
185 | top: 10;
186 | left: 0;
187 | width: 100%;
188 | background: var(--lightBackground);
189 | display: flex;
190 | flex-flow: row nowrap;
191 | padding: 0 16px;
192 | }
193 |
194 | .tabs-content {
195 | padding-top: 60px;
196 | height: 100%;
197 | overflow-y: scroll;
198 | -ms-overflow-style: none;
199 | scrollbar-width: none;
200 | }
201 |
202 | .tabs-content::-webkit-scrollbar {
203 | display: none;
204 | }
205 |
206 | .tabs-item {
207 | padding: 14px 0 10px;
208 | margin-right: 24px;
209 | font-weight: 600;
210 | font-size: 14px;
211 | line-height: 18px;
212 | text-align: center;
213 | letter-spacing: 0.02em;
214 | user-select: none;
215 | border-bottom: 2px transparent solid;
216 | transition: border-bottom 0.2s ease;
217 | will-change: border-bottom;
218 | }
219 |
220 | .tabs-item a {
221 | text-decoration: none;
222 | color: var(--text);
223 | user-select: none;
224 | transition: color 0.2s ease;
225 | will-change: color;
226 | }
227 |
228 | .tabs-item.is-active {
229 | border-bottom: 2px var(--brand) solid;
230 | }
231 |
232 | .tabs-item.is-active a {
233 | color: var(--brand);
234 | }
235 |
236 | .form-field {
237 | margin-bottom: 16px;
238 | display: block;
239 | font-weight: bold;
240 | line-height: 20px;
241 | font-size: 13px;
242 | color: var(--label);
243 | }
244 |
245 | .input {
246 | margin-top: 4px;
247 | width: 100%;
248 | flex: 1;
249 | outline: none;
250 | background: none;
251 | display: block;
252 | padding: 10px 8px;
253 | font-family: 'Proxima Nova', sans-serif;
254 | font-style: normal;
255 | font-weight: normal;
256 | line-height: 22px;
257 | font-size: 16px;
258 | color: var(--text);
259 | border: 1px solid var(--inputBorder);
260 | transition: border 0.2s ease;
261 | will-change: border;
262 | border-radius: 4px;
263 | }
264 |
265 | .input:focus {
266 | border: 1px solid var(--brand);
267 | }
268 |
269 | ::placeholder {
270 | /* Chrome, Firefox, Opera, Safari 10.1+ */
271 | color: var(--placeholder);
272 | opacity: 1;
273 | /* Firefox */
274 | }
275 |
276 | :-ms-input-placeholder {
277 | /* Internet Explorer 10-11 */
278 | color: var(--placeholder);
279 | }
280 |
281 | ::-ms-input-placeholder {
282 | /* Microsoft Edge */
283 | color: var(--placeholder);
284 | }
285 |
286 | .function-form {
287 | display: flex;
288 | flex-flow: row nowrap;
289 | }
290 |
291 | .form-field--group {
292 | display: flex;
293 | flex-flow: row wrap;
294 | justify-content: space-between;
295 | align-items: center;
296 | }
297 |
298 | .form-field--group .input {
299 | margin-right: 8px;
300 | }
301 |
302 | .form-field--group .input:last-child,
303 | .form-field--group .input:nth-child(4n) {
304 | margin-right: 0;
305 | }
306 |
307 | .radio {
308 | margin-top: 4px;
309 | margin-bottom: 4px;
310 | flex: 0 0 15%;
311 | line-height: 23px;
312 | font-size: 16px;
313 | font-weight: normal;
314 | color: var(--textGray);
315 | height: 40px;
316 | position: relative;
317 | }
318 |
319 | .radio-input {
320 | opacity: 0;
321 | width: 100%;
322 | height: 100%;
323 | position: absolute;
324 | top: 0;
325 | left: 0;
326 | z-index: 1;
327 | cursor: pointer;
328 | }
329 |
330 | .radio-body {
331 | padding: 11px 8px;
332 | position: absolute;
333 | display: flex;
334 | flex-flow: row nowrap;
335 | align-items: center;
336 | left: 0;
337 | top: 0;
338 | width: 100%;
339 | height: 100%;
340 | background: var(--grayInactive);
341 | border-radius: 4px;
342 | transition: background 0.2s ease;
343 | will-change: background;
344 | }
345 |
346 | .radio-body span {
347 | width: 8px;
348 | height: 8px;
349 | background: #7e8797;
350 | transition: background 0.2s ease;
351 | will-change: background;
352 | border-radius: 4px;
353 | margin-right: 4px;
354 | }
355 |
356 | .radio-input:checked + .radio-body {
357 | background: var(--brand);
358 | color: #fff;
359 | }
360 |
361 | .radio-input:checked + .radio-body span {
362 | background: #ffffff;
363 | }
364 |
365 | .button {
366 | text-align: center;
367 | margin-top: 4px;
368 | width: 100%;
369 | flex: 1;
370 | outline: none;
371 | border-radius: 4px;
372 | padding: 14px 16px;
373 | background: var(--brand);
374 | border: 1px var(--brand) solid;
375 | color: #ffffff;
376 | font-weight: bold;
377 | line-height: 23px;
378 | font-size: 16px;
379 | cursor: pointer;
380 | }
381 |
382 | .button--text {
383 | background: none;
384 | border-radius: 0;
385 | border: none;
386 | opacity: 0.6;
387 | }
388 |
389 | .restart-container {
390 | display: flex;
391 | flex-flow: row nowrap;
392 | justify-content: space-between;
393 | align-items: center;
394 | }
395 |
396 | .results {
397 | padding: 0 8px;
398 | }
399 |
400 | .results-count {
401 | font-weight: bold;
402 | line-height: 26px;
403 | font-size: 18px;
404 | color: var(--textGray);
405 | }
406 |
407 | .results-clear {
408 | cursor: pointer;
409 | font-style: normal;
410 | font-weight: normal;
411 | line-height: 23px;
412 | font-size: 16px;
413 | color: #ff6b81;
414 | background: none;
415 | border: none;
416 | outline: none;
417 | }
418 |
419 | .results-clear[disabled] {
420 | display: none;
421 | }
422 |
423 | table {
424 | width: 100%;
425 | border-collapse: collapse;
426 | }
427 |
428 | table tbody tr:nth-child(even) {
429 | padding-bottom: 4px;
430 | background: var(--grayInactive);
431 | }
432 |
433 | table tbody tr:nth-child(odd) {
434 | background: var(--lightBackground);
435 | }
436 |
437 | thead td {
438 | font-style: normal;
439 | font-weight: bold;
440 | line-height: 20px;
441 | font-size: 13px;
442 | color: var(--label);
443 | padding: 0 4px 4px;
444 | }
445 |
446 | table tbody td {
447 | font-weight: normal;
448 | line-height: 22px;
449 | font-size: 14px;
450 | color: var(--textGray);
451 | padding: 12px 8px 10px;
452 | }
453 |
454 | .table-input {
455 | width: 100%;
456 | outline: none;
457 | background: none;
458 | display: block;
459 | font-family: 'Proxima Nova', sans-serif;
460 | font-style: normal;
461 | font-weight: normal;
462 | line-height: 22px;
463 | border: none;
464 | font-size: 14px;
465 | color: var(--text);
466 | }
467 |
468 | .button-add {
469 | font-style: normal;
470 | font-weight: normal;
471 | line-height: 23px;
472 | font-size: 16px;
473 | color: var(--brand);
474 | display: flex;
475 | flex-flow: row nowrap;
476 | justify-content: flex-end;
477 | align-items: center;
478 | background: none;
479 | border: none;
480 | outline: none;
481 | width: 100%;
482 | cursor: pointer;
483 | }
484 |
485 | .button-add--icon {
486 | margin-top: 8px;
487 | margin-right: 7px;
488 | }
489 |
490 | .speedometer {
491 | margin: 0px 0 16px;
492 | position: relative;
493 | display: flex;
494 | flex-flow: column nowrap;
495 | justify-content: center;
496 | align-items: center;
497 | }
498 |
499 | .speedometer-current {
500 | position: absolute;
501 | top: calc(35% + 48px);
502 | left: calc(52%);
503 | transform: translate(-50%, -50%);
504 | max-width: 122px;
505 | text-align: center;
506 | margin-left: -8px;
507 | width: 100%;
508 | font-weight: bold;
509 | line-height: 104px;
510 | font-size: 72px;
511 | color: var(--textGray);
512 | }
513 |
514 | .speedometer svg .paint {
515 | fill: var(--grayInactive);
516 | transition: fill 0.2s ease;
517 | will-change: fill;
518 | }
519 |
520 | .speedometer svg .paint-bold {
521 | transition: fill 0.2s ease;
522 | will-change: fill;
523 | }
524 |
525 | .speedometer-arrow {
526 | transform: translate(0px, -157px) rotate(-67.8deg);
527 | transform-origin: 50% 100px;
528 | transition: transform 0.2s ease;
529 | will-change: transform;
530 | }
531 |
532 | @media (max-width: 440px) {
533 | .button-add span {
534 | display: none;
535 | }
536 | }
537 |
538 | .slider {
539 | margin-bottom: 32px;
540 | position: relative;
541 | }
542 |
543 | .slider-input {
544 | position: relative;
545 | }
546 |
547 | .slider-input--line {
548 | position: absolute;
549 | top: -3px;
550 | left: 0;
551 | width: 2px;
552 | height: 7px;
553 | border-radius: 100px;
554 | background: var(--brand);
555 | }
556 |
557 | .slider-input--line:nth-child(1) {
558 | left: 12%;
559 | }
560 |
561 | .slider-input--line:nth-child(2) {
562 | left: 21%;
563 | }
564 |
565 | .slider-input--line:nth-child(3) {
566 | left: 30%;
567 | }
568 |
569 | .slider-input--line:nth-child(4) {
570 | left: 39%;
571 | }
572 |
573 | .slider-input--line:nth-child(5) {
574 | left: 50%;
575 | }
576 |
577 | .slider-input--line:nth-child(6) {
578 | left: 60%;
579 | }
580 |
581 | .slider-input--line:nth-child(7) {
582 | left: 70%;
583 | }
584 |
585 | .slider-input--line:nth-child(8) {
586 | left: 80%;
587 | }
588 |
589 | .slider-input--line:nth-child(9) {
590 | left: 90%;
591 | }
592 |
593 | .slider #shRange {
594 | width: 100%;
595 | height: 24px;
596 | position: absolute;
597 | right: 0;
598 | top: -12px;
599 | opacity: 0;
600 | cursor: pointer;
601 | }
602 |
603 | .slider-inner {
604 | height: 1px;
605 | background: var(--grayInactive);
606 | width: 100%;
607 | position: relative;
608 | overflow: hidden;
609 | }
610 |
611 | .slider-inner-fill {
612 | position: absolute;
613 | top: 0;
614 | left: 0;
615 | width: 100%;
616 | height: 100%;
617 | background: var(--brand);
618 | transform: translateX(-80%);
619 | transition: transform 0.2s ease;
620 | will-change: transition;
621 | }
622 |
623 | .slider-round {
624 | width: 24px;
625 | height: 24px;
626 | border-radius: 24px;
627 | background: var(--grayInactive);
628 | border: 1px solid var(--brand);
629 | box-sizing: border-box;
630 | box-shadow: 0px 4px 8px rgba(121, 121, 121, 0.05);
631 | position: absolute;
632 | left: 0;
633 | top: 50%;
634 | transform: translate(80px, -50%);
635 | transition: transform 0.2s ease;
636 | will-change: transform;
637 | pointer-events: none;
638 | }
639 |
640 | .button-checkbox {
641 | cursor: pointer;
642 | border: 1px solid var(--brand);
643 | width: 16px;
644 | height: 16px;
645 | border-radius: 3px;
646 | background: none;
647 | position: relative;
648 | display: block;
649 | margin: 0 auto;
650 | }
651 |
652 | .button-checkbox svg {
653 | opacity: 0;
654 | position: absolute;
655 | top: 50%;
656 | left: 50%;
657 | transform: translate(-50%, -50%);
658 | }
659 |
660 | .button-checkbox--active svg {
661 | opacity: 1;
662 | }
663 |
664 | .button-remove {
665 | cursor: pointer;
666 | margin: 0 auto;
667 | opacity: 0.7;
668 | transition: opacity 0.1s ease;
669 | will-change: opacity;
670 | width: 18px;
671 | height: 24px;
672 | background: none;
673 | border: none;
674 | }
675 |
676 | .button-remove:hover {
677 | opacity: 1;
678 | }
679 |
680 | .language-wasm {
681 | display: block;
682 | outline: none;
683 | }
684 |
685 | .nothing-to-show {
686 | position: absolute;
687 | left: 50%;
688 | top: 50%;
689 | transform: translate(-50%, -50%);
690 | display: flex;
691 | flex-flow: column nowrap;
692 | align-items: center;
693 | justify-content: center;
694 | height: 100vh;
695 | width: 100%;
696 | text-align: center;
697 | font-weight: bold;
698 | line-height: 26px;
699 | font-size: 18px;
700 | color: var(--textGray);
701 | }
702 |
703 | .nothing-to-show span {
704 | margin-top: 6px;
705 | display: block;
706 | font-weight: 400;
707 | font-size: 14px;
708 | line-height: 22px;
709 | }
710 |
711 | .nothing-to-show svg {
712 | margin-bottom: 4px;
713 | width: 120px;
714 | height: 120px;
715 | }
716 |
717 | .bookmarks {
718 | padding: 0 8px;
719 | }
720 |
721 | .bookmarks tr td {
722 | width: 80px;
723 | }
724 |
725 | .bookmarks tr td:nth-child(3),
726 | .bookmarks tr td:nth-child(4),
727 | .bookmarks tr td:nth-child(5) {
728 | width: 100px;
729 | text-align: center;
730 | }
731 |
732 | .bookmarks tr td:nth-child(6) {
733 | width: 45px;
734 | }
735 |
736 | .overlay {
737 | position: fixed;
738 | width: 100%;
739 | height: 100%;
740 | top: 0;
741 | left: 0;
742 | right: 0;
743 | bottom: 0;
744 | background-color: var(--background);
745 | z-index: 10;
746 | cursor: pointer;
747 | display: flex;
748 | flex-flow: row nowrap;
749 | justify-content: center;
750 | align-items: center;
751 | font-style: normal;
752 | font-weight: 600;
753 | font-size: 24px;
754 | line-height: 100%;
755 | letter-spacing: 0.02em;
756 | color: var(--textGray);
757 | }
758 |
759 | .overlay-container {
760 | text-align: center
761 | }
762 |
763 | .patch-controls {
764 | display: flex;
765 | flex-flow: row nowrap;
766 | align-items: center;
767 | }
768 |
769 | .openSavePatchModalButton,
770 | .openLoadPatchModalButton {
771 | font-size: 13px;
772 | cursor: pointer;
773 | padding: 32px 0 8px;
774 | opacity: 0.7;
775 | transition: opacity 0.2s ease;
776 | will-change: opacity;
777 | }
778 |
779 | .openSavePatchModalButton:hover,
780 | .openLoadPatchModalButton:hover {
781 | opacity: 1;
782 | }
783 |
784 | .openSavePatchModalButton {
785 | margin-right: 16px;
786 | }
787 |
--------------------------------------------------------------------------------
/extension/thirdparty/prism/prism-live.js:
--------------------------------------------------------------------------------
1 | /**
2 | Prism Live: Code editor based on Prism.js
3 | Works best in Chrome. Currently only very basic support in other browsers (no snippets, no shortcuts)
4 | @author Lea Verou
5 | */
6 | (async function() {
7 |
8 | if (!window.Bliss) {
9 | // Load Bliss if not loaded
10 | console.log("Bliss not loaded. Loading remotely from blissfuljs.com");
11 |
12 | let bliss = document.createElement("script");
13 | bliss.src = "https://blissfuljs.com/bliss.shy.min.js";
14 | document.head.appendChild(bliss);
15 |
16 | await new Promise(resolve => bliss.onload = resolve);
17 | }
18 |
19 | var $ = Bliss, $$ = Bliss.$;
20 | var ready = Promise.resolve();
21 |
22 | if (document.currentScript) {
23 | // Tiny dynamic loader. Use e.g. ?load=css,markup,javascript to load components
24 | var base = document.currentScript.src;
25 | var load = new URL(base).searchParams.get("load");
26 |
27 | if (load !== null) {
28 | var files = ["../prism-live.css"];
29 |
30 | if (load) {
31 | files.push(...load.split(/,/).map(c => /\./.test(c)? c : `prism-live-${c}.js`));
32 | }
33 |
34 | ready = Promise.all(files.map(url => $.load(url, base)));
35 | }
36 | }
37 |
38 | var superKey = navigator.platform.indexOf("Mac") === 0? "metaKey" : "ctrlKey";
39 |
40 | var _ = Prism.Live = class PrismLive {
41 | constructor(source) {
42 | this.source = source;
43 | this.sourceType = source.nodeName.toLowerCase();
44 |
45 | this.wrapper = $.create({
46 | className: "prism-live",
47 | around: this.source
48 | });
49 |
50 | if (this.sourceType === "textarea") {
51 | this.textarea = this.source;
52 | this.code = $.create("code");
53 |
54 | this.pre = $.create("pre", {
55 | className: this.textarea.className + " no-whitespace-normalization",
56 | contents: this.code,
57 | before: this.textarea
58 | });
59 | }
60 | else {
61 | this.pre = this.source;
62 |
63 | this.textarea = $.create("textarea", {
64 | className: this.pre.className,
65 | value: this.pre.textContent,
66 | after: this.pre
67 | });
68 | }
69 |
70 | _.all.set(this.textarea, this);
71 | _.all.set(this.pre, this);
72 | _.all.set(this.code, this);
73 |
74 | this.pre.classList.add("prism-live");
75 | this.textarea.classList.add("prism-live");
76 |
77 | if (self.Incrementable) {
78 | // TODO data-* attribute for modifier
79 | // TODO load dynamically if not present
80 | new Incrementable(this.textarea);
81 | }
82 |
83 | $.bind(this.textarea, {
84 | input: evt => this.update(),
85 |
86 | keyup: evt => {
87 | if (evt.key == "Enter") { // Enter
88 | // Maintain indent on line breaks
89 | this.insert(this.currentIndent);
90 | this.syncScroll();
91 | }
92 | },
93 |
94 | keydown: evt => {
95 | if (evt.key == "Tab" && !evt.altKey) {
96 | // Default is to move focus off the textarea
97 | // this is never desirable in an editor
98 | evt.preventDefault();
99 |
100 | if (this.tabstops && this.tabstops.length > 0) {
101 | // We have tabstops to go
102 | this.moveCaret(this.tabstops.shift());
103 | }
104 | else if (this.hasSelection) {
105 | var before = this.beforeCaret("\n");
106 | var outdent = evt.shiftKey;
107 |
108 | this.selectionStart -= before.length;
109 |
110 | var selection = _.adjustIndentation(this.selection, {
111 | relative: true,
112 | indentation: outdent? -1 : 1
113 | });
114 |
115 | this.replace(selection);
116 |
117 | if (outdent) {
118 | var indentStart = _.regexp.gm`^${this.indent}`;
119 | var isBeforeIndented = indentStart.test(before);
120 | this.selectionStart += before.length + 1 - (outdent + isBeforeIndented);
121 | }
122 | else { // Indent
123 | var hasLineAbove = before.length == this.selectionStart;
124 | this.selectionStart += before.length + 1 + !hasLineAbove;
125 | }
126 | }
127 | else {
128 | // Nothing selected, expand snippet
129 | var selector = _.match(this.beforeCaret(), /\S*$/);
130 | var snippetExpanded = this.expandSnippet(selector);
131 |
132 | if (snippetExpanded) {
133 | requestAnimationFrame(() => $.fire(this.textarea, "input"));
134 | }
135 | else {
136 | this.insert(this.indent);
137 | }
138 | }
139 | }
140 | else if (_.pairs[evt.key]) {
141 | var other = _.pairs[evt.key];
142 | this.wrapSelection({
143 | before: evt.key,
144 | after: other,
145 | outside: true
146 | });
147 | evt.preventDefault();
148 | }
149 | else {
150 | for (let shortcut in _.shortcuts) {
151 | if (_.checkShortcut(shortcut, evt)) {
152 | _.shortcuts[shortcut].call(this, evt);
153 | evt.preventDefault();
154 | }
155 | }
156 | }
157 | },
158 |
159 | click: evt => {
160 | var l = this.getLine();
161 | var v = this.value;
162 | var ss = this.selectionStart;
163 | //console.log(ss, v[ss], l, v.slice(l.start, l.end));
164 | },
165 |
166 | "click keyup": evt => {
167 | if (!evt.key || evt.key.lastIndexOf("Arrow") > -1) {
168 | // Caret moved
169 | this.tabstops = null;
170 | }
171 | }
172 | });
173 |
174 | // this.syncScroll();
175 | this.textarea.addEventListener("scroll", this, {passive: true});
176 |
177 | $.bind(window, {
178 | "resize": evt => this.syncStyles()
179 | });
180 |
181 | // Copy styles with a delay
182 | requestAnimationFrame(() => {
183 | this.syncStyles();
184 |
185 | var sourceCS = getComputedStyle(this.source);
186 |
187 | this.pre.style.height = this.source.style.height || sourceCS.getPropertyValue("--height");
188 | this.pre.style.maxHeight = this.source.style.maxHeight || sourceCS.getPropertyValue("--max-height");
189 | });
190 |
191 | this.update();
192 | this.lang = this.code.className.match(/lang(?:uage)?-(\w+)/i)[1];
193 | }
194 |
195 | handleEvent(evt) {
196 | if (evt.type === "scroll") {
197 | this.syncScroll();
198 | }
199 | }
200 |
201 | expandSnippet(text) {
202 | if (!text) {
203 | return false;
204 | }
205 |
206 | var context = this.context;
207 |
208 | if (text in context.snippets || text in _.snippets) {
209 | // Static Snippets
210 | var expansion = context.snippets[text] || _.snippets[text];
211 | }
212 | else if (context.snippets.custom) {
213 | var expansion = context.snippets.custom.call(this, text);
214 | }
215 |
216 | if (expansion) {
217 | // Insert snippet
218 | var stops = [];
219 | var replacement = [];
220 | var str = expansion;
221 | var match;
222 |
223 | while (match = _.CARET_INDICATOR.exec(str)) {
224 | stops.push(match.index + 1);
225 | replacement.push(str.slice(0, match.index + match[1].length));
226 | str = str.slice(match.index + match[0].length);
227 | _.CARET_INDICATOR.lastIndex = 0;
228 | }
229 |
230 | replacement.push(str);
231 | replacement = replacement.join("");
232 |
233 | if (stops.length > 0) {
234 | // make first stop relative to end, all others relative to previous stop
235 | stops[0] -= replacement.length;
236 | }
237 |
238 | this.delete(text);
239 | this.insert(replacement, {matchIndentation: true});
240 | this.tabstops = stops;
241 | this.moveCaret(this.tabstops.shift());
242 | }
243 |
244 | return !!expansion;
245 | }
246 |
247 | get selectionStart() {
248 | return this.textarea.selectionStart;
249 | }
250 | set selectionStart(v) {
251 | this.textarea.selectionStart = v;
252 | }
253 |
254 | get selectionEnd() {
255 | return this.textarea.selectionEnd;
256 | }
257 | set selectionEnd(v) {
258 | this.textarea.selectionEnd = v;
259 | }
260 |
261 | get hasSelection() {
262 | return this.selectionStart != this.selectionEnd;
263 | }
264 |
265 | get selection() {
266 | return this.value.slice(this.selectionStart, this.selectionEnd);
267 | }
268 |
269 | get value() {
270 | return this.textarea.value;
271 | }
272 | set value(v) {
273 | this.textarea.value = v;
274 | }
275 |
276 | get indent() {
277 | return _.match(this.value, /^[\t ]+/m, _.DEFAULT_INDENT);
278 | }
279 |
280 | get currentIndent() {
281 | var before = this.value.slice(0, this.selectionStart-1);
282 | return _.match(before, /^[\t ]*/mg, "", -1);
283 | }
284 |
285 | // Current language at caret position
286 | get currentLanguage() {
287 | var node = this.getNode();
288 | node = node? node.parentNode : this.code;
289 | var lang = _.match(node.closest('[class*="language-"]').className, /language-(\w+)/, 1);
290 | return _.aliases[lang] || lang;
291 | }
292 |
293 | // Get settings based on current language
294 | get context() {
295 | var lang = this.currentLanguage;
296 | return _.languages[lang] || _.languages.DEFAULT;
297 | }
298 |
299 | update() {
300 | var code = this.value;
301 |
302 | if (/\n$/.test(this.value)) {
303 | code += "\u200b";
304 | }
305 |
306 | this.code.textContent = code;
307 |
308 | Prism.highlightElement(this.code);
309 | }
310 |
311 | syncStyles() {
312 | // Copy pre metrics over to textarea
313 | var cs = getComputedStyle(this.pre);
314 |
315 | // Copy styles from to textarea
316 | this.textarea.style.caretColor = cs.color;
317 |
318 | var properties = /^(font|lineHeight)|[tT]abSize/gi;
319 |
320 | for (var prop in cs) {
321 | if (cs[prop] && prop in this.textarea.style && properties.test(prop)) {
322 | this.wrapper.style[prop] = cs[prop];
323 | this.textarea.style[prop] = this.pre.style[prop] = "inherit";
324 | }
325 | }
326 |
327 | this.textarea.style.paddingLeft = cs.paddingLeft;
328 | this.textarea.style.paddingTop = cs.paddingTop;
329 |
330 | this.update();
331 | }
332 |
333 | syncScroll() {
334 | if (this.pre.clientWidth === 0 && this.pre.clientHeight === 0) {
335 | return;
336 | }
337 |
338 | this.pre.scrollTop = this.textarea.scrollTop;
339 | this.pre.scrollLeft = this.textarea.scrollLeft;
340 | }
341 |
342 | beforeCaretIndex(until = "") {
343 | return this.value.lastIndexOf(until, this.selectionStart);
344 | }
345 |
346 | afterCaretIndex(until = "") {
347 | return this.value.indexOf(until, this.selectionEnd);
348 | }
349 |
350 | beforeCaret(until = "") {
351 | var index = this.beforeCaretIndex(until);
352 |
353 | if (index === -1 || !until) {
354 | index = 0;
355 | }
356 |
357 | return this.value.slice(index, this.selectionStart);
358 | }
359 |
360 | getLine(offset = this.selectionStart) {
361 | var value = this.value;
362 | var lf = "\n", cr = "\r";
363 | var start, end, char;
364 |
365 | for (var start = this.selectionStart; char = value[start]; start--) {
366 | if (char === lf || char === cr || !start) {
367 | break;
368 | }
369 | }
370 |
371 | for (var end = this.selectionStart; char = value[end]; end++) {
372 | if (char === lf || char === cr) {
373 | break;
374 | }
375 | }
376 |
377 | return {start, end};
378 | }
379 |
380 | afterCaret(until = "") {
381 | var index = this.afterCaretIndex(until);
382 |
383 | if (index === -1 || !until) {
384 | index = undefined;
385 | }
386 |
387 | return this.value.slice(this.selectionEnd, index);
388 | }
389 |
390 | setCaret(pos) {
391 | this.selectionStart = this.selectionEnd = pos;
392 | }
393 |
394 | moveCaret(chars) {
395 | if (chars) {
396 | this.setCaret(this.selectionEnd + chars);
397 | }
398 | }
399 |
400 | insert(text, {index} = {}) {
401 | if (!text) {
402 | return;
403 | }
404 |
405 | this.textarea.focus();
406 |
407 | if (index === undefined) {
408 | // No specified index, insert in current caret position
409 | this.replace(text);
410 | }
411 | else {
412 | // Specified index, first move caret there
413 | var start = this.selectionStart;
414 | var end = this.selectionEnd;
415 |
416 | this.selectionStart = this.selectionEnd = index;
417 | this.replace(text);
418 |
419 | this.selectionStart = start + (index < start? text.length : 0);
420 | this.selectionEnd = end + (index <= end? text.length : 0);
421 | }
422 | }
423 |
424 | // Replace currently selected text
425 | replace(text) {
426 | if (_.supportsExecCommand) {
427 | var hadSelection = this.hasSelection;
428 | document.execCommand("insertText", false, text);
429 | if (hadSelection) {
430 | // By default inserText places the caret at the end, losing any selection
431 | // What we want instead is the replaced text to be selected
432 | this.selectionStart = this.selectionEnd - text.length;
433 | }
434 | }
435 | else {
436 | this.textarea.setRangeText(text);
437 | this.update();
438 | }
439 | }
440 |
441 | // Set text between indexes and restore caret position
442 | set(text, {start, end} = {}) {
443 | if (_.supportsExecCommand) {
444 | var ss = this.selectionStart;
445 | var se = this.selectionEnd;
446 |
447 | this.selectionStart = start;
448 | this.selectionEnd = end;
449 |
450 | document.execCommand("insertText", false, text);
451 |
452 | this.selectionStart = ss;
453 | this.selectionEnd = se;
454 | }
455 | else {
456 | this.textarea.setRangeText(text);
457 | this.update();
458 | }
459 | }
460 |
461 | /**
462 | * Wrap text with strings
463 | * @param before {String} The text to insert before
464 | * @param after {String} The text to insert after
465 | * @param start {Number} Character offset
466 | * @param end {Number} Character offset
467 | */
468 | wrap({before, after, start = this.selectionStart, end = this.selectionEnd} = {}) {
469 | var ss = this.selectionStart;
470 | var se = this.selectionEnd;
471 | var between = this.value.slice(start, end);
472 |
473 | this.set(before + between + after, {start, end});
474 |
475 | if (ss > start) {
476 | ss += before.length;
477 | }
478 |
479 | if (se > start) {
480 | se += before.length;
481 | }
482 |
483 | if (ss > end) {
484 | ss += after.length;
485 | }
486 |
487 | if (se > end) {
488 | se += after.length;
489 | }
490 |
491 | this.selectionStart = ss;
492 | this.selectionEnd = se;
493 | }
494 |
495 | wrapSelection(o = {}) {
496 | var hadSelection = this.hasSelection;
497 |
498 | this.replace(o.before + this.selection + o.after);
499 |
500 | if (hadSelection) {
501 | if (o.outside) {
502 | // Do not include new text in selection
503 | this.selectionStart += o.before.length;
504 | this.selectionEnd -= o.after.length;
505 | }
506 | }
507 | else {
508 | this.moveCaret(-o.after.length);
509 | }
510 | }
511 |
512 | toggleComment() {
513 | var comments = this.context.comments;
514 |
515 | // Are we inside a comment?
516 | var node = this.getNode();
517 | var commentNode = node.parentNode.closest(".token.comment");
518 |
519 | if (commentNode) {
520 | // Remove comment
521 | var start = this.getOffset(commentNode);
522 | var commentText = commentNode.textContent;
523 |
524 | if (comments.singleline && commentText.indexOf(comments.singleLine) === 0) {
525 | // TODO
526 | }
527 | else {
528 | comments = comments.multiline || comments;
529 | var end = start + commentText.length - comments[1].length;
530 | this.set(this.value.slice(start + comments[0].length, end), {start, end: end + comments[1].length});
531 | }
532 | }
533 | else {
534 | // Not inside comment, add
535 | if (this.hasSelection) {
536 | comments = comments.multiline || comments;
537 |
538 | this.wrapSelection({
539 | before: comments[0],
540 | after: comments[1]
541 | });
542 | }
543 | else {
544 | // No selection, wrap line
545 | // FIXME *inside indent*
546 | comments = comments.singleline? [comments.singleline, "\n"] : comments.multiline || comments;
547 | end = this.afterCaretIndex("\n");
548 | this.wrap({
549 | before: comments[0],
550 | after: comments[1],
551 | start: this.beforeCaretIndex("\n") + 1,
552 | end: end < 0? this.value.length : end
553 | });
554 | }
555 | }
556 | }
557 |
558 | duplicateContent() {
559 | var before = this.beforeCaret("\n");
560 | var after = this.afterCaret("\n");
561 | var text = before + this.selection + after;
562 |
563 | this.insert(text, {index: this.selectionStart - before.length});
564 | }
565 |
566 | delete(characters, {forward, pos} = {}) {
567 | var i = characters = characters > 0? characters : (characters + "").length;
568 |
569 | if (pos) {
570 | var selectionStart = this.selectionStart;
571 | this.selectionStart = pos;
572 | this.selectionEnd = pos + this.selectionEnd - selectionStart;
573 | }
574 |
575 | while (i--) {
576 | document.execCommand(forward? "forwardDelete" : "delete");
577 | }
578 |
579 | if (pos) {
580 | // Restore caret
581 | this.selectionStart = selectionStart - characters;
582 | this.selectionEnd = this.selectionEnd - pos + this.selectionStart;
583 | }
584 | }
585 |
586 | /**
587 | * Get the text node at a given chracter offset
588 | */
589 | getNode(offset = this.selectionStart, container = this.code) {
590 | var node, sum = 0;
591 | var walk = document.createTreeWalker(container, NodeFilter.SHOW_TEXT);
592 |
593 | while (node = walk.nextNode()) {
594 | sum += node.data.length;
595 |
596 | if (sum >= offset) {
597 | return node;
598 | }
599 | }
600 |
601 | // if here, offset is larger than maximum
602 | return null;
603 | }
604 |
605 | /**
606 | * Get the character offset of a given node in the highlighted source
607 | */
608 | getOffset(node) {
609 | var range = document.createRange();
610 | range.selectNodeContents(this.code);
611 | range.setEnd(node, 0);
612 | return range.toString().length;
613 | }
614 |
615 | // Utility method to get regex matches
616 | static match(str, regex, def, index = 0) {
617 | if (typeof def === "number" && arguments.length === 3) {
618 | index = def;
619 | def = undefined;
620 | }
621 |
622 | var match = str.match(regex);
623 |
624 | if (index < 0) {
625 | index = match.length + index;
626 | }
627 |
628 | return match? match[index] : def;
629 | }
630 |
631 | static checkShortcut(shortcut, evt) {
632 | return shortcut.trim().split(/\s*\+\s*/).every(key => {
633 | switch (key) {
634 | case "Cmd": return evt[superKey];
635 | case "Ctrl": return evt.ctrlKey;
636 | case "Shift": return evt.shiftKey;
637 | case "Alt": return evt.altKey;
638 | default: return evt.key === key;
639 | }
640 | });
641 | }
642 |
643 | static registerLanguage(name, context, parent = _.languages.DEFAULT) {
644 | Object.setPrototypeOf(context, parent);
645 | return _.languages[name] = context;
646 | }
647 |
648 | static matchIndentation(text, currentIndent) {
649 | // FIXME this assumes that text has no indentation of its own
650 | // to make this more generally useful beyond snippets, we should first
651 | // strip text's own indentation.
652 | text = text.replace(/\r?\n/g, "$&" + currentIndent);
653 | }
654 |
655 | static adjustIndentation(text, {indentation, relative = true, indent = _.DEFAULT_INDENT}) {
656 | if (!relative) {
657 | // First strip min indentation
658 | var minIndent = text.match(_.regexp.gm`^(${indent})+`).sort()[0];
659 |
660 | if (minIndent) {
661 | text.replace(_.regexp.gm`^${minIndent}`, "");
662 | }
663 | }
664 |
665 | if (indentation < 0) {
666 | return text.replace(_.regexp.gm`^${indent}`, "");
667 | }
668 | else if (indentation > 0) { // Indent
669 | return text.replace(/^/gm, indent);
670 | }
671 | }
672 | };
673 |
674 | // Static properties
675 | Object.assign(_, {
676 | all: new WeakMap(),
677 | ready,
678 | DEFAULT_INDENT: "\t",
679 | CARET_INDICATOR: /(^|[^\\])\$(\d+)/g,
680 | snippets: {
681 | "test": "Snippets work!",
682 | },
683 | pairs: {
684 | "(": ")",
685 | "[": "]",
686 | "{": "}",
687 | '"': '"',
688 | "'": "'",
689 | "`": "`"
690 | },
691 | shortcuts: {
692 | "Cmd + /": function() {
693 | this.toggleComment();
694 | },
695 | "Ctrl + Shift + D": function() {
696 | this.duplicateContent();
697 | }
698 | },
699 | languages: {
700 | DEFAULT: {
701 | comments: {
702 | multiline: ["/*", "*/"]
703 | },
704 | snippets: {}
705 | }
706 | },
707 | // Map of Prism language ids and their canonical name
708 | aliases: (() => {
709 | var ret = {};
710 | var canonical = new WeakMap(Object.entries(Prism.languages).map(x => x.reverse()).reverse());
711 |
712 | for (var id in Prism.languages) {
713 | var grammar = Prism.languages[id];
714 |
715 | if (typeof grammar !== "function") {
716 | ret[id] = canonical.get(grammar);
717 | }
718 | }
719 |
720 | return ret;
721 | })(),
722 |
723 | regexp: (() => {
724 | var escape = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
725 | var _regexp = (flags, strings, ...values) => {
726 | var pattern = strings[0] + values.map((v, i) => escape(v) + strings[i+1]).join("");
727 | return RegExp(pattern, flags);
728 | };
729 | var cache = {};
730 |
731 | return new Proxy(_regexp.bind(_, ""), {
732 | get: (t, property) => {
733 | return t[property] || cache[property]
734 | || (cache[property] = _regexp.bind(_, property));
735 | }
736 | });
737 | })()
738 | });
739 |
740 | $.ready().then(() => {
741 | var t = $.create("textarea", {inside: document.body});
742 | t.focus();
743 | document.execCommand("insertText", false, "a");
744 | _.supportsExecCommand = !!t.value;
745 | t.remove();
746 |
747 | $$(":not(.prism-live) > textarea.prism-live").forEach(textarea => {
748 | if (!_.all.get(textarea)) {
749 | new _(textarea);
750 | }
751 | });
752 | });
753 |
754 | })();
755 |
756 |
--------------------------------------------------------------------------------
/extension/thirdparty/bliss/bliss.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | "use strict";
3 |
4 | function overload(callback, start, end) {
5 | start = start === undefined ? 1 : start;
6 | end = end || start + 1;
7 |
8 | if (end - start <= 1) {
9 | return function() {
10 | if (arguments.length <= start || $.type(arguments[start]) === "string") {
11 | return callback.apply(this, arguments);
12 | }
13 |
14 | var obj = arguments[start];
15 | var ret;
16 |
17 | for (var key in obj) {
18 | var args = Array.prototype.slice.call(arguments);
19 | args.splice(start, 1, key, obj[key]);
20 | ret = callback.apply(this, args);
21 | }
22 |
23 | return ret;
24 | };
25 | }
26 |
27 | return overload(overload(callback, start + 1, end), start, end - 1);
28 | }
29 |
30 | // Copy properties from one object to another. Overwrites allowed.
31 | // Subtle difference of array vs string whitelist: If property doesn't exist in from, array will not define it.
32 | function extend(to, from, whitelist) {
33 | var whitelistType = type(whitelist);
34 |
35 | if (whitelistType === "string") {
36 | // To copy gettters/setters, preserve flags etc
37 | var descriptor = Object.getOwnPropertyDescriptor(from, whitelist);
38 |
39 | if (descriptor && (!descriptor.writable || !descriptor.configurable || !descriptor.enumerable || descriptor.get || descriptor.set)) {
40 | delete to[whitelist];
41 | Object.defineProperty(to, whitelist, descriptor);
42 | }
43 | else {
44 | to[whitelist] = from[whitelist];
45 | }
46 | }
47 | else if (whitelistType === "array") {
48 | whitelist.forEach(function(property) {
49 | if (property in from) {
50 | extend(to, from, property);
51 | }
52 | });
53 | }
54 | else {
55 | for (var property in from) {
56 | if (whitelist) {
57 | if (whitelistType === "regexp" && !whitelist.test(property) ||
58 | whitelistType === "function" && !whitelist.call(from, property)) {
59 | continue;
60 | }
61 | }
62 |
63 | extend(to, from, property);
64 | }
65 | }
66 |
67 | return to;
68 | }
69 |
70 | /**
71 | * Returns the [[Class]] of an object in lowercase (eg. array, date, regexp, string etc)
72 | */
73 | function type(obj) {
74 | if (obj === null) {
75 | return "null";
76 | }
77 |
78 | if (obj === undefined) {
79 | return "undefined";
80 | }
81 |
82 | var ret = (Object.prototype.toString.call(obj).match(/^\[object\s+(.*?)\]$/)[1] || "").toLowerCase();
83 |
84 | if (ret == "number" && isNaN(obj)) {
85 | return "nan";
86 | }
87 |
88 | return ret;
89 | }
90 |
91 | var $ = self.Bliss = extend(function(expr, context) {
92 | if (arguments.length == 2 && !context || !expr) {
93 | return null;
94 | }
95 |
96 | return $.type(expr) === "string"? (context || document).querySelector(expr) : expr || null;
97 | }, self.Bliss);
98 |
99 | extend($, {
100 | extend: extend,
101 | overload: overload,
102 | type: type,
103 |
104 | property: $.property || "_",
105 | listeners: self.WeakMap? new WeakMap() : new Map(),
106 |
107 | original: {
108 | addEventListener: (self.EventTarget || Node).prototype.addEventListener,
109 | removeEventListener: (self.EventTarget || Node).prototype.removeEventListener
110 | },
111 |
112 | sources: {},
113 |
114 | noop: function() {},
115 |
116 | $: function(expr, context) {
117 | if (expr instanceof Node || expr instanceof Window) {
118 | return [expr];
119 | }
120 |
121 | if (arguments.length == 2 && !context) {
122 | return [];
123 | }
124 |
125 | return Array.prototype.slice.call(typeof expr == "string"? (context || document).querySelectorAll(expr) : expr || []);
126 | },
127 |
128 | /*
129 | * Return first non-undefined value. Mainly used internally.
130 | */
131 | defined: function () {
132 | for (var i=0; i= 200 && env.xhr.status < 300 || env.xhr.status === 304) {
440 | // Success!
441 | resolve(env.xhr);
442 | }
443 | else {
444 | reject($.extend(Error(env.xhr.statusText), {
445 | xhr: env.xhr,
446 | get status() {
447 | return this.xhr.status;
448 | }
449 | }));
450 | }
451 | };
452 |
453 | env.xhr.onerror = function() {
454 | document.body.removeAttribute("data-loading");
455 | reject($.extend(Error("Network Error"), {xhr: env.xhr}));
456 | };
457 |
458 | env.xhr.ontimeout = function() {
459 | document.body.removeAttribute("data-loading");
460 | reject($.extend(Error("Network Timeout"), {xhr: env.xhr}));
461 | };
462 |
463 | env.xhr.send(env.method === "GET"? null : env.data);
464 | });
465 | // Hack: Expose xhr.abort(), by attaching xhr to the promise.
466 | promise.xhr = env.xhr;
467 | return promise;
468 | },
469 |
470 | value: function(obj) {
471 | var hasRoot = typeof obj !== "string";
472 |
473 | return $.$(arguments).slice(+hasRoot).reduce(function(obj, property) {
474 | return obj && obj[property];
475 | }, hasRoot? obj : self);
476 | }
477 | });
478 |
479 | $.Hooks = new $.Class({
480 | add: function (name, callback, first) {
481 | if (typeof arguments[0] != "string") {
482 | // Multiple hooks
483 | for (var name in arguments[0]) {
484 | this.add(name, arguments[0][name], arguments[1]);
485 | }
486 |
487 | return;
488 | }
489 |
490 | (Array.isArray(name)? name : [name]).forEach(function(name) {
491 | this[name] = this[name] || [];
492 |
493 | if (callback) {
494 | this[name][first? "unshift" : "push"](callback);
495 | }
496 | }, this);
497 | },
498 |
499 | run: function (name, env) {
500 | this[name] = this[name] || [];
501 | this[name].forEach(function(callback) {
502 | callback.call(env && env.context? env.context : env, env);
503 | });
504 | }
505 | });
506 |
507 | $.hooks = new $.Hooks();
508 |
509 | var _ = $.property;
510 |
511 | $.Element = function (subject) {
512 | this.subject = subject;
513 |
514 | // Author-defined element-related data
515 | this.data = {};
516 |
517 | // Internal Bliss element-related data
518 | this.bliss = {};
519 | };
520 |
521 | $.Element.prototype = {
522 | set: overload(function(property, value) {
523 | if (property in $.setProps) {
524 | $.setProps[property].call(this, value);
525 | }
526 | else if (property in this) {
527 | this[property] = value;
528 | }
529 | else {
530 | this.setAttribute(property, value);
531 | }
532 |
533 | }, 0),
534 |
535 | // Run a CSS transition, return promise
536 | transition: function(props, duration) {
537 | return new Promise(function(resolve, reject) {
538 | if ("transition" in this.style && duration !== 0) {
539 | // Get existing style
540 | var previous = $.extend({}, this.style, /^transition(Duration|Property)$/);
541 |
542 | $.style(this, {
543 | transitionDuration: (duration || 400) + "ms",
544 | transitionProperty: Object.keys(props).join(", ")
545 | });
546 |
547 | $.once(this, "transitionend", function() {
548 | clearTimeout(i);
549 | $.style(this, previous);
550 | resolve(this);
551 | });
552 |
553 | // Failsafe, in case transitionend doesn’t fire
554 | var i = setTimeout(resolve, duration+50, this);
555 |
556 | $.style(this, props);
557 | }
558 | else {
559 | $.style(this, props);
560 | resolve(this);
561 | }
562 | }.bind(this));
563 | },
564 |
565 | // Fire a synthesized event on the element
566 | fire: function (type, properties) {
567 | var evt = document.createEvent("HTMLEvents");
568 |
569 | evt.initEvent(type, true, true );
570 |
571 | // Return the result of dispatching the event, so we
572 | // can know if `e.preventDefault` was called inside it
573 | return this.dispatchEvent($.extend(evt, properties));
574 | },
575 |
576 | bind: overload(function(types, options) {
577 | if (arguments.length > 1 && ($.type(options) === "function" || options.handleEvent)) {
578 | // options is actually callback
579 | var callback = options;
580 | options = $.type(arguments[2]) === "object"? arguments[2] : {
581 | capture: !!arguments[2] // in case it's passed as a boolean 3rd arg
582 | };
583 | options.callback = callback;
584 | }
585 |
586 | var listeners = $.listeners.get(this) || {};
587 |
588 | types.trim().split(/\s+/).forEach(function (type) {
589 | if (type.indexOf(".") > -1) {
590 | type = type.split(".");
591 | var className = type[1];
592 | type = type[0];
593 | }
594 |
595 | listeners[type] = listeners[type] || [];
596 |
597 | if (listeners[type].filter(function(l) {
598 | return l.callback === options.callback && l.capture == options.capture;
599 | }).length === 0) {
600 | listeners[type].push($.extend({className: className}, options));
601 | }
602 |
603 | $.original.addEventListener.call(this, type, options.callback, options);
604 | }, this);
605 |
606 | $.listeners.set(this, listeners);
607 | }, 0),
608 |
609 | unbind: overload(function(types, options) {
610 | if (options && ($.type(options) === "function" || options.handleEvent)) {
611 | var callback = options;
612 | options = arguments[2];
613 | }
614 |
615 | if ($.type(options) == "boolean") {
616 | options = {capture: options};
617 | }
618 |
619 | options = options || {};
620 | options.callback = options.callback || callback;
621 |
622 | var listeners = $.listeners.get(this);
623 |
624 | (types || "").trim().split(/\s+/).forEach(function (type) {
625 | if (type.indexOf(".") > -1) {
626 | type = type.split(".");
627 | var className = type[1];
628 | type = type[0];
629 | }
630 |
631 | //if listeners exist, always go through listeners to clean up
632 | if (!listeners) {
633 | if (type && options.callback) {
634 | return $.original.removeEventListener.call(this, type, options.callback, options.capture);
635 | }
636 | return;
637 | }
638 |
639 | // Mass unbinding, need to go through listeners
640 | for (var ltype in listeners) {
641 | if (!type || ltype === type) {
642 | // No forEach, because we’re mutating the array
643 | for (var i=0, l; l=listeners[ltype][i]; i++) {
644 | if ((!className || className === l.className)
645 | && (!options.callback || options.callback === l.callback)
646 | && (!!options.capture == !!l.capture ||
647 | !type && !options.callback && undefined === options.capture)
648 | ) {
649 | listeners[ltype].splice(i, 1);
650 | $.original.removeEventListener.call(this, ltype, l.callback, l.capture);
651 | i--;
652 | }
653 | }
654 | }
655 | }
656 | }, this);
657 | }, 0),
658 |
659 | // Return a promise that resolves when an event fires, then unbind
660 | when: function(type, test) {
661 | var me = this;
662 | return new Promise(function(resolve) {
663 | me.addEventListener(type, function callee(evt) {
664 | if (!test || test.call(this, evt)) {
665 | this.removeEventListener(type, callee);
666 | resolve(evt);
667 | }
668 | });
669 | });
670 | },
671 |
672 | toggleAttribute: function(name, value, test) {
673 | if (arguments.length < 3) {
674 | test = value !== null;
675 | }
676 |
677 | if (test) {
678 | this.setAttribute(name, value);
679 | }
680 | else {
681 | this.removeAttribute(name);
682 | }
683 | }
684 | };
685 |
686 | /*
687 | * Properties with custom handling in $.set()
688 | * Also available as functions directly on element._ and on $
689 | */
690 | $.setProps = {
691 | // Set a bunch of inline CSS styles
692 | style: function (val) {
693 | for (var property in val) {
694 | if (property in this.style) {
695 | // camelCase versions
696 | this.style[property] = val[property];
697 | }
698 | else {
699 | // This way we can set CSS Variables too and use normal property names
700 | this.style.setProperty(property, val[property]);
701 | }
702 | }
703 | },
704 |
705 | // Set a bunch of attributes
706 | attributes: function (o) {
707 | for (var attribute in o) {
708 | this.setAttribute(attribute, o[attribute]);
709 | }
710 | },
711 |
712 | // Set a bunch of properties on the element
713 | properties: function (val) {
714 | $.extend(this, val);
715 | },
716 |
717 | // Bind one or more events to the element
718 | events: function (val) {
719 | if (arguments.length == 1 && val && val.addEventListener) {
720 | // Copy events from other element (requires Bliss Full)
721 | var me = this;
722 |
723 | // Copy listeners
724 | if ($.listeners) {
725 | var listeners = $.listeners.get(val);
726 |
727 | for (var type in listeners) {
728 | listeners[type].forEach(function(l) {
729 | $.bind(me, type, l.callback, l.capture);
730 | });
731 | }
732 | }
733 |
734 | // Copy inline events
735 | for (var onevent in val) {
736 | if (onevent.indexOf("on") === 0) {
737 | this[onevent] = val[onevent];
738 | }
739 | }
740 | }
741 | else {
742 | return $.bind.apply(this, [this].concat($.$(arguments)));
743 | }
744 | },
745 |
746 | once: overload(function(types, callback) {
747 | var me = this;
748 | var once = function() {
749 | $.unbind(me, types, once);
750 |
751 | return callback.apply(me, arguments);
752 | };
753 |
754 | $.bind(this, types, once, {once: true});
755 | }, 0),
756 |
757 | // Event delegation
758 | delegate: overload(function (type, selector, callback) {
759 | $.bind(this, type, function(evt) {
760 | if (evt.target.closest(selector)) {
761 | callback.call(this, evt);
762 | }
763 | });
764 | }, 0, 2),
765 |
766 | // Set the contents as a string, an element, an object to create an element or an array of these
767 | contents: function (val) {
768 | if (val || val === 0) {
769 | (Array.isArray(val)? val : [val]).forEach(function (child) {
770 | var type = $.type(child);
771 |
772 | if (/^(string|number)$/.test(type)) {
773 | child = document.createTextNode(child + "");
774 | }
775 | else if (type === "object") {
776 | child = $.create(child);
777 | }
778 |
779 | if (child instanceof Node) {
780 | this.appendChild(child);
781 | }
782 | }, this);
783 | }
784 | },
785 |
786 | // Append the element inside another element
787 | inside: function (element) {
788 | element && element.appendChild(this);
789 | },
790 |
791 | // Insert the element before another element
792 | before: function (element) {
793 | element && element.parentNode.insertBefore(this, element);
794 | },
795 |
796 | // Insert the element after another element
797 | after: function (element) {
798 | element && element.parentNode.insertBefore(this, element.nextSibling);
799 | },
800 |
801 | // Insert the element before another element's contents
802 | start: function (element) {
803 | element && element.insertBefore(this, element.firstChild);
804 | },
805 |
806 | // Wrap the element around another element
807 | around: function (element) {
808 | if (element && element.parentNode) {
809 | $.before(this, element);
810 | }
811 |
812 | this.appendChild(element);
813 | }
814 | };
815 |
816 | $.Array = function (subject) {
817 | this.subject = subject;
818 | };
819 |
820 | $.Array.prototype = {
821 | all: function(method) {
822 | var args = $.$(arguments).slice(1);
823 |
824 | return this[method].apply(this, args);
825 | }
826 | };
827 |
828 | // Extends Bliss with more methods
829 | $.add = overload(function(method, callback, on, noOverwrite) {
830 | on = $.extend({$: true, element: true, array: true}, on);
831 |
832 | if ($.type(callback) == "function") {
833 | if (on.element && (!(method in $.Element.prototype) || !noOverwrite)) {
834 | $.Element.prototype[method] = function () {
835 | return this.subject && $.defined(callback.apply(this.subject, arguments), this.subject);
836 | };
837 | }
838 |
839 | if (on.array && (!(method in $.Array.prototype) || !noOverwrite)) {
840 | $.Array.prototype[method] = function() {
841 | var args = arguments;
842 | return this.subject.map(function(element) {
843 | return element && $.defined(callback.apply(element, args), element);
844 | });
845 | };
846 | }
847 |
848 | if (on.$) {
849 | $.sources[method] = $[method] = callback;
850 |
851 | if (on.array || on.element) {
852 | $[method] = function () {
853 | var args = [].slice.apply(arguments);
854 | var subject = args.shift();
855 | var Type = on.array && Array.isArray(subject)? "Array" : "Element";
856 |
857 | return $[Type].prototype[method].apply({subject: subject}, args);
858 | };
859 | }
860 | }
861 | }
862 | }, 0);
863 |
864 | $.add($.Array.prototype, {element: false});
865 | $.add($.Element.prototype);
866 | $.add($.setProps);
867 | $.add($.classProps, {element: false, array: false});
868 |
869 | // Add native methods on $ and _
870 | var dummy = document.createElement("_");
871 | $.add($.extend({}, HTMLElement.prototype, function(method) {
872 | return $.type(dummy[method]) === "function";
873 | }), null, true);
874 |
875 |
876 | })();
877 |
878 | (function($) {
879 | "use strict";
880 |
881 | if (!Bliss || Bliss.shy) {
882 | return;
883 | }
884 |
885 | var _ = Bliss.property;
886 |
887 | // Methods requiring Bliss Full
888 | $.add({
889 | // Clone elements, with events and data
890 | clone: function () {
891 | console.warn("$.clone() is deprecated and will be removed in a future version of Bliss.");
892 | var clone = this.cloneNode(true);
893 | var descendants = $.$("*", clone).concat(clone);
894 |
895 | $.$("*", this).concat(this).forEach(function(element, i, arr) {
896 | $.events(descendants[i], element);
897 | descendants[i]._.data = $.extend({}, element._.data);
898 | });
899 |
900 | return clone;
901 | }
902 | }, {array: false});
903 |
904 | // Define the _ property on arrays and elements
905 |
906 | Object.defineProperty(Node.prototype, _, {
907 | // Written for IE compatability (see #49)
908 | get: function getter () {
909 | Object.defineProperty(Node.prototype, _, {
910 | get: undefined
911 | });
912 | Object.defineProperty(this, _, {
913 | value: new $.Element(this)
914 | });
915 | Object.defineProperty(Node.prototype, _, {
916 | get: getter
917 | });
918 | return this[_];
919 | },
920 | configurable: true
921 | });
922 |
923 | Object.defineProperty(Array.prototype, _, {
924 | get: function () {
925 | Object.defineProperty(this, _, {
926 | value: new $.Array(this)
927 | });
928 |
929 | return this[_];
930 | },
931 | configurable: true
932 | });
933 |
934 | // Hijack addEventListener and removeEventListener to store callbacks
935 |
936 | if (self.EventTarget && "addEventListener" in EventTarget.prototype) {
937 | EventTarget.prototype.addEventListener = function(type, callback, options) {
938 | return $.bind(this, type, callback, options);
939 | };
940 |
941 | EventTarget.prototype.removeEventListener = function(type, callback, options) {
942 | return $.unbind(this, type, callback, options);
943 | };
944 | }
945 |
946 | // Set $ and $$ convenience methods, if not taken
947 | self.$ = self.$ || $;
948 | self.$$ = self.$$ || $.$;
949 |
950 | })(Bliss);
951 |
--------------------------------------------------------------------------------
/content/thirdparty/stacktrace/stacktrace.min.js:
--------------------------------------------------------------------------------
1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.StackTrace=e()}}(function(){var e;return function n(e,r,t){function o(a,s){if(!r[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=r[a]={exports:{}};e[a][0].call(l.exports,function(n){var r=e[a][1][n];return o(r?r:n)},l,l.exports,n,e,r,t)}return r[a].exports}for(var i="function"==typeof require&&require,a=0;a-1&&(n=n.replace(/eval code/g,"eval").replace(/(\(eval at [^\()]*)|(\)\,.*$)/g,""));var r=n.replace(/^\s+/,"").replace(/\(eval code/g,"(").split(/\s+/).slice(1),t=this.extractLocation(r.pop()),o=r.join(" ")||void 0,i=["eval",""].indexOf(t[0])>-1?void 0:t[0];return new e({functionName:o,fileName:i,lineNumber:t[1],columnNumber:t[2],source:n})},this)},parseFFOrSafari:function(n){var r=n.stack.split("\n").filter(function(e){return!e.match(t)},this);return r.map(function(n){if(n.indexOf(" > eval")>-1&&(n=n.replace(/ line (\d+)(?: > eval line \d+)* > eval\:\d+\:\d+/g,":$1")),n.indexOf("@")===-1&&n.indexOf(":")===-1)return new e({functionName:n});var r=n.split("@"),t=this.extractLocation(r.pop()),o=r.join("@")||void 0;return new e({functionName:o,fileName:t[0],lineNumber:t[1],columnNumber:t[2],source:n})},this)},parseOpera:function(e){return!e.stacktrace||e.message.indexOf("\n")>-1&&e.message.split("\n").length>e.stacktrace.split("\n").length?this.parseOpera9(e):e.stack?this.parseOpera11(e):this.parseOpera10(e)},parseOpera9:function(n){for(var r=/Line (\d+).*script (?:in )?(\S+)/i,t=n.message.split("\n"),o=[],i=2,a=t.length;i/,"$2").replace(/\([^\)]*\)/g,"")||void 0;i.match(/\(([^\)]*)\)/)&&(r=i.replace(/^[^\(]+\(([^\)]*)\)$/,"$1"));var s=void 0===r||"[arguments not available]"===r?void 0:r.split(",");return new e({functionName:a,args:s,fileName:o[0],lineNumber:o[1],columnNumber:o[2],source:n})},this)}}})},{stackframe:10}],2:[function(e,n,r){function t(){this._array=[],this._set=Object.create(null)}var o=e("./util"),i=Object.prototype.hasOwnProperty;t.fromArray=function(e,n){for(var r=new t,o=0,i=e.length;o=0&&e>1;return n?-r:r}var i=e("./base64"),a=5,s=1<>>=a,o>0&&(n|=c),r+=i.encode(n);while(o>0);return r},r.decode=function(e,n,r){var t,s,l=e.length,f=0,p=0;do{if(n>=l)throw new Error("Expected more digits in base 64 VLQ value.");if(s=i.decode(e.charCodeAt(n++)),s===-1)throw new Error("Invalid base64 digit: "+e.charAt(n-1));t=!!(s&c),s&=u,f+=s<0?n-u>1?t(u,n,o,i,a,s):s==r.LEAST_UPPER_BOUND?n1?t(e,u,o,i,a,s):s==r.LEAST_UPPER_BOUND?u:e<0?-1:e}r.GREATEST_LOWER_BOUND=1,r.LEAST_UPPER_BOUND=2,r.search=function(e,n,o,i){if(0===n.length)return-1;var a=t(-1,n.length,e,n,o,i||r.GREATEST_LOWER_BOUND);if(a<0)return-1;for(;a-1>=0&&0===o(n[a],n[a-1],!0);)--a;return a}},{}],6:[function(e,n,r){function t(e,n,r){var t=e[n];e[n]=e[r],e[r]=t}function o(e,n){return Math.round(e+Math.random()*(n-e))}function i(e,n,r,a){if(r=0){var i=this._originalMappings[o];if(void 0===e.column)for(var a=i.originalLine;i&&i.originalLine===a;)t.push({line:s.getArg(i,"generatedLine",null),column:s.getArg(i,"generatedColumn",null),lastColumn:s.getArg(i,"lastGeneratedColumn",null)}),i=this._originalMappings[++o];else for(var c=i.originalColumn;i&&i.originalLine===n&&i.originalColumn==c;)t.push({line:s.getArg(i,"generatedLine",null),column:s.getArg(i,"generatedColumn",null),lastColumn:s.getArg(i,"lastGeneratedColumn",null)}),i=this._originalMappings[++o]}return t},r.SourceMapConsumer=t,o.prototype=Object.create(t.prototype),o.prototype.consumer=t,o.fromSourceMap=function(e){var n=Object.create(o.prototype),r=n._names=c.fromArray(e._names.toArray(),!0),t=n._sources=c.fromArray(e._sources.toArray(),!0);n.sourceRoot=e._sourceRoot,n.sourcesContent=e._generateSourcesContent(n._sources.toArray(),n.sourceRoot),n.file=e._file;for(var a=e._mappings.toArray().slice(),u=n.__generatedMappings=[],l=n.__originalMappings=[],p=0,g=a.length;p1&&(r.source=m+o[1],m+=o[1],r.originalLine=g+o[2],g=r.originalLine,r.originalLine+=1,r.originalColumn=h+o[3],h=r.originalColumn,o.length>4&&(r.name=d+o[4],d+=o[4])),C.push(r),"number"==typeof r.originalLine&&b.push(r)}f(C,s.compareByGeneratedPositionsDeflated),this.__generatedMappings=C,f(b,s.compareByOriginalPositions),this.__originalMappings=b},o.prototype._findMapping=function(e,n,r,t,o,i){if(e[r]<=0)throw new TypeError("Line must be greater than or equal to 1, got "+e[r]);if(e[t]<0)throw new TypeError("Column must be greater than or equal to 0, got "+e[t]);return u.search(e,n,o,i)},o.prototype.computeColumnSpans=function(){for(var e=0;e=0){var o=this._generatedMappings[r];if(o.generatedLine===n.generatedLine){var i=s.getArg(o,"source",null);null!==i&&(i=this._sources.at(i),null!=this.sourceRoot&&(i=s.join(this.sourceRoot,i)));var a=s.getArg(o,"name",null);return null!==a&&(a=this._names.at(a)),{source:i,line:s.getArg(o,"originalLine",null),column:s.getArg(o,"originalColumn",null),name:a}}}return{source:null,line:null,column:null,name:null}},o.prototype.hasContentsOfAllSources=function(){return!!this.sourcesContent&&(this.sourcesContent.length>=this._sources.size()&&!this.sourcesContent.some(function(e){return null==e}))},o.prototype.sourceContentFor=function(e,n){if(!this.sourcesContent)return null;if(null!=this.sourceRoot&&(e=s.relative(this.sourceRoot,e)),this._sources.has(e))return this.sourcesContent[this._sources.indexOf(e)];var r;if(null!=this.sourceRoot&&(r=s.urlParse(this.sourceRoot))){var t=e.replace(/^file:\/\//,"");if("file"==r.scheme&&this._sources.has(t))return this.sourcesContent[this._sources.indexOf(t)];if((!r.path||"/"==r.path)&&this._sources.has("/"+e))return this.sourcesContent[this._sources.indexOf("/"+e)]}if(n)return null;throw new Error('"'+e+'" is not in the SourceMap.')},o.prototype.generatedPositionFor=function(e){var n=s.getArg(e,"source");if(null!=this.sourceRoot&&(n=s.relative(this.sourceRoot,n)),!this._sources.has(n))return{line:null,column:null,lastColumn:null};n=this._sources.indexOf(n);var r={source:n,originalLine:s.getArg(e,"line"),originalColumn:s.getArg(e,"column")},o=this._findMapping(r,this._originalMappings,"originalLine","originalColumn",s.compareByOriginalPositions,s.getArg(e,"bias",t.GREATEST_LOWER_BOUND));if(o>=0){var i=this._originalMappings[o];if(i.source===r.source)return{line:s.getArg(i,"generatedLine",null),column:s.getArg(i,"generatedColumn",null),lastColumn:s.getArg(i,"lastGeneratedColumn",null)}}return{line:null,column:null,lastColumn:null}},r.BasicSourceMapConsumer=o,a.prototype=Object.create(t.prototype),a.prototype.constructor=t,a.prototype._version=3,Object.defineProperty(a.prototype,"sources",{get:function(){for(var e=[],n=0;n=0;l--)a=u[l],"."===a?u.splice(l,1):".."===a?c++:c>0&&(""===a?(u.splice(l+1,c),c=0):(u.splice(l,2),c--));return n=u.join("/"),""===n&&(n=s?"/":"."),t?(t.path=n,i(t)):n}function s(e,n){""===e&&(e="."),""===n&&(n=".");var r=o(n),t=o(e);if(t&&(e=t.path||"/"),r&&!r.scheme)return t&&(r.scheme=t.scheme),i(r);if(r||n.match(_))return n;if(t&&!t.host&&!t.path)return t.host=n,i(t);var s="/"===n.charAt(0)?n:a(e.replace(/\/+$/,"")+"/"+n);return t?(t.path=s,i(t)):s}function u(e,n){""===e&&(e="."),e=e.replace(/\/$/,"");for(var r=0;0!==n.indexOf(e+"/");){var t=e.lastIndexOf("/");if(t<0)return n;if(e=e.slice(0,t),e.match(/^([^\/]+:\/)?\/*$/))return n;++r}return Array(r+1).join("../")+n.substr(e.length+1)}function c(e){return e}function l(e){return p(e)?"$"+e:e}function f(e){return p(e)?e.slice(1):e}function p(e){if(!e)return!1;var n=e.length;if(n<9)return!1;if(95!==e.charCodeAt(n-1)||95!==e.charCodeAt(n-2)||111!==e.charCodeAt(n-3)||116!==e.charCodeAt(n-4)||111!==e.charCodeAt(n-5)||114!==e.charCodeAt(n-6)||112!==e.charCodeAt(n-7)||95!==e.charCodeAt(n-8)||95!==e.charCodeAt(n-9))return!1;for(var r=n-10;r>=0;r--)if(36!==e.charCodeAt(r))return!1;return!0}function g(e,n,r){var t=e.source-n.source;return 0!==t?t:(t=e.originalLine-n.originalLine,0!==t?t:(t=e.originalColumn-n.originalColumn,0!==t||r?t:(t=e.generatedColumn-n.generatedColumn,0!==t?t:(t=e.generatedLine-n.generatedLine,0!==t?t:e.name-n.name))))}function h(e,n,r){var t=e.generatedLine-n.generatedLine;return 0!==t?t:(t=e.generatedColumn-n.generatedColumn,0!==t||r?t:(t=e.source-n.source,0!==t?t:(t=e.originalLine-n.originalLine,0!==t?t:(t=e.originalColumn-n.originalColumn,0!==t?t:e.name-n.name))))}function m(e,n){return e===n?0:e>n?1:-1}function d(e,n){var r=e.generatedLine-n.generatedLine;return 0!==r?r:(r=e.generatedColumn-n.generatedColumn,0!==r?r:(r=m(e.source,n.source),0!==r?r:(r=e.originalLine-n.originalLine,0!==r?r:(r=e.originalColumn-n.originalColumn,0!==r?r:m(e.name,n.name)))))}r.getArg=t;var v=/^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/,_=/^data:.+\,.+$/;r.urlParse=o,r.urlGenerate=i,r.normalize=a,r.join=s,r.isAbsolute=function(e){return"/"===e.charAt(0)||!!e.match(v)},r.relative=u;var y=function(){var e=Object.create(null);return!("__proto__"in e)}();r.toSetString=y?c:l,r.fromSetString=y?c:f,r.compareByOriginalPositions=g,r.compareByGeneratedPositionsDeflated=h,r.compareByGeneratedPositionsInflated=d},{}],9:[function(n,r,t){!function(o,i){"use strict";"function"==typeof e&&e.amd?e("stack-generator",["stackframe"],i):"object"==typeof t?r.exports=i(n("stackframe")):o.StackGenerator=i(o.StackFrame)}(this,function(e){return{backtrace:function(n){var r=[],t=10;"object"==typeof n&&"number"==typeof n.maxStackSize&&(t=n.maxStackSize);for(var o=arguments.callee;o&&r.length=200&&t.status<300||"file://"===e.substr(0,7)&&t.responseText?n(t.responseText):r(new Error("HTTP status: "+t.status+" retrieving "+e)))},t.send()})}function t(e){if("undefined"!=typeof window&&window.atob)return window.atob(e);throw new Error("You must supply a polyfill for window.atob in this environment")}function o(e){if("undefined"!=typeof JSON&&JSON.parse)return JSON.parse(e);throw new Error("You must supply a polyfill for JSON.parse in this environment")}function i(e,n){for(var r=[/['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*function\b/,/function\s+([^('"`]*?)\s*\(([^)]*)\)/,/['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*(?:eval|new Function)\b/,/\b(?!(?:if|for|switch|while|with|catch)\b)(?:(?:static)\s+)?(\S+)\s*\(.*?\)\s*\{/,/['"]?([$_A-Za-z][$_A-Za-z0-9]*)['"]?\s*[:=]\s*\(.*?\)\s*=>/],t=e.split("\n"),o="",i=Math.min(n,20),a=0;a=0&&(s=s.substr(0,u)),s){o=s+o;for(var c=r.length,l=0;l=200&&a.status<400?o(a.responseText):i(new Error("POST to "+n+" failed with status: "+a.status)))},a.open("post",n),a.setRequestHeader("Content-Type","application/json"),t&&"object"==typeof t.headers){var s=t.headers;for(var u in s)s.hasOwnProperty(u)&&a.setRequestHeader(u,s[u])}var c={stack:e};void 0!==r&&null!==r&&(c.message=r),a.send(JSON.stringify(c))})}}})},{"error-stack-parser":1,"stack-generator":9,"stacktrace-gps":11}]},{},[12])(12)});
2 |
--------------------------------------------------------------------------------
/extension/libs/disassembler.js:
--------------------------------------------------------------------------------
1 | /**
2 | Copyright 2020 Jack Baker
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | const Instruction = class {
18 | constructor() {
19 | this.opcode = null;
20 |
21 | this.immediates = [];
22 | }
23 | };
24 |
25 | const InstructionReader = class extends BufferReader {
26 | readKeywords(nameArray) {
27 | const results = [];
28 |
29 | for (let i = 0; i < nameArray.length; i++) {
30 | const thisName = nameArray[i];
31 |
32 | if (typeof thisName !== "string") {
33 | throw new Error("Invalid keyword name in InstructionReader.readKeywords()");
34 | }
35 |
36 | const thisValue = this.readVarUint32();
37 |
38 | const thisString = `${thisName}=${thisValue}`;
39 |
40 | results.push(thisString);
41 | }
42 |
43 | return results;
44 | }
45 |
46 | readBlockType() {
47 | const blockType = this.readUint8();
48 |
49 | switch (blockType) {
50 | case VALUE_TYPE_I32:
51 | return "i32";
52 | case VALUE_TYPE_I64:
53 | return "i64";
54 | case VALUE_TYPE_F32:
55 | return "f32";
56 | case VALUE_TYPE_F64:
57 | return "f64";
58 | case VALUE_TYPE_ANYFUNC:
59 | case VALUE_TYPE_FUNC:
60 | case VALUE_TYPE_BLOCK:
61 | return "";
62 | default:
63 | throw new Error("Bad block type in InstructionReader.readBlockType()");
64 | }
65 | }
66 | };
67 |
68 | const Disassembler = class {
69 | constructor(bytes, symbols = {}) {
70 | this.reader = new InstructionReader(bytes);
71 |
72 | this.indentStr = " ";
73 |
74 | this.symbols = symbols;
75 | }
76 |
77 | disassemble() {
78 | const instructions = [];
79 | const outputLines = [];
80 |
81 | let indentDepth = 0;
82 | let lineNumber = 0;
83 |
84 | const byteIndexToLineNum = {};
85 |
86 | while (this.reader.inPos < this.reader.inBuffer.length) {
87 | byteIndexToLineNum[this.reader.inPos] = lineNumber++;
88 |
89 | const instruction = this.disassembleInstruction();
90 |
91 | instructions.push(instruction);
92 | }
93 |
94 | for (let i = 0; i < instructions.length; i++) {
95 | const thisInstr = instructions[i];
96 |
97 | const immediateString = thisInstr.immediates.join(" ");
98 | const instrString = `${thisInstr.opstring} ${immediateString}`;
99 |
100 | if (thisInstr.opcode == OP_END) {
101 | indentDepth--;
102 | }
103 |
104 | if (indentDepth < 0) {
105 | indentDepth = 0;
106 | }
107 |
108 | const instrFullString = (this.indentStr.repeat(indentDepth) + instrString);
109 |
110 | switch (thisInstr.opcode) {
111 | case OP_BLOCK:
112 | case OP_LOOP:
113 | case OP_IF:
114 | case OP_ELSE:
115 | indentDepth++;
116 | break;
117 | }
118 |
119 | outputLines.push(instrFullString);
120 | }
121 |
122 | const resultObj = {};
123 |
124 | resultObj.text = outputLines.join("\n");
125 | resultObj.lineNums = byteIndexToLineNum;
126 |
127 | return resultObj;
128 | }
129 |
130 | disassembleInstruction() {
131 | const instruction = {};
132 |
133 | instruction.opcode = this.reader.readUint8();
134 | instruction.immediates = [];
135 |
136 | switch (instruction.opcode) {
137 | case OP_UNREACHABLE:
138 | instruction.opstring = "unreachable";
139 | break;
140 | case OP_NOP:
141 | instruction.opstring = "nop";
142 | break;
143 | case OP_BLOCK:
144 | instruction.opstring = "block";
145 | instruction.immediates.push(this.reader.readBlockType());
146 | break;
147 | case OP_LOOP:
148 | instruction.opstring = "loop";
149 | instruction.immediates.push(this.reader.readBlockType());
150 | break;
151 | case OP_IF:
152 | instruction.opstring = "if";
153 | instruction.immediates.push(this.reader.readBlockType());
154 | break;
155 | case OP_ELSE:
156 | instruction.opstring = "else";
157 | break;
158 | case OP_END:
159 | instruction.opstring = "end";
160 | break;
161 | case OP_BR:
162 | instruction.opstring = "br";
163 | instruction.immediates.push(this.reader.readVarUint32());
164 | break;
165 | case OP_BR_IF:
166 | instruction.opstring = "br_if";
167 | instruction.immediates.push(this.reader.readVarUint32());
168 | break;
169 | case OP_BR_TABLE:
170 | instruction.opstring = "br_table";
171 | let count = this.reader.readVarUint32();
172 |
173 | instruction.immediates.push(count);
174 |
175 | for (let i = 0; i < count; i++) {
176 | instruction.immediates.push(this.reader.readVarUint32());
177 | }
178 |
179 | instruction.immediates.push(this.reader.readVarUint32());
180 | break;
181 | case OP_RETURN:
182 | instruction.opstring = "return";
183 | break;
184 | case OP_CALL:
185 | instruction.opstring = "call";
186 | const callTarget = this.reader.readVarUint32();
187 |
188 | if (typeof this.symbols[callTarget] !== "undefined") {
189 | instruction.immediates.push(this.symbols[callTarget]);
190 | }
191 | else {
192 | instruction.immediates.push(callTarget);
193 | }
194 | break;
195 | case OP_CALL_INDIRECT:
196 | instruction.opstring = "call_indirect";
197 | instruction.immediates.push(this.reader.readVarUint32());
198 | instruction.immediates.push(this.reader.readUint8());
199 | break;
200 | case OP_DROP:
201 | instruction.opstring = "drop";
202 | break;
203 | case OP_SELECT:
204 | instruction.opstring = "select";
205 | break;
206 | case OP_GET_LOCAL:
207 | instruction.opstring = "get_local";
208 | instruction.immediates.push(this.reader.readVarUint32());
209 | break;
210 | case OP_SET_LOCAL:
211 | instruction.opstring = "set_local";
212 | instruction.immediates.push(this.reader.readVarUint32());
213 | break;
214 | case OP_TEE_LOCAL:
215 | instruction.opstring = "tee_local";
216 | instruction.immediates.push(this.reader.readVarUint32());
217 | break;
218 | case OP_GET_GLOBAL:
219 | instruction.opstring = "get_global";
220 | instruction.immediates.push(this.reader.readVarUint32());
221 | break;
222 | case OP_SET_GLOBAL:
223 | instruction.opstring = "set_global";
224 | instruction.immediates.push(this.reader.readVarUint32());
225 | break;
226 | case OP_I32_LOAD:
227 | instruction.opstring = "i32.load";
228 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
229 | break;
230 | case OP_I64_LOAD:
231 | instruction.opstring = "i64.load";
232 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
233 | break;
234 | case OP_F32_LOAD:
235 | instruction.opstring = "f32.load";
236 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
237 | break;
238 | case OP_F64_LOAD:
239 | instruction.opstring = "f64.load";
240 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
241 | break;
242 | case OP_I32_LOAD8_S:
243 | instruction.opstring = "i32.load8_s";
244 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
245 | break;
246 | case OP_I32_LOAD8_U:
247 | instruction.opstring = "i32.load8_u";
248 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
249 | break;
250 | case OP_I32_LOAD16_S:
251 | instruction.opstring = "i32.load16_s";
252 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
253 | break;
254 | case OP_I32_LOAD16_U:
255 | instruction.opstring = "i32.load16_u";
256 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
257 | break;
258 | case OP_I64_LOAD8_S:
259 | instruction.opstring = "i64.load8_s";
260 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
261 | break;
262 | case OP_I64_LOAD8_U:
263 | instruction.opstring = "i64.load8_u";
264 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
265 | break;
266 | case OP_I64_LOAD16_S:
267 | instruction.opstring = "i64.load16_s";
268 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
269 | break;
270 | case OP_I64_LOAD16_U:
271 | instruction.opstring = "i64.load16_u";
272 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
273 | break;
274 | case OP_I64_LOAD32_S:
275 | instruction.opstring = "i64.load32_s";
276 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
277 | break;
278 | case OP_I64_LOAD32_U:
279 | instruction.opstring = "i64.load32_u";
280 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
281 | break;
282 | case OP_I32_STORE:
283 | instruction.opstring = "i32.store";
284 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
285 | break;
286 | case OP_I64_STORE:
287 | instruction.opstring = "i64.store";
288 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
289 | break;
290 | case OP_F32_STORE:
291 | instruction.opstring = "f32.store";
292 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
293 | break;
294 | case OP_F64_STORE:
295 | instruction.opstring = "f64.store";
296 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
297 | break;
298 | case OP_I32_STORE8:
299 | instruction.opstring = "i32.store8";
300 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
301 | break;
302 | case OP_I32_STORE16:
303 | instruction.opstring = "i32.store16";
304 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
305 | break;
306 | case OP_I64_STORE8:
307 | instruction.opstring = "i64.store8";
308 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
309 | break;
310 | case OP_I64_STORE16:
311 | instruction.opstring = "i64.store16";
312 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
313 | break;
314 | case OP_I64_STORE32:
315 | instruction.opstring = "i64.store32";
316 | instruction.immediates = this.reader.readKeywords(["align", "offset"]);
317 | break;
318 | case OP_MEMORY_SIZE:
319 | instruction.opstring = "current_memory";
320 | instruction.immediates.push(this.reader.readUint8());
321 | break;
322 | case OP_MEMORY_GROW:
323 | instruction.opstring = "grow_memory";
324 | instruction.immediates.push(this.reader.readUint8());
325 | break;
326 | case OP_I32_CONST:
327 | instruction.opstring = "i32.const";
328 | instruction.immediates.push(this.reader.readVarUint32());
329 | break;
330 | // TODO Fix
331 | case OP_I64_CONST:
332 | instruction.opstring = "i64.const";
333 | instruction.immediates.push(this.reader.readVarUint32());
334 | break;
335 | case OP_F32_CONST:
336 | instruction.opstring = "f32.const";
337 |
338 | const f32Bytes = this.reader.readBytes(4);
339 |
340 | const f32ByteBuffer = new Uint8Array(f32Bytes);
341 |
342 | const f32Array = new Float32Array(f32ByteBuffer.buffer);
343 |
344 | instruction.immediates.push(f32Array[0]);
345 | break;
346 | case OP_F64_CONST:
347 | instruction.opstring = "f64.const";
348 |
349 | const f64Bytes = this.reader.readBytes(8);
350 |
351 | const f64ByteBuffer = new Uint8Array(f64Bytes);
352 |
353 | const f64Array = new Float64Array(f64ByteBuffer.buffer);
354 |
355 | instruction.immediates.push(f64Array[0]);
356 | break;
357 | case OP_I32_EQZ:
358 | instruction.opstring = "i32.eqz";
359 | break;
360 | case OP_I32_EQ:
361 | instruction.opstring = "i32.eq";
362 | break;
363 | case OP_I32_NE:
364 | instruction.opstring = "i32.ne";
365 | break;
366 | case OP_I32_LT_S:
367 | instruction.opstring = "i32.lt_s";
368 | break;
369 | case OP_I32_LT_U:
370 | instruction.opstring = "i32.lt_u";
371 | break;
372 | case OP_I32_GT_S:
373 | instruction.opstring = "i32.gt_s";
374 | break;
375 | case OP_I32_GT_U:
376 | instruction.opstring = "i32.gt_u";
377 | break;
378 | case OP_I32_LE_S:
379 | instruction.opstring = "i32.le_s";
380 | break;
381 | case OP_I32_LE_U:
382 | instruction.opstring = "i32.le_u";
383 | break;
384 | case OP_I32_GE_S:
385 | instruction.opstring = "i32.ge_s";
386 | break;
387 | case OP_I32_GE_U:
388 | instruction.opstring = "i32.ge_u";
389 | break;
390 | case OP_I64_EQZ:
391 | instruction.opstring = "i64.eqz";
392 | break;
393 | case OP_I64_EQ:
394 | instruction.opstring = "i64.eq";
395 | break;
396 | case OP_I64_NE:
397 | instruction.opstring = "i64.ne";
398 | break;
399 | case OP_I64_LT_S:
400 | instruction.opstring = "i64.lt_s";
401 | break;
402 | case OP_I64_LT_U:
403 | instruction.opstring = "i64.lt_u";
404 | break;
405 | case OP_I64_GT_S:
406 | instruction.opstring = "i64.gt_s";
407 | break;
408 | case OP_I64_GT_U:
409 | instruction.opstring = "i64.gt_u";
410 | break;
411 | case OP_I64_LE_S:
412 | instruction.opstring = "i64.le_s";
413 | break;
414 | case OP_I64_LE_U:
415 | instruction.opstring = "i64.le_u";
416 | break;
417 | case OP_I64_GE_S:
418 | instruction.opstring = "i64.ge_s";
419 | break;
420 | case OP_I64_GE_U:
421 | instruction.opstring = "i64.ge_u";
422 | break;
423 | case OP_F32_EQ:
424 | instruction.opstring = "f32.eq";
425 | break;
426 | case OP_F32_NE:
427 | instruction.opstring = "f32.ne";
428 | break;
429 | case OP_F32_LT:
430 | instruction.opstring = "f32.lt";
431 | break;
432 | case OP_F32_GT:
433 | instruction.opstring = "f32.gt";
434 | break;
435 | case OP_F32_LE:
436 | instruction.opstring = "f32.le";
437 | break;
438 | case OP_F32_GE:
439 | instruction.opstring = "f32.ge";
440 | break;
441 | case OP_F64_EQ:
442 | instruction.opstring = "f64.eq";
443 | break;
444 | case OP_F64_NE:
445 | instruction.opstring = "f64.ne";
446 | break;
447 | case OP_F64_LT:
448 | instruction.opstring = "f64.lt";
449 | break;
450 | case OP_F64_GT:
451 | instruction.opstring = "f64.gt";
452 | break;
453 | case OP_F64_LE:
454 | instruction.opstring = "f64.le";
455 | break;
456 | case OP_F64_GE:
457 | instruction.opstring = "f64.ge";
458 | break;
459 | case OP_I32_CLZ:
460 | instruction.opstring = "i32.clz";
461 | break;
462 | case OP_I32_CTZ:
463 | instruction.opstring = "i32.ctz";
464 | break;
465 | case OP_I32_POPCNT:
466 | instruction.opstring = "i32.popcnt";
467 | break;
468 | case OP_I32_ADD:
469 | instruction.opstring = "i32.add";
470 | break;
471 | case OP_I32_SUB:
472 | instruction.opstring = "i32.sub";
473 | break;
474 | case OP_I32_MUL:
475 | instruction.opstring = "i32.mul";
476 | break;
477 | case OP_I32_DIV_S:
478 | instruction.opstring = "i32.div_s";
479 | break;
480 | case OP_I32_DIV_U:
481 | instruction.opstring = "i32.div_u";
482 | break;
483 | case OP_I32_REM_S:
484 | instruction.opstring = "i32.rem_s";
485 | break;
486 | case OP_I32_REM_U:
487 | instruction.opstring = "i32.rem_u";
488 | break;
489 | case OP_I32_AND:
490 | instruction.opstring = "i32.and";
491 | break;
492 | case OP_I32_OR:
493 | instruction.opstring = "i32.or";
494 | break;
495 | case OP_I32_XOR:
496 | instruction.opstring = "i32.xor";
497 | break;
498 | case OP_I32_SHL:
499 | instruction.opstring = "i32.shl";
500 | break;
501 | case OP_I32_SHR_S:
502 | instruction.opstring = "i32.shr_s";
503 | break;
504 | case OP_I32_SHR_U:
505 | instruction.opstring = "i32.shr_u";
506 | break;
507 | case OP_I32_ROTL:
508 | instruction.opstring = "i32.rotl";
509 | break;
510 | case OP_I32_ROTR:
511 | instruction.opstring = "i32.rotr";
512 | break;
513 | case OP_I64_CLZ:
514 | instruction.opstring = "i64.clz";
515 | break;
516 | case OP_I64_CTZ:
517 | instruction.opstring = "i64.ctz";
518 | break;
519 | case OP_I64_POPCNT:
520 | instruction.opstring = "i64.popcnt";
521 | break;
522 | case OP_I64_ADD:
523 | instruction.opstring = "i64.add";
524 | break;
525 | case OP_I64_SUB:
526 | instruction.opstring = "i64.sub";
527 | break;
528 | case OP_I64_MUL:
529 | instruction.opstring = "i64.mul";
530 | break;
531 | case OP_I64_DIV_S:
532 | instruction.opstring = "i64.div_s";
533 | break;
534 | case OP_I64_DIV_U:
535 | instruction.opstring = "i64.div_u";
536 | break;
537 | case OP_I64_REM_S:
538 | instruction.opstring = "i64.rem_s";
539 | break;
540 | case OP_I64_REM_U:
541 | instruction.opstring = "i64.rem_u";
542 | break;
543 | case OP_I64_AND:
544 | instruction.opstring = "i64.and";
545 | break;
546 | case OP_I64_OR:
547 | instruction.opstring = "i64.or";
548 | break;
549 | case OP_I64_XOR:
550 | instruction.opstring = "i64.xor";
551 | break;
552 | case OP_I64_SHL:
553 | instruction.opstring = "i64.shl";
554 | break;
555 | case OP_I64_SHR_S:
556 | instruction.opstring = "i64.shr_s";
557 | break;
558 | case OP_I64_SHR_U:
559 | instruction.opstring = "i64.shr_u";
560 | break;
561 | case OP_I64_ROTL:
562 | instruction.opstring = "i64.rotl";
563 | break;
564 | case OP_I64_ROTR:
565 | instruction.opstring = "i64.rotr";
566 | break;
567 | case OP_F32_ABS:
568 | instruction.opstring = "f32.abs";
569 | break;
570 | case OP_F32_NEG:
571 | instruction.opstring = "f32.neg";
572 | break;
573 | case OP_F32_CEIL:
574 | instruction.opstring = "f32.ceil";
575 | break;
576 | case OP_F32_FLOOR:
577 | instruction.opstring = "f32.floor";
578 | break;
579 | case OP_F32_TRUNC:
580 | instruction.opstring = "f32.trunc";
581 | break;
582 | case OP_F32_NEAREST:
583 | instruction.opstring = "f32.nearest";
584 | break;
585 | case OP_F32_SQRT:
586 | instruction.opstring = "f32.sqrt";
587 | break;
588 | case OP_F32_ADD:
589 | instruction.opstring = "f32.add";
590 | break;
591 | case OP_F32_SUB:
592 | instruction.opstring = "f32.sub";
593 | break;
594 | case OP_F32_MUL:
595 | instruction.opstring = "f32.mul";
596 | break;
597 | case OP_F32_DIV:
598 | instruction.opstring = "f32.div";
599 | break;
600 | case OP_F32_MIN:
601 | instruction.opstring = "f32.min";
602 | break;
603 | case OP_F32_MAX:
604 | instruction.opstring = "f32.max";
605 | break;
606 | case OP_F32_COPYSIGN:
607 | instruction.opstring = "f32.copysign";
608 | break;
609 | case OP_F64_ABS:
610 | instruction.opstring = "f64.abs";
611 | break;
612 | case OP_F64_NEG:
613 | instruction.opstring = "f64.neg";
614 | break;
615 | case OP_F64_CEIL:
616 | instruction.opstring = "f64.ceil";
617 | break;
618 | case OP_F64_FLOOR:
619 | instruction.opstring = "f64.floor";
620 | break;
621 | case OP_F64_TRUNC:
622 | instruction.opstring = "f64.trunc";
623 | break;
624 | case OP_F64_NEAREST:
625 | instruction.opstring = "f64.nearest";
626 | break;
627 | case OP_F64_SQRT:
628 | instruction.opstring = "f64.sqrt";
629 | break;
630 | case OP_F64_ADD:
631 | instruction.opstring = "f64.add";
632 | break;
633 | case OP_F64_SUB:
634 | instruction.opstring = "f64.sub";
635 | break;
636 | case OP_F64_MUL:
637 | instruction.opstring = "f64.mul";
638 | break;
639 | case OP_F64_DIV:
640 | instruction.opstring = "f64.div";
641 | break;
642 | case OP_F64_MIN:
643 | instruction.opstring = "f64.min";
644 | break;
645 | case OP_F64_MAX:
646 | instruction.opstring = "f64.max";
647 | break;
648 | case OP_F64_COPYSIGN:
649 | instruction.opstring = "f64.copysign";
650 | break;
651 | case OP_I32_WRAP_I64:
652 | instruction.opstring = "i32.wrap/i64";
653 | break;
654 | case OP_I32_TRUNC_S_F32:
655 | instruction.opstring = "i32.trunc_s/f32";
656 | break;
657 | case OP_I32_TRUNC_U_F32:
658 | instruction.opstring = "i32.trunc_u/f32";
659 | break;
660 | case OP_I32_TRUNC_S_F64:
661 | instruction.opstring = "i32.trunc_s/f64";
662 | break;
663 | case OP_I32_TRUNC_U_F64:
664 | instruction.opstring = "i32.trunc_u/f64";
665 | break;
666 | case OP_I64_EXTEND_S_I32:
667 | instruction.opstring = "i64.extend_s/i32";
668 | break;
669 | case OP_I64_EXTEND_U_I32:
670 | instruction.opstring = "i64.extend_u/i32";
671 | break;
672 | case OP_I64_TRUNC_S_F32:
673 | instruction.opstring = "i64.trunc_s/f32";
674 | break;
675 | case OP_I64_TRUNC_U_F32:
676 | instruction.opstring = "i64.trunc_u/f32";
677 | break;
678 | case OP_I64_TRUNC_S_F64:
679 | instruction.opstring = "i64.trunc_s/f64";
680 | break;
681 | case OP_I64_TRUNC_U_F64:
682 | instruction.opstring = "i64.trunc_u/f64";
683 | break;
684 | case OP_F32_CONVERT_S_I32:
685 | instruction.opstring = "f32.convert_s/i32";
686 | break;
687 | case OP_F32_CONVERT_U_I32:
688 | instruction.opstring = "f32.convert_u/i32";
689 | break;
690 | case OP_F32_CONVERT_S_I64:
691 | instruction.opstring = "f32.convert_s/i64";
692 | break;
693 | case OP_F32_CONVERT_U_I64:
694 | instruction.opstring = "f32.convert_u/i64";
695 | break;
696 | case OP_F32_DEMOTE_F64:
697 | instruction.opstring = "f32.demote/f64";
698 | break;
699 | case OP_F64_CONVERT_S_I32:
700 | instruction.opstring = "f64.convert_s/i32";
701 | break;
702 | case OP_F64_CONVERT_U_I32:
703 | instruction.opstring = "f64.convert_u/i32";
704 | break;
705 | case OP_F64_CONVERT_S_I64:
706 | instruction.opstring = "f64.convert_s/i64";
707 | break;
708 | case OP_F64_CONVERT_U_I64:
709 | instruction.opstring = "f64.convert_u/i64";
710 | break;
711 | case OP_F64_PROMOTE_F32:
712 | instruction.opstring = "f64.promote/f32";
713 | break;
714 | case OP_I32_REINTERPRET_F32:
715 | instruction.opstring = "i32.reinterpret/f32";
716 | break;
717 | case OP_I64_REINTERPRET_F64:
718 | instruction.opstring = "i64.reinterpret/f64";
719 | break;
720 | case OP_F32_REINTERPRET_I32:
721 | instruction.opstring = "f32.reinterpret/i32";
722 | break;
723 | case OP_F64_REINTERPRET_I64:
724 | instruction.opstring = "f64.reinterpret/i64";
725 | break;
726 | case OP_I32_EXTEND8_S:
727 | instruction.opstring = "i32.extend8_s";
728 | break;
729 | case OP_I32_EXTEND16_S:
730 | instruction.opstring = "i32.extend16_s";
731 | break;
732 | case OP_I64_EXTEND8_S:
733 | instruction.opstring = "i64.extend8_s";
734 | break;
735 | case OP_I64_EXTEND16_S:
736 | instruction.opstring = "i64.extend16_s";
737 | break;
738 | case OP_I64_EXTEND32_S:
739 | instruction.opstring = "i64.extend32_s";
740 | break;
741 | // TODO Handle BULK_MEMORY, SIMD, and ATOMIC instructions
742 | default:
743 | throw "Invalid/unknown opcode " + instruction.opcode;
744 | }
745 |
746 | return instruction;
747 | }
748 | };
749 |
--------------------------------------------------------------------------------