Index: frontend/node_modules/terser/dist/bundle.min.js
===================================================================
--- frontend/node_modules/terser/dist/bundle.min.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/terser/dist/bundle.min.js	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,34278 @@
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jridgewell/source-map')) :
+typeof define === 'function' && define.amd ? define(['exports', '@jridgewell/source-map'], factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Terser = {}, global.sourceMap));
+})(this, (function (exports, sourceMap) { 'use strict';
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function characters(str) {
+    return str.split("");
+}
+
+function member(name, array) {
+    return array.includes(name);
+}
+
+class DefaultsError extends Error {
+    constructor(msg, defs) {
+        super();
+
+        this.name = "DefaultsError";
+        this.message = msg;
+        this.defs = defs;
+    }
+}
+
+function defaults(args, defs, croak) {
+    if (args === true) {
+        args = {};
+    } else if (args != null && typeof args === "object") {
+        args = {...args};
+    }
+
+    const ret = args || {};
+
+    if (croak) for (const i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
+        throw new DefaultsError("`" + i + "` is not a supported option", defs);
+    }
+
+    for (const i in defs) if (HOP(defs, i)) {
+        if (!args || !HOP(args, i)) {
+            ret[i] = defs[i];
+        } else if (i === "ecma" || i === "builtins_ecma") {
+            let ecma = args[i] | 0;
+            if (ecma > 5 && ecma < 2015) ecma += 2009;
+            ret[i] = ecma;
+        } else {
+            ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
+        }
+    }
+
+    return ret;
+}
+
+function noop() {}
+function return_false() { return false; }
+function return_true() { return true; }
+function return_this() { return this; }
+function return_null() { return null; }
+
+var MAP = (function() {
+    function MAP(a, tw, allow_splicing = true) {
+        const new_a = [];
+
+        for (let i = 0; i < a.length; ++i) {
+            let item = a[i];
+            let ret = item.transform(tw, allow_splicing);
+
+            if (ret instanceof AST_Node) {
+                new_a.push(ret);
+            } else if (ret instanceof Splice) {
+                new_a.push(...ret.v);
+            }
+        }
+
+        return new_a;
+    }
+
+    MAP.splice = function(val) { return new Splice(val); };
+    MAP.skip = {};
+    function Splice(val) { this.v = val; }
+    return MAP;
+})();
+
+function make_node(ctor, orig, props) {
+    if (!props) props = {};
+    if (orig) {
+        if (!props.start) props.start = orig.start;
+        if (!props.end) props.end = orig.end;
+    }
+    return new ctor(props);
+}
+
+/** Makes a `void 0` expression. Use instead of AST_Undefined which may conflict
+ * with an existing variable called `undefined` */
+function make_void_0(orig) {
+    return make_node(AST_UnaryPrefix, orig, {
+        operator: "void",
+        expression: make_node(AST_Number, orig, { value: 0 })
+    });
+}
+
+function push_uniq(array, el) {
+    if (!array.includes(el))
+        array.push(el);
+}
+
+function string_template(text, props) {
+    return text.replace(/{(.+?)}/g, function(str, p) {
+        return props && props[p];
+    });
+}
+
+function remove(array, el) {
+    for (var i = array.length; --i >= 0;) {
+        if (array[i] === el) array.splice(i, 1);
+    }
+}
+
+function mergeSort(array, cmp) {
+    if (array.length < 2) return array.slice();
+    function merge(a, b) {
+        var r = [], ai = 0, bi = 0, i = 0;
+        while (ai < a.length && bi < b.length) {
+            cmp(a[ai], b[bi]) <= 0
+                ? r[i++] = a[ai++]
+                : r[i++] = b[bi++];
+        }
+        if (ai < a.length) r.push.apply(r, a.slice(ai));
+        if (bi < b.length) r.push.apply(r, b.slice(bi));
+        return r;
+    }
+    function _ms(a) {
+        if (a.length <= 1)
+            return a;
+        var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
+        left = _ms(left);
+        right = _ms(right);
+        return merge(left, right);
+    }
+    return _ms(array);
+}
+
+function makePredicate(words) {
+    if (!Array.isArray(words)) words = words.split(" ");
+
+    return new Set(words.sort());
+}
+
+function map_add(map, key, value) {
+    if (map.has(key)) {
+        map.get(key).push(value);
+    } else {
+        map.set(key, [ value ]);
+    }
+}
+
+function map_from_object(obj) {
+    var map = new Map();
+    for (var key in obj) {
+        if (HOP(obj, key) && key.charAt(0) === "$") {
+            map.set(key.substr(1), obj[key]);
+        }
+    }
+    return map;
+}
+
+function map_to_object(map) {
+    var obj = Object.create(null);
+    map.forEach(function (value, key) {
+        obj["$" + key] = value;
+    });
+    return obj;
+}
+
+function HOP(obj, prop) {
+    return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+function keep_name(keep_setting, name) {
+    return keep_setting === true
+        || (keep_setting instanceof RegExp && keep_setting.test(name));
+}
+
+var lineTerminatorEscape = {
+    "\0": "0",
+    "\n": "n",
+    "\r": "r",
+    "\u2028": "u2028",
+    "\u2029": "u2029",
+};
+function regexp_source_fix(source) {
+    // V8 does not escape line terminators in regexp patterns in node 12
+    // We'll also remove literal \0
+    return source.replace(/[\0\n\r\u2028\u2029]/g, function (match, offset) {
+        var escaped = source[offset - 1] == "\\"
+            && (source[offset - 2] != "\\"
+            || /(?:^|[^\\])(?:\\{2})*$/.test(source.slice(0, offset - 1)));
+        return (escaped ? "" : "\\") + lineTerminatorEscape[match];
+    });
+}
+
+// Subset of regexps that is not going to cause regexp based DDOS
+// https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
+const re_safe_regexp = /^[\\/|\0\s\w^$.[\]()]*$/;
+
+/** Check if the regexp is safe for Terser to create without risking a RegExp DOS */
+const regexp_is_safe = (source) => re_safe_regexp.test(source);
+
+const all_flags = "dgimsuyv";
+function sort_regexp_flags(flags) {
+    const existing_flags = new Set(flags.split(""));
+    let out = "";
+    for (const flag of all_flags) {
+        if (existing_flags.has(flag)) {
+            out += flag;
+            existing_flags.delete(flag);
+        }
+    }
+    if (existing_flags.size) {
+        // Flags Terser doesn't know about
+        existing_flags.forEach(flag => { out += flag; });
+    }
+    return out;
+}
+
+function has_annotation(node, annotation) {
+    return node._annotations & annotation;
+}
+
+function set_annotation(node, annotation) {
+    node._annotations |= annotation;
+}
+
+function clear_annotation(node, annotation) {
+    node._annotations &= ~annotation;
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+    Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/).
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+var LATEST_RAW = "";  // Only used for numbers and template strings
+var TEMPLATE_RAWS = new Map();  // Raw template strings
+
+var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with";
+var KEYWORDS_ATOM = "false null true";
+var RESERVED_WORDS = "enum import super this " + KEYWORDS_ATOM + " " + KEYWORDS;
+var ALL_RESERVED_WORDS = "implements interface package private protected public static " + RESERVED_WORDS;
+var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case yield await";
+
+KEYWORDS = makePredicate(KEYWORDS);
+RESERVED_WORDS = makePredicate(RESERVED_WORDS);
+KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION);
+KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM);
+ALL_RESERVED_WORDS = makePredicate(ALL_RESERVED_WORDS);
+
+var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
+
+var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
+var RE_OCT_NUMBER = /^0[0-7]+$/;
+var RE_ES6_OCT_NUMBER = /^0o[0-7]+$/i;
+var RE_BIN_NUMBER = /^0b[01]+$/i;
+var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
+var RE_BIG_INT = /^(0[xob])?[0-9a-f]+n$/i;
+
+var RE_KEYWORD_RELATIONAL_OPERATORS = /in(?:stanceof)?/y;
+
+var OPERATORS = makePredicate([
+    "in",
+    "instanceof",
+    "typeof",
+    "new",
+    "void",
+    "delete",
+    "++",
+    "--",
+    "+",
+    "-",
+    "!",
+    "~",
+    "&",
+    "|",
+    "^",
+    "*",
+    "**",
+    "/",
+    "%",
+    ">>",
+    "<<",
+    ">>>",
+    "<",
+    ">",
+    "<=",
+    ">=",
+    "==",
+    "===",
+    "!=",
+    "!==",
+    "?",
+    "=",
+    "+=",
+    "-=",
+    "||=",
+    "&&=",
+    "??=",
+    "/=",
+    "*=",
+    "**=",
+    "%=",
+    ">>=",
+    "<<=",
+    ">>>=",
+    "|=",
+    "^=",
+    "&=",
+    "&&",
+    "??",
+    "||",
+]);
+
+var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF"));
+
+var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
+
+var PUNC_AFTER_EXPRESSION = makePredicate(characters(";]),:"));
+
+var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:"));
+
+var PUNC_CHARS = makePredicate(characters("[]{}(),;:"));
+
+/* -----[ Tokenizer ]----- */
+
+// surrogate safe regexps adapted from https://github.com/mathiasbynens/unicode-8.0.0/tree/89b412d8a71ecca9ed593d9e9fa073ab64acfebe/Binary_Property
+var UNICODE = {
+    ID_Start: /[$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,
+    ID_Continue: /(?:[$0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF])+/,
+};
+
+function get_full_char(str, pos) {
+    if (is_surrogate_pair_head(str.charCodeAt(pos))) {
+        if (is_surrogate_pair_tail(str.charCodeAt(pos + 1))) {
+            return str.charAt(pos) + str.charAt(pos + 1);
+        }
+    } else if (is_surrogate_pair_tail(str.charCodeAt(pos))) {
+        if (is_surrogate_pair_head(str.charCodeAt(pos - 1))) {
+            return str.charAt(pos - 1) + str.charAt(pos);
+        }
+    }
+    return str.charAt(pos);
+}
+
+function get_full_char_code(str, pos) {
+    // https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates
+    if (is_surrogate_pair_head(str.charCodeAt(pos))) {
+        return 0x10000 + (str.charCodeAt(pos) - 0xd800 << 10) + str.charCodeAt(pos + 1) - 0xdc00;
+    }
+    return str.charCodeAt(pos);
+}
+
+function get_full_char_length(str) {
+    var surrogates = 0;
+
+    for (var i = 0; i < str.length; i++) {
+        if (is_surrogate_pair_head(str.charCodeAt(i)) && is_surrogate_pair_tail(str.charCodeAt(i + 1))) {
+            surrogates++;
+            i++;
+        }
+    }
+
+    return str.length - surrogates;
+}
+
+function from_char_code(code) {
+    // Based on https://github.com/mathiasbynens/String.fromCodePoint/blob/master/fromcodepoint.js
+    if (code > 0xFFFF) {
+        code -= 0x10000;
+        return (String.fromCharCode((code >> 10) + 0xD800) +
+            String.fromCharCode((code % 0x400) + 0xDC00));
+    }
+    return String.fromCharCode(code);
+}
+
+function is_surrogate_pair_head(code) {
+    return code >= 0xd800 && code <= 0xdbff;
+}
+
+function is_surrogate_pair_tail(code) {
+    return code >= 0xdc00 && code <= 0xdfff;
+}
+
+function is_digit(code) {
+    return code >= 48 && code <= 57;
+}
+
+function is_identifier_start(ch) {
+    return UNICODE.ID_Start.test(ch);
+}
+
+function is_identifier_char(ch) {
+    return UNICODE.ID_Continue.test(ch);
+}
+
+const BASIC_IDENT = /^[a-z_$][a-z0-9_$]*$/i;
+
+function is_basic_identifier_string(str) {
+    return BASIC_IDENT.test(str);
+}
+
+function is_identifier_string(str, allow_surrogates) {
+    if (BASIC_IDENT.test(str)) {
+        return true;
+    }
+    if (!allow_surrogates && /[\ud800-\udfff]/.test(str)) {
+        return false;
+    }
+    var match = UNICODE.ID_Start.exec(str);
+    if (!match || match.index !== 0) {
+        return false;
+    }
+
+    str = str.slice(match[0].length);
+    if (!str) {
+        return true;
+    }
+
+    match = UNICODE.ID_Continue.exec(str);
+    return !!match && match[0].length === str.length;
+}
+
+function parse_js_number(num, allow_e = true) {
+    if (!allow_e && num.includes("e")) {
+        return NaN;
+    }
+    if (RE_HEX_NUMBER.test(num)) {
+        return parseInt(num.substr(2), 16);
+    } else if (RE_OCT_NUMBER.test(num)) {
+        return parseInt(num.substr(1), 8);
+    } else if (RE_ES6_OCT_NUMBER.test(num)) {
+        return parseInt(num.substr(2), 8);
+    } else if (RE_BIN_NUMBER.test(num)) {
+        return parseInt(num.substr(2), 2);
+    } else if (RE_DEC_NUMBER.test(num)) {
+        return parseFloat(num);
+    } else {
+        var val = parseFloat(num);
+        if (val == num) return val;
+    }
+}
+
+class JS_Parse_Error extends Error {
+    constructor(message, filename, line, col, pos) {
+        super();
+
+        this.name = "SyntaxError";
+        this.message = message;
+        this.filename = filename;
+        this.line = line;
+        this.col = col;
+        this.pos = pos;
+    }
+}
+
+function js_error(message, filename, line, col, pos) {
+    throw new JS_Parse_Error(message, filename, line, col, pos);
+}
+
+function is_token(token, type, val) {
+    return token.type == type && (val == null || token.value == val);
+}
+
+var EX_EOF = {};
+
+function tokenizer($TEXT, filename, html5_comments, shebang) {
+    var S = {
+        text            : $TEXT,
+        filename        : filename,
+        pos             : 0,
+        tokpos          : 0,
+        line            : 1,
+        tokline         : 0,
+        col             : 0,
+        tokcol          : 0,
+        newline_before  : false,
+        regex_allowed   : false,
+        brace_counter   : 0,
+        template_braces : [],
+        comments_before : [],
+        directives      : {},
+        directive_stack : []
+    };
+
+    function peek() { return get_full_char(S.text, S.pos); }
+
+    // Used because parsing ?. involves a lookahead for a digit
+    function is_option_chain_op() {
+        const must_be_dot = S.text.charCodeAt(S.pos + 1) === 46;
+        if (!must_be_dot) return false;
+
+        const cannot_be_digit = S.text.charCodeAt(S.pos + 2);
+        return cannot_be_digit < 48 || cannot_be_digit > 57;
+    }
+
+    function next(signal_eof, in_string) {
+        var ch = get_full_char(S.text, S.pos++);
+        if (signal_eof && !ch)
+            throw EX_EOF;
+        if (NEWLINE_CHARS.has(ch)) {
+            S.newline_before = S.newline_before || !in_string;
+            ++S.line;
+            S.col = 0;
+            if (ch == "\r" && peek() == "\n") {
+                // treat a \r\n sequence as a single \n
+                ++S.pos;
+                ch = "\n";
+            }
+        } else {
+            if (ch.length > 1) {
+                ++S.pos;
+                ++S.col;
+            }
+            ++S.col;
+        }
+        return ch;
+    }
+
+    function forward(i) {
+        while (i--) next();
+    }
+
+    function looking_at(str) {
+        return S.text.substr(S.pos, str.length) == str;
+    }
+
+    function find_eol() {
+        var text = S.text;
+        for (var i = S.pos, n = S.text.length; i < n; ++i) {
+            var ch = text[i];
+            if (NEWLINE_CHARS.has(ch))
+                return i;
+        }
+        return -1;
+    }
+
+    function find(what, signal_eof) {
+        var pos = S.text.indexOf(what, S.pos);
+        if (signal_eof && pos == -1) throw EX_EOF;
+        return pos;
+    }
+
+    function start_token() {
+        S.tokline = S.line;
+        S.tokcol = S.col;
+        S.tokpos = S.pos;
+    }
+
+    var prev_was_dot = false;
+    var previous_token = null;
+    function token(type, value, is_comment) {
+        S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX.has(value)) ||
+                           (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION.has(value)) ||
+                           (type == "punc" && PUNC_BEFORE_EXPRESSION.has(value))) ||
+                           (type == "arrow");
+        if (type == "punc" && (value == "." || value == "?.")) {
+            prev_was_dot = true;
+        } else if (!is_comment) {
+            prev_was_dot = false;
+        }
+        const line     = S.tokline;
+        const col      = S.tokcol;
+        const pos      = S.tokpos;
+        const nlb      = S.newline_before;
+        const file     = filename;
+        let comments_before = [];
+        let comments_after  = [];
+
+        if (!is_comment) {
+            comments_before = S.comments_before;
+            comments_after = S.comments_before = [];
+        }
+        S.newline_before = false;
+        const tok = new AST_Token(type, value, line, col, pos, nlb, comments_before, comments_after, file);
+
+        if (!is_comment) previous_token = tok;
+        return tok;
+    }
+
+    function skip_whitespace() {
+        while (WHITESPACE_CHARS.has(peek()))
+            next();
+    }
+
+    function peek_next_token_start_or_newline() {
+        var pos = S.pos;
+        for (var in_multiline_comment = false; pos < S.text.length; ) {
+            var ch = get_full_char(S.text, pos);
+            if (NEWLINE_CHARS.has(ch)) {
+                return { char: ch, pos: pos };
+            } else if (in_multiline_comment) {
+                if (ch == "*" && get_full_char(S.text, pos + 1) == "/") {
+                    pos += 2;
+                    in_multiline_comment = false;
+                } else {
+                    pos++;
+                }
+            } else if (!WHITESPACE_CHARS.has(ch)) {
+                if (ch == "/") {
+                    var next_ch = get_full_char(S.text, pos + 1);
+                    if (next_ch == "/") {
+                        pos = find_eol();
+                        return { char: get_full_char(S.text, pos), pos: pos };
+                    } else if (next_ch == "*") {
+                        in_multiline_comment = true;
+                        pos += 2;
+                        continue;
+                    }
+                }
+                return { char: ch, pos: pos };
+            } else {
+                pos++;
+            }
+        }
+        return { char: null, pos: pos };
+    }
+
+    function ch_starts_binding_identifier(ch, pos) {
+        if (ch == "\\") {
+            return true;
+        } else if (is_identifier_start(ch)) {
+            RE_KEYWORD_RELATIONAL_OPERATORS.lastIndex = pos;
+            if (RE_KEYWORD_RELATIONAL_OPERATORS.test(S.text)) {
+                var after = get_full_char(S.text, RE_KEYWORD_RELATIONAL_OPERATORS.lastIndex);
+                if (!is_identifier_char(after) && after != "\\") {
+                    // "in" or "instanceof" are keywords, not binding identifiers
+                    return false; 
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    function read_while(pred) {
+        var ret = "", ch, i = 0;
+        while ((ch = peek()) && pred(ch, i++))
+            ret += next();
+        return ret;
+    }
+
+    function parse_error(err) {
+        js_error(err, filename, S.tokline, S.tokcol, S.tokpos);
+    }
+
+    function read_num(prefix) {
+        var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false, numeric_separator = false;
+        var num = read_while(function(ch, i) {
+            if (is_big_int) return false;
+
+            var code = ch.charCodeAt(0);
+            switch (code) {
+              case 95: // _
+                return (numeric_separator = true);
+              case 98: case 66: // bB
+                return (has_x = true); // Can occur in hex sequence, don't return false yet
+              case 111: case 79: // oO
+              case 120: case 88: // xX
+                return has_x ? false : (has_x = true);
+              case 101: case 69: // eE
+                return has_x ? true : has_e ? false : (has_e = after_e = true);
+              case 45: // -
+                return after_e || (i == 0 && !prefix);
+              case 43: // +
+                return after_e;
+              case (after_e = false, 46): // .
+                return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false;
+              case 110: // n
+                is_big_int = true;
+                return true;
+            }
+
+            return (
+                code >= 48 && code <= 57 // 0-9
+                || code >= 97 && code <= 102 // a-f
+                || code >= 65 && code <= 70 // A-F
+            );
+        });
+        if (prefix) num = prefix + num;
+
+        LATEST_RAW = num;
+
+        if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
+            parse_error("Legacy octal literals are not allowed in strict mode");
+        }
+        if (numeric_separator) {
+            if (num.endsWith("_")) {
+                parse_error("Numeric separators are not allowed at the end of numeric literals");
+            } else if (num.includes("__")) {
+                parse_error("Only one underscore is allowed as numeric separator");
+            }
+            num = num.replace(/_/g, "");
+        }
+        if (is_big_int) {
+            const without_n = num.slice(0, -1);
+            const allow_e = RE_HEX_NUMBER.test(without_n);
+            const valid = parse_js_number(without_n, allow_e);
+            if (!has_dot && RE_BIG_INT.test(num) && !isNaN(valid))
+                return token("big_int", without_n);
+            parse_error("Invalid or unexpected token");
+        }
+        var valid = parse_js_number(num);
+        if (!isNaN(valid)) {
+            return token("num", valid);
+        } else {
+            parse_error("Invalid syntax: " + num);
+        }
+    }
+
+    function is_octal(ch) {
+        return ch >= "0" && ch <= "7";
+    }
+
+    function read_escaped_char(in_string, strict_hex, template_string) {
+        var ch = next(true, in_string);
+        switch (ch.charCodeAt(0)) {
+          case 110 : return "\n";
+          case 114 : return "\r";
+          case 116 : return "\t";
+          case 98  : return "\b";
+          case 118 : return "\u000b"; // \v
+          case 102 : return "\f";
+          case 120 : return String.fromCharCode(hex_bytes(2, strict_hex)); // \x
+          case 117 : // \u
+            if (peek() == "{") {
+                next(true);
+                if (peek() === "}")
+                    parse_error("Expecting hex-character between {}");
+                while (peek() == "0") next(true); // No significance
+                var result, length = find("}", true) - S.pos;
+                // Avoid 32 bit integer overflow (1 << 32 === 1)
+                // We know first character isn't 0 and thus out of range anyway
+                if (length > 6 || (result = hex_bytes(length, strict_hex)) > 0x10FFFF) {
+                    parse_error("Unicode reference out of bounds");
+                }
+                next(true);
+                return from_char_code(result);
+            }
+            return String.fromCharCode(hex_bytes(4, strict_hex));
+          case 10  : return ""; // newline
+          case 13  :            // \r
+            if (peek() == "\n") { // DOS newline
+                next(true, in_string);
+                return "";
+            }
+        }
+        if (is_octal(ch)) {
+            if (template_string && strict_hex) {
+                const represents_null_character = ch === "0" && !is_octal(peek());
+                if (!represents_null_character) {
+                    parse_error("Octal escape sequences are not allowed in template strings");
+                }
+            }
+            return read_octal_escape_sequence(ch, strict_hex);
+        }
+        return ch;
+    }
+
+    function read_octal_escape_sequence(ch, strict_octal) {
+        // Read
+        var p = peek();
+        if (p >= "0" && p <= "7") {
+            ch += next(true);
+            if (ch[0] <= "3" && (p = peek()) >= "0" && p <= "7")
+                ch += next(true);
+        }
+
+        // Parse
+        if (ch === "0") return "\0";
+        if (ch.length > 0 && next_token.has_directive("use strict") && strict_octal)
+            parse_error("Legacy octal escape sequences are not allowed in strict mode");
+        return String.fromCharCode(parseInt(ch, 8));
+    }
+
+    function hex_bytes(n, strict_hex) {
+        var num = 0;
+        for (; n > 0; --n) {
+            if (!strict_hex && isNaN(parseInt(peek(), 16))) {
+                return parseInt(num, 16) || "";
+            }
+            var digit = next(true);
+            if (isNaN(parseInt(digit, 16)))
+                parse_error("Invalid hex-character pattern in string");
+            num += digit;
+        }
+        return parseInt(num, 16);
+    }
+
+    var read_string = with_eof_error("Unterminated string constant", function() {
+        const start_pos = S.pos;
+        var quote = next(), ret = [];
+        for (;;) {
+            var ch = next(true, true);
+            if (ch == "\\") ch = read_escaped_char(true, true);
+            else if (ch == "\r" || ch == "\n") parse_error("Unterminated string constant");
+            else if (ch == quote) break;
+            ret.push(ch);
+        }
+        var tok = token("string", ret.join(""));
+        LATEST_RAW = S.text.slice(start_pos, S.pos);
+        tok.quote = quote;
+        return tok;
+    });
+
+    var read_template_characters = with_eof_error("Unterminated template", function(begin) {
+        if (begin) {
+            S.template_braces.push(S.brace_counter);
+        }
+        var content = "", raw = "", ch, tok;
+        next(true, true);
+        while ((ch = next(true, true)) != "`") {
+            if (ch == "\r") {
+                if (peek() == "\n") ++S.pos;
+                ch = "\n";
+            } else if (ch == "$" && peek() == "{") {
+                next(true, true);
+                S.brace_counter++;
+                tok = token(begin ? "template_head" : "template_cont", content);
+                TEMPLATE_RAWS.set(tok, raw);
+                tok.template_end = false;
+                return tok;
+            }
+
+            raw += ch;
+            if (ch == "\\") {
+                var tmp = S.pos;
+                var prev_is_tag = previous_token && (previous_token.type === "name" || previous_token.type === "punc" && (previous_token.value === ")" || previous_token.value === "]"));
+                ch = read_escaped_char(true, !prev_is_tag, true);
+                raw += S.text.substr(tmp, S.pos - tmp);
+            }
+
+            content += ch;
+        }
+        S.template_braces.pop();
+        tok = token(begin ? "template_head" : "template_cont", content);
+        TEMPLATE_RAWS.set(tok, raw);
+        tok.template_end = true;
+        return tok;
+    });
+
+    function skip_line_comment(type) {
+        var regex_allowed = S.regex_allowed;
+        var i = find_eol(), ret;
+        if (i == -1) {
+            ret = S.text.substr(S.pos);
+            S.pos = S.text.length;
+        } else {
+            ret = S.text.substring(S.pos, i);
+            S.pos = i;
+        }
+        S.col = S.tokcol + (S.pos - S.tokpos);
+        S.comments_before.push(token(type, ret, true));
+        S.regex_allowed = regex_allowed;
+        return next_token;
+    }
+
+    var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() {
+        var regex_allowed = S.regex_allowed;
+        var i = find("*/", true);
+        var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n");
+        // update stream position
+        forward(get_full_char_length(text) /* text length doesn't count \r\n as 2 char while S.pos - i does */ + 2);
+        S.comments_before.push(token("comment2", text, true));
+        S.newline_before = S.newline_before || text.includes("\n");
+        S.regex_allowed = regex_allowed;
+        return next_token;
+    });
+
+    var read_name = function () {
+        let start = S.pos, end = start - 1, ch = "c";
+
+        while (
+            (ch = S.text.charAt(++end))
+            && (ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z")
+        );
+
+        // 0x7F is very rare in actual code, so we compare it to "~" (0x7E)
+        if (end > start + 1 && ch && ch !== "\\" && !is_identifier_char(ch) && ch <= "~") {
+            S.pos += end - start;
+            S.col += end - start;
+            return S.text.slice(start, S.pos);
+        }
+
+        return read_name_hard();
+    };
+
+    var read_name_hard = with_eof_error("Unterminated identifier name", function() {
+        var name = [], ch, escaped = false;
+        var read_escaped_identifier_char = function() {
+            escaped = true;
+            next();
+            if (peek() !== "u") {
+                parse_error("Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}");
+            }
+            return read_escaped_char(false, true);
+        };
+
+        // Read first character (ID_Start)
+        if ((ch = peek()) === "\\") {
+            ch = read_escaped_identifier_char();
+            if (!is_identifier_start(ch)) {
+                parse_error("First identifier char is an invalid identifier char");
+            }
+        } else if (is_identifier_start(ch)) {
+            next();
+        } else {
+            return "";
+        }
+
+        name.push(ch);
+
+        // Read ID_Continue
+        while ((ch = peek()) != null) {
+            if ((ch = peek()) === "\\") {
+                ch = read_escaped_identifier_char();
+                if (!is_identifier_char(ch)) {
+                    parse_error("Invalid escaped identifier char");
+                }
+            } else {
+                if (!is_identifier_char(ch)) {
+                    break;
+                }
+                next();
+            }
+            name.push(ch);
+        }
+        const name_str = name.join("");
+        if (RESERVED_WORDS.has(name_str) && escaped) {
+            parse_error("Escaped characters are not allowed in keywords");
+        }
+        return name_str;
+    });
+
+    var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
+        var prev_backslash = false, ch, in_class = false;
+        while ((ch = next(true))) if (NEWLINE_CHARS.has(ch)) {
+            parse_error("Unexpected line terminator");
+        } else if (prev_backslash) {
+            if (/^[\u0000-\u007F]$/.test(ch)) {
+                source += "\\" + ch;
+            } else {
+                // Remove the useless slash before the escape, but only for characters that won't be added to regexp syntax
+                source += ch;
+            }
+            prev_backslash = false;
+        } else if (ch == "[") {
+            in_class = true;
+            source += ch;
+        } else if (ch == "]" && in_class) {
+            in_class = false;
+            source += ch;
+        } else if (ch == "/" && !in_class) {
+            break;
+        } else if (ch == "\\") {
+            prev_backslash = true;
+        } else {
+            source += ch;
+        }
+        const flags = read_name();
+        return token("regexp", "/" + source + "/" + flags);
+    });
+
+    function read_operator(prefix) {
+        function grow(op) {
+            if (!peek()) return op;
+            var bigger = op + peek();
+            if (OPERATORS.has(bigger)) {
+                next();
+                return grow(bigger);
+            } else {
+                return op;
+            }
+        }
+        return token("operator", grow(prefix || next()));
+    }
+
+    function handle_slash() {
+        next();
+        switch (peek()) {
+          case "/":
+            next();
+            return skip_line_comment("comment1");
+          case "*":
+            next();
+            return skip_multiline_comment();
+        }
+        return S.regex_allowed ? read_regexp("") : read_operator("/");
+    }
+
+    function handle_eq_sign() {
+        next();
+        if (peek() === ">") {
+            next();
+            return token("arrow", "=>");
+        } else {
+            return read_operator("=");
+        }
+    }
+
+    function handle_dot() {
+        next();
+        if (is_digit(peek().charCodeAt(0))) {
+            return read_num(".");
+        }
+        if (peek() === ".") {
+            next();  // Consume second dot
+            next();  // Consume third dot
+            return token("expand", "...");
+        }
+
+        return token("punc", ".");
+    }
+
+    function read_word() {
+        var word = read_name();
+        if (prev_was_dot) return token("name", word);
+        return KEYWORDS_ATOM.has(word) ? token("atom", word)
+            : !KEYWORDS.has(word) ? token("name", word)
+            : OPERATORS.has(word) ? token("operator", word)
+            : token("keyword", word);
+    }
+
+    function read_private_word() {
+        next();
+        return token("privatename", read_name());
+    }
+
+    function with_eof_error(eof_error, cont) {
+        return function(x) {
+            try {
+                return cont(x);
+            } catch(ex) {
+                if (ex === EX_EOF) parse_error(eof_error);
+                else throw ex;
+            }
+        };
+    }
+
+    function next_token(force_regexp) {
+        if (force_regexp != null)
+            return read_regexp(force_regexp);
+        if (shebang && S.pos == 0 && looking_at("#!")) {
+            start_token();
+            forward(2);
+            skip_line_comment("comment5");
+        }
+        for (;;) {
+            skip_whitespace();
+            start_token();
+            if (html5_comments) {
+                if (looking_at("<!--")) {
+                    forward(4);
+                    skip_line_comment("comment3");
+                    continue;
+                }
+                if (looking_at("-->") && S.newline_before) {
+                    forward(3);
+                    skip_line_comment("comment4");
+                    continue;
+                }
+            }
+            var ch = peek();
+            if (!ch) return token("eof");
+            var code = ch.charCodeAt(0);
+            switch (code) {
+              case 34: case 39: return read_string();
+              case 46: return handle_dot();
+              case 47: {
+                  var tok = handle_slash();
+                  if (tok === next_token) continue;
+                  return tok;
+              }
+              case 61: return handle_eq_sign();
+              case 63: {
+                  if (!is_option_chain_op()) break;  // Handled below
+
+                  next(); // ?
+                  next(); // .
+
+                  return token("punc", "?.");
+              }
+              case 96: return read_template_characters(true);
+              case 123:
+                S.brace_counter++;
+                break;
+              case 125:
+                S.brace_counter--;
+                if (S.template_braces.length > 0
+                    && S.template_braces[S.template_braces.length - 1] === S.brace_counter)
+                    return read_template_characters(false);
+                break;
+            }
+            if (is_digit(code)) return read_num();
+            if (PUNC_CHARS.has(ch)) return token("punc", next());
+            if (OPERATOR_CHARS.has(ch)) return read_operator();
+            if (code == 92 || is_identifier_start(ch)) return read_word();
+            if (code == 35) return read_private_word();
+            break;
+        }
+        parse_error("Unexpected character '" + ch + "'");
+    }
+
+    next_token.next = next;
+    next_token.peek = peek;
+
+    next_token.context = function(nc) {
+        if (nc) S = nc;
+        return S;
+    };
+
+    next_token.add_directive = function(directive) {
+        S.directive_stack[S.directive_stack.length - 1].push(directive);
+
+        if (S.directives[directive] === undefined) {
+            S.directives[directive] = 1;
+        } else {
+            S.directives[directive]++;
+        }
+    };
+
+    next_token.push_directives_stack = function() {
+        S.directive_stack.push([]);
+    };
+
+    next_token.pop_directives_stack = function() {
+        var directives = S.directive_stack[S.directive_stack.length - 1];
+
+        for (var i = 0; i < directives.length; i++) {
+            S.directives[directives[i]]--;
+        }
+
+        S.directive_stack.pop();
+    };
+
+    next_token.has_directive = function(directive) {
+        return S.directives[directive] > 0;
+    };
+
+    next_token.peek_next_token_start_or_newline = peek_next_token_start_or_newline;
+    next_token.ch_starts_binding_identifier = ch_starts_binding_identifier;
+
+    return next_token;
+
+}
+
+/* -----[ Parser (constants) ]----- */
+
+var UNARY_PREFIX = makePredicate([
+    "typeof",
+    "void",
+    "delete",
+    "--",
+    "++",
+    "!",
+    "~",
+    "-",
+    "+"
+]);
+
+var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
+
+var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "??=", "&&=", "||=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
+
+var LOGICAL_ASSIGNMENT = makePredicate([ "??=", "&&=", "||=" ]);
+
+var PRECEDENCE = (function(a, ret) {
+    for (var i = 0; i < a.length; ++i) {
+        for (const op of a[i]) {
+            ret[op] = i + 1;
+        }
+    }
+    return ret;
+})(
+    [
+        ["||"],
+        ["??"],
+        ["&&"],
+        ["|"],
+        ["^"],
+        ["&"],
+        ["==", "===", "!=", "!=="],
+        ["<", ">", "<=", ">=", "in", "instanceof"],
+        [">>", "<<", ">>>"],
+        ["+", "-"],
+        ["*", "/", "%"],
+        ["**"]
+    ],
+    {}
+);
+
+var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name"]);
+
+/* -----[ Parser ]----- */
+
+function parse($TEXT, options) {
+    // maps start tokens to count of comments found outside of their parens
+    // Example: /* I count */ ( /* I don't */ foo() )
+    // Useful because comments_before property of call with parens outside
+    // contains both comments inside and outside these parens. Used to find the
+    
+    const outer_comments_before_counts = new WeakMap();
+
+    options = defaults(options, {
+        bare_returns   : false,
+        ecma           : null,  // Legacy
+        expression     : false,
+        filename       : null,
+        html5_comments : true,
+        module         : false,
+        shebang        : true,
+        strict         : false,
+        toplevel       : null,
+    }, true);
+
+    var S = {
+        input         : (typeof $TEXT == "string"
+                         ? tokenizer($TEXT, options.filename,
+                                     options.html5_comments, options.shebang)
+                         : $TEXT),
+        token         : null,
+        prev          : null,
+        peeked        : null,
+        in_function   : 0,
+        in_async      : -1,
+        in_generator  : -1,
+        in_directives : true,
+        in_loop       : 0,
+        labels        : []
+    };
+
+    S.token = next();
+
+    function is(type, value) {
+        return is_token(S.token, type, value);
+    }
+
+    function peek() { return S.peeked || (S.peeked = S.input()); }
+
+    function next() {
+        S.prev = S.token;
+
+        if (!S.peeked) peek();
+        S.token = S.peeked;
+        S.peeked = null;
+        S.in_directives = S.in_directives && (
+            S.token.type == "string" || is("punc", ";")
+        );
+        return S.token;
+    }
+
+    function prev() {
+        return S.prev;
+    }
+
+    function croak(msg, line, col, pos) {
+        var ctx = S.input.context();
+        js_error(msg,
+                 ctx.filename,
+                 line != null ? line : ctx.tokline,
+                 col != null ? col : ctx.tokcol,
+                 pos != null ? pos : ctx.tokpos);
+    }
+
+    function token_error(token, msg) {
+        croak(msg, token.line, token.col);
+    }
+
+    function unexpected(token) {
+        if (token == null)
+            token = S.token;
+        token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
+    }
+
+    function expect_token(type, val) {
+        if (is(type, val)) {
+            return next();
+        }
+        token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
+    }
+
+    function expect(punc) { return expect_token("punc", punc); }
+
+    function has_newline_before(token) {
+        return token.nlb || !token.comments_before.every((comment) => !comment.nlb);
+    }
+
+    function can_insert_semicolon() {
+        return !options.strict
+            && (is("eof") || is("punc", "}") || has_newline_before(S.token));
+    }
+
+    function is_in_generator() {
+        return S.in_generator === S.in_function;
+    }
+
+    function is_in_async() {
+        return S.in_async === S.in_function;
+    }
+
+    function can_await() {
+        return (
+            S.in_async === S.in_function
+            || S.in_function === 0 && S.input.has_directive("use strict")
+        );
+    }
+
+    function semicolon(optional) {
+        if (is("punc", ";")) next();
+        else if (!optional && !can_insert_semicolon()) unexpected();
+    }
+
+    function parenthesised() {
+        expect("(");
+        var exp = expression(true);
+        expect(")");
+        return exp;
+    }
+
+    function embed_tokens(parser) {
+        return function _embed_tokens_wrapper(...args) {
+            const start = S.token;
+            const expr = parser(...args);
+            expr.start = start;
+            expr.end = prev();
+            return expr;
+        };
+    }
+
+    function handle_regexp() {
+        if (is("operator", "/") || is("operator", "/=")) {
+            S.peeked = null;
+            S.token = S.input(S.token.value.substr(1)); // force regexp
+        }
+    }
+
+    var statement = embed_tokens(function statement(is_export_default, is_for_body, is_if_body) {
+        handle_regexp();
+        switch (S.token.type) {
+          case "string":
+            if (S.in_directives) {
+                var token = peek();
+                if (!LATEST_RAW.includes("\\")
+                    && (is_token(token, "punc", ";")
+                        || is_token(token, "punc", "}")
+                        || has_newline_before(token)
+                        || is_token(token, "eof"))) {
+                    S.input.add_directive(S.token.value);
+                } else {
+                    S.in_directives = false;
+                }
+            }
+            var dir = S.in_directives, stat = simple_statement();
+            return dir && stat.body instanceof AST_String ? new AST_Directive(stat.body) : stat;
+          case "template_head":
+          case "num":
+          case "big_int":
+          case "regexp":
+          case "operator":
+          case "atom":
+            return simple_statement();
+
+          case "name":
+            if (S.token.value == "async" && is_token(peek(), "keyword", "function")) {
+                next();
+                next();
+                if (is_for_body) {
+                    croak("functions are not allowed as the body of a loop");
+                }
+                return function_(AST_Defun, false, true, is_export_default);
+            }
+            if (S.token.value == "import" && !is_token(peek(), "punc", "(") && !is_token(peek(), "punc", ".")) {
+                next();
+                var node = import_statement();
+                semicolon();
+                return node;
+            }
+            if (S.token.value == "using" && is_token(peek(), "name") && !has_newline_before(peek())) {
+                next();
+                var node = using_();
+                semicolon();
+                return node;
+            }
+            if (S.token.value == "await" && can_await() && is_token(peek(), "name", "using") && !has_newline_before(peek())) {
+                var next_next = S.input.peek_next_token_start_or_newline();
+                if (S.input.ch_starts_binding_identifier(next_next.char, next_next.pos)) {
+                    next();
+                    // The "using" token will be consumed by the await_using_ function.
+                    var node = await_using_();
+                    semicolon();
+                    return node;
+                }
+            }
+            return is_token(peek(), "punc", ":")
+                ? labeled_statement()
+                : simple_statement();
+
+          case "privatename":
+            if(!S.in_class)
+              croak("Private field must be used in an enclosing class");
+            return simple_statement();
+
+          case "punc":
+            switch (S.token.value) {
+              case "{":
+                return new AST_BlockStatement({
+                    start : S.token,
+                    body  : block_(),
+                    end   : prev()
+                });
+              case "[":
+              case "(":
+                return simple_statement();
+              case ";":
+                S.in_directives = false;
+                next();
+                return new AST_EmptyStatement();
+              default:
+                unexpected();
+            }
+
+          case "keyword":
+            switch (S.token.value) {
+              case "break":
+                next();
+                return break_cont(AST_Break);
+
+              case "continue":
+                next();
+                return break_cont(AST_Continue);
+
+              case "debugger":
+                next();
+                semicolon();
+                return new AST_Debugger();
+
+              case "do":
+                next();
+                var body = in_loop(statement);
+                expect_token("keyword", "while");
+                var condition = parenthesised();
+                semicolon(true);
+                return new AST_Do({
+                    body      : body,
+                    condition : condition
+                });
+
+              case "while":
+                next();
+                return new AST_While({
+                    condition : parenthesised(),
+                    body      : in_loop(function() { return statement(false, true); })
+                });
+
+              case "for":
+                next();
+                return for_();
+
+              case "class":
+                next();
+                if (is_for_body) {
+                    croak("classes are not allowed as the body of a loop");
+                }
+                if (is_if_body) {
+                    croak("classes are not allowed as the body of an if");
+                }
+                return class_(AST_DefClass, is_export_default);
+
+              case "function":
+                next();
+                if (is_for_body) {
+                    croak("functions are not allowed as the body of a loop");
+                }
+                return function_(AST_Defun, false, false, is_export_default);
+
+              case "if":
+                next();
+                return if_();
+
+              case "return":
+                if (S.in_function == 0 && !options.bare_returns)
+                    croak("'return' outside of function");
+                next();
+                var value = null;
+                if (is("punc", ";")) {
+                    next();
+                } else if (!can_insert_semicolon()) {
+                    value = expression(true);
+                    semicolon();
+                }
+                return new AST_Return({
+                    value: value
+                });
+
+              case "switch":
+                next();
+                return new AST_Switch({
+                    expression : parenthesised(),
+                    body       : in_loop(switch_body_)
+                });
+
+              case "throw":
+                next();
+                if (has_newline_before(S.token))
+                    croak("Illegal newline after 'throw'");
+                var value = expression(true);
+                semicolon();
+                return new AST_Throw({
+                    value: value
+                });
+
+              case "try":
+                next();
+                return try_();
+
+              case "var":
+                next();
+                var node = var_();
+                semicolon();
+                return node;
+
+              case "let":
+                next();
+                var node = let_();
+                semicolon();
+                return node;
+
+              case "const":
+                next();
+                var node = const_();
+                semicolon();
+                return node;
+
+              case "with":
+                if (S.input.has_directive("use strict")) {
+                    croak("Strict mode may not include a with statement");
+                }
+                next();
+                return new AST_With({
+                    expression : parenthesised(),
+                    body       : statement()
+                });
+
+              case "export":
+                if (!is_token(peek(), "punc", "(")) {
+                    next();
+                    var node = export_statement();
+                    if (is("punc", ";")) semicolon();
+                    return node;
+                }
+            }
+        }
+        unexpected();
+    });
+
+    function labeled_statement() {
+        var label = as_symbol(AST_Label);
+        if (label.name === "await" && is_in_async()) {
+            token_error(S.prev, "await cannot be used as label inside async function");
+        }
+        if (S.labels.some((l) => l.name === label.name)) {
+            // ECMA-262, 12.12: An ECMAScript program is considered
+            // syntactically incorrect if it contains a
+            // LabelledStatement that is enclosed by a
+            // LabelledStatement with the same Identifier as label.
+            croak("Label " + label.name + " defined twice");
+        }
+        expect(":");
+        S.labels.push(label);
+        var stat = statement();
+        S.labels.pop();
+        if (!(stat instanceof AST_IterationStatement)) {
+            // check for `continue` that refers to this label.
+            // those should be reported as syntax errors.
+            // https://github.com/mishoo/UglifyJS2/issues/287
+            label.references.forEach(function(ref) {
+                if (ref instanceof AST_Continue) {
+                    ref = ref.label.start;
+                    croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
+                          ref.line, ref.col, ref.pos);
+                }
+            });
+        }
+        return new AST_LabeledStatement({ body: stat, label: label });
+    }
+
+    function simple_statement(tmp) {
+        return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) });
+    }
+
+    function break_cont(type) {
+        var label = null, ldef;
+        if (!can_insert_semicolon()) {
+            label = as_symbol(AST_LabelRef, true);
+        }
+        if (label != null) {
+            ldef = S.labels.find((l) => l.name === label.name);
+            if (!ldef)
+                croak("Undefined label " + label.name);
+            label.thedef = ldef;
+        } else if (S.in_loop == 0)
+            croak(type.TYPE + " not inside a loop or switch");
+        semicolon();
+        var stat = new type({ label: label });
+        if (ldef) ldef.references.push(stat);
+        return stat;
+    }
+
+    function for_() {
+        var for_await_error = "`for await` invalid in this context";
+        var await_tok = S.token;
+        if (await_tok.type == "name" && await_tok.value == "await") {
+            if (!can_await()) {
+                token_error(await_tok, for_await_error);
+            }
+            next();
+        } else {
+            await_tok = false;
+        }
+        expect("(");
+        var init = null;
+        if (!is("punc", ";")) {
+            init =
+                is("keyword", "var") ? (next(), var_(true)) :
+                is("keyword", "let") ? (next(), let_(true)) :
+                is("keyword", "const") ? (next(), const_(true)) :
+                is("name", "using") && is_token(peek(), "name") && (peek().value != "of" || S.input.peek_next_token_start_or_newline().char == "=") ? (next(), using_(true)) :
+                is("name", "await") && can_await() && is_token(peek(), "name", "using") ? (next(), await_using_(true)) :
+                                       expression(true, true);
+            var is_in = is("operator", "in");
+            var is_of = is("name", "of");
+            if (await_tok && !is_of) {
+                token_error(await_tok, for_await_error);
+            }
+            if (is_in || is_of) {
+                if (init instanceof AST_DefinitionsLike) {
+                    if (init.definitions.length > 1)
+                        token_error(init.start, "Only one variable declaration allowed in for..in loop");
+                    if (is_in && init instanceof AST_Using) {
+                        token_error(init.start, "Invalid using declaration in for..in loop");
+                    }
+                } else if (!(is_assignable(init) || (init = to_destructuring(init)) instanceof AST_Destructuring)) {
+                    token_error(init.start, "Invalid left-hand side in for..in loop");
+                }
+                next();
+                if (is_in) {
+                    return for_in(init);
+                } else {
+                    return for_of(init, !!await_tok);
+                }
+            }
+        } else if (await_tok) {
+            token_error(await_tok, for_await_error);
+        }
+        return regular_for(init);
+    }
+
+    function regular_for(init) {
+        expect(";");
+        var test = is("punc", ";") ? null : expression(true);
+        expect(";");
+        var step = is("punc", ")") ? null : expression(true);
+        expect(")");
+        return new AST_For({
+            init      : init,
+            condition : test,
+            step      : step,
+            body      : in_loop(function() { return statement(false, true); })
+        });
+    }
+
+    function for_of(init, is_await) {
+        var lhs = init instanceof AST_DefinitionsLike ? init.definitions[0].name : null;
+        var obj = expression(true);
+        expect(")");
+        return new AST_ForOf({
+            await  : is_await,
+            init   : init,
+            name   : lhs,
+            object : obj,
+            body   : in_loop(function() { return statement(false, true); })
+        });
+    }
+
+    function for_in(init) {
+        var obj = expression(true);
+        expect(")");
+        return new AST_ForIn({
+            init   : init,
+            object : obj,
+            body   : in_loop(function() { return statement(false, true); })
+        });
+    }
+
+    var arrow_function = function(start, argnames, is_async) {
+        if (has_newline_before(S.token)) {
+            croak("Unexpected newline before arrow (=>)");
+        }
+
+        expect_token("arrow", "=>");
+
+        var body = _function_body(is("punc", "{"), false, is_async);
+
+        return new AST_Arrow({
+            start    : start,
+            end      : body.end,
+            async    : is_async,
+            argnames : argnames,
+            body     : body
+        });
+    };
+
+    var function_ = function(ctor, is_generator, is_async, is_export_default) {
+        var in_statement = ctor === AST_Defun;
+        if (is("operator", "*")) {
+            is_generator = true;
+            next();
+        }
+
+        var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
+        if (in_statement && !name) {
+            if (is_export_default) {
+                ctor = AST_Function;
+            } else {
+                unexpected();
+            }
+        }
+
+        if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
+            unexpected(prev());
+
+        var args = [];
+        var body = _function_body(true, is_generator, is_async, name, args);
+        return new ctor({
+            start : args.start,
+            end   : body.end,
+            is_generator: is_generator,
+            async : is_async,
+            name  : name,
+            argnames: args,
+            body  : body
+        });
+    };
+
+    class UsedParametersTracker {
+        constructor(is_parameter, strict, duplicates_ok = false) {
+            this.is_parameter = is_parameter;
+            this.duplicates_ok = duplicates_ok;
+            this.parameters = new Set();
+            this.duplicate = null;
+            this.default_assignment = false;
+            this.spread = false;
+            this.strict_mode = !!strict;
+        }
+        add_parameter(token) {
+            if (this.parameters.has(token.value)) {
+                if (this.duplicate === null) {
+                    this.duplicate = token;
+                }
+                this.check_strict();
+            } else {
+                this.parameters.add(token.value);
+                if (this.is_parameter) {
+                    switch (token.value) {
+                      case "arguments":
+                      case "eval":
+                      case "yield":
+                        if (this.strict_mode) {
+                            token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode");
+                        }
+                        break;
+                      default:
+                        if (RESERVED_WORDS.has(token.value)) {
+                            unexpected();
+                        }
+                    }
+                }
+            }
+        }
+        mark_default_assignment(token) {
+            if (this.default_assignment === false) {
+                this.default_assignment = token;
+            }
+        }
+        mark_spread(token) {
+            if (this.spread === false) {
+                this.spread = token;
+            }
+        }
+        mark_strict_mode() {
+            this.strict_mode = true;
+        }
+        is_strict() {
+            return this.default_assignment !== false || this.spread !== false || this.strict_mode;
+        }
+        check_strict() {
+            if (this.is_strict() && this.duplicate !== null && !this.duplicates_ok) {
+                token_error(this.duplicate, "Parameter " + this.duplicate.value + " was used already");
+            }
+        }
+    }
+
+    function parameters(params) {
+        var used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict"));
+
+        expect("(");
+
+        while (!is("punc", ")")) {
+            var param = parameter(used_parameters);
+            params.push(param);
+
+            if (!is("punc", ")")) {
+                expect(",");
+            }
+
+            if (param instanceof AST_Expansion) {
+                break;
+            }
+        }
+
+        next();
+    }
+
+    function parameter(used_parameters, symbol_type) {
+        var param;
+        var expand = false;
+        if (used_parameters === undefined) {
+            used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict"));
+        }
+        if (is("expand", "...")) {
+            expand = S.token;
+            used_parameters.mark_spread(S.token);
+            next();
+        }
+        param = binding_element(used_parameters, symbol_type);
+
+        if (is("operator", "=") && expand === false) {
+            used_parameters.mark_default_assignment(S.token);
+            next();
+            param = new AST_DefaultAssign({
+                start: param.start,
+                left: param,
+                operator: "=",
+                right: expression(false),
+                end: S.token
+            });
+        }
+
+        if (expand !== false) {
+            if (!is("punc", ")")) {
+                unexpected();
+            }
+            param = new AST_Expansion({
+                start: expand,
+                expression: param,
+                end: expand
+            });
+        }
+        used_parameters.check_strict();
+
+        return param;
+    }
+
+    function binding_element(used_parameters, symbol_type) {
+        var elements = [];
+        var first = true;
+        var is_expand = false;
+        var expand_token;
+        var first_token = S.token;
+        if (used_parameters === undefined) {
+            const strict = S.input.has_directive("use strict");
+            const duplicates_ok = symbol_type === AST_SymbolVar;
+            used_parameters = new UsedParametersTracker(false, strict, duplicates_ok);
+        }
+        symbol_type = symbol_type === undefined ? AST_SymbolFunarg : symbol_type;
+        if (is("punc", "[")) {
+            next();
+            while (!is("punc", "]")) {
+                if (first) {
+                    first = false;
+                } else {
+                    expect(",");
+                }
+
+                if (is("expand", "...")) {
+                    is_expand = true;
+                    expand_token = S.token;
+                    used_parameters.mark_spread(S.token);
+                    next();
+                }
+                if (is("punc")) {
+                    switch (S.token.value) {
+                      case ",":
+                        elements.push(new AST_Hole({
+                            start: S.token,
+                            end: S.token
+                        }));
+                        continue;
+                      case "]": // Trailing comma after last element
+                        break;
+                      case "[":
+                      case "{":
+                        elements.push(binding_element(used_parameters, symbol_type));
+                        break;
+                      default:
+                        unexpected();
+                    }
+                } else if (is("name")) {
+                    used_parameters.add_parameter(S.token);
+                    elements.push(as_symbol(symbol_type));
+                } else {
+                    croak("Invalid function parameter");
+                }
+                if (is("operator", "=") && is_expand === false) {
+                    used_parameters.mark_default_assignment(S.token);
+                    next();
+                    elements[elements.length - 1] = new AST_DefaultAssign({
+                        start: elements[elements.length - 1].start,
+                        left: elements[elements.length - 1],
+                        operator: "=",
+                        right: expression(false),
+                        end: S.token
+                    });
+                }
+                if (is_expand) {
+                    if (!is("punc", "]")) {
+                        croak("Rest element must be last element");
+                    }
+                    elements[elements.length - 1] = new AST_Expansion({
+                        start: expand_token,
+                        expression: elements[elements.length - 1],
+                        end: expand_token
+                    });
+                }
+            }
+            expect("]");
+            used_parameters.check_strict();
+            return new AST_Destructuring({
+                start: first_token,
+                names: elements,
+                is_array: true,
+                end: prev()
+            });
+        } else if (is("punc", "{")) {
+            next();
+            while (!is("punc", "}")) {
+                if (first) {
+                    first = false;
+                } else {
+                    expect(",");
+                }
+                if (is("expand", "...")) {
+                    is_expand = true;
+                    expand_token = S.token;
+                    used_parameters.mark_spread(S.token);
+                    next();
+                }
+                if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].includes(peek().value)) {
+                    used_parameters.add_parameter(S.token);
+                    var start = prev();
+                    var value = as_symbol(symbol_type);
+                    if (is_expand) {
+                        elements.push(new AST_Expansion({
+                            start: expand_token,
+                            expression: value,
+                            end: value.end,
+                        }));
+                    } else {
+                        elements.push(new AST_ObjectKeyVal({
+                            start: start,
+                            key: value.name,
+                            value: value,
+                            end: value.end,
+                        }));
+                    }
+                } else if (is("punc", "}")) {
+                    continue; // Allow trailing hole
+                } else {
+                    var property_token = S.token;
+                    var property = as_property_name();
+                    if (property === null) {
+                        unexpected(prev());
+                    } else if (prev().type === "name" && !is("punc", ":")) {
+                        elements.push(new AST_ObjectKeyVal({
+                            start: prev(),
+                            key: property,
+                            value: new symbol_type({
+                                start: prev(),
+                                name: property,
+                                end: prev()
+                            }),
+                            end: prev()
+                        }));
+                    } else {
+                        expect(":");
+                        elements.push(new AST_ObjectKeyVal({
+                            start: property_token,
+                            quote: property_token.quote,
+                            key: property,
+                            value: binding_element(used_parameters, symbol_type),
+                            end: prev()
+                        }));
+                    }
+                }
+                if (is_expand) {
+                    if (!is("punc", "}")) {
+                        croak("Rest element must be last element");
+                    }
+                } else if (is("operator", "=")) {
+                    used_parameters.mark_default_assignment(S.token);
+                    next();
+                    elements[elements.length - 1].value = new AST_DefaultAssign({
+                        start: elements[elements.length - 1].value.start,
+                        left: elements[elements.length - 1].value,
+                        operator: "=",
+                        right: expression(false),
+                        end: S.token
+                    });
+                }
+            }
+            expect("}");
+            used_parameters.check_strict();
+            return new AST_Destructuring({
+                start: first_token,
+                names: elements,
+                is_array: false,
+                end: prev()
+            });
+        } else if (is("name")) {
+            used_parameters.add_parameter(S.token);
+            return as_symbol(symbol_type);
+        } else {
+            croak("Invalid function parameter");
+        }
+    }
+
+    function params_or_seq_(allow_arrows, maybe_sequence) {
+        var spread_token;
+        var invalid_sequence;
+        var trailing_comma;
+        var a = [];
+        expect("(");
+        while (!is("punc", ")")) {
+            if (spread_token) unexpected(spread_token);
+            if (is("expand", "...")) {
+                spread_token = S.token;
+                if (maybe_sequence) invalid_sequence = S.token;
+                next();
+                a.push(new AST_Expansion({
+                    start: prev(),
+                    expression: expression(),
+                    end: S.token,
+                }));
+            } else {
+                a.push(expression());
+            }
+            if (!is("punc", ")")) {
+                expect(",");
+                if (is("punc", ")")) {
+                    trailing_comma = prev();
+                    if (maybe_sequence) invalid_sequence = trailing_comma;
+                }
+            }
+        }
+        expect(")");
+        if (allow_arrows && is("arrow", "=>")) {
+            if (spread_token && trailing_comma) unexpected(trailing_comma);
+        } else if (invalid_sequence) {
+            unexpected(invalid_sequence);
+        }
+        return a;
+    }
+
+    function _function_body(block, generator, is_async, name, args) {
+        var loop = S.in_loop;
+        var labels = S.labels;
+        var current_generator = S.in_generator;
+        var current_async = S.in_async;
+        ++S.in_function;
+        if (generator)
+            S.in_generator = S.in_function;
+        if (is_async)
+            S.in_async = S.in_function;
+        if (args) parameters(args);
+        if (block)
+            S.in_directives = true;
+        S.in_loop = 0;
+        S.labels = [];
+        if (block) {
+            S.input.push_directives_stack();
+            var a = block_();
+            if (name) _verify_symbol(name);
+            if (args) args.forEach(_verify_symbol);
+            S.input.pop_directives_stack();
+        } else {
+            var a = [new AST_Return({
+                start: S.token,
+                value: expression(false),
+                end: S.token
+            })];
+        }
+        --S.in_function;
+        S.in_loop = loop;
+        S.labels = labels;
+        S.in_generator = current_generator;
+        S.in_async = current_async;
+        return a;
+    }
+
+    function _await_expression() {
+        // Previous token must be "await" and not be interpreted as an identifier
+        if (!can_await()) {
+            croak("Unexpected await expression outside async function",
+                S.prev.line, S.prev.col, S.prev.pos);
+        }
+        // the await expression is parsed as a unary expression in Babel
+        return new AST_Await({
+            start: prev(),
+            end: S.token,
+            expression : maybe_unary(true),
+        });
+    }
+
+    function _yield_expression() {
+        var start = S.token;
+        var star = false;
+        var has_expression = true;
+
+        // Attempt to get expression or star (and then the mandatory expression)
+        // behind yield on the same line.
+        //
+        // If nothing follows on the same line of the yieldExpression,
+        // it should default to the value `undefined` for yield to return.
+        // In that case, the `undefined` stored as `null` in ast.
+        //
+        // Note 1: It isn't allowed for yield* to close without an expression
+        // Note 2: If there is a nlb between yield and star, it is interpret as
+        //         yield <explicit undefined> <inserted automatic semicolon> *
+        if (
+            can_insert_semicolon()
+            || is("punc") && PUNC_AFTER_EXPRESSION.has(S.token.value)
+            || is("template_cont")
+        ) {
+            has_expression = false;
+        } else if (is("operator", "*")) {
+            star = true;
+            next();
+        }
+
+        return new AST_Yield({
+            start      : start,
+            is_star    : star,
+            expression : has_expression ? expression() : null,
+            end        : prev()
+        });
+    }
+
+    function if_() {
+        var cond = parenthesised(), body = statement(false, false, true), belse = null;
+        if (is("keyword", "else")) {
+            next();
+            belse = statement(false, false, true);
+        }
+        return new AST_If({
+            condition   : cond,
+            body        : body,
+            alternative : belse
+        });
+    }
+
+    function block_() {
+        expect("{");
+        var a = [];
+        while (!is("punc", "}")) {
+            if (is("eof")) unexpected();
+            a.push(statement());
+        }
+        next();
+        return a;
+    }
+
+    function switch_body_() {
+        expect("{");
+        var a = [], cur = null, branch = null, tmp;
+        while (!is("punc", "}")) {
+            if (is("eof")) unexpected();
+            if (is("keyword", "case")) {
+                if (branch) branch.end = prev();
+                cur = [];
+                branch = new AST_Case({
+                    start      : (tmp = S.token, next(), tmp),
+                    expression : expression(true),
+                    body       : cur
+                });
+                a.push(branch);
+                expect(":");
+            } else if (is("keyword", "default")) {
+                if (branch) branch.end = prev();
+                cur = [];
+                branch = new AST_Default({
+                    start : (tmp = S.token, next(), expect(":"), tmp),
+                    body  : cur
+                });
+                a.push(branch);
+            } else {
+                if (!cur) unexpected();
+                cur.push(statement());
+            }
+        }
+        if (branch) branch.end = prev();
+        next();
+        return a;
+    }
+
+    function try_() {
+        var body, bcatch = null, bfinally = null;
+        body = new AST_TryBlock({
+            start : S.token,
+            body  : block_(),
+            end   : prev(),
+        });
+        if (is("keyword", "catch")) {
+            var start = S.token;
+            next();
+            if (is("punc", "{")) {
+                var name = null;
+            } else {
+                expect("(");
+                var name = parameter(undefined, AST_SymbolCatch);
+                expect(")");
+            }
+            bcatch = new AST_Catch({
+                start   : start,
+                argname : name,
+                body    : block_(),
+                end     : prev()
+            });
+        }
+        if (is("keyword", "finally")) {
+            var start = S.token;
+            next();
+            bfinally = new AST_Finally({
+                start : start,
+                body  : block_(),
+                end   : prev()
+            });
+        }
+        if (!bcatch && !bfinally)
+            croak("Missing catch/finally blocks");
+        return new AST_Try({
+            body     : body,
+            bcatch   : bcatch,
+            bfinally : bfinally
+        });
+    }
+
+    /**
+     * var
+     *   vardef1 = 2,
+     *   vardef2 = 3;
+     */
+    function vardefs(no_in, kind) {
+        var var_defs = [];
+        var def;
+        for (;;) {
+            var sym_type =
+                kind === "var" ? AST_SymbolVar :
+                kind === "const" ? AST_SymbolConst :
+                kind === "let" ? AST_SymbolLet :
+                kind === "using" ? AST_SymbolUsing :
+                kind === "await using" ? AST_SymbolUsing : null;
+            var def_type = kind === "using" || kind === "await using" ? AST_UsingDef : AST_VarDef;
+            // var { a } = b
+            if (is("punc", "{") || is("punc", "[")) {
+                def = new def_type({
+                    start: S.token,
+                    name: binding_element(undefined, sym_type),
+                    value: is("operator", "=") ? (expect_token("operator", "="), expression(false, no_in)) : null,
+                    end: prev()
+                });
+            } else {
+                def = new def_type({
+                    start : S.token,
+                    name  : as_symbol(sym_type),
+                    value : is("operator", "=")
+                        ? (next(), expression(false, no_in))
+                        : !no_in && (kind === "const" || kind === "using" || kind === "await using")
+                            ? croak("Missing initializer in " + kind + " declaration") : null,
+                    end   : prev()
+                });
+                if (def.name.name == "import") croak("Unexpected token: import");
+            }
+            var_defs.push(def);
+            if (!is("punc", ","))
+                break;
+            next();
+        }
+        return var_defs;
+    }
+
+    var var_ = function(no_in) {
+        return new AST_Var({
+            start       : prev(),
+            definitions : vardefs(no_in, "var"),
+            end         : prev()
+        });
+    };
+
+    var let_ = function(no_in) {
+        return new AST_Let({
+            start       : prev(),
+            definitions : vardefs(no_in, "let"),
+            end         : prev()
+        });
+    };
+
+    var const_ = function(no_in) {
+        return new AST_Const({
+            start       : prev(),
+            definitions : vardefs(no_in, "const"),
+            end         : prev()
+        });
+    };
+
+    var using_ = function(no_in) {
+        return new AST_Using({
+            start       : prev(),
+            await       : false,
+            definitions : vardefs(no_in, "using"),
+            end         : prev()
+        });
+    };
+
+    var await_using_ = function(no_in) {
+        // Assumption: When await_using_ is called, only the `await` token has been consumed.
+        return new AST_Using({
+            start       : prev(),
+            await       : true,
+            definitions : (next(), vardefs(no_in, "await using")),
+            end         : prev()
+        });
+    };
+
+    var new_ = function(allow_calls) {
+        var start = S.token;
+        expect_token("operator", "new");
+        if (is("punc", ".")) {
+            next();
+            expect_token("name", "target");
+            return subscripts(new AST_NewTarget({
+                start : start,
+                end   : prev()
+            }), allow_calls);
+        }
+        var newexp = expr_atom(false), args;
+        if (is("punc", "(")) {
+            next();
+            args = expr_list(")", true);
+        } else {
+            args = [];
+        }
+        var call = new AST_New({
+            start      : start,
+            expression : newexp,
+            args       : args,
+            end        : prev()
+        });
+        annotate(call);
+        return subscripts(call, allow_calls);
+    };
+
+    function as_atom_node() {
+        var tok = S.token, ret;
+        switch (tok.type) {
+          case "name":
+            ret = _make_symbol(AST_SymbolRef);
+            break;
+          case "num":
+            if (tok.value === Infinity) {
+                // very large float values are parsed as Infinity
+                ret = new AST_Infinity({
+                    start: tok,
+                    end: tok,
+                });
+            } else {
+                ret = new AST_Number({
+                    start: tok,
+                    end: tok,
+                    value: tok.value,
+                    raw: LATEST_RAW
+                });
+            }
+            break;
+          case "big_int":
+            ret = new AST_BigInt({
+                start: tok,
+                end: tok,
+                value: tok.value,
+                raw: LATEST_RAW,
+            });
+            break;
+          case "string":
+            ret = new AST_String({
+                start : tok,
+                end   : tok,
+                value : tok.value,
+                quote : tok.quote
+            });
+            annotate(ret);
+            break;
+          case "regexp":
+            const [_, source, flags] = tok.value.match(/^\/(.*)\/(\w*)$/);
+
+            ret = new AST_RegExp({ start: tok, end: tok, value: { source, flags } });
+            break;
+          case "atom":
+            switch (tok.value) {
+              case "false":
+                ret = new AST_False({ start: tok, end: tok });
+                break;
+              case "true":
+                ret = new AST_True({ start: tok, end: tok });
+                break;
+              case "null":
+                ret = new AST_Null({ start: tok, end: tok });
+                break;
+            }
+            break;
+        }
+        next();
+        return ret;
+    }
+
+    function to_fun_args(ex, default_seen_above) {
+        var insert_default = function(ex, default_value) {
+            if (default_value) {
+                return new AST_DefaultAssign({
+                    start: ex.start,
+                    left: ex,
+                    operator: "=",
+                    right: default_value,
+                    end: default_value.end
+                });
+            }
+            return ex;
+        };
+        if (ex instanceof AST_Object) {
+            return insert_default(new AST_Destructuring({
+                start: ex.start,
+                end: ex.end,
+                is_array: false,
+                names: ex.properties.map(prop => to_fun_args(prop))
+            }), default_seen_above);
+        } else if (ex instanceof AST_ObjectKeyVal) {
+            ex.value = to_fun_args(ex.value);
+            return insert_default(ex, default_seen_above);
+        } else if (ex instanceof AST_Hole) {
+            return ex;
+        } else if (ex instanceof AST_Destructuring) {
+            ex.names = ex.names.map(name => to_fun_args(name));
+            return insert_default(ex, default_seen_above);
+        } else if (ex instanceof AST_SymbolRef) {
+            return insert_default(new AST_SymbolFunarg({
+                name: ex.name,
+                start: ex.start,
+                end: ex.end
+            }), default_seen_above);
+        } else if (ex instanceof AST_Expansion) {
+            ex.expression = to_fun_args(ex.expression);
+            return insert_default(ex, default_seen_above);
+        } else if (ex instanceof AST_Array) {
+            return insert_default(new AST_Destructuring({
+                start: ex.start,
+                end: ex.end,
+                is_array: true,
+                names: ex.elements.map(elm => to_fun_args(elm))
+            }), default_seen_above);
+        } else if (ex instanceof AST_Assign) {
+            return insert_default(to_fun_args(ex.left, ex.right), default_seen_above);
+        } else if (ex instanceof AST_DefaultAssign) {
+            ex.left = to_fun_args(ex.left);
+            return ex;
+        } else {
+            croak("Invalid function parameter", ex.start.line, ex.start.col);
+        }
+    }
+
+    var expr_atom = function(allow_calls, allow_arrows) {
+        if (is("operator", "new")) {
+            return new_(allow_calls);
+        }
+        if (is("name", "import") && is_token(peek(), "punc", ".")) {
+            return parse_import_expr(allow_calls);
+        }
+        var start = S.token;
+        var peeked;
+        var async = is("name", "async")
+            && (peeked = peek()).value != "["
+            && peeked.type != "arrow"
+            && as_atom_node();
+        if (is("punc")) {
+            switch (S.token.value) {
+              case "(":
+                if (async && !allow_calls) break;
+                var exprs = params_or_seq_(allow_arrows, !async);
+                if (allow_arrows && is("arrow", "=>")) {
+                    return arrow_function(start, exprs.map(e => to_fun_args(e)), !!async);
+                }
+                var ex = async ? new AST_Call({
+                    expression: async,
+                    args: exprs
+                }) : to_expr_or_sequence(start, exprs);
+                if (ex.start) {
+                    const outer_comments_before = start.comments_before.length;
+                    outer_comments_before_counts.set(start, outer_comments_before);
+                    ex.start.comments_before.unshift(...start.comments_before);
+                    start.comments_before = ex.start.comments_before;
+                    if (outer_comments_before == 0 && start.comments_before.length > 0) {
+                        var comment = start.comments_before[0];
+                        if (!comment.nlb) {
+                            comment.nlb = start.nlb;
+                            start.nlb = false;
+                        }
+                    }
+                    start.comments_after = ex.start.comments_after;
+                }
+                ex.start = start;
+                var end = prev();
+                if (ex.end) {
+                    end.comments_before = ex.end.comments_before;
+                    ex.end.comments_after.push(...end.comments_after);
+                    end.comments_after = ex.end.comments_after;
+                }
+                ex.end = end;
+                if (ex instanceof AST_Call) annotate(ex);
+                return subscripts(ex, allow_calls);
+              case "[":
+                return subscripts(array_(), allow_calls);
+              case "{":
+                return subscripts(object_or_destructuring_(), allow_calls);
+            }
+            if (!async) unexpected();
+        }
+        if (allow_arrows && is("name") && is_token(peek(), "arrow")) {
+            var param = new AST_SymbolFunarg({
+                name: S.token.value,
+                start: start,
+                end: start,
+            });
+            next();
+            return arrow_function(start, [param], !!async);
+        }
+        if (is("keyword", "function")) {
+            next();
+            var func = function_(AST_Function, false, !!async);
+            func.start = start;
+            func.end = prev();
+            return subscripts(func, allow_calls);
+        }
+        if (async) return subscripts(async, allow_calls);
+        if (is("keyword", "class")) {
+            next();
+            var cls = class_(AST_ClassExpression);
+            cls.start = start;
+            cls.end = prev();
+            return subscripts(cls, allow_calls);
+        }
+        if (is("template_head")) {
+            return subscripts(template_string(), allow_calls);
+        }
+        if (ATOMIC_START_TOKEN.has(S.token.type)) {
+            return subscripts(as_atom_node(), allow_calls);
+        }
+        unexpected();
+    };
+
+    function template_string() {
+        var segments = [], start = S.token;
+
+        segments.push(new AST_TemplateSegment({
+            start: S.token,
+            raw: TEMPLATE_RAWS.get(S.token),
+            value: S.token.value,
+            end: S.token
+        }));
+
+        while (!S.token.template_end) {
+            next();
+            handle_regexp();
+            segments.push(expression(true));
+
+            segments.push(new AST_TemplateSegment({
+                start: S.token,
+                raw: TEMPLATE_RAWS.get(S.token),
+                value: S.token.value,
+                end: S.token
+            }));
+        }
+        next();
+
+        return new AST_TemplateString({
+            start: start,
+            segments: segments,
+            end: S.token
+        });
+    }
+
+    function expr_list(closing, allow_trailing_comma, allow_empty) {
+        var first = true, a = [];
+        while (!is("punc", closing)) {
+            if (first) first = false; else expect(",");
+            if (allow_trailing_comma && is("punc", closing)) break;
+            if (is("punc", ",") && allow_empty) {
+                a.push(new AST_Hole({ start: S.token, end: S.token }));
+            } else if (is("expand", "...")) {
+                next();
+                a.push(new AST_Expansion({start: prev(), expression: expression(),end: S.token}));
+            } else {
+                a.push(expression(false));
+            }
+        }
+        next();
+        return a;
+    }
+
+    var array_ = embed_tokens(function() {
+        expect("[");
+        return new AST_Array({
+            elements: expr_list("]", !options.strict, true)
+        });
+    });
+
+    var create_accessor = embed_tokens((is_generator, is_async) => {
+        return function_(AST_Accessor, is_generator, is_async);
+    });
+
+    var object_or_destructuring_ = embed_tokens(function object_or_destructuring_() {
+        var start = S.token, first = true, a = [];
+        expect("{");
+        while (!is("punc", "}")) {
+            if (first) first = false; else expect(",");
+            if (!options.strict && is("punc", "}"))
+                // allow trailing comma
+                break;
+
+            start = S.token;
+            if (start.type == "expand") {
+                next();
+                a.push(new AST_Expansion({
+                    start: start,
+                    expression: expression(false),
+                    end: prev(),
+                }));
+                continue;
+            }
+            if(is("privatename")) {
+                croak("private fields are not allowed in an object");
+            }
+            var name = as_property_name();
+            var value;
+
+            // Check property and fetch value
+            if (!is("punc", ":")) {
+                var concise = object_or_class_property(name, start);
+                if (concise) {
+                    a.push(concise);
+                    continue;
+                }
+
+                value = new AST_SymbolRef({
+                    start: prev(),
+                    name: name,
+                    end: prev()
+                });
+            } else if (name === null) {
+                unexpected(prev());
+            } else {
+                next(); // `:` - see first condition
+                value = expression(false);
+            }
+
+            // Check for default value and alter value accordingly if necessary
+            if (is("operator", "=")) {
+                next();
+                value = new AST_Assign({
+                    start: start,
+                    left: value,
+                    operator: "=",
+                    right: expression(false),
+                    logical: false,
+                    end: prev()
+                });
+            }
+
+            // Create property
+            const kv = new AST_ObjectKeyVal({
+                start: start,
+                quote: start.quote,
+                key: name,
+                value: value,
+                end: prev()
+            });
+            a.push(annotate(kv));
+        }
+        next();
+        return new AST_Object({ properties: a });
+    });
+
+    function class_(KindOfClass, is_export_default) {
+        var start, method, class_name, extends_, properties = [];
+
+        S.input.push_directives_stack(); // Push directive stack, but not scope stack
+        S.input.add_directive("use strict");
+
+        if (S.token.type == "name" && S.token.value != "extends") {
+            class_name = as_symbol(KindOfClass === AST_DefClass ? AST_SymbolDefClass : AST_SymbolClass);
+        }
+
+        if (KindOfClass === AST_DefClass && !class_name) {
+            if (is_export_default) {
+                KindOfClass = AST_ClassExpression;
+            } else {
+                unexpected();
+            }
+        }
+
+        if (S.token.value == "extends") {
+            next();
+            extends_ = expression(true);
+        }
+
+        expect("{");
+        // mark in class feild,
+        const save_in_class = S.in_class;
+        S.in_class = true;
+        while (is("punc", ";")) { next(); }  // Leading semicolons are okay in class bodies.
+        while (!is("punc", "}")) {
+            start = S.token;
+            method = object_or_class_property(as_property_name(), start, true);
+            if (!method) { unexpected(); }
+            properties.push(method);
+            while (is("punc", ";")) { next(); }
+        }
+        // mark in class feild,
+        S.in_class = save_in_class;
+
+        S.input.pop_directives_stack();
+
+        next();
+
+        return new KindOfClass({
+            start: start,
+            name: class_name,
+            extends: extends_,
+            properties: properties,
+            end: prev(),
+        });
+    }
+
+    function object_or_class_property(name, start, is_class) {
+        const get_symbol_ast = (name, SymbolClass) => {
+            if (typeof name === "string") {
+                return new SymbolClass({ start, name, end: prev() });
+            } else if (name === null) {
+                unexpected();
+            }
+            return name;
+        };
+
+        var is_private = prev().type === "privatename";
+        const is_not_method_start = () =>
+            !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("punc", ";") && !is("operator", "=") && !is_private;
+
+        var is_async = false;
+        var is_static = false;
+        var is_generator = false;
+        var accessor_type = null;
+
+        if (is_class && name === "static" && is_not_method_start()) {
+            const static_block = class_static_block();
+            if (static_block != null) {
+                return static_block;
+            }
+            is_static = true;
+            name = as_property_name();
+        }
+        if (name === "async" && is_not_method_start()) {
+            is_async = true;
+            name = as_property_name();
+        }
+        if (prev().type === "operator" && prev().value === "*") {
+            is_generator = true;
+            name = as_property_name();
+        }
+        if ((name === "get" || name === "set") && is_not_method_start()) {
+            accessor_type = name;
+            name = as_property_name();
+        }
+        if (!is_private && prev().type === "privatename") {
+            is_private = true;
+        }
+
+        const property_token = prev();
+
+        if (accessor_type != null) {
+            if (!is_private) {
+                const AccessorClass = accessor_type === "get"
+                    ? AST_ObjectGetter
+                    : AST_ObjectSetter;
+
+                name = get_symbol_ast(name, AST_SymbolMethod);
+                return annotate(new AccessorClass({
+                    start,
+                    static: is_static,
+                    key: name,
+                    quote: name instanceof AST_SymbolMethod ? property_token.quote : undefined,
+                    value: create_accessor(),
+                    end: prev()
+                }));
+            } else {
+                const AccessorClass = accessor_type === "get"
+                    ? AST_PrivateGetter
+                    : AST_PrivateSetter;
+
+                return annotate(new AccessorClass({
+                    start,
+                    static: is_static,
+                    key: get_symbol_ast(name, AST_SymbolMethod),
+                    value: create_accessor(),
+                    end: prev(),
+                }));
+            }
+        }
+
+        if (is("punc", "(")) {
+            name = get_symbol_ast(name, AST_SymbolMethod);
+            const AST_MethodVariant = is_private
+                ? AST_PrivateMethod
+                : AST_ConciseMethod;
+            var node = new AST_MethodVariant({
+                start       : start,
+                static      : is_static,
+                key         : name,
+                quote       : name instanceof AST_SymbolMethod ?
+                              property_token.quote : undefined,
+                value       : create_accessor(is_generator, is_async),
+                end         : prev()
+            });
+            return annotate(node);
+        }
+
+        if (is_class) {
+            const AST_SymbolVariant = is_private
+                ? AST_SymbolPrivateProperty
+                : AST_SymbolClassProperty;
+            const AST_ClassPropertyVariant = is_private
+                ? AST_ClassPrivateProperty
+                : AST_ClassProperty;
+
+            const key = get_symbol_ast(name, AST_SymbolVariant);
+            const quote = key instanceof AST_SymbolClassProperty
+                ? property_token.quote
+                : undefined;
+            if (is("operator", "=")) {
+                next();
+                return annotate(
+                    new AST_ClassPropertyVariant({
+                        start,
+                        static: is_static,
+                        quote,
+                        key,
+                        value: expression(false),
+                        end: prev()
+                    })
+                );
+            } else if (
+                is("name")
+                || is("privatename")
+                || is("punc", "[")
+                || is("operator", "*")
+                || is("punc", ";")
+                || is("punc", "}")
+                || is("string")
+                || is("num")
+                || is("big_int")
+            ) {
+                return annotate(
+                    new AST_ClassPropertyVariant({
+                        start,
+                        static: is_static,
+                        quote,
+                        key,
+                        end: prev()
+                    })
+                );
+            }
+        }
+    }
+
+    function class_static_block() {
+        if (!is("punc", "{")) {
+            return null;
+        }
+
+        const start = S.token;
+        const body = [];
+
+        next();
+
+        while (!is("punc", "}")) {
+            body.push(statement());
+        }
+
+        next();
+
+        return new AST_ClassStaticBlock({ start, body, end: prev() });
+    }
+
+    function maybe_import_attributes() {
+        if (
+            (is("keyword", "with") || is("name", "assert"))
+            && !has_newline_before(S.token)
+        ) {
+            next();
+            return object_or_destructuring_();
+        }
+        return null;
+    }
+
+    function import_statement() {
+        var start = prev();
+
+        // import source x from "..."
+        // import defer * as x from "..."
+        var phase = null;
+        if (is("name", "source") || is("name", "defer")) {
+            var peeked = peek();
+            if (!is_token(peeked, "name", "from") && !is_token(peeked, "punc", ",")) {
+                phase = S.token.value;
+                next();
+            }
+        }
+
+        var imported_name;
+        var imported_names;
+        if (is("name")) {
+            imported_name = as_symbol(AST_SymbolImport);
+        }
+
+        if (is("punc", ",")) {
+            next();
+        }
+
+        imported_names = map_names(true);
+
+        if (imported_names || imported_name) {
+            expect_token("name", "from");
+        }
+        var mod_str = S.token;
+        if (mod_str.type !== "string") {
+            unexpected();
+        }
+        next();
+
+        const attributes = maybe_import_attributes();
+
+        return new AST_Import({
+            start,
+            imported_name,
+            imported_names,
+            module_name: new AST_String({
+                start: mod_str,
+                value: mod_str.value,
+                quote: mod_str.quote,
+                end: mod_str,
+            }),
+            attributes,
+            phase,
+            end: S.token,
+        });
+    }
+
+    //   import.meta
+    //   import.source("module")
+    //   import.defer("module")
+    function parse_import_expr(allow_calls) {
+        var start = S.token;
+        expect_token("name", "import");
+        expect_token("punc", ".");
+        if (is("name", "source") || is("name", "defer")) {
+            var phase = S.token.value;
+            next();
+            if (!is("punc", "(")) {
+                croak("'import." + phase + "' can only be used in a dynamic import");
+            }
+            next();
+            var args = expr_list(")");
+            return subscripts(new AST_DynamicImport({
+                start: start,
+                phase: phase,
+                args: args,
+                end: prev()
+            }), allow_calls);
+        }
+        expect_token("name", "meta");
+        return subscripts(new AST_ImportMeta({
+            start: start,
+            end: prev()
+        }), allow_calls);
+    }
+
+    function map_name(is_import) {
+        function make_symbol(type, quote) {
+            return new type({
+                name: as_property_name(),
+                quote: quote || undefined,
+                start: prev(),
+                end: prev()
+            });
+        }
+
+        var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign;
+        var type = is_import ? AST_SymbolImport : AST_SymbolExport;
+        var start = S.token;
+        var foreign_name;
+        var name;
+
+        if (is_import) {
+            foreign_name = make_symbol(foreign_type, start.quote);
+        } else {
+            name = make_symbol(type, start.quote);
+        }
+        if (is("name", "as")) {
+            next();  // The "as" word
+            if (is_import) {
+                name = make_symbol(type);
+            } else {
+                foreign_name = make_symbol(foreign_type, S.token.quote);
+            }
+        } else {
+            if (is_import) {
+                name = new type(foreign_name);
+            } else {
+                foreign_name = new foreign_type(name);
+            }
+        }
+
+        return new AST_NameMapping({
+            start: start,
+            foreign_name: foreign_name,
+            name: name,
+            end: prev(),
+        });
+    }
+
+    function map_nameAsterisk(is_import, import_or_export_foreign_name) {
+        var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign;
+        var type = is_import ? AST_SymbolImport : AST_SymbolExport;
+        var start = S.token;
+        var name, foreign_name;
+        var end = prev();
+
+        if (is_import) {
+            name = import_or_export_foreign_name;
+        } else {
+            foreign_name = import_or_export_foreign_name;
+        }
+
+        name = name || new type({
+            start: start,
+            name: "*",
+            end: end,
+        });
+
+        foreign_name = foreign_name || new foreign_type({
+            start: start,
+            name: "*",
+            end: end,
+        });
+
+        return new AST_NameMapping({
+            start: start,
+            foreign_name: foreign_name,
+            name: name,
+            end: end,
+        });
+    }
+
+    function map_names(is_import) {
+        var names;
+        if (is("punc", "{")) {
+            next();
+            names = [];
+            while (!is("punc", "}")) {
+                names.push(map_name(is_import));
+                if (is("punc", ",")) {
+                    next();
+                }
+            }
+            next();
+        } else if (is("operator", "*")) {
+            var name;
+            next();
+            if (is("name", "as")) {
+                next();  // The "as" word
+                name = is_import ? as_symbol(AST_SymbolImport) : as_symbol_or_string(AST_SymbolExportForeign);
+            }
+            names = [map_nameAsterisk(is_import, name)];
+        }
+        return names;
+    }
+
+    function export_statement() {
+        var start = S.token;
+        var is_default;
+        var exported_names;
+
+        if (is("keyword", "default")) {
+            is_default = true;
+            next();
+        } else if (exported_names = map_names(false)) {
+            if (is("name", "from")) {
+                next();
+
+                var mod_str = S.token;
+                if (mod_str.type !== "string") {
+                    unexpected();
+                }
+                next();
+
+                const attributes = maybe_import_attributes();
+
+                return new AST_Export({
+                    start: start,
+                    is_default: is_default,
+                    exported_names: exported_names,
+                    module_name: new AST_String({
+                        start: mod_str,
+                        value: mod_str.value,
+                        quote: mod_str.quote,
+                        end: mod_str,
+                    }),
+                    end: prev(),
+                    attributes
+                });
+            } else {
+                return new AST_Export({
+                    start: start,
+                    is_default: is_default,
+                    exported_names: exported_names,
+                    end: prev(),
+                });
+            }
+        }
+
+        var node;
+        var exported_value;
+        var exported_definition;
+        if (is("punc", "{")
+            || is_default
+                && (is("keyword", "class") || is("keyword", "function"))
+                && is_token(peek(), "punc")) {
+            exported_value = expression(false);
+            semicolon();
+        } else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) {
+            unexpected(node.start);
+        } else if (
+            node instanceof AST_Definitions
+            || node instanceof AST_Defun
+            || node instanceof AST_DefClass
+        ) {
+            exported_definition = node;
+        } else if (
+            node instanceof AST_ClassExpression
+            || node instanceof AST_Function
+        ) {
+            exported_value = node;
+        } else if (node instanceof AST_SimpleStatement) {
+            exported_value = node.body;
+        } else {
+            unexpected(node.start);
+        }
+
+        return new AST_Export({
+            start: start,
+            is_default: is_default,
+            exported_value: exported_value,
+            exported_definition: exported_definition,
+            end: prev(),
+            attributes: null
+        });
+    }
+
+    function as_property_name() {
+        var tmp = S.token;
+        switch (tmp.type) {
+          case "punc":
+            if (tmp.value === "[") {
+                next();
+                var ex = expression(false);
+                expect("]");
+                return ex;
+            } else unexpected(tmp);
+          case "operator":
+            if (tmp.value === "*") {
+                next();
+                return null;
+            }
+            if (!["delete", "in", "instanceof", "new", "typeof", "void"].includes(tmp.value)) {
+                unexpected(tmp);
+            }
+            /* falls through */
+          case "name":
+          case "privatename":
+          case "string":
+          case "keyword":
+          case "atom":
+            next();
+            return tmp.value;
+          case "num":
+          case "big_int":
+            next();
+            return "" + tmp.value;
+          default:
+            unexpected(tmp);
+        }
+    }
+
+    function as_name() {
+        var tmp = S.token;
+        if (tmp.type != "name" && tmp.type != "privatename") unexpected();
+        next();
+        return tmp.value;
+    }
+
+    function _make_symbol(type) {
+        var name = S.token.value;
+        return new (name == "this" ? AST_This :
+                    name == "super" ? AST_Super :
+                    type)({
+            name  : String(name),
+            start : S.token,
+            end   : S.token
+        });
+    }
+
+    function _verify_symbol(sym) {
+        var name = sym.name;
+        if (is_in_generator() && name == "yield") {
+            token_error(sym.start, "Yield cannot be used as identifier inside generators");
+        }
+        if (S.input.has_directive("use strict")) {
+            if (name == "yield") {
+                token_error(sym.start, "Unexpected yield identifier inside strict mode");
+            }
+            if (sym instanceof AST_SymbolDeclaration && (name == "arguments" || name == "eval")) {
+                token_error(sym.start, "Unexpected " + name + " in strict mode");
+            }
+        }
+    }
+
+    function as_symbol(type, noerror) {
+        if (!is("name")) {
+            if (!noerror) croak("Name expected");
+            return null;
+        }
+        var sym = _make_symbol(type);
+        _verify_symbol(sym);
+        next();
+        return sym;
+    }
+
+    function as_symbol_or_string(type) {
+        if (!is("name")) {
+            if (!is("string")) {
+                croak("Name or string expected");
+            }
+            var tok = S.token;
+            var ret = new type({
+                start : tok,
+                end   : tok,
+                name : tok.value,
+                quote : tok.quote
+            });
+            next();
+            return ret;
+        }
+        var sym = _make_symbol(type);
+        _verify_symbol(sym);
+        next();
+        return sym;
+    }
+
+    // Annotate AST_Call, AST_Lambda or AST_New with the special comments
+    function annotate(node, before_token = node.start) {
+        var comments = before_token.comments_before;
+        const comments_outside_parens = outer_comments_before_counts.get(before_token);
+        var i = comments_outside_parens != null ? comments_outside_parens : comments.length;
+        while (--i >= 0) {
+            var comment = comments[i];
+            if (/[@#]__/.test(comment.value)) {
+                if (/[@#]__PURE__/.test(comment.value)) {
+                    set_annotation(node, _PURE);
+                    break;
+                }
+                if (/[@#]__INLINE__/.test(comment.value)) {
+                    set_annotation(node, _INLINE);
+                    break;
+                }
+                if (/[@#]__NOINLINE__/.test(comment.value)) {
+                    set_annotation(node, _NOINLINE);
+                    break;
+                }
+                if (/[@#]__KEY__/.test(comment.value)) {
+                    set_annotation(node, _KEY);
+                    break;
+                }
+                if (/[@#]__MANGLE_PROP__/.test(comment.value)) {
+                    set_annotation(node, _MANGLEPROP);
+                    break;
+                }
+            }
+        }
+        return node;
+    }
+
+    var subscripts = function(expr, allow_calls, is_chain) {
+        var start = expr.start;
+        if (is("punc", ".")) {
+            next();
+            if(is("privatename") && !S.in_class) 
+                croak("Private field must be used in an enclosing class");
+            const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
+            return annotate(subscripts(new AST_DotVariant({
+                start      : start,
+                expression : expr,
+                optional   : false,
+                property   : as_name(),
+                end        : prev()
+            }), allow_calls, is_chain));
+        }
+        if (is("punc", "[")) {
+            next();
+            var prop = expression(true);
+            expect("]");
+            return annotate(subscripts(new AST_Sub({
+                start      : start,
+                expression : expr,
+                optional   : false,
+                property   : prop,
+                end        : prev()
+            }), allow_calls, is_chain));
+        }
+        if (allow_calls && is("punc", "(")) {
+            next();
+            var call = new AST_Call({
+                start      : start,
+                expression : expr,
+                optional   : false,
+                args       : call_args(),
+                end        : prev()
+            });
+            annotate(call);
+            return subscripts(call, true, is_chain);
+        }
+
+        // Optional chain
+        if (is("punc", "?.")) {
+            next();
+
+            let chain_contents;
+
+            if (allow_calls && is("punc", "(")) {
+                next();
+
+                const call = new AST_Call({
+                    start,
+                    optional: true,
+                    expression: expr,
+                    args: call_args(),
+                    end: prev()
+                });
+                annotate(call);
+
+                chain_contents = subscripts(call, true, true);
+            } else if (is("name") || is("privatename")) {
+                if(is("privatename") && !S.in_class) 
+                    croak("Private field must be used in an enclosing class");
+                const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot;
+                chain_contents = annotate(subscripts(new AST_DotVariant({
+                    start,
+                    expression: expr,
+                    optional: true,
+                    property: as_name(),
+                    end: prev()
+                }), allow_calls, true));
+            } else if (is("punc", "[")) {
+                next();
+                const property = expression(true);
+                expect("]");
+                chain_contents = annotate(subscripts(new AST_Sub({
+                    start,
+                    expression: expr,
+                    optional: true,
+                    property,
+                    end: prev()
+                }), allow_calls, true));
+            }
+
+            if (!chain_contents) unexpected();
+
+            if (chain_contents instanceof AST_Chain) return chain_contents;
+
+            return new AST_Chain({
+                start,
+                expression: chain_contents,
+                end: prev()
+            });
+        }
+
+        if (is("template_head")) {
+            if (is_chain) {
+                // a?.b`c` is a syntax error
+                unexpected();
+            }
+
+            return subscripts(new AST_PrefixedTemplateString({
+                start: start,
+                prefix: expr,
+                template_string: template_string(),
+                end: prev()
+            }), allow_calls);
+        }
+        return expr;
+    };
+
+    function call_args() {
+        var args = [];
+        while (!is("punc", ")")) {
+            if (is("expand", "...")) {
+                next();
+                args.push(new AST_Expansion({
+                    start: prev(),
+                    expression: expression(false),
+                    end: prev()
+                }));
+            } else {
+                args.push(expression(false));
+            }
+            if (!is("punc", ")")) {
+                expect(",");
+            }
+        }
+        next();
+        return args;
+    }
+
+    var maybe_unary = function(allow_calls, allow_arrows) {
+        var start = S.token;
+        if (start.type == "name" && start.value == "await" && can_await()) {
+            next();
+            return _await_expression();
+        }
+        if (is("operator") && UNARY_PREFIX.has(start.value)) {
+            next();
+            handle_regexp();
+            var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls));
+            ex.start = start;
+            ex.end = prev();
+            return ex;
+        }
+        var val = expr_atom(allow_calls, allow_arrows);
+        while (is("operator") && UNARY_POSTFIX.has(S.token.value) && !has_newline_before(S.token)) {
+            if (val instanceof AST_Arrow) unexpected();
+            val = make_unary(AST_UnaryPostfix, S.token, val);
+            val.start = start;
+            val.end = S.token;
+            next();
+        }
+        return val;
+    };
+
+    function make_unary(ctor, token, expr) {
+        var op = token.value;
+        switch (op) {
+          case "++":
+          case "--":
+            if (!is_assignable(expr))
+                croak("Invalid use of " + op + " operator", token.line, token.col, token.pos);
+            break;
+          case "delete":
+            if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict"))
+                croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos);
+            break;
+        }
+        return new ctor({ operator: op, expression: expr });
+    }
+
+    var expr_op = function(left, min_prec, no_in) {
+        var op = is("operator") ? S.token.value : null;
+        if (op == "in" && no_in) op = null;
+        if (op == "**" && left instanceof AST_UnaryPrefix
+            /* unary token in front not allowed - parenthesis required */
+            && !is_token(left.start, "punc", "(")
+            && left.operator !== "--" && left.operator !== "++")
+                unexpected(left.start);
+        var prec = op != null ? PRECEDENCE[op] : null;
+        if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
+            next();
+            var right = expr_ops(no_in, prec, true);
+            return expr_op(new AST_Binary({
+                start    : left.start,
+                left     : left,
+                operator : op,
+                right    : right,
+                end      : right.end
+            }), min_prec, no_in);
+        }
+        return left;
+    };
+
+    function expr_ops(no_in, min_prec, allow_calls, allow_arrows) {
+        // maybe_unary won't return us a AST_SymbolPrivateProperty
+        if (!no_in && min_prec < PRECEDENCE["in"] && is("privatename")) {
+            if(!S.in_class) {
+                croak("Private field must be used in an enclosing class");
+            }
+
+            const start = S.token;
+            const key = new AST_SymbolPrivateProperty({
+                start,
+                name: start.value,
+                end: start
+            });
+            next();
+            expect_token("operator", "in");
+
+            const private_in = new AST_PrivateIn({
+                start,
+                key,
+                value: expr_ops(no_in, PRECEDENCE["in"], true),
+                end: prev()
+            });
+
+            return expr_op(private_in, 0, no_in);
+        } else {
+            return expr_op(maybe_unary(allow_calls, allow_arrows), min_prec, no_in);
+        }
+    }
+
+    var maybe_conditional = function(no_in) {
+        var start = S.token;
+        var expr = expr_ops(no_in, 0, true, true);
+        if (is("operator", "?")) {
+            next();
+            var yes = expression(false);
+            expect(":");
+            return new AST_Conditional({
+                start       : start,
+                condition   : expr,
+                consequent  : yes,
+                alternative : expression(false, no_in),
+                end         : prev()
+            });
+        }
+        return expr;
+    };
+
+    function is_assignable(expr) {
+        return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef;
+    }
+
+    function to_destructuring(node) {
+        if (node instanceof AST_Object) {
+            node = new AST_Destructuring({
+                start: node.start,
+                names: node.properties.map(to_destructuring),
+                is_array: false,
+                end: node.end
+            });
+        } else if (node instanceof AST_Array) {
+            var names = [];
+
+            for (var i = 0; i < node.elements.length; i++) {
+                // Only allow expansion as last element
+                if (node.elements[i] instanceof AST_Expansion) {
+                    if (i + 1 !== node.elements.length) {
+                        token_error(node.elements[i].start, "Spread must the be last element in destructuring array");
+                    }
+                    node.elements[i].expression = to_destructuring(node.elements[i].expression);
+                }
+
+                names.push(to_destructuring(node.elements[i]));
+            }
+
+            node = new AST_Destructuring({
+                start: node.start,
+                names: names,
+                is_array: true,
+                end: node.end
+            });
+        } else if (node instanceof AST_ObjectProperty) {
+            node.value = to_destructuring(node.value);
+        } else if (node instanceof AST_Assign) {
+            node = new AST_DefaultAssign({
+                start: node.start,
+                left: node.left,
+                operator: "=",
+                right: node.right,
+                end: node.end
+            });
+        }
+        return node;
+    }
+
+    // In ES6, AssignmentExpression can also be an ArrowFunction
+    var maybe_assign = function(no_in) {
+        handle_regexp();
+        var start = S.token;
+
+        if (start.type == "name" && start.value == "yield") {
+            if (is_in_generator()) {
+                next();
+                return _yield_expression();
+            } else if (S.input.has_directive("use strict")) {
+                token_error(S.token, "Unexpected yield identifier inside strict mode");
+            }
+        }
+
+        var left = maybe_conditional(no_in);
+        var val = S.token.value;
+
+        if (is("operator") && ASSIGNMENT.has(val)) {
+            if (is_assignable(left) || (left = to_destructuring(left)) instanceof AST_Destructuring) {
+                next();
+
+                return new AST_Assign({
+                    start    : start,
+                    left     : left,
+                    operator : val,
+                    right    : maybe_assign(no_in),
+                    logical  : LOGICAL_ASSIGNMENT.has(val),
+                    end      : prev()
+                });
+            }
+            croak("Invalid assignment");
+        }
+        return left;
+    };
+
+    var to_expr_or_sequence = function(start, exprs) {
+        if (exprs.length === 1) {
+            return exprs[0];
+        } else if (exprs.length > 1) {
+            return new AST_Sequence({ start, expressions: exprs, end: peek() });
+        } else {
+            croak("Invalid parenthesized expression");
+        }
+    };
+
+    var expression = function(commas, no_in) {
+        var start = S.token;
+        var exprs = [];
+        while (true) {
+            exprs.push(maybe_assign(no_in));
+            if (!commas || !is("punc", ",")) break;
+            next();
+            commas = true;
+        }
+        return to_expr_or_sequence(start, exprs);
+    };
+
+    function in_loop(cont) {
+        ++S.in_loop;
+        var ret = cont();
+        --S.in_loop;
+        return ret;
+    }
+
+    if (options.expression) {
+        return expression(true);
+    }
+
+    return (function parse_toplevel() {
+        var start = S.token;
+        var body = [];
+        S.input.push_directives_stack();
+        if (options.module) S.input.add_directive("use strict");
+        while (!is("eof")) {
+            body.push(statement());
+        }
+        S.input.pop_directives_stack();
+        var end = prev();
+        var toplevel = options.toplevel;
+        if (toplevel) {
+            toplevel.body = toplevel.body.concat(body);
+            toplevel.end = end;
+        } else {
+            toplevel = new AST_Toplevel({ start: start, body: body, end: end });
+        }
+        TEMPLATE_RAWS = new Map();
+        return toplevel;
+    })();
+
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function DEFNODE(type, props, ctor, methods, base = AST_Node) {
+    if (!props) props = [];
+    else props = props.split(/\s+/);
+    var self_props = props;
+    if (base && base.PROPS)
+        props = props.concat(base.PROPS);
+    const proto = base && Object.create(base.prototype);
+    if (proto) {
+        ctor.prototype = proto;
+        ctor.BASE = base;
+    }
+    if (base) base.SUBCLASSES.push(ctor);
+    ctor.prototype.CTOR = ctor;
+    ctor.prototype.constructor = ctor;
+    ctor.PROPS = props || null;
+    ctor.SELF_PROPS = self_props;
+    ctor.SUBCLASSES = [];
+    if (type) {
+        ctor.prototype.TYPE = ctor.TYPE = type;
+    }
+    if (methods) for (let i in methods) if (HOP(methods, i)) {
+        if (i[0] === "$") {
+            ctor[i.substr(1)] = methods[i];
+        } else {
+            ctor.prototype[i] = methods[i];
+        }
+    }
+    ctor.DEFMETHOD = function(name, method) {
+        this.prototype[name] = method;
+    };
+    return ctor;
+}
+
+const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag);
+const set_tok_flag = (tok, flag, truth) => {
+    if (truth) {
+        tok.flags |= flag;
+    } else {
+        tok.flags &= ~flag;
+    }
+};
+
+const TOK_FLAG_NLB          = 0b0001;
+const TOK_FLAG_QUOTE_SINGLE = 0b0010;
+const TOK_FLAG_QUOTE_EXISTS = 0b0100;
+const TOK_FLAG_TEMPLATE_END = 0b1000;
+
+class AST_Token {
+    constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) {
+        this.flags = (nlb ? 1 : 0);
+
+        this.type = type;
+        this.value = value;
+        this.line = line;
+        this.col = col;
+        this.pos = pos;
+        this.comments_before = comments_before;
+        this.comments_after = comments_after;
+        this.file = file;
+
+        Object.seal(this);
+    }
+
+    // Return a string summary of the token for node.js console.log
+    [Symbol.for("nodejs.util.inspect.custom")](_depth, options) {
+        const special = str => options.stylize(str, "special");
+        const quote = typeof this.value === "string" && this.value.includes("`") ? "'" : "`";
+        const value = `${quote}${this.value}${quote}`;
+        return `${special("[AST_Token")} ${value} at ${this.line}:${this.col}${special("]")}`;
+    }
+
+    get nlb() {
+        return has_tok_flag(this, TOK_FLAG_NLB);
+    }
+
+    set nlb(new_nlb) {
+        set_tok_flag(this, TOK_FLAG_NLB, new_nlb);
+    }
+
+    get quote() {
+        return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS)
+            ? ""
+            : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"');
+    }
+
+    set quote(quote_type) {
+        set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'");
+        set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type);
+    }
+
+    get template_end() {
+        return has_tok_flag(this, TOK_FLAG_TEMPLATE_END);
+    }
+
+    set template_end(new_template_end) {
+        set_tok_flag(this, TOK_FLAG_TEMPLATE_END, new_template_end);
+    }
+}
+
+var AST_Node = DEFNODE("Node", "start end", function AST_Node(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    _clone: function(deep) {
+        if (deep) {
+            var self = this.clone();
+            return self.transform(new TreeTransformer(function(node) {
+                if (node !== self) {
+                    return node.clone(true);
+                }
+            }));
+        }
+        return new this.CTOR(this);
+    },
+    clone: function(deep) {
+        return this._clone(deep);
+    },
+    $documentation: "Base class of all AST nodes",
+    $propdoc: {
+        start: "[AST_Token] The first token of this node",
+        end: "[AST_Token] The last token of this node"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this);
+    },
+    walk: function(visitor) {
+        return this._walk(visitor); // not sure the indirection will be any help
+    },
+    _children_backwards: () => {}
+}, null);
+
+/* -----[ statements ]----- */
+
+var AST_Statement = DEFNODE("Statement", null, function AST_Statement(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class of all statements",
+});
+
+var AST_Debugger = DEFNODE("Debugger", null, function AST_Debugger(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Represents a debugger statement",
+}, AST_Statement);
+
+var AST_Directive = DEFNODE("Directive", "value quote", function AST_Directive(props) {
+    if (props) {
+        this.value = props.value;
+        this.quote = props.quote;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Represents a directive, like \"use strict\";",
+    $propdoc: {
+        value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
+        quote: "[string] the original quote character"
+    },
+}, AST_Statement);
+
+var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_SimpleStatement(props) {
+    if (props) {
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
+    $propdoc: {
+        body: "[AST_Node] an expression node (should not be instanceof AST_Statement)"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+    }
+}, AST_Statement);
+
+function walk_body(node, visitor) {
+    const body = node.body;
+    for (var i = 0, len = body.length; i < len; i++) {
+        body[i]._walk(visitor);
+    }
+}
+
+function clone_block_scope(deep) {
+    var clone = this._clone(deep);
+    if (this.block_scope) {
+        clone.block_scope = this.block_scope.clone();
+    }
+    return clone;
+}
+
+var AST_Block = DEFNODE("Block", "body block_scope", function AST_Block(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A body of statements (usually braced)",
+    $propdoc: {
+        body: "[AST_Statement*] an array of statements",
+        block_scope: "[AST_Scope] the block scope"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            walk_body(this, visitor);
+        });
+    },
+    _children_backwards(push) {
+        let i = this.body.length;
+        while (i--) push(this.body[i]);
+    },
+    clone: clone_block_scope
+}, AST_Statement);
+
+var AST_BlockStatement = DEFNODE("BlockStatement", null, function AST_BlockStatement(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A block statement",
+}, AST_Block);
+
+var AST_EmptyStatement = DEFNODE("EmptyStatement", null, function AST_EmptyStatement(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The empty statement (empty block or simply a semicolon)"
+}, AST_Statement);
+
+var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", function AST_StatementWithBody(props) {
+    if (props) {
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
+    $propdoc: {
+        body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
+    }
+}, AST_Statement);
+
+var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", function AST_LabeledStatement(props) {
+    if (props) {
+        this.label = props.label;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Statement with a label",
+    $propdoc: {
+        label: "[AST_Label] a label definition"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.label._walk(visitor);
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+        push(this.label);
+    },
+    clone: function(deep) {
+        var node = this._clone(deep);
+        if (deep) {
+            var label = node.label;
+            var def = this.label;
+            node.walk(new TreeWalker(function(node) {
+                if (node instanceof AST_LoopControl
+                    && node.label && node.label.thedef === def) {
+                    node.label.thedef = label;
+                    label.references.push(node);
+                }
+            }));
+        }
+        return node;
+    }
+}, AST_StatementWithBody);
+
+var AST_IterationStatement = DEFNODE(
+    "IterationStatement",
+    "block_scope",
+    function AST_IterationStatement(props) {
+        if (props) {
+            this.block_scope = props.block_scope;
+            this.body = props.body;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Internal class.  All loops inherit from it.",
+        $propdoc: {
+            block_scope: "[AST_Scope] the block scope for this iteration statement."
+        },
+        clone: clone_block_scope
+    },
+    AST_StatementWithBody
+);
+
+var AST_DWLoop = DEFNODE("DWLoop", "condition", function AST_DWLoop(props) {
+    if (props) {
+        this.condition = props.condition;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for do/while statements",
+    $propdoc: {
+        condition: "[AST_Node] the loop condition.  Should not be instanceof AST_Statement"
+    }
+}, AST_IterationStatement);
+
+var AST_Do = DEFNODE("Do", null, function AST_Do(props) {
+    if (props) {
+        this.condition = props.condition;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `do` statement",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.body._walk(visitor);
+            this.condition._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.condition);
+        push(this.body);
+    }
+}, AST_DWLoop);
+
+var AST_While = DEFNODE("While", null, function AST_While(props) {
+    if (props) {
+        this.condition = props.condition;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `while` statement",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.condition._walk(visitor);
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+        push(this.condition);
+    },
+}, AST_DWLoop);
+
+var AST_For = DEFNODE("For", "init condition step", function AST_For(props) {
+    if (props) {
+        this.init = props.init;
+        this.condition = props.condition;
+        this.step = props.step;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `for` statement",
+    $propdoc: {
+        init: "[AST_Node?] the `for` initialization code, or null if empty",
+        condition: "[AST_Node?] the `for` termination clause, or null if empty",
+        step: "[AST_Node?] the `for` update clause, or null if empty"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.init) this.init._walk(visitor);
+            if (this.condition) this.condition._walk(visitor);
+            if (this.step) this.step._walk(visitor);
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+        if (this.step) push(this.step);
+        if (this.condition) push(this.condition);
+        if (this.init) push(this.init);
+    },
+}, AST_IterationStatement);
+
+var AST_ForIn = DEFNODE("ForIn", "init object", function AST_ForIn(props) {
+    if (props) {
+        this.init = props.init;
+        this.object = props.object;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `for ... in` statement",
+    $propdoc: {
+        init: "[AST_Node] the `for/in` initialization code",
+        object: "[AST_Node] the object that we're looping through"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.init._walk(visitor);
+            this.object._walk(visitor);
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+        if (this.object) push(this.object);
+        if (this.init) push(this.init);
+    },
+}, AST_IterationStatement);
+
+var AST_ForOf = DEFNODE("ForOf", "await", function AST_ForOf(props) {
+    if (props) {
+        this.await = props.await;
+        this.init = props.init;
+        this.object = props.object;
+        this.block_scope = props.block_scope;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `for ... of` statement",
+}, AST_ForIn);
+
+var AST_With = DEFNODE("With", "expression", function AST_With(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `with` statement",
+    $propdoc: {
+        expression: "[AST_Node] the `with` expression"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+            this.body._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.body);
+        push(this.expression);
+    },
+}, AST_StatementWithBody);
+
+/* -----[ scope and functions ]----- */
+
+var AST_Scope = DEFNODE(
+    "Scope",
+    "variables uses_with uses_eval parent_scope enclosed cname",
+    function AST_Scope(props) {
+        if (props) {
+            this.variables = props.variables;
+            this.uses_with = props.uses_with;
+            this.uses_eval = props.uses_eval;
+            this.parent_scope = props.parent_scope;
+            this.enclosed = props.enclosed;
+            this.cname = props.cname;
+            this.body = props.body;
+            this.block_scope = props.block_scope;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Base class for all statements introducing a lexical scope",
+        $propdoc: {
+            variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
+            uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
+            uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
+            parent_scope: "[AST_Scope?/S] link to the parent scope",
+            enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
+            cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
+        },
+        get_defun_scope: function() {
+            var self = this;
+            while (self.is_block_scope()) {
+                self = self.parent_scope;
+            }
+            return self;
+        },
+        clone: function(deep, toplevel) {
+            var node = this._clone(deep);
+            if (deep && this.variables && toplevel && !this._block_scope) {
+                node.figure_out_scope({}, {
+                    toplevel: toplevel,
+                    parent_scope: this.parent_scope
+                });
+            } else {
+                if (this.variables) node.variables = new Map(this.variables);
+                if (this.enclosed) node.enclosed = this.enclosed.slice();
+                if (this._block_scope) node._block_scope = this._block_scope;
+            }
+            return node;
+        },
+        pinned: function() {
+            return this.uses_eval || this.uses_with;
+        }
+    },
+    AST_Block
+);
+
+var AST_Toplevel = DEFNODE("Toplevel", "globals", function AST_Toplevel(props) {
+    if (props) {
+        this.globals = props.globals;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The toplevel scope",
+    $propdoc: {
+        globals: "[Map/S] a map of name -> SymbolDef for all undeclared names",
+    },
+    wrap_commonjs: function(name) {
+        var body = this.body;
+        var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");";
+        wrapped_tl = parse(wrapped_tl);
+        wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) {
+            if (node instanceof AST_Directive && node.value == "$ORIG") {
+                return MAP.splice(body);
+            }
+        }));
+        return wrapped_tl;
+    },
+    wrap_enclose: function(args_values) {
+        if (typeof args_values != "string") args_values = "";
+        var index = args_values.indexOf(":");
+        if (index < 0) index = args_values.length;
+        var body = this.body;
+        return parse([
+            "(function(",
+            args_values.slice(0, index),
+            '){"$ORIG"})(',
+            args_values.slice(index + 1),
+            ")"
+        ].join("")).transform(new TreeTransformer(function(node) {
+            if (node instanceof AST_Directive && node.value == "$ORIG") {
+                return MAP.splice(body);
+            }
+        }));
+    }
+}, AST_Scope);
+
+var AST_Expansion = DEFNODE("Expansion", "expression", function AST_Expansion(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list",
+    $propdoc: {
+        expression: "[AST_Node] the thing to be expanded"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression.walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+});
+
+var AST_Lambda = DEFNODE(
+    "Lambda",
+    "name argnames uses_arguments is_generator async",
+    function AST_Lambda(props) {
+        if (props) {
+            this.name = props.name;
+            this.argnames = props.argnames;
+            this.uses_arguments = props.uses_arguments;
+            this.is_generator = props.is_generator;
+            this.async = props.async;
+            this.variables = props.variables;
+            this.uses_with = props.uses_with;
+            this.uses_eval = props.uses_eval;
+            this.parent_scope = props.parent_scope;
+            this.enclosed = props.enclosed;
+            this.cname = props.cname;
+            this.body = props.body;
+            this.block_scope = props.block_scope;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Base class for functions",
+        $propdoc: {
+            name: "[AST_SymbolDeclaration?] the name of this function",
+            argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments",
+            uses_arguments: "[boolean/S] tells whether this function accesses the arguments array",
+            is_generator: "[boolean] is this a generator method",
+            async: "[boolean] is this method async",
+        },
+        args_as_names: function () {
+            var out = [];
+            for (var i = 0; i < this.argnames.length; i++) {
+                if (this.argnames[i] instanceof AST_Destructuring) {
+                    out.push(...this.argnames[i].all_symbols());
+                } else {
+                    out.push(this.argnames[i]);
+                }
+            }
+            return out;
+        },
+        _walk: function(visitor) {
+            return visitor._visit(this, function() {
+                if (this.name) this.name._walk(visitor);
+                var argnames = this.argnames;
+                for (var i = 0, len = argnames.length; i < len; i++) {
+                    argnames[i]._walk(visitor);
+                }
+                walk_body(this, visitor);
+            });
+        },
+        _children_backwards(push) {
+            let i = this.body.length;
+            while (i--) push(this.body[i]);
+
+            i = this.argnames.length;
+            while (i--) push(this.argnames[i]);
+
+            if (this.name) push(this.name);
+        },
+        is_braceless() {
+            return this.body[0] instanceof AST_Return && this.body[0].value;
+        },
+        // Default args and expansion don't count, so .argnames.length doesn't cut it
+        length_property() {
+            let length = 0;
+
+            for (const arg of this.argnames) {
+                if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) {
+                    length++;
+                }
+            }
+
+            return length;
+        }
+    },
+    AST_Scope
+);
+
+var AST_Accessor = DEFNODE("Accessor", null, function AST_Accessor(props) {
+    if (props) {
+        this.name = props.name;
+        this.argnames = props.argnames;
+        this.uses_arguments = props.uses_arguments;
+        this.is_generator = props.is_generator;
+        this.async = props.async;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A setter/getter function.  The `name` property is always null."
+}, AST_Lambda);
+
+var AST_Function = DEFNODE("Function", null, function AST_Function(props) {
+    if (props) {
+        this.name = props.name;
+        this.argnames = props.argnames;
+        this.uses_arguments = props.uses_arguments;
+        this.is_generator = props.is_generator;
+        this.async = props.async;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A function expression"
+}, AST_Lambda);
+
+var AST_Arrow = DEFNODE("Arrow", null, function AST_Arrow(props) {
+    if (props) {
+        this.name = props.name;
+        this.argnames = props.argnames;
+        this.uses_arguments = props.uses_arguments;
+        this.is_generator = props.is_generator;
+        this.async = props.async;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An ES6 Arrow function ((a) => b)"
+}, AST_Lambda);
+
+var AST_Defun = DEFNODE("Defun", null, function AST_Defun(props) {
+    if (props) {
+        this.name = props.name;
+        this.argnames = props.argnames;
+        this.uses_arguments = props.uses_arguments;
+        this.is_generator = props.is_generator;
+        this.async = props.async;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A function definition"
+}, AST_Lambda);
+
+/* -----[ DESTRUCTURING ]----- */
+var AST_Destructuring = DEFNODE("Destructuring", "names is_array", function AST_Destructuring(props) {
+    if (props) {
+        this.names = props.names;
+        this.is_array = props.is_array;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names",
+    $propdoc: {
+        "names": "[AST_Node*] Array of properties or elements",
+        "is_array": "[Boolean] Whether the destructuring represents an object or array"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.names.forEach(function(name) {
+                name._walk(visitor);
+            });
+        });
+    },
+    _children_backwards(push) {
+        let i = this.names.length;
+        while (i--) push(this.names[i]);
+    },
+    all_symbols: function() {
+        var out = [];
+        walk(this, node => {
+            if (node instanceof AST_SymbolDeclaration) {
+                out.push(node);
+            }
+            if (node instanceof AST_Lambda) {
+                return true;
+            }
+        });
+        return out;
+    }
+});
+
+var AST_PrefixedTemplateString = DEFNODE(
+    "PrefixedTemplateString",
+    "template_string prefix",
+    function AST_PrefixedTemplateString(props) {
+        if (props) {
+            this.template_string = props.template_string;
+            this.prefix = props.prefix;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`",
+        $propdoc: {
+            template_string: "[AST_TemplateString] The template string",
+            prefix: "[AST_Node] The prefix, which will get called."
+        },
+        _walk: function(visitor) {
+            return visitor._visit(this, function () {
+                this.prefix._walk(visitor);
+                this.template_string._walk(visitor);
+            });
+        },
+        _children_backwards(push) {
+            push(this.template_string);
+            push(this.prefix);
+        },
+    }
+);
+
+var AST_TemplateString = DEFNODE("TemplateString", "segments", function AST_TemplateString(props) {
+    if (props) {
+        this.segments = props.segments;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A template string literal",
+    $propdoc: {
+        segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment."
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.segments.forEach(function(seg) {
+                seg._walk(visitor);
+            });
+        });
+    },
+    _children_backwards(push) {
+        let i = this.segments.length;
+        while (i--) push(this.segments[i]);
+    }
+});
+
+var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", function AST_TemplateSegment(props) {
+    if (props) {
+        this.value = props.value;
+        this.raw = props.raw;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A segment of a template string literal",
+    $propdoc: {
+        value: "Content of the segment",
+        raw: "Raw source of the segment",
+    }
+});
+
+/* -----[ JUMPS ]----- */
+
+var AST_Jump = DEFNODE("Jump", null, function AST_Jump(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
+}, AST_Statement);
+
+/** Base class for “exits” (`return` and `throw`) */
+var AST_Exit = DEFNODE("Exit", "value", function AST_Exit(props) {
+    if (props) {
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for “exits” (`return` and `throw`)",
+    $propdoc: {
+        value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, this.value && function() {
+            this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.value) push(this.value);
+    },
+}, AST_Jump);
+
+var AST_Return = DEFNODE("Return", null, function AST_Return(props) {
+    if (props) {
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `return` statement"
+}, AST_Exit);
+
+var AST_Throw = DEFNODE("Throw", null, function AST_Throw(props) {
+    if (props) {
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `throw` statement"
+}, AST_Exit);
+
+var AST_LoopControl = DEFNODE("LoopControl", "label", function AST_LoopControl(props) {
+    if (props) {
+        this.label = props.label;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for loop control statements (`break` and `continue`)",
+    $propdoc: {
+        label: "[AST_LabelRef?] the label, or null if none",
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, this.label && function() {
+            this.label._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.label) push(this.label);
+    },
+}, AST_Jump);
+
+var AST_Break = DEFNODE("Break", null, function AST_Break(props) {
+    if (props) {
+        this.label = props.label;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `break` statement"
+}, AST_LoopControl);
+
+var AST_Continue = DEFNODE("Continue", null, function AST_Continue(props) {
+    if (props) {
+        this.label = props.label;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `continue` statement"
+}, AST_LoopControl);
+
+var AST_Await = DEFNODE("Await", "expression", function AST_Await(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An `await` statement",
+    $propdoc: {
+        expression: "[AST_Node] the mandatory expression being awaited",
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+});
+
+var AST_Yield = DEFNODE("Yield", "expression is_star", function AST_Yield(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.is_star = props.is_star;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `yield` statement",
+    $propdoc: {
+        expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false",
+        is_star: "[Boolean] Whether this is a yield or yield* statement"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, this.expression && function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.expression) push(this.expression);
+    }
+});
+
+/* -----[ IF ]----- */
+
+var AST_If = DEFNODE("If", "condition alternative", function AST_If(props) {
+    if (props) {
+        this.condition = props.condition;
+        this.alternative = props.alternative;
+        this.body = props.body;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `if` statement",
+    $propdoc: {
+        condition: "[AST_Node] the `if` condition",
+        alternative: "[AST_Statement?] the `else` part, or null if not present"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.condition._walk(visitor);
+            this.body._walk(visitor);
+            if (this.alternative) this.alternative._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.alternative) {
+            push(this.alternative);
+        }
+        push(this.body);
+        push(this.condition);
+    }
+}, AST_StatementWithBody);
+
+/* -----[ SWITCH ]----- */
+
+var AST_Switch = DEFNODE("Switch", "expression", function AST_Switch(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `switch` statement",
+    $propdoc: {
+        expression: "[AST_Node] the `switch` “discriminant”"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+            walk_body(this, visitor);
+        });
+    },
+    _children_backwards(push) {
+        let i = this.body.length;
+        while (i--) push(this.body[i]);
+        push(this.expression);
+    }
+}, AST_Block);
+
+var AST_SwitchBranch = DEFNODE("SwitchBranch", null, function AST_SwitchBranch(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for `switch` branches",
+}, AST_Block);
+
+var AST_Default = DEFNODE("Default", null, function AST_Default(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `default` switch branch",
+}, AST_SwitchBranch);
+
+var AST_Case = DEFNODE("Case", "expression", function AST_Case(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `case` switch branch",
+    $propdoc: {
+        expression: "[AST_Node] the `case` expression"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+            walk_body(this, visitor);
+        });
+    },
+    _children_backwards(push) {
+        let i = this.body.length;
+        while (i--) push(this.body[i]);
+        push(this.expression);
+    },
+}, AST_SwitchBranch);
+
+/* -----[ EXCEPTIONS ]----- */
+
+var AST_Try = DEFNODE("Try", "body bcatch bfinally", function AST_Try(props) {
+    if (props) {
+        this.body = props.body;
+        this.bcatch = props.bcatch;
+        this.bfinally = props.bfinally;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `try` statement",
+    $propdoc: {
+        body: "[AST_TryBlock] the try block",
+        bcatch: "[AST_Catch?] the catch block, or null if not present",
+        bfinally: "[AST_Finally?] the finally block, or null if not present"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.body._walk(visitor);
+            if (this.bcatch) this.bcatch._walk(visitor);
+            if (this.bfinally) this.bfinally._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.bfinally) push(this.bfinally);
+        if (this.bcatch) push(this.bcatch);
+        push(this.body);
+    },
+}, AST_Statement);
+
+var AST_TryBlock = DEFNODE("TryBlock", null, function AST_TryBlock(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `try` block of a try statement"
+}, AST_Block);
+
+var AST_Catch = DEFNODE("Catch", "argname", function AST_Catch(props) {
+    if (props) {
+        this.argname = props.argname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `catch` node; only makes sense as part of a `try` statement",
+    $propdoc: {
+        argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.argname) this.argname._walk(visitor);
+            walk_body(this, visitor);
+        });
+    },
+    _children_backwards(push) {
+        let i = this.body.length;
+        while (i--) push(this.body[i]);
+        if (this.argname) push(this.argname);
+    },
+}, AST_Block);
+
+var AST_Finally = DEFNODE("Finally", null, function AST_Finally(props) {
+    if (props) {
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `finally` node; only makes sense as part of a `try` statement"
+}, AST_Block);
+
+/* -----[ VAR/CONST ]----- */
+
+var AST_DefinitionsLike = DEFNODE("DefinitionsLike", "definitions", function AST_DefinitionsLike(props) {
+    if (props) {
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for variable definitions and `using`",
+    $propdoc: {
+        definitions: "[AST_VarDef*|AST_UsingDef*] array of variable definitions"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            var definitions = this.definitions;
+            for (var i = 0, len = definitions.length; i < len; i++) {
+                definitions[i]._walk(visitor);
+            }
+        });
+    },
+    _children_backwards(push) {
+        let i = this.definitions.length;
+        while (i--) push(this.definitions[i]);
+    },
+}, AST_Statement);
+
+var AST_Definitions = DEFNODE("Definitions", null, function AST_Definitions(props) {
+    if (props) {
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)",
+}, AST_DefinitionsLike);
+
+var AST_Var = DEFNODE("Var", null, function AST_Var(props) {
+    if (props) {
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `var` statement"
+}, AST_Definitions);
+
+var AST_Let = DEFNODE("Let", null, function AST_Let(props) {
+    if (props) {
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `let` statement"
+}, AST_Definitions);
+
+var AST_Const = DEFNODE("Const", null, function AST_Const(props) {
+    if (props) {
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `const` statement"
+}, AST_Definitions);
+
+var AST_Using = DEFNODE("Using", "await", function AST_Using(props) {
+    if (props) {
+        this.await = props.await;
+        this.definitions = props.definitions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `using` statement",
+    $propdoc: {
+        await: "[boolean] Whether it's `await using`"
+    },
+}, AST_DefinitionsLike);
+
+var AST_VarDefLike = DEFNODE("VarDefLike", "name value", function AST_VarDefLike(props) {
+    if (props) {
+        this.name = props.name;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A name=value pair in a variable definition statement or `using`",
+    $propdoc: {
+        name: "[AST_Destructuring|AST_SymbolDeclaration] name of the variable",
+        value: "[AST_Node?] initializer, or null of there's no initializer"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.name._walk(visitor);
+            if (this.value) this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.value) push(this.value);
+        push(this.name);
+    },
+    declarations_as_names() {
+        if (this.name instanceof AST_SymbolDeclaration) {
+            return [this.name];
+        } else {
+            return this.name.all_symbols();
+        }
+    }
+});
+
+var AST_VarDef = DEFNODE("VarDef", null, function AST_VarDef(props) {
+    if (props) {
+        this.name = props.name;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A variable declaration; only appears in a AST_Definitions node",
+}, AST_VarDefLike);
+
+var AST_UsingDef = DEFNODE("UsingDef", null, function AST_UsingDef(props) {
+    if (props) {
+        this.name = props.name;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Like VarDef but specific to AST_Using",
+}, AST_VarDefLike);
+
+var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", function AST_NameMapping(props) {
+    if (props) {
+        this.foreign_name = props.foreign_name;
+        this.name = props.name;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The part of the export/import statement that declare names from a module.",
+    $propdoc: {
+        foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)",
+        name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module."
+    },
+    _walk: function (visitor) {
+        return visitor._visit(this, function() {
+            this.foreign_name._walk(visitor);
+            this.name._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.name);
+        push(this.foreign_name);
+    },
+});
+
+var AST_Import = DEFNODE(
+    "Import",
+    "phase imported_name imported_names module_name attributes",
+    function AST_Import(props) {
+        if (props) {
+            this.phase = props.phase;
+            this.imported_name = props.imported_name;
+            this.imported_names = props.imported_names;
+            this.module_name = props.module_name;
+            this.attributes = props.attributes;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "An `import` statement",
+        $propdoc: {
+            phase: "[string?] Phase keyword: 'source', 'defer', or null.",
+            imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.",
+            imported_names: "[AST_NameMapping*] The names of non-default imported variables",
+            module_name: "[AST_String] String literal describing where this module came from",
+            attributes: "[AST_Object?] The import attributes (with {...})"
+        },
+        _walk: function(visitor) {
+            return visitor._visit(this, function() {
+                if (this.imported_name) {
+                    this.imported_name._walk(visitor);
+                }
+                if (this.imported_names) {
+                    this.imported_names.forEach(function(name_import) {
+                        name_import._walk(visitor);
+                    });
+                }
+                this.module_name._walk(visitor);
+            });
+        },
+        _children_backwards(push) {
+            push(this.module_name);
+            if (this.imported_names) {
+                let i = this.imported_names.length;
+                while (i--) push(this.imported_names[i]);
+            }
+            if (this.imported_name) push(this.imported_name);
+        },
+    }
+);
+
+var AST_ImportMeta = DEFNODE("ImportMeta", null, function AST_ImportMeta(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A reference to import.meta",
+});
+
+var AST_DynamicImport = DEFNODE(
+    "DynamicImport",
+    "phase args",
+    function AST_DynamicImport(props) {
+        if (props) {
+            this.phase = props.phase;
+            this.args = props.args;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "A phased dynamic import expression: `import.source(specifier [, options])` or `import.defer(specifier [, options])`. Plain `import(x)` continues to be parsed as an AST_Call with a synthetic `import` SymbolRef callee.",
+        $propdoc: {
+            phase: "[string] Phase keyword ('source' or 'defer').",
+            args: "[AST_Node*] specifier followed by optional options argument"
+        },
+        _walk: function(visitor) {
+            return visitor._visit(this, function() {
+                var args = this.args;
+                for (var i = 0, len = args.length; i < len; i++) {
+                    args[i]._walk(visitor);
+                }
+            });
+        },
+        _children_backwards(push) {
+            let i = this.args.length;
+            while (i--) push(this.args[i]);
+        },
+    }
+);
+
+var AST_Export = DEFNODE(
+    "Export",
+    "exported_definition exported_value is_default exported_names module_name attributes",
+    function AST_Export(props) {
+        if (props) {
+            this.exported_definition = props.exported_definition;
+            this.exported_value = props.exported_value;
+            this.is_default = props.is_default;
+            this.exported_names = props.exported_names;
+            this.module_name = props.module_name;
+            this.attributes = props.attributes;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "An `export` statement",
+        $propdoc: {
+            exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition",
+            exported_value: "[AST_Node?] An exported value",
+            exported_names: "[AST_NameMapping*?] List of exported names",
+            module_name: "[AST_String?] Name of the file to load exports from",
+            is_default: "[Boolean] Whether this is the default exported value of this module",
+            attributes: "[AST_Object?] The import attributes"
+        },
+        _walk: function (visitor) {
+            return visitor._visit(this, function () {
+                if (this.exported_definition) {
+                    this.exported_definition._walk(visitor);
+                }
+                if (this.exported_value) {
+                    this.exported_value._walk(visitor);
+                }
+                if (this.exported_names) {
+                    this.exported_names.forEach(function(name_export) {
+                        name_export._walk(visitor);
+                    });
+                }
+                if (this.module_name) {
+                    this.module_name._walk(visitor);
+                }
+            });
+        },
+        _children_backwards(push) {
+            if (this.module_name) push(this.module_name);
+            if (this.exported_names) {
+                let i = this.exported_names.length;
+                while (i--) push(this.exported_names[i]);
+            }
+            if (this.exported_value) push(this.exported_value);
+            if (this.exported_definition) push(this.exported_definition);
+        }
+    },
+    AST_Statement
+);
+
+/* -----[ OTHER ]----- */
+
+var AST_Call = DEFNODE(
+    "Call",
+    "expression args optional _annotations",
+    function AST_Call(props) {
+        if (props) {
+            this.expression = props.expression;
+            this.args = props.args;
+            this.optional = props.optional;
+            this._annotations = props._annotations;
+            this.start = props.start;
+            this.end = props.end;
+            this.initialize();
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "A function call expression",
+        $propdoc: {
+            expression: "[AST_Node] expression to invoke as function",
+            args: "[AST_Node*] array of arguments",
+            optional: "[boolean] whether this is an optional call (IE ?.() )",
+            _annotations: "[number] bitfield containing information about the call"
+        },
+        initialize() {
+            if (this._annotations == null) this._annotations = 0;
+        },
+        _walk(visitor) {
+            return visitor._visit(this, function() {
+                var args = this.args;
+                for (var i = 0, len = args.length; i < len; i++) {
+                    args[i]._walk(visitor);
+                }
+                this.expression._walk(visitor);  // TODO why do we need to crawl this last?
+            });
+        },
+        _children_backwards(push) {
+            let i = this.args.length;
+            while (i--) push(this.args[i]);
+            push(this.expression);
+        },
+    }
+);
+
+var AST_New = DEFNODE("New", null, function AST_New(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.args = props.args;
+        this.optional = props.optional;
+        this._annotations = props._annotations;
+        this.start = props.start;
+        this.end = props.end;
+        this.initialize();
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An object instantiation.  Derives from a function call since it has exactly the same properties"
+}, AST_Call);
+
+var AST_Sequence = DEFNODE("Sequence", "expressions", function AST_Sequence(props) {
+    if (props) {
+        this.expressions = props.expressions;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A sequence expression (comma-separated expressions)",
+    $propdoc: {
+        expressions: "[AST_Node*] array of expressions (at least two)"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expressions.forEach(function(node) {
+                node._walk(visitor);
+            });
+        });
+    },
+    _children_backwards(push) {
+        let i = this.expressions.length;
+        while (i--) push(this.expressions[i]);
+    },
+});
+
+var AST_PropAccess = DEFNODE(
+    "PropAccess",
+    "expression property optional",
+    function AST_PropAccess(props) {
+        if (props) {
+            this.expression = props.expression;
+            this.property = props.property;
+            this.optional = props.optional;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
+        $propdoc: {
+            expression: "[AST_Node] the “container” expression",
+            property: "[AST_Node|string] the property to access.  For AST_Dot & AST_DotHash this is always a plain string, while for AST_Sub it's an arbitrary AST_Node",
+
+            optional: "[boolean] whether this is an optional property access (IE ?.)"
+        }
+    }
+);
+
+var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.expression = props.expression;
+        this.property = props.property;
+        this.optional = props.optional;
+        this._annotations = props._annotations;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A dotted property access expression",
+    $propdoc: {
+        quote: "[string] the original quote character when transformed from AST_Sub",
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+}, AST_PropAccess);
+
+var AST_DotHash = DEFNODE("DotHash", "", function AST_DotHash(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.property = props.property;
+        this.optional = props.optional;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A dotted property access to a private property",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+}, AST_PropAccess);
+
+var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.property = props.property;
+        this.optional = props.optional;
+        this._annotations = props._annotations;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+            this.property._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.property);
+        push(this.expression);
+    },
+}, AST_PropAccess);
+
+var AST_Chain = DEFNODE("Chain", "expression", function AST_Chain(props) {
+    if (props) {
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A chain expression like a?.b?.(c)?.[d]",
+    $propdoc: {
+        expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element."
+    },
+    _walk: function (visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+});
+
+var AST_Unary = DEFNODE("Unary", "operator expression", function AST_Unary(props) {
+    if (props) {
+        this.operator = props.operator;
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for unary expressions",
+    $propdoc: {
+        operator: "[string] the operator",
+        expression: "[AST_Node] expression that this unary operator applies to"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.expression._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.expression);
+    },
+});
+
+var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, function AST_UnaryPrefix(props) {
+    if (props) {
+        this.operator = props.operator;
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
+}, AST_Unary);
+
+var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, function AST_UnaryPostfix(props) {
+    if (props) {
+        this.operator = props.operator;
+        this.expression = props.expression;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Unary postfix expression, i.e. `i++`"
+}, AST_Unary);
+
+var AST_Binary = DEFNODE("Binary", "operator left right", function AST_Binary(props) {
+    if (props) {
+        this.operator = props.operator;
+        this.left = props.left;
+        this.right = props.right;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Binary expression, i.e. `a + b`",
+    $propdoc: {
+        left: "[AST_Node] left-hand side expression",
+        operator: "[string] the operator",
+        right: "[AST_Node] right-hand side expression"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.left._walk(visitor);
+            this.right._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.right);
+        push(this.left);
+    },
+});
+
+var AST_Conditional = DEFNODE(
+    "Conditional",
+    "condition consequent alternative",
+    function AST_Conditional(props) {
+        if (props) {
+            this.condition = props.condition;
+            this.consequent = props.consequent;
+            this.alternative = props.alternative;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
+        $propdoc: {
+            condition: "[AST_Node]",
+            consequent: "[AST_Node]",
+            alternative: "[AST_Node]"
+        },
+        _walk: function(visitor) {
+            return visitor._visit(this, function() {
+                this.condition._walk(visitor);
+                this.consequent._walk(visitor);
+                this.alternative._walk(visitor);
+            });
+        },
+        _children_backwards(push) {
+            push(this.alternative);
+            push(this.consequent);
+            push(this.condition);
+        },
+    }
+);
+
+var AST_Assign = DEFNODE("Assign", "logical", function AST_Assign(props) {
+    if (props) {
+        this.logical = props.logical;
+        this.operator = props.operator;
+        this.left = props.left;
+        this.right = props.right;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An assignment expression — `a = b + 5`",
+    $propdoc: {
+        logical: "Whether it's a logical assignment"
+    }
+}, AST_Binary);
+
+var AST_DefaultAssign = DEFNODE("DefaultAssign", null, function AST_DefaultAssign(props) {
+    if (props) {
+        this.operator = props.operator;
+        this.left = props.left;
+        this.right = props.right;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A default assignment expression like in `(a = 3) => a`"
+}, AST_Binary);
+
+/* -----[ LITERALS ]----- */
+
+var AST_Array = DEFNODE("Array", "elements", function AST_Array(props) {
+    if (props) {
+        this.elements = props.elements;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An array literal",
+    $propdoc: {
+        elements: "[AST_Node*] array of elements"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            var elements = this.elements;
+            for (var i = 0, len = elements.length; i < len; i++) {
+                elements[i]._walk(visitor);
+            }
+        });
+    },
+    _children_backwards(push) {
+        let i = this.elements.length;
+        while (i--) push(this.elements[i]);
+    },
+});
+
+var AST_Object = DEFNODE("Object", "properties", function AST_Object(props) {
+    if (props) {
+        this.properties = props.properties;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An object literal",
+    $propdoc: {
+        properties: "[AST_ObjectProperty*] array of properties"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            var properties = this.properties;
+            for (var i = 0, len = properties.length; i < len; i++) {
+                properties[i]._walk(visitor);
+            }
+        });
+    },
+    _children_backwards(push) {
+        let i = this.properties.length;
+        while (i--) push(this.properties[i]);
+    },
+});
+
+/* -----[ OBJECT/CLASS PROPERTIES ]----- */
+
+/**
+ * Everything inside the curly braces of an object/class is a subclass of AST_ObjectProperty, except for AST_ClassStaticBlock.
+ **/
+var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", function AST_ObjectProperty(props) {
+    if (props) {
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for literal object properties",
+    $propdoc: {
+        key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.",
+        value: "[AST_Node] property value.  For getters, setters and methods this is an AST_Accessor."
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.key instanceof AST_Node)
+                this.key._walk(visitor);
+            this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.value);
+        if (this.key instanceof AST_Node) push(this.key);
+    },
+});
+
+var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", function AST_ObjectKeyVal(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A key: value object property",
+    $propdoc: {
+        quote: "[string] the original quote character"
+    },
+    computed_key() {
+        return this.key instanceof AST_Node;
+    }
+}, AST_ObjectProperty);
+
+var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", function AST_PrivateSetter(props) {
+    if (props) {
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        static: "[boolean] whether this is a static private setter"
+    },
+    $documentation: "A private setter property",
+    computed_key() {
+        return false;
+    }
+}, AST_ObjectProperty);
+
+var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", function AST_PrivateGetter(props) {
+    if (props) {
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        static: "[boolean] whether this is a static private getter"
+    },
+    $documentation: "A private getter property",
+    computed_key() {
+        return false;
+    }
+}, AST_ObjectProperty);
+
+var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", function AST_ObjectSetter(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        quote: "[string|undefined] the original quote character, if any",
+        static: "[boolean] whether this is a static setter (classes only)"
+    },
+    $documentation: "An object setter property",
+    computed_key() {
+        return !(this.key instanceof AST_SymbolMethod);
+    }
+}, AST_ObjectProperty);
+
+var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", function AST_ObjectGetter(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        quote: "[string|undefined] the original quote character, if any",
+        static: "[boolean] whether this is a static getter (classes only)"
+    },
+    $documentation: "An object getter property",
+    computed_key() {
+        return !(this.key instanceof AST_SymbolMethod);
+    }
+}, AST_ObjectProperty);
+
+var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static", function AST_ConciseMethod(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        quote: "[string|undefined] the original quote character, if any",
+        static: "[boolean] is this method static (classes only)",
+    },
+    $documentation: "An ES6 concise method inside an object or class",
+    computed_key() {
+        return !(this.key instanceof AST_SymbolMethod);
+    }
+}, AST_ObjectProperty);
+
+var AST_PrivateMethod = DEFNODE("PrivateMethod", "static", function AST_PrivateMethod(props) {
+    if (props) {
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A private class method inside a class",
+    $propdoc: {
+        static: "[boolean] is this a static private method",
+    },
+    computed_key() {
+        return false;
+    },
+}, AST_ObjectProperty);
+
+var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(props) {
+    if (props) {
+        this.name = props.name;
+        this.extends = props.extends;
+        this.properties = props.properties;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.",
+        extends: "[AST_Node]? optional parent class",
+        properties: "[AST_ObjectProperty|AST_ClassStaticBlock]* array of properties or static blocks"
+    },
+    $documentation: "An ES6 class",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.name) {
+                this.name._walk(visitor);
+            }
+            if (this.extends) {
+                this.extends._walk(visitor);
+            }
+            this.properties.forEach((prop) => prop._walk(visitor));
+        });
+    },
+    _children_backwards(push) {
+        let i = this.properties.length;
+        while (i--) push(this.properties[i]);
+        if (this.extends) push(this.extends);
+        if (this.name) push(this.name);
+    },
+    /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */
+    visit_nondeferred_class_parts(visitor) {
+        if (this.extends) {
+            this.extends._walk(visitor);
+        }
+        this.properties.forEach((prop) => {
+            if (prop instanceof AST_ClassStaticBlock) {
+                prop._walk(visitor);
+                return;
+            }
+            if (prop.computed_key()) {
+                visitor.push(prop);
+                prop.key._walk(visitor);
+                visitor.pop();
+            }
+            if (
+                prop instanceof AST_ClassPrivateProperty && prop.static && prop.value
+                || prop instanceof AST_ClassProperty && prop.static && prop.value
+            ) {
+                visitor.push(prop);
+                prop.value._walk(visitor);
+                visitor.pop();
+            }
+        });
+    },
+    /** go through the bits that are executed later, when the class is `new`'d or a static method is called */
+    visit_deferred_class_parts(visitor) {
+        this.properties.forEach((prop) => {
+            if (
+                prop instanceof AST_ConciseMethod
+                || prop instanceof AST_PrivateMethod
+            ) {
+                prop.walk(visitor);
+            } else if (
+                prop instanceof AST_ClassProperty && !prop.static && prop.value
+                || prop instanceof AST_ClassPrivateProperty && !prop.static && prop.value
+            ) {
+                visitor.push(prop);
+                prop.value._walk(visitor);
+                visitor.pop();
+            }
+        });
+    },
+    is_self_referential: function() {
+        const this_id = this.name && this.name.definition().id;
+        let found = false;
+        let class_this = true;
+        this.visit_nondeferred_class_parts(new TreeWalker((node, descend) => {
+            if (found) return true;
+            if (node instanceof AST_This) return (found = class_this);
+            if (node instanceof AST_SymbolRef) return (found = node.definition().id === this_id);
+            if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) {
+                const class_this_save = class_this;
+                class_this = false;
+                descend();
+                class_this = class_this_save;
+                return true;
+            }
+        }));
+        return found;
+    },
+}, AST_Scope /* TODO a class might have a scope but it's not a scope */);
+
+var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) {
+    if (props) {
+        this.static = props.static;
+        this.quote = props.quote;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A class property",
+    $propdoc: {
+        static: "[boolean] whether this is a static key",
+        quote: "[string] which quote is being used"
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.key instanceof AST_Node)
+                this.key._walk(visitor);
+            if (this.value instanceof AST_Node)
+                this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.value instanceof AST_Node) push(this.value);
+        if (this.key instanceof AST_Node) push(this.key);
+    },
+    computed_key() {
+        return !(this.key instanceof AST_SymbolClassProperty);
+    }
+}, AST_ObjectProperty);
+
+var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", function AST_ClassPrivateProperty(props) {
+    if (props) {
+        this.static = props.static;
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A class property for a private property",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            if (this.value instanceof AST_Node)
+                this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        if (this.value instanceof AST_Node) push(this.value);
+    },
+    computed_key() {
+        return false;
+    },
+}, AST_ObjectProperty);
+
+var AST_PrivateIn = DEFNODE("PrivateIn", "key value", function AST_PrivateIn(props) {
+    if (props) {
+        this.key = props.key;
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "An `in` binop when the key is private, eg #x in this",
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            this.key._walk(visitor);
+            this.value._walk(visitor);
+        });
+    },
+    _children_backwards(push) {
+        push(this.value);
+        push(this.key);
+    },
+});
+
+var AST_DefClass = DEFNODE("DefClass", null, function AST_DefClass(props) {
+    if (props) {
+        this.name = props.name;
+        this.extends = props.extends;
+        this.properties = props.properties;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A class definition",
+}, AST_Class);
+
+var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", function AST_ClassStaticBlock (props) {
+    this.body = props.body;
+    this.block_scope = props.block_scope;
+    this.start = props.start;
+    this.end = props.end;
+}, {
+    $documentation: "A block containing statements to be executed in the context of the class",
+    $propdoc: {
+        body: "[AST_Statement*] an array of statements",
+    },
+    _walk: function(visitor) {
+        return visitor._visit(this, function() {
+            walk_body(this, visitor);
+        });
+    },
+    _children_backwards(push) {
+        let i = this.body.length;
+        while (i--) push(this.body[i]);
+    },
+    clone: clone_block_scope,
+    computed_key() {
+        return false;
+    },
+}, AST_Scope);
+
+var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) {
+    if (props) {
+        this.name = props.name;
+        this.extends = props.extends;
+        this.properties = props.properties;
+        this.variables = props.variables;
+        this.uses_with = props.uses_with;
+        this.uses_eval = props.uses_eval;
+        this.parent_scope = props.parent_scope;
+        this.enclosed = props.enclosed;
+        this.cname = props.cname;
+        this.body = props.body;
+        this.block_scope = props.block_scope;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A class expression."
+}, AST_Class);
+
+var AST_Symbol = DEFNODE("Symbol", "scope name thedef", function AST_Symbol(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $propdoc: {
+        name: "[string] name of this symbol",
+        scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
+        thedef: "[SymbolDef/S] the definition of this symbol"
+    },
+    $documentation: "Base class for all symbols"
+});
+
+var AST_NewTarget = DEFNODE("NewTarget", null, function AST_NewTarget(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A reference to new.target"
+});
+
+var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", function AST_SymbolDeclaration(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
+}, AST_Symbol);
+
+var AST_SymbolVar = DEFNODE("SymbolVar", null, function AST_SymbolVar(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol defining a variable",
+}, AST_SymbolDeclaration);
+
+var AST_SymbolBlockDeclaration = DEFNODE(
+    "SymbolBlockDeclaration",
+    null,
+    function AST_SymbolBlockDeclaration(props) {
+        if (props) {
+            this.init = props.init;
+            this.scope = props.scope;
+            this.name = props.name;
+            this.thedef = props.thedef;
+            this.start = props.start;
+            this.end = props.end;
+        }
+
+        this.flags = 0;
+    },
+    {
+        $documentation: "Base class for block-scoped declaration symbols"
+    },
+    AST_SymbolDeclaration
+);
+
+var AST_SymbolConst = DEFNODE("SymbolConst", null, function AST_SymbolConst(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A constant declaration"
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolUsing = DEFNODE("SymbolUsing", null, function AST_SymbolUsing(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A `using` declaration"
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolLet = DEFNODE("SymbolLet", null, function AST_SymbolLet(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A block-scoped `let` declaration"
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, function AST_SymbolFunarg(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming a function argument",
+}, AST_SymbolVar);
+
+var AST_SymbolDefun = DEFNODE("SymbolDefun", null, function AST_SymbolDefun(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol defining a function",
+}, AST_SymbolDeclaration);
+
+var AST_SymbolMethod = DEFNODE("SymbolMethod", null, function AST_SymbolMethod(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol in an object defining a method",
+}, AST_Symbol);
+
+var AST_SymbolClassProperty = DEFNODE("SymbolClassProperty", null, function AST_SymbolClassProperty(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol for a class property",
+}, AST_Symbol);
+
+var AST_SymbolLambda = DEFNODE("SymbolLambda", null, function AST_SymbolLambda(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming a function expression",
+}, AST_SymbolDeclaration);
+
+var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, function AST_SymbolDefClass(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolClass = DEFNODE("SymbolClass", null, function AST_SymbolClass(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming a class's name. Lexically scoped to the class."
+}, AST_SymbolDeclaration);
+
+var AST_SymbolCatch = DEFNODE("SymbolCatch", null, function AST_SymbolCatch(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming the exception in catch",
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolImport = DEFNODE("SymbolImport", null, function AST_SymbolImport(props) {
+    if (props) {
+        this.init = props.init;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol referring to an imported name",
+}, AST_SymbolBlockDeclaration);
+
+var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", "quote", function AST_SymbolImportForeign(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
+}, AST_Symbol);
+
+var AST_Label = DEFNODE("Label", "references", function AST_Label(props) {
+    if (props) {
+        this.references = props.references;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+        this.initialize();
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol naming a label (declaration)",
+    $propdoc: {
+        references: "[AST_LoopControl*] a list of nodes referring to this label"
+    },
+    initialize: function() {
+        this.references = [];
+        this.thedef = this;
+    }
+}, AST_Symbol);
+
+var AST_SymbolRef = DEFNODE("SymbolRef", null, function AST_SymbolRef(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Reference to some symbol (not definition/declaration)",
+}, AST_Symbol);
+
+var AST_SymbolExport = DEFNODE("SymbolExport", "quote", function AST_SymbolExport(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Symbol referring to a name to export",
+}, AST_SymbolRef);
+
+var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", "quote", function AST_SymbolExportForeign(props) {
+    if (props) {
+        this.quote = props.quote;
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes",
+}, AST_Symbol);
+
+var AST_LabelRef = DEFNODE("LabelRef", null, function AST_LabelRef(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Reference to a label symbol",
+}, AST_Symbol);
+
+var AST_SymbolPrivateProperty = DEFNODE("SymbolPrivateProperty", null, function AST_SymbolPrivateProperty(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A symbol that refers to a private property",
+}, AST_Symbol);
+
+var AST_This = DEFNODE("This", null, function AST_This(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `this` symbol",
+}, AST_Symbol);
+
+var AST_Super = DEFNODE("Super", null, function AST_Super(props) {
+    if (props) {
+        this.scope = props.scope;
+        this.name = props.name;
+        this.thedef = props.thedef;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `super` symbol",
+}, AST_This);
+
+var AST_Constant = DEFNODE("Constant", null, function AST_Constant(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for all constants",
+    getValue: function() {
+        return this.value;
+    }
+});
+
+var AST_String = DEFNODE("String", "value quote", function AST_String(props) {
+    if (props) {
+        this.value = props.value;
+        this.quote = props.quote;
+        this.start = props.start;
+        this.end = props.end;
+        this._annotations = props._annotations;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A string literal",
+    $propdoc: {
+        value: "[string] the contents of this string",
+        quote: "[string] the original quote character"
+    }
+}, AST_Constant);
+
+var AST_Number = DEFNODE("Number", "value raw", function AST_Number(props) {
+    if (props) {
+        this.value = props.value;
+        this.raw = props.raw;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A number literal",
+    $propdoc: {
+        value: "[number] the numeric value",
+        raw: "[string] numeric value as string"
+    }
+}, AST_Constant);
+
+var AST_BigInt = DEFNODE("BigInt", "value raw", function AST_BigInt(props) {
+    if (props) {
+        this.value = props.value;
+        this.raw = props.raw;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A big int literal",
+    $propdoc: {
+        value: "[string] big int value, represented as a string",
+        raw: "[string] the original format preserved"
+    }
+}, AST_Constant);
+
+var AST_RegExp = DEFNODE("RegExp", "value", function AST_RegExp(props) {
+    if (props) {
+        this.value = props.value;
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A regexp literal",
+    $propdoc: {
+        value: "[RegExp] the actual regexp",
+    }
+}, AST_Constant);
+
+var AST_Atom = DEFNODE("Atom", null, function AST_Atom(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for atoms",
+}, AST_Constant);
+
+var AST_Null = DEFNODE("Null", null, function AST_Null(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `null` atom",
+    value: null
+}, AST_Atom);
+
+var AST_NaN = DEFNODE("NaN", null, function AST_NaN(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The impossible value",
+    value: 0/0
+}, AST_Atom);
+
+var AST_Undefined = DEFNODE("Undefined", null, function AST_Undefined(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `undefined` value",
+    value: (function() {}())
+}, AST_Atom);
+
+var AST_Hole = DEFNODE("Hole", null, function AST_Hole(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "A hole in an array",
+    value: (function() {}())
+}, AST_Atom);
+
+var AST_Infinity = DEFNODE("Infinity", null, function AST_Infinity(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `Infinity` value",
+    value: 1/0
+}, AST_Atom);
+
+var AST_Boolean = DEFNODE("Boolean", null, function AST_Boolean(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "Base class for booleans",
+}, AST_Atom);
+
+var AST_False = DEFNODE("False", null, function AST_False(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `false` atom",
+    value: false
+}, AST_Boolean);
+
+var AST_True = DEFNODE("True", null, function AST_True(props) {
+    if (props) {
+        this.start = props.start;
+        this.end = props.end;
+    }
+
+    this.flags = 0;
+}, {
+    $documentation: "The `true` atom",
+    value: true
+}, AST_Boolean);
+
+/* -----[ Walk function ]---- */
+
+/**
+ * Walk nodes in depth-first search fashion.
+ * Callback can return `walk_abort` symbol to stop iteration.
+ * It can also return `true` to stop iteration just for child nodes.
+ * Iteration can be stopped and continued by passing the `to_visit` argument,
+ * which is given to the callback in the second argument.
+ **/
+function walk(node, cb, to_visit = [node]) {
+    const push = to_visit.push.bind(to_visit);
+    while (to_visit.length) {
+        const node = to_visit.pop();
+        const ret = cb(node, to_visit);
+
+        if (ret) {
+            if (ret === walk_abort) return true;
+            continue;
+        }
+
+        node._children_backwards(push);
+    }
+    return false;
+}
+
+/**
+ * Walks an AST node and its children.
+ *
+ * {cb} can return `walk_abort` to interrupt the walk.
+ *
+ * @param node
+ * @param cb {(node, info: { parent: (nth) => any }) => (boolean | undefined)}
+ *
+ * @returns {boolean} whether the walk was aborted
+ *
+ * @example
+ * const found_some_cond = walk_parent(my_ast_node, (node, { parent }) => {
+ *   if (some_cond(node, parent())) return walk_abort
+ * });
+ */
+function walk_parent(node, cb, initial_stack) {
+    const to_visit = [node];
+    const push = to_visit.push.bind(to_visit);
+    const stack = initial_stack ? initial_stack.slice() : [];
+    const parent_pop_indices = [];
+
+    let current;
+
+    const info = {
+        parent: (n = 0) => {
+            if (n === -1) {
+                return current;
+            }
+
+            // [ p1 p0 ] [ 1 0 ]
+            if (initial_stack && n >= stack.length) {
+                n -= stack.length;
+                return initial_stack[
+                    initial_stack.length - (n + 1)
+                ];
+            }
+
+            return stack[stack.length - (1 + n)];
+        },
+    };
+
+    while (to_visit.length) {
+        current = to_visit.pop();
+
+        while (
+            parent_pop_indices.length &&
+            to_visit.length == parent_pop_indices[parent_pop_indices.length - 1]
+        ) {
+            stack.pop();
+            parent_pop_indices.pop();
+        }
+
+        const ret = cb(current, info);
+
+        if (ret) {
+            if (ret === walk_abort) return true;
+            continue;
+        }
+
+        const visit_length = to_visit.length;
+
+        current._children_backwards(push);
+
+        // Push only if we're going to traverse the children
+        if (to_visit.length > visit_length) {
+            stack.push(current);
+            parent_pop_indices.push(visit_length - 1);
+        }
+    }
+
+    return false;
+}
+
+const walk_abort = Symbol("abort walk");
+
+/* -----[ TreeWalker ]----- */
+
+class TreeWalker {
+    constructor(callback) {
+        this.visit = callback;
+        this.stack = [];
+        this.directives = Object.create(null);
+    }
+
+    _visit(node, descend) {
+        this.push(node);
+        var ret = this.visit(node, descend ? function() {
+            descend.call(node);
+        } : noop);
+        if (!ret && descend) {
+            descend.call(node);
+        }
+        this.pop();
+        return ret;
+    }
+
+    parent(n) {
+        return this.stack[this.stack.length - 2 - (n || 0)];
+    }
+
+    push(node) {
+        if (node instanceof AST_Lambda) {
+            this.directives = Object.create(this.directives);
+        } else if (node instanceof AST_Directive && !this.directives[node.value]) {
+            this.directives[node.value] = node;
+        } else if (node instanceof AST_Class) {
+            this.directives = Object.create(this.directives);
+            if (!this.directives["use strict"]) {
+                this.directives["use strict"] = node;
+            }
+        }
+        this.stack.push(node);
+    }
+
+    pop() {
+        var node = this.stack.pop();
+        if (node instanceof AST_Lambda || node instanceof AST_Class) {
+            this.directives = Object.getPrototypeOf(this.directives);
+        }
+    }
+
+    self() {
+        return this.stack[this.stack.length - 1];
+    }
+
+    find_parent(type) {
+        var stack = this.stack;
+        for (var i = stack.length; --i >= 0;) {
+            var x = stack[i];
+            if (x instanceof type) return x;
+        }
+    }
+
+    is_within_loop() {
+        let i = this.stack.length - 1;
+        let child = this.stack[i];
+        while (i--) {
+            const node = this.stack[i];
+
+            if (node instanceof AST_Lambda) return false;
+            if (
+                node instanceof AST_IterationStatement
+                // exclude for-loop bits that only run once
+                && !((node instanceof AST_For) && child === node.init)
+                && !((node instanceof AST_ForIn || node instanceof AST_ForOf) && child === node.object)
+            ) {
+                return true;
+            }
+
+            child = node;
+        }
+
+        return false;
+    }
+
+    find_scope() {
+        var stack = this.stack;
+        for (var i = stack.length; --i >= 0;) {
+            const p = stack[i];
+            if (p instanceof AST_Toplevel) return p;
+            if (p instanceof AST_Lambda) return p;
+            if (p.block_scope) return p.block_scope;
+        }
+    }
+
+    has_directive(type) {
+        var dir = this.directives[type];
+        if (dir) return dir;
+        var node = this.stack[this.stack.length - 1];
+        if (node instanceof AST_Scope && node.body) {
+            for (var i = 0; i < node.body.length; ++i) {
+                var st = node.body[i];
+                if (!(st instanceof AST_Directive)) break;
+                if (st.value == type) return st;
+            }
+        }
+    }
+
+    loopcontrol_target(node) {
+        var stack = this.stack;
+        if (node.label) for (var i = stack.length; --i >= 0;) {
+            var x = stack[i];
+            if (x instanceof AST_LabeledStatement && x.label.name == node.label.name)
+                return x.body;
+        } else for (var i = stack.length; --i >= 0;) {
+            var x = stack[i];
+            if (x instanceof AST_IterationStatement
+                || node instanceof AST_Break && x instanceof AST_Switch)
+                return x;
+        }
+    }
+}
+
+// Tree transformer helpers.
+class TreeTransformer extends TreeWalker {
+    constructor(before, after) {
+        super();
+        this.before = before;
+        this.after = after;
+    }
+}
+
+const _PURE       = 0b00000001;
+const _INLINE     = 0b00000010;
+const _NOINLINE   = 0b00000100;
+const _KEY        = 0b00001000;
+const _MANGLEPROP = 0b00010000;
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function def_transform(node, descend) {
+    node.DEFMETHOD("transform", function(tw, in_list) {
+        let transformed = undefined;
+        tw.push(this);
+        if (tw.before) transformed = tw.before(this, descend, in_list);
+        if (transformed === undefined) {
+            transformed = this;
+            descend(transformed, tw);
+            if (tw.after) {
+                const after_ret = tw.after(transformed, in_list);
+                if (after_ret !== undefined) transformed = after_ret;
+            }
+        }
+        tw.pop();
+        return transformed;
+    });
+}
+
+def_transform(AST_Node, noop);
+
+def_transform(AST_LabeledStatement, function(self, tw) {
+    self.label = self.label.transform(tw);
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_SimpleStatement, function(self, tw) {
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_Block, function(self, tw) {
+    self.body = MAP(self.body, tw);
+});
+
+def_transform(AST_Do, function(self, tw) {
+    self.body = self.body.transform(tw);
+    self.condition = self.condition.transform(tw);
+});
+
+def_transform(AST_While, function(self, tw) {
+    self.condition = self.condition.transform(tw);
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_For, function(self, tw) {
+    if (self.init) self.init = self.init.transform(tw);
+    if (self.condition) self.condition = self.condition.transform(tw);
+    if (self.step) self.step = self.step.transform(tw);
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_ForIn, function(self, tw) {
+    self.init = self.init.transform(tw);
+    self.object = self.object.transform(tw);
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_With, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+    self.body = self.body.transform(tw);
+});
+
+def_transform(AST_Exit, function(self, tw) {
+    if (self.value) self.value = self.value.transform(tw);
+});
+
+def_transform(AST_LoopControl, function(self, tw) {
+    if (self.label) self.label = self.label.transform(tw);
+});
+
+def_transform(AST_If, function(self, tw) {
+    self.condition = self.condition.transform(tw);
+    self.body = self.body.transform(tw);
+    if (self.alternative) self.alternative = self.alternative.transform(tw);
+});
+
+def_transform(AST_Switch, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+    self.body = MAP(self.body, tw);
+});
+
+def_transform(AST_Case, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+    self.body = MAP(self.body, tw);
+});
+
+def_transform(AST_Try, function(self, tw) {
+    self.body = self.body.transform(tw);
+    if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
+    if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
+});
+
+def_transform(AST_Catch, function(self, tw) {
+    if (self.argname) self.argname = self.argname.transform(tw);
+    self.body = MAP(self.body, tw);
+});
+
+def_transform(AST_DefinitionsLike, function(self, tw) {
+    self.definitions = MAP(self.definitions, tw);
+});
+
+def_transform(AST_VarDefLike, function(self, tw) {
+    self.name = self.name.transform(tw);
+    if (self.value) self.value = self.value.transform(tw);
+});
+
+def_transform(AST_Destructuring, function(self, tw) {
+    self.names = MAP(self.names, tw);
+});
+
+def_transform(AST_Lambda, function(self, tw) {
+    if (self.name) self.name = self.name.transform(tw);
+    self.argnames = MAP(self.argnames, tw, /* allow_splicing */ false);
+    if (self.body instanceof AST_Node) {
+        self.body = self.body.transform(tw);
+    } else {
+        self.body = MAP(self.body, tw);
+    }
+});
+
+def_transform(AST_Call, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+    self.args = MAP(self.args, tw, /* allow_splicing */ false);
+});
+
+def_transform(AST_Sequence, function(self, tw) {
+    const result = MAP(self.expressions, tw);
+    self.expressions = result.length
+        ? result
+        : [new AST_Number({ value: 0 })];
+});
+
+def_transform(AST_PropAccess, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_Sub, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+    self.property = self.property.transform(tw);
+});
+
+def_transform(AST_Chain, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_Yield, function(self, tw) {
+    if (self.expression) self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_Await, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_Unary, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_Binary, function(self, tw) {
+    self.left = self.left.transform(tw);
+    self.right = self.right.transform(tw);
+});
+
+def_transform(AST_PrivateIn, function(self, tw) {
+    self.key = self.key.transform(tw);
+    self.value = self.value.transform(tw);
+});
+
+def_transform(AST_Conditional, function(self, tw) {
+    self.condition = self.condition.transform(tw);
+    self.consequent = self.consequent.transform(tw);
+    self.alternative = self.alternative.transform(tw);
+});
+
+def_transform(AST_Array, function(self, tw) {
+    self.elements = MAP(self.elements, tw);
+});
+
+def_transform(AST_Object, function(self, tw) {
+    self.properties = MAP(self.properties, tw);
+});
+
+def_transform(AST_ObjectProperty, function(self, tw) {
+    if (self.key instanceof AST_Node) {
+        self.key = self.key.transform(tw);
+    }
+    if (self.value) self.value = self.value.transform(tw);
+});
+
+def_transform(AST_Class, function(self, tw) {
+    if (self.name) self.name = self.name.transform(tw);
+    if (self.extends) self.extends = self.extends.transform(tw);
+    self.properties = MAP(self.properties, tw);
+});
+
+def_transform(AST_ClassStaticBlock, function(self, tw) {
+    self.body = MAP(self.body, tw);
+});
+
+def_transform(AST_Expansion, function(self, tw) {
+    self.expression = self.expression.transform(tw);
+});
+
+def_transform(AST_NameMapping, function(self, tw) {
+    self.foreign_name = self.foreign_name.transform(tw);
+    self.name = self.name.transform(tw);
+});
+
+def_transform(AST_Import, function(self, tw) {
+    if (self.imported_name) self.imported_name = self.imported_name.transform(tw);
+    if (self.imported_names) MAP(self.imported_names, tw);
+    self.module_name = self.module_name.transform(tw);
+});
+
+def_transform(AST_Export, function(self, tw) {
+    if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw);
+    if (self.exported_value) self.exported_value = self.exported_value.transform(tw);
+    if (self.exported_names) MAP(self.exported_names, tw);
+    if (self.module_name) self.module_name = self.module_name.transform(tw);
+});
+
+def_transform(AST_TemplateString, function(self, tw) {
+    self.segments = MAP(self.segments, tw);
+});
+
+def_transform(AST_PrefixedTemplateString, function(self, tw) {
+    self.prefix = self.prefix.transform(tw);
+    self.template_string = self.template_string.transform(tw);
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+(function() {
+
+    var normalize_directives = function(body) {
+        for (var i = 0; i < body.length; i++) {
+            if (body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
+                body[i] = new AST_Directive({
+                    start: body[i].start,
+                    end: body[i].end,
+                    quote: '"',
+                    value: body[i].body.value
+                });
+            } else {
+                return body;
+            }
+        }
+
+        return body;
+    };
+
+    function import_attributes_from_moz(attributes) {
+        if (attributes && attributes.length > 0) {
+            return new AST_Object({
+                start: my_start_token(attributes),
+                end: my_end_token(attributes),
+                properties: attributes.map((attr) =>
+                    new AST_ObjectKeyVal({
+                        start: my_start_token(attr),
+                        end: my_end_token(attr),
+                        key: attr.key.name || attr.key.value,
+                        value: from_moz(attr.value)
+                    })
+                )
+            });
+        }
+        return null;
+    }
+
+    var MOZ_TO_ME = {
+        Program: function(M) {
+            return new AST_Toplevel({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                body: normalize_directives(M.body.map(from_moz))
+            });
+        },
+
+        ArrayPattern: function(M) {
+            return new AST_Destructuring({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                names: M.elements.map(function(elm) {
+                    if (elm === null) {
+                        return new AST_Hole();
+                    }
+                    return from_moz(elm);
+                }),
+                is_array: true
+            });
+        },
+
+        ObjectPattern: function(M) {
+            return new AST_Destructuring({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                names: M.properties.map(from_moz),
+                is_array: false
+            });
+        },
+
+        AssignmentPattern: function(M) {
+            return new AST_DefaultAssign({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                left: from_moz(M.left),
+                operator: "=",
+                right: from_moz(M.right)
+            });
+        },
+
+        SpreadElement: function(M) {
+            return new AST_Expansion({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.argument)
+            });
+        },
+
+        RestElement: function(M) {
+            return new AST_Expansion({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.argument)
+            });
+        },
+
+        TemplateElement: function(M) {
+            return new AST_TemplateSegment({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                value: M.value.cooked,
+                raw: M.value.raw
+            });
+        },
+
+        TemplateLiteral: function(M) {
+            var segments = [];
+            for (var i = 0; i < M.quasis.length; i++) {
+                segments.push(from_moz(M.quasis[i]));
+                if (M.expressions[i]) {
+                    segments.push(from_moz(M.expressions[i]));
+                }
+            }
+            return new AST_TemplateString({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                segments: segments
+            });
+        },
+
+        TaggedTemplateExpression: function(M) {
+            return new AST_PrefixedTemplateString({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                template_string: from_moz(M.quasi),
+                prefix: from_moz(M.tag)
+            });
+        },
+
+        FunctionDeclaration: function(M) {
+            return new AST_Defun({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                name: M.id && from_moz_symbol(AST_SymbolDefun, M.id),
+                argnames: M.params.map(M => from_moz_pattern(M, AST_SymbolFunarg)),
+                is_generator: M.generator,
+                async: M.async,
+                body: normalize_directives(from_moz(M.body).body)
+            });
+        },
+
+        FunctionExpression: function(M) {
+            return from_moz_lambda(M, /*is_method=*/false);
+        },
+
+        ArrowFunctionExpression: function(M) {
+            const body = M.body.type === "BlockStatement"
+                ? from_moz(M.body).body
+                : [make_node(AST_Return, {}, { value: from_moz(M.body) })];
+            return new AST_Arrow({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                argnames: M.params.map(p => from_moz_pattern(p, AST_SymbolFunarg)),
+                body,
+                async: M.async,
+            });
+        },
+
+        ExpressionStatement: function(M) {
+            return new AST_SimpleStatement({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                body: from_moz(M.expression)
+            });
+        },
+
+        TryStatement: function(M) {
+            var handlers = M.handlers || [M.handler];
+            if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
+                throw new Error("Multiple catch clauses are not supported.");
+            }
+            return new AST_Try({
+                start    : my_start_token(M),
+                end      : my_end_token(M),
+                body     : new AST_TryBlock(from_moz(M.block)),
+                bcatch   : from_moz(handlers[0]),
+                bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
+            });
+        },
+
+        Property: function(M) {
+            if (M.kind == "init" && !M.method) {
+                var args = {
+                    start    : my_start_token(M.key || M.value),
+                    end      : my_end_token(M.value),
+                    key      : M.computed
+                                ? from_moz(M.key)
+                                : M.key.name || String(M.key.value),
+                    quote    : from_moz_quote(M.key, M.computed),
+                    static   : false, // always an object
+                    value    : from_moz(M.value)
+                };
+
+                return new AST_ObjectKeyVal(args);
+            } else {
+                var value = from_moz_lambda(M.value, /*is_method=*/true);
+                var args = {
+                    start    : my_start_token(M.key || M.value),
+                    end      : my_end_token(M.value),
+                    key      : M.computed
+                                ? from_moz(M.key)
+                                : from_moz_symbol(AST_SymbolMethod, M.key),
+                    quote    : from_moz_quote(M.key, M.computed),
+                    static   : false, // always an object
+                    value,
+                };
+
+                if (M.kind == "get") return new AST_ObjectGetter(args);
+                if (M.kind == "set") return new AST_ObjectSetter(args);
+                if (M.method) return new AST_ConciseMethod(args);
+            }
+        },
+
+        MethodDefinition: function(M) {
+            const is_private = M.key.type === "PrivateIdentifier";
+            const key = M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || String(M.key.value) });
+
+            var args = {
+                start    : my_start_token(M),
+                end      : my_end_token(M),
+                key,
+                quote    : from_moz_quote(M.key, M.computed),
+                value    : from_moz_lambda(M.value, /*is_method=*/true),
+                static   : M.static,
+            };
+            if (M.kind == "get") {
+                return new (is_private ? AST_PrivateGetter : AST_ObjectGetter)(args);
+            }
+            if (M.kind == "set") {
+                return new (is_private ? AST_PrivateSetter : AST_ObjectSetter)(args);
+            }
+            return new (is_private ? AST_PrivateMethod : AST_ConciseMethod)(args);
+        },
+
+        FieldDefinition: function(M) {
+            let key;
+            if (M.computed) {
+                key = from_moz(M.key);
+            } else {
+                if (M.key.type !== "Identifier") throw new Error("Non-Identifier key in FieldDefinition");
+                key = from_moz(M.key);
+            }
+            return new AST_ClassProperty({
+                start    : my_start_token(M),
+                end      : my_end_token(M),
+                quote    : from_moz_quote(M.key, M.computed),
+                key,
+                value    : from_moz(M.value),
+                static   : M.static,
+            });
+        },
+
+        PropertyDefinition: function(M) {
+            let key;
+            if (M.computed) {
+                key = from_moz(M.key);
+            } else if (M.key.type === "PrivateIdentifier") {
+                return new AST_ClassPrivateProperty({
+                    start    : my_start_token(M),
+                    end      : my_end_token(M),
+                    key      : from_moz(M.key),
+                    value    : from_moz(M.value),
+                    static   : M.static,
+                });
+            } else {
+                key = from_moz_symbol(AST_SymbolClassProperty, M.key);
+            }
+
+            return new AST_ClassProperty({
+                start    : my_start_token(M),
+                end      : my_end_token(M),
+                quote    : from_moz_quote(M.key, M.computed),
+                key,
+                value    : from_moz(M.value),
+                static   : M.static,
+            });
+        },
+
+        PrivateIdentifier: function (M) {
+            return new AST_SymbolPrivateProperty({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                name: M.name
+            });
+        },
+
+        StaticBlock: function(M) {
+            return new AST_ClassStaticBlock({
+                start : my_start_token(M),
+                end   : my_end_token(M),
+                body  : M.body.map(from_moz),
+            });
+        },
+
+        ArrayExpression: function(M) {
+            return new AST_Array({
+                start    : my_start_token(M),
+                end      : my_end_token(M),
+                elements : M.elements.map(function(elem) {
+                    return elem === null ? new AST_Hole() : from_moz(elem);
+                })
+            });
+        },
+
+        ObjectExpression: function(M) {
+            return new AST_Object({
+                start      : my_start_token(M),
+                end        : my_end_token(M),
+                properties : M.properties.map(function(prop) {
+                    if (prop.type === "SpreadElement") {
+                        return from_moz(prop);
+                    }
+                    prop.type = "Property";
+                    return from_moz(prop);
+                })
+            });
+        },
+
+        SequenceExpression: function(M) {
+            return new AST_Sequence({
+                start      : my_start_token(M),
+                end        : my_end_token(M),
+                expressions: M.expressions.map(from_moz)
+            });
+        },
+
+        MemberExpression: function(M) {
+            if (M.property.type === "PrivateIdentifier") {
+                return new AST_DotHash({
+                    start      : my_start_token(M),
+                    end        : my_end_token(M),
+                    property   : M.property.name,
+                    expression : from_moz(M.object),
+                    optional   : M.optional || false
+                });
+            }
+            return new (M.computed ? AST_Sub : AST_Dot)({
+                start      : my_start_token(M),
+                end        : my_end_token(M),
+                property   : M.computed ? from_moz(M.property) : M.property.name,
+                expression : from_moz(M.object),
+                optional   : M.optional || false
+            });
+        },
+
+        ChainExpression: function(M) {
+            return new AST_Chain({
+                start      : my_start_token(M),
+                end        : my_end_token(M),
+                expression : from_moz(M.expression)
+            });
+        },
+
+        SwitchCase: function(M) {
+            return new (M.test ? AST_Case : AST_Default)({
+                start      : my_start_token(M),
+                end        : my_end_token(M),
+                expression : from_moz(M.test),
+                body       : M.consequent.map(from_moz)
+            });
+        },
+
+        VariableDeclaration: function(M) {
+            let decl_type;
+            let defs_type = AST_VarDef;
+            let sym_type;
+            let await_using = false;
+            if (M.kind === "const") {
+                decl_type = AST_Const;
+                sym_type = AST_SymbolConst;
+            } else if (M.kind === "let") {
+                decl_type = AST_Let;
+                sym_type = AST_SymbolLet;
+            } else if (M.kind === "using") {
+                decl_type = AST_Using;
+                defs_type = AST_UsingDef;
+                sym_type = AST_SymbolUsing;
+            } else if (M.kind === "await using") {
+                decl_type = AST_Using;
+                defs_type = AST_UsingDef;
+                sym_type = AST_SymbolUsing;
+                await_using = true;
+            } else {
+                decl_type = AST_Var;
+                sym_type = AST_SymbolVar;
+            }
+            const definitions = M.declarations.map(M => {
+                return new defs_type({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    name: from_moz_pattern(M.id, sym_type),
+                    value: from_moz(M.init),
+                });
+            });
+            return new decl_type({
+                start       : my_start_token(M),
+                end         : my_end_token(M),
+                definitions : definitions,
+                await       : await_using,
+            });
+        },
+
+        ImportDeclaration: function(M) {
+            var imported_name = null;
+            var imported_names = null;
+            M.specifiers.forEach(function (specifier) {
+                if (specifier.type === "ImportSpecifier" || specifier.type === "ImportNamespaceSpecifier") {
+                    if (!imported_names) { imported_names = []; }
+                    imported_names.push(from_moz(specifier));
+                } else if (specifier.type === "ImportDefaultSpecifier") {
+                    imported_name = from_moz(specifier);
+                }
+            });
+            return new AST_Import({
+                start       : my_start_token(M),
+                end         : my_end_token(M),
+                imported_name: imported_name,
+                imported_names : imported_names,
+                module_name : from_moz(M.source),
+                attributes: import_attributes_from_moz(M.attributes || M.assertions),
+                phase: M.phase || null
+            });
+        },
+
+        ImportSpecifier: function(M) {
+            return new AST_NameMapping({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                foreign_name: from_moz_symbol(AST_SymbolImportForeign, M.imported, M.imported.type === "Literal"),
+                name: from_moz_symbol(AST_SymbolImport, M.local)
+            });
+        },
+
+        ImportDefaultSpecifier: function(M) {
+            return from_moz_symbol(AST_SymbolImport, M.local);
+        },
+
+        ImportNamespaceSpecifier: function(M) {
+            return new AST_NameMapping({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                foreign_name: new AST_SymbolImportForeign({ name: "*" }),
+                name: from_moz_symbol(AST_SymbolImport, M.local)
+            });
+        },
+
+        ImportExpression: function(M) {
+            const args = [from_moz(M.source)];
+            if (M.options) {
+                args.push(from_moz(M.options));
+            }
+            if (M.phase) {
+                return new AST_DynamicImport({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    phase: M.phase,
+                    args: args
+                });
+            }
+            return new AST_Call({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz({
+                    type: "Identifier",
+                    name: "import"
+                }),
+                optional: false,
+                args
+            });
+        },
+
+        ExportAllDeclaration: function(M) {
+            var foreign_name = M.exported == null ?
+                new AST_SymbolExportForeign({ name: "*" }) :
+                from_moz_symbol(AST_SymbolExportForeign, M.exported, M.exported.type === "Literal");
+            return new AST_Export({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                exported_names: [
+                    new AST_NameMapping({
+                        start: my_start_token(M),
+                        end: my_end_token(M),
+                        name: new AST_SymbolExport({ name: "*" }),
+                        foreign_name: foreign_name
+                    })
+                ],
+                module_name: from_moz(M.source),
+                attributes: import_attributes_from_moz(M.attributes || M.assertions)
+            });
+        },
+
+        ExportNamedDeclaration: function(M) {
+            if (M.declaration) {
+                // export const, export function, ...
+                return new AST_Export({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    exported_definition: from_moz(M.declaration),
+                    exported_names: null,
+                    module_name: null,
+                    attributes: null,
+                });
+            } else {
+                return new AST_Export({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    exported_definition: null,
+                    exported_names: M.specifiers && M.specifiers.length ? M.specifiers.map(from_moz) : [],
+                    module_name: from_moz(M.source),
+                    attributes: import_attributes_from_moz(M.attributes || M.assertions),
+                });
+            }
+        },
+
+        ExportDefaultDeclaration: function(M) {
+            return new AST_Export({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                exported_value: from_moz(M.declaration),
+                is_default: true
+            });
+        },
+
+        ExportSpecifier: function(M) {
+            return new AST_NameMapping({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                foreign_name: from_moz_symbol(AST_SymbolExportForeign, M.exported, M.exported.type === "Literal"),
+                name: from_moz_symbol(AST_SymbolExport, M.local, M.local.type === "Literal"),
+            });
+        },
+
+        Literal: function(M) {
+            var val = M.value, args = {
+                start  : my_start_token(M),
+                end    : my_end_token(M)
+            };
+            var rx = M.regex;
+            if (rx && rx.pattern) {
+                // RegExpLiteral as per ESTree AST spec
+                args.value = {
+                    source: rx.pattern,
+                    flags: rx.flags
+                };
+                return new AST_RegExp(args);
+            } else if (rx) {
+                // support legacy RegExp
+                const rx_source = M.raw || val;
+                const match = rx_source.match(/^\/(.*)\/(\w*)$/);
+                if (!match) throw new Error("Invalid regex source " + rx_source);
+                const [_, source, flags] = match;
+                args.value = { source, flags };
+                return new AST_RegExp(args);
+            }
+            const bi = typeof M.value === "bigint" ? M.value.toString() : M.bigint;
+            if (typeof bi === "string") {
+                args.value = bi;
+                args.raw = M.raw;
+                return new AST_BigInt(args);
+            }
+            if (val === null) return new AST_Null(args);
+            switch (typeof val) {
+              case "string":
+                args.quote = "\"";
+                args.value = val;
+                return new AST_String(args);
+              case "number":
+                args.value = val;
+                args.raw = M.raw || val.toString();
+                return new AST_Number(args);
+              case "boolean":
+                return new (val ? AST_True : AST_False)(args);
+            }
+        },
+
+        MetaProperty: function(M) {
+            if (M.meta.name === "new" && M.property.name === "target") {
+                return new AST_NewTarget({
+                    start: my_start_token(M),
+                    end: my_end_token(M)
+                });
+            } else if (M.meta.name === "import" && M.property.name === "meta") {
+                return new AST_ImportMeta({
+                    start: my_start_token(M),
+                    end: my_end_token(M)
+                });
+            }
+        },
+
+        Identifier: function(M) {
+            return new AST_SymbolRef({
+                start : my_start_token(M),
+                end   : my_end_token(M),
+                name  : M.name
+            });
+        },
+
+        EmptyStatement: function(M) {
+            return new AST_EmptyStatement({
+                start: my_start_token(M),
+                end: my_end_token(M)
+            });
+        },
+
+        BlockStatement: function(M) {
+            return new AST_BlockStatement({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                body: M.body.map(from_moz)
+            });
+        },
+
+        IfStatement: function(M) {
+            return new AST_If({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                condition: from_moz(M.test),
+                body: from_moz(M.consequent),
+                alternative: from_moz(M.alternate)
+            });
+        },
+
+        LabeledStatement: function(M) {
+            try {
+                const label = from_moz_symbol(AST_Label, M.label);
+                FROM_MOZ_LABELS.push(label);
+
+                const stat = new AST_LabeledStatement({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    label,
+                    body: from_moz(M.body)
+                });
+
+                return stat;
+            } finally {
+                FROM_MOZ_LABELS.pop();
+            }
+        },
+
+        BreakStatement: function(M) {
+            return new AST_Break({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                label: from_moz_label_ref(M.label),
+            });
+        },
+
+        ContinueStatement: function(M) {
+            return new AST_Continue({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                label: from_moz_label_ref(M.label),
+            });
+        },
+
+        WithStatement: function(M) {
+            return new AST_With({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.object),
+                body: from_moz(M.body)
+            });
+        },
+
+        SwitchStatement: function(M) {
+            return new AST_Switch({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.discriminant),
+                body: M.cases.map(from_moz)
+            });
+        },
+
+        ReturnStatement: function(M) {
+            return new AST_Return({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                value: from_moz(M.argument)
+            });
+        },
+
+        ThrowStatement: function(M) {
+            return new AST_Throw({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                value: from_moz(M.argument)
+            });
+        },
+
+        WhileStatement: function(M) {
+            return new AST_While({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                condition: from_moz(M.test),
+                body: from_moz(M.body)
+            });
+        },
+
+        DoWhileStatement: function(M) {
+            return new AST_Do({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                condition: from_moz(M.test),
+                body: from_moz(M.body)
+            });
+        },
+
+        ForStatement: function(M) {
+            return new AST_For({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                init: from_moz(M.init),
+                condition: from_moz(M.test),
+                step: from_moz(M.update),
+                body: from_moz(M.body)
+            });
+        },
+
+        ForInStatement: function(M) {
+            return new AST_ForIn({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                init: from_moz(M.left),
+                object: from_moz(M.right),
+                body: from_moz(M.body)
+            });
+        },
+
+        ForOfStatement: function(M) {
+            return new AST_ForOf({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                init: from_moz(M.left),
+                object: from_moz(M.right),
+                body: from_moz(M.body),
+                await: M.await
+            });
+        },
+
+        AwaitExpression: function(M) {
+            return new AST_Await({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.argument)
+            });
+        },
+
+        YieldExpression: function(M) {
+            return new AST_Yield({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.argument),
+                is_star: M.delegate
+            });
+        },
+
+        DebuggerStatement: function(M) {
+            return new AST_Debugger({
+                start: my_start_token(M),
+                end: my_end_token(M)
+            });
+        },
+
+        CatchClause: function(M) {
+            return new AST_Catch({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                argname: M.param ? from_moz_pattern(M.param, AST_SymbolCatch) : null,
+                body: from_moz(M.body).body
+            });
+        },
+
+        ThisExpression: function(M) {
+            return new AST_This({
+                start: my_start_token(M),
+                name: "this",
+                end: my_end_token(M)
+            });
+        },
+
+        Super: function(M) {
+            return new AST_Super({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                name: "super",
+            });
+        },
+
+        BinaryExpression: function(M) {
+            if (M.left.type === "PrivateIdentifier") {
+                return new AST_PrivateIn({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    key: new AST_SymbolPrivateProperty({
+                        start: my_start_token(M.left),
+                        end: my_end_token(M.left),
+                        name: M.left.name
+                    }),
+                    value: from_moz(M.right),
+                });
+            }
+            return new AST_Binary({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                operator: M.operator,
+                left: from_moz(M.left),
+                right: from_moz(M.right)
+            });
+        },
+
+        LogicalExpression: function(M) {
+            return new AST_Binary({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                operator: M.operator,
+                left: from_moz(M.left),
+                right: from_moz(M.right)
+            });
+        },
+
+        AssignmentExpression: function(M) {
+            return new AST_Assign({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                operator: M.operator,
+                logical: M.operator === "??=" || M.operator === "&&=" || M.operator === "||=",
+                left: from_moz(M.left),
+                right: from_moz(M.right)
+            });
+        },
+
+        ConditionalExpression: function(M) {
+            return new AST_Conditional({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                condition: from_moz(M.test),
+                consequent: from_moz(M.consequent),
+                alternative: from_moz(M.alternate)
+            });
+        },
+
+        NewExpression: function(M) {
+            return new AST_New({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.callee),
+                args: M.arguments.map(from_moz)
+            });
+        },
+
+        CallExpression: function(M) {
+            return new AST_Call({
+                start: my_start_token(M),
+                end: my_end_token(M),
+                expression: from_moz(M.callee),
+                optional: M.optional,
+                args: M.arguments.map(from_moz)
+            });
+        }
+    };
+
+    MOZ_TO_ME.UpdateExpression =
+    MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
+        var prefix = "prefix" in M ? M.prefix
+            : M.type == "UnaryExpression" ? true : false;
+        return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
+            start      : my_start_token(M),
+            end        : my_end_token(M),
+            operator   : M.operator,
+            expression : from_moz(M.argument)
+        });
+    };
+
+    MOZ_TO_ME.ClassDeclaration =
+    MOZ_TO_ME.ClassExpression = function From_Moz_Class(M) {
+        return new (M.type === "ClassDeclaration" ? AST_DefClass : AST_ClassExpression)({
+            start    : my_start_token(M),
+            end      : my_end_token(M),
+            name     : M.id && from_moz_symbol(M.type === "ClassDeclaration" ? AST_SymbolDefClass : AST_SymbolClass, M.id),
+            extends  : from_moz(M.superClass),
+            properties: M.body.body.map(from_moz)
+        });
+    };
+
+    def_to_moz(AST_EmptyStatement, function To_Moz_EmptyStatement() {
+        return {
+            type: "EmptyStatement"
+        };
+    });
+    def_to_moz(AST_BlockStatement, function To_Moz_BlockStatement(M) {
+        return {
+            type: "BlockStatement",
+            body: M.body.map(to_moz)
+        };
+    });
+    def_to_moz(AST_If, function To_Moz_IfStatement(M) {
+        return {
+            type: "IfStatement",
+            test: to_moz(M.condition),
+            consequent: to_moz(M.body),
+            alternate: to_moz(M.alternative)
+        };
+    });
+    def_to_moz(AST_LabeledStatement, function To_Moz_LabeledStatement(M) {
+        return {
+            type: "LabeledStatement",
+            label: to_moz(M.label),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_Break, function To_Moz_BreakStatement(M) {
+        return {
+            type: "BreakStatement",
+            label: to_moz(M.label)
+        };
+    });
+    def_to_moz(AST_Continue, function To_Moz_ContinueStatement(M) {
+        return {
+            type: "ContinueStatement",
+            label: to_moz(M.label)
+        };
+    });
+    def_to_moz(AST_With, function To_Moz_WithStatement(M) {
+        return {
+            type: "WithStatement",
+            object: to_moz(M.expression),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_Switch, function To_Moz_SwitchStatement(M) {
+        return {
+            type: "SwitchStatement",
+            discriminant: to_moz(M.expression),
+            cases: M.body.map(to_moz)
+        };
+    });
+    def_to_moz(AST_Return, function To_Moz_ReturnStatement(M) {
+        return {
+            type: "ReturnStatement",
+            argument: to_moz(M.value)
+        };
+    });
+    def_to_moz(AST_Throw, function To_Moz_ThrowStatement(M) {
+        return {
+            type: "ThrowStatement",
+            argument: to_moz(M.value)
+        };
+    });
+    def_to_moz(AST_While, function To_Moz_WhileStatement(M) {
+        return {
+            type: "WhileStatement",
+            test: to_moz(M.condition),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_Do, function To_Moz_DoWhileStatement(M) {
+        return {
+            type: "DoWhileStatement",
+            test: to_moz(M.condition),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_For, function To_Moz_ForStatement(M) {
+        return {
+            type: "ForStatement",
+            init: to_moz(M.init),
+            test: to_moz(M.condition),
+            update: to_moz(M.step),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_ForIn, function To_Moz_ForInStatement(M) {
+        return {
+            type: "ForInStatement",
+            left: to_moz(M.init),
+            right: to_moz(M.object),
+            body: to_moz(M.body)
+        };
+    });
+    def_to_moz(AST_ForOf, function To_Moz_ForOfStatement(M) {
+        return {
+            type: "ForOfStatement",
+            left: to_moz(M.init),
+            right: to_moz(M.object),
+            body: to_moz(M.body),
+            await: M.await
+        };
+    });
+    def_to_moz(AST_Await, function To_Moz_AwaitExpression(M) {
+        return {
+            type: "AwaitExpression",
+            argument: to_moz(M.expression)
+        };
+    });
+    def_to_moz(AST_Yield, function To_Moz_YieldExpression(M) {
+        return {
+            type: "YieldExpression",
+            argument: to_moz(M.expression),
+            delegate: M.is_star
+        };
+    });
+    def_to_moz(AST_Debugger, function To_Moz_DebuggerStatement() {
+        return {
+            type: "DebuggerStatement"
+        };
+    });
+    def_to_moz(AST_VarDefLike, function To_Moz_VariableDeclarator(M) {
+        return {
+            type: "VariableDeclarator",
+            id: to_moz(M.name),
+            init: to_moz(M.value)
+        };
+    });
+
+    def_to_moz(AST_This, function To_Moz_ThisExpression() {
+        return {
+            type: "ThisExpression"
+        };
+    });
+    def_to_moz(AST_Super, function To_Moz_Super() {
+        return {
+            type: "Super"
+        };
+    });
+    def_to_moz(AST_Conditional, function To_Moz_ConditionalExpression(M) {
+        return {
+            type: "ConditionalExpression",
+            test: to_moz(M.condition),
+            consequent: to_moz(M.consequent),
+            alternate: to_moz(M.alternative)
+        };
+    });
+    def_to_moz(AST_New, function To_Moz_NewExpression(M) {
+        return {
+            type: "NewExpression",
+            callee: to_moz(M.expression),
+            arguments: M.args.map(to_moz)
+        };
+    });
+    def_to_moz(AST_Call, function To_Moz_CallExpression(M) {
+        if (M.expression instanceof AST_SymbolRef && M.expression.name === "import") {
+            const [source, options] = M.args.map(to_moz);
+            return {
+                type: "ImportExpression",
+                source,
+                options: options || null
+            };
+        }
+
+        return {
+            type: "CallExpression",
+            callee: to_moz(M.expression),
+            optional: M.optional,
+            arguments: M.args.map(to_moz)
+        };
+    });
+
+    def_to_moz(AST_DynamicImport, function To_Moz_ImportExpression(M) {
+        const [source, options] = M.args.map(to_moz);
+        return {
+            type: "ImportExpression",
+            source,
+            options: options || null,
+            phase: M.phase
+        };
+    });
+
+    def_to_moz(AST_Toplevel, function To_Moz_Program(M) {
+        return to_moz_scope("Program", M);
+    });
+
+    def_to_moz(AST_Expansion, function To_Moz_Spread(M) {
+        return {
+            type: to_moz_in_destructuring() ? "RestElement" : "SpreadElement",
+            argument: to_moz(M.expression)
+        };
+    });
+
+    def_to_moz(AST_PrefixedTemplateString, function To_Moz_TaggedTemplateExpression(M) {
+        return {
+            type: "TaggedTemplateExpression",
+            tag: to_moz(M.prefix),
+            quasi: to_moz(M.template_string)
+        };
+    });
+
+    def_to_moz(AST_TemplateString, function To_Moz_TemplateLiteral(M) {
+        var quasis = [];
+        var expressions = [];
+        for (var i = 0; i < M.segments.length; i++) {
+            if (i % 2 !== 0) {
+                expressions.push(to_moz(M.segments[i]));
+            } else {
+                quasis.push({
+                    type: "TemplateElement",
+                    value: {
+                        raw: M.segments[i].raw,
+                        cooked: M.segments[i].value
+                    },
+                    tail: i === M.segments.length - 1
+                });
+            }
+        }
+        return {
+            type: "TemplateLiteral",
+            quasis: quasis,
+            expressions: expressions
+        };
+    });
+
+    def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
+        return {
+            type: "FunctionDeclaration",
+            id: to_moz(M.name),
+            params: M.argnames.map(to_moz_pattern),
+            generator: M.is_generator,
+            async: M.async,
+            body: to_moz_scope("BlockStatement", M)
+        };
+    });
+
+    def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) {
+        return {
+            type: "FunctionExpression",
+            id: to_moz(M.name),
+            params: M.argnames.map(to_moz_pattern),
+            generator: M.is_generator || false,
+            async: M.async || false,
+            body: to_moz_scope("BlockStatement", M)
+        };
+    });
+
+    def_to_moz(AST_Arrow, function To_Moz_ArrowFunctionExpression(M) {
+        var body = M.body.length === 1 && M.body[0] instanceof AST_Return && M.body[0].value
+            ? to_moz(M.body[0].value)
+            : {
+                type: "BlockStatement",
+                body: M.body.map(to_moz)
+            };
+        return {
+            type: "ArrowFunctionExpression",
+            params: M.argnames.map(to_moz_pattern),
+            async: M.async,
+            body: body,
+        };
+    });
+
+    def_to_moz(AST_Destructuring, function To_Moz_ObjectPattern(M) {
+        if (M.is_array) {
+            return {
+                type: "ArrayPattern",
+                elements: M.names.map(
+                    M => M instanceof AST_Hole ? null : to_moz_pattern(M)
+                ),
+            };
+        }
+        return {
+            type: "ObjectPattern",
+            properties: M.names.map(M => {
+                if (M instanceof AST_ObjectKeyVal) {
+                    var computed = M.computed_key();
+                    const [shorthand, key] = to_moz_property_key(M.key, computed, M.quote, M.value);
+
+                    return {
+                        type: "Property",
+                        computed,
+                        kind: "init",
+                        key: key,
+                        method: false,
+                        shorthand,
+                        value: to_moz_pattern(M.value)
+                    };
+                } else {
+                    return to_moz_pattern(M);
+                }
+            }),
+        };
+    });
+
+    def_to_moz(AST_DefaultAssign, function To_Moz_AssignmentExpression(M) {
+        return {
+            type: "AssignmentPattern",
+            left: to_moz_pattern(M.left),
+            right: to_moz(M.right),
+        };
+    });
+
+    def_to_moz(AST_Directive, function To_Moz_Directive(M) {
+        return {
+            type: "ExpressionStatement",
+            expression: {
+                type: "Literal",
+                value: M.value,
+                raw: M.print_to_string()
+            },
+            directive: M.value
+        };
+    });
+
+    def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) {
+        return {
+            type: "ExpressionStatement",
+            expression: to_moz(M.body)
+        };
+    });
+
+    def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
+        return {
+            type: "SwitchCase",
+            test: to_moz(M.expression),
+            consequent: M.body.map(to_moz)
+        };
+    });
+
+    def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
+        return {
+            type: "TryStatement",
+            block: to_moz_block(M.body),
+            handler: to_moz(M.bcatch),
+            guardedHandlers: [],
+            finalizer: to_moz(M.bfinally)
+        };
+    });
+
+    def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
+        return {
+            type: "CatchClause",
+            param: M.argname != null ? to_moz_pattern(M.argname) : null,
+            body: to_moz_block(M)
+        };
+    });
+
+    def_to_moz(AST_DefinitionsLike, function To_Moz_VariableDeclaration(M) {
+        return {
+            type: "VariableDeclaration",
+            kind:
+                M instanceof AST_Const ? "const" :
+                M instanceof AST_Let ? "let" :
+                M instanceof AST_Using ? (M.await ? "await using" : "using") :
+                "var",
+            declarations: M.definitions.map(to_moz)
+        };
+    });
+
+    function import_attributes_to_moz(attribute) {
+        const import_attributes = [];
+        if (attribute) {
+            for (const { key, value } of attribute.properties) {
+                const key_moz = is_basic_identifier_string(key)
+                    ? { type: "Identifier", name: key }
+                    : { type: "Literal", value: key, raw: JSON.stringify(key) };
+                import_attributes.push({
+                    type: "ImportAttribute",
+                    key: key_moz,
+                    value: to_moz(value)
+                });
+            }
+        }
+        return import_attributes;
+    }
+
+    def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) {
+        if (M.exported_names) {
+            var first_exported = M.exported_names[0];
+            if (first_exported && first_exported.name.name === "*" && !first_exported.name.quote) {
+                var foreign_name = first_exported.foreign_name;
+                var exported = foreign_name.name === "*" && !foreign_name.quote
+                    ? null
+                    : to_moz(foreign_name);
+                return {
+                    type: "ExportAllDeclaration",
+                    source: to_moz(M.module_name),
+                    exported: exported,
+                    attributes: import_attributes_to_moz(M.attributes)
+                };
+            }
+            return {
+                type: "ExportNamedDeclaration",
+                specifiers: M.exported_names.map(function (name_mapping) {
+                    return {
+                        type: "ExportSpecifier",
+                        exported: to_moz(name_mapping.foreign_name),
+                        local: to_moz(name_mapping.name)
+                    };
+                }),
+                declaration: to_moz(M.exported_definition),
+                source: to_moz(M.module_name),
+                attributes: import_attributes_to_moz(M.attributes)
+            };
+        }
+
+        if (M.is_default) {
+            return {
+                type: "ExportDefaultDeclaration",
+                declaration: to_moz(M.exported_value || M.exported_definition),
+            };
+        } else {
+            return {
+                type: "ExportNamedDeclaration",
+                declaration: to_moz(M.exported_value || M.exported_definition),
+                specifiers: [],
+                source: null,
+            };
+        }
+    });
+
+    def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) {
+        var specifiers = [];
+        if (M.imported_name) {
+            specifiers.push({
+                type: "ImportDefaultSpecifier",
+                local: to_moz(M.imported_name)
+            });
+        }
+        if (M.imported_names) {
+            var first_imported_foreign_name = M.imported_names[0].foreign_name;
+            if (first_imported_foreign_name.name === "*" && !first_imported_foreign_name.quote) {
+                specifiers.push({
+                    type: "ImportNamespaceSpecifier",
+                    local: to_moz(M.imported_names[0].name)
+                });
+            } else {
+                M.imported_names.forEach(function(name_mapping) {
+                    specifiers.push({
+                        type: "ImportSpecifier",
+                        local: to_moz(name_mapping.name),
+                        imported: to_moz(name_mapping.foreign_name)
+                    });
+                });
+            }
+        }
+        var moz = {
+            type: "ImportDeclaration",
+            specifiers: specifiers,
+            source: to_moz(M.module_name),
+            attributes: import_attributes_to_moz(M.attributes)
+        };
+        if (M.phase) moz.phase = M.phase;
+        return moz;
+    });
+
+    def_to_moz(AST_ImportMeta, function To_Moz_MetaProperty() {
+        return {
+            type: "MetaProperty",
+            meta: {
+                type: "Identifier",
+                name: "import"
+            },
+            property: {
+                type: "Identifier",
+                name: "meta"
+            }
+        };
+    });
+
+    def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
+        return {
+            type: "SequenceExpression",
+            expressions: M.expressions.map(to_moz)
+        };
+    });
+
+    def_to_moz(AST_DotHash, function To_Moz_PrivateMemberExpression(M) {
+        return {
+            type: "MemberExpression",
+            object: to_moz(M.expression),
+            computed: false,
+            property: {
+                type: "PrivateIdentifier",
+                name: M.property
+            },
+            optional: M.optional
+        };
+    });
+
+    def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
+        var isComputed = M instanceof AST_Sub;
+        return {
+            type: "MemberExpression",
+            object: to_moz(M.expression),
+            computed: isComputed,
+            property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property},
+            optional: M.optional
+        };
+    });
+
+    def_to_moz(AST_Chain, function To_Moz_ChainExpression(M) {
+        return {
+            type: "ChainExpression",
+            expression: to_moz(M.expression)
+        };
+    });
+
+    def_to_moz(AST_Unary, function To_Moz_Unary(M) {
+        return {
+            type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
+            operator: M.operator,
+            prefix: M instanceof AST_UnaryPrefix,
+            argument: to_moz(M.expression)
+        };
+    });
+
+    def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
+        if (M.operator == "=" && to_moz_in_destructuring()) {
+            return {
+                type: "AssignmentPattern",
+                left: to_moz(M.left),
+                right: to_moz(M.right)
+            };
+        }
+
+        const type = M.operator == "&&" || M.operator == "||" || M.operator === "??"
+            ? "LogicalExpression"
+            : "BinaryExpression";
+
+        return {
+            type,
+            left: to_moz(M.left),
+            operator: M.operator,
+            right: to_moz(M.right)
+        };
+    });
+
+    def_to_moz(AST_Assign, function To_Moz_AssignmentExpression(M) {
+        return {
+            type: "AssignmentExpression",
+            operator: M.operator,
+            left: to_moz(M.left),
+            right: to_moz(M.right)
+        };
+    });
+
+    def_to_moz(AST_PrivateIn, function To_Moz_BinaryExpression_PrivateIn(M) {
+        return {
+            type: "BinaryExpression",
+            left: { type: "PrivateIdentifier", name: M.key.name },
+            operator: "in",
+            right: to_moz(M.value),
+        };
+    });
+
+    def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
+        return {
+            type: "ArrayExpression",
+            elements: M.elements.map(to_moz)
+        };
+    });
+
+    def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
+        return {
+            type: "ObjectExpression",
+            properties: M.properties.map(to_moz)
+        };
+    });
+
+    def_to_moz(AST_ObjectProperty, function To_Moz_Property(M, parent) {
+        var computed = M.computed_key();
+        const [shorthand, key] = to_moz_property_key(M.key, computed, M.quote, M.value);
+
+        var kind;
+        if (M instanceof AST_ObjectGetter) {
+            kind = "get";
+        } else
+        if (M instanceof AST_ObjectSetter) {
+            kind = "set";
+        }
+        if (M instanceof AST_PrivateGetter || M instanceof AST_PrivateSetter) {
+            const kind = M instanceof AST_PrivateGetter ? "get" : "set";
+            return {
+                type: "MethodDefinition",
+                computed: false,
+                kind: kind,
+                static: M.static,
+                key: {
+                    type: "PrivateIdentifier",
+                    name: M.key.name
+                },
+                value: to_moz(M.value)
+            };
+        }
+        if (M instanceof AST_ClassPrivateProperty) {
+            return {
+                type: "PropertyDefinition",
+                key: {
+                    type: "PrivateIdentifier",
+                    name: M.key.name
+                },
+                value: to_moz(M.value),
+                computed: false,
+                static: M.static
+            };
+        }
+        if (M instanceof AST_ClassProperty) {
+            return {
+                type: "PropertyDefinition",
+                key,
+                value: to_moz(M.value),
+                computed,
+                static: M.static
+            };
+        }
+        if (parent instanceof AST_Class) {
+            return {
+                type: "MethodDefinition",
+                computed: computed,
+                kind: kind,
+                static: M.static,
+                key: to_moz(M.key),
+                value: to_moz(M.value)
+            };
+        }
+        return {
+            type: "Property",
+            computed: computed,
+            method: false,
+            shorthand,
+            kind: kind,
+            key: key,
+            value: to_moz(M.value)
+        };
+    });
+
+    def_to_moz(AST_ObjectKeyVal, function To_Moz_Property(M) {
+        var computed = M.computed_key();
+        const [shorthand, key] = to_moz_property_key(M.key, computed, M.quote, M.value);
+
+        return {
+            type: "Property",
+            computed: computed,
+            shorthand: shorthand,
+            method: false,
+            kind: "init",
+            key: key,
+            value: to_moz(M.value)
+        };
+    });
+
+    def_to_moz(AST_ConciseMethod, function To_Moz_MethodDefinition(M, parent) {
+        const computed = M.computed_key();
+        const [_always_false, key] = to_moz_property_key(M.key, computed, M.quote, M.value);
+
+        if (parent instanceof AST_Object) {
+            return {
+                type: "Property",
+                kind: "init",
+                computed,
+                method: true,
+                shorthand: false,
+                key,
+                value: to_moz(M.value),
+            };
+        }
+
+        return {
+            type: "MethodDefinition",
+            kind: !computed && M.key.name === "constructor" ? "constructor" : "method",
+            computed,
+            key,
+            value: to_moz(M.value),
+            static: M.static,
+        };
+    });
+
+    def_to_moz(AST_PrivateMethod, function To_Moz_MethodDefinition(M) {
+        return {
+            type: "MethodDefinition",
+            kind: "method",
+            key: { type: "PrivateIdentifier", name: M.key.name },
+            value: to_moz(M.value),
+            computed: false,
+            static: M.static,
+        };
+    });
+
+    def_to_moz(AST_Class, function To_Moz_Class(M) {
+        var type = M instanceof AST_ClassExpression ? "ClassExpression" : "ClassDeclaration";
+        return {
+            type: type,
+            superClass: to_moz(M.extends),
+            id: M.name ? to_moz(M.name) : null,
+            body: {
+                type: "ClassBody",
+                body: M.properties.map(to_moz)
+            }
+        };
+    });
+
+    def_to_moz(AST_ClassStaticBlock, function To_Moz_StaticBlock(M) {
+        return {
+            type: "StaticBlock",
+            body: M.body.map(to_moz),
+        };
+    });
+
+    def_to_moz(AST_NewTarget, function To_Moz_MetaProperty() {
+        return {
+            type: "MetaProperty",
+            meta: {
+                type: "Identifier",
+                name: "new"
+            },
+            property: {
+                type: "Identifier",
+                name: "target"
+            }
+        };
+    });
+
+    def_to_moz(AST_Symbol, function To_Moz_Identifier(M, parent) {
+        if (
+            (M instanceof AST_SymbolMethod && parent.quote) ||
+            ((
+                M instanceof AST_SymbolImportForeign ||
+                M instanceof AST_SymbolExportForeign ||
+                M instanceof AST_SymbolExport
+                ) && M.quote)
+         ) {
+            return {
+                type: "Literal",
+                value: M.name
+            };
+        }
+        var def = M.definition();
+        return {
+            type: "Identifier",
+            name: def ? def.mangled_name || def.name : M.name
+        };
+    });
+
+    def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
+        const pattern = M.value.source;
+        const flags = M.value.flags;
+        return {
+            type: "Literal",
+            value: null,
+            raw: M.print_to_string(),
+            regex: { pattern, flags }
+        };
+    });
+
+    def_to_moz(AST_Constant, function To_Moz_Literal(M) {
+        var value = M.value;
+        return {
+            type: "Literal",
+            value: value,
+            raw: M.raw || M.print_to_string()
+        };
+    });
+
+    def_to_moz(AST_Atom, function To_Moz_Atom(M) {
+        return {
+            type: "Identifier",
+            name: String(M.value)
+        };
+    });
+
+    def_to_moz(AST_BigInt, M => ({
+        type: "Literal",
+        // value cannot be represented natively
+        // see: https://github.com/estree/estree/blob/master/es2020.md#bigintliteral
+        value: null,
+        // `M.value` is a string that may be a hex number representation.
+        // but "bigint" property should have only decimal digits
+        bigint: typeof BigInt === "function" ? BigInt(M.value).toString() : M.value,
+        raw: M.raw,
+    }));
+
+    AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
+    AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
+    AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null; });
+
+    AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
+    AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast);
+
+    /* -----[ tools ]----- */
+
+    function my_start_token(moznode) {
+        var loc = moznode.loc, start = loc && loc.start;
+        var range = moznode.range;
+        return new AST_Token(
+            "",
+            "",
+            start && start.line || 0,
+            start && start.column || 0,
+            range ? range [0] : moznode.start,
+            false,
+            [],
+            [],
+            loc && loc.source,
+        );
+    }
+
+    function my_end_token(moznode) {
+        var loc = moznode.loc, end = loc && loc.end;
+        var range = moznode.range;
+        return new AST_Token(
+            "",
+            "",
+            end && end.line || 0,
+            end && end.column || 0,
+            range ? range [0] : moznode.end,
+            false,
+            [],
+            [],
+            loc && loc.source,
+        );
+    }
+
+    var FROM_MOZ_LABELS = null;
+
+    function from_moz(node) {
+        if (node == null) return null;
+        return MOZ_TO_ME[node.type](node);
+    }
+
+    function from_moz_quote(moz_key, computed) {
+        if (!computed && moz_key.type === "Literal" && typeof moz_key.value === "string") {
+            return '"';
+        } else {
+            return "";
+        }
+    }
+
+    function from_moz_symbol(symbol_type, M, has_quote) {
+        return new symbol_type({
+            start: my_start_token(M),
+            quote: has_quote ? '"' : undefined,
+            name: M.type === "Identifier" ? M.name : String(M.value),
+            end: my_end_token(M),
+        });
+    }
+
+    function from_moz_lambda(M, is_method) {
+        return new (is_method ? AST_Accessor : AST_Function)({
+            start: my_start_token(M),
+            end: my_end_token(M),
+            name: M.id && from_moz_symbol(is_method ? AST_SymbolMethod : AST_SymbolLambda, M.id),
+            argnames: M.params.map(M => from_moz_pattern(M, AST_SymbolFunarg)),
+            is_generator: M.generator,
+            async: M.async,
+            body: normalize_directives(from_moz(M.body).body)
+        });
+    }
+
+    function from_moz_pattern(M, sym_type) {
+        switch (M.type) {
+            case "ObjectPattern":
+                return new AST_Destructuring({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    names: M.properties.map(p => from_moz_pattern(p, sym_type)),
+                    is_array: false
+                });
+
+            case "Property":
+                var key = M.key;
+                var args = {
+                    start    : my_start_token(key || M.value),
+                    end      : my_end_token(M.value),
+                    key      : key.type == "Identifier" ? key.name : String(key.value),
+                    quote    : !M.computed && key.type === "Literal" && typeof key.value === "string"
+                                ? '"'
+                                : "",
+                    value    : from_moz_pattern(M.value, sym_type)
+                };
+                if (M.computed) {
+                    args.key = from_moz(M.key);
+                }
+                return new AST_ObjectKeyVal(args);
+
+            case "ArrayPattern":
+                return new AST_Destructuring({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    names: M.elements.map(function(elm) {
+                        if (elm === null) {
+                            return new AST_Hole();
+                        }
+                        return from_moz_pattern(elm, sym_type);
+                    }),
+                    is_array: true
+                });
+
+            case "SpreadElement":
+            case "RestElement":
+                return new AST_Expansion({
+                    start: my_start_token(M),
+                    end: my_end_token(M),
+                    expression: from_moz_pattern(M.argument, sym_type),
+                });
+
+            case "AssignmentPattern":
+                return new AST_DefaultAssign({
+                    start : my_start_token(M),
+                    end   : my_end_token(M),
+                    left  : from_moz_pattern(M.left, sym_type),
+                    operator: "=",
+                    right : from_moz(M.right),
+                });
+
+            case "Identifier":
+                return new sym_type({
+                    start : my_start_token(M),
+                    end   : my_end_token(M),
+                    name  : M.name,
+                });
+
+            default:
+                throw new Error("Invalid node type for destructuring: " + M.type);
+        }
+    }
+
+    function from_moz_label_ref(m_label) {
+        if (!m_label) return null;
+
+        const label = from_moz_symbol(AST_LabelRef, m_label);
+
+        let i = FROM_MOZ_LABELS.length;
+        while (i--) {
+            const label_origin = FROM_MOZ_LABELS[i];
+
+            if (label.name === label_origin.name) {
+                label.thedef = label_origin;
+                break;
+            }
+        }
+
+        return label;
+    }
+
+    AST_Node.from_mozilla_ast = function(node) {
+        var save_labels = FROM_MOZ_LABELS;
+        FROM_MOZ_LABELS = [];
+        var ast = from_moz(node);
+        FROM_MOZ_LABELS = save_labels;
+        return ast;
+    };
+
+    function set_moz_loc(mynode, moznode) {
+        var start = mynode.start;
+        var end = mynode.end;
+        if (!(start && end)) {
+            return moznode;
+        }
+        if (start.pos != null && end.endpos != null) {
+            moznode.range = [start.pos, end.endpos];
+        }
+        if (start.line) {
+            moznode.loc = {
+                start: {line: start.line, column: start.col},
+                end: end.endline ? {line: end.endline, column: end.endcol} : null
+            };
+            if (start.file) {
+                moznode.loc.source = start.file;
+            }
+        }
+        return moznode;
+    }
+
+    function def_to_moz(mytype, handler) {
+        mytype.DEFMETHOD("to_mozilla_ast", function(parent) {
+            return set_moz_loc(this, handler(this, parent));
+        });
+    }
+
+    var TO_MOZ_STACK = null;
+
+    function to_moz(node) {
+        if (TO_MOZ_STACK === null) { TO_MOZ_STACK = []; }
+        TO_MOZ_STACK.push(node);
+        var ast = node != null ? node.to_mozilla_ast(TO_MOZ_STACK[TO_MOZ_STACK.length - 2]) : null;
+        TO_MOZ_STACK.pop();
+        if (TO_MOZ_STACK.length === 0) { TO_MOZ_STACK = null; }
+        return ast;
+    }
+
+    /** Object property keys can be number literals, string literals, or raw names. Additionally they can be shorthand. We decide that here. */
+    function to_moz_property_key(key, computed = false, quote = false, value = null) {
+        if (computed) {
+            return [false, to_moz(key)];
+        }
+
+        const key_name = typeof key === "string" ? key : key.name;
+        let moz_key;
+        if (quote) {
+            moz_key = { type: "Literal", value: key_name, raw: JSON.stringify(key_name) };
+        } else if ("" + +key_name === key_name && +key_name >= 0) {
+            // representable as a number
+            moz_key = { type: "Literal", value: +key_name, raw: JSON.stringify(+key_name) };
+        } else {
+            moz_key = { type: "Identifier", name: key_name };
+        }
+
+        const shorthand =
+            moz_key.type === "Identifier"
+            && moz_key.name === key_name
+            && (value instanceof AST_Symbol && value.name === key_name
+                || value instanceof AST_DefaultAssign && value.left.name === key_name);
+        return [shorthand, moz_key];
+    }
+
+    function to_moz_pattern(node) {
+        if (node instanceof AST_Expansion) {
+            return {
+                type: "RestElement",
+                argument: to_moz_pattern(node.expression),
+            };
+        }
+
+        if ((
+            node instanceof AST_Symbol
+            || node instanceof AST_Destructuring
+            || node instanceof AST_DefaultAssign
+            || node instanceof AST_PropAccess
+        )) {
+            // Plain translation
+            return to_moz(node);
+        }
+
+        throw new Error(node.TYPE);
+    }
+
+    function to_moz_in_destructuring() {
+        var i = TO_MOZ_STACK.length;
+        while (i--) {
+            if (TO_MOZ_STACK[i] instanceof AST_Destructuring) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    function to_moz_block(node) {
+        return {
+            type: "BlockStatement",
+            body: node.body.map(to_moz)
+        };
+    }
+
+    function to_moz_scope(type, node) {
+        var body = node.body.map(to_moz);
+        if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) {
+            body.unshift(to_moz(new AST_EmptyStatement(node.body[0])));
+        }
+        return {
+            type: type,
+            body: body
+        };
+    }
+})();
+
+// return true if the node at the top of the stack (that means the
+// innermost node in the current output) is lexically the first in
+// a statement.
+function first_in_statement(stack) {
+    let node = stack.parent(-1);
+    for (let i = 0, p; p = stack.parent(i); i++) {
+        if (p instanceof AST_Statement && p.body === node)
+            return true;
+        if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
+            (p.TYPE === "Call" && p.expression === node) ||
+            (p instanceof AST_PrefixedTemplateString && p.prefix === node) ||
+            (p instanceof AST_Dot && p.expression === node) ||
+            (p instanceof AST_Sub && p.expression === node) ||
+            (p instanceof AST_Chain && p.expression === node) ||
+            (p instanceof AST_Conditional && p.condition === node) ||
+            (p instanceof AST_Binary && p.left === node) ||
+            (p instanceof AST_UnaryPostfix && p.expression === node)
+        ) {
+            node = p;
+        } else {
+            return false;
+        }
+    }
+}
+
+// Returns whether the leftmost item in the expression is an object
+function left_is_object(node) {
+    if (node instanceof AST_Object) return true;
+    if (node instanceof AST_Sequence) return left_is_object(node.expressions[0]);
+    if (node.TYPE === "Call") return left_is_object(node.expression);
+    if (node instanceof AST_PrefixedTemplateString) return left_is_object(node.prefix);
+    if (node instanceof AST_Dot || node instanceof AST_Sub) return left_is_object(node.expression);
+    if (node instanceof AST_Chain) return left_is_object(node.expression);
+    if (node instanceof AST_Conditional) return left_is_object(node.condition);
+    if (node instanceof AST_Binary) return left_is_object(node.left);
+    if (node instanceof AST_UnaryPostfix) return left_is_object(node.expression);
+    return false;
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+const CODE_LINE_BREAK = 10;
+const CODE_SPACE = 32;
+
+const r_annotation = /[@#]__(PURE|INLINE|NOINLINE)__/;
+
+function is_some_comments(comment) {
+    // multiline comment
+    return (
+        (comment.type === "comment2" || comment.type === "comment1")
+        && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value)
+    );
+}
+
+const ROPE_COMMIT_WHEN = 8 * 1000;
+class Rope {
+    constructor() {
+        this.committed = "";
+        this.current = "";
+    }
+
+    append(str) {
+        /** When `this.current` is too long, commit it. */
+        if (this.current.length > ROPE_COMMIT_WHEN) {
+            this.committed += this.current + str;
+            this.current = "";
+        } else {
+            this.current += str;
+        }
+    }
+
+    insertAt(char, index) {
+        const { committed, current } = this;
+        if (index < committed.length) {
+            this.committed = committed.slice(0, index) + char + committed.slice(index);
+        } else if (index === committed.length) {
+            this.committed += char;
+        } else {
+            index -= committed.length;
+            this.committed += current.slice(0, index) + char;
+            this.current = current.slice(index);
+        }
+    }
+
+    charAt(index) {
+        const { committed } = this;
+        if (index < committed.length) return committed[index];
+        return this.current[index - committed.length];
+    }
+
+    charCodeAt(index) {
+        const { committed } = this;
+        if (index < committed.length) return committed.charCodeAt(index);
+        return this.current.charCodeAt(index - committed.length);
+    }
+
+    length() {
+        return this.committed.length + this.current.length;
+    }
+
+    expectDirective() {
+        // /^$|[;{][\s\n]*$/
+
+        let ch, n = this.length();
+
+        if (n <= 0) return true;
+
+        // Skip N whitespace from the end
+        while (
+            (ch = this.charCodeAt(--n))
+            && (ch == CODE_SPACE || ch == CODE_LINE_BREAK)
+        );
+
+        // either ";", or "{", or the string ended
+        return !ch || ch === 59 || ch === 123;
+    }
+
+    hasNLB() {
+        let n = this.length() - 1;
+        while (n >= 0) {
+            const code = this.charCodeAt(n--);
+
+            if (code === CODE_LINE_BREAK) return true;
+            if (code !== CODE_SPACE) return false;
+        }
+        return true;
+    }
+
+
+    toString() {
+        return this.committed + this.current;
+    }
+}
+
+function OutputStream(options) {
+
+    var readonly = !options;
+    options = defaults(options, {
+        ascii_only           : false,
+        beautify             : false,
+        braces               : false,
+        comments             : "some",
+        ecma                 : 5,
+        ie8                  : false,
+        indent_level         : 4,
+        indent_start         : 0,
+        inline_script        : true,
+        keep_numbers         : false,
+        keep_quoted_props    : false,
+        max_line_len         : false,
+        preamble             : null,
+        preserve_annotations : false,
+        quote_keys           : false,
+        quote_style          : 0,
+        safari10             : false,
+        semicolons           : true,
+        shebang              : true,
+        shorthand            : undefined,
+        source_map           : null,
+        webkit               : false,
+        width                : 80,
+        wrap_iife            : false,
+        wrap_func_args       : false,
+
+        _destroy_ast         : false
+    }, true);
+
+    if (options.shorthand === undefined)
+        options.shorthand = options.ecma > 5;
+
+    // Convert comment option to RegExp if necessary and set up comments filter
+    var comment_filter = return_false; // Default case, throw all comments away
+    if (options.comments) {
+        let comments = options.comments;
+        if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) {
+            var regex_pos = options.comments.lastIndexOf("/");
+            comments = new RegExp(
+                options.comments.substr(1, regex_pos - 1),
+                options.comments.substr(regex_pos + 1)
+            );
+        }
+        if (comments instanceof RegExp) {
+            comment_filter = function(comment) {
+                return comment.type != "comment5" && comments.test(comment.value);
+            };
+        } else if (typeof comments === "function") {
+            comment_filter = function(comment) {
+                return comment.type != "comment5" && comments(this, comment);
+            };
+        } else if (comments === "some") {
+            comment_filter = is_some_comments;
+        } else { // NOTE includes "all" option
+            comment_filter = return_true;
+        }
+    }
+
+    if (options.preserve_annotations) {
+        let prev_comment_filter = comment_filter;
+        comment_filter = function (comment) {
+            return r_annotation.test(comment.value) || prev_comment_filter.apply(this, arguments);
+        };
+    }
+
+    var indentation = 0;
+    var current_col = 0;
+    var current_line = 1;
+    var current_pos = 0;
+    var OUTPUT = new Rope();
+    let printed_comments = new Set();
+
+    var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) {
+        if (options.ecma >= 2015 && !options.safari10 && !regexp) {
+            str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) {
+                var code = get_full_char_code(ch, 0).toString(16);
+                return "\\u{" + code + "}";
+            });
+        }
+        return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
+            var code = ch.charCodeAt(0).toString(16);
+            if (code.length <= 2 && !identifier) {
+                while (code.length < 2) code = "0" + code;
+                return "\\x" + code;
+            } else {
+                while (code.length < 4) code = "0" + code;
+                return "\\u" + code;
+            }
+        });
+    } : function(str) {
+        return str.replace(/[\ud800-\udbff][\udc00-\udfff]|([\ud800-\udbff]|[\udc00-\udfff])/g, function(match, lone) {
+            if (lone) {
+                return "\\u" + lone.charCodeAt(0).toString(16);
+            }
+            return match;
+        });
+    };
+
+    function make_string(str, quote) {
+        var dq = 0, sq = 0;
+        str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
+          function(s, i) {
+            switch (s) {
+              case '"': ++dq; return '"';
+              case "'": ++sq; return "'";
+              case "\\": return "\\\\";
+              case "\n": return "\\n";
+              case "\r": return "\\r";
+              case "\t": return "\\t";
+              case "\b": return "\\b";
+              case "\f": return "\\f";
+              case "\x0B": return options.ie8 ? "\\x0B" : "\\v";
+              case "\u2028": return "\\u2028";
+              case "\u2029": return "\\u2029";
+              case "\ufeff": return "\\ufeff";
+              case "\0":
+                  return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0";
+            }
+            return s;
+        });
+        function quote_single() {
+            return "'" + str.replace(/\x27/g, "\\'") + "'";
+        }
+        function quote_double() {
+            return '"' + str.replace(/\x22/g, '\\"') + '"';
+        }
+        function quote_template() {
+            return "`" + str.replace(/`/g, "\\`") + "`";
+        }
+        str = to_utf8(str);
+        if (quote === "`") return quote_template();
+        switch (options.quote_style) {
+          case 1:
+            return quote_single();
+          case 2:
+            return quote_double();
+          case 3:
+            return quote == "'" ? quote_single() : quote_double();
+          default:
+            return dq > sq ? quote_single() : quote_double();
+        }
+    }
+
+    function encode_string(str, quote) {
+        var ret = make_string(str, quote);
+        if (options.inline_script) {
+            ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2");
+            ret = ret.replace(/\x3c!--/g, "\\x3c!--");
+            ret = ret.replace(/--\x3e/g, "--\\x3e");
+        }
+        return ret;
+    }
+
+    function make_name(name) {
+        name = name.toString();
+        name = to_utf8(name, true);
+        return name;
+    }
+
+    function make_indent(back) {
+        return " ".repeat(options.indent_start + indentation - back * options.indent_level);
+    }
+
+    /* -----[ beautification/minification ]----- */
+
+    var has_parens = false;
+    var might_need_space = false;
+    var might_need_semicolon = false;
+    var might_add_newline = 0;
+    var need_newline_indented = false;
+    var need_space = false;
+    var newline_insert = -1;
+    var last = "";
+    var mapping_token, mapping_name, mappings = options.source_map && [];
+
+    var do_add_mapping = mappings ? function() {
+        mappings.forEach(function(mapping) {
+            try {
+                let { name, token } = mapping;
+                if (name !== false) {
+                    if (token.type == "name" || token.type === "privatename") {
+                        name = token.value;
+                    } else if (name instanceof AST_Symbol) {
+                        name = token.type === "string" ? token.value : name.name;
+                    }
+                }
+                options.source_map.add(
+                    mapping.token.file,
+                    mapping.line, mapping.col,
+                    mapping.token.line, mapping.token.col,
+                    is_basic_identifier_string(name) ? name : undefined
+                );
+            } catch(ex) {
+                // Ignore bad mapping
+            }
+        });
+        mappings = [];
+    } : noop;
+
+    var ensure_line_len = options.max_line_len ? function() {
+        if (current_col > options.max_line_len) {
+            if (might_add_newline) {
+                OUTPUT.insertAt("\n", might_add_newline);
+                const len_after_newline = OUTPUT.length() - might_add_newline - 1;
+                if (mappings) {
+                    var delta = len_after_newline - current_col;
+                    mappings.forEach(function(mapping) {
+                        mapping.line++;
+                        mapping.col += delta;
+                    });
+                }
+                current_line++;
+                current_pos++;
+                current_col = len_after_newline;
+            }
+        }
+        if (might_add_newline) {
+            might_add_newline = 0;
+            do_add_mapping();
+        }
+    } : noop;
+
+    var requireSemicolonChars = makePredicate("( [ + * / - , . `");
+
+    function print(str) {
+        str = String(str);
+        var ch = get_full_char(str, 0);
+        if (need_newline_indented && ch) {
+            need_newline_indented = false;
+            if (ch !== "\n") {
+                print("\n");
+                indent();
+            }
+        }
+        if (need_space && ch) {
+            need_space = false;
+            if (!/[\s;})]/.test(ch)) {
+                space();
+            }
+        }
+        newline_insert = -1;
+        var prev = last.charAt(last.length - 1);
+        if (might_need_semicolon) {
+            might_need_semicolon = false;
+
+            if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") {
+                if (options.semicolons || requireSemicolonChars.has(ch)) {
+                    OUTPUT.append(";");
+                    current_col++;
+                    current_pos++;
+                } else {
+                    ensure_line_len();
+                    if (current_col > 0) {
+                        OUTPUT.append("\n");
+                        current_pos++;
+                        current_line++;
+                        current_col = 0;
+                    }
+
+                    if (/^\s+$/.test(str)) {
+                        // reset the semicolon flag, since we didn't print one
+                        // now and might still have to later
+                        might_need_semicolon = true;
+                    }
+                }
+
+                if (!options.beautify)
+                    might_need_space = false;
+            }
+        }
+
+        if (might_need_space) {
+            if ((is_identifier_char(prev)
+                    && (is_identifier_char(ch) || ch == "\\"))
+                || (ch == "/" && ch == prev)
+                || ((ch == "+" || ch == "-") && ch == last)
+            ) {
+                OUTPUT.append(" ");
+                current_col++;
+                current_pos++;
+            }
+            might_need_space = false;
+        }
+
+        if (mapping_token) {
+            mappings.push({
+                token: mapping_token,
+                name: mapping_name,
+                line: current_line,
+                col: current_col
+            });
+            mapping_token = false;
+            if (!might_add_newline) do_add_mapping();
+        }
+
+        OUTPUT.append(str);
+        has_parens = str[str.length - 1] == "(";
+        current_pos += str.length;
+        var a = str.split(/\r?\n/), n = a.length - 1;
+        current_line += n;
+        current_col += a[0].length;
+        if (n > 0) {
+            ensure_line_len();
+            current_col = a[n].length;
+        }
+        last = str;
+    }
+
+    var star = function() {
+        print("*");
+    };
+
+    var space = options.beautify ? function() {
+        print(" ");
+    } : function() {
+        might_need_space = true;
+    };
+
+    var indent = options.beautify ? function(half) {
+        if (options.beautify) {
+            print(make_indent(half ? 0.5 : 0));
+        }
+    } : noop;
+
+    var with_indent = options.beautify ? function(col, cont) {
+        if (col === true) col = next_indent();
+        var save_indentation = indentation;
+        indentation = col;
+        var ret = cont();
+        indentation = save_indentation;
+        return ret;
+    } : function(col, cont) { return cont(); };
+
+    var newline = options.beautify ? function() {
+        if (newline_insert < 0) return print("\n");
+        if (OUTPUT.charAt(newline_insert) != "\n") {
+            OUTPUT.insertAt("\n", newline_insert);
+            current_pos++;
+            current_line++;
+        }
+        newline_insert++;
+    } : options.max_line_len ? function() {
+        ensure_line_len();
+        might_add_newline = OUTPUT.length();
+    } : noop;
+
+    var semicolon = options.beautify ? function() {
+        print(";");
+    } : function() {
+        might_need_semicolon = true;
+    };
+
+    function force_semicolon() {
+        might_need_semicolon = false;
+        print(";");
+    }
+
+    function next_indent() {
+        return indentation + options.indent_level;
+    }
+
+    function with_block(cont) {
+        var ret;
+        print("{");
+        newline();
+        with_indent(next_indent(), function() {
+            ret = cont();
+        });
+        indent();
+        print("}");
+        return ret;
+    }
+
+    function with_parens(cont) {
+        print("(");
+        //XXX: still nice to have that for argument lists
+        //var ret = with_indent(current_col, cont);
+        var ret = cont();
+        print(")");
+        return ret;
+    }
+
+    function with_square(cont) {
+        print("[");
+        //var ret = with_indent(current_col, cont);
+        var ret = cont();
+        print("]");
+        return ret;
+    }
+
+    function comma() {
+        print(",");
+        space();
+    }
+
+    function colon() {
+        print(":");
+        space();
+    }
+
+    var add_mapping = mappings ? function(token, name) {
+        mapping_token = token;
+        mapping_name = name;
+    } : noop;
+
+    function get() {
+        if (might_add_newline) {
+            ensure_line_len();
+        }
+        return OUTPUT.toString();
+    }
+
+    function filter_comment(comment) {
+        if (!options.preserve_annotations) {
+            comment = comment.replace(r_annotation, " ");
+        }
+        if (/^\s*$/.test(comment)) {
+            return "";
+        }
+        return comment.replace(/(<\s*\/\s*)(script)/i, "<\\/$2");
+    }
+
+    function prepend_comments(node) {
+        var self = this;
+        var start = node.start;
+        if (!start) return;
+        var printed_comments = self.printed_comments;
+
+        // There cannot be a newline between return/yield and its value.
+        const keyword_with_value = 
+            node instanceof AST_Exit && node.value
+            || (node instanceof AST_Await || node instanceof AST_Yield)
+                && node.expression;
+
+        if (
+            start.comments_before
+            && printed_comments.has(start.comments_before)
+        ) {
+            if (keyword_with_value) {
+                start.comments_before = [];
+            } else {
+                return;
+            }
+        }
+
+        var comments = start.comments_before;
+        if (!comments) {
+            comments = start.comments_before = [];
+        }
+        printed_comments.add(comments);
+
+        if (keyword_with_value) {
+            var tw = new TreeWalker(function(node) {
+                var parent = tw.parent();
+                if (parent instanceof AST_Exit
+                    || parent instanceof AST_Await
+                    || parent instanceof AST_Yield
+                    || parent instanceof AST_Binary && parent.left === node
+                    || parent.TYPE == "Call" && parent.expression === node
+                    || parent instanceof AST_Conditional && parent.condition === node
+                    || parent instanceof AST_Dot && parent.expression === node
+                    || parent instanceof AST_Sequence && parent.expressions[0] === node
+                    || parent instanceof AST_Sub && parent.expression === node
+                    || parent instanceof AST_UnaryPostfix) {
+                    if (!node.start) return;
+                    var text = node.start.comments_before;
+                    if (text && !printed_comments.has(text)) {
+                        printed_comments.add(text);
+                        comments = comments.concat(text);
+                    }
+                } else {
+                    return true;
+                }
+            });
+            tw.push(node);
+            keyword_with_value.walk(tw);
+        }
+
+        if (current_pos == 0) {
+            if (comments.length > 0 && options.shebang && comments[0].type === "comment5"
+                && !printed_comments.has(comments[0])) {
+                print("#!" + comments.shift().value + "\n");
+                indent();
+            }
+            var preamble = options.preamble;
+            if (preamble) {
+                print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
+            }
+        }
+
+        comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c));
+        if (comments.length == 0) return;
+        var last_nlb = OUTPUT.hasNLB();
+        comments.forEach(function(c, i) {
+            printed_comments.add(c);
+            if (!last_nlb) {
+                if (c.nlb) {
+                    print("\n");
+                    indent();
+                    last_nlb = true;
+                } else if (i > 0) {
+                    space();
+                }
+            }
+
+            if (/comment[134]/.test(c.type)) {
+                var value = filter_comment(c.value);
+                if (value) {
+                    print("//" + value + "\n");
+                    indent();
+                }
+                last_nlb = true;
+            } else if (c.type == "comment2") {
+                var value = filter_comment(c.value);
+                if (value) {
+                    print("/*" + value + "*/");
+                }
+                last_nlb = false;
+            }
+        });
+        if (!last_nlb) {
+            if (start.nlb) {
+                print("\n");
+                indent();
+            } else {
+                space();
+            }
+        }
+    }
+
+    function append_comments(node, tail) {
+        var self = this;
+        var token = node.end;
+        if (!token) return;
+        var printed_comments = self.printed_comments;
+        var comments = token[tail ? "comments_before" : "comments_after"];
+        if (!comments || printed_comments.has(comments)) return;
+        if (!(node instanceof AST_Statement || comments.every((c) =>
+            !/comment[134]/.test(c.type)
+        ))) return;
+        printed_comments.add(comments);
+        var insert = OUTPUT.length();
+        comments.filter(comment_filter, node).forEach(function(c, i) {
+            if (printed_comments.has(c)) return;
+            printed_comments.add(c);
+            need_space = false;
+            if (need_newline_indented) {
+                print("\n");
+                indent();
+                need_newline_indented = false;
+            } else if (c.nlb && (i > 0 || !OUTPUT.hasNLB())) {
+                print("\n");
+                indent();
+            } else if (i > 0 || !tail) {
+                space();
+            }
+            if (/comment[134]/.test(c.type)) {
+                const value = filter_comment(c.value);
+                if (value) {
+                    print("//" + value);
+                }
+                need_newline_indented = true;
+            } else if (c.type == "comment2") {
+                const value = filter_comment(c.value);
+                if (value) {
+                    print("/*" + value + "*/");
+                }
+                need_space = true;
+            }
+        });
+        if (OUTPUT.length() > insert) newline_insert = insert;
+    }
+
+    /**
+     * When output.option("_destroy_ast") is enabled, destroy the function.
+     * Call this after printing it.
+     */
+    const gc_scope =
+      options["_destroy_ast"]
+        ? function gc_scope(scope) {
+            scope.body.length = 0;
+            scope.argnames.length = 0;
+        }
+        : noop;
+
+    var stack = [];
+    return {
+        get             : get,
+        toString        : get,
+        indent          : indent,
+        in_directive    : false,
+        use_asm         : null,
+        active_scope    : null,
+        indentation     : function() { return indentation; },
+        current_width   : function() { return current_col - indentation; },
+        should_break    : function() { return options.width && this.current_width() >= options.width; },
+        has_parens      : function() { return has_parens; },
+        newline         : newline,
+        print           : print,
+        star            : star,
+        space           : space,
+        comma           : comma,
+        colon           : colon,
+        last            : function() { return last; },
+        semicolon       : semicolon,
+        force_semicolon : force_semicolon,
+        to_utf8         : to_utf8,
+        print_name      : function(name) { print(make_name(name)); },
+        print_string    : function(str, quote, escape_directive) {
+            var encoded = encode_string(str, quote);
+            if (escape_directive === true && !encoded.includes("\\")) {
+                // Insert semicolons to break directive prologue
+                if (!OUTPUT.expectDirective()) {
+                    force_semicolon();
+                }
+                force_semicolon();
+            }
+            print(encoded);
+        },
+        print_template_string_chars: function(str) {
+            var encoded = encode_string(str, "`").replace(/\${/g, "\\${");
+            return print(encoded.substr(1, encoded.length - 2));
+        },
+        encode_string   : encode_string,
+        next_indent     : next_indent,
+        with_indent     : with_indent,
+        with_block      : with_block,
+        with_parens     : with_parens,
+        with_square     : with_square,
+        add_mapping     : add_mapping,
+        option          : function(opt) { return options[opt]; },
+        gc_scope,
+        printed_comments: printed_comments,
+        prepend_comments: readonly ? noop : prepend_comments,
+        append_comments : readonly || comment_filter === return_false ? noop : append_comments,
+        line            : function() { return current_line; },
+        col             : function() { return current_col; },
+        pos             : function() { return current_pos; },
+        push_node       : function(node) { stack.push(node); },
+        pop_node        : function() { return stack.pop(); },
+        parent          : function(n) {
+            return stack[stack.length - 2 - (n || 0)];
+        }
+    };
+
+}
+
+/* -----[ code generators ]----- */
+
+(function() {
+
+    /* -----[ utils ]----- */
+
+    function DEFPRINT(nodetype, generator) {
+        nodetype.DEFMETHOD("_codegen", generator);
+    }
+
+    AST_Node.DEFMETHOD("print", function(output, force_parens) {
+        var self = this, generator = self._codegen;
+        if (self instanceof AST_Scope) {
+            output.active_scope = self;
+        } else if (!output.use_asm && self instanceof AST_Directive && self.value == "use asm") {
+            output.use_asm = output.active_scope;
+        }
+        function doit() {
+            output.prepend_comments(self);
+            self.add_source_map(output);
+            generator(self, output);
+            output.append_comments(self);
+        }
+        output.push_node(self);
+        if (force_parens || self.needs_parens(output)) {
+            output.with_parens(doit);
+        } else {
+            doit();
+        }
+        output.pop_node();
+        if (self === output.use_asm) {
+            output.use_asm = null;
+        }
+    });
+    AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
+
+    AST_Node.DEFMETHOD("print_to_string", function(options) {
+        var output = OutputStream(options);
+        this.print(output);
+        return output.get();
+    });
+
+    /* -----[ PARENTHESES ]----- */
+
+    function PARENS(nodetype, func) {
+        if (Array.isArray(nodetype)) {
+            nodetype.forEach(function(nodetype) {
+                PARENS(nodetype, func);
+            });
+        } else {
+            nodetype.DEFMETHOD("needs_parens", func);
+        }
+    }
+
+    PARENS(AST_Node, return_false);
+
+    // a function expression needs parens around it when it's provably
+    // the first token to appear in a statement.
+    PARENS(AST_Function, function(output) {
+        if (!output.has_parens() && first_in_statement(output)) {
+            return true;
+        }
+
+        if (output.option("webkit")) {
+            var p = output.parent();
+            if (p instanceof AST_PropAccess && p.expression === this) {
+                return true;
+            }
+        }
+
+        if (output.option("wrap_iife")) {
+            var p = output.parent();
+            if (p instanceof AST_Call && p.expression === this) {
+                return true;
+            }
+        }
+
+        if (output.option("wrap_func_args")) {
+            var p = output.parent();
+            if (p instanceof AST_Call && p.args.includes(this)) {
+                return true;
+            }
+        }
+
+        return false;
+    });
+
+    PARENS(AST_Arrow, function(output) {
+        var p = output.parent();
+
+        if (
+            output.option("wrap_func_args")
+            && p instanceof AST_Call
+            && p.args.includes(this)
+        ) {
+            return true;
+        }
+        return p instanceof AST_PropAccess && p.expression === this
+            || p instanceof AST_Conditional && p.condition === this;
+    });
+
+    // same goes for an object literal (as in AST_Function), because
+    // otherwise {...} would be interpreted as a block of code.
+    PARENS(AST_Object, function(output) {
+        return !output.has_parens() && first_in_statement(output);
+    });
+
+    PARENS(AST_ClassExpression, first_in_statement);
+
+    PARENS(AST_Unary, function(output) {
+        var p = output.parent();
+        return p instanceof AST_PropAccess && p.expression === this
+            || p instanceof AST_Call && p.expression === this
+            || p instanceof AST_Binary
+                && p.operator === "**"
+                && this instanceof AST_UnaryPrefix
+                && p.left === this
+                && this.operator !== "++"
+                && this.operator !== "--";
+    });
+
+    PARENS(AST_Await, function(output) {
+        var p = output.parent();
+        return p instanceof AST_PropAccess && p.expression === this
+            || p instanceof AST_Call && p.expression === this
+            || p instanceof AST_Binary && p.operator === "**" && p.left === this
+            || output.option("safari10") && p instanceof AST_UnaryPrefix;
+    });
+
+    PARENS(AST_Sequence, function(output) {
+        var p = output.parent();
+        return p instanceof AST_Call                              // (foo, bar)() or foo(1, (2, 3), 4)
+            || p instanceof AST_Unary                             // !(foo, bar, baz)
+            || p instanceof AST_Binary                            // 1 + (2, 3) + 4 ==> 8
+            || p instanceof AST_VarDefLike                        // var a = (1, 2), b = a + a; ==> b == 4
+            || p instanceof AST_PropAccess && this !== p.property // (1, {foo:2}).foo, (1, {foo:2})["foo"], not foo[1, 2]
+            || p instanceof AST_Array                             // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
+            || p instanceof AST_ObjectProperty                    // { foo: (1, 2) }.foo ==> 2
+            || p instanceof AST_Conditional                       /* (false, true) ? (a = 10, b = 20) : (c = 30)
+                                                                   * ==> 20 (side effect, set a := 10 and b := 20) */
+            || p instanceof AST_Arrow                             // x => (x, x)
+            || p instanceof AST_DefaultAssign                     // x => (x = (0, function(){}))
+            || p instanceof AST_Expansion                         // [...(a, b)]
+            || p instanceof AST_ForOf && this === p.object        // for (e of (foo, bar)) {}
+            || p instanceof AST_Yield                             // yield (foo, bar)
+            || p instanceof AST_Export                            // export default (foo, bar)
+        ;
+    });
+
+    PARENS(AST_Binary, function(output) {
+        var p = output.parent();
+        // (foo && bar)()
+        if (p instanceof AST_Call && p.expression === this)
+            return true;
+        // typeof (foo && bar)
+        if (p instanceof AST_Unary)
+            return true;
+        // (foo && bar)["prop"], (foo && bar).prop
+        if (p instanceof AST_PropAccess && p.expression === this)
+            return true;
+        // this deals with precedence: 3 * (2 + 1)
+        if (p instanceof AST_Binary) {
+            const parent_op = p.operator;
+            const op = this.operator;
+
+            // It is forbidden for ?? to be used with || or && without parens.
+            if (op === "??" && (parent_op === "||" || parent_op === "&&")) {
+                return true;
+            }
+            if (parent_op === "??" && (op === "||" || op === "&&")) {
+                return true;
+            }
+
+            const pp = PRECEDENCE[parent_op];
+            const sp = PRECEDENCE[op];
+            if (pp > sp
+                || (pp == sp
+                    && (this === p.right || parent_op == "**"))) {
+                return true;
+            }
+        }
+        if (p instanceof AST_PrivateIn) {
+            const op = this.operator;
+
+            const pp = PRECEDENCE["in"];
+            const sp = PRECEDENCE[op];
+            if (pp > sp || (pp == sp && this === p.value)) {
+                return true;
+            }
+        }
+    });
+
+    PARENS(AST_PrivateIn, function(output) {
+        var p = output.parent();
+        // (#x in this)()
+        if (p instanceof AST_Call && p.expression === this) {
+            return true;
+        }
+        // typeof (#x in this)
+        if (p instanceof AST_Unary) {
+            return true;
+        }
+        // (#x in this)["prop"], (#x in this).prop
+        if (p instanceof AST_PropAccess && p.expression === this) {
+            return true;
+        }
+        // same precedence as regular in operator
+        if (p instanceof AST_Binary) {
+            const parent_op = p.operator;
+
+            const pp = PRECEDENCE[parent_op];
+            const sp = PRECEDENCE["in"];
+            if (pp > sp
+                || (pp == sp
+                    && (this === p.right || parent_op == "**"))) {
+                return true;
+            }
+        }
+        // rules are the same as binary in, but the class differs
+        if (p instanceof AST_PrivateIn && this === p.value) {
+            return true;
+        }
+    });
+
+    PARENS(AST_Yield, function(output) {
+        var p = output.parent();
+        // (yield 1) + (yield 2)
+        // a = yield 3
+        if (p instanceof AST_Binary && p.operator !== "=")
+            return true;
+        // (yield 1)()
+        // new (yield 1)()
+        if (p instanceof AST_Call && p.expression === this)
+            return true;
+        // (yield 1) ? yield 2 : yield 3
+        if (p instanceof AST_Conditional && p.condition === this)
+            return true;
+        // -(yield 4)
+        if (p instanceof AST_Unary)
+            return true;
+        // (yield x).foo
+        // (yield x)['foo']
+        if (p instanceof AST_PropAccess && p.expression === this)
+            return true;
+    });
+
+    PARENS(AST_Chain, function(output) {
+        var p = output.parent();
+        if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false;
+        return p.expression === this;
+    });
+
+    PARENS(AST_PropAccess, function(output) {
+        var p = output.parent();
+        if (p instanceof AST_New && p.expression === this) {
+            // i.e. new (foo.bar().baz)
+            //
+            // if there's one call into this subtree, then we need
+            // parens around it too, otherwise the call will be
+            // interpreted as passing the arguments to the upper New
+            // expression.
+            return walk(this, node => {
+                if (node instanceof AST_Scope) return true;
+                if (node instanceof AST_Call) {
+                    return walk_abort;  // makes walk() return true.
+                }
+            });
+        }
+    });
+
+    PARENS(AST_Call, function(output) {
+        var p = output.parent(), p1;
+        if (p instanceof AST_New && p.expression === this
+            || p instanceof AST_Export && p.is_default && this.expression instanceof AST_Function)
+            return true;
+
+        // workaround for Safari bug.
+        // https://bugs.webkit.org/show_bug.cgi?id=123506
+        return this.expression instanceof AST_Function
+            && p instanceof AST_PropAccess
+            && p.expression === this
+            && (p1 = output.parent(1)) instanceof AST_Assign
+            && p1.left === p;
+    });
+
+    PARENS(AST_New, function(output) {
+        var p = output.parent();
+        if (this.args.length === 0
+            && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
+                || p instanceof AST_Call && p.expression === this
+                || p instanceof AST_PrefixedTemplateString && p.prefix === this)) // (new foo)(bar)
+            return true;
+    });
+
+    PARENS(AST_Number, function(output) {
+        var p = output.parent();
+        if (p instanceof AST_PropAccess && p.expression === this) {
+            var value = this.getValue();
+            if (value < 0 || /^0/.test(make_num(value))) {
+                return true;
+            }
+        }
+    });
+
+    PARENS(AST_BigInt, function(output) {
+        var p = output.parent();
+        if (p instanceof AST_PropAccess && p.expression === this) {
+            var value = this.getValue();
+            if (value.startsWith("-")) {
+                return true;
+            }
+        }
+    });
+
+    PARENS([ AST_Assign, AST_Conditional ], function(output) {
+        var p = output.parent();
+        // !(a = false) → true
+        if (p instanceof AST_Unary)
+            return true;
+        // 1 + (a = 2) + 3 → 6, side effect setting a = 2
+        if (p instanceof AST_Binary && !(p instanceof AST_Assign))
+            return true;
+        // (a = func)() —or— new (a = Object)()
+        if (p instanceof AST_Call && p.expression === this)
+            return true;
+        // (a = foo) ? bar : baz
+        if (p instanceof AST_Conditional && p.condition === this)
+            return true;
+        // (a = foo)["prop"] —or— (a = foo).prop
+        if (p instanceof AST_PropAccess && p.expression === this)
+            return true;
+        // ({a, b} = {a: 1, b: 2}), a destructuring assignment
+        if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false)
+            return true;
+    });
+
+    /* -----[ PRINTERS ]----- */
+
+    DEFPRINT(AST_Directive, function(self, output) {
+        output.print_string(self.value, self.quote);
+        output.semicolon();
+    });
+
+    DEFPRINT(AST_Expansion, function (self, output) {
+        output.print("...");
+        self.expression.print(output);
+    });
+
+    DEFPRINT(AST_Destructuring, function (self, output) {
+        output.print(self.is_array ? "[" : "{");
+        var len = self.names.length;
+        self.names.forEach(function (name, i) {
+            if (i > 0) output.comma();
+            name.print(output);
+            // If the final element is a hole, we need to make sure it
+            // doesn't look like a trailing comma, by inserting an actual
+            // trailing comma.
+            if (i == len - 1 && name instanceof AST_Hole) output.comma();
+        });
+        output.print(self.is_array ? "]" : "}");
+    });
+
+    DEFPRINT(AST_Debugger, function(self, output) {
+        output.print("debugger");
+        output.semicolon();
+    });
+
+    /* -----[ statements ]----- */
+
+    function display_body(body, is_toplevel, output, allow_directives) {
+        var last = body.length - 1;
+        output.in_directive = allow_directives;
+        body.forEach(function(stmt, i) {
+            if (output.in_directive === true && !(stmt instanceof AST_Directive ||
+                stmt instanceof AST_EmptyStatement ||
+                (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
+            )) {
+                output.in_directive = false;
+            }
+            if (!(stmt instanceof AST_EmptyStatement)) {
+                output.indent();
+                stmt.print(output);
+                if (!(i == last && is_toplevel)) {
+                    output.newline();
+                    if (is_toplevel) output.newline();
+                }
+            }
+            if (output.in_directive === true &&
+                stmt instanceof AST_SimpleStatement &&
+                stmt.body instanceof AST_String
+            ) {
+                output.in_directive = false;
+            }
+        });
+        output.in_directive = false;
+    }
+
+    AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
+        print_maybe_braced_body(this.body, output);
+    });
+
+    DEFPRINT(AST_Statement, function(self, output) {
+        self.body.print(output);
+        output.semicolon();
+    });
+    DEFPRINT(AST_Toplevel, function(self, output) {
+        display_body(self.body, true, output, true);
+        output.print("");
+    });
+    DEFPRINT(AST_LabeledStatement, function(self, output) {
+        self.label.print(output);
+        output.colon();
+        self.body.print(output);
+    });
+    DEFPRINT(AST_SimpleStatement, function(self, output) {
+        self.body.print(output);
+        output.semicolon();
+    });
+    function print_braced_empty(self, output) {
+        output.print("{");
+        output.with_indent(output.next_indent(), function() {
+            output.append_comments(self, true);
+        });
+        output.add_mapping(self.end);
+        output.print("}");
+    }
+    function print_braced(self, output, allow_directives) {
+        if (self.body.length > 0) {
+            output.with_block(function() {
+                display_body(self.body, false, output, allow_directives);
+                output.add_mapping(self.end);
+            });
+        } else print_braced_empty(self, output);
+    }
+    DEFPRINT(AST_BlockStatement, function(self, output) {
+        print_braced(self, output);
+    });
+    DEFPRINT(AST_EmptyStatement, function(self, output) {
+        output.semicolon();
+    });
+    DEFPRINT(AST_Do, function(self, output) {
+        output.print("do");
+        output.space();
+        make_block(self.body, output);
+        output.space();
+        output.print("while");
+        output.space();
+        output.with_parens(function() {
+            self.condition.print(output);
+        });
+        output.semicolon();
+    });
+    DEFPRINT(AST_While, function(self, output) {
+        output.print("while");
+        output.space();
+        output.with_parens(function() {
+            self.condition.print(output);
+        });
+        output.space();
+        self._do_print_body(output);
+    });
+    DEFPRINT(AST_For, function(self, output) {
+        output.print("for");
+        output.space();
+        output.with_parens(function() {
+            if (self.init) {
+                if (self.init instanceof AST_DefinitionsLike) {
+                    self.init.print(output);
+                } else {
+                    parenthesize_for_noin(self.init, output, true);
+                }
+                output.print(";");
+                output.space();
+            } else {
+                output.print(";");
+            }
+            if (self.condition) {
+                self.condition.print(output);
+                output.print(";");
+                output.space();
+            } else {
+                output.print(";");
+            }
+            if (self.step) {
+                self.step.print(output);
+            }
+        });
+        output.space();
+        self._do_print_body(output);
+    });
+    DEFPRINT(AST_ForIn, function(self, output) {
+        output.print("for");
+        if (self.await) {
+            output.space();
+            output.print("await");
+        }
+        output.space();
+        output.with_parens(function() {
+            self.init.print(output);
+            output.space();
+            output.print(self instanceof AST_ForOf ? "of" : "in");
+            output.space();
+            self.object.print(output);
+        });
+        output.space();
+        self._do_print_body(output);
+    });
+    DEFPRINT(AST_With, function(self, output) {
+        output.print("with");
+        output.space();
+        output.with_parens(function() {
+            self.expression.print(output);
+        });
+        output.space();
+        self._do_print_body(output);
+    });
+
+    /* -----[ functions ]----- */
+    AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) {
+        var self = this;
+        if (!nokeyword) {
+            if (self.async) {
+                output.print("async");
+                output.space();
+            }
+            output.print("function");
+            if (self.is_generator) {
+                output.star();
+            }
+            if (self.name) {
+                output.space();
+            }
+        }
+        if (self.name instanceof AST_Symbol) {
+            self.name.print(output);
+        } else if (nokeyword && self.name instanceof AST_Node) {
+            output.with_square(function() {
+                self.name.print(output); // Computed method name
+            });
+        }
+        output.with_parens(function() {
+            self.argnames.forEach(function(arg, i) {
+                if (i) output.comma();
+                arg.print(output);
+            });
+        });
+        output.space();
+        print_braced(self, output, true);
+    });
+    DEFPRINT(AST_Lambda, function(self, output) {
+        self._do_print(output);
+        output.gc_scope(self);
+    });
+
+    DEFPRINT(AST_PrefixedTemplateString, function(self, output) {
+        var tag = self.prefix;
+        var parenthesize_tag = tag instanceof AST_Lambda
+            || tag instanceof AST_Binary
+            || tag instanceof AST_Conditional
+            || tag instanceof AST_Sequence
+            || tag instanceof AST_Unary
+            || tag instanceof AST_Dot && tag.expression instanceof AST_Object;
+        if (parenthesize_tag) output.print("(");
+        self.prefix.print(output);
+        if (parenthesize_tag) output.print(")");
+        self.template_string.print(output);
+    });
+    DEFPRINT(AST_TemplateString, function(self, output) {
+        var is_tagged = output.parent() instanceof AST_PrefixedTemplateString;
+
+        output.print("`");
+        for (var i = 0; i < self.segments.length; i++) {
+            if (!(self.segments[i] instanceof AST_TemplateSegment)) {
+                output.print("${");
+                self.segments[i].print(output);
+                output.print("}");
+            } else if (is_tagged) {
+                output.print(self.segments[i].raw);
+            } else {
+                output.print_template_string_chars(self.segments[i].value);
+            }
+        }
+        output.print("`");
+    });
+    DEFPRINT(AST_TemplateSegment, function(self, output) {
+        output.print_template_string_chars(self.value);
+    });
+
+    AST_Arrow.DEFMETHOD("_do_print", function(output) {
+        var self = this;
+        var parent = output.parent();
+        var needs_parens = (parent instanceof AST_Binary &&
+                !(parent instanceof AST_Assign) &&
+                !(parent instanceof AST_DefaultAssign)) ||
+            parent instanceof AST_Unary ||
+            (parent instanceof AST_Call && self === parent.expression);
+        if (needs_parens) { output.print("("); }
+        if (self.async) {
+            output.print("async");
+            output.space();
+        }
+        if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) {
+            self.argnames[0].print(output);
+        } else {
+            output.with_parens(function() {
+                self.argnames.forEach(function(arg, i) {
+                    if (i) output.comma();
+                    arg.print(output);
+                });
+            });
+        }
+        output.space();
+        output.print("=>");
+        output.space();
+        const first_statement = self.body[0];
+        if (
+            self.body.length === 1
+            && first_statement instanceof AST_Return
+        ) {
+            const returned = first_statement.value;
+            if (!returned) {
+                output.print("{}");
+            } else if (left_is_object(returned)) {
+                output.print("(");
+                returned.print(output);
+                output.print(")");
+            } else {
+                returned.print(output);
+            }
+        } else {
+            print_braced(self, output);
+        }
+        if (needs_parens) { output.print(")"); }
+        output.gc_scope(self);
+    });
+
+    /* -----[ exits ]----- */
+    AST_Exit.DEFMETHOD("_do_print", function(output, kind) {
+        output.print(kind);
+        if (this.value) {
+            output.space();
+            const comments = this.value.start.comments_before;
+            if (comments && comments.length && !output.printed_comments.has(comments)) {
+                output.print("(");
+                this.value.print(output);
+                output.print(")");
+            } else {
+                this.value.print(output);
+            }
+        }
+        output.semicolon();
+    });
+    DEFPRINT(AST_Return, function(self, output) {
+        self._do_print(output, "return");
+    });
+    DEFPRINT(AST_Throw, function(self, output) {
+        self._do_print(output, "throw");
+    });
+
+    /* -----[ yield ]----- */
+
+    DEFPRINT(AST_Yield, function(self, output) {
+        var star = self.is_star ? "*" : "";
+        output.print("yield" + star);
+        if (self.expression) {
+            output.space();
+            self.expression.print(output);
+        }
+    });
+
+    DEFPRINT(AST_Await, function(self, output) {
+        output.print("await");
+        output.space();
+        var e = self.expression;
+        var parens = !(
+               e instanceof AST_Call
+            || e instanceof AST_SymbolRef
+            || e instanceof AST_PropAccess
+            || e instanceof AST_Unary
+            || e instanceof AST_Constant
+            || e instanceof AST_Await
+            || e instanceof AST_Object
+        );
+        if (parens) output.print("(");
+        self.expression.print(output);
+        if (parens) output.print(")");
+    });
+
+    /* -----[ loop control ]----- */
+    AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) {
+        output.print(kind);
+        if (this.label) {
+            output.space();
+            this.label.print(output);
+        }
+        output.semicolon();
+    });
+    DEFPRINT(AST_Break, function(self, output) {
+        self._do_print(output, "break");
+    });
+    DEFPRINT(AST_Continue, function(self, output) {
+        self._do_print(output, "continue");
+    });
+
+    /* -----[ if ]----- */
+    function make_then(self, output) {
+        var b = self.body;
+        if (output.option("braces")
+            || output.option("ie8") && b instanceof AST_Do)
+            return make_block(b, output);
+        // The squeezer replaces "block"-s that contain only a single
+        // statement with the statement itself; technically, the AST
+        // is correct, but this can create problems when we output an
+        // IF having an ELSE clause where the THEN clause ends in an
+        // IF *without* an ELSE block (then the outer ELSE would refer
+        // to the inner IF).  This function checks for this case and
+        // adds the block braces if needed.
+        if (!b) return output.force_semicolon();
+        while (true) {
+            if (b instanceof AST_If) {
+                if (!b.alternative) {
+                    make_block(self.body, output);
+                    return;
+                }
+                b = b.alternative;
+            } else if (b instanceof AST_StatementWithBody) {
+                b = b.body;
+            } else break;
+        }
+        print_maybe_braced_body(self.body, output);
+    }
+    DEFPRINT(AST_If, function(self, output) {
+        output.print("if");
+        output.space();
+        output.with_parens(function() {
+            self.condition.print(output);
+        });
+        output.space();
+        if (self.alternative) {
+            make_then(self, output);
+            output.space();
+            output.print("else");
+            output.space();
+            if (self.alternative instanceof AST_If)
+                self.alternative.print(output);
+            else
+                print_maybe_braced_body(self.alternative, output);
+        } else {
+            self._do_print_body(output);
+        }
+    });
+
+    /* -----[ switch ]----- */
+    DEFPRINT(AST_Switch, function(self, output) {
+        output.print("switch");
+        output.space();
+        output.with_parens(function() {
+            self.expression.print(output);
+        });
+        output.space();
+        var last = self.body.length - 1;
+        if (last < 0) print_braced_empty(self, output);
+        else output.with_block(function() {
+            self.body.forEach(function(branch, i) {
+                output.indent(true);
+                branch.print(output);
+                if (i < last && branch.body.length > 0)
+                    output.newline();
+            });
+        });
+    });
+    AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) {
+        output.newline();
+        this.body.forEach(function(stmt) {
+            output.indent();
+            stmt.print(output);
+            output.newline();
+        });
+    });
+    DEFPRINT(AST_Default, function(self, output) {
+        output.print("default:");
+        self._do_print_body(output);
+    });
+    DEFPRINT(AST_Case, function(self, output) {
+        output.print("case");
+        output.space();
+        self.expression.print(output);
+        output.print(":");
+        self._do_print_body(output);
+    });
+
+    /* -----[ exceptions ]----- */
+    DEFPRINT(AST_Try, function(self, output) {
+        output.print("try");
+        output.space();
+        self.body.print(output);
+        if (self.bcatch) {
+            output.space();
+            self.bcatch.print(output);
+        }
+        if (self.bfinally) {
+            output.space();
+            self.bfinally.print(output);
+        }
+    });
+    DEFPRINT(AST_TryBlock, function(self, output) {
+        print_braced(self, output);
+    });
+    DEFPRINT(AST_Catch, function(self, output) {
+        output.print("catch");
+        if (self.argname) {
+            output.space();
+            output.with_parens(function() {
+                self.argname.print(output);
+            });
+        }
+        output.space();
+        print_braced(self, output);
+    });
+    DEFPRINT(AST_Finally, function(self, output) {
+        output.print("finally");
+        output.space();
+        print_braced(self, output);
+    });
+
+    /* -----[ var/const ]----- */
+    AST_DefinitionsLike.DEFMETHOD("_do_print", function(output, kind) {
+        output.print(kind);
+        output.space();
+        this.definitions.forEach(function(def, i) {
+            if (i) output.comma();
+            def.print(output);
+        });
+        var p = output.parent();
+        var in_for = p instanceof AST_For || p instanceof AST_ForIn;
+        var output_semicolon = !in_for || p && p.init !== this;
+        if (output_semicolon)
+            output.semicolon();
+    });
+    DEFPRINT(AST_Let, function(self, output) {
+        self._do_print(output, "let");
+    });
+    DEFPRINT(AST_Var, function(self, output) {
+        self._do_print(output, "var");
+    });
+    DEFPRINT(AST_Const, function(self, output) {
+        self._do_print(output, "const");
+    });
+    DEFPRINT(AST_Using, function(self, output) {
+        self._do_print(output, self.await ? "await using" : "using");
+    });
+    DEFPRINT(AST_Import, function(self, output) {
+        output.print("import");
+        output.space();
+        if (self.phase) {
+            output.print(self.phase);
+            output.space();
+        }
+        if (self.imported_name) {
+            self.imported_name.print(output);
+        }
+        if (self.imported_name && self.imported_names) {
+            output.print(",");
+            output.space();
+        }
+        if (self.imported_names) {
+            if (self.imported_names.length === 1 &&
+                self.imported_names[0].foreign_name.name === "*" &&
+                !self.imported_names[0].foreign_name.quote) {
+                self.imported_names[0].print(output);
+            } else {
+                output.print("{");
+                self.imported_names.forEach(function (name_import, i) {
+                    output.space();
+                    name_import.print(output);
+                    if (i < self.imported_names.length - 1) {
+                        output.print(",");
+                    }
+                });
+                output.space();
+                output.print("}");
+            }
+        }
+        if (self.imported_name || self.imported_names) {
+            output.space();
+            output.print("from");
+            output.space();
+        }
+        self.module_name.print(output);
+        if (self.attributes) {
+            output.print("with");
+            self.attributes.print(output);
+        }
+        output.semicolon();
+    });
+    DEFPRINT(AST_ImportMeta, function(self, output) {
+        output.print("import.meta");
+    });
+    DEFPRINT(AST_DynamicImport, function(self, output) {
+        output.print("import." + self.phase);
+        output.with_parens(function() {
+            self.args.forEach(function(arg, i) {
+                if (i) output.comma();
+                arg.print(output);
+            });
+        });
+    });
+
+    DEFPRINT(AST_NameMapping, function(self, output) {
+        var is_import = output.parent() instanceof AST_Import;
+        var definition = self.name.definition();
+        var foreign_name = self.foreign_name;
+        var names_are_different =
+            (definition && definition.mangled_name || self.name.name) !==
+            foreign_name.name;
+        if (!names_are_different &&
+            foreign_name.name === "*" &&
+            !!foreign_name.quote != !!self.name.quote) {
+                // export * as "*"
+            names_are_different = true;
+        }
+        var foreign_name_is_name = !foreign_name.quote;
+        if (names_are_different) {
+            if (is_import) {
+                if (foreign_name_is_name) {
+                    output.print(foreign_name.name);
+                } else {
+                    output.print_string(foreign_name.name, foreign_name.quote);
+                }
+            } else {
+                if (!self.name.quote) {
+                    self.name.print(output);
+                } else {
+                    output.print_string(self.name.name, self.name.quote);
+                }
+                
+            }
+            output.space();
+            output.print("as");
+            output.space();
+            if (is_import) {
+                self.name.print(output);
+            } else {
+                if (foreign_name_is_name) {
+                    output.print(foreign_name.name);
+                } else {
+                    output.print_string(foreign_name.name, foreign_name.quote);
+                }
+            }
+        } else {
+            if (!self.name.quote) {
+                self.name.print(output);
+            } else {
+                output.print_string(self.name.name, self.name.quote);
+            }
+        }
+    });
+
+    DEFPRINT(AST_Export, function(self, output) {
+        output.print("export");
+        output.space();
+        if (self.is_default) {
+            output.print("default");
+            output.space();
+        }
+        if (self.exported_names) {
+            if (self.exported_names.length === 1 &&
+                self.exported_names[0].name.name === "*" &&
+                !self.exported_names[0].name.quote) {
+                    self.exported_names[0].print(output);
+            } else {
+                output.print("{");
+                self.exported_names.forEach(function(name_export, i) {
+                    output.space();
+                    name_export.print(output);
+                    if (i < self.exported_names.length - 1) {
+                        output.print(",");
+                    }
+                });
+                output.space();
+                output.print("}");
+            }
+        } else if (self.exported_value) {
+            self.exported_value.print(output);
+        } else if (self.exported_definition) {
+            self.exported_definition.print(output);
+            if (self.exported_definition instanceof AST_Definitions) return;
+        }
+        if (self.module_name) {
+            output.space();
+            output.print("from");
+            output.space();
+            self.module_name.print(output);
+        }
+        if (self.attributes) {
+            output.print("with");
+            self.attributes.print(output);
+        }
+        if (self.exported_value
+                && !(self.exported_value instanceof AST_Defun ||
+                    self.exported_value instanceof AST_Function ||
+                    self.exported_value instanceof AST_Class)
+            || self.module_name
+            || self.exported_names
+        ) {
+            output.semicolon();
+        }
+    });
+
+    function parenthesize_for_noin(node, output, noin) {
+        var parens = false;
+        // need to take some precautions here:
+        //    https://github.com/mishoo/UglifyJS2/issues/60
+        if (noin) {
+            parens = walk(node, node => {
+                // Don't go into scopes -- except arrow functions:
+                // https://github.com/terser/terser/issues/1019#issuecomment-877642607
+                if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
+                    return true;
+                }
+                if (
+                    node instanceof AST_Binary && node.operator == "in"
+                    || node instanceof AST_PrivateIn
+                ) {
+                    return walk_abort;  // makes walk() return true
+                }
+            });
+        }
+        node.print(output, parens);
+    }
+
+    DEFPRINT(AST_VarDefLike, function(self, output) {
+        self.name.print(output);
+        if (self.value) {
+            output.space();
+            output.print("=");
+            output.space();
+            var p = output.parent(1);
+            var noin = p instanceof AST_For || p instanceof AST_ForIn;
+            parenthesize_for_noin(self.value, output, noin);
+        }
+    });
+
+    /* -----[ other expressions ]----- */
+    DEFPRINT(AST_Call, function(self, output) {
+        self.expression.print(output);
+        if (self instanceof AST_New && self.args.length === 0)
+            return;
+        if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
+            output.add_mapping(self.start);
+        }
+        if (self.optional) output.print("?.");
+        output.with_parens(function() {
+            self.args.forEach(function(expr, i) {
+                if (i) output.comma();
+                expr.print(output);
+            });
+        });
+    });
+    DEFPRINT(AST_New, function(self, output) {
+        output.print("new");
+        output.space();
+        AST_Call.prototype._codegen(self, output);
+    });
+
+    AST_Sequence.DEFMETHOD("_do_print", function(output) {
+        this.expressions.forEach(function(node, index) {
+            if (index > 0) {
+                output.comma();
+                if (output.should_break()) {
+                    output.newline();
+                    output.indent();
+                }
+            }
+            node.print(output);
+        });
+    });
+    DEFPRINT(AST_Sequence, function(self, output) {
+        self._do_print(output);
+        // var p = output.parent();
+        // if (p instanceof AST_Statement) {
+        //     output.with_indent(output.next_indent(), function(){
+        //         self._do_print(output);
+        //     });
+        // } else {
+        //     self._do_print(output);
+        // }
+    });
+    DEFPRINT(AST_Dot, function(self, output) {
+        var expr = self.expression;
+        expr.print(output);
+        var prop = self.property;
+        var print_computed = ALL_RESERVED_WORDS.has(prop)
+            ? output.option("ie8")
+            : !is_identifier_string(
+                prop,
+                output.option("ecma") >= 2015 && !output.option("safari10")
+            );
+
+        if (self.optional) output.print("?.");
+
+        if (print_computed) {
+            output.print("[");
+            output.add_mapping(self.end);
+            output.print_string(prop);
+            output.print("]");
+        } else {
+            if (expr instanceof AST_Number && expr.getValue() >= 0) {
+                if (!/[xa-f.)]/i.test(output.last())) {
+                    output.print(".");
+                }
+            }
+            if (!self.optional) output.print(".");
+            // the name after dot would be mapped about here.
+            output.add_mapping(self.end);
+            output.print_name(prop);
+        }
+    });
+    DEFPRINT(AST_DotHash, function(self, output) {
+        var expr = self.expression;
+        expr.print(output);
+        var prop = self.property;
+
+        if (self.optional) output.print("?");
+        output.print(".#");
+        output.add_mapping(self.end);
+        output.print_name(prop);
+    });
+    DEFPRINT(AST_Sub, function(self, output) {
+        self.expression.print(output);
+        if (self.optional) output.print("?.");
+        output.print("[");
+        self.property.print(output);
+        output.print("]");
+    });
+    DEFPRINT(AST_Chain, function(self, output) {
+        self.expression.print(output);
+    });
+    DEFPRINT(AST_UnaryPrefix, function(self, output) {
+        var op = self.operator;
+        if (op === "--" && output.last().endsWith("!")) {
+            // avoid printing "<!--"
+            output.print(" ");
+        }
+        output.print(op);
+        if (/^[a-z]/i.test(op)
+            || (/[+-]$/.test(op)
+                && self.expression instanceof AST_UnaryPrefix
+                && /^[+-]/.test(self.expression.operator))) {
+            output.space();
+        }
+        self.expression.print(output);
+    });
+    DEFPRINT(AST_UnaryPostfix, function(self, output) {
+        self.expression.print(output);
+        output.print(self.operator);
+    });
+    DEFPRINT(AST_Binary, function(self, output) {
+        var op = self.operator;
+        self.left.print(output);
+        if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
+            && output.last().endsWith("--")) {
+            // space is mandatory to avoid outputting -->
+            output.print(" ");
+        } else {
+            // the space is optional depending on "beautify"
+            output.space();
+        }
+        output.print(op);
+        output.space();
+        self.right.print(output);
+    });
+    DEFPRINT(AST_Conditional, function(self, output) {
+        self.condition.print(output);
+        output.space();
+        output.print("?");
+        output.space();
+        self.consequent.print(output);
+        output.space();
+        output.colon();
+        self.alternative.print(output);
+    });
+
+    /* -----[ literals ]----- */
+    DEFPRINT(AST_Array, function(self, output) {
+        output.with_square(function() {
+            var a = self.elements, len = a.length;
+            if (len > 0) output.space();
+            a.forEach(function(exp, i) {
+                if (i) output.comma();
+                exp.print(output);
+                // If the final element is a hole, we need to make sure it
+                // doesn't look like a trailing comma, by inserting an actual
+                // trailing comma.
+                if (i === len - 1 && exp instanceof AST_Hole)
+                  output.comma();
+            });
+            if (len > 0) output.space();
+        });
+    });
+    DEFPRINT(AST_Object, function(self, output) {
+        if (self.properties.length > 0) output.with_block(function() {
+            self.properties.forEach(function(prop, i) {
+                if (i) {
+                    output.print(",");
+                    output.newline();
+                }
+                output.indent();
+                prop.print(output);
+            });
+            output.newline();
+        });
+        else print_braced_empty(self, output);
+    });
+    DEFPRINT(AST_Class, function(self, output) {
+        output.print("class");
+        output.space();
+        if (self.name) {
+            self.name.print(output);
+            output.space();
+        }
+        if (self.extends) {
+            var parens = (
+                   !(self.extends instanceof AST_SymbolRef)
+                && !(self.extends instanceof AST_PropAccess)
+                && !(self.extends instanceof AST_ClassExpression)
+                && !(self.extends instanceof AST_Function)
+            );
+            output.print("extends");
+            if (parens) {
+                output.print("(");
+            } else {
+                output.space();
+            }
+            self.extends.print(output);
+            if (parens) {
+                output.print(")");
+            } else {
+                output.space();
+            }
+        }
+        if (self.properties.length > 0) output.with_block(function() {
+            self.properties.forEach(function(prop, i) {
+                if (i) {
+                    output.newline();
+                }
+                output.indent();
+                prop.print(output);
+            });
+            output.newline();
+        });
+        else output.print("{}");
+    });
+    DEFPRINT(AST_NewTarget, function(self, output) {
+        output.print("new.target");
+    });
+
+    /** Prints a prop name. Returns whether it can be used as a shorthand. */
+    function print_property_name(key, quote, output) {
+        if (output.option("quote_keys")) {
+            output.print_string(key);
+            return false;
+        }
+        if ("" + +key == key && key >= 0) {
+            if (output.option("keep_numbers")) {
+                output.print(key);
+                return false;
+            }
+            output.print(make_num(key));
+            return false;
+        }
+        var print_string = ALL_RESERVED_WORDS.has(key)
+            ? output.option("ie8")
+            : (
+                output.option("ecma") < 2015 || output.option("safari10")
+                    ? !is_basic_identifier_string(key)
+                    : !is_identifier_string(key, true)
+            );
+        if (print_string || (quote && output.option("keep_quoted_props"))) {
+            output.print_string(key, quote);
+            return false;
+        }
+        output.print_name(key);
+        return true;
+    }
+
+    DEFPRINT(AST_ObjectKeyVal, function(self, output) {
+        function get_name(self) {
+            var def = self.definition();
+            return def ? def.mangled_name || def.name : self.name;
+        }
+
+        const try_shorthand = output.option("shorthand") && !(self.key instanceof AST_Node);
+        if (
+            try_shorthand
+            && self.value instanceof AST_Symbol
+            && get_name(self.value) === self.key
+            && !ALL_RESERVED_WORDS.has(self.key)
+        ) {
+            const was_shorthand = print_property_name(self.key, self.quote, output);
+            if (!was_shorthand) {
+                output.colon();
+                self.value.print(output);
+            }
+        } else if (
+            try_shorthand
+            && self.value instanceof AST_DefaultAssign
+            && self.value.left instanceof AST_Symbol
+            && get_name(self.value.left) === self.key
+        ) {
+            const was_shorthand = print_property_name(self.key, self.quote, output);
+            if (!was_shorthand) {
+                output.colon();
+                self.value.left.print(output);
+            }
+            output.space();
+            output.print("=");
+            output.space();
+            self.value.right.print(output);
+        } else {
+            if (!(self.key instanceof AST_Node)) {
+                print_property_name(self.key, self.quote, output);
+            } else {
+                output.with_square(function() {
+                    self.key.print(output);
+                });
+            }
+            output.colon();
+            self.value.print(output);
+        }
+    });
+    DEFPRINT(AST_ClassPrivateProperty, (self, output) => {
+        if (self.static) {
+            output.print("static");
+            output.space();
+        }
+
+        output.print("#");
+        
+        print_property_name(self.key.name, undefined, output);
+
+        if (self.value) {
+            output.print("=");
+            self.value.print(output);
+        }
+
+        output.semicolon();
+    });
+    DEFPRINT(AST_ClassProperty, (self, output) => {
+        if (self.static) {
+            output.print("static");
+            output.space();
+        }
+
+        if (self.key instanceof AST_SymbolClassProperty) {
+            print_property_name(self.key.name, self.quote, output);
+        } else {
+            output.print("[");
+            self.key.print(output);
+            output.print("]");
+        }
+
+        if (self.value) {
+            output.print("=");
+            self.value.print(output);
+        }
+
+        output.semicolon();
+    });
+    AST_ObjectProperty.DEFMETHOD("_print_getter_setter", function(type, is_private, output) {
+        var self = this;
+        if (self.static) {
+            output.print("static");
+            output.space();
+        }
+        if (type) {
+            output.print(type);
+            output.space();
+        }
+        if (self.key instanceof AST_SymbolMethod) {
+            if (is_private) output.print("#");
+            print_property_name(self.key.name, self.quote, output);
+            self.key.add_source_map(output);
+        } else {
+            output.with_square(function() {
+                self.key.print(output);
+            });
+        }
+        self.value._do_print(output, true);
+    });
+    DEFPRINT(AST_ObjectSetter, function(self, output) {
+        self._print_getter_setter("set", false, output);
+    });
+    DEFPRINT(AST_ObjectGetter, function(self, output) {
+        self._print_getter_setter("get", false, output);
+    });
+    DEFPRINT(AST_PrivateSetter, function(self, output) {
+        self._print_getter_setter("set", true, output);
+    });
+    DEFPRINT(AST_PrivateGetter, function(self, output) {
+        self._print_getter_setter("get", true, output);
+    });
+    DEFPRINT(AST_ConciseMethod, function(self, output) {
+        var type;
+        if (self.value.is_generator && self.value.async) {
+            type = "async*";
+        } else if (self.value.is_generator) {
+            type = "*";
+        } else if (self.value.async) {
+            type = "async";
+        }
+        self._print_getter_setter(type, false, output);
+    });
+    DEFPRINT(AST_PrivateMethod, function(self, output) {
+        var type;
+        if (self.value.is_generator && self.value.async) {
+            type = "async*";
+        } else if (self.value.is_generator) {
+            type = "*";
+        } else if (self.value.async) {
+            type = "async";
+        }
+        self._print_getter_setter(type, true, output);
+    });
+    DEFPRINT(AST_PrivateIn, function(self, output) {
+        self.key.print(output);
+        output.space();
+        output.print("in");
+        output.space();
+        self.value.print(output);
+    });
+    DEFPRINT(AST_SymbolPrivateProperty, function(self, output) {
+        output.print("#" + self.name);
+    });
+    DEFPRINT(AST_ClassStaticBlock, function (self, output) {
+        output.print("static");
+        output.space();
+        print_braced(self, output);
+    });
+    AST_Symbol.DEFMETHOD("_do_print", function(output) {
+        var def = this.definition();
+        output.print_name(def ? def.mangled_name || def.name : this.name);
+    });
+    DEFPRINT(AST_Symbol, function (self, output) {
+        self._do_print(output);
+    });
+    DEFPRINT(AST_Hole, noop);
+    DEFPRINT(AST_This, function(self, output) {
+        output.print("this");
+    });
+    DEFPRINT(AST_Super, function(self, output) {
+        output.print("super");
+    });
+    DEFPRINT(AST_Constant, function(self, output) {
+        output.print(self.getValue());
+    });
+    DEFPRINT(AST_String, function(self, output) {
+        output.print_string(self.getValue(), self.quote, output.in_directive);
+    });
+    DEFPRINT(AST_Number, function(self, output) {
+        if ((output.option("keep_numbers") || output.use_asm) && self.raw) {
+            output.print(self.raw);
+        } else {
+            output.print(make_num(self.getValue()));
+        }
+    });
+    DEFPRINT(AST_BigInt, function(self, output) {
+        if (output.option("keep_numbers") && self.raw) {
+            output.print(self.raw);
+        } else {
+            output.print(self.getValue() + "n");
+        }
+    });
+
+    const r_slash_script = /(<\s*\/\s*script)/i;
+    const r_starts_with_script = /^\s*script/i;
+    const slash_script_replace = (_, $1) => $1.replace("/", "\\/");
+    DEFPRINT(AST_RegExp, function(self, output) {
+        let { source, flags } = self.getValue();
+        source = regexp_source_fix(source);
+        flags = flags ? sort_regexp_flags(flags) : "";
+
+        // Avoid outputting end of script tag
+        source = source.replace(r_slash_script, slash_script_replace);
+        if (r_starts_with_script.test(source) && output.last().endsWith("<")) {
+            output.print(" ");
+        }
+
+        output.print(output.to_utf8(`/${source}/${flags}`, false, true));
+
+        const parent = output.parent();
+        if (
+            parent instanceof AST_Binary
+            && /^\w/.test(parent.operator)
+            && parent.left === self
+        ) {
+            output.print(" ");
+        }
+    });
+
+    /** if, for, while, may or may not have braces surrounding its body */
+    function print_maybe_braced_body(stat, output) {
+        if (output.option("braces")) {
+            make_block(stat, output);
+        } else {
+            if (!stat || stat instanceof AST_EmptyStatement)
+                output.force_semicolon();
+            else if ((stat instanceof AST_DefinitionsLike && !(stat instanceof AST_Var)) || stat instanceof AST_Class)
+                make_block(stat, output);
+            else
+                stat.print(output);
+        }
+    }
+
+    function best_of(a) {
+        var best = a[0], len = best.length;
+        for (var i = 1; i < a.length; ++i) {
+            if (a[i].length < len) {
+                best = a[i];
+                len = best.length;
+            }
+        }
+        return best;
+    }
+
+    function make_num(num) {
+        var str = num.toString(10).replace(/^0\./, ".").replace("e+", "e");
+        var candidates = [ str ];
+        if (Math.floor(num) === num) {
+            if (num < 0) {
+                candidates.push("-0x" + (-num).toString(16).toLowerCase());
+            } else {
+                candidates.push("0x" + num.toString(16).toLowerCase());
+            }
+        }
+        var match, len, digits;
+        if (match = /^\.0+/.exec(str)) {
+            len = match[0].length;
+            digits = str.slice(len);
+            candidates.push(digits + "e-" + (digits.length + len - 1));
+        } else if (match = /0+$/.exec(str)) {
+            len = match[0].length;
+            candidates.push(str.slice(0, -len) + "e" + len);
+        } else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) {
+            candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length));
+        }
+        return best_of(candidates);
+    }
+
+    function make_block(stmt, output) {
+        if (!stmt || stmt instanceof AST_EmptyStatement)
+            output.print("{}");
+        else if (stmt instanceof AST_BlockStatement)
+            stmt.print(output);
+        else output.with_block(function() {
+            output.indent();
+            stmt.print(output);
+            output.newline();
+        });
+    }
+
+    /* -----[ source map generators ]----- */
+
+    function DEFMAP(nodetype, generator) {
+        nodetype.forEach(function(nodetype) {
+            nodetype.DEFMETHOD("add_source_map", generator);
+        });
+    }
+
+    DEFMAP([
+        // We could easily add info for ALL nodes, but it seems to me that
+        // would be quite wasteful, hence this noop in the base class.
+        AST_Node,
+        // since the label symbol will mark it
+        AST_LabeledStatement,
+        AST_Toplevel,
+    ], noop);
+
+    // XXX: I'm not exactly sure if we need it for all of these nodes,
+    // or if we should add even more.
+    DEFMAP([
+        AST_Array,
+        AST_BlockStatement,
+        AST_Catch,
+        AST_Class,
+        AST_Constant,
+        AST_Debugger,
+        AST_DefinitionsLike,
+        AST_Directive,
+        AST_Finally,
+        AST_Jump,
+        AST_Lambda,
+        AST_New,
+        AST_Object,
+        AST_StatementWithBody,
+        AST_Symbol,
+        AST_Switch,
+        AST_SwitchBranch,
+        AST_TemplateString,
+        AST_TemplateSegment,
+        AST_Try,
+    ], function(output) {
+        output.add_mapping(this.start);
+    });
+
+    DEFMAP([
+        AST_ObjectGetter,
+        AST_ObjectSetter,
+        AST_PrivateGetter,
+        AST_PrivateSetter,
+        AST_ConciseMethod,
+        AST_PrivateMethod,
+    ], function(output) {
+        output.add_mapping(this.start, false /*name handled below*/);
+    });
+
+    DEFMAP([
+        AST_SymbolMethod,
+        AST_SymbolPrivateProperty
+    ], function(output) {
+        const tok_type = this.end && this.end.type;
+        if (tok_type === "name" || tok_type === "privatename") {
+            output.add_mapping(this.end, this.name);
+        } else {
+            output.add_mapping(this.end);
+        }
+    });
+
+    DEFMAP([ AST_ObjectProperty ], function(output) {
+        output.add_mapping(this.start, this.key);
+    });
+})();
+
+const shallow_cmp = (node1, node2) => {
+    return (
+        node1 === null && node2 === null
+        || node1.TYPE === node2.TYPE && node1.shallow_cmp(node2)
+    );
+};
+
+const equivalent_to = (tree1, tree2) => {
+    if (!shallow_cmp(tree1, tree2)) return false;
+    const walk_1_state = [tree1];
+    const walk_2_state = [tree2];
+
+    const walk_1_push = walk_1_state.push.bind(walk_1_state);
+    const walk_2_push = walk_2_state.push.bind(walk_2_state);
+
+    while (walk_1_state.length && walk_2_state.length) {
+        const node_1 = walk_1_state.pop();
+        const node_2 = walk_2_state.pop();
+
+        if (!shallow_cmp(node_1, node_2)) return false;
+
+        node_1._children_backwards(walk_1_push);
+        node_2._children_backwards(walk_2_push);
+
+        if (walk_1_state.length !== walk_2_state.length) {
+            // Different number of children
+            return false;
+        }
+    }
+
+    return walk_1_state.length == 0 && walk_2_state.length == 0;
+};
+
+const pass_through = () => true;
+
+AST_Node.prototype.shallow_cmp = function () {
+    throw new Error("did not find a shallow_cmp function for " + this.constructor.name);
+};
+
+AST_Debugger.prototype.shallow_cmp = pass_through;
+
+AST_Directive.prototype.shallow_cmp = function(other) {
+    return this.value === other.value;
+};
+
+AST_SimpleStatement.prototype.shallow_cmp = pass_through;
+
+AST_Block.prototype.shallow_cmp = pass_through;
+
+AST_EmptyStatement.prototype.shallow_cmp = pass_through;
+
+AST_LabeledStatement.prototype.shallow_cmp = function(other) {
+    return this.label.name === other.label.name;
+};
+
+AST_Do.prototype.shallow_cmp = pass_through;
+
+AST_While.prototype.shallow_cmp = pass_through;
+
+AST_For.prototype.shallow_cmp = function(other) {
+    return (this.init == null ? other.init == null : this.init === other.init) && (this.condition == null ? other.condition == null : this.condition === other.condition) && (this.step == null ? other.step == null : this.step === other.step);
+};
+
+AST_ForIn.prototype.shallow_cmp = pass_through;
+
+AST_ForOf.prototype.shallow_cmp = pass_through;
+
+AST_With.prototype.shallow_cmp = pass_through;
+
+AST_Toplevel.prototype.shallow_cmp = pass_through;
+
+AST_Expansion.prototype.shallow_cmp = pass_through;
+
+AST_Lambda.prototype.shallow_cmp = function(other) {
+    return this.is_generator === other.is_generator && this.async === other.async;
+};
+
+AST_Destructuring.prototype.shallow_cmp = function(other) {
+    return this.is_array === other.is_array;
+};
+
+AST_PrefixedTemplateString.prototype.shallow_cmp = pass_through;
+
+AST_TemplateString.prototype.shallow_cmp = pass_through;
+
+AST_TemplateSegment.prototype.shallow_cmp = function(other) {
+    return this.value === other.value;
+};
+
+AST_Jump.prototype.shallow_cmp = pass_through;
+
+AST_LoopControl.prototype.shallow_cmp = pass_through;
+
+AST_Await.prototype.shallow_cmp = pass_through;
+
+AST_Yield.prototype.shallow_cmp = function(other) {
+    return this.is_star === other.is_star;
+};
+
+AST_If.prototype.shallow_cmp = function(other) {
+    return this.alternative == null ? other.alternative == null : this.alternative === other.alternative;
+};
+
+AST_Switch.prototype.shallow_cmp = pass_through;
+
+AST_SwitchBranch.prototype.shallow_cmp = pass_through;
+
+AST_Try.prototype.shallow_cmp = function(other) {
+    return (this.body === other.body) && (this.bcatch == null ? other.bcatch == null : this.bcatch === other.bcatch) && (this.bfinally == null ? other.bfinally == null : this.bfinally === other.bfinally);
+};
+
+AST_Catch.prototype.shallow_cmp = function(other) {
+    return this.argname == null ? other.argname == null : this.argname === other.argname;
+};
+
+AST_Finally.prototype.shallow_cmp = pass_through;
+
+AST_DefinitionsLike.prototype.shallow_cmp = pass_through;
+
+AST_VarDefLike.prototype.shallow_cmp = function(other) {
+    return this.value == null ? other.value == null : this.value === other.value;
+};
+
+AST_NameMapping.prototype.shallow_cmp = pass_through;
+
+AST_Import.prototype.shallow_cmp = function(other) {
+    return (this.imported_name || null) === (other.imported_name || null)
+        && (this.imported_names || null) === (other.imported_names || null)
+        && (this.attributes || null) === (other.attributes || null)
+        && (this.phase || null) === (other.phase || null);
+};
+
+AST_ImportMeta.prototype.shallow_cmp = pass_through;
+
+AST_DynamicImport.prototype.shallow_cmp = function(other) {
+    return (this.phase || null) === (other.phase || null) && this.args.length === other.args.length;
+};
+
+AST_Export.prototype.shallow_cmp = function(other) {
+    return (this.exported_definition == null ? other.exported_definition == null : this.exported_definition === other.exported_definition) && (this.exported_value == null ? other.exported_value == null : this.exported_value === other.exported_value) && (this.exported_names == null ? other.exported_names == null : this.exported_names === other.exported_names) && (this.attributes == null ? other.attributes == null : this.attributes === other.attributes) && this.module_name === other.module_name && this.is_default === other.is_default;
+};
+
+AST_Call.prototype.shallow_cmp = pass_through;
+
+AST_Sequence.prototype.shallow_cmp = pass_through;
+
+AST_PropAccess.prototype.shallow_cmp = pass_through;
+
+AST_Chain.prototype.shallow_cmp = pass_through;
+
+AST_Dot.prototype.shallow_cmp = function(other) {
+    return (
+        this.property === other.property
+        && !!this.quote === !!other.quote
+    );
+};
+
+AST_DotHash.prototype.shallow_cmp = function(other) {
+    return this.property === other.property;
+};
+
+AST_Unary.prototype.shallow_cmp = function(other) {
+    return this.operator === other.operator;
+};
+
+AST_Binary.prototype.shallow_cmp = function(other) {
+    return this.operator === other.operator;
+};
+
+AST_PrivateIn.prototype.shallow_cmp = pass_through;
+
+AST_Conditional.prototype.shallow_cmp = pass_through;
+
+AST_Array.prototype.shallow_cmp = pass_through;
+
+AST_Object.prototype.shallow_cmp = pass_through;
+
+AST_ObjectProperty.prototype.shallow_cmp = pass_through;
+
+AST_ObjectKeyVal.prototype.shallow_cmp = function(other) {
+    return this.key === other.key && this.quote === other.quote;
+};
+
+AST_ObjectSetter.prototype.shallow_cmp = function(other) {
+    return this.static === other.static;
+};
+
+AST_ObjectGetter.prototype.shallow_cmp = function(other) {
+    return this.static === other.static;
+};
+
+AST_ConciseMethod.prototype.shallow_cmp = function(other) {
+    return this.static === other.static;
+};
+
+AST_PrivateMethod.prototype.shallow_cmp = function(other) {
+    return this.static === other.static;
+};
+
+AST_Class.prototype.shallow_cmp = function(other) {
+    return (this.name == null ? other.name == null : this.name === other.name) && (this.extends == null ? other.extends == null : this.extends === other.extends);
+};
+
+AST_ClassProperty.prototype.shallow_cmp = function(other) {
+    return this.static === other.static
+        && (typeof this.key === "string"
+            ? this.key === other.key
+            : true /* AST_Node handled elsewhere */);
+};
+
+AST_ClassPrivateProperty.prototype.shallow_cmp = function(other) {
+    return this.static === other.static;
+};
+
+AST_Symbol.prototype.shallow_cmp = function(other) {
+    return this.name === other.name;
+};
+
+AST_NewTarget.prototype.shallow_cmp = pass_through;
+
+AST_This.prototype.shallow_cmp = pass_through;
+
+AST_Super.prototype.shallow_cmp = pass_through;
+
+AST_String.prototype.shallow_cmp = function(other) {
+    return this.value === other.value;
+};
+
+AST_Number.prototype.shallow_cmp = function(other) {
+    return this.value === other.value;
+};
+
+AST_BigInt.prototype.shallow_cmp = function(other) {
+    return this.value === other.value;
+};
+
+AST_RegExp.prototype.shallow_cmp = function (other) {
+    return (
+        this.value.flags === other.value.flags
+        && this.value.source === other.value.source
+    );
+};
+
+AST_Atom.prototype.shallow_cmp = pass_through;
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+const MASK_EXPORT_DONT_MANGLE = 1 << 0;
+const MASK_EXPORT_WANT_MANGLE = 1 << 1;
+
+let function_defs = null;
+let unmangleable_names = null;
+/**
+ * When defined, there is a function declaration somewhere that's inside of a block.
+ * See https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics
+*/
+let scopes_with_block_defuns = null;
+
+class SymbolDef {
+    constructor(scope, orig, init) {
+        this.name = orig.name;
+        this.orig = [ orig ];
+        this.init = init;
+        this.eliminated = 0;
+        this.assignments = 0;
+        this.scope = scope;
+        this.replaced = 0;
+        this.global = false;
+        this.export = 0;
+        this.mangled_name = null;
+        this.undeclared = false;
+        this.id = SymbolDef.next_id++;
+        this.chained = false;
+        this.direct_access = false;
+        this.escaped = 0;
+        this.recursive_refs = 0;
+        this.references = [];
+        this.should_replace = undefined;
+        this.single_use = false;
+        this.fixed = false;
+        Object.seal(this);
+    }
+    fixed_value() {
+        if (!this.fixed || this.fixed instanceof AST_Node) return this.fixed;
+        return this.fixed();
+    }
+    unmangleable(options) {
+        if (!options) options = {};
+
+        if (
+            function_defs &&
+            function_defs.has(this.id) &&
+            keep_name(options.keep_fnames, this.orig[0].name)
+        ) return true;
+
+        return this.global && !options.toplevel
+            || (this.export & MASK_EXPORT_DONT_MANGLE)
+            || this.undeclared
+            || !options.eval && this.scope.pinned()
+            || (this.orig[0] instanceof AST_SymbolLambda
+                  || this.orig[0] instanceof AST_SymbolDefun) && keep_name(options.keep_fnames, this.orig[0].name)
+            || this.orig[0] instanceof AST_SymbolMethod
+            || (this.orig[0] instanceof AST_SymbolClass
+                  || this.orig[0] instanceof AST_SymbolDefClass) && keep_name(options.keep_classnames, this.orig[0].name);
+    }
+    mangle(options) {
+        const cache = options.cache && options.cache.props;
+        if (this.global && cache && cache.has(this.name)) {
+            this.mangled_name = cache.get(this.name);
+        } else if (!this.mangled_name && !this.unmangleable(options)) {
+            var s = this.scope;
+            var sym = this.orig[0];
+            if (options.ie8 && sym instanceof AST_SymbolLambda)
+                s = s.parent_scope;
+            const redefinition = redefined_catch_def(this);
+            this.mangled_name = redefinition
+                ? redefinition.mangled_name || redefinition.name
+                : s.next_mangled(options, this);
+            if (this.global && cache) {
+                cache.set(this.name, this.mangled_name);
+            }
+        }
+    }
+}
+
+SymbolDef.next_id = 1;
+
+function redefined_catch_def(def) {
+    if (def.orig[0] instanceof AST_SymbolCatch
+        && def.scope.is_block_scope()
+    ) {
+        return def.scope.get_defun_scope().variables.get(def.name);
+    }
+}
+
+AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = undefined, toplevel = this } = {}) {
+    options = defaults(options, {
+        cache: null,
+        ie8: false,
+        safari10: false,
+        module: false,
+    });
+
+    if (!(toplevel instanceof AST_Toplevel)) {
+        throw new Error("Invalid toplevel scope");
+    }
+
+    // pass 1: setup scope chaining and handle definitions
+    var scope = this.parent_scope = parent_scope;
+    var labels = new Map();
+    var defun = null;
+    var in_destructuring = null;
+    var for_scopes = [];
+    var tw = new TreeWalker((node, descend) => {
+        if (node.is_block_scope()) {
+            const save_scope = scope;
+            node.block_scope = scope = new AST_Scope(node);
+            scope._block_scope = true;
+            scope.init_scope_vars(save_scope);
+            scope.uses_with = save_scope.uses_with;
+            scope.uses_eval = save_scope.uses_eval;
+
+            if (options.safari10) {
+                if (node instanceof AST_For || node instanceof AST_ForIn || node instanceof AST_ForOf) {
+                    for_scopes.push(scope);
+                }
+            }
+
+            if (node instanceof AST_Switch) {
+                // XXX: HACK! Ensure the switch expression gets the correct scope (the parent scope) and the body gets the contained scope
+                // AST_Switch has a scope within the body, but it itself "is a block scope"
+                // This means the switched expression has to belong to the outer scope
+                // while the body inside belongs to the switch itself.
+                // This is pretty nasty and warrants an AST change
+                const the_block_scope = scope;
+                scope = save_scope;
+                node.expression.walk(tw);
+                scope = the_block_scope;
+                for (let i = 0; i < node.body.length; i++) {
+                    node.body[i].walk(tw);
+                }
+            } else {
+                descend();
+            }
+            scope = save_scope;
+            return true;
+        }
+        if (node instanceof AST_Destructuring) {
+            const save_destructuring = in_destructuring;
+            in_destructuring = node;
+            descend();
+            in_destructuring = save_destructuring;
+            return true;
+        }
+        if (node instanceof AST_Scope) {
+            node.init_scope_vars(scope);
+            var save_scope = scope;
+            var save_defun = defun;
+            var save_labels = labels;
+            defun = scope = node;
+            labels = new Map();
+            descend();
+            scope = save_scope;
+            defun = save_defun;
+            labels = save_labels;
+            return true;        // don't descend again in TreeWalker
+        }
+        if (node instanceof AST_LabeledStatement) {
+            var l = node.label;
+            if (labels.has(l.name)) {
+                throw new Error(string_template("Label {name} defined twice", l));
+            }
+            labels.set(l.name, l);
+            descend();
+            labels.delete(l.name);
+            return true;        // no descend again
+        }
+        if (node instanceof AST_With) {
+            for (var s = scope; s; s = s.parent_scope)
+                s.uses_with = true;
+            return;
+        }
+        if (node instanceof AST_Symbol) {
+            node.scope = scope;
+        }
+        if (node instanceof AST_Label) {
+            node.thedef = node;
+            node.references = [];
+        }
+        if (node instanceof AST_SymbolLambda) {
+            defun.def_function(node, node.name == "arguments" ? undefined : defun);
+        } else if (node instanceof AST_SymbolDefun) {
+            // Careful here, the scope where this should be defined is
+            // the parent scope.  The reason is that we enter a new
+            // scope when we encounter the AST_Defun node (which is
+            // instanceof AST_Scope) but we get to the symbol a bit
+            // later.
+            const closest_scope = defun.parent_scope;
+
+            // In strict mode, function definitions are block-scoped
+            node.scope = tw.directives["use strict"]
+                ? closest_scope
+                : closest_scope.get_defun_scope();
+
+            mark_export(node.scope.def_function(node, defun), 1);
+        } else if (node instanceof AST_SymbolClass) {
+            mark_export(defun.def_variable(node, defun), 1);
+        } else if (node instanceof AST_SymbolImport) {
+            scope.def_variable(node);
+        } else if (node instanceof AST_SymbolDefClass) {
+            // This deals with the name of the class being available
+            // inside the class.
+            mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1);
+        } else if (
+            node instanceof AST_SymbolVar
+            || node instanceof AST_SymbolLet
+            || node instanceof AST_SymbolConst
+            || node instanceof AST_SymbolUsing
+            || node instanceof AST_SymbolCatch
+        ) {
+            var def;
+            if (node instanceof AST_SymbolBlockDeclaration) {
+                def = scope.def_variable(node, null);
+            } else {
+                def = defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
+            }
+            if (!def.orig.every((sym) => {
+                if (sym === node) return true;
+                if (node instanceof AST_SymbolBlockDeclaration) {
+                    return sym instanceof AST_SymbolLambda;
+                }
+                return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst || sym instanceof AST_SymbolUsing);
+            })) {
+                js_error(
+                    `"${node.name}" is redeclared`,
+                    node.start.file,
+                    node.start.line,
+                    node.start.col,
+                    node.start.pos
+                );
+            }
+            if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2);
+            if (defun !== scope) {
+                node.mark_enclosed();
+                var def = scope.find_variable(node);
+                if (node.thedef !== def) {
+                    node.thedef = def;
+                    node.reference();
+                }
+            }
+        } else if (node instanceof AST_LabelRef) {
+            var sym = labels.get(node.name);
+            if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
+                name: node.name,
+                line: node.start.line,
+                col: node.start.col
+            }));
+            node.thedef = sym;
+        }
+        if (!(scope instanceof AST_Toplevel) && (node instanceof AST_Export || node instanceof AST_Import)) {
+            js_error(
+                `"${node.TYPE}" statement may only appear at the top level`,
+                node.start.file,
+                node.start.line,
+                node.start.col,
+                node.start.pos
+            );
+        }
+    });
+
+    if (options.module) {
+        tw.directives["use strict"] = true;
+    }
+
+    this.walk(tw);
+
+    function mark_export(def, level) {
+        if (in_destructuring) {
+            var i = 0;
+            do {
+                level++;
+            } while (tw.parent(i++) !== in_destructuring);
+        }
+        var node = tw.parent(level);
+        if (def.export = node instanceof AST_Export ? MASK_EXPORT_DONT_MANGLE : 0) {
+            var exported = node.exported_definition;
+            if ((exported instanceof AST_Defun || exported instanceof AST_DefClass) && node.is_default) {
+                def.export = MASK_EXPORT_WANT_MANGLE;
+            }
+        }
+    }
+
+    // pass 2: find back references and eval
+    const is_toplevel = this instanceof AST_Toplevel;
+    if (is_toplevel) {
+        this.globals = new Map();
+    }
+
+    var tw = new TreeWalker(node => {
+        if (node instanceof AST_LoopControl && node.label) {
+            node.label.thedef.references.push(node);
+            return true;
+        }
+        if (node instanceof AST_SymbolRef) {
+            var name = node.name;
+            if (name == "eval" && tw.parent() instanceof AST_Call) {
+                for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
+                    s.uses_eval = true;
+                }
+            }
+            var sym;
+            if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name
+                || !(sym = node.scope.find_variable(name))) {
+
+                sym = toplevel.def_global(node);
+                if (node instanceof AST_SymbolExport) sym.export = MASK_EXPORT_DONT_MANGLE;
+            } else if (sym.scope instanceof AST_Lambda && name == "arguments") {
+                sym.scope.get_defun_scope().uses_arguments = true;
+            }
+            node.thedef = sym;
+            node.reference();
+            if (node.scope.is_block_scope()
+                && !(sym.orig[0] instanceof AST_SymbolBlockDeclaration)) {
+                node.scope = node.scope.get_defun_scope();
+            }
+            return true;
+        }
+        // ensure mangling works if catch reuses a scope variable
+        var def;
+        if (node instanceof AST_SymbolCatch && (def = redefined_catch_def(node.definition()))) {
+            var s = node.scope;
+            while (s) {
+                push_uniq(s.enclosed, def);
+                if (s === def.scope) break;
+                s = s.parent_scope;
+            }
+        }
+    });
+    this.walk(tw);
+
+    // pass 3: work around IE8 and Safari catch scope bugs
+    if (options.ie8 || options.safari10) {
+        walk(this, node => {
+            if (node instanceof AST_SymbolCatch) {
+                var name = node.name;
+                var refs = node.thedef.references;
+                var scope = node.scope.get_defun_scope();
+                var def = scope.find_variable(name)
+                    || toplevel.globals.get(name)
+                    || scope.def_variable(node);
+                refs.forEach(function(ref) {
+                    ref.thedef = def;
+                    ref.reference();
+                });
+                node.thedef = def;
+                node.reference();
+                return true;
+            }
+        });
+    }
+
+    // pass 4: add symbol definitions to loop scopes
+    // Safari/Webkit bug workaround - loop init let variable shadowing argument.
+    // https://github.com/mishoo/UglifyJS2/issues/1753
+    // https://bugs.webkit.org/show_bug.cgi?id=171041
+    if (options.safari10) {
+        for (const scope of for_scopes) {
+            scope.parent_scope.variables.forEach(function(def) {
+                push_uniq(scope.enclosed, def);
+            });
+        }
+    }
+});
+
+AST_Toplevel.DEFMETHOD("def_global", function(node) {
+    var globals = this.globals, name = node.name;
+    if (globals.has(name)) {
+        return globals.get(name);
+    } else {
+        var g = new SymbolDef(this, node);
+        g.undeclared = true;
+        g.global = true;
+        globals.set(name, g);
+        return g;
+    }
+});
+
+AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) {
+    this.variables = new Map();         // map name to AST_SymbolVar (variables defined in this scope; includes functions)
+    this.uses_with = false;             // will be set to true if this or some nested scope uses the `with` statement
+    this.uses_eval = false;             // will be set to true if this or nested scope uses the global `eval`
+    this.parent_scope = parent_scope;   // the parent scope
+    this.enclosed = [];                 // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
+    this.cname = -1;                    // the current index for mangling functions/variables
+});
+
+AST_Scope.DEFMETHOD("conflicting_def", function (name) {
+    return (
+        this.enclosed.find(def => def.name === name)
+        || this.variables.has(name)
+        || (this.parent_scope && this.parent_scope.conflicting_def(name))
+    );
+});
+
+AST_Scope.DEFMETHOD("conflicting_def_shallow", function (name) {
+    return (
+        this.enclosed.find(def => def.name === name)
+        || this.variables.has(name)
+    );
+});
+
+AST_Scope.DEFMETHOD("add_child_scope", function (scope) {
+    // `scope` is going to be moved into `this` right now.
+    // Update the required scopes' information
+
+    if (scope.parent_scope === this) return;
+
+    scope.parent_scope = this;
+
+    // Propagate to this.uses_arguments from arrow functions
+    if ((scope instanceof AST_Arrow) && (this instanceof AST_Lambda && !this.uses_arguments)) {
+        this.uses_arguments = walk(scope, node => {
+            if (
+                node instanceof AST_SymbolRef
+                && node.scope instanceof AST_Lambda
+                && node.name === "arguments"
+            ) {
+                return walk_abort;
+            }
+
+            if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) {
+                return true;
+            }
+        });
+    }
+
+    this.uses_with = this.uses_with || scope.uses_with;
+    this.uses_eval = this.uses_eval || scope.uses_eval;
+
+    const scope_ancestry = (() => {
+        const ancestry = [];
+        let cur = this;
+        do {
+            ancestry.push(cur);
+        } while ((cur = cur.parent_scope));
+        ancestry.reverse();
+        return ancestry;
+    })();
+
+    const new_scope_enclosed_set = new Set(scope.enclosed);
+    const to_enclose = [];
+    for (const scope_topdown of scope_ancestry) {
+        to_enclose.forEach(e => push_uniq(scope_topdown.enclosed, e));
+        for (const def of scope_topdown.variables.values()) {
+            if (new_scope_enclosed_set.has(def)) {
+                push_uniq(to_enclose, def);
+                push_uniq(scope_topdown.enclosed, def);
+            }
+        }
+    }
+});
+
+function find_scopes_visible_from(scopes) {
+    const found_scopes = new Set();
+
+    for (const scope of new Set(scopes)) {
+        (function bubble_up(scope) {
+            if (scope == null || found_scopes.has(scope)) return;
+
+            found_scopes.add(scope);
+
+            bubble_up(scope.parent_scope);
+        })(scope);
+    }
+
+    return [...found_scopes];
+}
+
+// Creates a symbol during compression
+AST_Scope.DEFMETHOD("create_symbol", function(SymClass, {
+    source,
+    tentative_name,
+    scope,
+    conflict_scopes = [scope],
+    init = null
+} = {}) {
+    let symbol_name;
+
+    conflict_scopes = find_scopes_visible_from(conflict_scopes);
+
+    if (tentative_name) {
+        // Implement hygiene (no new names are conflicting with existing names)
+        tentative_name =
+            symbol_name =
+            tentative_name.replace(/(?:^[^a-z_$]|[^a-z0-9_$])/ig, "_");
+
+        let i = 0;
+        while (conflict_scopes.find(s => s.conflicting_def_shallow(symbol_name))) {
+            symbol_name = tentative_name + "$" + i++;
+        }
+    }
+
+    if (!symbol_name) {
+        throw new Error("No symbol name could be generated in create_symbol()");
+    }
+
+    const symbol = make_node(SymClass, source, {
+        name: symbol_name,
+        scope
+    });
+
+    this.def_variable(symbol, init || null);
+
+    symbol.mark_enclosed();
+
+    return symbol;
+});
+
+
+AST_Node.DEFMETHOD("is_block_scope", return_false);
+AST_Class.DEFMETHOD("is_block_scope", return_false);
+AST_Lambda.DEFMETHOD("is_block_scope", return_false);
+AST_Toplevel.DEFMETHOD("is_block_scope", return_false);
+AST_SwitchBranch.DEFMETHOD("is_block_scope", return_false);
+AST_Block.DEFMETHOD("is_block_scope", return_true);
+AST_Scope.DEFMETHOD("is_block_scope", function () {
+    return this._block_scope || false;
+});
+AST_IterationStatement.DEFMETHOD("is_block_scope", return_true);
+
+AST_Lambda.DEFMETHOD("init_scope_vars", function() {
+    AST_Scope.prototype.init_scope_vars.apply(this, arguments);
+    this.uses_arguments = false;
+    this.def_variable(new AST_SymbolFunarg({
+        name: "arguments",
+        start: this.start,
+        end: this.end
+    }));
+});
+
+AST_Arrow.DEFMETHOD("init_scope_vars", function() {
+    AST_Scope.prototype.init_scope_vars.apply(this, arguments);
+    this.uses_arguments = false;
+});
+
+AST_Symbol.DEFMETHOD("mark_enclosed", function() {
+    var def = this.definition();
+    var s = this.scope;
+    while (s) {
+        push_uniq(s.enclosed, def);
+        if (s === def.scope) break;
+        s = s.parent_scope;
+    }
+});
+
+AST_Symbol.DEFMETHOD("reference", function() {
+    this.definition().references.push(this);
+    this.mark_enclosed();
+});
+
+AST_Scope.DEFMETHOD("find_variable", function(name) {
+    if (name instanceof AST_Symbol) name = name.name;
+    return this.variables.get(name)
+        || (this.parent_scope && this.parent_scope.find_variable(name));
+});
+
+AST_Scope.DEFMETHOD("def_function", function(symbol, init) {
+    var def = this.def_variable(symbol, init);
+    if (!def.init || def.init instanceof AST_Defun) def.init = init;
+    return def;
+});
+
+AST_Scope.DEFMETHOD("def_variable", function(symbol, init) {
+    var def = this.variables.get(symbol.name);
+    if (def) {
+        def.orig.push(symbol);
+        if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) {
+            def.init = init;
+        }
+    } else {
+        def = new SymbolDef(this, symbol, init);
+        this.variables.set(symbol.name, def);
+        def.global = !this.parent_scope;
+    }
+    return symbol.thedef = def;
+});
+
+function next_mangled(scope, options) {
+    let defun_scope;
+    if (
+        scopes_with_block_defuns
+        && (defun_scope = scope.get_defun_scope())
+        && scopes_with_block_defuns.has(defun_scope)
+    ) {
+        scope = defun_scope;
+    }
+
+    var ext = scope.enclosed;
+    var nth_identifier = options.nth_identifier;
+    out: while (true) {
+        var m = nth_identifier.get(++scope.cname);
+        if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do"
+
+        // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
+        // shadow a name reserved from mangling.
+        if (options.reserved.has(m)) continue;
+
+        // Functions with short names might collide with base54 output
+        // and therefore cause collisions when keep_fnames is true.
+        if (unmangleable_names && unmangleable_names.has(m)) continue out;
+
+        // we must ensure that the mangled name does not shadow a name
+        // from some parent scope that is referenced in this or in
+        // inner scopes.
+        for (let i = ext.length; --i >= 0;) {
+            const def = ext[i];
+            const name = def.mangled_name || (def.unmangleable(options) && def.name);
+            if (m == name) continue out;
+        }
+        return m;
+    }
+}
+
+AST_Scope.DEFMETHOD("next_mangled", function(options) {
+    return next_mangled(this, options);
+});
+
+AST_Toplevel.DEFMETHOD("next_mangled", function(options) {
+    let name;
+    const mangled_names = this.mangled_names;
+    do {
+        name = next_mangled(this, options);
+    } while (mangled_names.has(name));
+    return name;
+});
+
+AST_Function.DEFMETHOD("next_mangled", function(options, def) {
+    // #179, #326
+    // in Safari strict mode, something like (function x(x){...}) is a syntax error;
+    // a function expression's argument cannot shadow the function expression's name
+
+    var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
+
+    // the function's mangled_name is null when keep_fnames is true
+    var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
+
+    while (true) {
+        var name = next_mangled(this, options);
+        if (!tricky_name || tricky_name != name)
+            return name;
+    }
+});
+
+AST_Symbol.DEFMETHOD("unmangleable", function(options) {
+    var def = this.definition();
+    return !def || def.unmangleable(options);
+});
+
+// labels are always mangleable
+AST_Label.DEFMETHOD("unmangleable", return_false);
+
+AST_Symbol.DEFMETHOD("unreferenced", function() {
+    return !this.definition().references.length && !this.scope.pinned();
+});
+
+AST_Symbol.DEFMETHOD("definition", function() {
+    return this.thedef;
+});
+
+AST_Symbol.DEFMETHOD("global", function() {
+    return this.thedef.global;
+});
+
+/**
+ * Format the mangler options (if any) into their appropriate types
+ */
+function format_mangler_options(options) {
+    options = defaults(options, {
+        eval        : false,
+        nth_identifier : base54,
+        ie8         : false,
+        keep_classnames: false,
+        keep_fnames : false,
+        module      : false,
+        reserved    : [],
+        toplevel    : false,
+    });
+    if (options.module) options.toplevel = true;
+    if (!Array.isArray(options.reserved)
+        && !(options.reserved instanceof Set)
+    ) {
+        options.reserved = [];
+    }
+    options.reserved = new Set(options.reserved);
+    // Never mangle arguments
+    options.reserved.add("arguments");
+    return options;
+}
+
+AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
+    options = format_mangler_options(options);
+    var nth_identifier = options.nth_identifier;
+
+    // We only need to mangle declaration nodes.  Special logic wired
+    // into the code generator will display the mangled name if it's
+    // present (and for AST_SymbolRef-s it'll use the mangled name of
+    // the AST_SymbolDeclaration that it points to).
+    var lname = -1;
+    var to_mangle = [];
+
+    if (options.keep_fnames) {
+        function_defs = new Set();
+    }
+
+    const mangled_names = this.mangled_names = new Set();
+    unmangleable_names = new Set();
+
+    if (options.cache) {
+        this.globals.forEach(collect);
+        if (options.cache.props) {
+            options.cache.props.forEach(function(mangled_name) {
+                mangled_names.add(mangled_name);
+            });
+        }
+    }
+
+    var tw = new TreeWalker(function(node, descend) {
+        if (node instanceof AST_LabeledStatement) {
+            // lname is incremented when we get to the AST_Label
+            var save_nesting = lname;
+            descend();
+            lname = save_nesting;
+            return true;        // don't descend again in TreeWalker
+        }
+        if (
+            node instanceof AST_Defun
+            && !(tw.parent() instanceof AST_Scope)
+        ) {
+            scopes_with_block_defuns = scopes_with_block_defuns || new Set();
+            scopes_with_block_defuns.add(node.parent_scope.get_defun_scope());
+        }
+        if (node instanceof AST_Scope) {
+            node.variables.forEach(collect);
+            return;
+        }
+        if (node.is_block_scope()) {
+            node.block_scope.variables.forEach(collect);
+            return;
+        }
+        if (
+            function_defs
+            && node instanceof AST_VarDef
+            && node.name instanceof AST_Symbol
+            && node.value instanceof AST_Lambda
+            && !node.value.name
+            && keep_name(options.keep_fnames, node.name.name)
+        ) {
+            function_defs.add(node.name.definition().id);
+            return;
+        }
+        if (node instanceof AST_Label) {
+            let name;
+            do {
+                name = nth_identifier.get(++lname);
+            } while (ALL_RESERVED_WORDS.has(name));
+            node.mangled_name = name;
+            return true;
+        }
+        if (!(options.ie8 || options.safari10) && node instanceof AST_SymbolCatch) {
+            to_mangle.push(node.definition());
+            return;
+        }
+    });
+
+    this.walk(tw);
+
+    if (options.keep_fnames || options.keep_classnames) {
+        // Collect a set of short names which are unmangleable,
+        // for use in avoiding collisions in next_mangled.
+        to_mangle.forEach(def => {
+            if (def.name.length < 6 && def.unmangleable(options)) {
+                unmangleable_names.add(def.name);
+            }
+        });
+    }
+
+    to_mangle.forEach(def => { def.mangle(options); });
+
+    function_defs = null;
+    unmangleable_names = null;
+    scopes_with_block_defuns = null;
+
+    function collect(symbol) {
+        if (symbol.export & MASK_EXPORT_DONT_MANGLE) {
+            unmangleable_names.add(symbol.name);
+        } else if (!options.reserved.has(symbol.name)) {
+            to_mangle.push(symbol);
+        }
+    }
+});
+
+AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) {
+    const cache = options.cache && options.cache.props;
+    const avoid = new Set();
+    options.reserved.forEach(to_avoid);
+    this.globals.forEach(add_def);
+    this.walk(new TreeWalker(function(node) {
+        if (node instanceof AST_Scope) node.variables.forEach(add_def);
+        if (node instanceof AST_SymbolCatch) add_def(node.definition());
+    }));
+    return avoid;
+
+    function to_avoid(name) {
+        avoid.add(name);
+    }
+
+    function add_def(def) {
+        var name = def.name;
+        if (def.global && cache && cache.has(name)) name = cache.get(name);
+        else if (!def.unmangleable(options)) return;
+        to_avoid(name);
+    }
+});
+
+AST_Toplevel.DEFMETHOD("expand_names", function(options) {
+    options = format_mangler_options(options);
+    var nth_identifier = options.nth_identifier;
+    if (nth_identifier.reset && nth_identifier.sort) {
+        nth_identifier.reset();
+        nth_identifier.sort();
+    }
+    var avoid = this.find_colliding_names(options);
+    var cname = 0;
+    this.globals.forEach(rename);
+    this.walk(new TreeWalker(function(node) {
+        if (node instanceof AST_Scope) node.variables.forEach(rename);
+        if (node instanceof AST_SymbolCatch) rename(node.definition());
+    }));
+
+    function next_name() {
+        var name;
+        do {
+            name = nth_identifier.get(cname++);
+        } while (avoid.has(name) || ALL_RESERVED_WORDS.has(name));
+        return name;
+    }
+
+    function rename(def) {
+        if (def.global && options.cache) return;
+        if (def.unmangleable(options)) return;
+        if (options.reserved.has(def.name)) return;
+        const redefinition = redefined_catch_def(def);
+        const name = def.name = redefinition ? redefinition.name : next_name();
+        def.orig.forEach(function(sym) {
+            sym.name = name;
+        });
+        def.references.forEach(function(sym) {
+            sym.name = name;
+        });
+    }
+});
+
+AST_Node.DEFMETHOD("tail_node", return_this);
+AST_Sequence.DEFMETHOD("tail_node", function() {
+    return this.expressions[this.expressions.length - 1];
+});
+
+AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) {
+    options = format_mangler_options(options);
+    var nth_identifier = options.nth_identifier;
+    if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) {
+        // If the identifier mangler is invariant, skip computing character frequency.
+        return;
+    }
+    nth_identifier.reset();
+
+    try {
+        AST_Node.prototype.print = function(stream, force_parens) {
+            this._print(stream, force_parens);
+            if (this instanceof AST_Symbol && !this.unmangleable(options)) {
+                nth_identifier.consider(this.name, -1);
+            } else if (options.properties) {
+                if (this instanceof AST_DotHash) {
+                    nth_identifier.consider("#" + this.property, -1);
+                } else if (this instanceof AST_Dot) {
+                    nth_identifier.consider(this.property, -1);
+                } else if (this instanceof AST_Sub) {
+                    skip_string(this.property);
+                }
+            }
+        };
+        nth_identifier.consider(this.print_to_string(), 1);
+    } finally {
+        AST_Node.prototype.print = AST_Node.prototype._print;
+    }
+    nth_identifier.sort();
+
+    function skip_string(node) {
+        if (node instanceof AST_String) {
+            nth_identifier.consider(node.value, -1);
+        } else if (node instanceof AST_Conditional) {
+            skip_string(node.consequent);
+            skip_string(node.alternative);
+        } else if (node instanceof AST_Sequence) {
+            skip_string(node.tail_node());
+        }
+    }
+});
+
+const base54 = (() => {
+    const leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split("");
+    const digits = "0123456789".split("");
+    let chars;
+    let frequency;
+    function reset() {
+        frequency = new Map();
+        leading.forEach(function(ch) {
+            frequency.set(ch, 0);
+        });
+        digits.forEach(function(ch) {
+            frequency.set(ch, 0);
+        });
+    }
+    function consider(str, delta) {
+        for (var i = str.length; --i >= 0;) {
+            frequency.set(str[i], frequency.get(str[i]) + delta);
+        }
+    }
+    function compare(a, b) {
+        return frequency.get(b) - frequency.get(a);
+    }
+    function sort() {
+        chars = mergeSort(leading, compare).concat(mergeSort(digits, compare));
+    }
+    // Ensure this is in a usable initial state.
+    reset();
+    sort();
+    function base54(num) {
+        var ret = "", base = 54;
+        num++;
+        do {
+            num--;
+            ret += chars[num % base];
+            num = Math.floor(num / base);
+            base = 64;
+        } while (num > 0);
+        return ret;
+    }
+
+    return {
+        get: base54,
+        consider,
+        reset,
+        sort
+    };
+})();
+
+let mangle_options = undefined;
+AST_Node.prototype.size = function (compressor, stack) {
+    mangle_options = compressor && compressor._mangle_options;
+
+    let size = 0;
+    walk_parent(this, (node, info) => {
+        size += node._size(info);
+
+        // Braceless arrow functions have fake "return" statements
+        if (node instanceof AST_Arrow && node.is_braceless()) {
+            size += node.body[0].value._size(info);
+            return true;
+        }
+    }, stack || (compressor && compressor.stack));
+
+    // just to save a bit of memory
+    mangle_options = undefined;
+
+    return size;
+};
+
+AST_Node.prototype._size = () => 0;
+
+AST_Debugger.prototype._size = () => 8;
+
+AST_Directive.prototype._size = function () {
+    // TODO string encoding stuff
+    return 2 + this.value.length;
+};
+
+/** Count commas/semicolons necessary to show a list of expressions/statements */
+const list_overhead = (array) => array.length && array.length - 1;
+
+AST_Block.prototype._size = function () {
+    return 2 + list_overhead(this.body);
+};
+
+AST_Toplevel.prototype._size = function() {
+    return list_overhead(this.body);
+};
+
+AST_EmptyStatement.prototype._size = () => 1;
+
+AST_LabeledStatement.prototype._size = () => 2;  // x:
+
+AST_Do.prototype._size = () => 9;
+
+AST_While.prototype._size = () => 7;
+
+AST_For.prototype._size = () => 8;
+
+AST_ForIn.prototype._size = () => 8;
+// AST_ForOf inherits ^
+
+AST_With.prototype._size = () => 6;
+
+AST_Expansion.prototype._size = () => 3;
+
+const lambda_modifiers = func =>
+    (func.is_generator ? 1 : 0) + (func.async ? 6 : 0);
+
+AST_Accessor.prototype._size = function () {
+    return lambda_modifiers(this) + 4 + list_overhead(this.argnames) + list_overhead(this.body);
+};
+
+AST_Function.prototype._size = function (info) {
+    const first = !!first_in_statement(info);
+    return (first * 2) + lambda_modifiers(this) + 12 + list_overhead(this.argnames) + list_overhead(this.body);
+};
+
+AST_Defun.prototype._size = function () {
+    return lambda_modifiers(this) + 13 + list_overhead(this.argnames) + list_overhead(this.body);
+};
+
+AST_Arrow.prototype._size = function () {
+    let args_and_arrow = 2 + list_overhead(this.argnames);
+
+    if (
+        !(
+            this.argnames.length === 1
+            && this.argnames[0] instanceof AST_Symbol
+        )
+    ) {
+        args_and_arrow += 2; // parens around the args
+    }
+
+    const body_overhead = this.is_braceless() ? 0 : list_overhead(this.body) + 2;
+
+    return lambda_modifiers(this) + args_and_arrow + body_overhead;
+};
+
+AST_Destructuring.prototype._size = () => 2;
+
+AST_TemplateString.prototype._size = function () {
+    return 2 + (Math.floor(this.segments.length / 2) * 3);  /* "${}" */
+};
+
+AST_TemplateSegment.prototype._size = function () {
+    return this.value.length;
+};
+
+AST_Return.prototype._size = function () {
+    return this.value ? 7 : 6;
+};
+
+AST_Throw.prototype._size = () => 6;
+
+AST_Break.prototype._size = function () {
+    return this.label ? 6 : 5;
+};
+
+AST_Continue.prototype._size = function () {
+    return this.label ? 9 : 8;
+};
+
+AST_If.prototype._size = () => 4;
+
+AST_Switch.prototype._size = function () {
+    return 8 + list_overhead(this.body);
+};
+
+AST_Case.prototype._size = function () {
+    return 5 + list_overhead(this.body);
+};
+
+AST_Default.prototype._size = function () {
+    return 8 + list_overhead(this.body);
+};
+
+AST_Try.prototype._size = () => 3;
+
+AST_Catch.prototype._size = function () {
+    let size = 7 + list_overhead(this.body);
+    if (this.argname) {
+        size += 2;
+    }
+    return size;
+};
+
+AST_Finally.prototype._size = function () {
+    return 7 + list_overhead(this.body);
+};
+
+AST_Var.prototype._size = function () {
+    return 4 + list_overhead(this.definitions);
+};
+
+AST_Let.prototype._size = function () {
+    return 4 + list_overhead(this.definitions);
+};
+
+AST_Const.prototype._size = function () {
+    return 6 + list_overhead(this.definitions);
+};
+
+AST_Using.prototype._size = function () {
+    const await_size = this.await ? 6 : 0;
+    return await_size + 6 + list_overhead(this.definitions);
+};
+
+AST_VarDefLike.prototype._size = function () {
+    return this.value ? 1 : 0;
+};
+
+AST_NameMapping.prototype._size = function () {
+    // foreign name isn't mangled
+    return this.name ? 4 : 0;
+};
+
+AST_Import.prototype._size = function () {
+    // import
+    let size = 6;
+
+    if (this.imported_name) size += 1;
+
+    // from
+    if (this.imported_name || this.imported_names) size += 5;
+
+    // braces, and the commas
+    if (this.imported_names) {
+        size += 2 + list_overhead(this.imported_names);
+    }
+
+    return size;
+};
+
+AST_ImportMeta.prototype._size = () => 11;
+
+AST_DynamicImport.prototype._size = function () {
+    // `import.` + phase + `()` + arg overhead
+    return 9 + this.phase.length + list_overhead(this.args);
+};
+
+AST_Export.prototype._size = function () {
+    let size = 7 + (this.is_default ? 8 : 0);
+
+    if (this.exported_value) {
+        size += this.exported_value._size();
+    }
+
+    if (this.exported_names) {
+        // Braces and commas
+        size += 2 + list_overhead(this.exported_names);
+    }
+
+    if (this.module_name) {
+        // "from "
+        size += 5;
+    }
+
+    return size;
+};
+
+AST_Call.prototype._size = function () {
+    if (this.optional) {
+        return 4 + list_overhead(this.args);
+    }
+    return 2 + list_overhead(this.args);
+};
+
+AST_New.prototype._size = function () {
+    return 6 + list_overhead(this.args);
+};
+
+AST_Sequence.prototype._size = function () {
+    return list_overhead(this.expressions);
+};
+
+AST_Dot.prototype._size = function () {
+    if (this.optional) {
+        return this.property.length + 2;
+    }
+    return this.property.length + 1;
+};
+
+AST_DotHash.prototype._size = function () {
+    if (this.optional) {
+        return this.property.length + 3;
+    }
+    return this.property.length + 2;
+};
+
+AST_Sub.prototype._size = function () {
+    return this.optional ? 4 : 2;
+};
+
+AST_Unary.prototype._size = function () {
+    if (this.operator === "typeof") return 7;
+    if (this.operator === "void") return 5;
+    return this.operator.length;
+};
+
+AST_Binary.prototype._size = function (info) {
+    if (this.operator === "in") return 4;
+
+    let size = this.operator.length;
+
+    if (
+        (this.operator === "+" || this.operator === "-")
+        && this.right instanceof AST_Unary && this.right.operator === this.operator
+    ) {
+        // 1+ +a > needs space between the +
+        size += 1;
+    }
+
+    if (this.needs_parens(info)) {
+        size += 2;
+    }
+
+    return size;
+};
+
+AST_Conditional.prototype._size = () => 3;
+
+AST_Array.prototype._size = function () {
+    return 2 + list_overhead(this.elements);
+};
+
+AST_Object.prototype._size = function (info) {
+    let base = 2;
+    if (first_in_statement(info)) {
+        base += 2; // parens
+    }
+    return base + list_overhead(this.properties);
+};
+
+/*#__INLINE__*/
+const key_size = key =>
+    typeof key === "string" ? key.length : 0;
+
+AST_ObjectKeyVal.prototype._size = function () {
+    return key_size(this.key) + 1;
+};
+
+/*#__INLINE__*/
+const static_size = is_static => is_static ? 7 : 0;
+
+AST_ObjectGetter.prototype._size = function () {
+    return 5 + static_size(this.static) + key_size(this.key);
+};
+
+AST_ObjectSetter.prototype._size = function () {
+    return 5 + static_size(this.static) + key_size(this.key);
+};
+
+AST_ConciseMethod.prototype._size = function () {
+    return static_size(this.static) + key_size(this.key);
+};
+
+AST_PrivateMethod.prototype._size = function () {
+    return AST_ConciseMethod.prototype._size.call(this) + 1;
+};
+
+AST_PrivateGetter.prototype._size = function () {
+    return AST_ConciseMethod.prototype._size.call(this) + 4;
+};
+
+AST_PrivateSetter.prototype._size = function () {
+    return AST_ConciseMethod.prototype._size.call(this) + 4;
+};
+
+AST_PrivateIn.prototype._size = function () {
+    return 5; // "#", and " in "
+};
+
+AST_Class.prototype._size = function () {
+    return (
+        (this.name ? 8 : 7)
+        + (this.extends ? 8 : 0)
+    );
+};
+
+AST_ClassStaticBlock.prototype._size = function () {
+    // "static{}" + semicolons
+    return 8 + list_overhead(this.body);
+};
+
+AST_ClassProperty.prototype._size = function () {
+    return (
+        static_size(this.static)
+        + (typeof this.key === "string" ? this.key.length + 2 : 0)
+        + (this.value ? 1 : 0)
+    );
+};
+
+AST_ClassPrivateProperty.prototype._size = function () {
+    return AST_ClassProperty.prototype._size.call(this) + 1;
+};
+
+AST_Symbol.prototype._size = function () {
+    if (!(mangle_options && this.thedef && !this.thedef.unmangleable(mangle_options))) {
+        return this.name.length;
+    } else {
+        return 1;
+    }
+};
+
+// TODO take propmangle into account
+AST_SymbolClassProperty.prototype._size = function () {
+    return this.name.length;
+};
+
+AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () {
+    if (this.name === "arguments") return 9;
+
+    return AST_Symbol.prototype._size.call(this);
+};
+
+AST_NewTarget.prototype._size = () => 10;
+
+AST_SymbolImportForeign.prototype._size = function () {
+    return this.name.length;
+};
+
+AST_SymbolExportForeign.prototype._size = function () {
+    return this.name.length;
+};
+
+AST_This.prototype._size = () => 4;
+
+AST_Super.prototype._size = () => 5;
+
+AST_String.prototype._size = function () {
+    return this.value.length + 2;
+};
+
+AST_Number.prototype._size = function () {
+    const { value } = this;
+    if (value === 0) return 1;
+    if (value > 0 && Math.floor(value) === value) {
+        return Math.floor(Math.log10(value) + 1);
+    }
+    return value.toString().length;
+};
+
+AST_BigInt.prototype._size = function () {
+    return this.value.length;
+};
+
+AST_RegExp.prototype._size = function () {
+    return this.value.toString().length;
+};
+
+AST_Null.prototype._size = () => 4;
+
+AST_NaN.prototype._size = () => 3;
+
+AST_Undefined.prototype._size = () => 6; // "void 0"
+
+AST_Hole.prototype._size = () => 0;  // comma is taken into account by list_overhead()
+
+AST_Infinity.prototype._size = () => 8;
+
+AST_True.prototype._size = () => 4;
+
+AST_False.prototype._size = () => 5;
+
+AST_Await.prototype._size = () => 6;
+
+AST_Yield.prototype._size = () => 6;
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// bitfield flags to be stored in node.flags.
+// These are set and unset during compression, and store information in the node without requiring multiple fields.
+const UNUSED = 0b00000001;
+const TRUTHY = 0b00000010;
+const FALSY = 0b00000100;
+const UNDEFINED = 0b00001000;
+const INLINED = 0b00010000;
+// Nodes to which values are ever written. Used when keep_assign is part of the unused option string.
+const WRITE_ONLY = 0b00100000;
+
+// information specific to a single compression pass
+const SQUEEZED = 0b0000000100000000;
+const OPTIMIZED = 0b0000001000000000;
+const TOP = 0b0000010000000000;
+const CLEAR_BETWEEN_PASSES = SQUEEZED | OPTIMIZED | TOP;
+
+const has_flag = (node, flag) => node.flags & flag;
+const set_flag = (node, flag) => { node.flags |= flag; };
+const clear_flag = (node, flag) => { node.flags &= ~flag; };
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function merge_sequence(array, node) {
+    if (node instanceof AST_Sequence) {
+        array.push(...node.expressions);
+    } else {
+        array.push(node);
+    }
+    return array;
+}
+
+function make_sequence(orig, expressions) {
+    if (expressions.length == 1) return expressions[0];
+    if (expressions.length == 0) throw new Error("trying to create a sequence with length zero!");
+    return make_node(AST_Sequence, orig, {
+        expressions: expressions.reduce(merge_sequence, [])
+    });
+}
+
+function make_empty_function(self) {
+    return make_node(AST_Function, self, {
+        uses_arguments: false,
+        argnames: [],
+        body: [],
+        is_generator: false,
+        async: false,
+        variables: new Map(),
+        uses_with: false,
+        uses_eval: false,
+        parent_scope: null,
+        enclosed: [],
+        cname: 0,
+        block_scope: undefined,
+    });
+}
+
+function make_node_from_constant(val, orig) {
+    switch (typeof val) {
+      case "string":
+        return make_node(AST_String, orig, {
+            value: val
+        });
+      case "number":
+        if (isNaN(val)) return make_node(AST_NaN, orig);
+        if (isFinite(val)) {
+            return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, {
+                operator: "-",
+                expression: make_node(AST_Number, orig, { value: -val })
+            }) : make_node(AST_Number, orig, { value: val });
+        }
+        return val < 0 ? make_node(AST_UnaryPrefix, orig, {
+            operator: "-",
+            expression: make_node(AST_Infinity, orig)
+        }) : make_node(AST_Infinity, orig);
+      case "bigint":
+        return make_node(AST_BigInt, orig, { value: val.toString() });
+      case "boolean":
+        return make_node(val ? AST_True : AST_False, orig);
+      case "undefined":
+        return make_void_0(orig);
+      default:
+        if (val === null) {
+            return make_node(AST_Null, orig, { value: null });
+        }
+        if (val instanceof RegExp) {
+            return make_node(AST_RegExp, orig, {
+                value: {
+                    source: regexp_source_fix(val.source),
+                    flags: val.flags
+                }
+            });
+        }
+        throw new Error(string_template("Can't handle constant of type: {type}", {
+            type: typeof val
+        }));
+    }
+}
+
+function best_of_expression(ast1, ast2) {
+    return ast1.size() > ast2.size() ? ast2 : ast1;
+}
+
+function best_of_statement(ast1, ast2) {
+    return best_of_expression(
+        make_node(AST_SimpleStatement, ast1, {
+            body: ast1
+        }),
+        make_node(AST_SimpleStatement, ast2, {
+            body: ast2
+        })
+    ).body;
+}
+
+/** Find which node is smaller, and return that */
+function best_of(compressor, ast1, ast2) {
+    if (first_in_statement(compressor)) {
+        return best_of_statement(ast1, ast2);
+    } else {
+        return best_of_expression(ast1, ast2);
+    }
+}
+
+/** Simplify an object property's key, if possible */
+function get_simple_key(key) {
+    if (key instanceof AST_Constant) {
+        return key.getValue();
+    }
+    if (key instanceof AST_UnaryPrefix
+        && key.operator == "void"
+        && key.expression instanceof AST_Constant) {
+        return undefined;
+    }
+    return key;
+}
+
+function read_property(obj, key) {
+    key = get_simple_key(key);
+    if (key instanceof AST_Node) return;
+
+    var value;
+    if (obj instanceof AST_Array) {
+        var elements = obj.elements;
+        if (key == "length") return make_node_from_constant(elements.length, obj);
+        if (typeof key == "number" && key in elements) value = elements[key];
+    } else if (obj instanceof AST_Object) {
+        key = "" + key;
+        var props = obj.properties;
+        for (var i = props.length; --i >= 0;) {
+            var prop = props[i];
+            if (!(prop instanceof AST_ObjectKeyVal)) return;
+            if (!value && props[i].key === key) value = props[i].value;
+        }
+    }
+
+    return value instanceof AST_SymbolRef && value.fixed_value() || value;
+}
+
+function has_break_or_continue(loop, parent) {
+    var found = false;
+    var tw = new TreeWalker(function(node) {
+        if (found || node instanceof AST_Scope) return true;
+        if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) {
+            return found = true;
+        }
+    });
+    if (parent instanceof AST_LabeledStatement) tw.push(parent);
+    tw.push(loop);
+    loop.body.walk(tw);
+    return found;
+}
+
+// we shouldn't compress (1,func)(something) to
+// func(something) because that changes the meaning of
+// the func (becomes lexical instead of global).
+function maintain_this_binding(parent, orig, val) {
+    if (requires_sequence_to_maintain_binding(parent, orig, val)) {
+        const zero = make_node(AST_Number, orig, { value: 0 });
+        return make_sequence(orig, [ zero, val ]);
+    } else {
+        return val;
+    }
+}
+
+/** Detect (1, x.noThis)(), (0, eval)(), which need sequences */
+function requires_sequence_to_maintain_binding(parent, orig, val) {
+    return (
+        parent instanceof AST_UnaryPrefix && parent.operator == "delete"
+        || parent instanceof AST_Call && parent.expression === orig
+            && (
+                val instanceof AST_Chain
+                || val instanceof AST_PropAccess
+                || val instanceof AST_SymbolRef && val.name == "eval"
+            )
+    );
+}
+
+function is_func_expr(node) {
+    return node instanceof AST_Arrow || node instanceof AST_Function;
+}
+
+/**
+ * Used to determine whether the node can benefit from negation.
+ * Not the case with arrow functions (you need an extra set of parens). */
+function is_iife_call(node) {
+    if (node.TYPE != "Call") return false;
+    return node.expression instanceof AST_Function || is_iife_call(node.expression);
+}
+
+function is_empty(thing) {
+    if (thing === null) return true;
+    if (thing instanceof AST_EmptyStatement) return true;
+    if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
+    return false;
+}
+
+const identifier_atom = makePredicate("Infinity NaN undefined");
+function is_identifier_atom(node) {
+    return node instanceof AST_Infinity
+        || node instanceof AST_NaN
+        || node instanceof AST_Undefined;
+}
+
+/** Check if this is a SymbolRef node which has one def of a certain AST type */
+function is_ref_of(ref, type) {
+    if (!(ref instanceof AST_SymbolRef)) return false;
+    var orig = ref.definition().orig;
+    for (var i = orig.length; --i >= 0;) {
+        if (orig[i] instanceof type) return true;
+    }
+}
+
+/**Can we turn { block contents... } into just the block contents ?
+ * Not if one of these is inside.
+ **/
+function can_be_evicted_from_block(node) {
+    return !(
+        node instanceof AST_DefClass ||
+        node instanceof AST_Defun ||
+        node instanceof AST_Let ||
+        node instanceof AST_Const ||
+        node instanceof AST_Using ||
+        node instanceof AST_Export ||
+        node instanceof AST_Import
+    );
+}
+
+function as_statement_array(thing) {
+    if (thing === null) return [];
+    if (thing instanceof AST_BlockStatement) return thing.body;
+    if (thing instanceof AST_EmptyStatement) return [];
+    if (thing instanceof AST_Statement) return [ thing ];
+    throw new Error("Can't convert thing to statement array");
+}
+
+function is_reachable(scope_node, defs) {
+    const find_ref = node => {
+        if (node instanceof AST_SymbolRef && defs.includes(node.definition())) {
+            return walk_abort;
+        }
+    };
+
+    return walk_parent(scope_node, (node, info) => {
+        if (node instanceof AST_Scope && node !== scope_node) {
+            var parent = info.parent();
+
+            if (
+                parent instanceof AST_Call
+                && parent.expression === node
+                // Async/Generators aren't guaranteed to sync evaluate all of
+                // their body steps, so it's possible they close over the variable.
+                && !(node.async || node.is_generator)
+            ) {
+                return;
+            }
+
+            if (walk(node, find_ref)) return walk_abort;
+
+            return true;
+        }
+    });
+}
+
+/** Check if a ref refers to the name of a function/class it's defined within */
+function is_recursive_ref(tw, def) {
+    var node;
+    for (var i = 0; node = tw.parent(i); i++) {
+        if (node instanceof AST_Lambda || node instanceof AST_Class) {
+            var name = node.name;
+            if (name && name.definition() === def) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// TODO this only works with AST_Defun, shouldn't it work for other ways of defining functions?
+function retain_top_func(fn, compressor) {
+    return compressor.top_retain
+        && fn instanceof AST_Defun
+        && has_flag(fn, TOP)
+        && fn.name
+        && compressor.top_retain(fn.name.definition());
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// Lists of native methods, useful for `unsafe` option which assumes they exist.
+// Note: Lots of methods and functions are missing here, in case they aren't pure
+// or not available in all JS environments.
+
+const make_nested_lookup = (feature_callback) => (compressor) => {
+    const obj = feature_callback(feature_variables(compressor));
+
+    const out = new Map();
+    for (var key of Object.keys(obj)) {
+        if (obj[key]) {
+            out.set(key, makePredicate(remove_false(obj[key])));
+        }
+    }
+
+    const does_have = (global_name, fname) => {
+        const inner_map = out.get(global_name);
+        return inner_map != null && inner_map.has(fname);
+    };
+    return does_have;
+};
+
+const make_lookup = (feature_callback) => (compressor) => {
+    const obj = feature_callback(feature_variables(compressor));
+
+    const predicate = makePredicate(remove_false(obj));
+    const does_have = (global_name) => {
+        return predicate.has(global_name);
+    };
+    return does_have;
+};
+
+function remove_false(arr) {
+    for (let i = 0; i < arr.length; i++) {
+        if (arr[i] === false) {
+            arr.splice(i, 1);
+            i--;
+        }
+    }
+    return arr;
+}
+
+/** Generate the object with arguments seen below */
+function feature_variables(compressor) {
+    return {
+        sloppy: compressor.option("unsafe"),
+        es: compressor.option("builtins_ecma"),
+    };
+}
+
+// eslint-disable-next-line no-unused-vars
+const pure_access_globals = make_lookup(({ sloppy, es }) => [
+    "Array",
+    "Boolean",
+    "clearInterval",
+    "clearTimeout",
+    "console",
+    "Date",
+    "decodeURI",
+    "decodeURIComponent",
+    "encodeURI",
+    "encodeURIComponent",
+    "Error",
+    "escape",
+    "eval",
+    "EvalError",
+    "Function",
+    es >= 2020 && "globalThis",
+    "isFinite",
+    "isNaN",
+    "JSON",
+    "Math",
+    "Number",
+    "parseFloat",
+    "parseInt",
+    "RangeError",
+    "ReferenceError",
+    "RegExp",
+    "Object",
+    "setInterval",
+    "setTimeout",
+    "String",
+    "SyntaxError",
+    "TypeError",
+    "unescape",
+    "URIError",
+]);
+
+// Objects which are safe to access without throwing or causing a side effect.
+// Usually we'd check the `unsafe` option first but these are way too common for that
+const pure_prop_access_globals = new Set([
+    "Number",
+    "String",
+    "Array",
+    "Object",
+    "Function",
+    "Promise",
+]);
+
+// eslint-disable-next-line no-unused-vars
+const is_pure_native_fn = make_lookup(({ sloppy, es }) => [
+    sloppy && es >= 2021 && "AggregateError",
+    "Array",
+    "ArrayBuffer",
+    es >= 2020 && "BigInt",
+    es >= 2020 && "BigInt64Array",
+    es >= 2020 && "BigUint64Array",
+    "Boolean",
+    "Date",
+    sloppy && "decodeURI",
+    sloppy && "decodeURIComponent",
+    sloppy && "encodeURI",
+    sloppy && "encodeURIComponent",
+    "Error",
+    "escape",
+    "EvalError",
+    es >= 2021 && "FinalizationRegistry",
+    es >= 2026 && "Float16Array",
+    "Float32Array",
+    "Float64Array",
+    "Int16Array",
+    "Int32Array",
+    "Int8Array",
+    "isFinite",
+    "isNaN",
+    es >= 2026 && "Iterator",
+    es >= 2015 && "Map",
+    "Number",
+    "parseFloat",
+    "parseInt",
+    es >= 2015 && "Promise",
+    es >= 2015 && "Proxy",
+    "RangeError",
+    "ReferenceError",
+    sloppy && "RegExp",
+    es >= 2015 && "Set",
+    "String",
+    es >= 2015 && "Symbol",
+    "SyntaxError",
+    "TypeError",
+    "Uint16Array",
+    "Uint32Array",
+    "Uint8Array",
+    "Uint8ClampedArray",
+    sloppy && "unescape",
+    "URIError",
+    sloppy && es >= 2015 && "WeakMap",
+    sloppy && es >= 2021 && "WeakRef",
+    sloppy && es >= 2015 && "WeakSet",
+]);
+
+const arg1_is_iterable = new Set([
+    "Map",
+    "Set",
+    "WeakMap",
+    "WeakSet",
+]);
+const arg1_is_range_or_iterable = new Set([
+    "ArrayBuffer",
+    "Float32Array",
+    "Float64Array",
+    "Int16Array",
+    "Int32Array",
+    "Int8Array",
+    "Uint16Array",
+    "Uint32Array",
+    "Uint8Array",
+    "Uint8ClampedArray",
+]);
+const lone_arg_is_range = new Set(["Array"]);
+
+const object_methods = [
+    "constructor",
+    "toString",
+    "valueOf",
+];
+
+// eslint-disable-next-line no-unused-vars
+const is_pure_native_method = make_nested_lookup(({ sloppy, es }) => ({
+    Array: [
+        es >= 2022 && "at",
+        es >= 2019 && "flat",
+        es >= 2016 && "includes",
+        "indexOf",
+        "join",
+        "lastIndexOf",
+        "slice",
+        ...object_methods,
+    ],
+    Boolean: object_methods,
+    Function: object_methods,
+    Number: [
+        "toExponential",
+        "toFixed",
+        "toPrecision",
+        ...object_methods,
+    ],
+    Object: object_methods,
+    RegExp: [
+        "test",
+        ...object_methods,
+    ],
+    String: [
+        es >= 2022 && "at",
+        "charAt",
+        "charCodeAt",
+        es >= 2015 && "codePointAt",
+        "concat",
+        es >= 2025 && "endsWith",
+        es >= 2015 && "includes",
+        "indexOf",
+        "italics",
+        "lastIndexOf",
+        es >= 2020 && "localeCompare",
+        "match",
+        es >= 2020 && "matchAll",
+        es >= 2015 && "normalize",
+        es >= 2017 && "padStart",
+        es >= 2017 && "padEnd",
+        es >= 2015 && sloppy && "repeat",
+        "replace",
+        es >= 2021 && "replaceAll",
+        "search",
+        "slice",
+        "split",
+        es >= 2015 && "startsWith",
+        "substr",
+        "substring",
+        es >= 2015 && "repeat",
+        "toLocaleLowerCase",
+        "toLocaleUpperCase",
+        "toLowerCase",
+        "toUpperCase",
+        "trim",
+        es >= 2019 && "trimEnd",
+        es >= 2019 && "trimStart",
+        es >= 2019 && "trimLeft",
+        es >= 2019 && "trimRight",
+        ...object_methods,
+    ],
+}));
+
+// eslint-disable-next-line no-unused-vars
+const is_pure_native_static_fn = make_nested_lookup(({ sloppy, es }) => ({
+    Array: [
+        "isArray",
+        es >= 2015 && "of",
+    ],
+    ArrayBuffer: [
+        "isView",
+    ],
+    BigInt: es >= 2020 && [
+        sloppy && "asIntN",
+        sloppy && "asUintN",
+    ],
+    BigInt64Array: sloppy && es >= 2020 && ["of"],
+    BigUint64Array: sloppy && es >= 2020 && ["of"],
+    Date: [
+        "now",
+        "parse",
+        "UTC",
+    ],
+    Error: [
+        es >= 2026 && "isError",
+    ],
+    Float16Array: sloppy && es >= 2026 && ["of"],
+    Float32Array: sloppy && ["of"],
+    Float64Array: sloppy && ["of"],
+    Int16Array: sloppy && ["of"],
+    Int32Array: sloppy && ["of"],
+    Int8Array: sloppy && ["of"],
+    Math: [
+        "abs",
+        "acos",
+        es >= 2015 && "acosh",
+        "asin",
+        es >= 2015 && "asinh",
+        "atan",
+        "atan2",
+        es >= 2015 && "atanh",
+        es >= 2015 && "cbrt",
+        "ceil",
+        es >= 2015 && "clz32",
+        "cos",
+        es >= 2015 && "cosh",
+        "exp",
+        es >= 2015 && "expm1",
+        "floor",
+        es >= 2026 && "f16round",
+        es >= 2015 && "fround",
+        es >= 2015 && "hypot",
+        es >= 2015 && "imul",
+        "log",
+        es >= 2015 && "log10",
+        es >= 2015 && "log1p",
+        es >= 2015 && "log2",
+        "max",
+        "min",
+        "pow",
+        "round",
+        es >= 2015 && "sign",
+        "sin",
+        es >= 2015 && "sinh",
+        "sqrt",
+        "tan",
+        es >= 2015 && "tanh",
+        es >= 2015 && "trunc",
+    ],
+    Number: [
+        es >= 2015 && "isFinite",
+        es >= 2015 && "isInteger",
+        es >= 2015 && "isSafeInteger",
+        es >= 2015 && "isNaN",
+        es >= 2015 && "parseFloat",
+        es >= 2015 && "parseInt",
+    ],
+    Object: [
+        sloppy && "create",
+        sloppy && "getOwnPropertyDescriptor",
+        es >= 2017 && sloppy && "getOwnPropertyDescriptors",
+        sloppy && "getOwnPropertyNames",
+        es >= 2015 && sloppy && "getOwnPropertySymbols",
+        sloppy && "getPrototypeOf",
+        es >= 2022 && sloppy && "hasOwn",
+        es >= 2015 && "is",
+        "isExtensible",
+        "isFrozen",
+        "isSealed",
+        es >= 2015 && sloppy && "keys",
+    ],
+    Promise: es >= 2015 && [
+        es >= 2024 && "withResolvers",
+    ],
+    Proxy: es >= 2015 && [
+        sloppy && "revocable",
+    ],
+    Reflect: es >= 2015 && [
+        sloppy && "has",
+        sloppy && "isExtensible",
+        sloppy && "ownKeys",
+    ],
+    RegExp: [
+        es >= 2026 && sloppy && "escape",
+    ],
+    String: [
+        "fromCharCode",
+        sloppy && es >= 2025 && "fromCodePoint",
+    ],
+    Uint16Array: ["of"],
+    Uint32Array: ["of"],
+    Uint8Array: ["of"],
+    Uint8ClampedArray: ["of"],
+}));
+
+// Known numeric values which come with JS environments
+// eslint-disable-next-line no-unused-vars
+const is_pure_native_static_property = make_nested_lookup(({ sloppy, es }) => ({
+    Math: [
+        "E",
+        "LN10",
+        "LN2",
+        "LOG2E",
+        "LOG10E",
+        "PI",
+        "SQRT1_2",
+        "SQRT2",
+    ],
+    Number: [
+        es >= 2015 && "EPSILON",
+        es >= 2015 && "MAX_SAFE_VALUE",
+        "MAX_VALUE",
+        es >= 2015 && "MIN_SAFE_VALUE",
+        "MIN_VALUE",
+        "NaN",
+        "NEGATIVE_INFINITY",
+        "POSITIVE_INFINITY",
+    ],
+    RegExp: [
+        "$_",
+        "$0",
+        "$1",
+        "$2",
+        "$3",
+        "$4",
+        "$5",
+        "$6",
+        "$7",
+        "$8",
+        "$9",
+        "input",
+        "lastMatch",
+        "lastParen",
+        "leftContext",
+        "rightContext",
+    ],
+}));
+
+const re_uppercase_first_letter = /^[A-Z]/;
+function is_pure_builtin_call(compressor, call) {
+    let builtin = "";
+    let method = "";
+
+    let exp = call.expression;
+    if (is_undeclared_ref(exp)) {
+        builtin = exp.name;
+    } else if (exp instanceof AST_Dot) {
+        method = exp.property;
+
+        exp = exp.expression;
+        if (is_undeclared_ref(exp)) {
+            if (
+                // globalThis.pureFunc()
+                exp.name === "globalThis"
+                && compressor.option("builtins_ecma") >= 2020
+            ) {
+                builtin = method;
+                method = "";
+            } else {
+                // SomeBuiltin.pureFunc()
+                builtin = exp.name;
+            }
+        } else if (exp instanceof AST_Dot) {
+            if (
+                is_undeclared_ref(exp.expression)
+                && exp.expression.name === "globalThis"
+                && compressor.option("builtins_ecma") >= 2020
+            ) {
+                // globalThis.SomeBuiltin.pureFunc()
+                builtin = exp.property;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    } else {
+        return false;
+    }
+
+    if (!method) {
+        if (compressor.is_pure_native_fn(builtin)) {
+            // some require `new`, others throw if you use it
+            const is_new = call instanceof AST_New;
+            const should_be_new = re_uppercase_first_letter.test(builtin); // true of all `is_pure_native_fn`
+            if (is_new !== should_be_new) return false;
+
+            if (!is_builtin_pure_with_these_args(builtin, call.args)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        return false;
+    } else {
+        return compressor.is_pure_native_static_fn(builtin, method);
+    }
+}
+
+/** Some builtins are listed above but their purity is subject to some conditions */
+function is_builtin_pure_with_these_args(builtin, args) {
+    // all the builtins we deal with here are ok with getting 0 args
+    if (args.length === 0) return true;
+
+    let arg1 = args[0];
+    if (arg1 instanceof AST_SymbolRef) {
+        arg1 = arg1.fixed_value();
+    }
+
+    if (lone_arg_is_range.has(builtin)) { // new Array(number)
+        const arg_valid = args.length > 1
+            || arg1 instanceof AST_Number
+                && arg1.value >= 0 && arg1.value <= 0xffffffff;
+            // TODO: or, we are asked to ignore TypeError
+        if (!arg_valid) return false;
+    }
+
+    if (arg1_is_range_or_iterable.has(builtin)) { // new Float32Array(number | Array)
+        const arg_valid = args.length === 0
+            || arg1 instanceof AST_Array
+            || arg1 instanceof AST_Number
+                && arg1.value >= 0 && arg1.value <= 0xffffffff;
+        if (!arg_valid) return false;
+    }
+
+    if (arg1_is_iterable.has(builtin)) { // new Set(iterable)
+        const arg_valid = args.length === 0 || arg1 instanceof AST_Array;
+        if (!arg_valid) return false;
+    }
+
+    return true;
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// Functions and methods to infer certain facts about expressions
+// It's not always possible to be 100% sure about something just by static analysis,
+// so `true` means yes, and `false` means maybe
+
+const is_undeclared_ref = (node) =>
+    node instanceof AST_SymbolRef && node.definition().undeclared;
+
+const bitwise_binop = makePredicate("<<< >> << & | ^ ~");
+const lazy_op = makePredicate("&& || ??");
+const unary_side_effects = makePredicate("delete ++ --");
+
+// methods to determine whether an expression has a boolean result type
+(function(def_is_boolean) {
+    const unary_bool = makePredicate("! delete");
+    const binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
+    def_is_boolean(AST_Node, return_false);
+    def_is_boolean(AST_UnaryPrefix, function() {
+        return unary_bool.has(this.operator);
+    });
+    def_is_boolean(AST_Binary, function() {
+        return binary_bool.has(this.operator)
+            || lazy_op.has(this.operator)
+                && this.left.is_boolean()
+                && this.right.is_boolean();
+    });
+    def_is_boolean(AST_Conditional, function() {
+        return this.consequent.is_boolean() && this.alternative.is_boolean();
+    });
+    def_is_boolean(AST_Assign, function() {
+        return this.operator == "=" && this.right.is_boolean();
+    });
+    def_is_boolean(AST_Sequence, function() {
+        return this.tail_node().is_boolean();
+    });
+    def_is_boolean(AST_True, return_true);
+    def_is_boolean(AST_False, return_true);
+})(function(node, func) {
+    node.DEFMETHOD("is_boolean", func);
+});
+
+// methods to determine if an expression has a numeric result type
+(function(def_is_number) {
+    def_is_number(AST_Node, return_false);
+    def_is_number(AST_Number, return_true);
+    const unary = makePredicate("+ - ~ ++ --");
+    def_is_number(AST_Unary, function(compressor) {
+        return unary.has(this.operator) && this.expression.is_number(compressor);
+    });
+    const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
+    def_is_number(AST_Binary, function(compressor) {
+        if (this.operator === "+") {
+            // Both sides need to be `number`. Or one is a `number` and the other is number-ish.
+            return this.left.is_number(compressor) && this.right.is_number_or_bigint(compressor)
+                || this.right.is_number(compressor) && this.left.is_number_or_bigint(compressor);
+        } else if (numeric_ops.has(this.operator)) {
+            return this.left.is_number(compressor) || this.right.is_number(compressor);
+        } else {
+            return false;
+        }
+    });
+    def_is_number(AST_Assign, function(compressor) {
+        return (this.operator === "=" || numeric_ops.has(this.operator.slice(0, -1)))
+            && this.right.is_number(compressor);
+    });
+    def_is_number(AST_Sequence, function(compressor) {
+        return this.tail_node().is_number(compressor);
+    });
+    def_is_number(AST_Conditional, function(compressor) {
+        return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("is_number", func);
+});
+
+// methods to determine if an expression returns a BigInt
+(function(def_is_bigint) {
+    def_is_bigint(AST_Node, return_false);
+    def_is_bigint(AST_BigInt, return_true);
+    const unary = makePredicate("+ - ~ ++ --");
+    def_is_bigint(AST_Unary, function(compressor) {
+        return unary.has(this.operator) && this.expression.is_bigint(compressor);
+    });
+    const numeric_ops = makePredicate("- * / % & | ^ << >>");
+    def_is_bigint(AST_Binary, function(compressor) {
+        if (this.operator === "+") {
+            return this.left.is_bigint(compressor) && this.right.is_number_or_bigint(compressor)
+                || this.right.is_bigint(compressor) && this.left.is_number_or_bigint(compressor);
+        } else if (numeric_ops.has(this.operator)) {
+            return this.left.is_bigint(compressor) || this.right.is_bigint(compressor);
+        } else {
+            return false;
+        }
+    });
+    def_is_bigint(AST_Assign, function(compressor) {
+        return (numeric_ops.has(this.operator.slice(0, -1)) || this.operator == "=")
+            && this.right.is_bigint(compressor);
+    });
+    def_is_bigint(AST_Sequence, function(compressor) {
+        return this.tail_node().is_bigint(compressor);
+    });
+    def_is_bigint(AST_Conditional, function(compressor) {
+        return this.consequent.is_bigint(compressor) && this.alternative.is_bigint(compressor);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("is_bigint", func);
+});
+
+// methods to determine if an expression is a number or a bigint
+(function(def_is_number_or_bigint) {
+    def_is_number_or_bigint(AST_Node, return_false);
+    def_is_number_or_bigint(AST_Number, return_true);
+    def_is_number_or_bigint(AST_BigInt, return_true);
+    const numeric_unary_ops = makePredicate("+ - ~ ++ --");
+    def_is_number_or_bigint(AST_Unary, function(_compressor) {
+        return numeric_unary_ops.has(this.operator);
+    });
+    const numeric_ops = makePredicate("- * / % & | ^ << >>");
+    def_is_number_or_bigint(AST_Binary, function(compressor) {
+        return this.operator === "+"
+            ? this.left.is_number_or_bigint(compressor) && this.right.is_number_or_bigint(compressor)
+            : numeric_ops.has(this.operator);
+    });
+    def_is_number_or_bigint(AST_Assign, function(compressor) {
+        return numeric_ops.has(this.operator.slice(0, -1))
+            || this.operator == "=" && this.right.is_number_or_bigint(compressor);
+    });
+    def_is_number_or_bigint(AST_Sequence, function(compressor) {
+        return this.tail_node().is_number_or_bigint(compressor);
+    });
+    def_is_number_or_bigint(AST_Conditional, function(compressor) {
+        return this.consequent.is_number_or_bigint(compressor) && this.alternative.is_number_or_bigint(compressor);
+    });
+}(function (node, func) {
+    node.DEFMETHOD("is_number_or_bigint", func);
+}));
+
+
+// methods to determine if an expression is a 32 bit integer (IE results from bitwise ops, or is an integer constant fitting in that size
+(function(def_is_32_bit_integer) {
+    def_is_32_bit_integer(AST_Node, return_false);
+    def_is_32_bit_integer(AST_Number, function(_compressor) {
+        return this.value === (this.value | 0);
+    });
+    def_is_32_bit_integer(AST_UnaryPrefix, function(compressor) {
+        return this.operator == "~" ? this.expression.is_number(compressor)
+            : this.operator === "+" ? this.expression.is_32_bit_integer(compressor)
+            : false;
+    });
+    def_is_32_bit_integer(AST_Binary, function(compressor) {
+        return bitwise_binop.has(this.operator)
+            && (this.left.is_number(compressor) || this.right.is_number(compressor));
+    });
+}(function (node, func) {
+    node.DEFMETHOD("is_32_bit_integer", func);
+}));
+
+// methods to determine if an expression has a string result type
+(function(def_is_string) {
+    def_is_string(AST_Node, return_false);
+    def_is_string(AST_String, return_true);
+    def_is_string(AST_TemplateString, return_true);
+    def_is_string(AST_UnaryPrefix, function() {
+        return this.operator == "typeof";
+    });
+    def_is_string(AST_Binary, function(compressor) {
+        return this.operator == "+" &&
+            (this.left.is_string(compressor) || this.right.is_string(compressor));
+    });
+    def_is_string(AST_Assign, function(compressor) {
+        return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
+    });
+    def_is_string(AST_Sequence, function(compressor) {
+        return this.tail_node().is_string(compressor);
+    });
+    def_is_string(AST_Conditional, function(compressor) {
+        return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("is_string", func);
+});
+
+function is_undefined(node, compressor) {
+    return (
+        has_flag(node, UNDEFINED)
+        || node instanceof AST_Undefined
+        || node instanceof AST_UnaryPrefix
+            && node.operator == "void"
+            && !node.expression.has_side_effects(compressor)
+    );
+}
+
+// Is the node explicitly null or undefined.
+function is_null_or_undefined(node, compressor) {
+    let fixed;
+    return (
+        node instanceof AST_Null
+        || is_undefined(node, compressor)
+        || (
+            node instanceof AST_SymbolRef
+            && (fixed = node.definition().fixed) instanceof AST_Node
+            && is_nullish(fixed, compressor)
+        )
+    );
+}
+
+// Find out if this expression is optionally chained from a base-point that we
+// can statically analyze as null or undefined.
+function is_nullish_shortcircuited(node, compressor) {
+    if (node instanceof AST_PropAccess || node instanceof AST_Call) {
+        return (
+            (node.optional && is_null_or_undefined(node.expression, compressor))
+            || is_nullish_shortcircuited(node.expression, compressor)
+        );
+    }
+    if (node instanceof AST_Chain) return is_nullish_shortcircuited(node.expression, compressor);
+    return false;
+}
+
+// Find out if something is == null, or can short circuit into nullish.
+// Used to optimize ?. and ??
+function is_nullish(node, compressor) {
+    if (is_null_or_undefined(node, compressor)) return true;
+    return is_nullish_shortcircuited(node, compressor);
+}
+
+// Determine if expression might cause side effects
+// If there's a possibility that a node may change something when it's executed, this returns true
+(function(def_has_side_effects) {
+    def_has_side_effects(AST_Node, return_true);
+
+    def_has_side_effects(AST_EmptyStatement, return_false);
+    def_has_side_effects(AST_Constant, return_false);
+    def_has_side_effects(AST_This, return_false);
+
+    function any(list, compressor) {
+        for (var i = list.length; --i >= 0;)
+            if (list[i].has_side_effects(compressor))
+                return true;
+        return false;
+    }
+
+    def_has_side_effects(AST_Block, function(compressor) {
+        return any(this.body, compressor);
+    });
+    def_has_side_effects(AST_Call, function(compressor) {
+        if (
+            !this.is_callee_pure(compressor)
+            && (!this.expression.is_call_pure(compressor)
+                || this.expression.has_side_effects(compressor))
+        ) {
+            return true;
+        }
+        return any(this.args, compressor);
+    });
+    def_has_side_effects(AST_Switch, function(compressor) {
+        return this.expression.has_side_effects(compressor)
+            || any(this.body, compressor);
+    });
+    def_has_side_effects(AST_Case, function(compressor) {
+        return this.expression.has_side_effects(compressor)
+            || any(this.body, compressor);
+    });
+    def_has_side_effects(AST_Try, function(compressor) {
+        return this.body.has_side_effects(compressor)
+            || this.bcatch && this.bcatch.has_side_effects(compressor)
+            || this.bfinally && this.bfinally.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_If, function(compressor) {
+        return this.condition.has_side_effects(compressor)
+            || this.body && this.body.has_side_effects(compressor)
+            || this.alternative && this.alternative.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_ImportMeta, return_false);
+    def_has_side_effects(AST_DynamicImport, function() {
+        // `import.source(x)` only compiles the module, which is side-effect free
+        return this.phase !== "source";
+    });
+    def_has_side_effects(AST_LabeledStatement, function(compressor) {
+        return this.body.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_SimpleStatement, function(compressor) {
+        return this.body.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Lambda, return_false);
+    def_has_side_effects(AST_Class, function (compressor) {
+        if (this.extends && this.extends.has_side_effects(compressor)) {
+            return true;
+        }
+        return any(this.properties, compressor);
+    });
+    def_has_side_effects(AST_ClassStaticBlock, function(compressor) {
+        return any(this.body, compressor);
+    });
+    def_has_side_effects(AST_Binary, function(compressor) {
+        return this.left.has_side_effects(compressor)
+            || this.right.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Assign, return_true);
+    def_has_side_effects(AST_Conditional, function(compressor) {
+        return this.condition.has_side_effects(compressor)
+            || this.consequent.has_side_effects(compressor)
+            || this.alternative.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Unary, function(compressor) {
+        return unary_side_effects.has(this.operator)
+            || this.expression.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_SymbolRef, function(compressor) {
+        return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
+    });
+    def_has_side_effects(AST_SymbolClassProperty, return_false);
+    def_has_side_effects(AST_SymbolDeclaration, return_false);
+    def_has_side_effects(AST_Object, function(compressor) {
+        return any(this.properties, compressor);
+    });
+    def_has_side_effects(AST_ObjectKeyVal, function(compressor) {
+        return (
+            this.computed_key() && this.key.has_side_effects(compressor)
+            || this.value && this.value.has_side_effects(compressor)
+        );
+    });
+    def_has_side_effects([
+        AST_ClassProperty,
+        AST_ClassPrivateProperty,
+    ], function(compressor) {
+        return (
+            this.computed_key() && this.key.has_side_effects(compressor)
+            || this.static && this.value && this.value.has_side_effects(compressor)
+        );
+    });
+    def_has_side_effects([
+        AST_PrivateMethod,
+        AST_PrivateGetter,
+        AST_PrivateSetter,
+        AST_ConciseMethod,
+        AST_ObjectGetter,
+        AST_ObjectSetter,
+    ], function(compressor) {
+        return this.computed_key() && this.key.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Array, function(compressor) {
+        return any(this.elements, compressor);
+    });
+    def_has_side_effects(AST_Dot, function(compressor) {
+        if (is_nullish(this, compressor)) {
+            return this.expression.has_side_effects(compressor);
+        }
+        if (!this.optional && this.expression.may_throw_on_access(compressor)) {
+            return true;
+        }
+
+        return this.expression.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Sub, function(compressor) {
+        if (is_nullish(this, compressor)) {
+            return this.expression.has_side_effects(compressor);
+        }
+        if (!this.optional && this.expression.may_throw_on_access(compressor)) {
+            return true;
+        }
+
+        var property = this.property.has_side_effects(compressor);
+        if (property && this.optional) return true; // "?." is a condition
+
+        return property || this.expression.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Chain, function (compressor) {
+        return this.expression.has_side_effects(compressor);
+    });
+    def_has_side_effects(AST_Sequence, function(compressor) {
+        return any(this.expressions, compressor);
+    });
+    def_has_side_effects(AST_Definitions, function(compressor) {
+        return any(this.definitions, compressor);
+    });
+    def_has_side_effects(AST_VarDef, function() {
+        return this.value != null;
+    });
+    def_has_side_effects(AST_TemplateSegment, return_false);
+    def_has_side_effects(AST_TemplateString, function(compressor) {
+        return any(this.segments, compressor);
+    });
+})(function(node_or_nodes, func) {
+    for (const node of [].concat(node_or_nodes)) {
+        node.DEFMETHOD("has_side_effects", func);
+    }
+});
+
+// determine if expression may throw
+(function(def_may_throw) {
+    def_may_throw(AST_Node, return_true);
+
+    def_may_throw(AST_Constant, return_false);
+    def_may_throw(AST_EmptyStatement, return_false);
+    def_may_throw(AST_Lambda, return_false);
+    def_may_throw(AST_SymbolDeclaration, return_false);
+    def_may_throw(AST_This, return_false);
+    def_may_throw(AST_ImportMeta, return_false);
+
+    function any(list, compressor) {
+        for (var i = list.length; --i >= 0;)
+            if (list[i].may_throw(compressor))
+                return true;
+        return false;
+    }
+
+    def_may_throw(AST_Class, function(compressor) {
+        if (this.extends && this.extends.may_throw(compressor)) return true;
+        return any(this.properties, compressor);
+    });
+    def_may_throw(AST_ClassStaticBlock, function (compressor) {
+        return any(this.body, compressor);
+    });
+
+    def_may_throw(AST_Array, function(compressor) {
+        return any(this.elements, compressor);
+    });
+    def_may_throw(AST_Assign, function(compressor) {
+        if (this.right.may_throw(compressor)) return true;
+        if (!compressor.has_directive("use strict")
+            && this.operator == "="
+            && this.left instanceof AST_SymbolRef) {
+            return false;
+        }
+        return this.left.may_throw(compressor);
+    });
+    def_may_throw(AST_Binary, function(compressor) {
+        return this.left.may_throw(compressor)
+            || this.right.may_throw(compressor);
+    });
+    def_may_throw(AST_Block, function(compressor) {
+        return any(this.body, compressor);
+    });
+    def_may_throw(AST_Call, function(compressor) {
+        if (is_nullish(this, compressor)) return false;
+        if (any(this.args, compressor)) return true;
+        if (this.is_callee_pure(compressor)) return false;
+        if (this.expression.may_throw(compressor)) return true;
+        return !(this.expression instanceof AST_Lambda)
+            || any(this.expression.body, compressor);
+    });
+    def_may_throw(AST_Case, function(compressor) {
+        return this.expression.may_throw(compressor)
+            || any(this.body, compressor);
+    });
+    def_may_throw(AST_Conditional, function(compressor) {
+        return this.condition.may_throw(compressor)
+            || this.consequent.may_throw(compressor)
+            || this.alternative.may_throw(compressor);
+    });
+    def_may_throw(AST_Definitions, function(compressor) {
+        return any(this.definitions, compressor);
+    });
+    def_may_throw(AST_If, function(compressor) {
+        return this.condition.may_throw(compressor)
+            || this.body && this.body.may_throw(compressor)
+            || this.alternative && this.alternative.may_throw(compressor);
+    });
+    def_may_throw(AST_LabeledStatement, function(compressor) {
+        return this.body.may_throw(compressor);
+    });
+    def_may_throw(AST_Object, function(compressor) {
+        return any(this.properties, compressor);
+    });
+    def_may_throw(AST_ObjectKeyVal, function(compressor) {
+        return (
+            this.computed_key() && this.key.may_throw(compressor)
+            || this.value ? this.value.may_throw(compressor) : false
+        );
+    });
+    def_may_throw([
+        AST_ClassProperty,
+        AST_ClassPrivateProperty,
+    ], function(compressor) {
+        return (
+            this.computed_key() && this.key.may_throw(compressor)
+            || this.static && this.value && this.value.may_throw(compressor)
+        );
+    });
+    def_may_throw([
+        AST_ConciseMethod,
+        AST_ObjectGetter,
+        AST_ObjectSetter,
+    ], function(compressor) {
+        return this.computed_key() && this.key.may_throw(compressor);
+    });
+    def_may_throw([
+        AST_PrivateMethod,
+        AST_PrivateGetter,
+        AST_PrivateSetter,
+    ], return_false);
+    def_may_throw(AST_Return, function(compressor) {
+        return this.value && this.value.may_throw(compressor);
+    });
+    def_may_throw(AST_Sequence, function(compressor) {
+        return any(this.expressions, compressor);
+    });
+    def_may_throw(AST_SimpleStatement, function(compressor) {
+        return this.body.may_throw(compressor);
+    });
+    def_may_throw(AST_Dot, function(compressor) {
+        if (is_nullish(this, compressor)) return false;
+        return !this.optional && this.expression.may_throw_on_access(compressor)
+            || this.expression.may_throw(compressor);
+    });
+    def_may_throw(AST_Sub, function(compressor) {
+        if (is_nullish(this, compressor)) return false;
+        return !this.optional && this.expression.may_throw_on_access(compressor)
+            || this.expression.may_throw(compressor)
+            || this.property.may_throw(compressor);
+    });
+    def_may_throw(AST_Chain, function(compressor) {
+        return this.expression.may_throw(compressor);
+    });
+    def_may_throw(AST_Switch, function(compressor) {
+        return this.expression.may_throw(compressor)
+            || any(this.body, compressor);
+    });
+    def_may_throw(AST_SymbolRef, function(compressor) {
+        return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
+    });
+    def_may_throw(AST_SymbolClassProperty, return_false);
+    def_may_throw(AST_Try, function(compressor) {
+        return this.bcatch ? this.bcatch.may_throw(compressor) : this.body.may_throw(compressor)
+            || this.bfinally && this.bfinally.may_throw(compressor);
+    });
+    def_may_throw(AST_Unary, function(compressor) {
+        if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
+            return false;
+        return this.expression.may_throw(compressor);
+    });
+    def_may_throw(AST_VarDef, function(compressor) {
+        if (!this.value) return false;
+        return this.value.may_throw(compressor);
+    });
+})(function(node_or_nodes, func) {
+    for (const node of [].concat(node_or_nodes)) {
+        node.DEFMETHOD("may_throw", func);
+    }
+});
+
+// determine if expression is constant
+(function(def_is_constant_expression) {
+    function all_refs_local(scope) {
+        let result = true;
+        walk(this, node => {
+            if (node instanceof AST_SymbolRef) {
+                if (has_flag(this, INLINED)) {
+                    result = false;
+                    return walk_abort;
+                }
+                var def = node.definition();
+                if (
+                    member(def, this.enclosed)
+                    && !this.variables.has(def.name)
+                ) {
+                    if (scope) {
+                        var scope_def = scope.find_variable(node);
+                        if (def.undeclared ? !scope_def : scope_def === def) {
+                            result = "f";
+                            return true;
+                        }
+                    }
+                    result = false;
+                    return walk_abort;
+                }
+                return true;
+            }
+            if (node instanceof AST_This && this instanceof AST_Arrow) {
+                result = false;
+                return walk_abort;
+            }
+        });
+        return result;
+    }
+
+    def_is_constant_expression(AST_Node, return_false);
+    def_is_constant_expression(AST_Constant, return_true);
+    def_is_constant_expression(AST_Class, function(scope) {
+        if (this.extends && !this.extends.is_constant_expression(scope)) {
+            return false;
+        }
+
+        for (const prop of this.properties) {
+            if (prop.computed_key() && !prop.key.is_constant_expression(scope)) {
+                return false;
+            }
+            if (prop.static && prop.value && !prop.value.is_constant_expression(scope)) {
+                return false;
+            }
+            if (prop instanceof AST_ClassStaticBlock) {
+                return false;
+            }
+        }
+
+        return all_refs_local.call(this, scope);
+    });
+    def_is_constant_expression(AST_Lambda, all_refs_local);
+    def_is_constant_expression(AST_Unary, function() {
+        return this.expression.is_constant_expression();
+    });
+    def_is_constant_expression(AST_Binary, function() {
+        return this.left.is_constant_expression()
+            && this.right.is_constant_expression();
+    });
+    def_is_constant_expression(AST_Array, function() {
+        return this.elements.every((l) => l.is_constant_expression());
+    });
+    def_is_constant_expression(AST_Object, function() {
+        return this.properties.every((l) => l.is_constant_expression());
+    });
+    def_is_constant_expression(AST_ObjectProperty, function() {
+        return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression());
+    });
+})(function(node, func) {
+    node.DEFMETHOD("is_constant_expression", func);
+});
+
+
+// may_throw_on_access()
+// returns true if this node may be null, undefined or contain `AST_Accessor`
+(function(def_may_throw_on_access) {
+    AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
+        return !compressor.option("pure_getters")
+            || this._dot_throw(compressor);
+    });
+
+    function is_strict(compressor) {
+        return /strict/.test(compressor.option("pure_getters"));
+    }
+
+    def_may_throw_on_access(AST_Node, is_strict);
+    def_may_throw_on_access(AST_Null, return_true);
+    def_may_throw_on_access(AST_Undefined, return_true);
+    def_may_throw_on_access(AST_Constant, return_false);
+    def_may_throw_on_access(AST_Array, return_false);
+    def_may_throw_on_access(AST_Object, function(compressor) {
+        if (!is_strict(compressor)) return false;
+        for (var i = this.properties.length; --i >=0;)
+            if (this.properties[i]._dot_throw(compressor)) return true;
+        return false;
+    });
+    // Do not be as strict with classes as we are with objects.
+    // Hopefully the community is not going to abuse static getters and setters.
+    // https://github.com/terser/terser/issues/724#issuecomment-643655656
+    def_may_throw_on_access(AST_Class, return_false);
+    def_may_throw_on_access(AST_ObjectProperty, return_false);
+    def_may_throw_on_access(AST_ObjectGetter, return_true);
+    def_may_throw_on_access(AST_Expansion, function(compressor) {
+        return this.expression._dot_throw(compressor);
+    });
+    def_may_throw_on_access(AST_Function, return_false);
+    def_may_throw_on_access(AST_Arrow, return_false);
+    def_may_throw_on_access(AST_UnaryPostfix, return_false);
+    def_may_throw_on_access(AST_UnaryPrefix, function() {
+        return this.operator == "void";
+    });
+    def_may_throw_on_access(AST_Binary, function(compressor) {
+        return (this.operator == "&&" || this.operator == "||" || this.operator == "??")
+            && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
+    });
+    def_may_throw_on_access(AST_Assign, function(compressor) {
+        if (this.logical) return true;
+
+        return this.operator == "="
+            && this.right._dot_throw(compressor);
+    });
+    def_may_throw_on_access(AST_Conditional, function(compressor) {
+        return this.consequent._dot_throw(compressor)
+            || this.alternative._dot_throw(compressor);
+    });
+    def_may_throw_on_access(AST_Dot, function(compressor) {
+        if (!is_strict(compressor)) return false;
+
+        if (this.property == "prototype") {
+            return !(
+                this.expression instanceof AST_Function
+                || this.expression instanceof AST_Class
+            );
+        }
+        return true;
+    });
+    def_may_throw_on_access(AST_Chain, function(compressor) {
+        return this.expression._dot_throw(compressor);
+    });
+    def_may_throw_on_access(AST_Sequence, function(compressor) {
+        return this.tail_node()._dot_throw(compressor);
+    });
+    def_may_throw_on_access(AST_SymbolRef, function(compressor) {
+        if (this.name === "arguments" && this.scope instanceof AST_Lambda) return false;
+        if (has_flag(this, UNDEFINED)) return true;
+        if (!is_strict(compressor)) return false;
+        if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
+        if (this.is_immutable()) return false;
+        var fixed = this.fixed_value();
+        return !fixed || fixed._dot_throw(compressor);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("_dot_throw", func);
+});
+
+function is_lhs(node, parent) {
+    if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
+    if (parent instanceof AST_Assign && parent.left === node) return node;
+    if (parent instanceof AST_ForIn && parent.init === node) return node;
+}
+
+// method to negate an expression
+(function(def_negate) {
+    function basic_negation(exp) {
+        return make_node(AST_UnaryPrefix, exp, {
+            operator: "!",
+            expression: exp
+        });
+    }
+    function best(orig, alt, first_in_statement) {
+        var negated = basic_negation(orig);
+        if (first_in_statement) {
+            var stat = make_node(AST_SimpleStatement, alt, {
+                body: alt
+            });
+            return best_of_expression(negated, stat) === stat ? alt : negated;
+        }
+        return best_of_expression(negated, alt);
+    }
+    def_negate(AST_Node, function() {
+        return basic_negation(this);
+    });
+    def_negate(AST_Statement, function() {
+        throw new Error("Cannot negate a statement");
+    });
+    def_negate(AST_Function, function() {
+        return basic_negation(this);
+    });
+    def_negate(AST_Class, function() {
+        return basic_negation(this);
+    });
+    def_negate(AST_Arrow, function() {
+        return basic_negation(this);
+    });
+    def_negate(AST_UnaryPrefix, function() {
+        if (this.operator == "!")
+            return this.expression;
+        return basic_negation(this);
+    });
+    def_negate(AST_Sequence, function(compressor) {
+        var expressions = this.expressions.slice();
+        expressions.push(expressions.pop().negate(compressor));
+        return make_sequence(this, expressions);
+    });
+    def_negate(AST_Conditional, function(compressor, first_in_statement) {
+        var self = this.clone();
+        self.consequent = self.consequent.negate(compressor);
+        self.alternative = self.alternative.negate(compressor);
+        return best(this, self, first_in_statement);
+    });
+    def_negate(AST_Binary, function(compressor, first_in_statement) {
+        var self = this.clone(), op = this.operator;
+        if (compressor.option("unsafe_comps")) {
+            switch (op) {
+              case "<=" : self.operator = ">"  ; return self;
+              case "<"  : self.operator = ">=" ; return self;
+              case ">=" : self.operator = "<"  ; return self;
+              case ">"  : self.operator = "<=" ; return self;
+            }
+        }
+        switch (op) {
+          case "==" : self.operator = "!="; return self;
+          case "!=" : self.operator = "=="; return self;
+          case "===": self.operator = "!=="; return self;
+          case "!==": self.operator = "==="; return self;
+          case "&&":
+            self.operator = "||";
+            self.left = self.left.negate(compressor, first_in_statement);
+            self.right = self.right.negate(compressor);
+            return best(this, self, first_in_statement);
+          case "||":
+            self.operator = "&&";
+            self.left = self.left.negate(compressor, first_in_statement);
+            self.right = self.right.negate(compressor);
+            return best(this, self, first_in_statement);
+        }
+        return basic_negation(this);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("negate", function(compressor, first_in_statement) {
+        return func.call(this, compressor, first_in_statement);
+    });
+});
+
+(function (def_bitwise_negate) {
+    function basic_bitwise_negation(exp) {
+        return make_node(AST_UnaryPrefix, exp, {
+            operator: "~",
+            expression: exp
+        });
+    }
+
+    def_bitwise_negate(AST_Node, function(_compressor) {
+        return basic_bitwise_negation(this);
+    });
+
+    def_bitwise_negate(AST_Number, function(_compressor) {
+        const neg = ~this.value;
+        if (neg.toString().length > this.value.toString().length) {
+            return basic_bitwise_negation(this);
+        }
+        return make_node(AST_Number, this, { value: neg });
+    });
+
+    def_bitwise_negate(AST_UnaryPrefix, function(compressor, in_32_bit_context) {
+        if (
+            this.operator == "~"
+            && (
+                this.expression.is_32_bit_integer(compressor) ||
+                (in_32_bit_context != null ? in_32_bit_context : compressor.in_32_bit_context())
+            )
+        ) {
+            return this.expression;
+        } else {
+            return basic_bitwise_negation(this);
+        }
+    });
+})(function (node, func) {
+    node.DEFMETHOD("bitwise_negate", func);
+});
+
+// Is the callee of this function pure?
+var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
+AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
+    if (compressor.option("unsafe")) {
+        var expr = this.expression;
+        var first_arg;
+        if (
+            expr.expression && expr.expression.name === "hasOwnProperty" &&
+            (
+                (first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor))) == null
+                || first_arg.thedef && first_arg.thedef.undeclared
+            )
+        ) {
+            return false;
+        }
+        if (is_undeclared_ref(expr) && global_pure_fns.has(expr.name)) return true;
+        if (is_pure_builtin_call(compressor, this)) return true;
+    } else if (compressor.option("builtins_pure")) {
+        if (is_pure_builtin_call(compressor, this)) return true;
+    }
+    if ((this instanceof AST_New) && compressor.option("pure_new")) {
+        return true;
+    }
+    if (compressor.option("side_effects") && has_annotation(this, _PURE)) {
+        return true;
+    }
+    return !compressor.pure_funcs(this);
+});
+
+// If I call this, is it a pure function?
+AST_Node.DEFMETHOD("is_call_pure", return_false);
+AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
+    if (!compressor.option("unsafe")) return;
+    const expr = this.expression;
+
+    let native_obj;
+    if (expr instanceof AST_Array) {
+        native_obj = "Array";
+    } else if (expr.is_boolean()) {
+        native_obj = "Boolean";
+    } else if (expr.is_number(compressor)) {
+        native_obj = "Number";
+    } else if (expr instanceof AST_RegExp) {
+        native_obj = "RegExp";
+    } else if (expr.is_string(compressor)) {
+        native_obj = "String";
+    } else if (!this.may_throw_on_access(compressor)) {
+        native_obj = "Object";
+    }
+    return native_obj != null && compressor.is_pure_native_method(native_obj, this.property);
+});
+
+// tell me if a statement aborts
+const aborts = (thing) => thing && thing.aborts();
+
+(function(def_aborts) {
+    def_aborts(AST_Statement, return_null);
+    def_aborts(AST_Jump, return_this);
+    function block_aborts() {
+        for (var i = 0; i < this.body.length; i++) {
+            if (aborts(this.body[i])) {
+                return this.body[i];
+            }
+        }
+        return null;
+    }
+    def_aborts(AST_Import, return_null);
+    def_aborts(AST_BlockStatement, block_aborts);
+    def_aborts(AST_SwitchBranch, block_aborts);
+    def_aborts(AST_DefClass, function () {
+        for (const prop of this.properties) {
+            if (prop instanceof AST_ClassStaticBlock) {
+                if (prop.aborts()) return prop;
+            }
+        }
+        return null;
+    });
+    def_aborts(AST_ClassStaticBlock, block_aborts);
+    def_aborts(AST_If, function() {
+        return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
+    });
+})(function(node, func) {
+    node.DEFMETHOD("aborts", func);
+});
+
+AST_Node.DEFMETHOD("contains_this", function() {
+    return walk(this, node => {
+        if (node instanceof AST_This) return walk_abort;
+        if (
+            node !== this
+            && node instanceof AST_Scope
+            && !(node instanceof AST_Arrow)
+        ) {
+            return true;
+        }
+    });
+});
+
+function is_modified(compressor, tw, node, value, level, immutable) {
+    var parent = tw.parent(level);
+    var lhs = is_lhs(node, parent);
+    if (lhs) return lhs;
+    if (!immutable
+        && parent instanceof AST_Call
+        && parent.expression === node
+        && !(value instanceof AST_Arrow)
+        && !(value instanceof AST_Class)
+        && !parent.is_callee_pure(compressor)
+        && (!(value instanceof AST_Function)
+            || !(parent instanceof AST_New) && value.contains_this())) {
+        return true;
+    }
+    if (parent instanceof AST_Array) {
+        return is_modified(compressor, tw, parent, parent, level + 1);
+    }
+    if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
+        var obj = tw.parent(level + 1);
+        return is_modified(compressor, tw, obj, obj, level + 2);
+    }
+    if (parent instanceof AST_PropAccess && parent.expression === node) {
+        var prop = read_property(value, parent.property);
+        return !immutable && is_modified(compressor, tw, parent, prop, level + 1);
+    }
+}
+
+/**
+ * Check if a node may be used by the expression it's in
+ * void (0, 1, {node}, 2) -> false
+ * console.log(0, {node}) -> true
+ */
+function is_used_in_expression(tw) {
+    for (let p = -1, node, parent; node = tw.parent(p), parent = tw.parent(p + 1); p++) {
+        if (parent instanceof AST_Sequence) {
+            const nth_expression = parent.expressions.indexOf(node);
+            if (nth_expression !== parent.expressions.length - 1) {
+                // Detect (0, x.noThis)() constructs
+                const grandparent = tw.parent(p + 2);
+                if (
+                    parent.expressions.length > 2
+                    || parent.expressions.length === 1
+                    || !requires_sequence_to_maintain_binding(grandparent, parent, parent.expressions[1])
+                ) {
+                    return false;
+                }
+                return true;
+            } else {
+                continue;
+            }
+        }
+        if (parent instanceof AST_Unary) {
+            const op = parent.operator;
+            if (op === "void") {
+                return false;
+            }
+            if (op === "typeof" || op === "+" || op === "-" || op === "!" || op === "~") {
+                continue;
+            }
+        }
+        if (
+            parent instanceof AST_SimpleStatement
+            || parent instanceof AST_LabeledStatement
+        ) {
+            return false;
+        }
+        if (parent instanceof AST_Scope) {
+            return false;
+        }
+        return true;
+    }
+
+    return true;
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// methods to evaluate a constant expression
+
+function def_eval(node, func) {
+    node.DEFMETHOD("_eval", func);
+}
+
+// Used to propagate a nullish short-circuit signal upwards through the chain.
+const nullish = Symbol("This AST_Chain is nullish");
+
+// If the node has been successfully reduced to a constant,
+// then its value is returned; otherwise the element itself
+// is returned.
+// They can be distinguished as constant value is never a
+// descendant of AST_Node.
+AST_Node.DEFMETHOD("evaluate", function (compressor) {
+    if (!compressor.option("evaluate"))
+        return this;
+    var val = this._eval(compressor, 1);
+    if (!val || val instanceof RegExp)
+        return val;
+    if (typeof val == "function" || typeof val == "object" || val == nullish)
+        return this;
+
+    // Evaluated strings can be larger than the original expression
+    if (typeof val === "string") {
+        const unevaluated_size = this.size(compressor);
+        if (val.length + 2 > unevaluated_size) return this;
+    }
+
+    return val;
+});
+
+var unaryPrefix = makePredicate("! ~ - + void");
+AST_Node.DEFMETHOD("is_constant", function () {
+    // Accomodate when compress option evaluate=false
+    // as well as the common constant expressions !0 and -1
+    if (this instanceof AST_Constant) {
+        return !(this instanceof AST_RegExp);
+    } else {
+        return this instanceof AST_UnaryPrefix
+            && unaryPrefix.has(this.operator)
+            && (
+                // `this.expression` may be an `AST_RegExp`,
+                // so not only `.is_constant()`.
+                this.expression instanceof AST_Constant
+                || this.expression.is_constant()
+            );
+    }
+});
+
+def_eval(AST_Statement, function () {
+    throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
+});
+
+def_eval(AST_Lambda, return_this);
+def_eval(AST_Class, return_this);
+def_eval(AST_Node, return_this);
+def_eval(AST_Constant, function () {
+    return this.getValue();
+});
+
+const supports_bigint = typeof BigInt === "function";
+def_eval(AST_BigInt, function () {
+    if (supports_bigint) {
+        return BigInt(this.value);
+    } else {
+        return this;
+    }
+});
+
+def_eval(AST_RegExp, function (compressor) {
+    let evaluated = compressor.evaluated_regexps.get(this.value);
+    if (evaluated === undefined && regexp_is_safe(this.value.source)) {
+        try {
+            const { source, flags } = this.value;
+            evaluated = new RegExp(source, flags);
+        } catch (e) {
+            evaluated = null;
+        }
+        compressor.evaluated_regexps.set(this.value, evaluated);
+    }
+    return evaluated || this;
+});
+
+def_eval(AST_TemplateString, function () {
+    if (this.segments.length !== 1) return this;
+    return this.segments[0].value;
+});
+
+def_eval(AST_Function, function (compressor) {
+    if (compressor.option("unsafe")) {
+        var fn = function () { };
+        fn.node = this;
+        fn.toString = () => this.print_to_string();
+        return fn;
+    }
+    return this;
+});
+
+def_eval(AST_Array, function (compressor, depth) {
+    if (compressor.option("unsafe")) {
+        var elements = [];
+        for (var i = 0, len = this.elements.length; i < len; i++) {
+            var element = this.elements[i];
+            var value = element._eval(compressor, depth);
+            if (element === value)
+                return this;
+            elements.push(value);
+        }
+        return elements;
+    }
+    return this;
+});
+
+def_eval(AST_Object, function (compressor, depth) {
+    if (compressor.option("unsafe")) {
+        var val = {};
+        for (var i = 0, len = this.properties.length; i < len; i++) {
+            var prop = this.properties[i];
+            if (prop instanceof AST_Expansion)
+                return this;
+            var key = prop.key;
+            if (key instanceof AST_Symbol) {
+                key = key.name;
+            } else if (key instanceof AST_Node) {
+                key = key._eval(compressor, depth);
+                if (key === prop.key)
+                    return this;
+            }
+            if (typeof Object.prototype[key] === "function") {
+                return this;
+            }
+            if (prop.value instanceof AST_Function)
+                continue;
+            val[key] = prop.value._eval(compressor, depth);
+            if (val[key] === prop.value)
+                return this;
+        }
+        return val;
+    }
+    return this;
+});
+
+var non_converting_unary = makePredicate("! typeof void");
+def_eval(AST_UnaryPrefix, function (compressor, depth) {
+    var e = this.expression;
+    if (compressor.option("typeofs")
+        && this.operator == "typeof") {
+        // Function would be evaluated to an array and so typeof would
+        // incorrectly return 'object'. Hence making is a special case.
+        if (e instanceof AST_Lambda
+            || e instanceof AST_SymbolRef
+            && e.fixed_value() instanceof AST_Lambda) {
+            return typeof function () { };
+        }
+        if (
+            (e instanceof AST_Object
+                || e instanceof AST_Array
+                || (e instanceof AST_SymbolRef
+                    && (e.fixed_value() instanceof AST_Object
+                        || e.fixed_value() instanceof AST_Array)))
+            && !e.has_side_effects(compressor)
+        ) {
+            return typeof {};
+        }
+    }
+    if (!non_converting_unary.has(this.operator))
+        depth++;
+    e = e._eval(compressor, depth);
+    if (e === this.expression)
+        return this;
+    switch (this.operator) {
+        case "!": return !e;
+        case "typeof":
+            // typeof <RegExp> returns "object" or "function" on different platforms
+            // so cannot evaluate reliably
+            if (e instanceof RegExp)
+                return this;
+            return typeof e;
+        case "void": return void e;
+        case "~": return ~e;
+        case "-": return -e;
+        case "+": return +e;
+    }
+    return this;
+});
+
+var non_converting_binary = makePredicate("&& || ?? === !==");
+const identity_comparison = makePredicate("== != === !==");
+const has_identity = value => typeof value === "object"
+    || typeof value === "function"
+    || typeof value === "symbol";
+
+def_eval(AST_Binary, function (compressor, depth) {
+    if (!non_converting_binary.has(this.operator))
+        depth++;
+
+    var left = this.left._eval(compressor, depth);
+    if (left === this.left)
+        return this;
+    var right = this.right._eval(compressor, depth);
+    if (right === this.right)
+        return this;
+
+    if (left != null
+        && right != null
+        && identity_comparison.has(this.operator)
+        && has_identity(left)
+        && has_identity(right)
+        && typeof left === typeof right) {
+        // Do not compare by reference
+        return this;
+    }
+
+    // Do not mix BigInt and Number; Don't use `>>>` on BigInt or `/ 0n`
+    if (
+        (typeof left === "bigint") !== (typeof right === "bigint")
+        || typeof left === "bigint"
+            && (this.operator === ">>>"
+                || this.operator === "/" && Number(right) === 0)
+    ) {
+        return this;
+    }
+
+    var result;
+    switch (this.operator) {
+        case "&&": result = left && right; break;
+        case "||": result = left || right; break;
+        case "??": result = left != null ? left : right; break;
+        case "|": result = left | right; break;
+        case "&": result = left & right; break;
+        case "^": result = left ^ right; break;
+        case "+": result = left + right; break;
+        case "*": result = left * right; break;
+        case "**": result = left ** right; break;
+        case "/": result = left / right; break;
+        case "%": result = left % right; break;
+        case "-": result = left - right; break;
+        case "<<": result = left << right; break;
+        case ">>": result = left >> right; break;
+        case ">>>": result = left >>> right; break;
+        case "==": result = left == right; break;
+        case "===": result = left === right; break;
+        case "!=": result = left != right; break;
+        case "!==": result = left !== right; break;
+        case "<": result = left < right; break;
+        case "<=": result = left <= right; break;
+        case ">": result = left > right; break;
+        case ">=": result = left >= right; break;
+        default:
+            return this;
+    }
+    if (typeof result === "number" && isNaN(result) && compressor.find_parent(AST_With)) {
+        // leave original expression as is
+        return this;
+    }
+    return result;
+});
+
+def_eval(AST_Conditional, function (compressor, depth) {
+    var condition = this.condition._eval(compressor, depth);
+    if (condition === this.condition)
+        return this;
+    var node = condition ? this.consequent : this.alternative;
+    var value = node._eval(compressor, depth);
+    return value === node ? this : value;
+});
+
+// Set of AST_SymbolRef which are currently being evaluated.
+// Avoids infinite recursion of ._eval()
+const reentrant_ref_eval = new Set();
+def_eval(AST_SymbolRef, function (compressor, depth) {
+    if (reentrant_ref_eval.has(this))
+        return this;
+
+    var fixed = this.fixed_value();
+    if (!fixed)
+        return this;
+
+    reentrant_ref_eval.add(this);
+    const value = fixed._eval(compressor, depth);
+    reentrant_ref_eval.delete(this);
+
+    if (value === fixed)
+        return this;
+
+    if (value && typeof value == "object") {
+        var escaped = this.definition().escaped;
+        if (escaped && depth > escaped)
+            return this;
+    }
+    return value;
+});
+
+def_eval(AST_Chain, function (compressor, depth) {
+    const evaluated = this.expression._eval(compressor, depth, /*ast_chain=*/true);
+    return evaluated === nullish
+        ? undefined
+        : evaluated === this.expression
+          ? this
+          : evaluated;
+});
+
+const global_objs = { Array, Math, Number, Object, String };
+
+const regexp_flags = new Set([
+    "dotAll",
+    "global",
+    "ignoreCase",
+    "multiline",
+    "sticky",
+    "unicode",
+]);
+
+def_eval(AST_PropAccess, function (compressor, depth, ast_chain) {
+    let obj = (ast_chain || this.property === "length" || compressor.option("unsafe"))
+        && this.expression._eval(compressor, depth + 1, ast_chain);
+
+    if (ast_chain) {
+        if (obj === nullish || (this.optional && obj == null)) return nullish;
+    }
+
+    // `.length` of strings and arrays is always safe
+    if (this.property === "length") {
+        if (typeof obj === "string") {
+            return obj.length;
+        }
+
+        const is_spreadless_array =
+            obj instanceof AST_Array
+            && obj.elements.every(el => !(el instanceof AST_Expansion));
+
+        if (
+            is_spreadless_array
+            && obj.elements.every(el => !el.has_side_effects(compressor))
+        ) {
+            return obj.elements.length;
+        }
+    }
+
+    if (compressor.option("unsafe")) {
+        var key = this.property;
+        if (key instanceof AST_Node) {
+            key = key._eval(compressor, depth);
+            if (key === this.property)
+                return this;
+        }
+
+        var exp = this.expression;
+        if (is_undeclared_ref(exp)) {
+            var aa;
+            var first_arg = exp.name === "hasOwnProperty"
+                && key === "call"
+                && (aa = compressor.parent() && compressor.parent().args)
+                && (aa && aa[0]
+                    && aa[0].evaluate(compressor));
+
+            first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
+
+            if (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared) {
+                return this.clone();
+            }
+            if (!compressor.is_pure_native_static_property(exp.name, key))
+                return this;
+            obj = global_objs[exp.name];
+        } else {
+            if (obj instanceof RegExp) {
+                if (key == "source") {
+                    return regexp_source_fix(obj.source);
+                } else if (key == "flags" || regexp_flags.has(key)) {
+                    return obj[key];
+                }
+            }
+            if (!obj || obj === exp || !HOP(obj, key))
+                return this;
+
+            if (typeof obj == "function")
+                switch (key) {
+                    case "name":
+                        return obj.node.name ? obj.node.name.name : "";
+                    case "length":
+                        return obj.node.length_property();
+                    default:
+                        return this;
+                }
+        }
+        return obj[key];
+    }
+    return this;
+});
+
+def_eval(AST_Call, function (compressor, depth, ast_chain) {
+    var exp = this.expression;
+
+    if (ast_chain) {
+        const callee = exp._eval(compressor, depth, ast_chain);
+        if (callee === nullish || (this.optional && callee == null)) return nullish;
+    }
+
+    if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
+        var key = exp.property;
+        if (key instanceof AST_Node) {
+            key = key._eval(compressor, depth);
+            if (typeof key !== "string" && typeof key !== "number")
+                return this;
+        }
+        var val;
+        var e = exp.expression;
+        if (is_undeclared_ref(e)) {
+            var first_arg = e.name === "hasOwnProperty" &&
+                key === "call" &&
+                (this.args[0] && this.args[0].evaluate(compressor));
+
+            first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
+
+            if ((first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)) {
+                return this.clone();
+            }
+            if (!compressor.is_pure_native_static_fn(e.name, key)) return this;
+            val = global_objs[e.name];
+        } else {
+            val = e._eval(compressor, depth + 1, /* don't pass ast_chain (exponential work) */);
+
+            if (val === e || !val)
+                return this;
+            if (!compressor.is_pure_native_method(val.constructor.name, key))
+                return this;
+        }
+        var args = [];
+        for (var i = 0, len = this.args.length; i < len; i++) {
+            var arg = this.args[i];
+            var value = arg._eval(compressor, depth);
+            if (arg === value)
+                return this;
+            if (arg instanceof AST_Lambda)
+                return this;
+            args.push(value);
+        }
+        try {
+            return val[key].apply(val, args);
+        } catch (ex) {
+            // We don't really care
+        }
+    }
+    return this;
+});
+
+// Also a subclass of AST_Call
+def_eval(AST_New, return_this);
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// AST_Node#drop_side_effect_free() gets called when we don't care about the value,
+// only about side effects. We'll be defining this method for each node type in this module
+//
+// Examples:
+// foo++ -> foo++
+// 1 + func() -> func()
+// 10 -> (nothing)
+// knownPureFunc(foo++) -> foo++
+
+function def_drop_side_effect_free(node_or_nodes, func) {
+    for (const node of [].concat(node_or_nodes)) {
+        node.DEFMETHOD("drop_side_effect_free", func);
+    }
+}
+
+// Drop side-effect-free elements from an array of expressions.
+// Returns an array of expressions with side-effects or null
+// if all elements were dropped. Note: original array may be
+// returned if nothing changed.
+function trim(nodes, compressor, first_in_statement) {
+    var len = nodes.length;
+    if (!len)  return null;
+
+    var ret = [], changed = false;
+    for (var i = 0; i < len; i++) {
+        var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
+        changed |= node !== nodes[i];
+        if (node) {
+            ret.push(node);
+            first_in_statement = false;
+        }
+    }
+    return changed ? ret.length ? ret : null : nodes;
+}
+
+def_drop_side_effect_free(AST_Node, return_this);
+def_drop_side_effect_free(AST_Constant, return_null);
+def_drop_side_effect_free(AST_This, return_null);
+
+def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) {
+    if (is_nullish_shortcircuited(this, compressor)) {
+        return this.expression.drop_side_effect_free(compressor, first_in_statement);
+    }
+
+    if (!this.is_callee_pure(compressor)) {
+        if (this.expression.is_call_pure(compressor)) {
+            var exprs = this.args.slice();
+            exprs.unshift(this.expression.expression);
+            exprs = trim(exprs, compressor, first_in_statement);
+            return exprs && make_sequence(this, exprs);
+        }
+        if (is_func_expr(this.expression)
+            && (!this.expression.name || !this.expression.name.definition().references.length)) {
+            var node = this.clone();
+            node.expression.process_expression(false, compressor);
+            return node;
+        }
+        return this;
+    }
+
+    var args = trim(this.args, compressor, first_in_statement);
+    return args && make_sequence(this, args);
+});
+
+def_drop_side_effect_free(AST_DynamicImport, function (compressor, first_in_statement) {
+    if (this.phase !== "source") return this;
+    var args = trim(this.args, compressor, first_in_statement);
+    return args && make_sequence(this, args);
+});
+
+def_drop_side_effect_free(AST_Accessor, return_null);
+
+def_drop_side_effect_free(AST_Function, return_null);
+
+def_drop_side_effect_free(AST_Arrow, return_null);
+
+def_drop_side_effect_free(AST_Class, function (compressor) {
+    const with_effects = [];
+
+    if (this.is_self_referential() && this.has_side_effects(compressor)) {
+        return this;
+    }
+
+    const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
+    if (trimmed_extends) with_effects.push(trimmed_extends);
+
+    for (const prop of this.properties) {
+        if (prop instanceof AST_ClassStaticBlock) {
+            if (prop.has_side_effects(compressor)) {
+                return this; // Be cautious about these
+            }
+        } else {
+            const trimmed_prop = prop.drop_side_effect_free(compressor);
+            if (trimmed_prop) with_effects.push(trimmed_prop);
+        }
+    }
+
+    if (!with_effects.length)
+        return null;
+
+    const exprs = make_sequence(this, with_effects);
+    if (this instanceof AST_DefClass) {
+        // We want a statement
+        return make_node(AST_SimpleStatement, this, { body: exprs });
+    } else {
+        return exprs;
+    }
+});
+
+def_drop_side_effect_free([
+    AST_ClassProperty,
+    AST_ClassPrivateProperty,
+], function (compressor) {
+    const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
+
+    const value = this.static && this.value
+        && this.value.drop_side_effect_free(compressor);
+
+    if (key && value)
+        return make_sequence(this, [key, value]);
+    return key || value || null;
+});
+
+def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
+    var right = this.right.drop_side_effect_free(compressor);
+    if (!right)
+        return this.left.drop_side_effect_free(compressor, first_in_statement);
+    if (lazy_op.has(this.operator)) {
+        if (right === this.right)
+            return this;
+        var node = this.clone();
+        node.right = right;
+        return node;
+    } else {
+        var left = this.left.drop_side_effect_free(compressor, first_in_statement);
+        if (!left)
+            return this.right.drop_side_effect_free(compressor, first_in_statement);
+        return make_sequence(this, [left, right]);
+    }
+});
+
+def_drop_side_effect_free(AST_Assign, function (compressor) {
+    if (this.logical)
+        return this;
+
+    var left = this.left;
+    if (left.has_side_effects(compressor)
+        || compressor.has_directive("use strict")
+        && left instanceof AST_PropAccess
+        && left.expression.is_constant()) {
+        return this;
+    }
+    set_flag(this, WRITE_ONLY);
+    while (left instanceof AST_PropAccess) {
+        left = left.expression;
+    }
+    if (left.is_constant_expression(compressor.find_parent(AST_Scope))) {
+        return this.right.drop_side_effect_free(compressor);
+    }
+    return this;
+});
+
+def_drop_side_effect_free(AST_Conditional, function (compressor) {
+    var consequent = this.consequent.drop_side_effect_free(compressor);
+    var alternative = this.alternative.drop_side_effect_free(compressor);
+    if (consequent === this.consequent && alternative === this.alternative)
+        return this;
+    if (!consequent)
+        return alternative ? make_node(AST_Binary, this, {
+            operator: "||",
+            left: this.condition,
+            right: alternative
+        }) : this.condition.drop_side_effect_free(compressor);
+    if (!alternative)
+        return make_node(AST_Binary, this, {
+            operator: "&&",
+            left: this.condition,
+            right: consequent
+        });
+    var node = this.clone();
+    node.consequent = consequent;
+    node.alternative = alternative;
+    return node;
+});
+
+def_drop_side_effect_free(AST_Unary, function (compressor, first_in_statement) {
+    if (unary_side_effects.has(this.operator)) {
+        if (!this.expression.has_side_effects(compressor)) {
+            set_flag(this, WRITE_ONLY);
+        } else {
+            clear_flag(this, WRITE_ONLY);
+        }
+        return this;
+    }
+    if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
+        return null;
+    var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
+    if (first_in_statement && expression && is_iife_call(expression)) {
+        if (expression === this.expression && this.operator == "!")
+            return this;
+        return expression.negate(compressor, first_in_statement);
+    }
+    return expression;
+});
+
+def_drop_side_effect_free(AST_SymbolRef, function (compressor) {
+    const safe_access = this.is_declared(compressor)
+        || pure_prop_access_globals.has(this.name);
+    return safe_access ? null : this;
+});
+
+def_drop_side_effect_free(AST_Object, function (compressor, first_in_statement) {
+    var values = trim(this.properties, compressor, first_in_statement);
+    return values && make_sequence(this, values);
+});
+
+def_drop_side_effect_free(AST_ObjectKeyVal, function (compressor, first_in_statement) {
+    const computed_key = this.key instanceof AST_Node;
+    const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement);
+    const value = this.value.drop_side_effect_free(compressor, first_in_statement);
+    if (key && value) {
+        return make_sequence(this, [key, value]);
+    }
+    return key || value;
+});
+
+def_drop_side_effect_free([
+    AST_ConciseMethod,
+    AST_ObjectGetter,
+    AST_ObjectSetter,
+], function (compressor, first_in_statement) {
+    return this.computed_key() ? this.key.drop_side_effect_free(compressor, first_in_statement) : null;
+});
+
+def_drop_side_effect_free([
+    AST_PrivateMethod,
+    AST_PrivateGetter,
+    AST_PrivateSetter,
+], function () {
+    return null;
+});
+
+def_drop_side_effect_free(AST_Array, function (compressor, first_in_statement) {
+    var values = trim(this.elements, compressor, first_in_statement);
+    return values && make_sequence(this, values);
+});
+
+def_drop_side_effect_free(AST_Dot, function (compressor, first_in_statement) {
+    if (is_nullish_shortcircuited(this, compressor)) {
+        return this.expression.drop_side_effect_free(compressor, first_in_statement);
+    }
+    if (!this.optional && this.expression.may_throw_on_access(compressor)) {
+        return this;
+    }
+
+    return this.expression.drop_side_effect_free(compressor, first_in_statement);
+});
+
+def_drop_side_effect_free(AST_Sub, function (compressor, first_in_statement) {
+    if (is_nullish_shortcircuited(this, compressor)) {
+        return this.expression.drop_side_effect_free(compressor, first_in_statement);
+    }
+    if (!this.optional && this.expression.may_throw_on_access(compressor)) {
+        return this;
+    }
+
+    var property = this.property.drop_side_effect_free(compressor);
+    if (property && this.optional) return this;
+
+    var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
+
+    if (expression && property) return make_sequence(this, [expression, property]);
+    return expression || property;
+});
+
+def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) {
+    return this.expression.drop_side_effect_free(compressor, first_in_statement);
+});
+
+def_drop_side_effect_free(AST_Sequence, function (compressor) {
+    var last = this.tail_node();
+    var expr = last.drop_side_effect_free(compressor);
+    if (expr === last)
+        return this;
+    var expressions = this.expressions.slice(0, -1);
+    if (expr)
+        expressions.push(expr);
+    if (!expressions.length) {
+        return make_node(AST_Number, this, { value: 0 });
+    }
+    return make_sequence(this, expressions);
+});
+
+def_drop_side_effect_free(AST_Expansion, function (compressor, first_in_statement) {
+    return this.expression.drop_side_effect_free(compressor, first_in_statement);
+});
+
+def_drop_side_effect_free(AST_TemplateSegment, return_null);
+
+def_drop_side_effect_free(AST_TemplateString, function (compressor) {
+    var values = trim(this.segments, compressor, first_in_statement);
+    return values && make_sequence(this, values);
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+const r_keep_assign = /keep_assign/;
+
+/** Drop unused variables from this scope */
+AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
+    if (!compressor.option("unused")) return;
+    if (compressor.has_directive("use asm")) return;
+    if (!this.variables) return; // not really a scope (eg: AST_Class)
+
+    var self = this;
+    if (self.pinned()) return;
+    var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
+    var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
+    const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) {
+        if (node instanceof AST_Assign
+            && !node.logical
+            && (has_flag(node, WRITE_ONLY) || node.operator == "=")
+        ) {
+            return node.left;
+        }
+        if (node instanceof AST_Unary && has_flag(node, WRITE_ONLY)) {
+            return node.expression;
+        }
+    };
+    var in_use_ids = new Map();
+    var fixed_ids = new Map();
+    if (self instanceof AST_Toplevel && compressor.top_retain) {
+        self.variables.forEach(function(def) {
+            if (compressor.top_retain(def)) {
+                in_use_ids.set(def.id, def);
+            }
+        });
+    }
+    var var_defs_by_id = new Map();
+    var initializations = new Map();
+
+    // pass 1: find out which symbols are directly used in
+    // this scope (not in nested scopes).
+    var scope = this;
+    var tw = new TreeWalker(function(node, descend) {
+        if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) {
+            node.argnames.forEach(function(argname) {
+                if (!(argname instanceof AST_SymbolDeclaration)) return;
+                var def = argname.definition();
+                in_use_ids.set(def.id, def);
+            });
+        }
+        if (node === self) return;
+        if (node instanceof AST_Class && node.has_side_effects(compressor)) {
+            if (node.is_self_referential()) {
+                descend();
+            } else {
+                node.visit_nondeferred_class_parts(tw);
+            }
+        }
+        if (node instanceof AST_Defun || node instanceof AST_DefClass) {
+            var node_def = node.name.definition();
+            const in_export = tw.parent() instanceof AST_Export;
+            if (in_export || !drop_funcs && scope === self) {
+                if (node_def.global) {
+                    in_use_ids.set(node_def.id, node_def);
+                }
+            }
+
+            map_add(initializations, node_def.id, node);
+            return true; // don't go in nested scopes
+        }
+        // In the root scope, we drop things. In inner scopes, we just check for uses.
+        const in_root_scope = scope === self;
+        if (node instanceof AST_SymbolFunarg && in_root_scope) {
+            map_add(var_defs_by_id, node.definition().id, node);
+        }
+        if (node instanceof AST_Definitions && in_root_scope) {
+            const in_export = tw.parent() instanceof AST_Export;
+            node.definitions.forEach(function(def) {
+                if (def.name instanceof AST_SymbolVar) {
+                    map_add(var_defs_by_id, def.name.definition().id, def);
+                }
+                if (in_export || !drop_vars) {
+                    walk(def.name, node => {
+                        if (node instanceof AST_SymbolDeclaration) {
+                            const def = node.definition();
+                            if (def.global) {
+                                in_use_ids.set(def.id, def);
+                            }
+                        }
+                    });
+                }
+                if (def.name instanceof AST_Destructuring) {
+                    def.walk(tw);
+                }
+                if (def.name instanceof AST_SymbolDeclaration && def.value) {
+                    var node_def = def.name.definition();
+                    map_add(initializations, node_def.id, def.value);
+                    if (!node_def.chained && def.name.fixed_value() === def.value) {
+                        fixed_ids.set(node_def.id, def);
+                    }
+                    if (def.value.has_side_effects(compressor)) {
+                        def.value.walk(tw);
+                    }
+                }
+            });
+            return true;
+        }
+        return scan_ref_scoped(node, descend);
+    });
+    self.walk(tw);
+
+    // pass 2: for every used symbol we need to walk its
+    // initialization code to figure out if it uses other
+    // symbols (that may not be in_use).
+    tw = new TreeWalker(scan_ref_scoped);
+    in_use_ids.forEach(function (def) {
+        var init = initializations.get(def.id);
+        if (init) init.forEach(function(init) {
+            init.walk(tw);
+        });
+    });
+
+    // pass 3: we should drop declarations not in_use
+    var tt = new TreeTransformer(
+        function before(node, descend, in_list) {
+            var parent = tt.parent();
+            if (drop_vars) {
+                const sym = assign_as_unused(node);
+                if (sym instanceof AST_SymbolRef) {
+                    var def = sym.definition();
+                    var in_use = in_use_ids.has(def.id);
+                    if (node instanceof AST_Assign) {
+                        if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) {
+                            const assignee = node.right.transform(tt);
+                            if (!in_use && !assignee.has_side_effects(compressor) && !is_used_in_expression(tt)) {
+                                return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
+                            }
+                            return maintain_this_binding(parent, node, assignee);
+                        }
+                    } else if (!in_use) {
+                        return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
+                    }
+                }
+            }
+            if (scope !== self) return;
+            var def;
+            if (node.name
+                && (node instanceof AST_ClassExpression
+                    && !keep_name(compressor.option("keep_classnames"), (def = node.name.definition()).name)
+                || node instanceof AST_Function
+                    && !keep_name(compressor.option("keep_fnames"), (def = node.name.definition()).name))) {
+                // any declarations with same name will overshadow
+                // name of this anonymous function and can therefore
+                // never be used anywhere
+                if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null;
+            }
+            if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
+                var trim =
+                    !compressor.option("keep_fargs")
+                    // Is this an IIFE that won't refer to its name?
+                    || parent instanceof AST_Call
+                        && parent.expression === node
+                        && !node.pinned()
+                        && (!node.name || node.name.unreferenced());
+                for (var a = node.argnames, i = a.length; --i >= 0;) {
+                    var sym = a[i];
+                    if (sym instanceof AST_Expansion) {
+                        sym = sym.expression;
+                    }
+                    if (sym instanceof AST_DefaultAssign) {
+                        sym = sym.left;
+                    }
+                    // Do not drop destructuring arguments.
+                    // They constitute a type assertion of sorts
+                    if (
+                        !(sym instanceof AST_Destructuring)
+                        && !in_use_ids.has(sym.definition().id)
+                    ) {
+                        set_flag(sym, UNUSED);
+                        if (trim) {
+                            a.pop();
+                        }
+                    } else {
+                        trim = false;
+                    }
+                }
+            }
+            if (node instanceof AST_DefClass && node !== self) {
+                const def = node.name.definition();
+                descend(node, this);
+                const keep_class = def.global && !drop_funcs || in_use_ids.has(def.id);
+                if (!keep_class) {
+                    const kept = node.drop_side_effect_free(compressor);
+                    if (kept == null) {
+                        def.eliminated++;
+                        return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
+                    }
+                    return kept;
+                }
+                return node;
+            }
+            if (node instanceof AST_Defun && node !== self) {
+                const def = node.name.definition();
+                const keep = def.global && !drop_funcs || in_use_ids.has(def.id);
+                if (!keep) {
+                    def.eliminated++;
+                    return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
+                }
+            }
+            if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) {
+                var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var);
+                // place uninitialized names at the start
+                var body = [], head = [], tail = [];
+                // for unused names whose initialization has
+                // side effects, we can cascade the init. code
+                // into the next one, or next statement.
+                var side_effects = [];
+                node.definitions.forEach(function(def) {
+                    if (def.value) def.value = def.value.transform(tt);
+                    var is_destructure = def.name instanceof AST_Destructuring;
+                    var sym = is_destructure
+                        ? new SymbolDef(null, { name: "<destructure>" }) /* fake SymbolDef */
+                        : def.name.definition();
+                    if (drop_block && sym.global) return tail.push(def);
+                    if (!(drop_vars || drop_block)
+                        || is_destructure
+                            && (def.name.names.length
+                                || def.name.is_array
+                                || compressor.option("pure_getters") != true)
+                        || in_use_ids.has(sym.id)
+                    ) {
+                        if (def.value && fixed_ids.has(sym.id) && fixed_ids.get(sym.id) !== def) {
+                            def.value = def.value.drop_side_effect_free(compressor);
+                        }
+                        if (def.name instanceof AST_SymbolVar) {
+                            var var_defs = var_defs_by_id.get(sym.id);
+                            if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) {
+                                if (def.value) {
+                                    var ref = make_node(AST_SymbolRef, def.name, def.name);
+                                    sym.references.push(ref);
+                                    var assign = make_node(AST_Assign, def, {
+                                        operator: "=",
+                                        logical: false,
+                                        left: ref,
+                                        right: def.value
+                                    });
+                                    if (fixed_ids.get(sym.id) === def) {
+                                        fixed_ids.set(sym.id, assign);
+                                    }
+                                    side_effects.push(assign.transform(tt));
+                                }
+                                remove(var_defs, def);
+                                sym.eliminated++;
+                                return;
+                            }
+                        }
+                        if (def.value) {
+                            if (side_effects.length > 0) {
+                                if (tail.length > 0) {
+                                    side_effects.push(def.value);
+                                    def.value = make_sequence(def.value, side_effects);
+                                } else {
+                                    body.push(make_node(AST_SimpleStatement, node, {
+                                        body: make_sequence(node, side_effects)
+                                    }));
+                                }
+                                side_effects = [];
+                            }
+                            tail.push(def);
+                        } else {
+                            head.push(def);
+                        }
+                    } else if (sym.orig[0] instanceof AST_SymbolCatch) {
+                        var value = def.value && def.value.drop_side_effect_free(compressor);
+                        if (value) side_effects.push(value);
+                        def.value = null;
+                        head.push(def);
+                    } else {
+                        var value = def.value && def.value.drop_side_effect_free(compressor);
+                        if (value) {
+                            side_effects.push(value);
+                        }
+                        sym.eliminated++;
+                    }
+                });
+                if (head.length > 0 || tail.length > 0) {
+                    node.definitions = head.concat(tail);
+                    body.push(node);
+                }
+                if (side_effects.length > 0) {
+                    body.push(make_node(AST_SimpleStatement, node, {
+                        body: make_sequence(node, side_effects)
+                    }));
+                }
+                switch (body.length) {
+                  case 0:
+                    return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
+                  case 1:
+                    return body[0];
+                  default:
+                    return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body });
+                }
+            }
+            // certain combination of unused name + side effect leads to:
+            //    https://github.com/mishoo/UglifyJS2/issues/44
+            //    https://github.com/mishoo/UglifyJS2/issues/1830
+            //    https://github.com/mishoo/UglifyJS2/issues/1838
+            // that's an invalid AST.
+            // We fix it at this stage by moving the `var` outside the `for`.
+            if (node instanceof AST_For) {
+                descend(node, this);
+                var block;
+                if (node.init instanceof AST_BlockStatement) {
+                    block = node.init;
+                    node.init = block.body.pop();
+                    block.body.push(node);
+                }
+                if (node.init instanceof AST_SimpleStatement) {
+                    node.init = node.init.body;
+                } else if (is_empty(node.init)) {
+                    node.init = null;
+                }
+                return !block ? node : in_list ? MAP.splice(block.body) : block;
+            }
+            if (node instanceof AST_LabeledStatement
+                && node.body instanceof AST_For
+            ) {
+                descend(node, this);
+                if (node.body instanceof AST_BlockStatement) {
+                    var block = node.body;
+                    node.body = block.body.pop();
+                    block.body.push(node);
+                    return in_list ? MAP.splice(block.body) : block;
+                }
+                return node;
+            }
+            if (node instanceof AST_BlockStatement) {
+                descend(node, this);
+                if (in_list && node.body.every(can_be_evicted_from_block)) {
+                    return MAP.splice(node.body);
+                }
+                return node;
+            }
+            if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
+                const save_scope = scope;
+                scope = node;
+                descend(node, this);
+                scope = save_scope;
+                return node;
+            }
+        },
+        function after(node, in_list) {
+            if (node instanceof AST_Sequence) {
+                switch (node.expressions.length) {
+                    case 0: return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 });
+                    case 1: return node.expressions[0];
+                }
+            }
+        }
+    );
+
+    self.transform(tt);
+
+    function scan_ref_scoped(node, descend) {
+        var node_def;
+        const sym = assign_as_unused(node);
+        if (sym instanceof AST_SymbolRef
+            && !is_ref_of(node.left, AST_SymbolBlockDeclaration)
+            && self.variables.get(sym.name) === (node_def = sym.definition())
+        ) {
+            if (node instanceof AST_Assign) {
+                node.right.walk(tw);
+                if (!node_def.chained && node.left.fixed_value() === node.right) {
+                    fixed_ids.set(node_def.id, node);
+                }
+            }
+            return true;
+        }
+        if (node instanceof AST_SymbolRef) {
+            node_def = node.definition();
+            if (!in_use_ids.has(node_def.id)) {
+                in_use_ids.set(node_def.id, node_def);
+                if (node_def.orig[0] instanceof AST_SymbolCatch) {
+                    const redef = node_def.scope.is_block_scope()
+                        && node_def.scope.get_defun_scope().variables.get(node_def.name);
+                    if (redef) in_use_ids.set(redef.id, redef);
+                }
+            }
+            return true;
+        }
+        if (node instanceof AST_Class) {
+            descend();
+            return true;
+        }
+        if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) {
+            var save_scope = scope;
+            scope = node;
+            descend();
+            scope = save_scope;
+            return true;
+        }
+    }
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+/**
+ * Define the method AST_Node#reduce_vars, which goes through the AST in
+ * execution order to perform basic flow analysis
+ */
+function def_reduce_vars(node, func) {
+    node.DEFMETHOD("reduce_vars", func);
+}
+
+def_reduce_vars(AST_Node, noop);
+
+/** Clear definition properties */
+function reset_def(compressor, def) {
+    def.assignments = 0;
+    def.chained = false;
+    def.direct_access = false;
+    def.escaped = 0;
+    def.recursive_refs = 0;
+    def.references = [];
+    def.single_use = undefined;
+    if (
+        def.scope.pinned()
+        || (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments)
+    ) {
+        def.fixed = false;
+    } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
+        def.fixed = def.init;
+    } else {
+        def.fixed = false;
+    }
+}
+
+function reset_variables(tw, compressor, node) {
+    node.variables.forEach(function(def) {
+        reset_def(compressor, def);
+        if (def.fixed === null) {
+            tw.defs_to_safe_ids.set(def.id, tw.safe_ids);
+            mark(tw, def, true);
+        } else if (def.fixed) {
+            tw.loop_ids.set(def.id, tw.in_loop);
+            mark(tw, def, true);
+        }
+    });
+}
+
+function reset_block_variables(compressor, node) {
+    if (node.block_scope) node.block_scope.variables.forEach((def) => {
+        reset_def(compressor, def);
+    });
+}
+
+function push(tw) {
+    tw.safe_ids = Object.create(tw.safe_ids);
+}
+
+function pop(tw) {
+    tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
+}
+
+function mark(tw, def, safe) {
+    tw.safe_ids[def.id] = safe;
+}
+
+function safe_to_read(tw, def) {
+    if (def.single_use == "m") return false;
+    if (tw.safe_ids[def.id]) {
+        if (def.fixed == null) {
+            var orig = def.orig[0];
+            if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
+            def.fixed = make_void_0(orig);
+        }
+        return true;
+    }
+    return def.fixed instanceof AST_Defun;
+}
+
+function safe_to_assign(tw, def, scope, value) {
+    if (def.fixed === undefined) return true;
+    let def_safe_ids;
+    if (def.fixed === null
+        && (def_safe_ids = tw.defs_to_safe_ids.get(def.id))
+    ) {
+        def_safe_ids[def.id] = false;
+        tw.defs_to_safe_ids.delete(def.id);
+        return true;
+    }
+    if (!HOP(tw.safe_ids, def.id)) return false;
+    if (!safe_to_read(tw, def)) return false;
+    if (def.fixed === false) return false;
+    if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
+    if (def.fixed instanceof AST_Defun) {
+        return value instanceof AST_Node && def.fixed.parent_scope === scope;
+    }
+    return def.orig.every((sym) => {
+        return !(sym instanceof AST_SymbolConst
+            || sym instanceof AST_SymbolDefun
+            || sym instanceof AST_SymbolLambda);
+    });
+}
+
+function ref_once(tw, compressor, def) {
+    return compressor.option("unused")
+        && !def.scope.pinned()
+        && def.references.length - def.recursive_refs == 1
+        && tw.loop_ids.get(def.id) === tw.in_loop;
+}
+
+function is_immutable(value) {
+    if (!value) return false;
+    return value.is_constant()
+        || value instanceof AST_Lambda
+        || value instanceof AST_This;
+}
+
+// A definition "escapes" when its value can leave the point of use.
+// Example: `a = b || c`
+// In this example, "b" and "c" are escaping, because they're going into "a"
+//
+// def.escaped is != 0 when it escapes.
+//
+// When greater than 1, it means that N chained properties will be read off
+// of that def before an escape occurs. This is useful for evaluating
+// property accesses, where you need to know when to stop.
+function mark_escaped(tw, d, scope, node, value, level = 0, depth = 1) {
+    var parent = tw.parent(level);
+    if (value) {
+        if (value.is_constant()) return;
+        if (value instanceof AST_ClassExpression) return;
+    }
+
+    if (
+        parent instanceof AST_Assign && (parent.operator === "=" || parent.logical) && node === parent.right
+        || parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
+        || parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
+        || parent instanceof AST_VarDefLike && node === parent.value
+        || parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope
+    ) {
+        if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
+        if (!d.escaped || d.escaped > depth) d.escaped = depth;
+        return;
+    } else if (
+        parent instanceof AST_Array
+        || parent instanceof AST_Await
+        || parent instanceof AST_Binary && lazy_op.has(parent.operator)
+        || parent instanceof AST_Conditional && node !== parent.condition
+        || parent instanceof AST_Expansion
+        || parent instanceof AST_Sequence && node === parent.tail_node()
+    ) {
+        mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
+    } else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
+        var obj = tw.parent(level + 1);
+
+        mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
+    } else if (parent instanceof AST_PropAccess && node === parent.expression) {
+        value = read_property(value, parent.property);
+
+        mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
+        if (value) return;
+    }
+
+    if (level > 0) return;
+    if (parent instanceof AST_Sequence && node !== parent.tail_node()) return;
+    if (parent instanceof AST_SimpleStatement) return;
+
+    d.direct_access = true;
+}
+
+const suppress = node => walk(node, node => {
+    if (!(node instanceof AST_Symbol)) return;
+    var d = node.definition();
+    if (!d) return;
+    if (node instanceof AST_SymbolRef) d.references.push(node);
+    d.fixed = false;
+});
+
+def_reduce_vars(AST_Accessor, function(tw, descend, compressor) {
+    push(tw);
+    reset_variables(tw, compressor, this);
+    descend();
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_Assign, function(tw, descend, compressor) {
+    var node = this;
+    if (node.left instanceof AST_Destructuring) {
+        suppress(node.left);
+        return;
+    }
+
+    const finish_walk = () => {
+        if (node.logical) {
+            node.left.walk(tw);
+
+            push(tw);
+            node.right.walk(tw);
+            pop(tw);
+
+            return true;
+        }
+    };
+
+    var sym = node.left;
+    if (!(sym instanceof AST_SymbolRef)) return finish_walk();
+
+    var def = sym.definition();
+    var safe = safe_to_assign(tw, def, sym.scope, node.right);
+    def.assignments++;
+    if (!safe) return finish_walk();
+
+    var fixed = def.fixed;
+    if (!fixed && node.operator != "=" && !node.logical) return finish_walk();
+
+    var eq = node.operator == "=";
+    var value = eq ? node.right : node;
+    if (is_modified(compressor, tw, node, value, 0)) return finish_walk();
+
+    def.references.push(sym);
+
+    if (!node.logical) {
+        if (!eq) def.chained = true;
+
+        def.fixed = eq ? function() {
+            return node.right;
+        } : function() {
+            return make_node(AST_Binary, node, {
+                operator: node.operator.slice(0, -1),
+                left: fixed instanceof AST_Node ? fixed : fixed(),
+                right: node.right
+            });
+        };
+    }
+
+    if (node.logical) {
+        mark(tw, def, false);
+        push(tw);
+        node.right.walk(tw);
+        pop(tw);
+        return true;
+    }
+
+    mark(tw, def, false);
+    node.right.walk(tw);
+    mark(tw, def, true);
+
+    mark_escaped(tw, def, sym.scope, node, value, 0, 1);
+
+    return true;
+});
+
+def_reduce_vars(AST_Binary, function(tw) {
+    if (!lazy_op.has(this.operator)) return;
+    this.left.walk(tw);
+    push(tw);
+    this.right.walk(tw);
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_Block, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+});
+
+def_reduce_vars(AST_Case, function(tw) {
+    push(tw);
+    this.expression.walk(tw);
+    pop(tw);
+    push(tw);
+    walk_body(this, tw);
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_Class, function(tw, descend) {
+    clear_flag(this, INLINED);
+    push(tw);
+    descend();
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_ClassStaticBlock, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+});
+
+def_reduce_vars(AST_Conditional, function(tw) {
+    this.condition.walk(tw);
+    push(tw);
+    this.consequent.walk(tw);
+    pop(tw);
+    push(tw);
+    this.alternative.walk(tw);
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_Chain, function(tw, descend) {
+    // Chains' conditions apply left-to-right, cumulatively.
+    // If we walk normally we don't go in that order because we would pop before pushing again
+    // Solution: AST_PropAccess and AST_Call push when they are optional, and never pop.
+    // Then we pop everything when they are done being walked.
+    const safe_ids = tw.safe_ids;
+
+    descend();
+
+    // Unroll back to start
+    tw.safe_ids = safe_ids;
+    return true;
+});
+
+def_reduce_vars(AST_Call, function (tw) {
+    this.expression.walk(tw);
+
+    if (this.optional) {
+        // Never pop -- it's popped at AST_Chain above
+        push(tw);
+    }
+
+    for (const arg of this.args) arg.walk(tw);
+
+    return true;
+});
+
+def_reduce_vars(AST_PropAccess, function (tw) {
+    if (!this.optional) return;
+
+    this.expression.walk(tw);
+
+    // Never pop -- it's popped at AST_Chain above
+    push(tw);
+
+    if (this.property instanceof AST_Node) this.property.walk(tw);
+
+    return true;
+});
+
+def_reduce_vars(AST_Default, function(tw, descend) {
+    push(tw);
+    descend();
+    pop(tw);
+    return true;
+});
+
+function mark_lambda(tw, descend, compressor) {
+    clear_flag(this, INLINED);
+    push(tw);
+    reset_variables(tw, compressor, this);
+
+    var iife;
+    if (!this.name
+        && !this.uses_arguments
+        && !this.pinned()
+        && (iife = tw.parent()) instanceof AST_Call
+        && iife.expression === this
+        && !iife.args.some(arg => arg instanceof AST_Expansion)
+        && this.argnames.every(arg_name => arg_name instanceof AST_Symbol)
+    ) {
+        // Virtually turn IIFE parameters into variable definitions:
+        //   (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
+        // So existing transformation rules can work on them.
+        this.argnames.forEach((arg, i) => {
+            if (!arg.definition) return;
+            var d = arg.definition();
+            // Avoid setting fixed when there's more than one origin for a variable value
+            if (d.orig.length > 1) return;
+            if (d.fixed === undefined && (!this.uses_arguments || tw.has_directive("use strict"))) {
+                d.fixed = function() {
+                    return iife.args[i] || make_void_0(iife);
+                };
+                tw.loop_ids.set(d.id, tw.in_loop);
+                mark(tw, d, true);
+            } else {
+                d.fixed = false;
+            }
+        });
+    }
+
+    descend();
+    pop(tw);
+
+    handle_defined_after_hoist(this);
+
+    return true;
+}
+
+/**
+ * It's possible for a hoisted function to use something that's not defined yet. Example:
+ *
+ * hoisted();
+ * var defined_after = true;
+ * function hoisted() {
+ *   // use defined_after
+ * }
+ *
+ * Or even indirectly:
+ *
+ * B();
+ * var defined_after = true;
+ * function A() {
+ *   // use defined_after
+ * }
+ * function B() {
+ *   A();
+ * }
+ *
+ * Access a variable before declaration will either throw a ReferenceError
+ * (if the variable is declared with `let` or `const`),
+ * or get an `undefined` (if the variable is declared with `var`).
+ *
+ * If the variable is inlined into the function, the behavior will change.
+ *
+ * This function is called on the parent to disallow inlining of such variables,
+ */
+function handle_defined_after_hoist(parent) {
+    const defuns = [];
+    walk(parent, node => {
+        if (node === parent) return;
+        if (node instanceof AST_Defun) {
+            defuns.push(node);
+            return true;
+        }
+        if (
+            node instanceof AST_Scope
+            || node instanceof AST_SimpleStatement
+        ) return true;
+    });
+
+    // `defun` id to array of `defun` it uses
+    const defun_dependencies_map = new Map();
+    // `defun` id to array of enclosing `def` that are used by the function
+    const dependencies_map = new Map();
+    // all symbol ids that will be tracked for read/write
+    const symbols_of_interest = new Set();
+    const defuns_of_interest = new Set();
+
+    for (const defun of defuns) {
+        const fname_def = defun.name.definition();
+        const enclosing_defs = [];
+
+        for (const def of defun.enclosed) {
+            if (
+                def.fixed === false
+                || def === fname_def
+                || def.scope.get_defun_scope() !== parent
+            ) {
+                continue;
+            }
+
+            symbols_of_interest.add(def.id);
+
+            // found a reference to another function
+            if (
+                def.assignments === 0
+                && def.orig.length === 1
+                && def.orig[0] instanceof AST_SymbolDefun
+            ) {
+                defuns_of_interest.add(def.id);
+                symbols_of_interest.add(def.id);
+
+                defuns_of_interest.add(fname_def.id);
+                symbols_of_interest.add(fname_def.id);
+
+                if (!defun_dependencies_map.has(fname_def.id)) {
+                    defun_dependencies_map.set(fname_def.id, []);
+                }
+                defun_dependencies_map.get(fname_def.id).push(def.id);
+
+                continue;
+            }
+
+            enclosing_defs.push(def);
+        }
+
+        if (enclosing_defs.length) {
+            dependencies_map.set(fname_def.id, enclosing_defs);
+            defuns_of_interest.add(fname_def.id);
+            symbols_of_interest.add(fname_def.id);
+        }
+    }
+
+    // No defuns use outside constants
+    if (!dependencies_map.size) {
+        return;
+    }
+
+    // Increment to count "symbols of interest" (defuns or defs) that we found.
+    // These are tracked in AST order so we can check which is after which.
+    let symbol_index = 1;
+    // Map a defun ID to its first read (a `symbol_index`)
+    const defun_first_read_map = new Map();
+    // Map a symbol ID to its last write (a `symbol_index`)
+    const symbol_last_write_map = new Map();
+
+    walk_parent(parent, (node, walk_info) => {
+        if (node instanceof AST_Symbol && node.thedef) {
+            const id = node.definition().id;
+
+            symbol_index++;
+
+            // Track last-writes to symbols
+            if (symbols_of_interest.has(id)) {
+                if (node instanceof AST_SymbolDeclaration || is_lhs(node, walk_info.parent())) {
+                    symbol_last_write_map.set(id, symbol_index);
+                }
+            }
+
+            // Track first-reads of defuns (refined later)
+            if (defuns_of_interest.has(id)) {
+                if (!defun_first_read_map.has(id) && !is_recursive_ref(walk_info, id)) {
+                    defun_first_read_map.set(id, symbol_index);
+                }
+            }
+        }
+    });
+
+    // Refine `defun_first_read_map` to be as high as possible
+    for (const [defun, defun_first_read] of defun_first_read_map) {
+        // Update all dependencies of `defun`
+        const queue = new Set(defun_dependencies_map.get(defun));
+        for (const enclosed_defun of queue) {
+            let enclosed_defun_first_read = defun_first_read_map.get(enclosed_defun);
+            if (enclosed_defun_first_read != null && enclosed_defun_first_read < defun_first_read) {
+                continue;
+            }
+
+            defun_first_read_map.set(enclosed_defun, defun_first_read);
+
+            for (const enclosed_enclosed_defun of defun_dependencies_map.get(enclosed_defun) || []) {
+                queue.add(enclosed_enclosed_defun);
+            }
+        }
+    }
+
+    // ensure write-then-read order, otherwise clear `fixed`
+    // This is safe because last-writes (found_symbol_writes) are assumed to be as late as possible, and first-reads (defun_first_read_map) are assumed to be as early as possible.
+    for (const [defun, defs] of dependencies_map) {
+        const defun_first_read = defun_first_read_map.get(defun);
+        if (defun_first_read === undefined) {
+            continue;
+        }
+
+        for (const def of defs) {
+            if (def.fixed === false) {
+                continue;
+            }
+
+            let def_last_write = symbol_last_write_map.get(def.id) || 0;
+
+            if (defun_first_read < def_last_write) {
+                def.fixed = false;
+            }
+        }
+    }
+}
+
+def_reduce_vars(AST_Lambda, mark_lambda);
+
+def_reduce_vars(AST_Do, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+    const saved_loop = tw.in_loop;
+    tw.in_loop = this;
+    push(tw);
+    this.body.walk(tw);
+    if (has_break_or_continue(this)) {
+        pop(tw);
+        push(tw);
+    }
+    this.condition.walk(tw);
+    pop(tw);
+    tw.in_loop = saved_loop;
+    return true;
+});
+
+def_reduce_vars(AST_For, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+    if (this.init) this.init.walk(tw);
+    const saved_loop = tw.in_loop;
+    tw.in_loop = this;
+    push(tw);
+    if (this.condition) this.condition.walk(tw);
+    this.body.walk(tw);
+    if (this.step) {
+        if (has_break_or_continue(this)) {
+            pop(tw);
+            push(tw);
+        }
+        this.step.walk(tw);
+    }
+    pop(tw);
+    tw.in_loop = saved_loop;
+    return true;
+});
+
+def_reduce_vars(AST_ForIn, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+    suppress(this.init);
+    this.object.walk(tw);
+    const saved_loop = tw.in_loop;
+    tw.in_loop = this;
+    push(tw);
+    this.body.walk(tw);
+    pop(tw);
+    tw.in_loop = saved_loop;
+    return true;
+});
+
+def_reduce_vars(AST_If, function(tw) {
+    this.condition.walk(tw);
+    push(tw);
+    this.body.walk(tw);
+    pop(tw);
+    if (this.alternative) {
+        push(tw);
+        this.alternative.walk(tw);
+        pop(tw);
+    }
+    return true;
+});
+
+def_reduce_vars(AST_LabeledStatement, function(tw) {
+    push(tw);
+    this.body.walk(tw);
+    pop(tw);
+    return true;
+});
+
+def_reduce_vars(AST_SymbolCatch, function() {
+    this.definition().fixed = false;
+});
+
+def_reduce_vars(AST_SymbolRef, function(tw, descend, compressor) {
+    var d = this.definition();
+    d.references.push(this);
+    if (d.references.length == 1
+        && !d.fixed
+        && d.orig[0] instanceof AST_SymbolDefun) {
+        tw.loop_ids.set(d.id, tw.in_loop);
+    }
+    var fixed_value;
+    if (d.fixed === undefined || !safe_to_read(tw, d)) {
+        d.fixed = false;
+    } else if (d.fixed) {
+        fixed_value = this.fixed_value();
+        if (
+            fixed_value instanceof AST_Lambda
+            && is_recursive_ref(tw, d)
+        ) {
+            d.recursive_refs++;
+        } else if (fixed_value
+            && !compressor.exposed(d)
+            && ref_once(tw, compressor, d)
+        ) {
+            d.single_use =
+                fixed_value instanceof AST_Lambda && !fixed_value.pinned()
+                || fixed_value instanceof AST_Class
+                || d.scope === this.scope && fixed_value.is_constant_expression();
+        } else {
+            d.single_use = false;
+        }
+        if (is_modified(compressor, tw, this, fixed_value, 0, is_immutable(fixed_value))) {
+            if (d.single_use) {
+                d.single_use = "m";
+            } else {
+                d.fixed = false;
+            }
+        }
+    }
+    mark_escaped(tw, d, this.scope, this, fixed_value, 0, 1);
+});
+
+def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) {
+    this.globals.forEach(function(def) {
+        reset_def(compressor, def);
+    });
+    reset_variables(tw, compressor, this);
+    descend();
+    handle_defined_after_hoist(this);
+    return true;
+});
+
+def_reduce_vars(AST_Try, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+    push(tw);
+    this.body.walk(tw);
+    pop(tw);
+    if (this.bcatch) {
+        push(tw);
+        this.bcatch.walk(tw);
+        pop(tw);
+    }
+    if (this.bfinally) this.bfinally.walk(tw);
+    return true;
+});
+
+def_reduce_vars(AST_Unary, function(tw) {
+    var node = this;
+    if (node.operator !== "++" && node.operator !== "--") return;
+    var exp = node.expression;
+    if (!(exp instanceof AST_SymbolRef)) return;
+    var def = exp.definition();
+    var safe = safe_to_assign(tw, def, exp.scope, true);
+    def.assignments++;
+    if (!safe) return;
+    var fixed = def.fixed;
+    if (!fixed) return;
+    def.references.push(exp);
+    def.chained = true;
+    def.fixed = function() {
+        return make_node(AST_Binary, node, {
+            operator: node.operator.slice(0, -1),
+            left: make_node(AST_UnaryPrefix, node, {
+                operator: "+",
+                expression: fixed instanceof AST_Node ? fixed : fixed()
+            }),
+            right: make_node(AST_Number, node, {
+                value: 1
+            })
+        });
+    };
+    mark(tw, def, true);
+    return true;
+});
+
+def_reduce_vars(AST_VarDef, function(tw, descend) {
+    var node = this;
+    if (node.name instanceof AST_Destructuring) {
+        suppress(node.name);
+        return;
+    }
+    var d = node.name.definition();
+    if (node.value) {
+        if (safe_to_assign(tw, d, node.name.scope, node.value)) {
+            d.fixed = function() {
+                return node.value;
+            };
+            tw.loop_ids.set(d.id, tw.in_loop);
+            mark(tw, d, false);
+            descend();
+            mark(tw, d, true);
+            return true;
+        } else {
+            d.fixed = false;
+        }
+    }
+});
+
+def_reduce_vars(AST_UsingDef, function() {
+    suppress(this.name);
+});
+
+def_reduce_vars(AST_While, function(tw, descend, compressor) {
+    reset_block_variables(compressor, this);
+    const saved_loop = tw.in_loop;
+    tw.in_loop = this;
+    push(tw);
+    descend();
+    pop(tw);
+    tw.in_loop = saved_loop;
+    return true;
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function loop_body(x) {
+    if (x instanceof AST_IterationStatement) {
+        return x.body instanceof AST_BlockStatement ? x.body : x;
+    }
+    return x;
+}
+
+function is_lhs_read_only(lhs) {
+    if (lhs instanceof AST_This) return true;
+    if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda;
+    if (lhs instanceof AST_PropAccess) {
+        lhs = lhs.expression;
+        if (lhs instanceof AST_SymbolRef) {
+            if (lhs.is_immutable()) return false;
+            lhs = lhs.fixed_value();
+        }
+        if (!lhs) return true;
+        if (lhs instanceof AST_RegExp) return false;
+        if (lhs instanceof AST_Constant) return true;
+        return is_lhs_read_only(lhs);
+    }
+    return false;
+}
+
+/** var a = 1 --> var a*/
+function remove_initializers(var_statement) {
+    var decls = [];
+    var_statement.definitions.forEach(function(def) {
+        if (def.name instanceof AST_SymbolDeclaration) {
+            def.value = null;
+            decls.push(def);
+        } else {
+            def.declarations_as_names().forEach(name => {
+                decls.push(make_node(AST_VarDef, def, {
+                    name,
+                    value: null
+                }));
+            });
+        }
+    });
+    return decls.length ? make_node(AST_Var, var_statement, { definitions: decls }) : null;
+}
+
+/** Called on code which won't be executed but has an effect outside of itself: `var`, `function` statements, `export`, `import`. */
+function extract_from_unreachable_code(compressor, stat, target) {
+    walk(stat, node => {
+        if (node instanceof AST_Var) {
+            const no_initializers = remove_initializers(node);
+            if (no_initializers) target.push(no_initializers);
+            return true;
+        }
+        if (
+            node instanceof AST_Defun
+            && (node === stat || !compressor.has_directive("use strict"))
+        ) {
+            target.push(node === stat ? node : make_node(AST_Var, node, {
+                definitions: [
+                    make_node(AST_VarDef, node, {
+                        name: make_node(AST_SymbolVar, node.name, node.name),
+                        value: null
+                    })
+                ]
+            }));
+            return true;
+        }
+        if (node instanceof AST_Export || node instanceof AST_Import) {
+            target.push(node);
+            return true;
+        }
+        if (node instanceof AST_Scope || node instanceof AST_Class) {
+            // Do not go into nested scopes
+            return true;
+        }
+    });
+}
+
+/** Tighten a bunch of statements together, and perform statement-level optimization. */
+function tighten_body(statements, compressor) {
+    const nearest_scope = compressor.find_scope();
+    const defun_scope = nearest_scope.get_defun_scope();
+    const { in_loop, in_try } = find_loop_scope_try();
+
+    var CHANGED, max_iter = 10;
+    do {
+        CHANGED = false;
+        eliminate_spurious_blocks(statements);
+        if (compressor.option("dead_code")) {
+            eliminate_dead_code(statements, compressor);
+        }
+        if (compressor.option("if_return")) {
+            handle_if_return(statements, compressor);
+        }
+        if (compressor.sequences_limit > 0) {
+            sequencesize(statements, compressor);
+            sequencesize_2(statements, compressor);
+        }
+        if (compressor.option("join_vars")) {
+            join_consecutive_vars(statements);
+        }
+        if (compressor.option("collapse_vars")) {
+            collapse(statements, compressor);
+        }
+    } while (CHANGED && max_iter-- > 0);
+
+    function find_loop_scope_try() {
+        var node = compressor.self(), level = 0, in_loop = false, in_try = false;
+        do {
+            if (node instanceof AST_IterationStatement) {
+                in_loop = true;
+            } else if (node instanceof AST_Scope) {
+                break;
+            } else if (node instanceof AST_TryBlock) {
+                in_try = true;
+            }
+        } while (node = compressor.parent(level++));
+
+        return { in_loop, in_try };
+    }
+
+    // Search from right to left for assignment-like expressions:
+    // - `var a = x;`
+    // - `a = x;`
+    // - `++a`
+    // For each candidate, scan from left to right for first usage, then try
+    // to fold assignment into the site for compression.
+    // Will not attempt to collapse assignments into or past code blocks
+    // which are not sequentially executed, e.g. loops and conditionals.
+    function collapse(statements, compressor) {
+        if (nearest_scope.pinned() || defun_scope.pinned())
+            return statements;
+        var args;
+        var candidates = [];
+        var stat_index = statements.length;
+        var scanner = new TreeTransformer(function (node) {
+            if (abort)
+                return node;
+            // Skip nodes before `candidate` as quickly as possible
+            if (!hit) {
+                if (node !== hit_stack[hit_index])
+                    return node;
+                hit_index++;
+                if (hit_index < hit_stack.length)
+                    return handle_custom_scan_order(node);
+                hit = true;
+                stop_after = find_stop(node, 0);
+                if (stop_after === node)
+                    abort = true;
+                return node;
+            }
+            // Stop immediately if these node types are encountered
+            var parent = scanner.parent();
+            if (node instanceof AST_Assign
+                    && (node.logical || node.operator != "=" && lhs.equivalent_to(node.left))
+                || node instanceof AST_Await
+                || node instanceof AST_Using
+                || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
+                ||
+                    (node instanceof AST_Call || node instanceof AST_PropAccess)
+                    && node.optional
+                || node instanceof AST_Debugger
+                || node instanceof AST_Destructuring
+                || node instanceof AST_Expansion
+                    && node.expression instanceof AST_Symbol
+                    && (
+                        node.expression instanceof AST_This
+                        || node.expression.definition().references.length > 1
+                    )
+                || node instanceof AST_IterationStatement && !(node instanceof AST_For)
+                || node instanceof AST_LoopControl
+                || node instanceof AST_Try
+                || node instanceof AST_With
+                || node instanceof AST_Yield
+                || node instanceof AST_Export
+                || node instanceof AST_Class
+                || parent instanceof AST_For && node !== parent.init
+                || !replace_all
+                    && (
+                        node instanceof AST_SymbolRef
+                        && !node.is_declared(compressor)
+                        && !pure_prop_access_globals.has(node)
+                    )
+                || node instanceof AST_SymbolRef
+                    && parent instanceof AST_Call
+                    && has_annotation(parent, _NOINLINE)
+                || node instanceof AST_ObjectProperty && node.key instanceof AST_Node
+            ) {
+                abort = true;
+                return node;
+            }
+            // Stop only if candidate is found within conditional branches
+            if (!stop_if_hit && (!lhs_local || !replace_all)
+                && (parent instanceof AST_Binary && lazy_op.has(parent.operator) && parent.left !== node
+                    || parent instanceof AST_Conditional && parent.condition !== node
+                    || parent instanceof AST_If && parent.condition !== node)) {
+                stop_if_hit = parent;
+            }
+            // Replace variable with assignment when found
+            if (
+                can_replace
+                && !(node instanceof AST_SymbolDeclaration)
+                && lhs.equivalent_to(node)
+                && !shadows(scanner.find_scope() || nearest_scope, lvalues)
+            ) {
+                if (stop_if_hit) {
+                    abort = true;
+                    return node;
+                }
+                if (is_lhs(node, parent)) {
+                    if (value_def)
+                        replaced++;
+                    return node;
+                } else {
+                    replaced++;
+                    if (value_def && candidate instanceof AST_VarDef)
+                        return node;
+                }
+                CHANGED = abort = true;
+                if (candidate instanceof AST_UnaryPostfix) {
+                    return make_node(AST_UnaryPrefix, candidate, candidate);
+                }
+                if (candidate instanceof AST_VarDef) {
+                    var def = candidate.name.definition();
+                    var value = candidate.value;
+                    if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
+                        def.replaced++;
+                        if (funarg && is_identifier_atom(value)) {
+                            return value.transform(compressor);
+                        } else {
+                            return maintain_this_binding(parent, node, value);
+                        }
+                    }
+                    return make_node(AST_Assign, candidate, {
+                        operator: "=",
+                        logical: false,
+                        left: make_node(AST_SymbolRef, candidate.name, candidate.name),
+                        right: value
+                    });
+                }
+                clear_flag(candidate, WRITE_ONLY);
+                return candidate;
+            }
+            // These node types have child nodes that execute sequentially,
+            // but are otherwise not safe to scan into or beyond them.
+            var sym;
+            if (node instanceof AST_Call
+                || node instanceof AST_Exit
+                && (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs))
+                || node instanceof AST_PropAccess
+                && (side_effects || node.expression.may_throw_on_access(compressor))
+                || node instanceof AST_SymbolRef
+                && ((lvalues.has(node.name) && lvalues.get(node.name).modified) || side_effects && may_modify(node))
+                || node instanceof AST_VarDef && node.value
+                && (lvalues.has(node.name.name) || side_effects && may_modify(node.name))
+                || node instanceof AST_Using
+                || (sym = is_lhs(node.left, node))
+                && (sym instanceof AST_PropAccess || lvalues.has(sym.name))
+                || may_throw
+                && (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) {
+                stop_after = node;
+                if (node instanceof AST_Scope)
+                    abort = true;
+            }
+            return handle_custom_scan_order(node);
+        }, function (node) {
+            if (abort)
+                return;
+            if (stop_after === node)
+                abort = true;
+            if (stop_if_hit === node)
+                stop_if_hit = null;
+        });
+
+        var multi_replacer = new TreeTransformer(function (node) {
+            if (abort)
+                return node;
+            // Skip nodes before `candidate` as quickly as possible
+            if (!hit) {
+                if (node !== hit_stack[hit_index])
+                    return node;
+                hit_index++;
+                if (hit_index < hit_stack.length)
+                    return;
+                hit = true;
+                return node;
+            }
+            // Replace variable when found
+            if (node instanceof AST_SymbolRef
+                && node.name == def.name) {
+                if (!--replaced)
+                    abort = true;
+                if (is_lhs(node, multi_replacer.parent()))
+                    return node;
+                def.replaced++;
+                value_def.replaced--;
+                return candidate.value;
+            }
+            // Skip (non-executed) functions and (leading) default case in switch statements
+            if (node instanceof AST_Default || node instanceof AST_Scope)
+                return node;
+        });
+
+        while (--stat_index >= 0) {
+            // Treat parameters as collapsible in IIFE, i.e.
+            //   function(a, b){ ... }(x());
+            // would be translated into equivalent assignments:
+            //   var a = x(), b = undefined;
+            if (stat_index == 0 && compressor.option("unused"))
+                extract_args();
+            // Find collapsible assignments
+            var hit_stack = [];
+            extract_candidates(statements[stat_index]);
+            while (candidates.length > 0) {
+                hit_stack = candidates.pop();
+                var hit_index = 0;
+                var candidate = hit_stack[hit_stack.length - 1];
+                var value_def = null;
+                var stop_after = null;
+                var stop_if_hit = null;
+                var lhs = get_lhs(candidate);
+                if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor))
+                    continue;
+                // Locate symbols which may execute code outside of scanning range
+                var lvalues = get_lvalues(candidate);
+                var lhs_local = is_lhs_local(lhs);
+                if (lhs instanceof AST_SymbolRef) {
+                    lvalues.set(lhs.name, { def: lhs.definition(), modified: false });
+                }
+                var side_effects = value_has_side_effects(candidate);
+                var replace_all = replace_all_symbols();
+                var may_throw = candidate.may_throw(compressor);
+                var funarg = candidate.name instanceof AST_SymbolFunarg;
+                var hit = funarg;
+                var abort = false, replaced = 0, can_replace = !args || !hit;
+                if (!can_replace) {
+                    for (
+                        let j = compressor.self().argnames.lastIndexOf(candidate.name) + 1;
+                        !abort && j < args.length;
+                        j++
+                    ) {
+                        args[j].transform(scanner);
+                    }
+                    can_replace = true;
+                }
+                for (var i = stat_index; !abort && i < statements.length; i++) {
+                    statements[i].transform(scanner);
+                }
+                if (value_def) {
+                    var def = candidate.name.definition();
+                    if (abort && def.references.length - def.replaced > replaced)
+                        replaced = false;
+                    else {
+                        abort = false;
+                        hit_index = 0;
+                        hit = funarg;
+                        for (var i = stat_index; !abort && i < statements.length; i++) {
+                            statements[i].transform(multi_replacer);
+                        }
+                        value_def.single_use = false;
+                    }
+                }
+                if (replaced && !remove_candidate(candidate))
+                    statements.splice(stat_index, 1);
+            }
+        }
+
+        function handle_custom_scan_order(node) {
+            // Skip (non-executed) functions
+            if (node instanceof AST_Scope)
+                return node;
+
+            // Scan case expressions first in a switch statement
+            if (node instanceof AST_Switch) {
+                node.expression = node.expression.transform(scanner);
+                for (var i = 0, len = node.body.length; !abort && i < len; i++) {
+                    var branch = node.body[i];
+                    if (branch instanceof AST_Case) {
+                        if (!hit) {
+                            if (branch !== hit_stack[hit_index])
+                                continue;
+                            hit_index++;
+                        }
+                        branch.expression = branch.expression.transform(scanner);
+                        if (!replace_all)
+                            break;
+                    }
+                }
+                abort = true;
+                return node;
+            }
+        }
+
+        function redefined_within_scope(def, scope) {
+            if (def.global)
+                return false;
+            let cur_scope = def.scope;
+            while (cur_scope && cur_scope !== scope) {
+                if (cur_scope.variables.has(def.name)) {
+                    return true;
+                }
+                cur_scope = cur_scope.parent_scope;
+            }
+            return false;
+        }
+
+        function has_overlapping_symbol(fn, arg, fn_strict) {
+            var found = false, scan_this = !(fn instanceof AST_Arrow);
+            arg.walk(new TreeWalker(function (node, descend) {
+                if (found)
+                    return true;
+                if (node instanceof AST_SymbolRef && (fn.variables.has(node.name) || redefined_within_scope(node.definition(), fn))) {
+                    var s = node.definition().scope;
+                    if (s !== defun_scope)
+                        while (s = s.parent_scope) {
+                            if (s === defun_scope)
+                                return true;
+                        }
+                    return found = true;
+                }
+                if ((fn_strict || scan_this) && node instanceof AST_This) {
+                    return found = true;
+                }
+                if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
+                    var prev = scan_this;
+                    scan_this = false;
+                    descend();
+                    scan_this = prev;
+                    return true;
+                }
+            }));
+            return found;
+        }
+
+        function arg_is_injectable(arg) {
+            if (arg instanceof AST_Expansion) return false;
+            const contains_await = walk(arg, (node) => {
+                if (node instanceof AST_Await) return walk_abort;
+            });
+            if (contains_await) return false;
+            return true;
+        }
+        function extract_args() {
+            var iife, fn = compressor.self();
+            if (is_func_expr(fn)
+                && !fn.name
+                && !fn.uses_arguments
+                && !fn.pinned()
+                && (iife = compressor.parent()) instanceof AST_Call
+                && iife.expression === fn
+                && iife.args.every(arg_is_injectable)
+            ) {
+                var fn_strict = compressor.has_directive("use strict");
+                if (fn_strict && !member(fn_strict, fn.body))
+                    fn_strict = false;
+                var len = fn.argnames.length;
+                args = iife.args.slice(len);
+                var names = new Set();
+                for (var i = len; --i >= 0;) {
+                    var sym = fn.argnames[i];
+                    var arg = iife.args[i];
+                    // The following two line fix is a duplicate of the fix at
+                    // https://github.com/terser/terser/commit/011d3eb08cefe6922c7d1bdfa113fc4aeaca1b75
+                    // This might mean that these two pieces of code (one here in collapse_vars and another in reduce_vars
+                    // Might be doing the exact same thing.
+                    const def = sym.definition && sym.definition();
+                    const is_reassigned = def && def.orig.length > 1;
+                    if (is_reassigned)
+                        continue;
+                    args.unshift(make_node(AST_VarDef, sym, {
+                        name: sym,
+                        value: arg
+                    }));
+                    if (names.has(sym.name))
+                        continue;
+                    names.add(sym.name);
+                    if (sym instanceof AST_Expansion) {
+                        var elements = iife.args.slice(i);
+                        if (elements.every((arg) => !has_overlapping_symbol(fn, arg, fn_strict)
+                        )) {
+                            candidates.unshift([make_node(AST_VarDef, sym, {
+                                name: sym.expression,
+                                value: make_node(AST_Array, iife, {
+                                    elements: elements
+                                })
+                            })]);
+                        }
+                    } else {
+                        if (!arg) {
+                            arg = make_void_0(sym).transform(compressor);
+                        } else if (arg instanceof AST_Lambda && arg.pinned()
+                            || has_overlapping_symbol(fn, arg, fn_strict)) {
+                            arg = null;
+                        }
+                        if (arg)
+                            candidates.unshift([make_node(AST_VarDef, sym, {
+                                name: sym,
+                                value: arg
+                            })]);
+                    }
+                }
+            }
+        }
+
+        function extract_candidates(expr) {
+            hit_stack.push(expr);
+            if (expr instanceof AST_Assign) {
+                if (!expr.left.has_side_effects(compressor)
+                    && !(expr.right instanceof AST_Chain)) {
+                    candidates.push(hit_stack.slice());
+                }
+                extract_candidates(expr.right);
+            } else if (expr instanceof AST_Binary) {
+                extract_candidates(expr.left);
+                extract_candidates(expr.right);
+            } else if (expr instanceof AST_Call && !has_annotation(expr, _NOINLINE)) {
+                extract_candidates(expr.expression);
+                expr.args.forEach(extract_candidates);
+            } else if (expr instanceof AST_Case) {
+                extract_candidates(expr.expression);
+            } else if (expr instanceof AST_Conditional) {
+                extract_candidates(expr.condition);
+                extract_candidates(expr.consequent);
+                extract_candidates(expr.alternative);
+            } else if (expr instanceof AST_Definitions) {
+                var len = expr.definitions.length;
+                // limit number of trailing variable definitions for consideration
+                var i = len - 200;
+                if (i < 0)
+                    i = 0;
+                for (; i < len; i++) {
+                    extract_candidates(expr.definitions[i]);
+                }
+            } else if (expr instanceof AST_DWLoop) {
+                extract_candidates(expr.condition);
+                if (!(expr.body instanceof AST_Block)) {
+                    extract_candidates(expr.body);
+                }
+            } else if (expr instanceof AST_Exit) {
+                if (expr.value)
+                    extract_candidates(expr.value);
+            } else if (expr instanceof AST_For) {
+                if (expr.init)
+                    extract_candidates(expr.init);
+                if (expr.condition)
+                    extract_candidates(expr.condition);
+                if (expr.step)
+                    extract_candidates(expr.step);
+                if (!(expr.body instanceof AST_Block)) {
+                    extract_candidates(expr.body);
+                }
+            } else if (expr instanceof AST_ForIn) {
+                extract_candidates(expr.object);
+                if (!(expr.body instanceof AST_Block)) {
+                    extract_candidates(expr.body);
+                }
+            } else if (expr instanceof AST_If) {
+                extract_candidates(expr.condition);
+                if (!(expr.body instanceof AST_Block)) {
+                    extract_candidates(expr.body);
+                }
+                if (expr.alternative && !(expr.alternative instanceof AST_Block)) {
+                    extract_candidates(expr.alternative);
+                }
+            } else if (expr instanceof AST_Sequence) {
+                expr.expressions.forEach(extract_candidates);
+            } else if (expr instanceof AST_SimpleStatement) {
+                extract_candidates(expr.body);
+            } else if (expr instanceof AST_Switch) {
+                extract_candidates(expr.expression);
+                expr.body.forEach(extract_candidates);
+            } else if (expr instanceof AST_Unary) {
+                if (expr.operator == "++" || expr.operator == "--") {
+                    candidates.push(hit_stack.slice());
+                }
+            } else if (expr instanceof AST_VarDef) {
+                if (expr.value && !(expr.value instanceof AST_Chain)) {
+                    candidates.push(hit_stack.slice());
+                    extract_candidates(expr.value);
+                }
+            }
+            hit_stack.pop();
+        }
+
+        function find_stop(node, level, write_only) {
+            var parent = scanner.parent(level);
+            if (parent instanceof AST_Assign) {
+                if (write_only
+                    && !parent.logical
+                    && !(parent.left instanceof AST_PropAccess
+                        || lvalues.has(parent.left.name))) {
+                    return find_stop(parent, level + 1, write_only);
+                }
+                return node;
+            }
+            if (parent instanceof AST_Binary) {
+                if (write_only && (!lazy_op.has(parent.operator) || parent.left === node)) {
+                    return find_stop(parent, level + 1, write_only);
+                }
+                return node;
+            }
+            if (parent instanceof AST_Call)
+                return node;
+            if (parent instanceof AST_Case)
+                return node;
+            if (parent instanceof AST_Conditional) {
+                if (write_only && parent.condition === node) {
+                    return find_stop(parent, level + 1, write_only);
+                }
+                return node;
+            }
+            if (parent instanceof AST_Definitions) {
+                return find_stop(parent, level + 1, true);
+            }
+            if (parent instanceof AST_Exit) {
+                return write_only ? find_stop(parent, level + 1, write_only) : node;
+            }
+            if (parent instanceof AST_If) {
+                if (write_only && parent.condition === node) {
+                    return find_stop(parent, level + 1, write_only);
+                }
+                return node;
+            }
+            if (parent instanceof AST_IterationStatement)
+                return node;
+            if (parent instanceof AST_Sequence) {
+                return find_stop(parent, level + 1, parent.tail_node() !== node);
+            }
+            if (parent instanceof AST_SimpleStatement) {
+                return find_stop(parent, level + 1, true);
+            }
+            if (parent instanceof AST_Switch)
+                return node;
+            if (parent instanceof AST_VarDef)
+                return node;
+            return null;
+        }
+
+        function mangleable_var(var_def) {
+            var value = var_def.value;
+            if (!(value instanceof AST_SymbolRef))
+                return;
+            if (value.name == "arguments")
+                return;
+            var def = value.definition();
+            if (def.undeclared)
+                return;
+            return value_def = def;
+        }
+
+        function get_lhs(expr) {
+            if (expr instanceof AST_Assign && expr.logical) {
+                return false;
+            } else if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) {
+                var def = expr.name.definition();
+                if (!member(expr.name, def.orig))
+                    return;
+                var referenced = def.references.length - def.replaced;
+                if (!referenced)
+                    return;
+                var declared = def.orig.length - def.eliminated;
+                if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)
+                    || (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) {
+                    return make_node(AST_SymbolRef, expr.name, expr.name);
+                }
+            } else {
+                const lhs = expr instanceof AST_Assign
+                    ? expr.left
+                    : expr.expression;
+                return !is_ref_of(lhs, AST_SymbolConst)
+                    && !is_ref_of(lhs, AST_SymbolLet)
+                    && !is_ref_of(lhs, AST_SymbolUsing)
+                    && lhs;
+            }
+        }
+
+        function get_rvalue(expr) {
+            if (expr instanceof AST_Assign) {
+                return expr.right;
+            } else {
+                return expr.value;
+            }
+        }
+
+        function get_lvalues(expr) {
+            var lvalues = new Map();
+            if (expr instanceof AST_Unary)
+                return lvalues;
+            var tw = new TreeWalker(function (node) {
+                var sym = node;
+                while (sym instanceof AST_PropAccess)
+                    sym = sym.expression;
+                if (sym instanceof AST_SymbolRef) {
+                    const prev = lvalues.get(sym.name);
+                    if (!prev || !prev.modified) {
+                        lvalues.set(sym.name, {
+                            def: sym.definition(),
+                            modified: is_modified(compressor, tw, node, node, 0)
+                        });
+                    }
+                }
+            });
+            get_rvalue(expr).walk(tw);
+            return lvalues;
+        }
+
+        function remove_candidate(expr) {
+            if (expr.name instanceof AST_SymbolFunarg) {
+                var iife = compressor.parent(), argnames = compressor.self().argnames;
+                var index = argnames.indexOf(expr.name);
+                if (index < 0) {
+                    iife.args.length = Math.min(iife.args.length, argnames.length - 1);
+                } else {
+                    var args = iife.args;
+                    if (args[index])
+                        args[index] = make_node(AST_Number, args[index], {
+                            value: 0
+                        });
+                }
+                return true;
+            }
+            var found = false;
+            return statements[stat_index].transform(new TreeTransformer(function (node, descend, in_list) {
+                if (found)
+                    return node;
+                if (node === expr || node.body === expr) {
+                    found = true;
+                    if (node instanceof AST_VarDef) {
+                        node.value = node.name instanceof AST_SymbolConst
+                            ? make_void_0(node.value) // `const` always needs value.
+                            : null;
+                        return node;
+                    }
+                    return in_list ? MAP.skip : null;
+                }
+            }, function (node) {
+                if (node instanceof AST_Sequence)
+                    switch (node.expressions.length) {
+                        case 0: return null;
+                        case 1: return node.expressions[0];
+                    }
+            }));
+        }
+
+        function is_lhs_local(lhs) {
+            while (lhs instanceof AST_PropAccess)
+                lhs = lhs.expression;
+            return lhs instanceof AST_SymbolRef
+                && lhs.definition().scope.get_defun_scope() === defun_scope
+                && !(in_loop
+                    && (lvalues.has(lhs.name)
+                        || candidate instanceof AST_Unary
+                        || (candidate instanceof AST_Assign
+                            && !candidate.logical
+                            && candidate.operator != "=")));
+        }
+
+        function value_has_side_effects(expr) {
+            if (expr instanceof AST_Unary)
+                return unary_side_effects.has(expr.operator);
+            return get_rvalue(expr).has_side_effects(compressor);
+        }
+
+        function replace_all_symbols() {
+            if (side_effects)
+                return false;
+            if (value_def)
+                return true;
+            if (lhs instanceof AST_SymbolRef) {
+                var def = lhs.definition();
+                if (def.references.length - def.replaced == (candidate instanceof AST_VarDef ? 1 : 2)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        function may_modify(sym) {
+            if (!sym.definition)
+                return true; // AST_Destructuring
+            var def = sym.definition();
+            if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun)
+                return false;
+            if (def.scope.get_defun_scope() !== defun_scope)
+                return true;
+            return def.references.some((ref) =>
+                ref.scope.get_defun_scope() !== defun_scope
+            );
+        }
+
+        function side_effects_external(node, lhs) {
+            if (node instanceof AST_Assign)
+                return side_effects_external(node.left, true);
+            if (node instanceof AST_Unary)
+                return side_effects_external(node.expression, true);
+            if (node instanceof AST_VarDef)
+                return node.value && side_effects_external(node.value);
+            if (lhs) {
+                if (node instanceof AST_Dot)
+                    return side_effects_external(node.expression, true);
+                if (node instanceof AST_Sub)
+                    return side_effects_external(node.expression, true);
+                if (node instanceof AST_SymbolRef)
+                    return node.definition().scope.get_defun_scope() !== defun_scope;
+            }
+            return false;
+        }
+
+        /**
+         * Will any of the pulled-in lvalues shadow a variable in newScope or parents?
+         * similar to scope_encloses_variables_in_this_scope */
+        function shadows(my_scope, lvalues) {
+            for (const { def } of lvalues.values()) {
+                const looked_up = my_scope.find_variable(def.name);
+                if (looked_up) {
+                    if (looked_up === def) continue;
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    function eliminate_spurious_blocks(statements) {
+        var seen_dirs = [];
+        for (var i = 0; i < statements.length;) {
+            var stat = statements[i];
+            if (stat instanceof AST_BlockStatement && stat.body.every(can_be_evicted_from_block)) {
+                CHANGED = true;
+                eliminate_spurious_blocks(stat.body);
+                statements.splice(i, 1, ...stat.body);
+                i += stat.body.length;
+            } else if (stat instanceof AST_EmptyStatement) {
+                CHANGED = true;
+                statements.splice(i, 1);
+            } else if (stat instanceof AST_Directive) {
+                if (seen_dirs.indexOf(stat.value) < 0) {
+                    i++;
+                    seen_dirs.push(stat.value);
+                } else {
+                    CHANGED = true;
+                    statements.splice(i, 1);
+                }
+            } else
+                i++;
+        }
+    }
+
+    function handle_if_return(statements, compressor) {
+        var self = compressor.self();
+        var multiple_if_returns = has_multiple_if_returns(statements);
+        var in_lambda = self instanceof AST_Lambda;
+        // Prevent extremely deep nesting
+        // https://github.com/terser/terser/issues/1432
+        // https://github.com/webpack/webpack/issues/17548
+        const iteration_start = Math.min(statements.length, 500);
+        for (var i = iteration_start; --i >= 0;) {
+            var stat = statements[i];
+            var j = next_index(i);
+            var next = statements[j];
+
+            if (in_lambda && !next && stat instanceof AST_Return) {
+                if (!stat.value) {
+                    CHANGED = true;
+                    statements.splice(i, 1);
+                    continue;
+                }
+                if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") {
+                    CHANGED = true;
+                    statements[i] = make_node(AST_SimpleStatement, stat, {
+                        body: stat.value.expression
+                    });
+                    continue;
+                }
+            }
+
+            if (stat instanceof AST_If) {
+                let ab, new_else;
+
+                ab = aborts(stat.body);
+                if (
+                    can_merge_flow(ab)
+                    && (new_else = as_statement_array_with_return(stat.body, ab))
+                ) {
+                    if (ab.label) {
+                        remove(ab.label.thedef.references, ab);
+                    }
+                    CHANGED = true;
+                    stat = stat.clone();
+                    stat.condition = stat.condition.negate(compressor);
+                    stat.body = make_node(AST_BlockStatement, stat, {
+                        body: as_statement_array(stat.alternative).concat(extract_defuns())
+                    });
+                    stat.alternative = make_node(AST_BlockStatement, stat, {
+                        body: new_else
+                    });
+                    statements[i] = stat.transform(compressor);
+                    continue;
+                }
+
+                ab = aborts(stat.alternative);
+                if (
+                    can_merge_flow(ab)
+                    && (new_else = as_statement_array_with_return(stat.alternative, ab))
+                ) {
+                    if (ab.label) {
+                        remove(ab.label.thedef.references, ab);
+                    }
+                    CHANGED = true;
+                    stat = stat.clone();
+                    stat.body = make_node(AST_BlockStatement, stat.body, {
+                        body: as_statement_array(stat.body).concat(extract_defuns())
+                    });
+                    stat.alternative = make_node(AST_BlockStatement, stat.alternative, {
+                        body: new_else
+                    });
+                    statements[i] = stat.transform(compressor);
+                    continue;
+                }
+            }
+
+            if (stat instanceof AST_If && stat.body instanceof AST_Return) {
+                var value = stat.body.value;
+                //---
+                // pretty silly case, but:
+                // if (foo()) return; return; ==> foo(); return;
+                if (!value && !stat.alternative
+                    && (in_lambda && !next || next instanceof AST_Return && !next.value)) {
+                    CHANGED = true;
+                    statements[i] = make_node(AST_SimpleStatement, stat.condition, {
+                        body: stat.condition
+                    });
+                    continue;
+                }
+                //---
+                // if (foo()) return x; return y; ==> return foo() ? x : y;
+                if (value && !stat.alternative && next instanceof AST_Return && next.value) {
+                    CHANGED = true;
+                    stat = stat.clone();
+                    stat.alternative = next;
+                    statements[i] = stat.transform(compressor);
+                    statements.splice(j, 1);
+                    continue;
+                }
+                //---
+                // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
+                if (value && !stat.alternative
+                    && (!next && in_lambda && multiple_if_returns
+                        || next instanceof AST_Return)) {
+                    CHANGED = true;
+                    stat = stat.clone();
+                    stat.alternative = next || make_node(AST_Return, stat, {
+                        value: null
+                    });
+                    statements[i] = stat.transform(compressor);
+                    if (next)
+                        statements.splice(j, 1);
+                    continue;
+                }
+                //---
+                // if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
+                //
+                // if sequences is not enabled, this can lead to an endless loop (issue #866).
+                // however, with sequences on this helps producing slightly better output for
+                // the example code.
+                var prev = statements[prev_index(i)];
+                if (compressor.option("sequences") && in_lambda && !stat.alternative
+                    && prev instanceof AST_If && prev.body instanceof AST_Return
+                    && next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
+                    CHANGED = true;
+                    stat = stat.clone();
+                    stat.alternative = make_node(AST_BlockStatement, next, {
+                        body: [
+                            next,
+                            make_node(AST_Return, next, {
+                                value: null
+                            })
+                        ]
+                    });
+                    statements[i] = stat.transform(compressor);
+                    statements.splice(j, 1);
+                    continue;
+                }
+            }
+        }
+
+        function has_multiple_if_returns(statements) {
+            var n = 0;
+            for (var i = statements.length; --i >= 0;) {
+                var stat = statements[i];
+                if (stat instanceof AST_If && stat.body instanceof AST_Return) {
+                    if (++n > 1)
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        function is_return_void(value) {
+            return !value || value instanceof AST_UnaryPrefix && value.operator == "void";
+        }
+
+        function can_merge_flow(ab) {
+            if (!ab)
+                return false;
+            for (var j = i + 1, len = statements.length; j < len; j++) {
+                var stat = statements[j];
+                if (stat instanceof AST_DefinitionsLike && !(stat instanceof AST_Var))
+                    return false;
+            }
+            var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null;
+            return ab instanceof AST_Return && in_lambda && is_return_void(ab.value)
+                || ab instanceof AST_Continue && self === loop_body(lct)
+                || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct;
+        }
+
+        function extract_defuns() {
+            var tail = statements.slice(i + 1);
+            statements.length = i + 1;
+            return tail.filter(function (stat) {
+                if (stat instanceof AST_Defun) {
+                    statements.push(stat);
+                    return false;
+                }
+                return true;
+            });
+        }
+
+        function as_statement_array_with_return(node, ab) {
+            var body = as_statement_array(node);
+            if (ab !== body[body.length - 1]) {
+                return undefined;
+            }
+            body = body.slice(0, -1);
+            if (!body.every(stat => can_be_evicted_from_block(stat))) {
+                return undefined;
+            }
+            if (ab.value) {
+                body.push(make_node(AST_SimpleStatement, ab.value, {
+                    body: ab.value.expression
+                }));
+            }
+            return body;
+        }
+
+        function next_index(i) {
+            for (var j = i + 1, len = statements.length; j < len; j++) {
+                var stat = statements[j];
+                if (!(stat instanceof AST_Var && declarations_only(stat))) {
+                    break;
+                }
+            }
+            return j;
+        }
+
+        function prev_index(i) {
+            for (var j = i; --j >= 0;) {
+                var stat = statements[j];
+                if (!(stat instanceof AST_Var && declarations_only(stat))) {
+                    break;
+                }
+            }
+            return j;
+        }
+    }
+
+    function eliminate_dead_code(statements, compressor) {
+        var has_quit;
+        var self = compressor.self();
+        for (var i = 0, n = 0, len = statements.length; i < len; i++) {
+            var stat = statements[i];
+            if (stat instanceof AST_LoopControl) {
+                var lct = compressor.loopcontrol_target(stat);
+                if (stat instanceof AST_Break
+                    && !(lct instanceof AST_IterationStatement)
+                    && loop_body(lct) === self
+                    || stat instanceof AST_Continue
+                    && loop_body(lct) === self) {
+                    if (stat.label) {
+                        remove(stat.label.thedef.references, stat);
+                    }
+                } else {
+                    statements[n++] = stat;
+                }
+            } else {
+                statements[n++] = stat;
+            }
+            if (aborts(stat)) {
+                has_quit = statements.slice(i + 1);
+                break;
+            }
+        }
+        statements.length = n;
+        CHANGED = n != len;
+        if (has_quit)
+            has_quit.forEach(function (stat) {
+                extract_from_unreachable_code(compressor, stat, statements);
+            });
+    }
+
+    function declarations_only(node) {
+        return node.definitions.every((var_def) => !var_def.value);
+    }
+
+    function sequencesize(statements, compressor) {
+        if (statements.length < 2)
+            return;
+        var seq = [], n = 0;
+        function push_seq() {
+            if (!seq.length)
+                return;
+            var body = make_sequence(seq[0], seq);
+            statements[n++] = make_node(AST_SimpleStatement, body, { body: body });
+            seq = [];
+        }
+        for (var i = 0, len = statements.length; i < len; i++) {
+            var stat = statements[i];
+            if (stat instanceof AST_SimpleStatement) {
+                if (seq.length >= compressor.sequences_limit)
+                    push_seq();
+                var body = stat.body;
+                if (seq.length > 0)
+                    body = body.drop_side_effect_free(compressor);
+                if (body)
+                    merge_sequence(seq, body);
+            } else if (stat instanceof AST_Definitions && declarations_only(stat)
+                || stat instanceof AST_Defun) {
+                statements[n++] = stat;
+            } else {
+                push_seq();
+                statements[n++] = stat;
+            }
+        }
+        push_seq();
+        statements.length = n;
+        if (n != len)
+            CHANGED = true;
+    }
+
+    function to_simple_statement(block, decls) {
+        if (!(block instanceof AST_BlockStatement))
+            return block;
+        var stat = null;
+        for (var i = 0, len = block.body.length; i < len; i++) {
+            var line = block.body[i];
+            if (line instanceof AST_Var && declarations_only(line)) {
+                decls.push(line);
+            } else if (stat || line instanceof AST_DefinitionsLike && !(line instanceof AST_Var)) {
+                return false;
+            } else {
+                stat = line;
+            }
+        }
+        return stat;
+    }
+
+    function sequencesize_2(statements, compressor) {
+        function cons_seq(right) {
+            n--;
+            CHANGED = true;
+            var left = prev.body;
+            return make_sequence(left, [left, right]).transform(compressor);
+        }
+        var n = 0, prev;
+        for (var i = 0; i < statements.length; i++) {
+            var stat = statements[i];
+            if (prev) {
+                if (stat instanceof AST_Exit) {
+                    stat.value = cons_seq(stat.value || make_void_0(stat).transform(compressor));
+                } else if (stat instanceof AST_For) {
+                    if (!(stat.init instanceof AST_DefinitionsLike)) {
+                        const abort = walk(prev.body, node => {
+                            if (node instanceof AST_Scope)
+                                return true;
+                            if (node instanceof AST_Binary
+                                && node.operator === "in") {
+                                return walk_abort;
+                            }
+                        });
+                        if (!abort) {
+                            if (stat.init)
+                                stat.init = cons_seq(stat.init);
+                            else {
+                                stat.init = prev.body;
+                                n--;
+                                CHANGED = true;
+                            }
+                        }
+                    }
+                } else if (stat instanceof AST_ForIn) {
+                    if (!(stat.init instanceof AST_DefinitionsLike) || stat.init instanceof AST_Var) {
+                        stat.object = cons_seq(stat.object);
+                    }
+                } else if (stat instanceof AST_If) {
+                    stat.condition = cons_seq(stat.condition);
+                } else if (stat instanceof AST_Switch) {
+                    stat.expression = cons_seq(stat.expression);
+                } else if (stat instanceof AST_With) {
+                    stat.expression = cons_seq(stat.expression);
+                }
+            }
+            if (compressor.option("conditionals") && stat instanceof AST_If) {
+                var decls = [];
+                var body = to_simple_statement(stat.body, decls);
+                var alt = to_simple_statement(stat.alternative, decls);
+                if (body !== false && alt !== false && decls.length > 0) {
+                    var len = decls.length;
+                    decls.push(make_node(AST_If, stat, {
+                        condition: stat.condition,
+                        body: body || make_node(AST_EmptyStatement, stat.body),
+                        alternative: alt
+                    }));
+                    decls.unshift(n, 1);
+                    [].splice.apply(statements, decls);
+                    i += len;
+                    n += len + 1;
+                    prev = null;
+                    CHANGED = true;
+                    continue;
+                }
+            }
+            statements[n++] = stat;
+            prev = stat instanceof AST_SimpleStatement ? stat : null;
+        }
+        statements.length = n;
+    }
+
+    function join_object_assignments(defn, body) {
+        if (!(defn instanceof AST_Definitions))
+            return;
+        var def = defn.definitions[defn.definitions.length - 1];
+        if (!(def.value instanceof AST_Object))
+            return;
+        var exprs;
+        if (body instanceof AST_Assign && !body.logical) {
+            exprs = [body];
+        } else if (body instanceof AST_Sequence) {
+            exprs = body.expressions.slice();
+        }
+        if (!exprs)
+            return;
+        var trimmed = false;
+        do {
+            var node = exprs[0];
+            if (!(node instanceof AST_Assign))
+                break;
+            if (node.operator != "=")
+                break;
+            if (!(node.left instanceof AST_PropAccess))
+                break;
+            var sym = node.left.expression;
+            if (!(sym instanceof AST_SymbolRef))
+                break;
+            if (def.name.name != sym.name)
+                break;
+            if (!node.right.is_constant_expression(nearest_scope))
+                break;
+            var prop = node.left.property;
+            if (prop instanceof AST_Node) {
+                prop = prop.evaluate(compressor);
+            }
+            if (prop instanceof AST_Node)
+                break;
+            prop = "" + prop;
+            var diff = compressor.option("ecma") < 2015
+                && compressor.has_directive("use strict") ? function (node) {
+                    return node.key != prop && (node.key && node.key.name != prop);
+                } : function (node) {
+                    return node.key && node.key.name != prop;
+                };
+            if (!def.value.properties.every(diff))
+                break;
+            var p = def.value.properties.filter(function (p) { return p.key === prop; })[0];
+            if (!p) {
+                def.value.properties.push(make_node(AST_ObjectKeyVal, node, {
+                    key: prop,
+                    value: node.right
+                }));
+            } else {
+                p.value = new AST_Sequence({
+                    start: p.start,
+                    expressions: [p.value.clone(), node.right.clone()],
+                    end: p.end
+                });
+            }
+            exprs.shift();
+            trimmed = true;
+        } while (exprs.length);
+        return trimmed && exprs;
+    }
+
+    function join_consecutive_vars(statements) {
+        var defs;
+        for (var i = 0, j = -1, len = statements.length; i < len; i++) {
+            var stat = statements[i];
+            var prev = statements[j];
+            if (stat instanceof AST_Definitions) {
+                if (prev && prev.TYPE == stat.TYPE) {
+                    prev.definitions = prev.definitions.concat(stat.definitions);
+                    CHANGED = true;
+                } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
+                    defs.definitions = defs.definitions.concat(stat.definitions);
+                    CHANGED = true;
+                } else {
+                    statements[++j] = stat;
+                    defs = stat;
+                }
+            } else if (
+                stat instanceof AST_Using
+                && prev instanceof AST_Using
+                && prev.await === stat.await
+            ) {
+                prev.definitions = prev.definitions.concat(stat.definitions);
+            } else if (stat instanceof AST_Exit) {
+                stat.value = extract_object_assignments(stat.value);
+            } else if (stat instanceof AST_For) {
+                var exprs = join_object_assignments(prev, stat.init);
+                if (exprs) {
+                    CHANGED = true;
+                    stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
+                    statements[++j] = stat;
+                } else if (
+                    prev instanceof AST_Var
+                    && (!stat.init || stat.init.TYPE == prev.TYPE)
+                ) {
+                    if (stat.init) {
+                        prev.definitions = prev.definitions.concat(stat.init.definitions);
+                    }
+                    stat.init = prev;
+                    statements[j] = stat;
+                    CHANGED = true;
+                } else if (
+                    defs instanceof AST_Var
+                    && stat.init instanceof AST_Var
+                    && declarations_only(stat.init)
+                ) {
+                    defs.definitions = defs.definitions.concat(stat.init.definitions);
+                    stat.init = null;
+                    statements[++j] = stat;
+                    CHANGED = true;
+                } else {
+                    statements[++j] = stat;
+                }
+            } else if (stat instanceof AST_ForIn) {
+                stat.object = extract_object_assignments(stat.object);
+            } else if (stat instanceof AST_If) {
+                stat.condition = extract_object_assignments(stat.condition);
+            } else if (stat instanceof AST_SimpleStatement) {
+                var exprs = join_object_assignments(prev, stat.body);
+                if (exprs) {
+                    CHANGED = true;
+                    if (!exprs.length)
+                        continue;
+                    stat.body = make_sequence(stat.body, exprs);
+                }
+                statements[++j] = stat;
+            } else if (stat instanceof AST_Switch) {
+                stat.expression = extract_object_assignments(stat.expression);
+            } else if (stat instanceof AST_With) {
+                stat.expression = extract_object_assignments(stat.expression);
+            } else {
+                statements[++j] = stat;
+            }
+        }
+        statements.length = j + 1;
+
+        function extract_object_assignments(value) {
+            statements[++j] = stat;
+            var exprs = join_object_assignments(prev, value);
+            if (exprs) {
+                CHANGED = true;
+                if (exprs.length) {
+                    return make_sequence(value, exprs);
+                } else if (value instanceof AST_Sequence) {
+                    return value.tail_node().left;
+                } else {
+                    return value.left;
+                }
+            }
+            return value;
+        }
+    }
+}
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+/**
+ * Module that contains the inlining logic.
+ *
+ * @module
+ *
+ * The stars of the show are `inline_into_symbolref` and `inline_into_call`.
+ */
+
+function within_array_or_object_literal(compressor) {
+    var node, level = 0;
+    while (node = compressor.parent(level++)) {
+        if (node instanceof AST_Statement) return false;
+        if (node instanceof AST_Array
+            || node instanceof AST_ObjectKeyVal
+            || node instanceof AST_Object) {
+            return true;
+        }
+    }
+    return false;
+}
+
+function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
+    for (const enclosed of pulled_scope.enclosed) {
+        if (pulled_scope.variables.has(enclosed.name)) {
+            continue;
+        }
+        const looked_up = scope.find_variable(enclosed.name);
+        if (looked_up) {
+            if (looked_up === enclosed) continue;
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * An extra check function for `top_retain` option, compare the length of const identifier
+ * and init value length and return true if init value is longer than identifier. for example:
+ * ```
+ * // top_retain: ["example"]
+ * const example = 100
+ * ```
+ * it will return false because length of "100" is short than identifier "example".
+ */
+function is_const_symbol_short_than_init_value(def, fixed_value) {
+    if (def.orig.length === 1 && fixed_value) {
+        const init_value_length = fixed_value.size();
+        const identifer_length = def.name.length;
+        return init_value_length > identifer_length;
+    }
+    return true;
+}
+
+function inline_into_symbolref(self, compressor) {
+    if (compressor.in_computed_key()) return self;
+
+    const parent = compressor.parent();
+    const def = self.definition();
+    const nearest_scope = compressor.find_scope();
+    let fixed = self.fixed_value();
+    if (
+        compressor.top_retain &&
+        def.global && 
+        compressor.top_retain(def) && 
+        // when identifier is in top_retain option dose not mean we can always inline it.
+        // if identifier name is longer then init value, we can replace it.
+        is_const_symbol_short_than_init_value(def, fixed)
+    ) {
+        // keep it
+        def.fixed = false;
+        def.single_use = false;
+        return self;
+    }
+
+    if (dont_inline_lambda_in_loop(compressor, fixed)) return self;
+
+    let single_use = def.single_use
+        && !(parent instanceof AST_Call
+            && (parent.is_callee_pure(compressor))
+                || has_annotation(parent, _NOINLINE))
+        && !(parent instanceof AST_Export
+            && fixed instanceof AST_Lambda
+            && fixed.name);
+
+    if (single_use && fixed instanceof AST_Node) {
+        single_use =
+            !fixed.has_side_effects(compressor)
+            && !fixed.may_throw(compressor);
+    }
+
+    if (fixed instanceof AST_Class && def.scope !== self.scope) {
+        return self;
+    }
+
+    if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
+        if (retain_top_func(fixed, compressor)) {
+            single_use = false;
+        } else if (def.scope !== self.scope
+            && (def.escaped == 1
+                || has_flag(fixed, INLINED)
+                || within_array_or_object_literal(compressor)
+                || !compressor.option("reduce_funcs"))) {
+            single_use = false;
+        } else if (is_recursive_ref(compressor, def)) {
+            single_use = false;
+        } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
+            single_use = fixed.is_constant_expression(self.scope);
+            if (single_use == "f") {
+                var scope = self.scope;
+                do {
+                    if (scope instanceof AST_Defun || is_func_expr(scope)) {
+                        set_flag(scope, INLINED);
+                    }
+                } while (scope = scope.parent_scope);
+            }
+        }
+    }
+
+    if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
+        single_use =
+            def.scope === self.scope
+                && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
+            || parent instanceof AST_Call
+                && parent.expression === self
+                && !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
+                && !(fixed.name && fixed.name.definition().recursive_refs > 0);
+    }
+
+    if (single_use && fixed) {
+        if (fixed instanceof AST_DefClass) {
+            set_flag(fixed, SQUEEZED);
+            fixed = make_node(AST_ClassExpression, fixed, fixed);
+        }
+        if (fixed instanceof AST_Defun) {
+            set_flag(fixed, SQUEEZED);
+            fixed = make_node(AST_Function, fixed, fixed);
+        }
+        if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
+            const defun_def = fixed.name.definition();
+            let lambda_def = fixed.variables.get(fixed.name.name);
+            let name = lambda_def && lambda_def.orig[0];
+            if (!(name instanceof AST_SymbolLambda)) {
+                name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
+                name.scope = fixed;
+                fixed.name = name;
+                lambda_def = fixed.def_function(name);
+            }
+            walk(fixed, node => {
+                if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
+                    node.thedef = lambda_def;
+                    lambda_def.references.push(node);
+                }
+            });
+        }
+        if (
+            (fixed instanceof AST_Lambda || fixed instanceof AST_Class)
+            && fixed.parent_scope !== nearest_scope
+        ) {
+            fixed = fixed.clone(true, compressor.get_toplevel());
+
+            nearest_scope.add_child_scope(fixed);
+        }
+        return fixed.optimize(compressor);
+    }
+
+    // multiple uses
+    if (fixed) {
+        let replace;
+
+        if (fixed instanceof AST_This) {
+            if (!(def.orig[0] instanceof AST_SymbolFunarg)
+                && def.references.every((ref) =>
+                    def.scope === ref.scope
+                )) {
+                replace = fixed;
+            }
+        } else {
+            var ev = fixed.evaluate(compressor);
+            if (
+                ev !== fixed
+                && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
+            ) {
+                replace = make_node_from_constant(ev, fixed);
+            }
+        }
+
+        if (replace) {
+            const name_length = self.size(compressor);
+            const replace_size = replace.size(compressor);
+
+            let overhead = 0;
+            if (compressor.option("unused") && !compressor.exposed(def)) {
+                overhead =
+                    (name_length + 2 + fixed.size(compressor)) /
+                    (def.references.length - def.assignments);
+            }
+
+            if (replace_size <= name_length + overhead) {
+                return replace;
+            }
+        }
+    }
+
+    return self;
+}
+
+function inline_into_call(self, compressor) {
+    if (compressor.in_computed_key()) return self;
+
+    var exp = self.expression;
+    var fn = exp;
+    var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
+
+    if (compressor.option("reduce_vars")
+        && fn instanceof AST_SymbolRef
+        && !has_annotation(self, _NOINLINE)
+    ) {
+        const fixed = fn.fixed_value();
+
+        if (
+            retain_top_func(fixed, compressor)
+            || !compressor.toplevel.funcs && exp.definition().global
+        ) {
+            return self;
+        }
+
+        fn = fixed;
+    }
+
+    if (
+        dont_inline_lambda_in_loop(compressor, fn)
+        && !has_annotation(self, _INLINE)
+    ) return self;
+
+    var is_func = fn instanceof AST_Lambda;
+
+    var stat = is_func && fn.body[0];
+    var is_regular_func = is_func && !fn.is_generator && !fn.async;
+    var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor);
+    if (can_inline && stat instanceof AST_Return) {
+        let returned = stat.value;
+        if (!returned || returned.is_constant_expression()) {
+            if (returned) {
+                returned = returned.clone(true);
+            } else {
+                returned = make_void_0(self);
+            }
+            const args = self.args.concat(returned);
+            return make_sequence(self, args).optimize(compressor);
+        }
+
+        // optimize identity function
+        if (
+            fn.argnames.length === 1
+            && (fn.argnames[0] instanceof AST_SymbolFunarg)
+            && self.args.length < 2
+            && !(self.args[0] instanceof AST_Expansion)
+            && returned instanceof AST_SymbolRef
+            && returned.name === fn.argnames[0].name
+        ) {
+            const replacement =
+                (self.args[0] || make_void_0()).optimize(compressor);
+
+            let parent;
+            if (
+                replacement instanceof AST_PropAccess
+                && (parent = compressor.parent()) instanceof AST_Call
+                && parent.expression === self
+            ) {
+                // identity function was being used to remove `this`, like in
+                //
+                // id(bag.no_this)(...)
+                //
+                // Replace with a larger but more effish (0, bag.no_this) wrapper.
+
+                return make_sequence(self, [
+                    make_node(AST_Number, self, { value: 0 }),
+                    replacement
+                ]);
+            }
+            // replace call with first argument or undefined if none passed
+            return replacement;
+        }
+    }
+
+    if (can_inline) {
+        var scope, in_loop, level = -1;
+        let def;
+        let returned_value;
+        let nearest_scope;
+        if (simple_args
+            && !fn.uses_arguments
+            && !(compressor.parent() instanceof AST_Class)
+            && !(fn.name && fn instanceof AST_Function)
+            && (returned_value = can_flatten_body(stat))
+            && (exp === fn
+                || has_annotation(self, _INLINE)
+                || compressor.option("unused")
+                    && (def = exp.definition()).references.length == 1
+                    && !is_recursive_ref(compressor, def)
+                    && fn.is_constant_expression(exp.scope))
+            && !has_annotation(self, _PURE | _NOINLINE)
+            && !fn.contains_this()
+            && can_inject_symbols()
+            && (nearest_scope = compressor.find_scope())
+            && !scope_encloses_variables_in_this_scope(nearest_scope, fn)
+            && !(function in_default_assign() {
+                    // Due to the fact function parameters have their own scope
+                    // which can't use `var something` in the function body within,
+                    // we simply don't inline into DefaultAssign.
+                    let i = 0;
+                    let p;
+                    while ((p = compressor.parent(i++))) {
+                        if (p instanceof AST_DefaultAssign) return true;
+                        if (p instanceof AST_Block) break;
+                    }
+                    return false;
+                })()
+            && !(scope instanceof AST_Class)
+        ) {
+            set_flag(fn, SQUEEZED);
+            nearest_scope.add_child_scope(fn);
+            return make_sequence(self, flatten_fn(returned_value)).optimize(compressor);
+        }
+    }
+
+    if (can_inline && has_annotation(self, _INLINE)) {
+        set_flag(fn, SQUEEZED);
+        fn = make_node(fn.CTOR === AST_Defun ? AST_Function : fn.CTOR, fn, fn);
+        fn = fn.clone(true);
+        fn.figure_out_scope({}, {
+            parent_scope: compressor.find_scope(),
+            toplevel: compressor.get_toplevel()
+        });
+
+        return make_node(AST_Call, self, {
+            expression: fn,
+            args: self.args,
+        }).optimize(compressor);
+    }
+
+    const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty);
+    if (can_drop_this_call) {
+        var args = self.args.concat(make_void_0(self));
+        return make_sequence(self, args).optimize(compressor);
+    }
+
+    if (compressor.option("negate_iife")
+        && compressor.parent() instanceof AST_SimpleStatement
+        && is_iife_call(self)) {
+        return self.negate(compressor, true);
+    }
+
+    var ev = self.evaluate(compressor);
+    if (ev !== self) {
+        ev = make_node_from_constant(ev, self).optimize(compressor);
+        return best_of(compressor, ev, self);
+    }
+
+    return self;
+
+    function return_value(stat) {
+        if (!stat) return make_void_0(self);
+        if (stat instanceof AST_Return) {
+            if (!stat.value) return make_void_0(self);
+            return stat.value.clone(true);
+        }
+        if (stat instanceof AST_SimpleStatement) {
+            return make_node(AST_UnaryPrefix, stat, {
+                operator: "void",
+                expression: stat.body.clone(true)
+            });
+        }
+    }
+
+    function can_flatten_body(stat) {
+        var body = fn.body;
+        var len = body.length;
+        if (compressor.option("inline") < 3) {
+            return len == 1 && return_value(stat);
+        }
+        stat = null;
+        for (var i = 0; i < len; i++) {
+            var line = body[i];
+            if (line instanceof AST_Var) {
+                if (stat && !line.definitions.every((var_def) =>
+                    !var_def.value
+                )) {
+                    return false;
+                }
+            } else if (stat) {
+                return false;
+            } else if (!(line instanceof AST_EmptyStatement)) {
+                stat = line;
+            }
+        }
+        return return_value(stat);
+    }
+
+    function can_inject_args(block_scoped, safe_to_inject) {
+        for (var i = 0, len = fn.argnames.length; i < len; i++) {
+            var arg = fn.argnames[i];
+            if (arg instanceof AST_DefaultAssign) {
+                if (has_flag(arg.left, UNUSED)) continue;
+                return false;
+            }
+            if (arg instanceof AST_Destructuring) return false;
+            if (arg instanceof AST_Expansion) {
+                if (has_flag(arg.expression, UNUSED)) continue;
+                return false;
+            }
+            if (has_flag(arg, UNUSED)) continue;
+            if (!safe_to_inject
+                || block_scoped.has(arg.name)
+                || identifier_atom.has(arg.name)
+                || scope.conflicting_def(arg.name)) {
+                return false;
+            }
+            if (in_loop) in_loop.push(arg.definition());
+        }
+        return true;
+    }
+
+    function can_inject_vars(block_scoped, safe_to_inject) {
+        var len = fn.body.length;
+        for (var i = 0; i < len; i++) {
+            var stat = fn.body[i];
+            if (!(stat instanceof AST_Var)) continue;
+            if (!safe_to_inject) return false;
+            for (var j = stat.definitions.length; --j >= 0;) {
+                var name = stat.definitions[j].name;
+                if (name instanceof AST_Destructuring
+                    || block_scoped.has(name.name)
+                    || identifier_atom.has(name.name)
+                    || scope.conflicting_def(name.name)) {
+                    return false;
+                }
+                if (in_loop) in_loop.push(name.definition());
+            }
+        }
+        return true;
+    }
+
+    function can_inject_symbols() {
+        var block_scoped = new Set();
+        do {
+            scope = compressor.parent(++level);
+            if (scope.is_block_scope() && scope.block_scope) {
+                // TODO this is sometimes undefined during compression.
+                // But it should always have a value!
+                scope.block_scope.variables.forEach(function (variable) {
+                    block_scoped.add(variable.name);
+                });
+            }
+            if (scope instanceof AST_Catch) {
+                // TODO can we delete? AST_Catch is a block scope.
+                if (scope.argname) {
+                    block_scoped.add(scope.argname.name);
+                }
+            } else if (scope instanceof AST_IterationStatement) {
+                in_loop = [];
+            } else if (scope instanceof AST_SymbolRef) {
+                if (scope.fixed_value() instanceof AST_Scope) return false;
+            }
+        } while (!(scope instanceof AST_Scope));
+
+        var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
+        var inline = compressor.option("inline");
+        if (!can_inject_vars(block_scoped, inline >= 3 && safe_to_inject)) return false;
+        if (!can_inject_args(block_scoped, inline >= 2 && safe_to_inject)) return false;
+        return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
+    }
+
+    function append_var(decls, expressions, name, value) {
+        var def = name.definition();
+
+        // Name already exists, only when a function argument had the same name
+        const already_appended = scope.variables.has(name.name);
+        if (!already_appended) {
+            scope.variables.set(name.name, def);
+            scope.enclosed.push(def);
+            decls.push(make_node(AST_VarDef, name, {
+                name: name,
+                value: null
+            }));
+        }
+
+        var sym = make_node(AST_SymbolRef, name, name);
+        def.references.push(sym);
+        if (value) expressions.push(make_node(AST_Assign, self, {
+            operator: "=",
+            logical: false,
+            left: sym,
+            right: value.clone()
+        }));
+    }
+
+    function flatten_args(decls, expressions) {
+        var len = fn.argnames.length;
+        for (var i = self.args.length; --i >= len;) {
+            expressions.push(self.args[i]);
+        }
+        for (i = len; --i >= 0;) {
+            var name = fn.argnames[i];
+            var value = self.args[i];
+            if (has_flag(name, UNUSED) || !name.name || scope.conflicting_def(name.name)) {
+                if (value) expressions.push(value);
+            } else {
+                var symbol = make_node(AST_SymbolVar, name, name);
+                name.definition().orig.push(symbol);
+                if (!value && in_loop) value = make_void_0(self);
+                append_var(decls, expressions, symbol, value);
+            }
+        }
+        decls.reverse();
+        expressions.reverse();
+    }
+
+    function flatten_vars(decls, expressions) {
+        var pos = expressions.length;
+        for (var i = 0, lines = fn.body.length; i < lines; i++) {
+            var stat = fn.body[i];
+            if (!(stat instanceof AST_Var)) continue;
+            for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
+                var var_def = stat.definitions[j];
+                var name = var_def.name;
+                append_var(decls, expressions, name, var_def.value);
+                if (in_loop && fn.argnames.every((argname) =>
+                    argname.name != name.name
+                )) {
+                    var def = fn.variables.get(name.name);
+                    var sym = make_node(AST_SymbolRef, name, name);
+                    def.references.push(sym);
+                    expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
+                        operator: "=",
+                        logical: false,
+                        left: sym,
+                        right: make_void_0(name),
+                    }));
+                }
+            }
+        }
+    }
+
+    function flatten_fn(returned_value) {
+        var decls = [];
+        var expressions = [];
+        flatten_args(decls, expressions);
+        flatten_vars(decls, expressions);
+        expressions.push(returned_value);
+
+        if (decls.length) {
+            const i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
+            scope.body.splice(i, 0, make_node(AST_Var, fn, {
+                definitions: decls
+            }));
+        }
+
+        return expressions.map(exp => exp.clone(true));
+    }
+}
+
+/** prevent inlining functions into loops, for performance reasons */
+function dont_inline_lambda_in_loop(compressor, maybe_lambda) {
+    return (
+        (maybe_lambda instanceof AST_Lambda || maybe_lambda instanceof AST_Class)
+        && !!compressor.is_within_loop()
+    );
+}
+
+(function(def_find_defs) {
+    function to_node(value, orig) {
+        if (value instanceof AST_Node) {
+            if (!(value instanceof AST_Constant)) {
+                // Value may be a function, an array including functions and even a complex assign / block expression,
+                // so it should never be shared in different places.
+                // Otherwise wrong information may be used in the compression phase
+                value = value.clone(true);
+            }
+            return make_node(value.CTOR, orig, value);
+        }
+        if (Array.isArray(value)) return make_node(AST_Array, orig, {
+            elements: value.map(function(value) {
+                return to_node(value, orig);
+            })
+        });
+        if (value && typeof value == "object") {
+            var props = [];
+            for (var key in value) if (HOP(value, key)) {
+                props.push(make_node(AST_ObjectKeyVal, orig, {
+                    key: key,
+                    value: to_node(value[key], orig)
+                }));
+            }
+            return make_node(AST_Object, orig, {
+                properties: props
+            });
+        }
+        return make_node_from_constant(value, orig);
+    }
+
+    AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
+        if (!compressor.option("global_defs")) return this;
+        this.figure_out_scope({ ie8: compressor.option("ie8") });
+        return this.transform(new TreeTransformer(function(node) {
+            var def = node._find_defs(compressor, "");
+            if (!def) return;
+            var level = 0, child = node, parent;
+            while (parent = this.parent(level++)) {
+                if (!(parent instanceof AST_PropAccess)) break;
+                if (parent.expression !== child) break;
+                child = parent;
+            }
+            if (is_lhs(child, parent)) {
+                return;
+            }
+            return def;
+        }));
+    });
+    def_find_defs(AST_Node, noop);
+    def_find_defs(AST_Chain, function(compressor, suffix) {
+        return this.expression._find_defs(compressor, suffix);
+    });
+    def_find_defs(AST_Dot, function(compressor, suffix) {
+        return this.expression._find_defs(compressor, "." + this.property + suffix);
+    });
+    def_find_defs(AST_SymbolDeclaration, function() {
+        if (!this.global()) return;
+    });
+    def_find_defs(AST_SymbolRef, function(compressor, suffix) {
+        if (!this.global()) return;
+        var defines = compressor.option("global_defs");
+        var name = this.name + suffix;
+        if (HOP(defines, name)) return to_node(defines[name], this);
+    });
+    def_find_defs(AST_ImportMeta, function(compressor, suffix) {
+        var defines = compressor.option("global_defs");
+        var name = "import.meta" + suffix;
+        if (HOP(defines, name)) return to_node(defines[name], this);
+    });
+})(function(node, func) {
+    node.DEFMETHOD("_find_defs", func);
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+class Compressor extends TreeWalker {
+    constructor(options, { false_by_default = false, mangle_options = false }) {
+        super();
+        if (options.defaults !== undefined && !options.defaults) false_by_default = true;
+        this.options = defaults(options, {
+            arguments     : false,
+            arrows        : !false_by_default,
+            booleans      : !false_by_default,
+            booleans_as_integers : false,
+            collapse_vars : !false_by_default,
+            comparisons   : !false_by_default,
+            computed_props: !false_by_default,
+            conditionals  : !false_by_default,
+            dead_code     : !false_by_default,
+            defaults      : true,
+            directives    : !false_by_default,
+            drop_console  : false,
+            drop_debugger : !false_by_default,
+            ecma          : 5,
+            builtins_ecma : 5,
+            builtins_pure : false,
+            evaluate      : !false_by_default,
+            expression    : false,
+            global_defs   : false,
+            hoist_funs    : false,
+            hoist_props   : !false_by_default,
+            hoist_vars    : false,
+            ie8           : false,
+            if_return     : !false_by_default,
+            inline        : !false_by_default,
+            join_vars     : !false_by_default,
+            keep_classnames: false,
+            keep_fargs    : true,
+            keep_fnames   : false,
+            keep_infinity : false,
+            lhs_constants : !false_by_default,
+            loops         : !false_by_default,
+            module        : false,
+            negate_iife   : !false_by_default,
+            passes        : 1,
+            properties    : !false_by_default,
+            pure_getters  : !false_by_default && "strict",
+            pure_funcs    : null,
+            pure_new      : false,
+            reduce_funcs  : !false_by_default,
+            reduce_vars   : !false_by_default,
+            sequences     : !false_by_default,
+            side_effects  : !false_by_default,
+            switches      : !false_by_default,
+            top_retain    : null,
+            toplevel      : !!(options && options["top_retain"]),
+            typeofs       : !false_by_default,
+            unsafe        : false,
+            unsafe_arrows : false,
+            unsafe_comps  : false,
+            unsafe_Function: false,
+            unsafe_math   : false,
+            unsafe_symbols: false,
+            unsafe_methods: false,
+            unsafe_proto  : false,
+            unsafe_regexp : false,
+            unsafe_undefined: false,
+            unused        : !false_by_default,
+            warnings      : false  // legacy
+        }, true);
+        var global_defs = this.options["global_defs"];
+        if (typeof global_defs == "object") for (var key in global_defs) {
+            if (key[0] === "@" && HOP(global_defs, key)) {
+                global_defs[key.slice(1)] = parse(global_defs[key], {
+                    expression: true
+                });
+            }
+        }
+        if (this.options["inline"] === true) this.options["inline"] = 3;
+        var pure_funcs = this.options["pure_funcs"];
+        if (typeof pure_funcs == "function") {
+            this.pure_funcs = pure_funcs;
+        } else {
+            this.pure_funcs = pure_funcs ? function(node) {
+                return !pure_funcs.includes(node.expression.print_to_string());
+            } : return_true;
+        }
+        var top_retain = this.options["top_retain"];
+        if (top_retain instanceof RegExp) {
+            this.top_retain = function(def) {
+                return top_retain.test(def.name);
+            };
+        } else if (typeof top_retain == "function") {
+            this.top_retain = top_retain;
+        } else if (top_retain) {
+            if (typeof top_retain == "string") {
+                top_retain = top_retain.split(/,/);
+            }
+            this.top_retain = function(def) {
+                return top_retain.includes(def.name);
+            };
+        }
+        if (this.options["module"]) {
+            this.directives["use strict"] = true;
+            this.options["toplevel"] = true;
+        }
+        var toplevel = this.options["toplevel"];
+        this.toplevel = typeof toplevel == "string" ? {
+            funcs: /funcs/.test(toplevel),
+            vars: /vars/.test(toplevel)
+        } : {
+            funcs: toplevel,
+            vars: toplevel
+        };
+        var sequences = this.options["sequences"];
+        this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
+        this.evaluated_regexps = new Map();
+        this._toplevel = undefined;
+        this._mangle_options = mangle_options
+            ? format_mangler_options(mangle_options)
+            : mangle_options;
+
+        this.pure_access_globals = pure_access_globals(this);
+        this.is_pure_native_fn = is_pure_native_fn(this);
+        this.is_pure_native_method = is_pure_native_method(this);
+        this.is_pure_native_static_fn = is_pure_native_static_fn(this);
+        this.is_pure_native_static_property = is_pure_native_static_property(this);
+    }
+
+    mangle_options() {
+        var nth_identifier = this._mangle_options && this._mangle_options.nth_identifier || base54;
+        var module = this._mangle_options && this._mangle_options.module || this.option("module");
+        return { ie8: this.option("ie8"), nth_identifier, module };
+    }
+
+    option(key) {
+        return this.options[key];
+    }
+
+    exposed(def) {
+        if (def.export) return true;
+        if (def.global) for (var i = 0, len = def.orig.length; i < len; i++)
+            if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
+                return true;
+        return false;
+    }
+
+    in_boolean_context() {
+        if (!this.option("booleans")) return false;
+        var self = this.self();
+        for (var i = 0, p; p = this.parent(i); i++) {
+            if (p instanceof AST_SimpleStatement
+                || p instanceof AST_Conditional && p.condition === self
+                || p instanceof AST_DWLoop && p.condition === self
+                || p instanceof AST_For && p.condition === self
+                || p instanceof AST_If && p.condition === self
+                || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) {
+                return true;
+            }
+            if (
+                p instanceof AST_Binary
+                    && (
+                        p.operator == "&&"
+                        || p.operator == "||"
+                        || p.operator == "??"
+                    )
+                || p instanceof AST_Conditional
+                || p.tail_node() === self
+            ) {
+                self = p;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /** True if compressor.self()'s result will be turned into a 32-bit integer.
+     * ex:
+     * ~{expr}
+     * (1, 2, {expr}) | 0
+     **/
+    in_32_bit_context(other_operand_must_be_number) {
+        if (!this.option("evaluate")) return false;
+        var self = this.self();
+        for (var i = 0, p; p = this.parent(i); i++) {
+            if (p instanceof AST_Binary && bitwise_binop.has(p.operator)) {
+                if (other_operand_must_be_number) {
+                    return (self === p.left ? p.right : p.left).is_number(this);
+                } else {
+                    return true;
+                }
+            }
+            if (p instanceof AST_UnaryPrefix) {
+                return p.operator === "~";
+            }
+            if (
+                p instanceof AST_Binary
+                    && (
+                        // Don't talk about p.left. Can change branch taken
+                        p.operator == "&&" && p.right === self
+                        || p.operator == "||" && p.right === self
+                        || p.operator == "??" && p.right === self
+                    )
+                || p instanceof AST_Conditional && p.condition !== self
+                || p.tail_node() === self
+            ) {
+                self = p;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    in_computed_key() {
+        if (!this.option("evaluate")) return false;
+        var self = this.self();
+        for (var i = 0, p; p = this.parent(i); i++) {
+            if (p instanceof AST_ObjectProperty && p.key === self) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    get_toplevel() {
+        return this._toplevel;
+    }
+
+    compress(toplevel) {
+        toplevel = toplevel.resolve_defines(this);
+        this._toplevel = toplevel;
+        if (this.option("expression")) {
+            this._toplevel.process_expression(true);
+        }
+        var passes = +this.options.passes || 1;
+        var min_count = 1 / 0;
+        var stopping = false;
+        var mangle = this.mangle_options();
+        for (var pass = 0; pass < passes; pass++) {
+            this._toplevel.figure_out_scope(mangle);
+            if (pass === 0 && this.option("drop_console")) {
+                // must be run before reduce_vars and compress pass
+                this._toplevel = this._toplevel.drop_console(this.option("drop_console"));
+            }
+            if (pass > 0 || this.option("reduce_vars")) {
+                this._toplevel.reset_opt_flags(this);
+            }
+            this._toplevel = this._toplevel.transform(this);
+            if (passes > 1) {
+                let count = 0;
+                walk(this._toplevel, () => { count++; });
+                if (count < min_count) {
+                    min_count = count;
+                    stopping = false;
+                } else if (stopping) {
+                    break;
+                } else {
+                    stopping = true;
+                }
+            }
+        }
+        if (this.option("expression")) {
+            this._toplevel.process_expression(false);
+        }
+        toplevel = this._toplevel;
+        this._toplevel = undefined;
+        return toplevel;
+    }
+
+    before(node, descend) {
+        if (has_flag(node, SQUEEZED)) return node;
+        var was_scope = false;
+        if (node instanceof AST_Scope) {
+            node = node.hoist_properties(this);
+            node = node.hoist_declarations(this);
+            was_scope = true;
+        }
+        // Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
+        // would call AST_Node.transform() if a different instance of AST_Node is
+        // produced after def_optimize().
+        // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
+        // Migrate and defer all children's AST_Node.transform() to below, which
+        // will now happen after this parent AST_Node has been properly substituted
+        // thus gives a consistent AST snapshot.
+        descend(node, this);
+        // Existing code relies on how AST_Node.optimize() worked, and omitting the
+        // following replacement call would result in degraded efficiency of both
+        // output and performance.
+        descend(node, this);
+        var opt = node.optimize(this);
+        if (was_scope && opt instanceof AST_Scope) {
+            opt.drop_unused(this);
+            descend(opt, this);
+        }
+        if (opt === node) set_flag(opt, SQUEEZED);
+        return opt;
+    }
+
+    /** Alternative to plain is_lhs() which doesn't work within .optimize() */
+    is_lhs() {
+        const self = this.stack[this.stack.length - 1];
+        const parent = this.stack[this.stack.length - 2];
+        return is_lhs(self, parent);
+    }
+}
+
+
+function def_optimize(node, optimizer) {
+    node.DEFMETHOD("optimize", function(compressor) {
+        var self = this;
+        if (has_flag(self, OPTIMIZED)) return self;
+        if (compressor.has_directive("use asm")) return self;
+        var opt = optimizer(self, compressor);
+        set_flag(opt, OPTIMIZED);
+        return opt;
+    });
+}
+
+def_optimize(AST_Node, function(self) {
+    return self;
+});
+
+AST_Toplevel.DEFMETHOD("drop_console", function(options) {
+    const isArray = Array.isArray(options);
+    const tt = new TreeTransformer(function(self) {
+        if (self.TYPE !== "Call") {
+            return;
+        }
+
+        var exp = self.expression;
+
+        if (!(exp instanceof AST_PropAccess)) {
+            return;
+        }
+
+        var name = exp.expression;
+        var property = exp.property;
+        var depth = 2;
+        while (name.expression) {
+            property = name.property;
+            name = name.expression;
+            depth++;
+        }
+
+        if (isArray && !options.includes(property)) {
+            return;
+        }
+
+        if (is_undeclared_ref(name) && name.name == "console") {
+            if (
+                depth === 3
+                && !["call", "apply"].includes(exp.property)
+                && is_used_in_expression(tt)
+            ) {
+                // a (used) call to Function.prototype methods (eg: console.log.bind(console))
+                // but not .call and .apply which would also return undefined.
+                exp.expression = make_empty_function(self);
+                set_flag(exp.expression, SQUEEZED);
+                self.args = [];
+            } else {
+                return make_void_0(self);
+            }
+        }
+    });
+
+    return this.transform(tt);
+});
+
+AST_Node.DEFMETHOD("equivalent_to", function(node) {
+    return equivalent_to(this, node);
+});
+
+AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) {
+    var self = this;
+    var tt = new TreeTransformer(function(node) {
+        if (insert && node instanceof AST_SimpleStatement) {
+            return make_node(AST_Return, node, {
+                value: node.body
+            });
+        }
+        if (!insert && node instanceof AST_Return) {
+            if (compressor) {
+                var value = node.value && node.value.drop_side_effect_free(compressor, true);
+                return value
+                    ? make_node(AST_SimpleStatement, node, { body: value })
+                    : make_node(AST_EmptyStatement, node);
+            }
+            return make_node(AST_SimpleStatement, node, {
+                body: node.value || make_void_0(node)
+            });
+        }
+        if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) {
+            return node;
+        }
+        if (node instanceof AST_Block) {
+            var index = node.body.length - 1;
+            if (index >= 0) {
+                node.body[index] = node.body[index].transform(tt);
+            }
+        } else if (node instanceof AST_If) {
+            node.body = node.body.transform(tt);
+            if (node.alternative) {
+                node.alternative = node.alternative.transform(tt);
+            }
+        } else if (node instanceof AST_With) {
+            node.body = node.body.transform(tt);
+        }
+        return node;
+    });
+    self.transform(tt);
+});
+
+AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) {
+    const self = this;
+    const reduce_vars = compressor.option("reduce_vars");
+
+    const preparation = new TreeWalker(function(node, descend) {
+        clear_flag(node, CLEAR_BETWEEN_PASSES);
+        if (reduce_vars) {
+            if (compressor.top_retain
+                && node instanceof AST_Defun  // Only functions are retained
+                && preparation.parent() === self
+            ) {
+                set_flag(node, TOP);
+            }
+            return node.reduce_vars(preparation, descend, compressor);
+        }
+    });
+    // Stack of look-up tables to keep track of whether a `SymbolDef` has been
+    // properly assigned before use:
+    // - `push()` & `pop()` when visiting conditional branches
+    preparation.safe_ids = Object.create(null);
+    preparation.in_loop = null;
+    preparation.loop_ids = new Map();
+    preparation.defs_to_safe_ids = new Map();
+    self.walk(preparation);
+});
+
+AST_Symbol.DEFMETHOD("fixed_value", function() {
+    var fixed = this.thedef.fixed;
+    if (!fixed || fixed instanceof AST_Node) return fixed;
+    return fixed();
+});
+
+AST_SymbolRef.DEFMETHOD("is_immutable", function() {
+    var orig = this.definition().orig;
+    return orig.length == 1 && orig[0] instanceof AST_SymbolLambda;
+});
+
+function find_variable(compressor, name) {
+    var scope, i = 0;
+    while (scope = compressor.parent(i++)) {
+        if (scope instanceof AST_Scope) break;
+        if (scope instanceof AST_Catch && scope.argname) {
+            scope = scope.argname.definition().scope;
+            break;
+        }
+    }
+    return scope.find_variable(name);
+}
+
+AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
+    return !this.definition().undeclared
+        || (compressor.option("unsafe") || compressor.option("builtins_pure")) && compressor.pure_access_globals(this.name);
+});
+
+/* -----[ optimizers ]----- */
+
+var directives = new Set(["use asm", "use strict"]);
+def_optimize(AST_Directive, function(self, compressor) {
+    if (compressor.option("directives")
+        && (!directives.has(self.value) || compressor.has_directive(self.value) !== self)) {
+        return make_node(AST_EmptyStatement, self);
+    }
+    return self;
+});
+
+def_optimize(AST_Debugger, function(self, compressor) {
+    if (compressor.option("drop_debugger"))
+        return make_node(AST_EmptyStatement, self);
+    return self;
+});
+
+def_optimize(AST_LabeledStatement, function(self, compressor) {
+    if (self.body instanceof AST_Break
+        && compressor.loopcontrol_target(self.body) === self.body) {
+        return make_node(AST_EmptyStatement, self);
+    }
+    return self.label.references.length == 0 ? self.body : self;
+});
+
+def_optimize(AST_Block, function(self, compressor) {
+    tighten_body(self.body, compressor);
+    return self;
+});
+
+function can_be_extracted_from_if_block(node) {
+    return !(
+        node instanceof AST_Const
+        || node instanceof AST_Let
+        || node instanceof AST_Using
+        || node instanceof AST_Class
+    );
+}
+
+def_optimize(AST_BlockStatement, function(self, compressor) {
+    tighten_body(self.body, compressor);
+    switch (self.body.length) {
+      case 1:
+        if (!compressor.has_directive("use strict")
+            && compressor.parent() instanceof AST_If
+            && can_be_extracted_from_if_block(self.body[0])
+            || can_be_evicted_from_block(self.body[0])) {
+            return self.body[0];
+        }
+        break;
+      case 0: return make_node(AST_EmptyStatement, self);
+    }
+    return self;
+});
+
+function opt_AST_Lambda(self, compressor) {
+    tighten_body(self.body, compressor);
+    if (compressor.option("side_effects")
+        && self.body.length == 1
+        && self.body[0] === compressor.has_directive("use strict")) {
+        self.body.length = 0;
+    }
+    return self;
+}
+def_optimize(AST_Lambda, opt_AST_Lambda);
+
+AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
+    var self = this;
+    if (compressor.has_directive("use asm")) return self;
+
+    var hoist_funs = compressor.option("hoist_funs");
+    var hoist_vars = compressor.option("hoist_vars");
+
+    if (hoist_funs || hoist_vars) {
+        var dirs = [];
+        var hoisted = [];
+        var vars = new Map(), vars_found = 0, var_decl = 0;
+        // let's count var_decl first, we seem to waste a lot of
+        // space if we hoist `var` when there's only one.
+        walk(self, node => {
+            if (node instanceof AST_Scope && node !== self)
+                return true;
+            if (node instanceof AST_Var) {
+                ++var_decl;
+                return true;
+            }
+        });
+        hoist_vars = hoist_vars && var_decl > 1;
+        var tt = new TreeTransformer(
+            function before(node) {
+                if (node !== self) {
+                    if (node instanceof AST_Directive) {
+                        dirs.push(node);
+                        return make_node(AST_EmptyStatement, node);
+                    }
+                    if (hoist_funs && node instanceof AST_Defun
+                        && !(tt.parent() instanceof AST_Export)
+                        && tt.parent() === self) {
+                        hoisted.push(node);
+                        return make_node(AST_EmptyStatement, node);
+                    }
+                    if (
+                        hoist_vars
+                        && node instanceof AST_Var
+                        && !node.definitions.some(def => def.name instanceof AST_Destructuring)
+                    ) {
+                        node.definitions.forEach(function(def) {
+                            vars.set(def.name.name, def);
+                            ++vars_found;
+                        });
+                        var seq = node.to_assignments(compressor);
+                        var p = tt.parent();
+                        if (p instanceof AST_ForIn && p.init === node) {
+                            if (seq == null) {
+                                var def = node.definitions[0].name;
+                                return make_node(AST_SymbolRef, def, def);
+                            }
+                            return seq;
+                        }
+                        if (p instanceof AST_For && p.init === node) {
+                            return seq;
+                        }
+                        if (!seq) return make_node(AST_EmptyStatement, node);
+                        return make_node(AST_SimpleStatement, node, {
+                            body: seq
+                        });
+                    }
+                    if (node instanceof AST_Scope)
+                        return node; // to avoid descending in nested scopes
+                }
+            }
+        );
+        self = self.transform(tt);
+        if (vars_found > 0) {
+            // collect only vars which don't show up in self's arguments list
+            var defs = [];
+            const is_lambda = self instanceof AST_Lambda;
+            const args_as_names = is_lambda ? self.args_as_names() : null;
+            vars.forEach((def, name) => {
+                if (is_lambda && args_as_names.some((x) => x.name === def.name.name)) {
+                    vars.delete(name);
+                } else {
+                    def = def.clone();
+                    def.value = null;
+                    defs.push(def);
+                    vars.set(name, def);
+                }
+            });
+            if (defs.length > 0) {
+                // try to merge in assignments
+                for (var i = 0; i < self.body.length;) {
+                    if (self.body[i] instanceof AST_SimpleStatement) {
+                        var expr = self.body[i].body, sym, assign;
+                        if (expr instanceof AST_Assign
+                            && expr.operator == "="
+                            && (sym = expr.left) instanceof AST_Symbol
+                            && vars.has(sym.name)
+                        ) {
+                            var def = vars.get(sym.name);
+                            if (def.value) break;
+                            def.value = expr.right;
+                            remove(defs, def);
+                            defs.push(def);
+                            self.body.splice(i, 1);
+                            continue;
+                        }
+                        if (expr instanceof AST_Sequence
+                            && (assign = expr.expressions[0]) instanceof AST_Assign
+                            && assign.operator == "="
+                            && (sym = assign.left) instanceof AST_Symbol
+                            && vars.has(sym.name)
+                        ) {
+                            var def = vars.get(sym.name);
+                            if (def.value) break;
+                            def.value = assign.right;
+                            remove(defs, def);
+                            defs.push(def);
+                            self.body[i].body = make_sequence(expr, expr.expressions.slice(1));
+                            continue;
+                        }
+                    }
+                    if (self.body[i] instanceof AST_EmptyStatement) {
+                        self.body.splice(i, 1);
+                        continue;
+                    }
+                    if (self.body[i] instanceof AST_BlockStatement) {
+                        self.body.splice(i, 1, ...self.body[i].body);
+                        continue;
+                    }
+                    break;
+                }
+                defs = make_node(AST_Var, self, {
+                    definitions: defs
+                });
+                hoisted.push(defs);
+            }
+        }
+        self.body = dirs.concat(hoisted, self.body);
+    }
+    return self;
+});
+
+AST_Scope.DEFMETHOD("hoist_properties", function(compressor) {
+    var self = this;
+    if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
+    var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false;
+    var defs_by_id = new Map();
+    var hoister = new TreeTransformer(function(node, descend) {
+        if (node instanceof AST_VarDef) {
+            const sym = node.name;
+            let def;
+            let value;
+            if (sym.scope === self
+                && !(sym instanceof AST_SymbolUsing)
+                && (def = sym.definition()).escaped != 1
+                && !def.assignments
+                && !def.direct_access
+                && !def.single_use
+                && !compressor.exposed(def)
+                && !top_retain(def)
+                && (value = sym.fixed_value()) === node.value
+                && value instanceof AST_Object
+                && !value.properties.some(prop =>
+                    prop instanceof AST_Expansion || prop.computed_key()
+                )
+            ) {
+                descend(node, this);
+                const defs = new Map();
+                const assignments = [];
+                value.properties.forEach(({ key, value }) => {
+                    const scope = hoister.find_scope();
+                    const symbol = self.create_symbol(sym.CTOR, {
+                        source: sym,
+                        scope,
+                        conflict_scopes: new Set([
+                            scope,
+                            ...sym.definition().references.map(ref => ref.scope)
+                        ]),
+                        tentative_name: sym.name + "_" + key
+                    });
+
+                    defs.set(String(key), symbol.definition());
+
+                    assignments.push(make_node(AST_VarDef, node, {
+                        name: symbol,
+                        value
+                    }));
+                });
+                defs_by_id.set(def.id, defs);
+                return MAP.splice(assignments);
+            }
+        } else if (node instanceof AST_PropAccess
+            && node.expression instanceof AST_SymbolRef
+        ) {
+            const defs = defs_by_id.get(node.expression.definition().id);
+            if (defs) {
+                const def = defs.get(String(get_simple_key(node.property)));
+                const sym = make_node(AST_SymbolRef, node, {
+                    name: def.name,
+                    scope: node.expression.scope,
+                    thedef: def
+                });
+                sym.reference({});
+                return sym;
+            }
+        }
+    });
+    return self.transform(hoister);
+});
+
+def_optimize(AST_SimpleStatement, function(self, compressor) {
+    if (compressor.option("side_effects")) {
+        var body = self.body;
+        var node = body.drop_side_effect_free(compressor, true);
+        if (!node) {
+            return make_node(AST_EmptyStatement, self);
+        }
+        if (node !== body) {
+            return make_node(AST_SimpleStatement, self, { body: node });
+        }
+    }
+    return self;
+});
+
+def_optimize(AST_While, function(self, compressor) {
+    return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self;
+});
+
+def_optimize(AST_Do, function(self, compressor) {
+    if (!compressor.option("loops")) return self;
+    var cond = self.condition.tail_node().evaluate(compressor);
+    if (!(cond instanceof AST_Node)) {
+        if (cond) return make_node(AST_For, self, {
+            body: make_node(AST_BlockStatement, self.body, {
+                body: [
+                    self.body,
+                    make_node(AST_SimpleStatement, self.condition, {
+                        body: self.condition
+                    })
+                ]
+            })
+        }).optimize(compressor);
+        if (!has_break_or_continue(self, compressor.parent())) {
+            return make_node(AST_BlockStatement, self.body, {
+                body: [
+                    self.body,
+                    make_node(AST_SimpleStatement, self.condition, {
+                        body: self.condition
+                    })
+                ]
+            }).optimize(compressor);
+        }
+    }
+    return self;
+});
+
+function if_break_in_loop(self, compressor) {
+    var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
+    if (compressor.option("dead_code") && is_break(first)) {
+        var body = [];
+        if (self.init instanceof AST_Statement) {
+            body.push(self.init);
+        } else if (self.init) {
+            body.push(make_node(AST_SimpleStatement, self.init, {
+                body: self.init
+            }));
+        }
+        if (self.condition) {
+            body.push(make_node(AST_SimpleStatement, self.condition, {
+                body: self.condition
+            }));
+        }
+        extract_from_unreachable_code(compressor, self.body, body);
+        return make_node(AST_BlockStatement, self, {
+            body: body
+        });
+    }
+    if (first instanceof AST_If) {
+        if (is_break(first.body)) {
+            if (self.condition) {
+                self.condition = make_node(AST_Binary, self.condition, {
+                    left: self.condition,
+                    operator: "&&",
+                    right: first.condition.negate(compressor),
+                });
+            } else {
+                self.condition = first.condition.negate(compressor);
+            }
+            drop_it(first.alternative);
+        } else if (is_break(first.alternative)) {
+            if (self.condition) {
+                self.condition = make_node(AST_Binary, self.condition, {
+                    left: self.condition,
+                    operator: "&&",
+                    right: first.condition,
+                });
+            } else {
+                self.condition = first.condition;
+            }
+            drop_it(first.body);
+        }
+    }
+    return self;
+
+    function is_break(node) {
+        return node instanceof AST_Break
+            && compressor.loopcontrol_target(node) === compressor.self();
+    }
+
+    function drop_it(rest) {
+        rest = as_statement_array(rest);
+        if (self.body instanceof AST_BlockStatement) {
+            self.body = self.body.clone();
+            self.body.body = rest.concat(self.body.body.slice(1));
+            self.body = self.body.transform(compressor);
+        } else {
+            self.body = make_node(AST_BlockStatement, self.body, {
+                body: rest
+            }).transform(compressor);
+        }
+        self = if_break_in_loop(self, compressor);
+    }
+}
+
+def_optimize(AST_For, function(self, compressor) {
+    if (!compressor.option("loops")) return self;
+    if (compressor.option("side_effects") && self.init) {
+        self.init = self.init.drop_side_effect_free(compressor);
+    }
+    if (self.condition) {
+        var cond = self.condition.evaluate(compressor);
+        if (!(cond instanceof AST_Node)) {
+            if (cond) self.condition = null;
+            else if (!compressor.option("dead_code")) {
+                var orig = self.condition;
+                self.condition = make_node_from_constant(cond, self.condition);
+                self.condition = best_of_expression(self.condition.transform(compressor), orig);
+            }
+        }
+        if (compressor.option("dead_code")) {
+            if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
+            if (!cond) {
+                var body = [];
+                extract_from_unreachable_code(compressor, self.body, body);
+                if (self.init instanceof AST_Statement) {
+                    body.push(self.init);
+                } else if (self.init) {
+                    body.push(make_node(AST_SimpleStatement, self.init, {
+                        body: self.init
+                    }));
+                }
+                body.push(make_node(AST_SimpleStatement, self.condition, {
+                    body: self.condition
+                }));
+                return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
+            }
+        }
+    }
+    return if_break_in_loop(self, compressor);
+});
+
+def_optimize(AST_If, function(self, compressor) {
+    if (is_empty(self.alternative)) self.alternative = null;
+
+    if (!compressor.option("conditionals")) return self;
+    // if condition can be statically determined, drop
+    // one of the blocks.  note, statically determined implies
+    // “has no side effects”; also it doesn't work for cases like
+    // `x && true`, though it probably should.
+    var cond = self.condition.evaluate(compressor);
+    if (!compressor.option("dead_code") && !(cond instanceof AST_Node)) {
+        var orig = self.condition;
+        self.condition = make_node_from_constant(cond, orig);
+        self.condition = best_of_expression(self.condition.transform(compressor), orig);
+    }
+    if (compressor.option("dead_code")) {
+        if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor);
+        if (!cond) {
+            var body = [];
+            extract_from_unreachable_code(compressor, self.body, body);
+            body.push(make_node(AST_SimpleStatement, self.condition, {
+                body: self.condition
+            }));
+            if (self.alternative) body.push(self.alternative);
+            return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
+        } else if (!(cond instanceof AST_Node)) {
+            var body = [];
+            body.push(make_node(AST_SimpleStatement, self.condition, {
+                body: self.condition
+            }));
+            body.push(self.body);
+            if (self.alternative) {
+                extract_from_unreachable_code(compressor, self.alternative, body);
+            }
+            return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
+        }
+    }
+    var negated = self.condition.negate(compressor);
+    var self_condition_length = self.condition.size();
+    var negated_length = negated.size();
+    var negated_is_best = negated_length < self_condition_length;
+    if (self.alternative && negated_is_best) {
+        negated_is_best = false; // because we already do the switch here.
+        // no need to swap values of self_condition_length and negated_length
+        // here because they are only used in an equality comparison later on.
+        self.condition = negated;
+        var tmp = self.body;
+        self.body = self.alternative || make_node(AST_EmptyStatement, self);
+        self.alternative = tmp;
+    }
+    if (is_empty(self.body) && is_empty(self.alternative)) {
+        return make_node(AST_SimpleStatement, self.condition, {
+            body: self.condition.clone()
+        }).optimize(compressor);
+    }
+    if (self.body instanceof AST_SimpleStatement
+        && self.alternative instanceof AST_SimpleStatement) {
+        return make_node(AST_SimpleStatement, self, {
+            body: make_node(AST_Conditional, self, {
+                condition   : self.condition,
+                consequent  : self.body.body,
+                alternative : self.alternative.body
+            })
+        }).optimize(compressor);
+    }
+    if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
+        if (self_condition_length === negated_length && !negated_is_best
+            && self.condition instanceof AST_Binary && self.condition.operator == "||") {
+            // although the code length of self.condition and negated are the same,
+            // negated does not require additional surrounding parentheses.
+            // see https://github.com/mishoo/UglifyJS2/issues/979
+            negated_is_best = true;
+        }
+        if (negated_is_best) return make_node(AST_SimpleStatement, self, {
+            body: make_node(AST_Binary, self, {
+                operator : "||",
+                left     : negated,
+                right    : self.body.body
+            })
+        }).optimize(compressor);
+        return make_node(AST_SimpleStatement, self, {
+            body: make_node(AST_Binary, self, {
+                operator : "&&",
+                left     : self.condition,
+                right    : self.body.body
+            })
+        }).optimize(compressor);
+    }
+    if (self.body instanceof AST_EmptyStatement
+        && self.alternative instanceof AST_SimpleStatement) {
+        return make_node(AST_SimpleStatement, self, {
+            body: make_node(AST_Binary, self, {
+                operator : "||",
+                left     : self.condition,
+                right    : self.alternative.body
+            })
+        }).optimize(compressor);
+    }
+    if (self.body instanceof AST_Exit
+        && self.alternative instanceof AST_Exit
+        && self.body.TYPE == self.alternative.TYPE) {
+        return make_node(self.body.CTOR, self, {
+            value: make_node(AST_Conditional, self, {
+                condition   : self.condition,
+                consequent  : self.body.value || make_void_0(self.body),
+                alternative : self.alternative.value || make_void_0(self.alternative),
+            }).transform(compressor)
+        }).optimize(compressor);
+    }
+    if (self.body instanceof AST_If
+        && !self.body.alternative
+        && !self.alternative) {
+        self = make_node(AST_If, self, {
+            condition: make_node(AST_Binary, self.condition, {
+                operator: "&&",
+                left: self.condition,
+                right: self.body.condition
+            }),
+            body: self.body.body,
+            alternative: null
+        });
+    }
+    if (aborts(self.body)) {
+        if (self.alternative) {
+            var alt = self.alternative;
+            self.alternative = null;
+            return make_node(AST_BlockStatement, self, {
+                body: [ self, alt ]
+            }).optimize(compressor);
+        }
+    }
+    if (aborts(self.alternative)) {
+        var body = self.body;
+        self.body = self.alternative;
+        self.condition = negated_is_best ? negated : self.condition.negate(compressor);
+        self.alternative = null;
+        return make_node(AST_BlockStatement, self, {
+            body: [ self, body ]
+        }).optimize(compressor);
+    }
+    return self;
+});
+
+def_optimize(AST_Switch, function(self, compressor) {
+    if (!compressor.option("switches")) return self;
+    var branch;
+    var value = self.expression.evaluate(compressor);
+    if (!(value instanceof AST_Node)) {
+        var orig = self.expression;
+        self.expression = make_node_from_constant(value, orig);
+        self.expression = best_of_expression(self.expression.transform(compressor), orig);
+    }
+    if (!compressor.option("dead_code")) return self;
+    if (value instanceof AST_Node) {
+        value = self.expression.tail_node().evaluate(compressor);
+    }
+    var decl = [];
+    var body = [];
+    var default_branch;
+    var exact_match;
+    // - compress self.body into `body`
+    // - find and deduplicate default branch
+    // - find the exact match (`case 1234` inside `switch(1234)`)
+    for (var i = 0, len = self.body.length; i < len && !exact_match; i++) {
+        branch = self.body[i];
+        if (branch instanceof AST_Default) {
+            if (!default_branch) {
+                default_branch = branch;
+            } else {
+                eliminate_branch(branch, body[body.length - 1]);
+            }
+        } else if (!(value instanceof AST_Node)) {
+            var exp = branch.expression.evaluate(compressor);
+            if (!(exp instanceof AST_Node) && exp !== value) {
+                eliminate_branch(branch, body[body.length - 1]);
+                continue;
+            }
+            if (exp instanceof AST_Node && !exp.has_side_effects(compressor)) {
+                exp = branch.expression.tail_node().evaluate(compressor);
+            }
+            if (exp === value) {
+                exact_match = branch;
+                if (default_branch) {
+                    var default_index = body.indexOf(default_branch);
+                    body.splice(default_index, 1);
+                    eliminate_branch(default_branch, body[default_index - 1]);
+                    default_branch = null;
+                }
+            }
+        }
+        body.push(branch);
+    }
+    // i < len if we found an exact_match. eliminate the rest
+    while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]);
+    self.body = body;
+
+    let default_or_exact = default_branch || exact_match;
+    default_branch = null;
+    exact_match = null;
+
+    // group equivalent branches so they will be located next to each other,
+    // that way the next micro-optimization will merge them.
+    // ** bail micro-optimization if not a simple switch case with breaks
+    if (body.every((branch, i) =>
+        (branch === default_or_exact || branch.expression instanceof AST_Constant)
+        && (branch.body.length === 0 || aborts(branch) || body.length - 1 === i))
+    ) {
+        for (let i = 0; i < body.length; i++) {
+            const branch = body[i];
+            for (let j = i + 1; j < body.length; j++) {
+                const next = body[j];
+                if (next.body.length === 0) continue;
+                const last_branch = j === (body.length - 1);
+                const equivalentBranch = branches_equivalent(next, branch, false);
+                if (equivalentBranch || (last_branch && branches_equivalent(next, branch, true))) {
+                    if (!equivalentBranch && last_branch) {
+                        next.body.push(make_node(AST_Break));
+                    }
+
+                    // let's find previous siblings with inert fallthrough...
+                    let x = j - 1;
+                    let fallthroughDepth = 0;
+                    while (x > i) {
+                        if (is_inert_body(body[x--])) {
+                            fallthroughDepth++;
+                        } else {
+                            break;
+                        }
+                    }
+
+                    const plucked = body.splice(j - fallthroughDepth, 1 + fallthroughDepth);
+                    body.splice(i + 1, 0, ...plucked);
+                    i += plucked.length;
+                }
+            }
+        }
+    }
+
+    // merge equivalent branches in a row
+    for (let i = 0; i < body.length; i++) {
+        let branch = body[i];
+        if (branch.body.length === 0) continue;
+        if (!aborts(branch)) continue;
+
+        for (let j = i + 1; j < body.length; i++, j++) {
+            let next = body[j];
+            if (next.body.length === 0) continue;
+            if (
+                branches_equivalent(next, branch, false)
+                || (j === body.length - 1 && branches_equivalent(next, branch, true))
+            ) {
+                branch.body = [];
+                branch = next;
+                continue;
+            }
+            break;
+        }
+    }
+
+    // Prune any empty branches at the end of the switch statement.
+    {
+        let i = body.length - 1;
+        for (; i >= 0; i--) {
+            let bbody = body[i].body;
+            while (is_break(bbody[bbody.length - 1], compressor)) bbody.pop();
+            if (!is_inert_body(body[i])) break;
+        }
+        // i now points to the index of a branch that contains a body. By incrementing, it's
+        // pointing to the first branch that's empty.
+        i++;
+        if (!default_or_exact || body.indexOf(default_or_exact) >= i) {
+            // The default behavior is to do nothing. We can take advantage of that to
+            // remove all case expressions that are side-effect free that also do
+            // nothing, since they'll default to doing nothing. But we can't remove any
+            // case expressions before one that would side-effect, since they may cause
+            // the side-effect to be skipped.
+            for (let j = body.length - 1; j >= i; j--) {
+                let branch = body[j];
+                if (branch === default_or_exact) {
+                    default_or_exact = null;
+                    eliminate_branch(body.pop());
+                } else if (!branch.expression.has_side_effects(compressor)) {
+                    eliminate_branch(body.pop());
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+
+
+    // Prune side-effect free branches that fall into default.
+    DEFAULT: if (default_or_exact) {
+        let default_index = body.indexOf(default_or_exact);
+        let default_body_index = default_index;
+        for (; default_body_index < body.length - 1; default_body_index++) {
+            if (!is_inert_body(body[default_body_index])) break;
+        }
+        if (default_body_index < body.length - 1) {
+            break DEFAULT;
+        }
+
+        let side_effect_index = body.length - 1;
+        for (; side_effect_index >= 0; side_effect_index--) {
+            let branch = body[side_effect_index];
+            if (branch === default_or_exact) continue;
+            if (branch.expression.has_side_effects(compressor)) break;
+        }
+        // If the default behavior comes after any side-effect case expressions,
+        // then we can fold all side-effect free cases into the default branch.
+        // If the side-effect case is after the default, then any side-effect
+        // free cases could prevent the side-effect from occurring.
+        if (default_body_index > side_effect_index) {
+            let prev_body_index = default_index - 1;
+            for (; prev_body_index >= 0; prev_body_index--) {
+                if (!is_inert_body(body[prev_body_index])) break;
+            }
+            let before = Math.max(side_effect_index, prev_body_index) + 1;
+            let after = default_index;
+            if (side_effect_index > default_index) {
+                // If the default falls into the same body as a side-effect
+                // case, then we need preserve that case and only prune the
+                // cases after it.
+                after = side_effect_index;
+                body[side_effect_index].body = body[default_body_index].body;
+            } else {
+                // The default will be the last branch.
+                default_or_exact.body = body[default_body_index].body;
+            }
+
+            // Prune everything after the default (or last side-effect case)
+            // until the next case with a body.
+            body.splice(after + 1, default_body_index - after);
+            // Prune everything before the default that falls into it.
+            body.splice(before, default_index - before);
+        }
+    }
+
+    // See if we can remove the switch entirely if all cases (the default) fall into the same case body.
+    DEFAULT: if (default_or_exact) {
+        let i = body.findIndex(branch => !is_inert_body(branch));
+        let caseBody;
+        // `i` is equal to one of the following:
+        // - `-1`, there is no body in the switch statement.
+        // - `body.length - 1`, all cases fall into the same body.
+        // - anything else, there are multiple bodies in the switch.
+        if (i === body.length - 1) {
+            // All cases fall into the case body.
+            let branch = body[i];
+            if (has_nested_break(self)) break DEFAULT;
+
+            // This is the last case body, and we've already pruned any breaks, so it's
+            // safe to hoist.
+            caseBody = make_node(AST_BlockStatement, branch, {
+                body: branch.body
+            });
+            branch.body = [];
+        } else if (i !== -1) {
+            // If there are multiple bodies, then we cannot optimize anything.
+            break DEFAULT;
+        }
+
+        let sideEffect = body.find(
+            branch => branch !== default_or_exact && branch.expression.has_side_effects(compressor)
+        );
+        // If no cases cause a side-effect, we can eliminate the switch entirely.
+        if (!sideEffect) {
+            return make_node(AST_BlockStatement, self, {
+                body: decl.concat(
+                    statement(self.expression),
+                    default_or_exact.expression ? statement(default_or_exact.expression) : [],
+                    caseBody || []
+                )
+            }).optimize(compressor);
+        }
+
+        // If we're this far, either there was no body or all cases fell into the same body.
+        // If there was no body, then we don't need a default branch (because the default is
+        // do nothing). If there was a body, we'll extract it to after the switch, so the
+        // switch's new default is to do nothing and we can still prune it.
+        const default_index = body.indexOf(default_or_exact);
+        body.splice(default_index, 1);
+        default_or_exact = null;
+
+        if (caseBody) {
+            // Recurse into switch statement one more time so that we can append the case body
+            // outside of the switch. This recursion will only happen once since we've pruned
+            // the default case.
+            return make_node(AST_BlockStatement, self, {
+                body: decl.concat(self, caseBody)
+            }).optimize(compressor);
+        }
+        // If we fall here, there is a default branch somewhere, there are no case bodies,
+        // and there's a side-effect somewhere. Just let the below paths take care of it.
+    }
+
+    // Reintegrate `decl` (var statements)
+    if (body.length > 0) {
+        body[0].body = decl.concat(body[0].body);
+    }
+    if (body.length == 0) {
+        return make_node(AST_BlockStatement, self, {
+            body: decl.concat(statement(self.expression))
+        }).optimize(compressor);
+    }
+
+    if (body.length == 1 && !has_nested_break(self)) {
+        // This is the last case body, and we've already pruned any breaks, so it's
+        // safe to hoist.
+        let branch = body[0];
+        return make_node(AST_If, self, {
+            condition: make_node(AST_Binary, self, {
+                operator: "===",
+                left: self.expression,
+                right: branch.expression,
+            }),
+            body: make_node(AST_BlockStatement, branch, {
+                body: branch.body
+            }),
+            alternative: null
+        }).optimize(compressor);
+    }
+    if (body.length === 2 && default_or_exact && !has_nested_break(self)) {
+        let branch = body[0] === default_or_exact ? body[1] : body[0];
+        let exact_exp = default_or_exact.expression && statement(default_or_exact.expression);
+        if (aborts(body[0])) {
+            // Only the first branch body could have a break (at the last statement)
+            let first = body[0];
+            if (is_break(first.body[first.body.length - 1], compressor)) {
+                first.body.pop();
+            }
+            return make_node(AST_If, self, {
+                condition: make_node(AST_Binary, self, {
+                    operator: "===",
+                    left: self.expression,
+                    right: branch.expression,
+                }),
+                body: make_node(AST_BlockStatement, branch, {
+                    body: branch.body
+                }),
+                alternative: make_node(AST_BlockStatement, default_or_exact, {
+                    body: [].concat(
+                        exact_exp || [],
+                        default_or_exact.body
+                    )
+                })
+            }).optimize(compressor);
+        }
+        let operator = "===";
+        let consequent = make_node(AST_BlockStatement, branch, {
+            body: branch.body,
+        });
+        let always = make_node(AST_BlockStatement, default_or_exact, {
+            body: [].concat(
+                exact_exp || [],
+                default_or_exact.body
+            )
+        });
+        if (body[0] === default_or_exact) {
+            operator = "!==";
+            let tmp = always;
+            always = consequent;
+            consequent = tmp;
+        }
+        return make_node(AST_BlockStatement, self, {
+            body: [
+                make_node(AST_If, self, {
+                    condition: make_node(AST_Binary, self, {
+                        operator: operator,
+                        left: self.expression,
+                        right: branch.expression,
+                    }),
+                    body: consequent,
+                    alternative: null,
+                }),
+                always,
+            ],
+        }).optimize(compressor);
+    }
+    return self;
+
+    function eliminate_branch(branch, prev) {
+        if (prev && !aborts(prev)) {
+            prev.body = prev.body.concat(branch.body);
+        } else {
+            extract_from_unreachable_code(compressor, branch, decl);
+        }
+    }
+    function branches_equivalent(branch, prev, insertBreak) {
+        let bbody = branch.body;
+        let pbody = prev.body;
+        if (insertBreak) {
+            bbody = bbody.concat(make_node(AST_Break));
+        }
+        if (bbody.length !== pbody.length) return false;
+        let bblock = make_node(AST_BlockStatement, branch, { body: bbody });
+        let pblock = make_node(AST_BlockStatement, prev, { body: pbody });
+        return bblock.equivalent_to(pblock);
+    }
+    function statement(body) {
+        return make_node(AST_SimpleStatement, body, { body });
+    }
+    function has_nested_break(root) {
+        let has_break = false;
+
+        let tw = new TreeWalker(node => {
+            if (has_break) return true;
+            if (node instanceof AST_Lambda) return true;
+            if (node instanceof AST_SimpleStatement) return true;
+            if (!is_break(node, tw)) return;
+            let parent = tw.parent();
+            if (
+                parent instanceof AST_SwitchBranch
+                && parent.body[parent.body.length - 1] === node
+            ) {
+                return;
+            }
+            has_break = true;
+        });
+        root.walk(tw);
+        return has_break;
+    }
+    function is_break(node, stack) {
+        return node instanceof AST_Break
+            && stack.loopcontrol_target(node) === self;
+    }
+    function is_inert_body(branch) {
+        return !aborts(branch) && !make_node(AST_BlockStatement, branch, {
+            body: branch.body
+        }).has_side_effects(compressor);
+    }
+});
+
+def_optimize(AST_Try, function(self, compressor) {
+    if (self.bcatch && self.bfinally && self.bfinally.body.every(is_empty)) self.bfinally = null;
+
+    if (compressor.option("dead_code") && self.body.body.every(is_empty)) {
+        var body = [];
+        if (self.bcatch) {
+            extract_from_unreachable_code(compressor, self.bcatch, body);
+        }
+        if (self.bfinally) body.push(...self.bfinally.body);
+        return make_node(AST_BlockStatement, self, {
+            body: body
+        }).optimize(compressor);
+    }
+    return self;
+});
+
+AST_Definitions.DEFMETHOD("to_assignments", function(compressor) {
+    var reduce_vars = compressor.option("reduce_vars");
+    var assignments = [];
+
+    for (const def of this.definitions) {
+        if (def.value) {
+            var name = make_node(AST_SymbolRef, def.name, def.name);
+            assignments.push(make_node(AST_Assign, def, {
+                operator : "=",
+                logical: false,
+                left     : name,
+                right    : def.value
+            }));
+            if (reduce_vars) name.definition().fixed = false;
+        }
+        const thedef = def.name.definition();
+        thedef.eliminated++;
+        thedef.replaced--;
+    }
+
+    if (assignments.length == 0) return null;
+    return make_sequence(this, assignments);
+});
+
+def_optimize(AST_Definitions, function(self) {
+    if (self.definitions.length == 0) {
+        return make_node(AST_EmptyStatement, self);
+    }
+    return self;
+});
+
+def_optimize(AST_VarDef, function(self, compressor) {
+    if (
+        self.name instanceof AST_SymbolLet
+        && self.value != null
+        && is_undefined(self.value, compressor)
+    ) {
+        self.value = null;
+    }
+    return self;
+});
+
+def_optimize(AST_Import, function(self) {
+    return self;
+});
+
+def_optimize(AST_Call, function(self, compressor) {
+    var exp = self.expression;
+    var fn = exp;
+    inline_array_like_spread(self.args);
+    var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
+
+    if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
+        fn = fn.fixed_value();
+    }
+
+    var is_func = fn instanceof AST_Lambda;
+
+    if (is_func && fn.pinned()) return self;
+
+    if (compressor.option("unused")
+        && simple_args
+        && is_func
+        && !fn.uses_arguments) {
+        var pos = 0, last = 0;
+        for (var i = 0, len = self.args.length; i < len; i++) {
+            if (fn.argnames[i] instanceof AST_Expansion) {
+                if (has_flag(fn.argnames[i].expression, UNUSED)) while (i < len) {
+                    var node = self.args[i++].drop_side_effect_free(compressor);
+                    if (node) {
+                        self.args[pos++] = node;
+                    }
+                } else while (i < len) {
+                    self.args[pos++] = self.args[i++];
+                }
+                last = pos;
+                break;
+            }
+            var trim = i >= fn.argnames.length;
+            if (trim || has_flag(fn.argnames[i], UNUSED)) {
+                var node = self.args[i].drop_side_effect_free(compressor);
+                if (node) {
+                    self.args[pos++] = node;
+                } else if (!trim) {
+                    self.args[pos++] = make_node(AST_Number, self.args[i], {
+                        value: 0
+                    });
+                    continue;
+                }
+            } else {
+                self.args[pos++] = self.args[i];
+            }
+            last = pos;
+        }
+        self.args.length = last;
+    }
+
+    if (
+        exp instanceof AST_Dot
+        && exp.expression instanceof AST_SymbolRef
+        && exp.expression.name === "console"
+        && exp.expression.definition().undeclared
+        && exp.property === "assert"
+    ) {
+        const condition = self.args[0];
+        if (condition) {
+            const value = condition.evaluate(compressor);
+    
+            if (value === 1 || value === true) {
+                return make_void_0(self).optimize(compressor);
+            }
+        }
+    }    
+
+    if (compressor.option("unsafe") && !exp.contains_optional()) {
+        if (exp instanceof AST_Dot && exp.start.value === "Array" && exp.property === "from" && self.args.length === 1) {
+            const [argument] = self.args;
+            if (argument instanceof AST_Array) {
+                return make_node(AST_Array, argument, {
+                    elements: argument.elements
+                }).optimize(compressor);
+            }
+        }
+        if (is_undeclared_ref(exp)) switch (exp.name) {
+          case "Array":
+            if (self.args.length != 1) {
+                return make_node(AST_Array, self, {
+                    elements: self.args
+                }).optimize(compressor);
+            } else if (self.args[0] instanceof AST_Number && self.args[0].value <= 11) {
+                const elements = [];
+                for (let i = 0; i < self.args[0].value; i++) elements.push(new AST_Hole);
+                return new AST_Array({ elements });
+            }
+            break;
+          case "Object":
+            if (self.args.length == 0) {
+                return make_node(AST_Object, self, {
+                    properties: []
+                });
+            }
+            break;
+          case "String":
+            if (self.args.length == 0) return make_node(AST_String, self, {
+                value: ""
+            });
+            if (self.args.length <= 1) return make_node(AST_Binary, self, {
+                left: self.args[0],
+                operator: "+",
+                right: make_node(AST_String, self, { value: "" })
+            }).optimize(compressor);
+            break;
+          case "Number":
+            if (self.args.length == 0) return make_node(AST_Number, self, {
+                value: 0
+            });
+            if (self.args.length == 1 && compressor.option("unsafe_math")) {
+                return make_node(AST_UnaryPrefix, self, {
+                    expression: self.args[0],
+                    operator: "+"
+                }).optimize(compressor);
+            }
+            break;
+          case "Symbol":
+            if (self.args.length == 1 && self.args[0] instanceof AST_String && compressor.option("unsafe_symbols"))
+                self.args.length = 0;
+                break;
+          case "Boolean":
+            if (self.args.length == 0) return make_node(AST_False, self);
+            if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, {
+                expression: make_node(AST_UnaryPrefix, self, {
+                    expression: self.args[0],
+                    operator: "!"
+                }),
+                operator: "!"
+            }).optimize(compressor);
+            break;
+          case "RegExp":
+            var params = [];
+            if (self.args.length >= 1
+                && self.args.length <= 2
+                && self.args.every((arg) => {
+                    var value = arg.evaluate(compressor);
+                    params.push(value);
+                    return arg !== value;
+                })
+                && regexp_is_safe(params[0])
+            ) {
+                let [ source, flags ] = params;
+                source = regexp_source_fix(new RegExp(source).source);
+                const rx = make_node(AST_RegExp, self, {
+                    value: { source, flags }
+                });
+                if (rx._eval(compressor) !== rx) {
+                    return rx;
+                }
+            }
+            break;
+        } else if (exp instanceof AST_Dot) switch(exp.property) {
+          case "toString":
+            if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) {
+                return make_node(AST_Binary, self, {
+                    left: make_node(AST_String, self, { value: "" }),
+                    operator: "+",
+                    right: exp.expression
+                }).optimize(compressor);
+            }
+            break;
+          case "join":
+            if (exp.expression instanceof AST_Array) EXIT: {
+                var separator;
+                if (self.args.length > 0) {
+                    separator = self.args[0].evaluate(compressor);
+                    if (separator === self.args[0]) break EXIT; // not a constant
+                }
+                var elements = [];
+                var consts = [];
+                for (var i = 0, len = exp.expression.elements.length; i < len; i++) {
+                    var el = exp.expression.elements[i];
+                    if (el instanceof AST_Expansion) break EXIT;
+                    var value = el.evaluate(compressor);
+                    if (value !== el) {
+                        consts.push(value);
+                    } else {
+                        if (consts.length > 0) {
+                            elements.push(make_node(AST_String, self, {
+                                value: consts.join(separator)
+                            }));
+                            consts.length = 0;
+                        }
+                        elements.push(el);
+                    }
+                }
+                if (consts.length > 0) {
+                    elements.push(make_node(AST_String, self, {
+                        value: consts.join(separator)
+                    }));
+                }
+                if (elements.length == 0) return make_node(AST_String, self, { value: "" });
+                if (elements.length == 1) {
+                    if (elements[0].is_string(compressor)) {
+                        return elements[0];
+                    }
+                    return make_node(AST_Binary, elements[0], {
+                        operator : "+",
+                        left     : make_node(AST_String, self, { value: "" }),
+                        right    : elements[0]
+                    });
+                }
+                if (separator == "") {
+                    var first;
+                    if (elements[0].is_string(compressor)
+                        || elements[1].is_string(compressor)) {
+                        first = elements.shift();
+                    } else {
+                        first = make_node(AST_String, self, { value: "" });
+                    }
+                    return elements.reduce(function(prev, el) {
+                        return make_node(AST_Binary, el, {
+                            operator : "+",
+                            left     : prev,
+                            right    : el
+                        });
+                    }, first).optimize(compressor);
+                }
+                // need this awkward cloning to not affect original element
+                // best_of will decide which one to get through.
+                var node = self.clone();
+                node.expression = node.expression.clone();
+                node.expression.expression = node.expression.expression.clone();
+                node.expression.expression.elements = elements;
+                return best_of(compressor, self, node);
+            }
+            break;
+          case "charAt":
+            if (exp.expression.is_string(compressor)) {
+                var arg = self.args[0];
+                var index = arg ? arg.evaluate(compressor) : 0;
+                if (index !== arg) {
+                    return make_node(AST_Sub, exp, {
+                        expression: exp.expression,
+                        property: make_node_from_constant(index | 0, arg || exp)
+                    }).optimize(compressor);
+                }
+            }
+            break;
+          case "apply":
+            if (self.args.length == 2 && self.args[1] instanceof AST_Array) {
+                var args = self.args[1].elements.slice();
+                args.unshift(self.args[0]);
+                return make_node(AST_Call, self, {
+                    expression: make_node(AST_Dot, exp, {
+                        expression: exp.expression,
+                        optional: false,
+                        property: "call"
+                    }),
+                    args: args
+                }).optimize(compressor);
+            }
+            break;
+          case "call":
+            var func = exp.expression;
+            if (func instanceof AST_SymbolRef) {
+                func = func.fixed_value();
+            }
+            if (func instanceof AST_Lambda && !func.contains_this()) {
+                return (self.args.length ? make_sequence(this, [
+                    self.args[0],
+                    make_node(AST_Call, self, {
+                        expression: exp.expression,
+                        args: self.args.slice(1)
+                    })
+                ]) : make_node(AST_Call, self, {
+                    expression: exp.expression,
+                    args: []
+                })).optimize(compressor);
+            }
+            break;
+        }
+    }
+
+    if (compressor.option("unsafe_Function")
+        && is_undeclared_ref(exp)
+        && exp.name == "Function") {
+        // new Function() => function(){}
+        if (self.args.length == 0) return make_empty_function(self).optimize(compressor);
+        if (self.args.every((x) => x instanceof AST_String)) {
+            // quite a corner-case, but we can handle it:
+            //   https://github.com/mishoo/UglifyJS2/issues/203
+            // if the code argument is a constant, then we can minify it.
+            try {
+                var code = "n(function(" + self.args.slice(0, -1).map(function(arg) {
+                    return arg.value;
+                }).join(",") + "){" + self.args[self.args.length - 1].value + "})";
+                var ast = parse(code);
+                var mangle = compressor.mangle_options();
+                ast.figure_out_scope(mangle);
+                var comp = new Compressor(compressor.options, {
+                    mangle_options: compressor._mangle_options
+                });
+                ast = ast.transform(comp);
+                ast.figure_out_scope(mangle);
+                ast.compute_char_frequency(mangle);
+                ast.mangle_names(mangle);
+                var fun;
+                walk(ast, node => {
+                    if (is_func_expr(node)) {
+                        fun = node;
+                        return walk_abort;
+                    }
+                });
+                var code = OutputStream();
+                AST_BlockStatement.prototype._codegen.call(fun, fun, code);
+                self.args = [
+                    make_node(AST_String, self, {
+                        value: fun.argnames.map(function(arg) {
+                            return arg.print_to_string();
+                        }).join(",")
+                    }),
+                    make_node(AST_String, self.args[self.args.length - 1], {
+                        value: code.get().replace(/^{|}$/g, "")
+                    })
+                ];
+                return self;
+            } catch (ex) {
+                if (!(ex instanceof JS_Parse_Error)) {
+                    throw ex;
+                }
+
+                // Otherwise, it crashes at runtime. Or maybe it's nonstandard syntax.
+            }
+        }
+    }
+
+    return inline_into_call(self, compressor);
+});
+
+/** Does this node contain optional property access or optional call? */
+AST_Node.DEFMETHOD("contains_optional", function() {
+    if (
+        this instanceof AST_PropAccess
+        || this instanceof AST_Call
+        || this instanceof AST_Chain
+    ) {
+        if (this.optional) {
+            return true;
+        } else {
+            return this.expression.contains_optional();
+        }
+    } else {
+        return false;
+    }
+});
+
+def_optimize(AST_New, function(self, compressor) {
+    if (
+        compressor.option("unsafe") &&
+        is_undeclared_ref(self.expression) &&
+        ["Object", "RegExp", "Function", "Error", "Array"].includes(self.expression.name)
+    ) return make_node(AST_Call, self, self).transform(compressor);
+    return self;
+});
+
+def_optimize(AST_Sequence, function(self, compressor) {
+    if (!compressor.option("side_effects")) return self;
+    var expressions = [];
+    filter_for_side_effects();
+    var end = expressions.length - 1;
+    trim_right_for_undefined();
+    if (end == 0) {
+        self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]);
+        if (!(self instanceof AST_Sequence)) self = self.optimize(compressor);
+        return self;
+    }
+    self.expressions = expressions;
+    return self;
+
+    function filter_for_side_effects() {
+        var first = first_in_statement(compressor);
+        var last = self.expressions.length - 1;
+        self.expressions.forEach(function(expr, index) {
+            if (index < last) expr = expr.drop_side_effect_free(compressor, first);
+            if (expr) {
+                merge_sequence(expressions, expr);
+                first = false;
+            }
+        });
+    }
+
+    function trim_right_for_undefined() {
+        while (end > 0 && is_undefined(expressions[end], compressor)) end--;
+        if (end < expressions.length - 1) {
+            expressions[end] = make_node(AST_UnaryPrefix, self, {
+                operator   : "void",
+                expression : expressions[end]
+            });
+            expressions.length = end + 1;
+        }
+    }
+});
+
+AST_Unary.DEFMETHOD("lift_sequences", function(compressor) {
+    if (compressor.option("sequences")) {
+        if (this.expression instanceof AST_Sequence) {
+            var x = this.expression.expressions.slice();
+            var e = this.clone();
+            e.expression = x.pop();
+            x.push(e);
+            return make_sequence(this, x).optimize(compressor);
+        }
+    }
+    return this;
+});
+
+def_optimize(AST_UnaryPostfix, function(self, compressor) {
+    return self.lift_sequences(compressor);
+});
+
+def_optimize(AST_UnaryPrefix, function(self, compressor) {
+    var e = self.expression;
+    if (
+        self.operator == "delete" &&
+        !(
+            e instanceof AST_SymbolRef ||
+            e instanceof AST_PropAccess ||
+            e instanceof AST_Chain ||
+            is_identifier_atom(e)
+        )
+    ) {
+        return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor);
+    }
+    // Short-circuit common `void 0`
+    if (self.operator === "void" && e instanceof AST_Number && e.value === 0) {
+        return unsafe_undefined_ref(self, compressor) || self;
+    }
+    var seq = self.lift_sequences(compressor);
+    if (seq !== self) {
+        return seq;
+    }
+    if (compressor.option("side_effects") && self.operator == "void") {
+        e = e.drop_side_effect_free(compressor);
+        if (e) {
+            self.expression = e;
+            return self;
+        } else {
+            return make_void_0(self).optimize(compressor);
+        }
+    }
+    if (compressor.in_boolean_context()) {
+        switch (self.operator) {
+          case "!":
+            if (e instanceof AST_UnaryPrefix && e.operator == "!") {
+                // !!foo ==> foo, if we're in boolean context
+                return e.expression;
+            }
+            if (e instanceof AST_Binary) {
+                self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
+            }
+            break;
+          case "typeof":
+            // typeof always returns a non-empty string, thus it's
+            // always true in booleans
+            // And we don't need to check if it's undeclared, because in typeof, that's OK
+            return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [
+                e,
+                make_node(AST_True, self)
+            ])).optimize(compressor);
+        }
+    }
+    if (self.operator == "-" && e instanceof AST_Infinity) {
+        e = e.transform(compressor);
+    }
+    if (e instanceof AST_Binary
+        && (self.operator == "+" || self.operator == "-")
+        && (e.operator == "*" || e.operator == "/" || e.operator == "%")) {
+        return make_node(AST_Binary, self, {
+            operator: e.operator,
+            left: make_node(AST_UnaryPrefix, e.left, {
+                operator: self.operator,
+                expression: e.left
+            }),
+            right: e.right
+        });
+    }
+
+    if (compressor.option("evaluate")) {
+        // ~~x => x (in 32-bit context)
+        // ~~{32 bit integer} => {32 bit integer}
+        if (
+            self.operator === "~"
+            && self.expression instanceof AST_UnaryPrefix
+            && self.expression.operator === "~"
+            && (compressor.in_32_bit_context(false) || self.expression.expression.is_32_bit_integer(compressor))
+        ) {
+            return self.expression.expression;
+        }
+
+        // ~(x ^ y) => x ^ ~y
+        if (
+            self.operator === "~"
+            && e instanceof AST_Binary
+            && e.operator === "^"
+        ) {
+            if (e.left instanceof AST_UnaryPrefix && e.left.operator === "~") {
+                // ~(~x ^ y) => x ^ y
+                e.left = e.left.bitwise_negate(compressor, true);
+            } else {
+                e.right = e.right.bitwise_negate(compressor, true);
+            }
+            return e;
+        }
+    }
+
+    if (
+        self.operator != "-"
+        // avoid infinite recursion of numerals
+        || !(e instanceof AST_Number || e instanceof AST_Infinity || e instanceof AST_BigInt)
+    ) {
+        var ev = self.evaluate(compressor);
+        if (ev !== self) {
+            ev = make_node_from_constant(ev, self).optimize(compressor);
+            return best_of(compressor, ev, self);
+        }
+    }
+    return self;
+});
+
+AST_Binary.DEFMETHOD("lift_sequences", function(compressor) {
+    if (compressor.option("sequences")) {
+        if (this.left instanceof AST_Sequence) {
+            var x = this.left.expressions.slice();
+            var e = this.clone();
+            e.left = x.pop();
+            x.push(e);
+            return make_sequence(this, x).optimize(compressor);
+        }
+        if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) {
+            var assign = this.operator == "=" && this.left instanceof AST_SymbolRef;
+            var x = this.right.expressions;
+            var last = x.length - 1;
+            for (var i = 0; i < last; i++) {
+                if (!assign && x[i].has_side_effects(compressor)) break;
+            }
+            if (i == last) {
+                x = x.slice();
+                var e = this.clone();
+                e.right = x.pop();
+                x.push(e);
+                return make_sequence(this, x).optimize(compressor);
+            } else if (i > 0) {
+                var e = this.clone();
+                e.right = make_sequence(this.right, x.slice(i));
+                x = x.slice(0, i);
+                x.push(e);
+                return make_sequence(this, x).optimize(compressor);
+            }
+        }
+    }
+    return this;
+});
+
+var commutativeOperators = makePredicate("== === != !== * & | ^");
+function is_object(node) {
+    return node instanceof AST_Array
+        || node instanceof AST_Lambda
+        || node instanceof AST_Object
+        || node instanceof AST_Class;
+}
+
+def_optimize(AST_Binary, function(self, compressor) {
+    function reversible() {
+        return self.left.is_constant()
+            || self.right.is_constant()
+            || !self.left.has_side_effects(compressor)
+                && !self.right.has_side_effects(compressor);
+    }
+    function reverse(op) {
+        if (reversible()) {
+            if (op) self.operator = op;
+            var tmp = self.left;
+            self.left = self.right;
+            self.right = tmp;
+        }
+    }
+    if (compressor.option("lhs_constants") && commutativeOperators.has(self.operator)) {
+        if (self.right.is_constant()
+            && !self.left.is_constant()) {
+            // if right is a constant, whatever side effects the
+            // left side might have could not influence the
+            // result.  hence, force switch.
+
+            if (!(self.left instanceof AST_Binary
+                  && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
+                reverse();
+            }
+        }
+    }
+    self = self.lift_sequences(compressor);
+    if (compressor.option("comparisons")) switch (self.operator) {
+      case "===":
+      case "!==":
+        var is_strict_comparison = true;
+        if (
+            (self.left.is_string(compressor) && self.right.is_string(compressor)) ||
+            (self.left.is_number(compressor) && self.right.is_number(compressor)) ||
+            (self.left.is_bigint(compressor) && self.right.is_bigint(compressor)) ||
+            (self.left.is_boolean() && self.right.is_boolean()) ||
+            self.left.equivalent_to(self.right)
+        ) {
+            self.operator = self.operator.substr(0, 2);
+        }
+
+        // XXX: intentionally falling down to the next case
+      case "==":
+      case "!=":
+        // void 0 == x => null == x
+        if (!is_strict_comparison && is_undefined(self.left, compressor)) {
+            self.left = make_node(AST_Null, self.left);
+        // x == void 0 => x == null
+        } else if (!is_strict_comparison && is_undefined(self.right, compressor)) {
+            self.right = make_node(AST_Null, self.right);
+        } else if (compressor.option("typeofs")
+            // "undefined" == typeof x => undefined === x
+            && self.left instanceof AST_String
+            && self.left.value == "undefined"
+            && self.right instanceof AST_UnaryPrefix
+            && self.right.operator == "typeof") {
+            var expr = self.right.expression;
+            if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
+                : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
+                self.right = expr;
+                self.left = make_void_0(self.left).optimize(compressor);
+                if (self.operator.length == 2) self.operator += "=";
+            }
+        } else if (compressor.option("typeofs")
+            // typeof x === "undefined" => x === undefined
+            && self.left instanceof AST_UnaryPrefix
+            && self.left.operator == "typeof"
+            && self.right instanceof AST_String
+            && self.right.value == "undefined") {
+            var expr = self.left.expression;
+            if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
+                : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
+                self.left = expr;
+                self.right = make_void_0(self.right).optimize(compressor);
+                if (self.operator.length == 2) self.operator += "=";
+            }
+        } else if (self.left instanceof AST_SymbolRef
+            // obj !== obj => false
+            && self.right instanceof AST_SymbolRef
+            && self.left.definition() === self.right.definition()
+            && is_object(self.left.fixed_value())) {
+            return make_node(self.operator[0] == "=" ? AST_True : AST_False, self);
+        } else if (self.left.is_32_bit_integer(compressor) && self.right.is_32_bit_integer(compressor)) {
+            const not = node => make_node(AST_UnaryPrefix, node, {
+                operator: "!",
+                expression: node
+            });
+            const booleanify = (node, truthy) => {
+                if (truthy) {
+                    return compressor.in_boolean_context()
+                        ? node
+                        : not(not(node));
+                } else {
+                    return not(node);
+                }
+            };
+
+            // The only falsy 32-bit integer is 0
+            if (self.left instanceof AST_Number && self.left.value === 0) {
+                return booleanify(self.right, self.operator[0] === "!");
+            }
+            if (self.right instanceof AST_Number && self.right.value === 0) {
+                return booleanify(self.left, self.operator[0] === "!");
+            }
+
+            // Mask all-bits check
+            // (x & 0xFF) != 0xFF => !(~x & 0xFF)
+            let and_op, x, mask;
+            if (
+                (and_op =
+                    self.left instanceof AST_Binary ? self.left
+                    : self.right instanceof AST_Binary ? self.right : null)
+                && (mask = and_op === self.left ? self.right : self.left)
+                && and_op.operator === "&"
+                && mask instanceof AST_Number
+                && mask.is_32_bit_integer(compressor)
+                && (x =
+                    and_op.left.equivalent_to(mask) ? and_op.right
+                    : and_op.right.equivalent_to(mask) ? and_op.left : null)
+            ) {
+                let optimized = booleanify(make_node(AST_Binary, self, {
+                    operator: "&",
+                    left: mask,
+                    right: make_node(AST_UnaryPrefix, self, {
+                        operator: "~",
+                        expression: x
+                    })
+                }), self.operator[0] === "!");
+
+                return best_of(compressor, optimized, self);
+            }
+        }
+        break;
+      case "&&":
+      case "||":
+        var lhs = self.left;
+        if (lhs.operator == self.operator) {
+            lhs = lhs.right;
+        }
+        if (lhs instanceof AST_Binary
+            && lhs.operator == (self.operator == "&&" ? "!==" : "===")
+            && self.right instanceof AST_Binary
+            && lhs.operator == self.right.operator
+            && (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null
+                || lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor))
+            && !lhs.right.has_side_effects(compressor)
+            && lhs.right.equivalent_to(self.right.right)) {
+            var combined = make_node(AST_Binary, self, {
+                operator: lhs.operator.slice(0, -1),
+                left: make_node(AST_Null, self),
+                right: lhs.right
+            });
+            if (lhs !== self.left) {
+                combined = make_node(AST_Binary, self, {
+                    operator: self.operator,
+                    left: self.left.left,
+                    right: combined
+                });
+            }
+            return combined;
+        }
+        break;
+    }
+    if (self.operator == "+" && compressor.in_boolean_context()) {
+        var ll = self.left.evaluate(compressor);
+        var rr = self.right.evaluate(compressor);
+        if (ll && typeof ll == "string") {
+            return make_sequence(self, [
+                self.right,
+                make_node(AST_True, self)
+            ]).optimize(compressor);
+        }
+        if (rr && typeof rr == "string") {
+            return make_sequence(self, [
+                self.left,
+                make_node(AST_True, self)
+            ]).optimize(compressor);
+        }
+    }
+    if (compressor.option("comparisons") && self.is_boolean()) {
+        if (!(compressor.parent() instanceof AST_Binary)
+            || compressor.parent() instanceof AST_Assign) {
+            var negated = make_node(AST_UnaryPrefix, self, {
+                operator: "!",
+                expression: self.negate(compressor, first_in_statement(compressor))
+            });
+            self = best_of(compressor, self, negated);
+        }
+        if (compressor.option("unsafe_comps")) {
+            switch (self.operator) {
+              case "<": reverse(">"); break;
+              case "<=": reverse(">="); break;
+            }
+        }
+    }
+    if (self.operator == "+") {
+        if (self.right instanceof AST_String
+            && self.right.getValue() == ""
+            && self.left.is_string(compressor)) {
+            return self.left;
+        }
+        if (self.left instanceof AST_String
+            && self.left.getValue() == ""
+            && self.right.is_string(compressor)) {
+            return self.right;
+        }
+        if (self.left instanceof AST_Binary
+            && self.left.operator == "+"
+            && self.left.left instanceof AST_String
+            && self.left.left.getValue() == ""
+            && self.right.is_string(compressor)) {
+            self.left = self.left.right;
+            return self;
+        }
+    }
+    if (compressor.option("evaluate")) {
+        switch (self.operator) {
+          case "&&":
+            var ll = has_flag(self.left, TRUTHY)
+                ? true
+                : has_flag(self.left, FALSY)
+                    ? false
+                    : self.left.evaluate(compressor);
+            if (!ll) {
+                return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor);
+            } else if (!(ll instanceof AST_Node)) {
+                return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
+            }
+            var rr = self.right.evaluate(compressor);
+            if (!rr) {
+                if (compressor.in_boolean_context()) {
+                    return make_sequence(self, [
+                        self.left,
+                        make_node(AST_False, self)
+                    ]).optimize(compressor);
+                } else {
+                    set_flag(self, FALSY);
+                }
+            } else if (!(rr instanceof AST_Node)) {
+                var parent = compressor.parent();
+                if (parent.operator == "&&" && parent.left === compressor.self() || compressor.in_boolean_context()) {
+                    return self.left.optimize(compressor);
+                }
+            }
+            // x || false && y ---> x ? y : false
+            if (self.left.operator == "||") {
+                var lr = self.left.right.evaluate(compressor);
+                if (!lr) return make_node(AST_Conditional, self, {
+                    condition: self.left.left,
+                    consequent: self.right,
+                    alternative: self.left.right
+                }).optimize(compressor);
+            }
+            break;
+          case "||":
+            var ll = has_flag(self.left, TRUTHY)
+              ? true
+              : has_flag(self.left, FALSY)
+                ? false
+                : self.left.evaluate(compressor);
+            if (!ll) {
+                return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
+            } else if (!(ll instanceof AST_Node)) {
+                return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor);
+            }
+            var rr = self.right.evaluate(compressor);
+            if (!rr) {
+                var parent = compressor.parent();
+                if (parent.operator == "||" && parent.left === compressor.self() || compressor.in_boolean_context()) {
+                    return self.left.optimize(compressor);
+                }
+            } else if (!(rr instanceof AST_Node)) {
+                if (compressor.in_boolean_context()) {
+                    return make_sequence(self, [
+                        self.left,
+                        make_node(AST_True, self)
+                    ]).optimize(compressor);
+                } else {
+                    set_flag(self, TRUTHY);
+                }
+            }
+            if (self.left.operator == "&&") {
+                var lr = self.left.right.evaluate(compressor);
+                if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, {
+                    condition: self.left.left,
+                    consequent: self.left.right,
+                    alternative: self.right
+                }).optimize(compressor);
+            }
+            break;
+          case "??":
+            if (is_nullish(self.left, compressor)) {
+                return self.right;
+            }
+
+            var ll = self.left.evaluate(compressor);
+            if (!(ll instanceof AST_Node)) {
+                // if we know the value for sure we can simply compute right away.
+                return ll == null ? self.right : self.left;
+            }
+
+            if (compressor.in_boolean_context()) {
+                const rr = self.right.evaluate(compressor);
+                if (!(rr instanceof AST_Node) && !rr) {
+                    return self.left;
+                }
+            }
+        }
+        var associative = true;
+        switch (self.operator) {
+          case "+":
+            // (x + "foo") + "bar" => x + "foobar"
+            if (self.right instanceof AST_Constant
+                && self.left instanceof AST_Binary
+                && self.left.operator == "+"
+                && self.left.is_string(compressor)) {
+                var binary = make_node(AST_Binary, self, {
+                    operator: "+",
+                    left: self.left.right,
+                    right: self.right,
+                });
+                var r = binary.optimize(compressor);
+                if (binary !== r) {
+                    self = make_node(AST_Binary, self, {
+                        operator: "+",
+                        left: self.left.left,
+                        right: r
+                    });
+                }
+            }
+            // (x + "foo") + ("bar" + y) => (x + "foobar") + y
+            if (self.left instanceof AST_Binary
+                && self.left.operator == "+"
+                && self.left.is_string(compressor)
+                && self.right instanceof AST_Binary
+                && self.right.operator == "+"
+                && self.right.is_string(compressor)) {
+                var binary = make_node(AST_Binary, self, {
+                    operator: "+",
+                    left: self.left.right,
+                    right: self.right.left,
+                });
+                var m = binary.optimize(compressor);
+                if (binary !== m) {
+                    self = make_node(AST_Binary, self, {
+                        operator: "+",
+                        left: make_node(AST_Binary, self.left, {
+                            operator: "+",
+                            left: self.left.left,
+                            right: m
+                        }),
+                        right: self.right.right
+                    });
+                }
+            }
+            // a + -b => a - b
+            if (self.right instanceof AST_UnaryPrefix
+                && self.right.operator == "-"
+                && self.left.is_number_or_bigint(compressor)) {
+                self = make_node(AST_Binary, self, {
+                    operator: "-",
+                    left: self.left,
+                    right: self.right.expression
+                });
+                break;
+            }
+            // -a + b => b - a
+            if (self.left instanceof AST_UnaryPrefix
+                && self.left.operator == "-"
+                && reversible()
+                && self.right.is_number_or_bigint(compressor)) {
+                self = make_node(AST_Binary, self, {
+                    operator: "-",
+                    left: self.right,
+                    right: self.left.expression
+                });
+                break;
+            }
+            // `foo${bar}baz` + 1 => `foo${bar}baz1`
+            if (self.left instanceof AST_TemplateString) {
+                var l = self.left;
+                var r = self.right.evaluate(compressor);
+                if (r != self.right) {
+                    l.segments[l.segments.length - 1].value += String(r);
+                    return l;
+                }
+            }
+            // 1 + `foo${bar}baz` => `1foo${bar}baz`
+            if (self.right instanceof AST_TemplateString) {
+                var r = self.right;
+                var l = self.left.evaluate(compressor);
+                if (l != self.left) {
+                    r.segments[0].value = String(l) + r.segments[0].value;
+                    return r;
+                }
+            }
+            // `1${bar}2` + `foo${bar}baz` => `1${bar}2foo${bar}baz`
+            if (self.left instanceof AST_TemplateString
+                && self.right instanceof AST_TemplateString) {
+                var l = self.left;
+                var segments = l.segments;
+                var r = self.right;
+                segments[segments.length - 1].value += r.segments[0].value;
+                for (var i = 1; i < r.segments.length; i++) {
+                    segments.push(r.segments[i]);
+                }
+                return l;
+            }
+          case "*":
+            associative = compressor.option("unsafe_math");
+          case "&":
+          case "|":
+          case "^":
+            // a + +b => +b + a
+            if (
+                self.left.is_number_or_bigint(compressor)
+                && self.right.is_number_or_bigint(compressor)
+                && reversible()
+                && !(self.left instanceof AST_Binary
+                    && self.left.operator != self.operator
+                    && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) {
+                var reversed = make_node(AST_Binary, self, {
+                    operator: self.operator,
+                    left: self.right,
+                    right: self.left
+                });
+                if (self.right instanceof AST_Constant
+                    && !(self.left instanceof AST_Constant)) {
+                    self = best_of(compressor, reversed, self);
+                } else {
+                    self = best_of(compressor, self, reversed);
+                }
+            }
+            if (associative && self.is_number_or_bigint(compressor)) {
+                // a + (b + c) => (a + b) + c
+                if (self.right instanceof AST_Binary
+                    && self.right.operator == self.operator) {
+                    self = make_node(AST_Binary, self, {
+                        operator: self.operator,
+                        left: make_node(AST_Binary, self.left, {
+                            operator: self.operator,
+                            left: self.left,
+                            right: self.right.left,
+                            start: self.left.start,
+                            end: self.right.left.end
+                        }),
+                        right: self.right.right
+                    });
+                }
+                // (n + 2) + 3 => 5 + n
+                // (2 * n) * 3 => 6 + n
+                if (self.right instanceof AST_Constant
+                    && self.left instanceof AST_Binary
+                    && self.left.operator == self.operator) {
+                    if (self.left.left instanceof AST_Constant) {
+                        self = make_node(AST_Binary, self, {
+                            operator: self.operator,
+                            left: make_node(AST_Binary, self.left, {
+                                operator: self.operator,
+                                left: self.left.left,
+                                right: self.right,
+                                start: self.left.left.start,
+                                end: self.right.end
+                            }),
+                            right: self.left.right
+                        });
+                    } else if (self.left.right instanceof AST_Constant) {
+                        self = make_node(AST_Binary, self, {
+                            operator: self.operator,
+                            left: make_node(AST_Binary, self.left, {
+                                operator: self.operator,
+                                left: self.left.right,
+                                right: self.right,
+                                start: self.left.right.start,
+                                end: self.right.end
+                            }),
+                            right: self.left.left
+                        });
+                    }
+                }
+                // (a | 1) | (2 | d) => (3 | a) | b
+                if (self.left instanceof AST_Binary
+                    && self.left.operator == self.operator
+                    && self.left.right instanceof AST_Constant
+                    && self.right instanceof AST_Binary
+                    && self.right.operator == self.operator
+                    && self.right.left instanceof AST_Constant) {
+                    self = make_node(AST_Binary, self, {
+                        operator: self.operator,
+                        left: make_node(AST_Binary, self.left, {
+                            operator: self.operator,
+                            left: make_node(AST_Binary, self.left.left, {
+                                operator: self.operator,
+                                left: self.left.right,
+                                right: self.right.left,
+                                start: self.left.right.start,
+                                end: self.right.left.end
+                            }),
+                            right: self.left.left
+                        }),
+                        right: self.right.right
+                    });
+                }
+            }
+        }
+
+        // bitwise ops
+        if (bitwise_binop.has(self.operator)) {
+            // Use De Morgan's laws
+            // z & (X | y)
+            // => z & X (given y & z === 0)
+            // => z & X | {y & z} (given y & z !== 0)
+            let y, z, x_node, y_node, z_node = self.left;
+            if (
+                self.operator === "&"
+                && self.right instanceof AST_Binary
+                && self.right.operator === "|"
+                && typeof (z = self.left.evaluate(compressor)) === "number"
+            ) {
+                if (typeof (y = self.right.right.evaluate(compressor)) === "number") {
+                    // z & (X | y)
+                    x_node = self.right.left;
+                    y_node = self.right.right;
+                } else if (typeof (y = self.right.left.evaluate(compressor)) === "number") {
+                    // z & (y | X)
+                    x_node = self.right.right;
+                    y_node = self.right.left;
+                }
+
+                if (x_node && y_node) {
+                    if ((y & z) === 0) {
+                        self = make_node(AST_Binary, self, {
+                            operator: self.operator,
+                            left: z_node,
+                            right: x_node
+                        });
+                    } else {
+                        const reordered_ops = make_node(AST_Binary, self, {
+                            operator: "|",
+                            left: make_node(AST_Binary, self, {
+                                operator: "&",
+                                left: x_node,
+                                right: z_node
+                            }),
+                            right: make_node_from_constant(y & z, y_node),
+                        });
+
+                        self = best_of(compressor, self, reordered_ops);
+                    }
+                }
+            }
+
+            // x | x => 0 | x
+            // x & x => 0 | x
+            if (
+                (self.operator === "|" || self.operator === "&")
+                && self.left.equivalent_to(self.right)
+                && !self.left.has_side_effects(compressor)
+                && compressor.in_32_bit_context(true)
+            ) {
+                self.left = make_node(AST_Number, self, { value: 0 });
+                self.operator = "|";
+            }
+
+            // ~x ^ ~y => x ^ y
+            if (
+                self.operator === "^"
+                && self.left instanceof AST_UnaryPrefix
+                && self.left.operator === "~"
+                && self.right instanceof AST_UnaryPrefix
+                && self.right.operator === "~"
+            ) {
+                self = make_node(AST_Binary, self, {
+                    operator: "^",
+                    left: self.left.expression,
+                    right: self.right.expression
+                });
+            }
+
+
+            // Shifts that do nothing
+            // {anything} >> 0 => {anything} | 0
+            // {anything} << 0 => {anything} | 0
+            if (
+                (self.operator === "<<" || self.operator === ">>")
+                && self.right instanceof AST_Number && self.right.value === 0
+            ) {
+                self.operator = "|";
+            }
+
+            // Find useless to-bitwise conversions
+            // {32 bit integer} | 0 => {32 bit integer}
+            // {32 bit integer} ^ 0 => {32 bit integer}
+            const zero_side = self.right instanceof AST_Number && self.right.value === 0 ? self.right
+                : self.left instanceof AST_Number && self.left.value === 0 ? self.left
+                : null;
+            const non_zero_side = zero_side && (zero_side === self.right ? self.left : self.right);
+            if (
+                zero_side
+                && (self.operator === "|" || self.operator === "^")
+                && (non_zero_side.is_32_bit_integer(compressor) || compressor.in_32_bit_context(true))
+            ) {
+                return non_zero_side;
+            }
+
+            // {anything} & 0 => 0
+            if (
+                zero_side
+                && self.operator === "&"
+                && !non_zero_side.has_side_effects(compressor)
+                && non_zero_side.is_32_bit_integer(compressor)
+            ) {
+                return zero_side;
+            }
+
+            // ~0 is all ones, as well as -1.
+            // We can ellide some operations with it.
+            const is_full_mask = (node) =>
+                node instanceof AST_Number && node.value === -1
+                ||
+                    node instanceof AST_UnaryPrefix
+                    && node.operator === "-"
+                    && node.expression instanceof AST_Number
+                    && node.expression.value === 1;
+
+            const full_mask = is_full_mask(self.right) ? self.right
+                : is_full_mask(self.left) ? self.left
+                : null;
+            const other_side = (full_mask === self.right ? self.left : self.right);
+
+            // {32 bit integer} & -1 => {32 bit integer}
+            if (
+                full_mask
+                && self.operator === "&"
+                && (
+                    other_side.is_32_bit_integer(compressor)
+                    || compressor.in_32_bit_context(true)
+                )
+            ) {
+                return other_side;
+            }
+
+            // {anything} ^ -1 => ~{anything}
+            if (
+                full_mask
+                && self.operator === "^"
+                && (
+                    other_side.is_32_bit_integer(compressor)
+                    || compressor.in_32_bit_context(true)
+                )
+            ) {
+                return other_side.bitwise_negate(compressor);
+            }
+        }
+    }
+    // x && (y && z)  ==>  x && y && z
+    // x || (y || z)  ==>  x || y || z
+    // x + ("y" + z)  ==>  x + "y" + z
+    // "x" + (y + "z")==>  "x" + y + "z"
+    if (self.right instanceof AST_Binary
+        && self.right.operator == self.operator
+        && (lazy_op.has(self.operator)
+            || (self.operator == "+"
+                && (self.right.left.is_string(compressor)
+                    || (self.left.is_string(compressor)
+                        && self.right.right.is_string(compressor)))))
+    ) {
+        self.left = make_node(AST_Binary, self.left, {
+            operator : self.operator,
+            left     : self.left.transform(compressor),
+            right    : self.right.left.transform(compressor)
+        });
+        self.right = self.right.right.transform(compressor);
+        return self.transform(compressor);
+    }
+    var ev = self.evaluate(compressor);
+    if (ev !== self) {
+        ev = make_node_from_constant(ev, self).optimize(compressor);
+        return best_of(compressor, ev, self);
+    }
+    return self;
+});
+
+def_optimize(AST_SymbolExport, function(self) {
+    return self;
+});
+
+def_optimize(AST_SymbolRef, function(self, compressor) {
+    if (
+        !compressor.option("ie8")
+        && is_undeclared_ref(self)
+        && !compressor.find_parent(AST_With)
+    ) {
+        switch (self.name) {
+          case "undefined":
+            return make_node(AST_Undefined, self).optimize(compressor);
+          case "NaN":
+            return make_node(AST_NaN, self).optimize(compressor);
+          case "Infinity":
+            return make_node(AST_Infinity, self).optimize(compressor);
+        }
+    }
+
+    if (compressor.option("reduce_vars") && !compressor.is_lhs()) {
+        return inline_into_symbolref(self, compressor);
+    } else {
+        return self;
+    }
+});
+
+function is_atomic(lhs, self) {
+    return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE;
+}
+
+/** Apply the `unsafe_undefined` option: find a variable called `undefined` and turn `self` into a reference to it. */
+function unsafe_undefined_ref(self, compressor) {
+    if (compressor.option("unsafe_undefined")) {
+        var undef = find_variable(compressor, "undefined");
+        if (undef) {
+            var ref = make_node(AST_SymbolRef, self, {
+                name   : "undefined",
+                scope  : undef.scope,
+                thedef : undef
+            });
+            set_flag(ref, UNDEFINED);
+            return ref;
+        }
+    }
+    return null;
+}
+
+def_optimize(AST_Undefined, function(self, compressor) {
+    var symbolref = unsafe_undefined_ref(self, compressor);
+    if (symbolref) return symbolref;
+    var lhs = compressor.is_lhs();
+    if (lhs && is_atomic(lhs, self)) return self;
+    return make_void_0(self);
+});
+
+def_optimize(AST_Infinity, function(self, compressor) {
+    var lhs = compressor.is_lhs();
+    if (lhs && is_atomic(lhs, self)) return self;
+    if (
+        compressor.option("keep_infinity")
+        && !(lhs && !is_atomic(lhs, self))
+        && !find_variable(compressor, "Infinity")
+    ) {
+        return self;
+    }
+    return make_node(AST_Binary, self, {
+        operator: "/",
+        left: make_node(AST_Number, self, {
+            value: 1
+        }),
+        right: make_node(AST_Number, self, {
+            value: 0
+        })
+    });
+});
+
+def_optimize(AST_NaN, function(self, compressor) {
+    var lhs = compressor.is_lhs();
+    if (lhs && !is_atomic(lhs, self)
+        || find_variable(compressor, "NaN")) {
+        return make_node(AST_Binary, self, {
+            operator: "/",
+            left: make_node(AST_Number, self, {
+                value: 0
+            }),
+            right: make_node(AST_Number, self, {
+                value: 0
+            })
+        });
+    }
+    return self;
+});
+
+const ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &");
+const ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &");
+def_optimize(AST_Assign, function(self, compressor) {
+    if (self.logical) {
+        return self.lift_sequences(compressor);
+    }
+
+    var def;
+    // x = x ---> x
+    if (
+        self.operator === "="
+        && self.left instanceof AST_SymbolRef
+        && self.left.name !== "arguments"
+        && !(def = self.left.definition()).undeclared
+        && self.right.equivalent_to(self.left)
+    ) {
+        return self.right;
+    }
+
+    if (compressor.option("dead_code")
+        && self.left instanceof AST_SymbolRef
+        && (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) {
+        var level = 0, node, parent = self;
+        do {
+            node = parent;
+            parent = compressor.parent(level++);
+            if (parent instanceof AST_Exit) {
+                if (in_try(level, parent)) break;
+                if (is_reachable(def.scope, [ def ])) break;
+                if (self.operator == "=") return self.right;
+                def.fixed = false;
+                return make_node(AST_Binary, self, {
+                    operator: self.operator.slice(0, -1),
+                    left: self.left,
+                    right: self.right
+                }).optimize(compressor);
+            }
+        } while (parent instanceof AST_Binary && parent.right === node
+            || parent instanceof AST_Sequence && parent.tail_node() === node);
+    }
+    self = self.lift_sequences(compressor);
+
+    if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) {
+        // x = expr1 OP expr2
+        if (self.right.left instanceof AST_SymbolRef
+            && self.right.left.name == self.left.name
+            && ASSIGN_OPS.has(self.right.operator)) {
+            // x = x - 2  --->  x -= 2
+            self.operator = self.right.operator + "=";
+            self.right = self.right.right;
+        } else if (self.right.right instanceof AST_SymbolRef
+            && self.right.right.name == self.left.name
+            && ASSIGN_OPS_COMMUTATIVE.has(self.right.operator)
+            && !self.right.left.has_side_effects(compressor)) {
+            // x = 2 & x  --->  x &= 2
+            self.operator = self.right.operator + "=";
+            self.right = self.right.left;
+        }
+    }
+    return self;
+
+    function in_try(level, node) {
+        function may_assignment_throw() {
+            const right = self.right;
+            self.right = make_node(AST_Null, right);
+            const may_throw = node.may_throw(compressor);
+            self.right = right;
+
+            return may_throw;
+        }
+
+        var stop_at = self.left.definition().scope.get_defun_scope();
+        var parent;
+        while ((parent = compressor.parent(level++)) !== stop_at) {
+            if (parent instanceof AST_Try) {
+                if (parent.bfinally) return true;
+                if (parent.bcatch && may_assignment_throw()) return true;
+            }
+        }
+    }
+});
+
+def_optimize(AST_DefaultAssign, function(self, compressor) {
+    if (!compressor.option("evaluate")) {
+        return self;
+    }
+    var evaluateRight = self.right.evaluate(compressor);
+
+    // `[x = undefined] = foo` ---> `[x] = foo`
+    // `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`)
+    // `((arg = undefined) => ...)()` ---> `((arg) => ...)()`
+    let lambda, iife;
+    if (evaluateRight === undefined) {
+        if (
+            (lambda = compressor.parent()) instanceof AST_Lambda
+                ? (
+                    compressor.option("keep_fargs") === false
+                    || (iife = compressor.parent(1)).TYPE === "Call"
+                        && iife.expression === lambda
+                )
+                : true
+        ) {
+            self = self.left;
+        }
+    } else if (evaluateRight !== self.right) {
+        evaluateRight = make_node_from_constant(evaluateRight, self.right);
+        self.right = best_of_expression(evaluateRight, self.right);
+    }
+
+    return self;
+});
+
+function is_nullish_check(check, check_subject, compressor) {
+    if (check_subject.may_throw(compressor)) return false;
+
+    let nullish_side;
+
+    // foo == null
+    if (
+        check instanceof AST_Binary
+        && check.operator === "=="
+        // which side is nullish?
+        && (
+            (nullish_side = is_nullish(check.left, compressor) && check.left)
+            || (nullish_side = is_nullish(check.right, compressor) && check.right)
+        )
+        // is the other side the same as the check_subject
+        && (
+            nullish_side === check.left
+                ? check.right
+                : check.left
+        ).equivalent_to(check_subject)
+    ) {
+        return true;
+    }
+
+    // foo === null || foo === undefined
+    if (check instanceof AST_Binary && check.operator === "||") {
+        let null_cmp;
+        let undefined_cmp;
+
+        const find_comparison = cmp => {
+            if (!(
+                cmp instanceof AST_Binary
+                && (cmp.operator === "===" || cmp.operator === "==")
+            )) {
+                return false;
+            }
+
+            let found = 0;
+            let defined_side;
+
+            if (cmp.left instanceof AST_Null) {
+                found++;
+                null_cmp = cmp;
+                defined_side = cmp.right;
+            }
+            if (cmp.right instanceof AST_Null) {
+                found++;
+                null_cmp = cmp;
+                defined_side = cmp.left;
+            }
+            if (is_undefined(cmp.left, compressor)) {
+                found++;
+                undefined_cmp = cmp;
+                defined_side = cmp.right;
+            }
+            if (is_undefined(cmp.right, compressor)) {
+                found++;
+                undefined_cmp = cmp;
+                defined_side = cmp.left;
+            }
+
+            if (found !== 1) {
+                return false;
+            }
+
+            if (!defined_side.equivalent_to(check_subject)) {
+                return false;
+            }
+
+            return true;
+        };
+
+        if (!find_comparison(check.left)) return false;
+        if (!find_comparison(check.right)) return false;
+
+        if (null_cmp && undefined_cmp && null_cmp !== undefined_cmp) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+def_optimize(AST_Conditional, function(self, compressor) {
+    if (!compressor.option("conditionals")) return self;
+    // This looks like lift_sequences(), should probably be under "sequences"
+    if (self.condition instanceof AST_Sequence) {
+        var expressions = self.condition.expressions.slice();
+        self.condition = expressions.pop();
+        expressions.push(self);
+        return make_sequence(self, expressions);
+    }
+    var cond = self.condition.evaluate(compressor);
+    if (cond !== self.condition) {
+        if (cond) {
+            return maintain_this_binding(compressor.parent(), compressor.self(), self.consequent);
+        } else {
+            return maintain_this_binding(compressor.parent(), compressor.self(), self.alternative);
+        }
+    }
+    var negated = cond.negate(compressor, first_in_statement(compressor));
+    if (best_of(compressor, cond, negated) === negated) {
+        self = make_node(AST_Conditional, self, {
+            condition: negated,
+            consequent: self.alternative,
+            alternative: self.consequent
+        });
+    }
+    var condition = self.condition;
+    var consequent = self.consequent;
+    var alternative = self.alternative;
+    // x?x:y --> x||y
+    if (condition instanceof AST_SymbolRef
+        && consequent instanceof AST_SymbolRef
+        && condition.definition() === consequent.definition()) {
+        return make_node(AST_Binary, self, {
+            operator: "||",
+            left: condition,
+            right: alternative
+        });
+    }
+    // if (foo) exp = something; else exp = something_else;
+    //                   |
+    //                   v
+    // exp = foo ? something : something_else;
+    if (
+        consequent instanceof AST_Assign
+        && alternative instanceof AST_Assign
+        && consequent.operator === alternative.operator
+        && consequent.logical === alternative.logical
+        && consequent.left.equivalent_to(alternative.left)
+        && (!self.condition.has_side_effects(compressor)
+            || consequent.operator == "="
+                && !consequent.left.has_side_effects(compressor))
+    ) {
+        return make_node(AST_Assign, self, {
+            operator: consequent.operator,
+            left: consequent.left,
+            logical: consequent.logical,
+            right: make_node(AST_Conditional, self, {
+                condition: self.condition,
+                consequent: consequent.right,
+                alternative: alternative.right
+            })
+        });
+    }
+    // x ? y(a) : y(b) --> y(x ? a : b)
+    var arg_index;
+    if (consequent instanceof AST_Call
+        && alternative.TYPE === consequent.TYPE
+        && consequent.args.length > 0
+        && consequent.args.length == alternative.args.length
+        && consequent.expression.equivalent_to(alternative.expression)
+        && !self.condition.has_side_effects(compressor)
+        && !consequent.expression.has_side_effects(compressor)
+        && typeof (arg_index = single_arg_diff()) == "number") {
+        var node = consequent.clone();
+        node.args[arg_index] = make_node(AST_Conditional, self, {
+            condition: self.condition,
+            consequent: consequent.args[arg_index],
+            alternative: alternative.args[arg_index]
+        });
+        return node;
+    }
+    // a ? b : c ? b : d --> (a || c) ? b : d
+    if (alternative instanceof AST_Conditional
+        && consequent.equivalent_to(alternative.consequent)) {
+        return make_node(AST_Conditional, self, {
+            condition: make_node(AST_Binary, self, {
+                operator: "||",
+                left: condition,
+                right: alternative.condition
+            }),
+            consequent: consequent,
+            alternative: alternative.alternative
+        }).optimize(compressor);
+    }
+
+    // a == null ? b : a -> a ?? b
+    if (
+        compressor.option("ecma") >= 2020 &&
+        is_nullish_check(condition, alternative, compressor)
+    ) {
+        return make_node(AST_Binary, self, {
+            operator: "??",
+            left: alternative,
+            right: consequent
+        }).optimize(compressor);
+    }
+
+    // a ? b : (c, b) --> (a || c), b
+    if (alternative instanceof AST_Sequence
+        && consequent.equivalent_to(alternative.expressions[alternative.expressions.length - 1])) {
+        return make_sequence(self, [
+            make_node(AST_Binary, self, {
+                operator: "||",
+                left: condition,
+                right: make_sequence(self, alternative.expressions.slice(0, -1))
+            }),
+            consequent
+        ]).optimize(compressor);
+    }
+    // a ? b : (c && b) --> (a || c) && b
+    if (alternative instanceof AST_Binary
+        && alternative.operator == "&&"
+        && consequent.equivalent_to(alternative.right)) {
+        return make_node(AST_Binary, self, {
+            operator: "&&",
+            left: make_node(AST_Binary, self, {
+                operator: "||",
+                left: condition,
+                right: alternative.left
+            }),
+            right: consequent
+        }).optimize(compressor);
+    }
+    // x?y?z:a:a --> x&&y?z:a
+    if (consequent instanceof AST_Conditional
+        && consequent.alternative.equivalent_to(alternative)) {
+        return make_node(AST_Conditional, self, {
+            condition: make_node(AST_Binary, self, {
+                left: self.condition,
+                operator: "&&",
+                right: consequent.condition
+            }),
+            consequent: consequent.consequent,
+            alternative: alternative
+        });
+    }
+    // x ? y : y --> x, y
+    if (consequent.equivalent_to(alternative)) {
+        return make_sequence(self, [
+            self.condition,
+            consequent
+        ]).optimize(compressor);
+    }
+    // x ? y || z : z --> x && y || z
+    if (consequent instanceof AST_Binary
+        && consequent.operator == "||"
+        && consequent.right.equivalent_to(alternative)) {
+        return make_node(AST_Binary, self, {
+            operator: "||",
+            left: make_node(AST_Binary, self, {
+                operator: "&&",
+                left: self.condition,
+                right: consequent.left
+            }),
+            right: alternative
+        }).optimize(compressor);
+    }
+
+    const in_bool = compressor.in_boolean_context();
+    if (is_true(self.consequent)) {
+        if (is_false(self.alternative)) {
+            // c ? true : false ---> !!c
+            return booleanize(self.condition);
+        }
+        // c ? true : x ---> !!c || x
+        return make_node(AST_Binary, self, {
+            operator: "||",
+            left: booleanize(self.condition),
+            right: self.alternative
+        });
+    }
+    if (is_false(self.consequent)) {
+        if (is_true(self.alternative)) {
+            // c ? false : true ---> !c
+            return booleanize(self.condition.negate(compressor));
+        }
+        // c ? false : x ---> !c && x
+        return make_node(AST_Binary, self, {
+            operator: "&&",
+            left: booleanize(self.condition.negate(compressor)),
+            right: self.alternative
+        });
+    }
+    if (is_true(self.alternative)) {
+        // c ? x : true ---> !c || x
+        return make_node(AST_Binary, self, {
+            operator: "||",
+            left: booleanize(self.condition.negate(compressor)),
+            right: self.consequent
+        });
+    }
+    if (is_false(self.alternative)) {
+        // c ? x : false ---> !!c && x
+        return make_node(AST_Binary, self, {
+            operator: "&&",
+            left: booleanize(self.condition),
+            right: self.consequent
+        });
+    }
+
+    return self;
+
+    function booleanize(node) {
+        if (node.is_boolean()) return node;
+        // !!expression
+        return make_node(AST_UnaryPrefix, node, {
+            operator: "!",
+            expression: node.negate(compressor)
+        });
+    }
+
+    // AST_True or !0
+    function is_true(node) {
+        return node instanceof AST_True
+            || in_bool
+                && node instanceof AST_Constant
+                && node.getValue()
+            || (node instanceof AST_UnaryPrefix
+                && node.operator == "!"
+                && node.expression instanceof AST_Constant
+                && !node.expression.getValue());
+    }
+    // AST_False or !1
+    function is_false(node) {
+        return node instanceof AST_False
+            || in_bool
+                && node instanceof AST_Constant
+                && !node.getValue()
+            || (node instanceof AST_UnaryPrefix
+                && node.operator == "!"
+                && node.expression instanceof AST_Constant
+                && node.expression.getValue());
+    }
+
+    function single_arg_diff() {
+        var a = consequent.args;
+        var b = alternative.args;
+        for (var i = 0, len = a.length; i < len; i++) {
+            if (a[i] instanceof AST_Expansion) return;
+            if (!a[i].equivalent_to(b[i])) {
+                if (b[i] instanceof AST_Expansion) return;
+                for (var j = i + 1; j < len; j++) {
+                    if (a[j] instanceof AST_Expansion) return;
+                    if (!a[j].equivalent_to(b[j])) return;
+                }
+                return i;
+            }
+        }
+    }
+});
+
+def_optimize(AST_Boolean, function(self, compressor) {
+    if (compressor.in_boolean_context()) return make_node(AST_Number, self, {
+        value: +self.value
+    });
+    var p = compressor.parent();
+    if (compressor.option("booleans_as_integers")) {
+        if (p instanceof AST_Binary && (p.operator == "===" || p.operator == "!==")) {
+            p.operator = p.operator.replace(/=$/, "");
+        }
+        return make_node(AST_Number, self, {
+            value: +self.value
+        });
+    }
+    if (compressor.option("booleans")) {
+        if (p instanceof AST_Binary && (p.operator == "=="
+                                        || p.operator == "!=")) {
+            return make_node(AST_Number, self, {
+                value: +self.value
+            });
+        }
+        return make_node(AST_UnaryPrefix, self, {
+            operator: "!",
+            expression: make_node(AST_Number, self, {
+                value: 1 - self.value
+            })
+        });
+    }
+    return self;
+});
+
+function safe_to_flatten(value, compressor) {
+    if (value instanceof AST_SymbolRef) {
+        value = value.fixed_value();
+    }
+    if (!value) return false;
+    if (!(value instanceof AST_Lambda || value instanceof AST_Class)) return true;
+    if (!(value instanceof AST_Lambda && value.contains_this())) return true;
+    return compressor.parent() instanceof AST_New;
+}
+
+AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) {
+    if (!compressor.option("properties")) return;
+    if (key === "__proto__") return;
+    if (this instanceof AST_DotHash) return;
+
+    var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015;
+    var expr = this.expression;
+    if (expr instanceof AST_Object) {
+        var props = expr.properties;
+
+        for (var i = props.length; --i >= 0;) {
+            var prop = props[i];
+
+            if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) {
+                const all_props_flattenable = props.every((p) =>
+                    (p instanceof AST_ObjectKeyVal
+                        || arrows && p instanceof AST_ConciseMethod && !p.value.is_generator
+                    )
+                    && !p.computed_key()
+                );
+
+                if (!all_props_flattenable) return;
+                if (!safe_to_flatten(prop.value, compressor)) return;
+
+                return make_node(AST_Sub, this, {
+                    expression: make_node(AST_Array, expr, {
+                        elements: props.map(function(prop) {
+                            var v = prop.value;
+                            if (v instanceof AST_Accessor) {
+                                v = make_node(AST_Function, v, v);
+                            }
+
+                            var k = prop.key;
+                            if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) {
+                                return make_sequence(prop, [ k, v ]);
+                            }
+
+                            return v;
+                        })
+                    }),
+                    property: make_node(AST_Number, this, {
+                        value: i
+                    })
+                });
+            }
+        }
+    }
+});
+
+def_optimize(AST_Sub, function(self, compressor) {
+    var expr = self.expression;
+    var prop = self.property;
+    if (compressor.option("properties")) {
+        var key = prop.evaluate(compressor);
+        if (key !== prop) {
+            if (typeof key == "string") {
+                if (key == "undefined") {
+                    key = undefined;
+                } else {
+                    var value = parseFloat(key);
+                    if (value.toString() == key) {
+                        key = value;
+                    }
+                }
+            }
+            prop = self.property = best_of_expression(
+                prop,
+                make_node_from_constant(key, prop).transform(compressor)
+            );
+            var property = "" + key;
+            if (is_basic_identifier_string(property)
+                && property.length <= prop.size() + 1) {
+                return make_node(AST_Dot, self, {
+                    expression: expr,
+                    optional: self.optional,
+                    property: property,
+                    quote: prop.quote,
+                }).optimize(compressor);
+            }
+        }
+    }
+    var fn;
+    OPT_ARGUMENTS: if (compressor.option("arguments")
+        && expr instanceof AST_SymbolRef
+        && expr.name == "arguments"
+        && expr.definition().orig.length == 1
+        && (fn = expr.scope) instanceof AST_Lambda
+        && fn.uses_arguments
+        && !(fn instanceof AST_Arrow)
+        && prop instanceof AST_Number) {
+        var index = prop.getValue();
+        var params = new Set();
+        var argnames = fn.argnames;
+        for (var n = 0; n < argnames.length; n++) {
+            if (!(argnames[n] instanceof AST_SymbolFunarg)) {
+                break OPT_ARGUMENTS; // destructuring parameter - bail
+            }
+            var param = argnames[n].name;
+            if (params.has(param)) {
+                break OPT_ARGUMENTS; // duplicate parameter - bail
+            }
+            params.add(param);
+        }
+        var argname = fn.argnames[index];
+        if (argname && compressor.has_directive("use strict")) {
+            var def = argname.definition();
+            if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) {
+                argname = null;
+            }
+        } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) {
+            while (index >= fn.argnames.length) {
+                argname = fn.create_symbol(AST_SymbolFunarg, {
+                    source: fn,
+                    scope: fn,
+                    tentative_name: "argument_" + fn.argnames.length,
+                });
+                fn.argnames.push(argname);
+            }
+        }
+        if (argname) {
+            var sym = make_node(AST_SymbolRef, self, argname);
+            sym.reference({});
+            clear_flag(argname, UNUSED);
+            return sym;
+        }
+    }
+    if (compressor.is_lhs()) return self;
+    if (key !== prop) {
+        var sub = self.flatten_object(property, compressor);
+        if (sub) {
+            expr = self.expression = sub.expression;
+            prop = self.property = sub.property;
+        }
+    }
+    if (compressor.option("properties") && compressor.option("side_effects")
+        && prop instanceof AST_Number && expr instanceof AST_Array) {
+        var index = prop.getValue();
+        var elements = expr.elements;
+        var retValue = elements[index];
+        FLATTEN: if (safe_to_flatten(retValue, compressor)) {
+            var flatten = true;
+            var values = [];
+            for (var i = elements.length; --i > index;) {
+                var value = elements[i].drop_side_effect_free(compressor);
+                if (value) {
+                    values.unshift(value);
+                    if (flatten && value.has_side_effects(compressor)) flatten = false;
+                }
+            }
+            if (retValue instanceof AST_Expansion) break FLATTEN;
+            retValue = retValue instanceof AST_Hole ? make_void_0(retValue) : retValue;
+            if (!flatten) values.unshift(retValue);
+            while (--i >= 0) {
+                var value = elements[i];
+                if (value instanceof AST_Expansion) break FLATTEN;
+                value = value.drop_side_effect_free(compressor);
+                if (value) values.unshift(value);
+                else index--;
+            }
+            if (flatten) {
+                values.push(retValue);
+                return make_sequence(self, values).optimize(compressor);
+            } else return make_node(AST_Sub, self, {
+                expression: make_node(AST_Array, expr, {
+                    elements: values
+                }),
+                property: make_node(AST_Number, prop, {
+                    value: index
+                })
+            });
+        }
+    }
+    var ev = self.evaluate(compressor);
+    if (ev !== self) {
+        ev = make_node_from_constant(ev, self).optimize(compressor);
+        return best_of(compressor, ev, self);
+    }
+    return self;
+});
+
+def_optimize(AST_Chain, function (self, compressor) {
+    if (is_nullish(self.expression, compressor)) {
+        let parent = compressor.parent();
+        // It's valid to delete a nullish optional chain, but if we optimized
+        // this to `delete undefined` then it would appear to be a syntax error
+        // when we try to optimize the delete. Thankfully, `delete 0` is fine.
+        if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") {
+            return make_node_from_constant(0, self);
+        }
+        return make_void_0(self).optimize(compressor);
+    }
+    if (
+        self.expression instanceof AST_PropAccess
+        || self.expression instanceof AST_Call
+    ) {
+        return self;
+    } else {
+        // Keep the AST valid, in case the child swapped itself
+        return self.expression;
+    }
+});
+
+def_optimize(AST_Dot, function(self, compressor) {
+    const parent = compressor.parent();
+    if (compressor.is_lhs()) return self;
+    if (compressor.option("unsafe_proto")
+        && self.expression instanceof AST_Dot
+        && self.expression.property == "prototype") {
+        var exp = self.expression.expression;
+        if (is_undeclared_ref(exp)) switch (exp.name) {
+          case "Array":
+            self.expression = make_node(AST_Array, self.expression, {
+                elements: []
+            });
+            break;
+          case "Function":
+            self.expression = make_empty_function(self.expression);
+            break;
+          case "Number":
+            self.expression = make_node(AST_Number, self.expression, {
+                value: 0
+            });
+            break;
+          case "Object":
+            self.expression = make_node(AST_Object, self.expression, {
+                properties: []
+            });
+            break;
+          case "RegExp":
+            self.expression = make_node(AST_RegExp, self.expression, {
+                value: { source: "t", flags: "" }
+            });
+            break;
+          case "String":
+            self.expression = make_node(AST_String, self.expression, {
+                value: ""
+            });
+            break;
+        }
+    }
+    if (!(parent instanceof AST_Call) || !has_annotation(parent, _NOINLINE)) {
+        const sub = self.flatten_object(self.property, compressor);
+        if (sub) return sub.optimize(compressor);
+    }
+
+    if (self.expression instanceof AST_PropAccess
+        && parent instanceof AST_PropAccess) {
+        return self;
+    }
+
+    let ev = self.evaluate(compressor);
+    if (ev !== self) {
+        ev = make_node_from_constant(ev, self).optimize(compressor);
+        return best_of(compressor, ev, self);
+    }
+    return self;
+});
+
+function literals_in_boolean_context(self, compressor) {
+    if (compressor.in_boolean_context()) {
+        return best_of(compressor, self, make_sequence(self, [
+            self,
+            make_node(AST_True, self)
+        ]).optimize(compressor));
+    }
+    return self;
+}
+
+function inline_array_like_spread(elements) {
+    for (var i = 0; i < elements.length; i++) {
+        var el = elements[i];
+        if (el instanceof AST_Expansion) {
+            var expr = el.expression;
+            if (
+                expr instanceof AST_Array
+                && !expr.elements.some(elm => elm instanceof AST_Hole)
+            ) {
+                elements.splice(i, 1, ...expr.elements);
+                // Step back one, as the element at i is now new.
+                i--;
+            }
+            // In array-like spread, spreading a non-iterable value is TypeError.
+            // We therefore can’t optimize anything else, unlike with object spread.
+        }
+    }
+}
+
+def_optimize(AST_Array, function(self, compressor) {
+    var optimized = literals_in_boolean_context(self, compressor);
+    if (optimized !== self) {
+        return optimized;
+    }
+    inline_array_like_spread(self.elements);
+    return self;
+});
+
+function inline_object_prop_spread(props) {
+    for (var i = 0; i < props.length; i++) {
+        var prop = props[i];
+        if (prop instanceof AST_Expansion) {
+            const expr = prop.expression;
+            if (
+                expr instanceof AST_Object
+                && expr.properties.every(prop => prop instanceof AST_ObjectKeyVal)
+            ) {
+                props.splice(i, 1, ...expr.properties);
+                // Step back one, as the property at i is now new.
+                i--;
+            } else if ((
+                    // `expr.is_constant()` returns `false` for `AST_RegExp`, so need both.
+                    expr instanceof AST_Constant
+                    || expr.is_constant()
+                ) && !(expr instanceof AST_String)) {
+                // Unlike array-like spread, in object spread, spreading a
+                // non-iterable value silently does nothing; it is thus safe
+                // to remove. AST_String is the only iterable constant.
+                props.splice(i, 1);
+                i--;
+            }
+        }
+    }
+}
+
+def_optimize(AST_Object, function(self, compressor) {
+    var optimized = literals_in_boolean_context(self, compressor);
+    if (optimized !== self) {
+        return optimized;
+    }
+    inline_object_prop_spread(self.properties);
+    return self;
+});
+
+def_optimize(AST_RegExp, literals_in_boolean_context);
+
+def_optimize(AST_Return, function(self, compressor) {
+    if (self.value && is_undefined(self.value, compressor)) {
+        self.value = null;
+    }
+    return self;
+});
+
+def_optimize(AST_Arrow, opt_AST_Lambda);
+
+def_optimize(AST_Function, function(self, compressor) {
+    self = opt_AST_Lambda(self, compressor);
+    if (compressor.option("unsafe_arrows")
+        && compressor.option("ecma") >= 2015
+        && !self.name
+        && !self.is_generator
+        && !self.uses_arguments
+        && !self.pinned()) {
+        const uses_this = walk(self, node => {
+            if (node instanceof AST_This) return walk_abort;
+        });
+        if (!uses_this) return make_node(AST_Arrow, self, self).optimize(compressor);
+    }
+    return self;
+});
+
+def_optimize(AST_Class, function(self) {
+    for (let i = 0; i < self.properties.length; i++) {
+        const prop = self.properties[i];
+        if (prop instanceof AST_ClassStaticBlock && prop.body.length == 0) {
+            self.properties.splice(i, 1);
+            i--;
+        }
+    }
+
+    return self;
+});
+
+def_optimize(AST_ClassStaticBlock, function(self, compressor) {
+    tighten_body(self.body, compressor);
+    return self;
+});
+
+def_optimize(AST_Yield, function(self, compressor) {
+    if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) {
+        self.expression = null;
+    }
+    return self;
+});
+
+def_optimize(AST_TemplateString, function(self, compressor) {
+    if (
+        !compressor.option("evaluate")
+        || compressor.parent() instanceof AST_PrefixedTemplateString
+    ) {
+        return self;
+    }
+
+    var segments = [];
+    for (var i = 0; i < self.segments.length; i++) {
+        var segment = self.segments[i];
+        if (segment instanceof AST_Node) {
+            var result = segment.evaluate(compressor);
+            // Evaluate to constant value
+            // Constant value shorter than ${segment}
+            if (result !== segment && (result + "").length <= segment.size() + "${}".length) {
+                // There should always be a previous and next segment if segment is a node
+                segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value;
+                continue;
+            }
+            // `before ${`innerBefore ${any} innerAfter`} after` => `before innerBefore ${any} innerAfter after`
+            // TODO:
+            // `before ${'test' + foo} after` => `before innerBefore ${any} innerAfter after`
+            // `before ${foo + 'test} after` => `before innerBefore ${any} innerAfter after`
+            if (segment instanceof AST_TemplateString) {
+                var inners = segment.segments;
+                segments[segments.length - 1].value += inners[0].value;
+                for (var j = 1; j < inners.length; j++) {
+                    segment = inners[j];
+                    segments.push(segment);
+                }
+                continue;
+            }
+        }
+        segments.push(segment);
+    }
+    self.segments = segments;
+
+    // `foo` => "foo"
+    if (segments.length == 1) {
+        return make_node(AST_String, self, segments[0]);
+    }
+
+    if (
+        segments.length === 3
+        && segments[1] instanceof AST_Node
+        && (
+            segments[1].is_string(compressor)
+            || segments[1].is_number_or_bigint(compressor)
+            || is_nullish(segments[1], compressor)
+            || compressor.option("unsafe")
+        )
+    ) {
+        // `foo${bar}` => "foo" + bar
+        if (segments[2].value === "") {
+            return make_node(AST_Binary, self, {
+                operator: "+",
+                left: make_node(AST_String, self, {
+                    value: segments[0].value,
+                }),
+                right: segments[1],
+            });
+        }
+        // `${bar}baz` => bar + "baz"
+        if (segments[0].value === "") {
+            return make_node(AST_Binary, self, {
+                operator: "+",
+                left: segments[1],
+                right: make_node(AST_String, self, {
+                    value: segments[2].value,
+                }),
+            });
+        }
+    }
+    return self;
+});
+
+def_optimize(AST_PrefixedTemplateString, function(self) {
+    return self;
+});
+
+// ["p"]:1 ---> p:1
+// [42]:1 ---> 42:1
+function lift_key(self, compressor) {
+    if (!compressor.option("computed_props")) return self;
+    // save a comparison in the typical case
+    if (!(self.key instanceof AST_Constant)) return self;
+    // allow certain acceptable props as not all AST_Constants are true constants
+    if (self.key instanceof AST_String || self.key instanceof AST_Number) {
+        const key = self.key.value.toString();
+
+        if (key === "__proto__") return self;
+        if (key == "constructor"
+            && compressor.parent() instanceof AST_Class) return self;
+        if (self instanceof AST_ObjectKeyVal) {
+            self.quote = self.key.quote;
+            self.key = key;
+        } else if (self instanceof AST_ClassProperty) {
+            self.quote = self.key.quote;
+            self.key = make_node(AST_SymbolClassProperty, self.key, {
+                name: key,
+            });
+        } else {
+            self.quote = self.key.quote;
+            self.key = make_node(AST_SymbolMethod, self.key, {
+                name: key,
+            });
+        }
+    }
+    return self;
+}
+
+def_optimize(AST_ObjectProperty, lift_key);
+
+def_optimize(AST_ConciseMethod, function(self, compressor) {
+    lift_key(self, compressor);
+    // p(){return x;} ---> p:()=>x
+    if (compressor.option("arrows")
+        && compressor.parent() instanceof AST_Object
+        && !self.value.is_generator
+        && !self.value.uses_arguments
+        && !self.value.pinned()
+        && self.value.body.length == 1
+        && self.value.body[0] instanceof AST_Return
+        && self.value.body[0].value
+        && !self.value.contains_this()) {
+        var arrow = make_node(AST_Arrow, self.value, self.value);
+        arrow.async = self.value.async;
+        arrow.is_generator = self.value.is_generator;
+        return make_node(AST_ObjectKeyVal, self, {
+            key: self.key instanceof AST_SymbolMethod ? self.key.name : self.key,
+            value: arrow,
+            quote: self.quote,
+        });
+    }
+    return self;
+});
+
+def_optimize(AST_ObjectKeyVal, function(self, compressor) {
+    lift_key(self, compressor);
+    // p:function(){} ---> p(){}
+    // p:function*(){} ---> *p(){}
+    // p:async function(){} ---> async p(){}
+    // p:()=>{} ---> p(){}
+    // p:async()=>{} ---> async p(){}
+    var unsafe_methods = compressor.option("unsafe_methods");
+    if (unsafe_methods
+        && compressor.option("ecma") >= 2015
+        && (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) {
+        var key = self.key;
+        var value = self.value;
+        var is_arrow_with_block = value instanceof AST_Arrow
+            && Array.isArray(value.body)
+            && !value.contains_this();
+        if ((is_arrow_with_block || value instanceof AST_Function) && !value.name) {
+            return make_node(AST_ConciseMethod, self, {
+                key: key instanceof AST_Node ? key : make_node(AST_SymbolMethod, self, {
+                    name: key,
+                }),
+                value: make_node(AST_Accessor, value, value),
+                quote: self.quote,
+            });
+        }
+    }
+    return self;
+});
+
+def_optimize(AST_Destructuring, function(self, compressor) {
+    if (compressor.option("pure_getters") == true
+        && compressor.option("unused")
+        && !self.is_array
+        && Array.isArray(self.names)
+        && !is_destructuring_export_decl(compressor)
+        && !(self.names[self.names.length - 1] instanceof AST_Expansion)) {
+        var keep = [];
+        for (var i = 0; i < self.names.length; i++) {
+            var elem = self.names[i];
+            if (!(elem instanceof AST_ObjectKeyVal
+                && typeof elem.key == "string"
+                && elem.value instanceof AST_SymbolDeclaration
+                && !should_retain(compressor, elem.value.definition()))) {
+                keep.push(elem);
+            }
+        }
+        if (keep.length != self.names.length) {
+            self.names = keep;
+        }
+    }
+    return self;
+
+    function is_destructuring_export_decl(compressor) {
+        var ancestors = [/^VarDef$/, /^(Const|Let|Var)$/, /^Export$/];
+        for (var a = 0, p = 0, len = ancestors.length; a < len; p++) {
+            var parent = compressor.parent(p);
+            if (!parent) return false;
+            if (a === 0 && parent.TYPE == "Destructuring") continue;
+            if (!ancestors[a].test(parent.TYPE)) {
+                return false;
+            }
+            a++;
+        }
+        return true;
+    }
+
+    function should_retain(compressor, def) {
+        if (def.references.length) return true;
+        if (!def.global) return false;
+        if (compressor.toplevel.vars) {
+            if (compressor.top_retain) {
+                return compressor.top_retain(def);
+            }
+            return false;
+        }
+        return true;
+    }
+});
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// a small wrapper around source-map and @jridgewell/source-map
+function* SourceMap(options) {
+    options = defaults(options, {
+        file : null,
+        root : null,
+        orig : null,
+        files: {},
+    });
+
+    var orig_map;
+    var generator = new sourceMap.SourceMapGenerator({
+        file       : options.file,
+        sourceRoot : options.root
+    });
+
+    let sourcesContent = {__proto__: null};
+    let files = options.files;
+    for (var name in files) if (HOP(files, name)) {
+        sourcesContent[name] = files[name];
+    }
+    if (options.orig) {
+        // We support both @jridgewell/source-map (which has a sync
+        // SourceMapConsumer) and source-map (which has an async
+        // SourceMapConsumer).
+        orig_map = yield new sourceMap.SourceMapConsumer(options.orig);
+        if (orig_map.sourcesContent) {
+            orig_map.sources.forEach(function(source, i) {
+                var content = orig_map.sourcesContent[i];
+                if (content) {
+                    sourcesContent[source] = content;
+                }
+            });
+        }
+    }
+
+    function add(source, gen_line, gen_col, orig_line, orig_col, name) {
+        let generatedPos = { line: gen_line, column: gen_col };
+
+        if (orig_map) {
+            var info = orig_map.originalPositionFor({
+                line: orig_line,
+                column: orig_col
+            });
+            if (info.source === null) {
+                generator.addMapping({
+                    generated: generatedPos,
+                    original: null,
+                    source: null,
+                    name: null
+                });
+                return;
+            }
+            source = info.source;
+            orig_line = info.line;
+            orig_col = info.column;
+            name = info.name || name;
+        }
+        generator.addMapping({
+            generated : generatedPos,
+            original  : { line: orig_line, column: orig_col },
+            source    : source,
+            name      : name
+        });
+        generator.setSourceContent(source, sourcesContent[source]);
+    }
+
+    function clean(map) {
+        const allNull = map.sourcesContent && map.sourcesContent.every(c => c == null);
+        if (allNull) delete map.sourcesContent;
+        if (map.file === undefined) delete map.file;
+        if (map.sourceRoot === undefined) delete map.sourceRoot;
+        return map;
+    }
+
+    function getDecoded() {
+        if (!generator.toDecodedMap) return null;
+        return clean(generator.toDecodedMap());
+    }
+
+    function getEncoded() {
+        return clean(generator.toJSON());
+    }
+
+    function destroy() {
+        // @jridgewell/source-map's SourceMapConsumer does not need to be
+        // manually freed.
+        if (orig_map && orig_map.destroy) orig_map.destroy();
+    }
+
+    return {
+        add,
+        getDecoded,
+        getEncoded,
+        destroy,
+    };
+}
+
+var domprops = [
+    "$&",
+    "$'",
+    "$*",
+    "$+",
+    "$1",
+    "$2",
+    "$3",
+    "$4",
+    "$5",
+    "$6",
+    "$7",
+    "$8",
+    "$9",
+    "$_",
+    "$`",
+    "$input",
+    "-moz-animation",
+    "-moz-animation-delay",
+    "-moz-animation-direction",
+    "-moz-animation-duration",
+    "-moz-animation-fill-mode",
+    "-moz-animation-iteration-count",
+    "-moz-animation-name",
+    "-moz-animation-play-state",
+    "-moz-animation-timing-function",
+    "-moz-appearance",
+    "-moz-backface-visibility",
+    "-moz-border-end",
+    "-moz-border-end-color",
+    "-moz-border-end-style",
+    "-moz-border-end-width",
+    "-moz-border-image",
+    "-moz-border-start",
+    "-moz-border-start-color",
+    "-moz-border-start-style",
+    "-moz-border-start-width",
+    "-moz-box-align",
+    "-moz-box-direction",
+    "-moz-box-flex",
+    "-moz-box-ordinal-group",
+    "-moz-box-orient",
+    "-moz-box-pack",
+    "-moz-box-sizing",
+    "-moz-float-edge",
+    "-moz-font-feature-settings",
+    "-moz-font-language-override",
+    "-moz-force-broken-image-icon",
+    "-moz-hyphens",
+    "-moz-image-region",
+    "-moz-margin-end",
+    "-moz-margin-start",
+    "-moz-orient",
+    "-moz-osx-font-smoothing",
+    "-moz-outline-radius",
+    "-moz-outline-radius-bottomleft",
+    "-moz-outline-radius-bottomright",
+    "-moz-outline-radius-topleft",
+    "-moz-outline-radius-topright",
+    "-moz-padding-end",
+    "-moz-padding-start",
+    "-moz-perspective",
+    "-moz-perspective-origin",
+    "-moz-tab-size",
+    "-moz-text-size-adjust",
+    "-moz-transform",
+    "-moz-transform-origin",
+    "-moz-transform-style",
+    "-moz-transition",
+    "-moz-transition-delay",
+    "-moz-transition-duration",
+    "-moz-transition-property",
+    "-moz-transition-timing-function",
+    "-moz-user-focus",
+    "-moz-user-input",
+    "-moz-user-modify",
+    "-moz-user-select",
+    "-moz-window-dragging",
+    "-webkit-align-content",
+    "-webkit-align-items",
+    "-webkit-align-self",
+    "-webkit-animation",
+    "-webkit-animation-delay",
+    "-webkit-animation-direction",
+    "-webkit-animation-duration",
+    "-webkit-animation-fill-mode",
+    "-webkit-animation-iteration-count",
+    "-webkit-animation-name",
+    "-webkit-animation-play-state",
+    "-webkit-animation-timing-function",
+    "-webkit-appearance",
+    "-webkit-backface-visibility",
+    "-webkit-background-clip",
+    "-webkit-background-origin",
+    "-webkit-background-size",
+    "-webkit-border-bottom-left-radius",
+    "-webkit-border-bottom-right-radius",
+    "-webkit-border-image",
+    "-webkit-border-radius",
+    "-webkit-border-top-left-radius",
+    "-webkit-border-top-right-radius",
+    "-webkit-box-align",
+    "-webkit-box-direction",
+    "-webkit-box-flex",
+    "-webkit-box-ordinal-group",
+    "-webkit-box-orient",
+    "-webkit-box-pack",
+    "-webkit-box-shadow",
+    "-webkit-box-sizing",
+    "-webkit-clip-path",
+    "-webkit-filter",
+    "-webkit-flex",
+    "-webkit-flex-basis",
+    "-webkit-flex-direction",
+    "-webkit-flex-flow",
+    "-webkit-flex-grow",
+    "-webkit-flex-shrink",
+    "-webkit-flex-wrap",
+    "-webkit-font-feature-settings",
+    "-webkit-justify-content",
+    "-webkit-line-clamp",
+    "-webkit-mask",
+    "-webkit-mask-clip",
+    "-webkit-mask-composite",
+    "-webkit-mask-image",
+    "-webkit-mask-origin",
+    "-webkit-mask-position",
+    "-webkit-mask-position-x",
+    "-webkit-mask-position-y",
+    "-webkit-mask-repeat",
+    "-webkit-mask-size",
+    "-webkit-order",
+    "-webkit-perspective",
+    "-webkit-perspective-origin",
+    "-webkit-text-fill-color",
+    "-webkit-text-security",
+    "-webkit-text-size-adjust",
+    "-webkit-text-stroke",
+    "-webkit-text-stroke-color",
+    "-webkit-text-stroke-width",
+    "-webkit-transform",
+    "-webkit-transform-origin",
+    "-webkit-transform-style",
+    "-webkit-transition",
+    "-webkit-transition-delay",
+    "-webkit-transition-duration",
+    "-webkit-transition-property",
+    "-webkit-transition-timing-function",
+    "-webkit-user-select",
+    "@@iterator",
+    "ABORT_ERR",
+    "ACTIVE",
+    "ACTIVE_ATTRIBUTES",
+    "ACTIVE_TEXTURE",
+    "ACTIVE_UNIFORMS",
+    "ACTIVE_UNIFORM_BLOCKS",
+    "ADDITION",
+    "ALIASED_LINE_WIDTH_RANGE",
+    "ALIASED_POINT_SIZE_RANGE",
+    "ALL",
+    "ALLOW_KEYBOARD_INPUT",
+    "ALLPASS",
+    "ALPHA",
+    "ALPHA_BITS",
+    "ALREADY_SIGNALED",
+    "ALT_MASK",
+    "ALWAYS",
+    "ANY_SAMPLES_PASSED",
+    "ANY_SAMPLES_PASSED_CONSERVATIVE",
+    "ANY_TYPE",
+    "ANY_UNORDERED_NODE_TYPE",
+    "ARRAY_BUFFER",
+    "ARRAY_BUFFER_BINDING",
+    "ATTACHED_SHADERS",
+    "ATTRIBUTE_NODE",
+    "AT_TARGET",
+    "AbortController",
+    "AbortSignal",
+    "AbsoluteOrientationSensor",
+    "AbstractRange",
+    "Accelerometer",
+    "AddSearchProvider",
+    "AggregateError",
+    "AnalyserNode",
+    "Animation",
+    "AnimationEffect",
+    "AnimationEvent",
+    "AnimationPlaybackEvent",
+    "AnimationTimeline",
+    "AnonXMLHttpRequest",
+    "Any",
+    "AnyPermissions",
+    "ApplicationCache",
+    "ApplicationCacheErrorEvent",
+    "Array",
+    "ArrayBuffer",
+    "ArrayType",
+    "AsyncDisposableStack",
+    "Atomics",
+    "Attr",
+    "Audio",
+    "AudioBuffer",
+    "AudioBufferSourceNode",
+    "AudioContext",
+    "AudioData",
+    "AudioDecoder",
+    "AudioDestinationNode",
+    "AudioEncoder",
+    "AudioListener",
+    "AudioNode",
+    "AudioParam",
+    "AudioParamMap",
+    "AudioProcessingEvent",
+    "AudioScheduledSourceNode",
+    "AudioSinkInfo",
+    "AudioStreamTrack",
+    "AudioWorklet",
+    "AudioWorkletNode",
+    "AuthenticatorAssertionResponse",
+    "AuthenticatorAttestationResponse",
+    "AuthenticatorResponse",
+    "AutocompleteErrorEvent",
+    "BACK",
+    "BAD_BOUNDARYPOINTS_ERR",
+    "BAD_REQUEST",
+    "BANDPASS",
+    "BLEND",
+    "BLEND_COLOR",
+    "BLEND_DST_ALPHA",
+    "BLEND_DST_RGB",
+    "BLEND_EQUATION",
+    "BLEND_EQUATION_ALPHA",
+    "BLEND_EQUATION_RGB",
+    "BLEND_SRC_ALPHA",
+    "BLEND_SRC_RGB",
+    "BLUE",
+    "BLUE_BITS",
+    "BLUR",
+    "BOOL",
+    "BOOLEAN_TYPE",
+    "BOOL_VEC2",
+    "BOOL_VEC3",
+    "BOOL_VEC4",
+    "BOTH",
+    "BROWSER_DEFAULT_WEBGL",
+    "BUBBLING_PHASE",
+    "BUFFER_SIZE",
+    "BUFFER_USAGE",
+    "BYTE",
+    "BYTES_PER_ELEMENT",
+    "BackgroundFetchManager",
+    "BackgroundFetchRecord",
+    "BackgroundFetchRegistration",
+    "BarProp",
+    "BarcodeDetector",
+    "BaseAudioContext",
+    "BaseHref",
+    "BatteryManager",
+    "BeforeInstallPromptEvent",
+    "BeforeLoadEvent",
+    "BeforeUnloadEvent",
+    "BigInt",
+    "BigInt64Array",
+    "BigUint64Array",
+    "BiquadFilterNode",
+    "Blob",
+    "BlobEvent",
+    "Bluetooth",
+    "BluetoothCharacteristicProperties",
+    "BluetoothDevice",
+    "BluetoothRemoteGATTCharacteristic",
+    "BluetoothRemoteGATTDescriptor",
+    "BluetoothRemoteGATTServer",
+    "BluetoothRemoteGATTService",
+    "BluetoothUUID",
+    "Boolean",
+    "BroadcastChannel",
+    "BrowserCaptureMediaStreamTrack",
+    "BrowserInfo",
+    "ByteLengthQueuingStrategy",
+    "CAPTURING_PHASE",
+    "CCW",
+    "CDATASection",
+    "CDATA_SECTION_NODE",
+    "CHANGE",
+    "CHARSET_RULE",
+    "CHECKING",
+    "CLAMP_TO_EDGE",
+    "CLICK",
+    "CLOSED",
+    "CLOSING",
+    "COLOR",
+    "COLOR_ATTACHMENT0",
+    "COLOR_ATTACHMENT1",
+    "COLOR_ATTACHMENT10",
+    "COLOR_ATTACHMENT11",
+    "COLOR_ATTACHMENT12",
+    "COLOR_ATTACHMENT13",
+    "COLOR_ATTACHMENT14",
+    "COLOR_ATTACHMENT15",
+    "COLOR_ATTACHMENT2",
+    "COLOR_ATTACHMENT3",
+    "COLOR_ATTACHMENT4",
+    "COLOR_ATTACHMENT5",
+    "COLOR_ATTACHMENT6",
+    "COLOR_ATTACHMENT7",
+    "COLOR_ATTACHMENT8",
+    "COLOR_ATTACHMENT9",
+    "COLOR_BUFFER_BIT",
+    "COLOR_CLEAR_VALUE",
+    "COLOR_WRITEMASK",
+    "COMMENT_NODE",
+    "COMPARE_REF_TO_TEXTURE",
+    "COMPILE_STATUS",
+    "COMPLETION_STATUS_KHR",
+    "COMPRESSED_RGBA_S3TC_DXT1_EXT",
+    "COMPRESSED_RGBA_S3TC_DXT3_EXT",
+    "COMPRESSED_RGBA_S3TC_DXT5_EXT",
+    "COMPRESSED_RGB_S3TC_DXT1_EXT",
+    "COMPRESSED_TEXTURE_FORMATS",
+    "COMPUTE",
+    "CONDITION_SATISFIED",
+    "CONFIGURATION_UNSUPPORTED",
+    "CONNECTING",
+    "CONSTANT_ALPHA",
+    "CONSTANT_COLOR",
+    "CONSTRAINT_ERR",
+    "CONTEXT_LOST_WEBGL",
+    "CONTROL_MASK",
+    "COPY_DST",
+    "COPY_READ_BUFFER",
+    "COPY_READ_BUFFER_BINDING",
+    "COPY_SRC",
+    "COPY_WRITE_BUFFER",
+    "COPY_WRITE_BUFFER_BINDING",
+    "COUNTER_STYLE_RULE",
+    "CSPViolationReportBody",
+    "CSS",
+    "CSS2Properties",
+    "CSSAnimation",
+    "CSSCharsetRule",
+    "CSSConditionRule",
+    "CSSContainerRule",
+    "CSSCounterStyleRule",
+    "CSSFontFaceRule",
+    "CSSFontFeatureValuesRule",
+    "CSSFontPaletteValuesRule",
+    "CSSFunctionDeclarations",
+    "CSSFunctionDescriptors",
+    "CSSFunctionRule",
+    "CSSGroupingRule",
+    "CSSImageValue",
+    "CSSImportRule",
+    "CSSKeyframeRule",
+    "CSSKeyframesRule",
+    "CSSKeywordValue",
+    "CSSLayerBlockRule",
+    "CSSLayerStatementRule",
+    "CSSMarginRule",
+    "CSSMathClamp",
+    "CSSMathInvert",
+    "CSSMathMax",
+    "CSSMathMin",
+    "CSSMathNegate",
+    "CSSMathProduct",
+    "CSSMathSum",
+    "CSSMathValue",
+    "CSSMatrixComponent",
+    "CSSMediaRule",
+    "CSSMozDocumentRule",
+    "CSSNameSpaceRule",
+    "CSSNamespaceRule",
+    "CSSNestedDeclarations",
+    "CSSNumericArray",
+    "CSSNumericValue",
+    "CSSPageDescriptors",
+    "CSSPageRule",
+    "CSSPerspective",
+    "CSSPositionTryDescriptors",
+    "CSSPositionTryRule",
+    "CSSPositionValue",
+    "CSSPrimitiveValue",
+    "CSSPropertyRule",
+    "CSSRotate",
+    "CSSRule",
+    "CSSRuleList",
+    "CSSScale",
+    "CSSScopeRule",
+    "CSSSkew",
+    "CSSSkewX",
+    "CSSSkewY",
+    "CSSStartingStyleRule",
+    "CSSStyleDeclaration",
+    "CSSStyleProperties",
+    "CSSStyleRule",
+    "CSSStyleSheet",
+    "CSSStyleValue",
+    "CSSSupportsRule",
+    "CSSTransformComponent",
+    "CSSTransformValue",
+    "CSSTransition",
+    "CSSTranslate",
+    "CSSUnitValue",
+    "CSSUnknownRule",
+    "CSSUnparsedValue",
+    "CSSValue",
+    "CSSValueList",
+    "CSSVariableReferenceValue",
+    "CSSVariablesDeclaration",
+    "CSSVariablesRule",
+    "CSSViewTransitionRule",
+    "CSSViewportRule",
+    "CSS_ATTR",
+    "CSS_CM",
+    "CSS_COUNTER",
+    "CSS_CUSTOM",
+    "CSS_DEG",
+    "CSS_DIMENSION",
+    "CSS_EMS",
+    "CSS_EXS",
+    "CSS_FILTER_BLUR",
+    "CSS_FILTER_BRIGHTNESS",
+    "CSS_FILTER_CONTRAST",
+    "CSS_FILTER_CUSTOM",
+    "CSS_FILTER_DROP_SHADOW",
+    "CSS_FILTER_GRAYSCALE",
+    "CSS_FILTER_HUE_ROTATE",
+    "CSS_FILTER_INVERT",
+    "CSS_FILTER_OPACITY",
+    "CSS_FILTER_REFERENCE",
+    "CSS_FILTER_SATURATE",
+    "CSS_FILTER_SEPIA",
+    "CSS_GRAD",
+    "CSS_HZ",
+    "CSS_IDENT",
+    "CSS_IN",
+    "CSS_INHERIT",
+    "CSS_KHZ",
+    "CSS_MATRIX",
+    "CSS_MATRIX3D",
+    "CSS_MM",
+    "CSS_MS",
+    "CSS_NUMBER",
+    "CSS_PC",
+    "CSS_PERCENTAGE",
+    "CSS_PERSPECTIVE",
+    "CSS_PRIMITIVE_VALUE",
+    "CSS_PT",
+    "CSS_PX",
+    "CSS_RAD",
+    "CSS_RECT",
+    "CSS_RGBCOLOR",
+    "CSS_ROTATE",
+    "CSS_ROTATE3D",
+    "CSS_ROTATEX",
+    "CSS_ROTATEY",
+    "CSS_ROTATEZ",
+    "CSS_S",
+    "CSS_SCALE",
+    "CSS_SCALE3D",
+    "CSS_SCALEX",
+    "CSS_SCALEY",
+    "CSS_SCALEZ",
+    "CSS_SKEW",
+    "CSS_SKEWX",
+    "CSS_SKEWY",
+    "CSS_STRING",
+    "CSS_TRANSLATE",
+    "CSS_TRANSLATE3D",
+    "CSS_TRANSLATEX",
+    "CSS_TRANSLATEY",
+    "CSS_TRANSLATEZ",
+    "CSS_UNKNOWN",
+    "CSS_URI",
+    "CSS_VALUE_LIST",
+    "CSS_VH",
+    "CSS_VMAX",
+    "CSS_VMIN",
+    "CSS_VW",
+    "CULL_FACE",
+    "CULL_FACE_MODE",
+    "CURRENT_PROGRAM",
+    "CURRENT_QUERY",
+    "CURRENT_VERTEX_ATTRIB",
+    "CUSTOM",
+    "CW",
+    "Cache",
+    "CacheStorage",
+    "CanvasCaptureMediaStream",
+    "CanvasCaptureMediaStreamTrack",
+    "CanvasGradient",
+    "CanvasPattern",
+    "CanvasRenderingContext2D",
+    "CaptureController",
+    "CaretPosition",
+    "ChannelMergerNode",
+    "ChannelSplitterNode",
+    "ChapterInformation",
+    "CharacterBoundsUpdateEvent",
+    "CharacterData",
+    "ClientRect",
+    "ClientRectList",
+    "Clipboard",
+    "ClipboardEvent",
+    "ClipboardItem",
+    "CloseEvent",
+    "CloseWatcher",
+    "Collator",
+    "ColorArray",
+    "ColorValue",
+    "CommandEvent",
+    "Comment",
+    "CompileError",
+    "CompositionEvent",
+    "CompressionStream",
+    "Console",
+    "ConstantSourceNode",
+    "ContentVisibilityAutoStateChangeEvent",
+    "ContextFilter",
+    "ContextType",
+    "Controllers",
+    "ConvolverNode",
+    "CookieChangeEvent",
+    "CookieStore",
+    "CookieStoreManager",
+    "CountQueuingStrategy",
+    "Counter",
+    "CreateMonitor",
+    "CreateType",
+    "Credential",
+    "CredentialsContainer",
+    "CropTarget",
+    "Crypto",
+    "CryptoKey",
+    "CustomElementRegistry",
+    "CustomEvent",
+    "CustomStateSet",
+    "DATABASE_ERR",
+    "DATA_CLONE_ERR",
+    "DATA_ERR",
+    "DBLCLICK",
+    "DECR",
+    "DECR_WRAP",
+    "DELETE_STATUS",
+    "DEPTH",
+    "DEPTH24_STENCIL8",
+    "DEPTH32F_STENCIL8",
+    "DEPTH_ATTACHMENT",
+    "DEPTH_BITS",
+    "DEPTH_BUFFER_BIT",
+    "DEPTH_CLEAR_VALUE",
+    "DEPTH_COMPONENT",
+    "DEPTH_COMPONENT16",
+    "DEPTH_COMPONENT24",
+    "DEPTH_COMPONENT32F",
+    "DEPTH_FUNC",
+    "DEPTH_RANGE",
+    "DEPTH_STENCIL",
+    "DEPTH_STENCIL_ATTACHMENT",
+    "DEPTH_TEST",
+    "DEPTH_WRITEMASK",
+    "DEVICE_INELIGIBLE",
+    "DIRECTION_DOWN",
+    "DIRECTION_LEFT",
+    "DIRECTION_RIGHT",
+    "DIRECTION_UP",
+    "DISABLED",
+    "DISPATCH_REQUEST_ERR",
+    "DITHER",
+    "DOCUMENT_FRAGMENT_NODE",
+    "DOCUMENT_NODE",
+    "DOCUMENT_POSITION_CONTAINED_BY",
+    "DOCUMENT_POSITION_CONTAINS",
+    "DOCUMENT_POSITION_DISCONNECTED",
+    "DOCUMENT_POSITION_FOLLOWING",
+    "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC",
+    "DOCUMENT_POSITION_PRECEDING",
+    "DOCUMENT_TYPE_NODE",
+    "DOMCursor",
+    "DOMError",
+    "DOMException",
+    "DOMImplementation",
+    "DOMImplementationLS",
+    "DOMMatrix",
+    "DOMMatrixReadOnly",
+    "DOMParser",
+    "DOMPoint",
+    "DOMPointReadOnly",
+    "DOMQuad",
+    "DOMRect",
+    "DOMRectList",
+    "DOMRectReadOnly",
+    "DOMRequest",
+    "DOMSTRING_SIZE_ERR",
+    "DOMSettableTokenList",
+    "DOMStringList",
+    "DOMStringMap",
+    "DOMTokenList",
+    "DOMTransactionEvent",
+    "DOM_DELTA_LINE",
+    "DOM_DELTA_PAGE",
+    "DOM_DELTA_PIXEL",
+    "DOM_INPUT_METHOD_DROP",
+    "DOM_INPUT_METHOD_HANDWRITING",
+    "DOM_INPUT_METHOD_IME",
+    "DOM_INPUT_METHOD_KEYBOARD",
+    "DOM_INPUT_METHOD_MULTIMODAL",
+    "DOM_INPUT_METHOD_OPTION",
+    "DOM_INPUT_METHOD_PASTE",
+    "DOM_INPUT_METHOD_SCRIPT",
+    "DOM_INPUT_METHOD_UNKNOWN",
+    "DOM_INPUT_METHOD_VOICE",
+    "DOM_KEY_LOCATION_JOYSTICK",
+    "DOM_KEY_LOCATION_LEFT",
+    "DOM_KEY_LOCATION_MOBILE",
+    "DOM_KEY_LOCATION_NUMPAD",
+    "DOM_KEY_LOCATION_RIGHT",
+    "DOM_KEY_LOCATION_STANDARD",
+    "DOM_VK_0",
+    "DOM_VK_1",
+    "DOM_VK_2",
+    "DOM_VK_3",
+    "DOM_VK_4",
+    "DOM_VK_5",
+    "DOM_VK_6",
+    "DOM_VK_7",
+    "DOM_VK_8",
+    "DOM_VK_9",
+    "DOM_VK_A",
+    "DOM_VK_ACCEPT",
+    "DOM_VK_ADD",
+    "DOM_VK_ALT",
+    "DOM_VK_ALTGR",
+    "DOM_VK_AMPERSAND",
+    "DOM_VK_ASTERISK",
+    "DOM_VK_AT",
+    "DOM_VK_ATTN",
+    "DOM_VK_B",
+    "DOM_VK_BACKSPACE",
+    "DOM_VK_BACK_QUOTE",
+    "DOM_VK_BACK_SLASH",
+    "DOM_VK_BACK_SPACE",
+    "DOM_VK_C",
+    "DOM_VK_CANCEL",
+    "DOM_VK_CAPS_LOCK",
+    "DOM_VK_CIRCUMFLEX",
+    "DOM_VK_CLEAR",
+    "DOM_VK_CLOSE_BRACKET",
+    "DOM_VK_CLOSE_CURLY_BRACKET",
+    "DOM_VK_CLOSE_PAREN",
+    "DOM_VK_COLON",
+    "DOM_VK_COMMA",
+    "DOM_VK_CONTEXT_MENU",
+    "DOM_VK_CONTROL",
+    "DOM_VK_CONVERT",
+    "DOM_VK_CRSEL",
+    "DOM_VK_CTRL",
+    "DOM_VK_D",
+    "DOM_VK_DECIMAL",
+    "DOM_VK_DELETE",
+    "DOM_VK_DIVIDE",
+    "DOM_VK_DOLLAR",
+    "DOM_VK_DOUBLE_QUOTE",
+    "DOM_VK_DOWN",
+    "DOM_VK_E",
+    "DOM_VK_EISU",
+    "DOM_VK_END",
+    "DOM_VK_ENTER",
+    "DOM_VK_EQUALS",
+    "DOM_VK_EREOF",
+    "DOM_VK_ESCAPE",
+    "DOM_VK_EXCLAMATION",
+    "DOM_VK_EXECUTE",
+    "DOM_VK_EXSEL",
+    "DOM_VK_F",
+    "DOM_VK_F1",
+    "DOM_VK_F10",
+    "DOM_VK_F11",
+    "DOM_VK_F12",
+    "DOM_VK_F13",
+    "DOM_VK_F14",
+    "DOM_VK_F15",
+    "DOM_VK_F16",
+    "DOM_VK_F17",
+    "DOM_VK_F18",
+    "DOM_VK_F19",
+    "DOM_VK_F2",
+    "DOM_VK_F20",
+    "DOM_VK_F21",
+    "DOM_VK_F22",
+    "DOM_VK_F23",
+    "DOM_VK_F24",
+    "DOM_VK_F25",
+    "DOM_VK_F26",
+    "DOM_VK_F27",
+    "DOM_VK_F28",
+    "DOM_VK_F29",
+    "DOM_VK_F3",
+    "DOM_VK_F30",
+    "DOM_VK_F31",
+    "DOM_VK_F32",
+    "DOM_VK_F33",
+    "DOM_VK_F34",
+    "DOM_VK_F35",
+    "DOM_VK_F36",
+    "DOM_VK_F4",
+    "DOM_VK_F5",
+    "DOM_VK_F6",
+    "DOM_VK_F7",
+    "DOM_VK_F8",
+    "DOM_VK_F9",
+    "DOM_VK_FINAL",
+    "DOM_VK_FRONT",
+    "DOM_VK_G",
+    "DOM_VK_GREATER_THAN",
+    "DOM_VK_H",
+    "DOM_VK_HANGUL",
+    "DOM_VK_HANJA",
+    "DOM_VK_HASH",
+    "DOM_VK_HELP",
+    "DOM_VK_HK_TOGGLE",
+    "DOM_VK_HOME",
+    "DOM_VK_HYPHEN_MINUS",
+    "DOM_VK_I",
+    "DOM_VK_INSERT",
+    "DOM_VK_J",
+    "DOM_VK_JUNJA",
+    "DOM_VK_K",
+    "DOM_VK_KANA",
+    "DOM_VK_KANJI",
+    "DOM_VK_L",
+    "DOM_VK_LEFT",
+    "DOM_VK_LEFT_TAB",
+    "DOM_VK_LESS_THAN",
+    "DOM_VK_M",
+    "DOM_VK_META",
+    "DOM_VK_MODECHANGE",
+    "DOM_VK_MULTIPLY",
+    "DOM_VK_N",
+    "DOM_VK_NONCONVERT",
+    "DOM_VK_NUMPAD0",
+    "DOM_VK_NUMPAD1",
+    "DOM_VK_NUMPAD2",
+    "DOM_VK_NUMPAD3",
+    "DOM_VK_NUMPAD4",
+    "DOM_VK_NUMPAD5",
+    "DOM_VK_NUMPAD6",
+    "DOM_VK_NUMPAD7",
+    "DOM_VK_NUMPAD8",
+    "DOM_VK_NUMPAD9",
+    "DOM_VK_NUM_LOCK",
+    "DOM_VK_O",
+    "DOM_VK_OEM_1",
+    "DOM_VK_OEM_102",
+    "DOM_VK_OEM_2",
+    "DOM_VK_OEM_3",
+    "DOM_VK_OEM_4",
+    "DOM_VK_OEM_5",
+    "DOM_VK_OEM_6",
+    "DOM_VK_OEM_7",
+    "DOM_VK_OEM_8",
+    "DOM_VK_OEM_COMMA",
+    "DOM_VK_OEM_MINUS",
+    "DOM_VK_OEM_PERIOD",
+    "DOM_VK_OEM_PLUS",
+    "DOM_VK_OPEN_BRACKET",
+    "DOM_VK_OPEN_CURLY_BRACKET",
+    "DOM_VK_OPEN_PAREN",
+    "DOM_VK_P",
+    "DOM_VK_PA1",
+    "DOM_VK_PAGEDOWN",
+    "DOM_VK_PAGEUP",
+    "DOM_VK_PAGE_DOWN",
+    "DOM_VK_PAGE_UP",
+    "DOM_VK_PAUSE",
+    "DOM_VK_PERCENT",
+    "DOM_VK_PERIOD",
+    "DOM_VK_PIPE",
+    "DOM_VK_PLAY",
+    "DOM_VK_PLUS",
+    "DOM_VK_PRINT",
+    "DOM_VK_PRINTSCREEN",
+    "DOM_VK_PROCESSKEY",
+    "DOM_VK_PROPERITES",
+    "DOM_VK_Q",
+    "DOM_VK_QUESTION_MARK",
+    "DOM_VK_QUOTE",
+    "DOM_VK_R",
+    "DOM_VK_REDO",
+    "DOM_VK_RETURN",
+    "DOM_VK_RIGHT",
+    "DOM_VK_S",
+    "DOM_VK_SCROLL_LOCK",
+    "DOM_VK_SELECT",
+    "DOM_VK_SEMICOLON",
+    "DOM_VK_SEPARATOR",
+    "DOM_VK_SHIFT",
+    "DOM_VK_SLASH",
+    "DOM_VK_SLEEP",
+    "DOM_VK_SPACE",
+    "DOM_VK_SUBTRACT",
+    "DOM_VK_T",
+    "DOM_VK_TAB",
+    "DOM_VK_TILDE",
+    "DOM_VK_U",
+    "DOM_VK_UNDERSCORE",
+    "DOM_VK_UNDO",
+    "DOM_VK_UNICODE",
+    "DOM_VK_UP",
+    "DOM_VK_V",
+    "DOM_VK_VOLUME_DOWN",
+    "DOM_VK_VOLUME_MUTE",
+    "DOM_VK_VOLUME_UP",
+    "DOM_VK_W",
+    "DOM_VK_WIN",
+    "DOM_VK_WINDOW",
+    "DOM_VK_WIN_ICO_00",
+    "DOM_VK_WIN_ICO_CLEAR",
+    "DOM_VK_WIN_ICO_HELP",
+    "DOM_VK_WIN_OEM_ATTN",
+    "DOM_VK_WIN_OEM_AUTO",
+    "DOM_VK_WIN_OEM_BACKTAB",
+    "DOM_VK_WIN_OEM_CLEAR",
+    "DOM_VK_WIN_OEM_COPY",
+    "DOM_VK_WIN_OEM_CUSEL",
+    "DOM_VK_WIN_OEM_ENLW",
+    "DOM_VK_WIN_OEM_FINISH",
+    "DOM_VK_WIN_OEM_FJ_JISHO",
+    "DOM_VK_WIN_OEM_FJ_LOYA",
+    "DOM_VK_WIN_OEM_FJ_MASSHOU",
+    "DOM_VK_WIN_OEM_FJ_ROYA",
+    "DOM_VK_WIN_OEM_FJ_TOUROKU",
+    "DOM_VK_WIN_OEM_JUMP",
+    "DOM_VK_WIN_OEM_PA1",
+    "DOM_VK_WIN_OEM_PA2",
+    "DOM_VK_WIN_OEM_PA3",
+    "DOM_VK_WIN_OEM_RESET",
+    "DOM_VK_WIN_OEM_WSCTRL",
+    "DOM_VK_X",
+    "DOM_VK_XF86XK_ADD_FAVORITE",
+    "DOM_VK_XF86XK_APPLICATION_LEFT",
+    "DOM_VK_XF86XK_APPLICATION_RIGHT",
+    "DOM_VK_XF86XK_AUDIO_CYCLE_TRACK",
+    "DOM_VK_XF86XK_AUDIO_FORWARD",
+    "DOM_VK_XF86XK_AUDIO_LOWER_VOLUME",
+    "DOM_VK_XF86XK_AUDIO_MEDIA",
+    "DOM_VK_XF86XK_AUDIO_MUTE",
+    "DOM_VK_XF86XK_AUDIO_NEXT",
+    "DOM_VK_XF86XK_AUDIO_PAUSE",
+    "DOM_VK_XF86XK_AUDIO_PLAY",
+    "DOM_VK_XF86XK_AUDIO_PREV",
+    "DOM_VK_XF86XK_AUDIO_RAISE_VOLUME",
+    "DOM_VK_XF86XK_AUDIO_RANDOM_PLAY",
+    "DOM_VK_XF86XK_AUDIO_RECORD",
+    "DOM_VK_XF86XK_AUDIO_REPEAT",
+    "DOM_VK_XF86XK_AUDIO_REWIND",
+    "DOM_VK_XF86XK_AUDIO_STOP",
+    "DOM_VK_XF86XK_AWAY",
+    "DOM_VK_XF86XK_BACK",
+    "DOM_VK_XF86XK_BACK_FORWARD",
+    "DOM_VK_XF86XK_BATTERY",
+    "DOM_VK_XF86XK_BLUE",
+    "DOM_VK_XF86XK_BLUETOOTH",
+    "DOM_VK_XF86XK_BOOK",
+    "DOM_VK_XF86XK_BRIGHTNESS_ADJUST",
+    "DOM_VK_XF86XK_CALCULATOR",
+    "DOM_VK_XF86XK_CALENDAR",
+    "DOM_VK_XF86XK_CD",
+    "DOM_VK_XF86XK_CLOSE",
+    "DOM_VK_XF86XK_COMMUNITY",
+    "DOM_VK_XF86XK_CONTRAST_ADJUST",
+    "DOM_VK_XF86XK_COPY",
+    "DOM_VK_XF86XK_CUT",
+    "DOM_VK_XF86XK_CYCLE_ANGLE",
+    "DOM_VK_XF86XK_DISPLAY",
+    "DOM_VK_XF86XK_DOCUMENTS",
+    "DOM_VK_XF86XK_DOS",
+    "DOM_VK_XF86XK_EJECT",
+    "DOM_VK_XF86XK_EXCEL",
+    "DOM_VK_XF86XK_EXPLORER",
+    "DOM_VK_XF86XK_FAVORITES",
+    "DOM_VK_XF86XK_FINANCE",
+    "DOM_VK_XF86XK_FORWARD",
+    "DOM_VK_XF86XK_FRAME_BACK",
+    "DOM_VK_XF86XK_FRAME_FORWARD",
+    "DOM_VK_XF86XK_GAME",
+    "DOM_VK_XF86XK_GO",
+    "DOM_VK_XF86XK_GREEN",
+    "DOM_VK_XF86XK_HIBERNATE",
+    "DOM_VK_XF86XK_HISTORY",
+    "DOM_VK_XF86XK_HOME_PAGE",
+    "DOM_VK_XF86XK_HOT_LINKS",
+    "DOM_VK_XF86XK_I_TOUCH",
+    "DOM_VK_XF86XK_KBD_BRIGHTNESS_DOWN",
+    "DOM_VK_XF86XK_KBD_BRIGHTNESS_UP",
+    "DOM_VK_XF86XK_KBD_LIGHT_ON_OFF",
+    "DOM_VK_XF86XK_LAUNCH0",
+    "DOM_VK_XF86XK_LAUNCH1",
+    "DOM_VK_XF86XK_LAUNCH2",
+    "DOM_VK_XF86XK_LAUNCH3",
+    "DOM_VK_XF86XK_LAUNCH4",
+    "DOM_VK_XF86XK_LAUNCH5",
+    "DOM_VK_XF86XK_LAUNCH6",
+    "DOM_VK_XF86XK_LAUNCH7",
+    "DOM_VK_XF86XK_LAUNCH8",
+    "DOM_VK_XF86XK_LAUNCH9",
+    "DOM_VK_XF86XK_LAUNCH_A",
+    "DOM_VK_XF86XK_LAUNCH_B",
+    "DOM_VK_XF86XK_LAUNCH_C",
+    "DOM_VK_XF86XK_LAUNCH_D",
+    "DOM_VK_XF86XK_LAUNCH_E",
+    "DOM_VK_XF86XK_LAUNCH_F",
+    "DOM_VK_XF86XK_LIGHT_BULB",
+    "DOM_VK_XF86XK_LOG_OFF",
+    "DOM_VK_XF86XK_MAIL",
+    "DOM_VK_XF86XK_MAIL_FORWARD",
+    "DOM_VK_XF86XK_MARKET",
+    "DOM_VK_XF86XK_MEETING",
+    "DOM_VK_XF86XK_MEMO",
+    "DOM_VK_XF86XK_MENU_KB",
+    "DOM_VK_XF86XK_MENU_PB",
+    "DOM_VK_XF86XK_MESSENGER",
+    "DOM_VK_XF86XK_MON_BRIGHTNESS_DOWN",
+    "DOM_VK_XF86XK_MON_BRIGHTNESS_UP",
+    "DOM_VK_XF86XK_MUSIC",
+    "DOM_VK_XF86XK_MY_COMPUTER",
+    "DOM_VK_XF86XK_MY_SITES",
+    "DOM_VK_XF86XK_NEW",
+    "DOM_VK_XF86XK_NEWS",
+    "DOM_VK_XF86XK_OFFICE_HOME",
+    "DOM_VK_XF86XK_OPEN",
+    "DOM_VK_XF86XK_OPEN_URL",
+    "DOM_VK_XF86XK_OPTION",
+    "DOM_VK_XF86XK_PASTE",
+    "DOM_VK_XF86XK_PHONE",
+    "DOM_VK_XF86XK_PICTURES",
+    "DOM_VK_XF86XK_POWER_DOWN",
+    "DOM_VK_XF86XK_POWER_OFF",
+    "DOM_VK_XF86XK_RED",
+    "DOM_VK_XF86XK_REFRESH",
+    "DOM_VK_XF86XK_RELOAD",
+    "DOM_VK_XF86XK_REPLY",
+    "DOM_VK_XF86XK_ROCKER_DOWN",
+    "DOM_VK_XF86XK_ROCKER_ENTER",
+    "DOM_VK_XF86XK_ROCKER_UP",
+    "DOM_VK_XF86XK_ROTATE_WINDOWS",
+    "DOM_VK_XF86XK_ROTATION_KB",
+    "DOM_VK_XF86XK_ROTATION_PB",
+    "DOM_VK_XF86XK_SAVE",
+    "DOM_VK_XF86XK_SCREEN_SAVER",
+    "DOM_VK_XF86XK_SCROLL_CLICK",
+    "DOM_VK_XF86XK_SCROLL_DOWN",
+    "DOM_VK_XF86XK_SCROLL_UP",
+    "DOM_VK_XF86XK_SEARCH",
+    "DOM_VK_XF86XK_SEND",
+    "DOM_VK_XF86XK_SHOP",
+    "DOM_VK_XF86XK_SPELL",
+    "DOM_VK_XF86XK_SPLIT_SCREEN",
+    "DOM_VK_XF86XK_STANDBY",
+    "DOM_VK_XF86XK_START",
+    "DOM_VK_XF86XK_STOP",
+    "DOM_VK_XF86XK_SUBTITLE",
+    "DOM_VK_XF86XK_SUPPORT",
+    "DOM_VK_XF86XK_SUSPEND",
+    "DOM_VK_XF86XK_TASK_PANE",
+    "DOM_VK_XF86XK_TERMINAL",
+    "DOM_VK_XF86XK_TIME",
+    "DOM_VK_XF86XK_TOOLS",
+    "DOM_VK_XF86XK_TOP_MENU",
+    "DOM_VK_XF86XK_TO_DO_LIST",
+    "DOM_VK_XF86XK_TRAVEL",
+    "DOM_VK_XF86XK_USER1KB",
+    "DOM_VK_XF86XK_USER2KB",
+    "DOM_VK_XF86XK_USER_PB",
+    "DOM_VK_XF86XK_UWB",
+    "DOM_VK_XF86XK_VENDOR_HOME",
+    "DOM_VK_XF86XK_VIDEO",
+    "DOM_VK_XF86XK_VIEW",
+    "DOM_VK_XF86XK_WAKE_UP",
+    "DOM_VK_XF86XK_WEB_CAM",
+    "DOM_VK_XF86XK_WHEEL_BUTTON",
+    "DOM_VK_XF86XK_WLAN",
+    "DOM_VK_XF86XK_WORD",
+    "DOM_VK_XF86XK_WWW",
+    "DOM_VK_XF86XK_XFER",
+    "DOM_VK_XF86XK_YELLOW",
+    "DOM_VK_XF86XK_ZOOM_IN",
+    "DOM_VK_XF86XK_ZOOM_OUT",
+    "DOM_VK_Y",
+    "DOM_VK_Z",
+    "DOM_VK_ZOOM",
+    "DONE",
+    "DONT_CARE",
+    "DOWNLOADING",
+    "DRAGDROP",
+    "DRAW_BUFFER0",
+    "DRAW_BUFFER1",
+    "DRAW_BUFFER10",
+    "DRAW_BUFFER11",
+    "DRAW_BUFFER12",
+    "DRAW_BUFFER13",
+    "DRAW_BUFFER14",
+    "DRAW_BUFFER15",
+    "DRAW_BUFFER2",
+    "DRAW_BUFFER3",
+    "DRAW_BUFFER4",
+    "DRAW_BUFFER5",
+    "DRAW_BUFFER6",
+    "DRAW_BUFFER7",
+    "DRAW_BUFFER8",
+    "DRAW_BUFFER9",
+    "DRAW_FRAMEBUFFER",
+    "DRAW_FRAMEBUFFER_BINDING",
+    "DST_ALPHA",
+    "DST_COLOR",
+    "DYNAMIC_COPY",
+    "DYNAMIC_DRAW",
+    "DYNAMIC_READ",
+    "DataChannel",
+    "DataTransfer",
+    "DataTransferItem",
+    "DataTransferItemList",
+    "DataView",
+    "Date",
+    "DateTimeFormat",
+    "DecompressionStream",
+    "DelayNode",
+    "DelegatedInkTrailPresenter",
+    "DeprecationReportBody",
+    "DesktopNotification",
+    "DesktopNotificationCenter",
+    "Details",
+    "DeviceLightEvent",
+    "DeviceMotionEvent",
+    "DeviceMotionEventAcceleration",
+    "DeviceMotionEventRotationRate",
+    "DeviceOrientationEvent",
+    "DevicePosture",
+    "DeviceProximityEvent",
+    "DeviceStorage",
+    "DeviceStorageChangeEvent",
+    "DigitalCredential",
+    "Directory",
+    "DisplayNames",
+    "DisposableStack",
+    "Document",
+    "DocumentFragment",
+    "DocumentPictureInPicture",
+    "DocumentPictureInPictureEvent",
+    "DocumentTimeline",
+    "DocumentType",
+    "DragEvent",
+    "Duration",
+    "DurationFormat",
+    "DynamicsCompressorNode",
+    "E",
+    "ELEMENT_ARRAY_BUFFER",
+    "ELEMENT_ARRAY_BUFFER_BINDING",
+    "ELEMENT_NODE",
+    "EMPTY",
+    "ENCODING_ERR",
+    "ENDED",
+    "END_TO_END",
+    "END_TO_START",
+    "ENTITY_NODE",
+    "ENTITY_REFERENCE_NODE",
+    "EPSILON",
+    "EQUAL",
+    "EQUALPOWER",
+    "ERROR",
+    "EXPONENTIAL_DISTANCE",
+    "EditContext",
+    "Element",
+    "ElementInternals",
+    "ElementQuery",
+    "EncodedAudioChunk",
+    "EncodedVideoChunk",
+    "EnterPictureInPictureEvent",
+    "Entity",
+    "EntityReference",
+    "Error",
+    "ErrorEvent",
+    "EvalError",
+    "Event",
+    "EventCounts",
+    "EventException",
+    "EventSource",
+    "EventTarget",
+    "Exception",
+    "ExtensionContext",
+    "ExtensionDisabledReason",
+    "ExtensionInfo",
+    "ExtensionInstallType",
+    "ExtensionType",
+    "External",
+    "EyeDropper",
+    "FASTEST",
+    "FIDOSDK",
+    "FILTER_ACCEPT",
+    "FILTER_INTERRUPT",
+    "FILTER_REJECT",
+    "FILTER_SKIP",
+    "FINISHED_STATE",
+    "FIRST_ORDERED_NODE_TYPE",
+    "FLOAT",
+    "FLOAT_32_UNSIGNED_INT_24_8_REV",
+    "FLOAT_MAT2",
+    "FLOAT_MAT2x3",
+    "FLOAT_MAT2x4",
+    "FLOAT_MAT3",
+    "FLOAT_MAT3x2",
+    "FLOAT_MAT3x4",
+    "FLOAT_MAT4",
+    "FLOAT_MAT4x2",
+    "FLOAT_MAT4x3",
+    "FLOAT_VEC2",
+    "FLOAT_VEC3",
+    "FLOAT_VEC4",
+    "FOCUS",
+    "FONT_FACE_RULE",
+    "FONT_FEATURE_VALUES_RULE",
+    "FRAGMENT",
+    "FRAGMENT_SHADER",
+    "FRAGMENT_SHADER_DERIVATIVE_HINT",
+    "FRAGMENT_SHADER_DERIVATIVE_HINT_OES",
+    "FRAMEBUFFER",
+    "FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_BLUE_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING",
+    "FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE",
+    "FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_GREEN_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME",
+    "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE",
+    "FRAMEBUFFER_ATTACHMENT_RED_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE",
+    "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE",
+    "FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER",
+    "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL",
+    "FRAMEBUFFER_BINDING",
+    "FRAMEBUFFER_COMPLETE",
+    "FRAMEBUFFER_DEFAULT",
+    "FRAMEBUFFER_INCOMPLETE_ATTACHMENT",
+    "FRAMEBUFFER_INCOMPLETE_DIMENSIONS",
+    "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT",
+    "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE",
+    "FRAMEBUFFER_UNSUPPORTED",
+    "FRONT",
+    "FRONT_AND_BACK",
+    "FRONT_FACE",
+    "FUNC_ADD",
+    "FUNC_REVERSE_SUBTRACT",
+    "FUNC_SUBTRACT",
+    "FeaturePolicy",
+    "FeaturePolicyViolationReportBody",
+    "FederatedCredential",
+    "Feed",
+    "FeedEntry",
+    "Fence",
+    "FencedFrameConfig",
+    "FetchLaterResult",
+    "File",
+    "FileError",
+    "FileList",
+    "FileReader",
+    "FileSystem",
+    "FileSystemDirectoryEntry",
+    "FileSystemDirectoryHandle",
+    "FileSystemDirectoryReader",
+    "FileSystemEntry",
+    "FileSystemFileEntry",
+    "FileSystemFileHandle",
+    "FileSystemHandle",
+    "FileSystemObserver",
+    "FileSystemWritableFileStream",
+    "FinalizationRegistry",
+    "FindInPage",
+    "Float16Array",
+    "Float32Array",
+    "Float64Array",
+    "FocusEvent",
+    "FontData",
+    "FontFace",
+    "FontFaceSet",
+    "FontFaceSetLoadEvent",
+    "FormData",
+    "FormDataEvent",
+    "FragmentDirective",
+    "Function",
+    "GENERATE_MIPMAP_HINT",
+    "GEQUAL",
+    "GPU",
+    "GPUAdapter",
+    "GPUAdapterInfo",
+    "GPUBindGroup",
+    "GPUBindGroupLayout",
+    "GPUBuffer",
+    "GPUBufferUsage",
+    "GPUCanvasContext",
+    "GPUColorWrite",
+    "GPUCommandBuffer",
+    "GPUCommandEncoder",
+    "GPUCompilationInfo",
+    "GPUCompilationMessage",
+    "GPUComputePassEncoder",
+    "GPUComputePipeline",
+    "GPUDevice",
+    "GPUDeviceLostInfo",
+    "GPUError",
+    "GPUExternalTexture",
+    "GPUInternalError",
+    "GPUMapMode",
+    "GPUOutOfMemoryError",
+    "GPUPipelineError",
+    "GPUPipelineLayout",
+    "GPUQuerySet",
+    "GPUQueue",
+    "GPURenderBundle",
+    "GPURenderBundleEncoder",
+    "GPURenderPassEncoder",
+    "GPURenderPipeline",
+    "GPUSampler",
+    "GPUShaderModule",
+    "GPUShaderStage",
+    "GPUSupportedFeatures",
+    "GPUSupportedLimits",
+    "GPUTexture",
+    "GPUTextureUsage",
+    "GPUTextureView",
+    "GPUUncapturedErrorEvent",
+    "GPUValidationError",
+    "GREATER",
+    "GREEN",
+    "GREEN_BITS",
+    "GainNode",
+    "Gamepad",
+    "GamepadAxisMoveEvent",
+    "GamepadButton",
+    "GamepadButtonEvent",
+    "GamepadEvent",
+    "GamepadHapticActuator",
+    "GamepadPose",
+    "Geolocation",
+    "GeolocationCoordinates",
+    "GeolocationPosition",
+    "GeolocationPositionError",
+    "GestureEvent",
+    "GetInfo",
+    "Global",
+    "GravitySensor",
+    "Gyroscope",
+    "HALF_FLOAT",
+    "HAVE_CURRENT_DATA",
+    "HAVE_ENOUGH_DATA",
+    "HAVE_FUTURE_DATA",
+    "HAVE_METADATA",
+    "HAVE_NOTHING",
+    "HEADERS_RECEIVED",
+    "HID",
+    "HIDConnectionEvent",
+    "HIDDEN",
+    "HIDDevice",
+    "HIDInputReportEvent",
+    "HIERARCHY_REQUEST_ERR",
+    "HIGHPASS",
+    "HIGHSHELF",
+    "HIGH_FLOAT",
+    "HIGH_INT",
+    "HORIZONTAL",
+    "HORIZONTAL_AXIS",
+    "HRTF",
+    "HTMLAllCollection",
+    "HTMLAnchorElement",
+    "HTMLAppletElement",
+    "HTMLAreaElement",
+    "HTMLAudioElement",
+    "HTMLBRElement",
+    "HTMLBaseElement",
+    "HTMLBaseFontElement",
+    "HTMLBlockquoteElement",
+    "HTMLBodyElement",
+    "HTMLButtonElement",
+    "HTMLCanvasElement",
+    "HTMLCollection",
+    "HTMLCommandElement",
+    "HTMLContentElement",
+    "HTMLDListElement",
+    "HTMLDataElement",
+    "HTMLDataListElement",
+    "HTMLDetailsElement",
+    "HTMLDialogElement",
+    "HTMLDirectoryElement",
+    "HTMLDivElement",
+    "HTMLDocument",
+    "HTMLElement",
+    "HTMLEmbedElement",
+    "HTMLFencedFrameElement",
+    "HTMLFieldSetElement",
+    "HTMLFontElement",
+    "HTMLFormControlsCollection",
+    "HTMLFormElement",
+    "HTMLFrameElement",
+    "HTMLFrameSetElement",
+    "HTMLHRElement",
+    "HTMLHeadElement",
+    "HTMLHeadingElement",
+    "HTMLHtmlElement",
+    "HTMLIFrameElement",
+    "HTMLImageElement",
+    "HTMLInputElement",
+    "HTMLIsIndexElement",
+    "HTMLKeygenElement",
+    "HTMLLIElement",
+    "HTMLLabelElement",
+    "HTMLLegendElement",
+    "HTMLLinkElement",
+    "HTMLMapElement",
+    "HTMLMarqueeElement",
+    "HTMLMediaElement",
+    "HTMLMenuElement",
+    "HTMLMenuItemElement",
+    "HTMLMetaElement",
+    "HTMLMeterElement",
+    "HTMLModElement",
+    "HTMLOListElement",
+    "HTMLObjectElement",
+    "HTMLOptGroupElement",
+    "HTMLOptionElement",
+    "HTMLOptionsCollection",
+    "HTMLOutputElement",
+    "HTMLParagraphElement",
+    "HTMLParamElement",
+    "HTMLPictureElement",
+    "HTMLPreElement",
+    "HTMLProgressElement",
+    "HTMLPropertiesCollection",
+    "HTMLQuoteElement",
+    "HTMLScriptElement",
+    "HTMLSelectElement",
+    "HTMLSelectedContentElement",
+    "HTMLShadowElement",
+    "HTMLSlotElement",
+    "HTMLSourceElement",
+    "HTMLSpanElement",
+    "HTMLStyleElement",
+    "HTMLTableCaptionElement",
+    "HTMLTableCellElement",
+    "HTMLTableColElement",
+    "HTMLTableElement",
+    "HTMLTableRowElement",
+    "HTMLTableSectionElement",
+    "HTMLTemplateElement",
+    "HTMLTextAreaElement",
+    "HTMLTimeElement",
+    "HTMLTitleElement",
+    "HTMLTrackElement",
+    "HTMLUListElement",
+    "HTMLUnknownElement",
+    "HTMLVideoElement",
+    "HashChangeEvent",
+    "Headers",
+    "Highlight",
+    "HighlightRegistry",
+    "History",
+    "Hz",
+    "ICE_CHECKING",
+    "ICE_CLOSED",
+    "ICE_COMPLETED",
+    "ICE_CONNECTED",
+    "ICE_FAILED",
+    "ICE_GATHERING",
+    "ICE_WAITING",
+    "IDBCursor",
+    "IDBCursorWithValue",
+    "IDBDatabase",
+    "IDBDatabaseException",
+    "IDBFactory",
+    "IDBFileHandle",
+    "IDBFileRequest",
+    "IDBIndex",
+    "IDBKeyRange",
+    "IDBMutableFile",
+    "IDBObjectStore",
+    "IDBOpenDBRequest",
+    "IDBRecord",
+    "IDBRequest",
+    "IDBTransaction",
+    "IDBVersionChangeEvent",
+    "IDLE",
+    "IIRFilterNode",
+    "IMPLEMENTATION_COLOR_READ_FORMAT",
+    "IMPLEMENTATION_COLOR_READ_TYPE",
+    "IMPORT_RULE",
+    "INCR",
+    "INCR_WRAP",
+    "INDEX",
+    "INDEX_SIZE_ERR",
+    "INDIRECT",
+    "INT",
+    "INTERLEAVED_ATTRIBS",
+    "INT_2_10_10_10_REV",
+    "INT_SAMPLER_2D",
+    "INT_SAMPLER_2D_ARRAY",
+    "INT_SAMPLER_3D",
+    "INT_SAMPLER_CUBE",
+    "INT_VEC2",
+    "INT_VEC3",
+    "INT_VEC4",
+    "INUSE_ATTRIBUTE_ERR",
+    "INVALID_ACCESS_ERR",
+    "INVALID_CHARACTER_ERR",
+    "INVALID_ENUM",
+    "INVALID_EXPRESSION_ERR",
+    "INVALID_FRAMEBUFFER_OPERATION",
+    "INVALID_INDEX",
+    "INVALID_MODIFICATION_ERR",
+    "INVALID_NODE_TYPE_ERR",
+    "INVALID_OPERATION",
+    "INVALID_STATE_ERR",
+    "INVALID_VALUE",
+    "INVERSE_DISTANCE",
+    "INVERT",
+    "IceCandidate",
+    "IconInfo",
+    "IdentityCredential",
+    "IdentityCredentialError",
+    "IdentityProvider",
+    "IdleDeadline",
+    "IdleDetector",
+    "Image",
+    "ImageBitmap",
+    "ImageBitmapRenderingContext",
+    "ImageCapture",
+    "ImageData",
+    "ImageDataType",
+    "ImageDecoder",
+    "ImageTrack",
+    "ImageTrackList",
+    "Infinity",
+    "Ink",
+    "InputDeviceCapabilities",
+    "InputDeviceInfo",
+    "InputEvent",
+    "InputMethodContext",
+    "InstallTrigger",
+    "InstallTriggerImpl",
+    "Instance",
+    "Instant",
+    "Int16Array",
+    "Int32Array",
+    "Int8Array",
+    "IntegrityViolationReportBody",
+    "Intent",
+    "InterestEvent",
+    "InternalError",
+    "IntersectionObserver",
+    "IntersectionObserverEntry",
+    "Intl",
+    "IsSearchProviderInstalled",
+    "Iterator",
+    "JSON",
+    "JSTag",
+    "KEEP",
+    "KEYDOWN",
+    "KEYFRAMES_RULE",
+    "KEYFRAME_RULE",
+    "KEYPRESS",
+    "KEYUP",
+    "KeyEvent",
+    "Keyboard",
+    "KeyboardEvent",
+    "KeyboardLayoutMap",
+    "KeyframeEffect",
+    "LENGTHADJUST_SPACING",
+    "LENGTHADJUST_SPACINGANDGLYPHS",
+    "LENGTHADJUST_UNKNOWN",
+    "LEQUAL",
+    "LESS",
+    "LINEAR",
+    "LINEAR_DISTANCE",
+    "LINEAR_MIPMAP_LINEAR",
+    "LINEAR_MIPMAP_NEAREST",
+    "LINES",
+    "LINE_LOOP",
+    "LINE_STRIP",
+    "LINE_WIDTH",
+    "LINK_STATUS",
+    "LIVE",
+    "LN10",
+    "LN2",
+    "LOADED",
+    "LOADING",
+    "LOG10E",
+    "LOG2E",
+    "LOWPASS",
+    "LOWSHELF",
+    "LOW_FLOAT",
+    "LOW_INT",
+    "LSException",
+    "LSParserFilter",
+    "LUMINANCE",
+    "LUMINANCE_ALPHA",
+    "LanguageCode",
+    "LanguageDetector",
+    "LargestContentfulPaint",
+    "LaunchParams",
+    "LaunchQueue",
+    "LaunchType",
+    "LayoutShift",
+    "LayoutShiftAttribution",
+    "LinearAccelerationSensor",
+    "LinkError",
+    "ListFormat",
+    "LocalMediaStream",
+    "Locale",
+    "Location",
+    "Lock",
+    "LockManager",
+    "MAP_READ",
+    "MAP_WRITE",
+    "MARGIN_RULE",
+    "MAX",
+    "MAX_3D_TEXTURE_SIZE",
+    "MAX_ARRAY_TEXTURE_LAYERS",
+    "MAX_CAPTURE_VISIBLE_TAB_CALLS_PER_SECOND",
+    "MAX_CLIENT_WAIT_TIMEOUT_WEBGL",
+    "MAX_COLOR_ATTACHMENTS",
+    "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS",
+    "MAX_COMBINED_TEXTURE_IMAGE_UNITS",
+    "MAX_COMBINED_UNIFORM_BLOCKS",
+    "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS",
+    "MAX_CUBE_MAP_TEXTURE_SIZE",
+    "MAX_DRAW_BUFFERS",
+    "MAX_ELEMENTS_INDICES",
+    "MAX_ELEMENTS_VERTICES",
+    "MAX_ELEMENT_INDEX",
+    "MAX_FRAGMENT_INPUT_COMPONENTS",
+    "MAX_FRAGMENT_UNIFORM_BLOCKS",
+    "MAX_FRAGMENT_UNIFORM_COMPONENTS",
+    "MAX_FRAGMENT_UNIFORM_VECTORS",
+    "MAX_PROGRAM_TEXEL_OFFSET",
+    "MAX_RENDERBUFFER_SIZE",
+    "MAX_SAFE_INTEGER",
+    "MAX_SAMPLES",
+    "MAX_SERVER_WAIT_TIMEOUT",
+    "MAX_TEXTURE_IMAGE_UNITS",
+    "MAX_TEXTURE_LOD_BIAS",
+    "MAX_TEXTURE_MAX_ANISOTROPY_EXT",
+    "MAX_TEXTURE_SIZE",
+    "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS",
+    "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS",
+    "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS",
+    "MAX_UNIFORM_BLOCK_SIZE",
+    "MAX_UNIFORM_BUFFER_BINDINGS",
+    "MAX_VALUE",
+    "MAX_VARYING_COMPONENTS",
+    "MAX_VARYING_VECTORS",
+    "MAX_VERTEX_ATTRIBS",
+    "MAX_VERTEX_OUTPUT_COMPONENTS",
+    "MAX_VERTEX_TEXTURE_IMAGE_UNITS",
+    "MAX_VERTEX_UNIFORM_BLOCKS",
+    "MAX_VERTEX_UNIFORM_COMPONENTS",
+    "MAX_VERTEX_UNIFORM_VECTORS",
+    "MAX_VIEWPORT_DIMS",
+    "MEDIA_ERR_ABORTED",
+    "MEDIA_ERR_DECODE",
+    "MEDIA_ERR_ENCRYPTED",
+    "MEDIA_ERR_NETWORK",
+    "MEDIA_ERR_SRC_NOT_SUPPORTED",
+    "MEDIA_KEYERR_CLIENT",
+    "MEDIA_KEYERR_DOMAIN",
+    "MEDIA_KEYERR_HARDWARECHANGE",
+    "MEDIA_KEYERR_OUTPUT",
+    "MEDIA_KEYERR_SERVICE",
+    "MEDIA_KEYERR_UNKNOWN",
+    "MEDIA_RULE",
+    "MEDIUM_FLOAT",
+    "MEDIUM_INT",
+    "META_MASK",
+    "MIDIAccess",
+    "MIDIConnectionEvent",
+    "MIDIInput",
+    "MIDIInputMap",
+    "MIDIMessageEvent",
+    "MIDIOutput",
+    "MIDIOutputMap",
+    "MIDIPort",
+    "MIN",
+    "MIN_PROGRAM_TEXEL_OFFSET",
+    "MIN_SAFE_INTEGER",
+    "MIN_VALUE",
+    "MIRRORED_REPEAT",
+    "MODE_ASYNCHRONOUS",
+    "MODE_SYNCHRONOUS",
+    "MODIFICATION",
+    "MOUSEDOWN",
+    "MOUSEDRAG",
+    "MOUSEMOVE",
+    "MOUSEOUT",
+    "MOUSEOVER",
+    "MOUSEUP",
+    "MOZ_KEYFRAMES_RULE",
+    "MOZ_KEYFRAME_RULE",
+    "MOZ_SOURCE_CURSOR",
+    "MOZ_SOURCE_ERASER",
+    "MOZ_SOURCE_KEYBOARD",
+    "MOZ_SOURCE_MOUSE",
+    "MOZ_SOURCE_PEN",
+    "MOZ_SOURCE_TOUCH",
+    "MOZ_SOURCE_UNKNOWN",
+    "MSGESTURE_FLAG_BEGIN",
+    "MSGESTURE_FLAG_CANCEL",
+    "MSGESTURE_FLAG_END",
+    "MSGESTURE_FLAG_INERTIA",
+    "MSGESTURE_FLAG_NONE",
+    "MSPOINTER_TYPE_MOUSE",
+    "MSPOINTER_TYPE_PEN",
+    "MSPOINTER_TYPE_TOUCH",
+    "MS_ASYNC_CALLBACK_STATUS_ASSIGN_DELEGATE",
+    "MS_ASYNC_CALLBACK_STATUS_CANCEL",
+    "MS_ASYNC_CALLBACK_STATUS_CHOOSEANY",
+    "MS_ASYNC_CALLBACK_STATUS_ERROR",
+    "MS_ASYNC_CALLBACK_STATUS_JOIN",
+    "MS_ASYNC_OP_STATUS_CANCELED",
+    "MS_ASYNC_OP_STATUS_ERROR",
+    "MS_ASYNC_OP_STATUS_SUCCESS",
+    "MS_MANIPULATION_STATE_ACTIVE",
+    "MS_MANIPULATION_STATE_CANCELLED",
+    "MS_MANIPULATION_STATE_COMMITTED",
+    "MS_MANIPULATION_STATE_DRAGGING",
+    "MS_MANIPULATION_STATE_INERTIA",
+    "MS_MANIPULATION_STATE_PRESELECT",
+    "MS_MANIPULATION_STATE_SELECTING",
+    "MS_MANIPULATION_STATE_STOPPED",
+    "MS_MEDIA_ERR_ENCRYPTED",
+    "MS_MEDIA_KEYERR_CLIENT",
+    "MS_MEDIA_KEYERR_DOMAIN",
+    "MS_MEDIA_KEYERR_HARDWARECHANGE",
+    "MS_MEDIA_KEYERR_OUTPUT",
+    "MS_MEDIA_KEYERR_SERVICE",
+    "MS_MEDIA_KEYERR_UNKNOWN",
+    "Map",
+    "Math",
+    "MathMLElement",
+    "MediaCapabilities",
+    "MediaCapabilitiesInfo",
+    "MediaController",
+    "MediaDeviceInfo",
+    "MediaDevices",
+    "MediaElementAudioSourceNode",
+    "MediaEncryptedEvent",
+    "MediaError",
+    "MediaKeyError",
+    "MediaKeyEvent",
+    "MediaKeyMessageEvent",
+    "MediaKeyNeededEvent",
+    "MediaKeySession",
+    "MediaKeyStatusMap",
+    "MediaKeySystemAccess",
+    "MediaKeys",
+    "MediaList",
+    "MediaMetadata",
+    "MediaQueryList",
+    "MediaQueryListEvent",
+    "MediaRecorder",
+    "MediaRecorderErrorEvent",
+    "MediaSession",
+    "MediaSettingsRange",
+    "MediaSource",
+    "MediaSourceHandle",
+    "MediaStream",
+    "MediaStreamAudioDestinationNode",
+    "MediaStreamAudioSourceNode",
+    "MediaStreamEvent",
+    "MediaStreamTrack",
+    "MediaStreamTrackAudioSourceNode",
+    "MediaStreamTrackAudioStats",
+    "MediaStreamTrackEvent",
+    "MediaStreamTrackGenerator",
+    "MediaStreamTrackProcessor",
+    "MediaStreamTrackVideoStats",
+    "Memory",
+    "MessageChannel",
+    "MessageEvent",
+    "MessagePort",
+    "MessageSender",
+    "Methods",
+    "MimeType",
+    "MimeTypeArray",
+    "Module",
+    "MouseEvent",
+    "MouseScrollEvent",
+    "MozAnimation",
+    "MozAnimationDelay",
+    "MozAnimationDirection",
+    "MozAnimationDuration",
+    "MozAnimationFillMode",
+    "MozAnimationIterationCount",
+    "MozAnimationName",
+    "MozAnimationPlayState",
+    "MozAnimationTimingFunction",
+    "MozAppearance",
+    "MozBackfaceVisibility",
+    "MozBinding",
+    "MozBorderBottomColors",
+    "MozBorderEnd",
+    "MozBorderEndColor",
+    "MozBorderEndStyle",
+    "MozBorderEndWidth",
+    "MozBorderImage",
+    "MozBorderLeftColors",
+    "MozBorderRightColors",
+    "MozBorderStart",
+    "MozBorderStartColor",
+    "MozBorderStartStyle",
+    "MozBorderStartWidth",
+    "MozBorderTopColors",
+    "MozBoxAlign",
+    "MozBoxDirection",
+    "MozBoxFlex",
+    "MozBoxOrdinalGroup",
+    "MozBoxOrient",
+    "MozBoxPack",
+    "MozBoxSizing",
+    "MozCSSKeyframeRule",
+    "MozCSSKeyframesRule",
+    "MozColumnCount",
+    "MozColumnFill",
+    "MozColumnGap",
+    "MozColumnRule",
+    "MozColumnRuleColor",
+    "MozColumnRuleStyle",
+    "MozColumnRuleWidth",
+    "MozColumnWidth",
+    "MozColumns",
+    "MozContactChangeEvent",
+    "MozFloatEdge",
+    "MozFontFeatureSettings",
+    "MozFontLanguageOverride",
+    "MozForceBrokenImageIcon",
+    "MozHyphens",
+    "MozImageRegion",
+    "MozMarginEnd",
+    "MozMarginStart",
+    "MozMmsEvent",
+    "MozMmsMessage",
+    "MozMobileMessageThread",
+    "MozOSXFontSmoothing",
+    "MozOrient",
+    "MozOsxFontSmoothing",
+    "MozOutlineRadius",
+    "MozOutlineRadiusBottomleft",
+    "MozOutlineRadiusBottomright",
+    "MozOutlineRadiusTopleft",
+    "MozOutlineRadiusTopright",
+    "MozPaddingEnd",
+    "MozPaddingStart",
+    "MozPerspective",
+    "MozPerspectiveOrigin",
+    "MozPowerManager",
+    "MozSettingsEvent",
+    "MozSmsEvent",
+    "MozSmsMessage",
+    "MozStackSizing",
+    "MozTabSize",
+    "MozTextAlignLast",
+    "MozTextDecorationColor",
+    "MozTextDecorationLine",
+    "MozTextDecorationStyle",
+    "MozTextSizeAdjust",
+    "MozTransform",
+    "MozTransformOrigin",
+    "MozTransformStyle",
+    "MozTransition",
+    "MozTransitionDelay",
+    "MozTransitionDuration",
+    "MozTransitionProperty",
+    "MozTransitionTimingFunction",
+    "MozUserFocus",
+    "MozUserInput",
+    "MozUserModify",
+    "MozUserSelect",
+    "MozWindowDragging",
+    "MozWindowShadow",
+    "MutationEvent",
+    "MutationObserver",
+    "MutationRecord",
+    "MutedInfo",
+    "MutedInfoReason",
+    "NAMESPACE_ERR",
+    "NAMESPACE_RULE",
+    "NEAREST",
+    "NEAREST_MIPMAP_LINEAR",
+    "NEAREST_MIPMAP_NEAREST",
+    "NEGATIVE_INFINITY",
+    "NETWORK_EMPTY",
+    "NETWORK_ERR",
+    "NETWORK_IDLE",
+    "NETWORK_LOADED",
+    "NETWORK_LOADING",
+    "NETWORK_NO_SOURCE",
+    "NEVER",
+    "NEW",
+    "NEXT",
+    "NEXT_NO_DUPLICATE",
+    "NICEST",
+    "NODE_AFTER",
+    "NODE_BEFORE",
+    "NODE_BEFORE_AND_AFTER",
+    "NODE_INSIDE",
+    "NONE",
+    "NON_TRANSIENT_ERR",
+    "NOTATION_NODE",
+    "NOTCH",
+    "NOTEQUAL",
+    "NOT_ALLOWED_ERR",
+    "NOT_FOUND_ERR",
+    "NOT_READABLE_ERR",
+    "NOT_SUPPORTED_ERR",
+    "NO_DATA_ALLOWED_ERR",
+    "NO_ERR",
+    "NO_ERROR",
+    "NO_MODIFICATION_ALLOWED_ERR",
+    "NUMBER_TYPE",
+    "NUM_COMPRESSED_TEXTURE_FORMATS",
+    "NaN",
+    "NamedNodeMap",
+    "NavigateEvent",
+    "Navigation",
+    "NavigationActivation",
+    "NavigationCurrentEntryChangeEvent",
+    "NavigationDestination",
+    "NavigationHistoryEntry",
+    "NavigationPrecommitController",
+    "NavigationPreloadManager",
+    "NavigationTransition",
+    "Navigator",
+    "NavigatorLogin",
+    "NavigatorManagedData",
+    "NavigatorUAData",
+    "NearbyLinks",
+    "NetworkInformation",
+    "Node",
+    "NodeFilter",
+    "NodeIterator",
+    "NodeList",
+    "NotRestoredReasonDetails",
+    "NotRestoredReasons",
+    "Notation",
+    "Notification",
+    "NotifyPaintEvent",
+    "Now",
+    "Number",
+    "NumberFormat",
+    "OBJECT_TYPE",
+    "OBSOLETE",
+    "OK",
+    "ONE",
+    "ONE_MINUS_CONSTANT_ALPHA",
+    "ONE_MINUS_CONSTANT_COLOR",
+    "ONE_MINUS_DST_ALPHA",
+    "ONE_MINUS_DST_COLOR",
+    "ONE_MINUS_SRC_ALPHA",
+    "ONE_MINUS_SRC_COLOR",
+    "OPEN",
+    "OPENED",
+    "OPENING",
+    "ORDERED_NODE_ITERATOR_TYPE",
+    "ORDERED_NODE_SNAPSHOT_TYPE",
+    "OTHER_ERROR",
+    "OTPCredential",
+    "OUT_OF_MEMORY",
+    "Object",
+    "Observable",
+    "OfflineAudioCompletionEvent",
+    "OfflineAudioContext",
+    "OfflineResourceList",
+    "OffscreenCanvas",
+    "OffscreenCanvasRenderingContext2D",
+    "OnClickData",
+    "OnInstalledReason",
+    "OnPerformanceWarningCategory",
+    "OnPerformanceWarningSeverity",
+    "OnRestartRequiredReason",
+    "Option",
+    "OrientationSensor",
+    "OscillatorNode",
+    "OverconstrainedError",
+    "OverflowEvent",
+    "PACK_ALIGNMENT",
+    "PACK_ROW_LENGTH",
+    "PACK_SKIP_PIXELS",
+    "PACK_SKIP_ROWS",
+    "PAGE_RULE",
+    "PARSE_ERR",
+    "PATHSEG_ARC_ABS",
+    "PATHSEG_ARC_REL",
+    "PATHSEG_CLOSEPATH",
+    "PATHSEG_CURVETO_CUBIC_ABS",
+    "PATHSEG_CURVETO_CUBIC_REL",
+    "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS",
+    "PATHSEG_CURVETO_CUBIC_SMOOTH_REL",
+    "PATHSEG_CURVETO_QUADRATIC_ABS",
+    "PATHSEG_CURVETO_QUADRATIC_REL",
+    "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS",
+    "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL",
+    "PATHSEG_LINETO_ABS",
+    "PATHSEG_LINETO_HORIZONTAL_ABS",
+    "PATHSEG_LINETO_HORIZONTAL_REL",
+    "PATHSEG_LINETO_REL",
+    "PATHSEG_LINETO_VERTICAL_ABS",
+    "PATHSEG_LINETO_VERTICAL_REL",
+    "PATHSEG_MOVETO_ABS",
+    "PATHSEG_MOVETO_REL",
+    "PATHSEG_UNKNOWN",
+    "PATH_EXISTS_ERR",
+    "PEAKING",
+    "PERMISSION_DENIED",
+    "PERSISTENT",
+    "PI",
+    "PIXEL_PACK_BUFFER",
+    "PIXEL_PACK_BUFFER_BINDING",
+    "PIXEL_UNPACK_BUFFER",
+    "PIXEL_UNPACK_BUFFER_BINDING",
+    "PLAYING_STATE",
+    "POINTS",
+    "POLYGON_OFFSET_FACTOR",
+    "POLYGON_OFFSET_FILL",
+    "POLYGON_OFFSET_UNITS",
+    "POSITION_UNAVAILABLE",
+    "POSITIVE_INFINITY",
+    "PREV",
+    "PREV_NO_DUPLICATE",
+    "PROCESSING_INSTRUCTION_NODE",
+    "PageChangeEvent",
+    "PageRevealEvent",
+    "PageSettings",
+    "PageSwapEvent",
+    "PageTransitionEvent",
+    "PaintRequest",
+    "PaintRequestList",
+    "PannerNode",
+    "PasswordCredential",
+    "Path2D",
+    "PaymentAddress",
+    "PaymentInstruments",
+    "PaymentManager",
+    "PaymentMethodChangeEvent",
+    "PaymentRequest",
+    "PaymentRequestUpdateEvent",
+    "PaymentResponse",
+    "Performance",
+    "PerformanceElementTiming",
+    "PerformanceEntry",
+    "PerformanceEventTiming",
+    "PerformanceLongAnimationFrameTiming",
+    "PerformanceLongTaskTiming",
+    "PerformanceMark",
+    "PerformanceMeasure",
+    "PerformanceNavigation",
+    "PerformanceNavigationTiming",
+    "PerformanceObserver",
+    "PerformanceObserverEntryList",
+    "PerformancePaintTiming",
+    "PerformanceResourceTiming",
+    "PerformanceScriptTiming",
+    "PerformanceServerTiming",
+    "PerformanceTiming",
+    "PeriodicSyncManager",
+    "PeriodicWave",
+    "PermissionStatus",
+    "Permissions",
+    "PhotoCapabilities",
+    "PictureInPictureEvent",
+    "PictureInPictureWindow",
+    "PlainDate",
+    "PlainDateTime",
+    "PlainMonthDay",
+    "PlainTime",
+    "PlainYearMonth",
+    "PlatformArch",
+    "PlatformInfo",
+    "PlatformNaclArch",
+    "PlatformOs",
+    "Plugin",
+    "PluginArray",
+    "PluralRules",
+    "PointerEvent",
+    "PopStateEvent",
+    "PopupBlockedEvent",
+    "Port",
+    "Presentation",
+    "PresentationAvailability",
+    "PresentationConnection",
+    "PresentationConnectionAvailableEvent",
+    "PresentationConnectionCloseEvent",
+    "PresentationConnectionList",
+    "PresentationReceiver",
+    "PresentationRequest",
+    "PressureObserver",
+    "PressureRecord",
+    "ProcessingInstruction",
+    "Profiler",
+    "ProgressEvent",
+    "Promise",
+    "PromiseRejectionEvent",
+    "PropertyNodeList",
+    "ProtectedAudience",
+    "Proxy",
+    "PublicKeyCredential",
+    "PushManager",
+    "PushSubscription",
+    "PushSubscriptionOptions",
+    "Q",
+    "QUERY_RESOLVE",
+    "QUERY_RESULT",
+    "QUERY_RESULT_AVAILABLE",
+    "QUOTA_ERR",
+    "QUOTA_EXCEEDED_ERR",
+    "QueryInterface",
+    "QuotaExceededError",
+    "R11F_G11F_B10F",
+    "R16F",
+    "R16I",
+    "R16UI",
+    "R32F",
+    "R32I",
+    "R32UI",
+    "R8",
+    "R8I",
+    "R8UI",
+    "R8_SNORM",
+    "RASTERIZER_DISCARD",
+    "READ",
+    "READ_BUFFER",
+    "READ_FRAMEBUFFER",
+    "READ_FRAMEBUFFER_BINDING",
+    "READ_ONLY",
+    "READ_ONLY_ERR",
+    "READ_WRITE",
+    "RED",
+    "RED_BITS",
+    "RED_INTEGER",
+    "REMOVAL",
+    "RENDERBUFFER",
+    "RENDERBUFFER_ALPHA_SIZE",
+    "RENDERBUFFER_BINDING",
+    "RENDERBUFFER_BLUE_SIZE",
+    "RENDERBUFFER_DEPTH_SIZE",
+    "RENDERBUFFER_GREEN_SIZE",
+    "RENDERBUFFER_HEIGHT",
+    "RENDERBUFFER_INTERNAL_FORMAT",
+    "RENDERBUFFER_RED_SIZE",
+    "RENDERBUFFER_SAMPLES",
+    "RENDERBUFFER_STENCIL_SIZE",
+    "RENDERBUFFER_WIDTH",
+    "RENDERER",
+    "RENDERING_INTENT_ABSOLUTE_COLORIMETRIC",
+    "RENDERING_INTENT_AUTO",
+    "RENDERING_INTENT_PERCEPTUAL",
+    "RENDERING_INTENT_RELATIVE_COLORIMETRIC",
+    "RENDERING_INTENT_SATURATION",
+    "RENDERING_INTENT_UNKNOWN",
+    "RENDER_ATTACHMENT",
+    "REPEAT",
+    "REPLACE",
+    "RG",
+    "RG16F",
+    "RG16I",
+    "RG16UI",
+    "RG32F",
+    "RG32I",
+    "RG32UI",
+    "RG8",
+    "RG8I",
+    "RG8UI",
+    "RG8_SNORM",
+    "RGB",
+    "RGB10_A2",
+    "RGB10_A2UI",
+    "RGB16F",
+    "RGB16I",
+    "RGB16UI",
+    "RGB32F",
+    "RGB32I",
+    "RGB32UI",
+    "RGB565",
+    "RGB5_A1",
+    "RGB8",
+    "RGB8I",
+    "RGB8UI",
+    "RGB8_SNORM",
+    "RGB9_E5",
+    "RGBA",
+    "RGBA16F",
+    "RGBA16I",
+    "RGBA16UI",
+    "RGBA32F",
+    "RGBA32I",
+    "RGBA32UI",
+    "RGBA4",
+    "RGBA8",
+    "RGBA8I",
+    "RGBA8UI",
+    "RGBA8_SNORM",
+    "RGBA_INTEGER",
+    "RGBColor",
+    "RGB_INTEGER",
+    "RG_INTEGER",
+    "ROTATION_CLOCKWISE",
+    "ROTATION_COUNTERCLOCKWISE",
+    "RTCCertificate",
+    "RTCDTMFSender",
+    "RTCDTMFToneChangeEvent",
+    "RTCDataChannel",
+    "RTCDataChannelEvent",
+    "RTCDtlsTransport",
+    "RTCEncodedAudioFrame",
+    "RTCEncodedVideoFrame",
+    "RTCError",
+    "RTCErrorEvent",
+    "RTCIceCandidate",
+    "RTCIceTransport",
+    "RTCPeerConnection",
+    "RTCPeerConnectionIceErrorEvent",
+    "RTCPeerConnectionIceEvent",
+    "RTCRtpReceiver",
+    "RTCRtpScriptTransform",
+    "RTCRtpSender",
+    "RTCRtpTransceiver",
+    "RTCSctpTransport",
+    "RTCSessionDescription",
+    "RTCStatsReport",
+    "RTCTrackEvent",
+    "RadioNodeList",
+    "Range",
+    "RangeError",
+    "RangeException",
+    "ReadableByteStreamController",
+    "ReadableStream",
+    "ReadableStreamBYOBReader",
+    "ReadableStreamBYOBRequest",
+    "ReadableStreamDefaultController",
+    "ReadableStreamDefaultReader",
+    "RecordErrorEvent",
+    "Rect",
+    "ReferenceError",
+    "Reflect",
+    "RegExp",
+    "RelativeOrientationSensor",
+    "RelativeTimeFormat",
+    "RemotePlayback",
+    "Report",
+    "ReportBody",
+    "ReportingObserver",
+    "Request",
+    "RequestUpdateCheckStatus",
+    "ResizeObserver",
+    "ResizeObserverEntry",
+    "ResizeObserverSize",
+    "Response",
+    "RestrictionTarget",
+    "RuntimeError",
+    "SAMPLER_2D",
+    "SAMPLER_2D_ARRAY",
+    "SAMPLER_2D_ARRAY_SHADOW",
+    "SAMPLER_2D_SHADOW",
+    "SAMPLER_3D",
+    "SAMPLER_BINDING",
+    "SAMPLER_CUBE",
+    "SAMPLER_CUBE_SHADOW",
+    "SAMPLES",
+    "SAMPLE_ALPHA_TO_COVERAGE",
+    "SAMPLE_BUFFERS",
+    "SAMPLE_COVERAGE",
+    "SAMPLE_COVERAGE_INVERT",
+    "SAMPLE_COVERAGE_VALUE",
+    "SAWTOOTH",
+    "SCHEDULED_STATE",
+    "SCISSOR_BOX",
+    "SCISSOR_TEST",
+    "SCROLL_PAGE_DOWN",
+    "SCROLL_PAGE_UP",
+    "SDP_ANSWER",
+    "SDP_OFFER",
+    "SDP_PRANSWER",
+    "SECURITY_ERR",
+    "SELECT",
+    "SEPARATE_ATTRIBS",
+    "SERIALIZE_ERR",
+    "SEVERITY_ERROR",
+    "SEVERITY_FATAL_ERROR",
+    "SEVERITY_WARNING",
+    "SHADER_COMPILER",
+    "SHADER_TYPE",
+    "SHADING_LANGUAGE_VERSION",
+    "SHIFT_MASK",
+    "SHORT",
+    "SHOWING",
+    "SHOW_ALL",
+    "SHOW_ATTRIBUTE",
+    "SHOW_CDATA_SECTION",
+    "SHOW_COMMENT",
+    "SHOW_DOCUMENT",
+    "SHOW_DOCUMENT_FRAGMENT",
+    "SHOW_DOCUMENT_TYPE",
+    "SHOW_ELEMENT",
+    "SHOW_ENTITY",
+    "SHOW_ENTITY_REFERENCE",
+    "SHOW_NOTATION",
+    "SHOW_PROCESSING_INSTRUCTION",
+    "SHOW_TEXT",
+    "SIGNALED",
+    "SIGNED_NORMALIZED",
+    "SINE",
+    "SOUNDFIELD",
+    "SQLException",
+    "SQRT1_2",
+    "SQRT2",
+    "SQUARE",
+    "SRC_ALPHA",
+    "SRC_ALPHA_SATURATE",
+    "SRC_COLOR",
+    "SRGB",
+    "SRGB8",
+    "SRGB8_ALPHA8",
+    "START_TO_END",
+    "START_TO_START",
+    "STATIC_COPY",
+    "STATIC_DRAW",
+    "STATIC_READ",
+    "STENCIL",
+    "STENCIL_ATTACHMENT",
+    "STENCIL_BACK_FAIL",
+    "STENCIL_BACK_FUNC",
+    "STENCIL_BACK_PASS_DEPTH_FAIL",
+    "STENCIL_BACK_PASS_DEPTH_PASS",
+    "STENCIL_BACK_REF",
+    "STENCIL_BACK_VALUE_MASK",
+    "STENCIL_BACK_WRITEMASK",
+    "STENCIL_BITS",
+    "STENCIL_BUFFER_BIT",
+    "STENCIL_CLEAR_VALUE",
+    "STENCIL_FAIL",
+    "STENCIL_FUNC",
+    "STENCIL_INDEX",
+    "STENCIL_INDEX8",
+    "STENCIL_PASS_DEPTH_FAIL",
+    "STENCIL_PASS_DEPTH_PASS",
+    "STENCIL_REF",
+    "STENCIL_TEST",
+    "STENCIL_VALUE_MASK",
+    "STENCIL_WRITEMASK",
+    "STORAGE",
+    "STORAGE_BINDING",
+    "STREAM_COPY",
+    "STREAM_DRAW",
+    "STREAM_READ",
+    "STRING_TYPE",
+    "STYLE_RULE",
+    "SUBPIXEL_BITS",
+    "SUPPORTS_RULE",
+    "SVGAElement",
+    "SVGAltGlyphDefElement",
+    "SVGAltGlyphElement",
+    "SVGAltGlyphItemElement",
+    "SVGAngle",
+    "SVGAnimateColorElement",
+    "SVGAnimateElement",
+    "SVGAnimateMotionElement",
+    "SVGAnimateTransformElement",
+    "SVGAnimatedAngle",
+    "SVGAnimatedBoolean",
+    "SVGAnimatedEnumeration",
+    "SVGAnimatedInteger",
+    "SVGAnimatedLength",
+    "SVGAnimatedLengthList",
+    "SVGAnimatedNumber",
+    "SVGAnimatedNumberList",
+    "SVGAnimatedPreserveAspectRatio",
+    "SVGAnimatedRect",
+    "SVGAnimatedString",
+    "SVGAnimatedTransformList",
+    "SVGAnimationElement",
+    "SVGCircleElement",
+    "SVGClipPathElement",
+    "SVGColor",
+    "SVGComponentTransferFunctionElement",
+    "SVGCursorElement",
+    "SVGDefsElement",
+    "SVGDescElement",
+    "SVGDiscardElement",
+    "SVGDocument",
+    "SVGElement",
+    "SVGElementInstance",
+    "SVGElementInstanceList",
+    "SVGEllipseElement",
+    "SVGException",
+    "SVGFEBlendElement",
+    "SVGFEColorMatrixElement",
+    "SVGFEComponentTransferElement",
+    "SVGFECompositeElement",
+    "SVGFEConvolveMatrixElement",
+    "SVGFEDiffuseLightingElement",
+    "SVGFEDisplacementMapElement",
+    "SVGFEDistantLightElement",
+    "SVGFEDropShadowElement",
+    "SVGFEFloodElement",
+    "SVGFEFuncAElement",
+    "SVGFEFuncBElement",
+    "SVGFEFuncGElement",
+    "SVGFEFuncRElement",
+    "SVGFEGaussianBlurElement",
+    "SVGFEImageElement",
+    "SVGFEMergeElement",
+    "SVGFEMergeNodeElement",
+    "SVGFEMorphologyElement",
+    "SVGFEOffsetElement",
+    "SVGFEPointLightElement",
+    "SVGFESpecularLightingElement",
+    "SVGFESpotLightElement",
+    "SVGFETileElement",
+    "SVGFETurbulenceElement",
+    "SVGFilterElement",
+    "SVGFontElement",
+    "SVGFontFaceElement",
+    "SVGFontFaceFormatElement",
+    "SVGFontFaceNameElement",
+    "SVGFontFaceSrcElement",
+    "SVGFontFaceUriElement",
+    "SVGForeignObjectElement",
+    "SVGGElement",
+    "SVGGeometryElement",
+    "SVGGlyphElement",
+    "SVGGlyphRefElement",
+    "SVGGradientElement",
+    "SVGGraphicsElement",
+    "SVGHKernElement",
+    "SVGImageElement",
+    "SVGLength",
+    "SVGLengthList",
+    "SVGLineElement",
+    "SVGLinearGradientElement",
+    "SVGMPathElement",
+    "SVGMarkerElement",
+    "SVGMaskElement",
+    "SVGMatrix",
+    "SVGMetadataElement",
+    "SVGMissingGlyphElement",
+    "SVGNumber",
+    "SVGNumberList",
+    "SVGPaint",
+    "SVGPathElement",
+    "SVGPathSeg",
+    "SVGPathSegArcAbs",
+    "SVGPathSegArcRel",
+    "SVGPathSegClosePath",
+    "SVGPathSegCurvetoCubicAbs",
+    "SVGPathSegCurvetoCubicRel",
+    "SVGPathSegCurvetoCubicSmoothAbs",
+    "SVGPathSegCurvetoCubicSmoothRel",
+    "SVGPathSegCurvetoQuadraticAbs",
+    "SVGPathSegCurvetoQuadraticRel",
+    "SVGPathSegCurvetoQuadraticSmoothAbs",
+    "SVGPathSegCurvetoQuadraticSmoothRel",
+    "SVGPathSegLinetoAbs",
+    "SVGPathSegLinetoHorizontalAbs",
+    "SVGPathSegLinetoHorizontalRel",
+    "SVGPathSegLinetoRel",
+    "SVGPathSegLinetoVerticalAbs",
+    "SVGPathSegLinetoVerticalRel",
+    "SVGPathSegList",
+    "SVGPathSegMovetoAbs",
+    "SVGPathSegMovetoRel",
+    "SVGPatternElement",
+    "SVGPoint",
+    "SVGPointList",
+    "SVGPolygonElement",
+    "SVGPolylineElement",
+    "SVGPreserveAspectRatio",
+    "SVGRadialGradientElement",
+    "SVGRect",
+    "SVGRectElement",
+    "SVGRenderingIntent",
+    "SVGSVGElement",
+    "SVGScriptElement",
+    "SVGSetElement",
+    "SVGStopElement",
+    "SVGStringList",
+    "SVGStyleElement",
+    "SVGSwitchElement",
+    "SVGSymbolElement",
+    "SVGTRefElement",
+    "SVGTSpanElement",
+    "SVGTextContentElement",
+    "SVGTextElement",
+    "SVGTextPathElement",
+    "SVGTextPositioningElement",
+    "SVGTitleElement",
+    "SVGTransform",
+    "SVGTransformList",
+    "SVGUnitTypes",
+    "SVGUseElement",
+    "SVGVKernElement",
+    "SVGViewElement",
+    "SVGViewSpec",
+    "SVGZoomAndPan",
+    "SVGZoomEvent",
+    "SVG_ANGLETYPE_DEG",
+    "SVG_ANGLETYPE_GRAD",
+    "SVG_ANGLETYPE_RAD",
+    "SVG_ANGLETYPE_UNKNOWN",
+    "SVG_ANGLETYPE_UNSPECIFIED",
+    "SVG_CHANNEL_A",
+    "SVG_CHANNEL_B",
+    "SVG_CHANNEL_G",
+    "SVG_CHANNEL_R",
+    "SVG_CHANNEL_UNKNOWN",
+    "SVG_COLORTYPE_CURRENTCOLOR",
+    "SVG_COLORTYPE_RGBCOLOR",
+    "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR",
+    "SVG_COLORTYPE_UNKNOWN",
+    "SVG_EDGEMODE_DUPLICATE",
+    "SVG_EDGEMODE_NONE",
+    "SVG_EDGEMODE_UNKNOWN",
+    "SVG_EDGEMODE_WRAP",
+    "SVG_FEBLEND_MODE_COLOR",
+    "SVG_FEBLEND_MODE_COLOR_BURN",
+    "SVG_FEBLEND_MODE_COLOR_DODGE",
+    "SVG_FEBLEND_MODE_DARKEN",
+    "SVG_FEBLEND_MODE_DIFFERENCE",
+    "SVG_FEBLEND_MODE_EXCLUSION",
+    "SVG_FEBLEND_MODE_HARD_LIGHT",
+    "SVG_FEBLEND_MODE_HUE",
+    "SVG_FEBLEND_MODE_LIGHTEN",
+    "SVG_FEBLEND_MODE_LUMINOSITY",
+    "SVG_FEBLEND_MODE_MULTIPLY",
+    "SVG_FEBLEND_MODE_NORMAL",
+    "SVG_FEBLEND_MODE_OVERLAY",
+    "SVG_FEBLEND_MODE_SATURATION",
+    "SVG_FEBLEND_MODE_SCREEN",
+    "SVG_FEBLEND_MODE_SOFT_LIGHT",
+    "SVG_FEBLEND_MODE_UNKNOWN",
+    "SVG_FECOLORMATRIX_TYPE_HUEROTATE",
+    "SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA",
+    "SVG_FECOLORMATRIX_TYPE_MATRIX",
+    "SVG_FECOLORMATRIX_TYPE_SATURATE",
+    "SVG_FECOLORMATRIX_TYPE_UNKNOWN",
+    "SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE",
+    "SVG_FECOMPONENTTRANSFER_TYPE_GAMMA",
+    "SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY",
+    "SVG_FECOMPONENTTRANSFER_TYPE_LINEAR",
+    "SVG_FECOMPONENTTRANSFER_TYPE_TABLE",
+    "SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN",
+    "SVG_FECOMPOSITE_OPERATOR_ARITHMETIC",
+    "SVG_FECOMPOSITE_OPERATOR_ATOP",
+    "SVG_FECOMPOSITE_OPERATOR_IN",
+    "SVG_FECOMPOSITE_OPERATOR_LIGHTER",
+    "SVG_FECOMPOSITE_OPERATOR_OUT",
+    "SVG_FECOMPOSITE_OPERATOR_OVER",
+    "SVG_FECOMPOSITE_OPERATOR_UNKNOWN",
+    "SVG_FECOMPOSITE_OPERATOR_XOR",
+    "SVG_INVALID_VALUE_ERR",
+    "SVG_LENGTHTYPE_CM",
+    "SVG_LENGTHTYPE_EMS",
+    "SVG_LENGTHTYPE_EXS",
+    "SVG_LENGTHTYPE_IN",
+    "SVG_LENGTHTYPE_MM",
+    "SVG_LENGTHTYPE_NUMBER",
+    "SVG_LENGTHTYPE_PC",
+    "SVG_LENGTHTYPE_PERCENTAGE",
+    "SVG_LENGTHTYPE_PT",
+    "SVG_LENGTHTYPE_PX",
+    "SVG_LENGTHTYPE_UNKNOWN",
+    "SVG_MARKERUNITS_STROKEWIDTH",
+    "SVG_MARKERUNITS_UNKNOWN",
+    "SVG_MARKERUNITS_USERSPACEONUSE",
+    "SVG_MARKER_ORIENT_ANGLE",
+    "SVG_MARKER_ORIENT_AUTO",
+    "SVG_MARKER_ORIENT_AUTO_START_REVERSE",
+    "SVG_MARKER_ORIENT_UNKNOWN",
+    "SVG_MASKTYPE_ALPHA",
+    "SVG_MASKTYPE_LUMINANCE",
+    "SVG_MATRIX_NOT_INVERTABLE",
+    "SVG_MEETORSLICE_MEET",
+    "SVG_MEETORSLICE_SLICE",
+    "SVG_MEETORSLICE_UNKNOWN",
+    "SVG_MORPHOLOGY_OPERATOR_DILATE",
+    "SVG_MORPHOLOGY_OPERATOR_ERODE",
+    "SVG_MORPHOLOGY_OPERATOR_UNKNOWN",
+    "SVG_PAINTTYPE_CURRENTCOLOR",
+    "SVG_PAINTTYPE_NONE",
+    "SVG_PAINTTYPE_RGBCOLOR",
+    "SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR",
+    "SVG_PAINTTYPE_UNKNOWN",
+    "SVG_PAINTTYPE_URI",
+    "SVG_PAINTTYPE_URI_CURRENTCOLOR",
+    "SVG_PAINTTYPE_URI_NONE",
+    "SVG_PAINTTYPE_URI_RGBCOLOR",
+    "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR",
+    "SVG_PRESERVEASPECTRATIO_NONE",
+    "SVG_PRESERVEASPECTRATIO_UNKNOWN",
+    "SVG_PRESERVEASPECTRATIO_XMAXYMAX",
+    "SVG_PRESERVEASPECTRATIO_XMAXYMID",
+    "SVG_PRESERVEASPECTRATIO_XMAXYMIN",
+    "SVG_PRESERVEASPECTRATIO_XMIDYMAX",
+    "SVG_PRESERVEASPECTRATIO_XMIDYMID",
+    "SVG_PRESERVEASPECTRATIO_XMIDYMIN",
+    "SVG_PRESERVEASPECTRATIO_XMINYMAX",
+    "SVG_PRESERVEASPECTRATIO_XMINYMID",
+    "SVG_PRESERVEASPECTRATIO_XMINYMIN",
+    "SVG_SPREADMETHOD_PAD",
+    "SVG_SPREADMETHOD_REFLECT",
+    "SVG_SPREADMETHOD_REPEAT",
+    "SVG_SPREADMETHOD_UNKNOWN",
+    "SVG_STITCHTYPE_NOSTITCH",
+    "SVG_STITCHTYPE_STITCH",
+    "SVG_STITCHTYPE_UNKNOWN",
+    "SVG_TRANSFORM_MATRIX",
+    "SVG_TRANSFORM_ROTATE",
+    "SVG_TRANSFORM_SCALE",
+    "SVG_TRANSFORM_SKEWX",
+    "SVG_TRANSFORM_SKEWY",
+    "SVG_TRANSFORM_TRANSLATE",
+    "SVG_TRANSFORM_UNKNOWN",
+    "SVG_TURBULENCE_TYPE_FRACTALNOISE",
+    "SVG_TURBULENCE_TYPE_TURBULENCE",
+    "SVG_TURBULENCE_TYPE_UNKNOWN",
+    "SVG_UNIT_TYPE_OBJECTBOUNDINGBOX",
+    "SVG_UNIT_TYPE_UNKNOWN",
+    "SVG_UNIT_TYPE_USERSPACEONUSE",
+    "SVG_WRONG_TYPE_ERR",
+    "SVG_ZOOMANDPAN_DISABLE",
+    "SVG_ZOOMANDPAN_MAGNIFY",
+    "SVG_ZOOMANDPAN_UNKNOWN",
+    "SYNC_CONDITION",
+    "SYNC_FENCE",
+    "SYNC_FLAGS",
+    "SYNC_FLUSH_COMMANDS_BIT",
+    "SYNC_GPU_COMMANDS_COMPLETE",
+    "SYNC_STATUS",
+    "SYNTAX_ERR",
+    "SavedPages",
+    "Scheduler",
+    "Scheduling",
+    "Screen",
+    "ScreenDetailed",
+    "ScreenDetails",
+    "ScreenOrientation",
+    "Script",
+    "ScriptProcessorNode",
+    "ScrollAreaEvent",
+    "ScrollTimeline",
+    "SecurityPolicyViolationEvent",
+    "Segmenter",
+    "Selection",
+    "Sensor",
+    "SensorErrorEvent",
+    "Serial",
+    "SerialPort",
+    "ServiceWorker",
+    "ServiceWorkerContainer",
+    "ServiceWorkerRegistration",
+    "SessionDescription",
+    "Set",
+    "ShadowRoot",
+    "SharedArrayBuffer",
+    "SharedStorage",
+    "SharedStorageAppendMethod",
+    "SharedStorageClearMethod",
+    "SharedStorageDeleteMethod",
+    "SharedStorageModifierMethod",
+    "SharedStorageSetMethod",
+    "SharedStorageWorklet",
+    "SharedWorker",
+    "SharingState",
+    "SimpleGestureEvent",
+    "SnapEvent",
+    "SourceBuffer",
+    "SourceBufferList",
+    "SpeechGrammar",
+    "SpeechGrammarList",
+    "SpeechRecognition",
+    "SpeechRecognitionErrorEvent",
+    "SpeechRecognitionEvent",
+    "SpeechRecognitionPhrase",
+    "SpeechSynthesis",
+    "SpeechSynthesisErrorEvent",
+    "SpeechSynthesisEvent",
+    "SpeechSynthesisUtterance",
+    "SpeechSynthesisVoice",
+    "StaticRange",
+    "StereoPannerNode",
+    "StopIteration",
+    "Storage",
+    "StorageBucket",
+    "StorageBucketManager",
+    "StorageEvent",
+    "StorageManager",
+    "String",
+    "StructType",
+    "StylePropertyMap",
+    "StylePropertyMapReadOnly",
+    "StyleSheet",
+    "StyleSheetList",
+    "SubmitEvent",
+    "Subscriber",
+    "SubtleCrypto",
+    "Summarizer",
+    "SuppressedError",
+    "SuspendError",
+    "Suspending",
+    "Symbol",
+    "SyncManager",
+    "SyntaxError",
+    "TAB_ID_NONE",
+    "TAB_INDEX_NONE",
+    "TEMPORARY",
+    "TEXTPATH_METHODTYPE_ALIGN",
+    "TEXTPATH_METHODTYPE_STRETCH",
+    "TEXTPATH_METHODTYPE_UNKNOWN",
+    "TEXTPATH_SPACINGTYPE_AUTO",
+    "TEXTPATH_SPACINGTYPE_EXACT",
+    "TEXTPATH_SPACINGTYPE_UNKNOWN",
+    "TEXTURE",
+    "TEXTURE0",
+    "TEXTURE1",
+    "TEXTURE10",
+    "TEXTURE11",
+    "TEXTURE12",
+    "TEXTURE13",
+    "TEXTURE14",
+    "TEXTURE15",
+    "TEXTURE16",
+    "TEXTURE17",
+    "TEXTURE18",
+    "TEXTURE19",
+    "TEXTURE2",
+    "TEXTURE20",
+    "TEXTURE21",
+    "TEXTURE22",
+    "TEXTURE23",
+    "TEXTURE24",
+    "TEXTURE25",
+    "TEXTURE26",
+    "TEXTURE27",
+    "TEXTURE28",
+    "TEXTURE29",
+    "TEXTURE3",
+    "TEXTURE30",
+    "TEXTURE31",
+    "TEXTURE4",
+    "TEXTURE5",
+    "TEXTURE6",
+    "TEXTURE7",
+    "TEXTURE8",
+    "TEXTURE9",
+    "TEXTURE_2D",
+    "TEXTURE_2D_ARRAY",
+    "TEXTURE_3D",
+    "TEXTURE_BASE_LEVEL",
+    "TEXTURE_BINDING",
+    "TEXTURE_BINDING_2D",
+    "TEXTURE_BINDING_2D_ARRAY",
+    "TEXTURE_BINDING_3D",
+    "TEXTURE_BINDING_CUBE_MAP",
+    "TEXTURE_COMPARE_FUNC",
+    "TEXTURE_COMPARE_MODE",
+    "TEXTURE_CUBE_MAP",
+    "TEXTURE_CUBE_MAP_NEGATIVE_X",
+    "TEXTURE_CUBE_MAP_NEGATIVE_Y",
+    "TEXTURE_CUBE_MAP_NEGATIVE_Z",
+    "TEXTURE_CUBE_MAP_POSITIVE_X",
+    "TEXTURE_CUBE_MAP_POSITIVE_Y",
+    "TEXTURE_CUBE_MAP_POSITIVE_Z",
+    "TEXTURE_IMMUTABLE_FORMAT",
+    "TEXTURE_IMMUTABLE_LEVELS",
+    "TEXTURE_MAG_FILTER",
+    "TEXTURE_MAX_ANISOTROPY_EXT",
+    "TEXTURE_MAX_LEVEL",
+    "TEXTURE_MAX_LOD",
+    "TEXTURE_MIN_FILTER",
+    "TEXTURE_MIN_LOD",
+    "TEXTURE_WRAP_R",
+    "TEXTURE_WRAP_S",
+    "TEXTURE_WRAP_T",
+    "TEXT_NODE",
+    "TIMEOUT",
+    "TIMEOUT_ERR",
+    "TIMEOUT_EXPIRED",
+    "TIMEOUT_IGNORED",
+    "TOO_LARGE_ERR",
+    "TRANSACTION_INACTIVE_ERR",
+    "TRANSFORM_FEEDBACK",
+    "TRANSFORM_FEEDBACK_ACTIVE",
+    "TRANSFORM_FEEDBACK_BINDING",
+    "TRANSFORM_FEEDBACK_BUFFER",
+    "TRANSFORM_FEEDBACK_BUFFER_BINDING",
+    "TRANSFORM_FEEDBACK_BUFFER_MODE",
+    "TRANSFORM_FEEDBACK_BUFFER_SIZE",
+    "TRANSFORM_FEEDBACK_BUFFER_START",
+    "TRANSFORM_FEEDBACK_PAUSED",
+    "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN",
+    "TRANSFORM_FEEDBACK_VARYINGS",
+    "TRIANGLE",
+    "TRIANGLES",
+    "TRIANGLE_FAN",
+    "TRIANGLE_STRIP",
+    "TYPE_BACK_FORWARD",
+    "TYPE_ERR",
+    "TYPE_MISMATCH_ERR",
+    "TYPE_NAVIGATE",
+    "TYPE_RELOAD",
+    "TYPE_RESERVED",
+    "Tab",
+    "TabStatus",
+    "Table",
+    "Tag",
+    "TaskAttributionTiming",
+    "TaskController",
+    "TaskPriorityChangeEvent",
+    "TaskSignal",
+    "Temporal",
+    "Text",
+    "TextDecoder",
+    "TextDecoderStream",
+    "TextEncoder",
+    "TextEncoderStream",
+    "TextEvent",
+    "TextFormat",
+    "TextFormatUpdateEvent",
+    "TextMetrics",
+    "TextTrack",
+    "TextTrackCue",
+    "TextTrackCueList",
+    "TextTrackList",
+    "TextUpdateEvent",
+    "TimeEvent",
+    "TimeRanges",
+    "ToggleEvent",
+    "Touch",
+    "TouchEvent",
+    "TouchList",
+    "TrackEvent",
+    "TransformStream",
+    "TransformStreamDefaultController",
+    "TransitionEvent",
+    "Translator",
+    "TreeWalker",
+    "TrustedHTML",
+    "TrustedScript",
+    "TrustedScriptURL",
+    "TrustedTypePolicy",
+    "TrustedTypePolicyFactory",
+    "TypeError",
+    "TypedObject",
+    "U2F",
+    "UIEvent",
+    "UNCACHED",
+    "UNIFORM",
+    "UNIFORM_ARRAY_STRIDE",
+    "UNIFORM_BLOCK_ACTIVE_UNIFORMS",
+    "UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES",
+    "UNIFORM_BLOCK_BINDING",
+    "UNIFORM_BLOCK_DATA_SIZE",
+    "UNIFORM_BLOCK_INDEX",
+    "UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER",
+    "UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER",
+    "UNIFORM_BUFFER",
+    "UNIFORM_BUFFER_BINDING",
+    "UNIFORM_BUFFER_OFFSET_ALIGNMENT",
+    "UNIFORM_BUFFER_SIZE",
+    "UNIFORM_BUFFER_START",
+    "UNIFORM_IS_ROW_MAJOR",
+    "UNIFORM_MATRIX_STRIDE",
+    "UNIFORM_OFFSET",
+    "UNIFORM_SIZE",
+    "UNIFORM_TYPE",
+    "UNKNOWN_ERR",
+    "UNKNOWN_RULE",
+    "UNMASKED_RENDERER_WEBGL",
+    "UNMASKED_VENDOR_WEBGL",
+    "UNORDERED_NODE_ITERATOR_TYPE",
+    "UNORDERED_NODE_SNAPSHOT_TYPE",
+    "UNPACK_ALIGNMENT",
+    "UNPACK_COLORSPACE_CONVERSION_WEBGL",
+    "UNPACK_FLIP_Y_WEBGL",
+    "UNPACK_IMAGE_HEIGHT",
+    "UNPACK_PREMULTIPLY_ALPHA_WEBGL",
+    "UNPACK_ROW_LENGTH",
+    "UNPACK_SKIP_IMAGES",
+    "UNPACK_SKIP_PIXELS",
+    "UNPACK_SKIP_ROWS",
+    "UNSCHEDULED_STATE",
+    "UNSENT",
+    "UNSIGNALED",
+    "UNSIGNED_BYTE",
+    "UNSIGNED_INT",
+    "UNSIGNED_INT_10F_11F_11F_REV",
+    "UNSIGNED_INT_24_8",
+    "UNSIGNED_INT_2_10_10_10_REV",
+    "UNSIGNED_INT_5_9_9_9_REV",
+    "UNSIGNED_INT_SAMPLER_2D",
+    "UNSIGNED_INT_SAMPLER_2D_ARRAY",
+    "UNSIGNED_INT_SAMPLER_3D",
+    "UNSIGNED_INT_SAMPLER_CUBE",
+    "UNSIGNED_INT_VEC2",
+    "UNSIGNED_INT_VEC3",
+    "UNSIGNED_INT_VEC4",
+    "UNSIGNED_NORMALIZED",
+    "UNSIGNED_SHORT",
+    "UNSIGNED_SHORT_4_4_4_4",
+    "UNSIGNED_SHORT_5_5_5_1",
+    "UNSIGNED_SHORT_5_6_5",
+    "UNSPECIFIED_EVENT_TYPE_ERR",
+    "UPDATEREADY",
+    "URIError",
+    "URL",
+    "URLPattern",
+    "URLSearchParams",
+    "URLUnencoded",
+    "URL_MISMATCH_ERR",
+    "USB",
+    "USBAlternateInterface",
+    "USBConfiguration",
+    "USBConnectionEvent",
+    "USBDevice",
+    "USBEndpoint",
+    "USBInTransferResult",
+    "USBInterface",
+    "USBIsochronousInTransferPacket",
+    "USBIsochronousInTransferResult",
+    "USBIsochronousOutTransferPacket",
+    "USBIsochronousOutTransferResult",
+    "USBOutTransferResult",
+    "UTC",
+    "Uint16Array",
+    "Uint32Array",
+    "Uint8Array",
+    "Uint8ClampedArray",
+    "UpdateFilter",
+    "UpdatePropertyName",
+    "UserActivation",
+    "UserMessageHandler",
+    "UserMessageHandlersNamespace",
+    "UserProximityEvent",
+    "VALIDATE_STATUS",
+    "VALIDATION_ERR",
+    "VARIABLES_RULE",
+    "VENDOR",
+    "VERSION",
+    "VERSION_CHANGE",
+    "VERSION_ERR",
+    "VERTEX",
+    "VERTEX_ARRAY_BINDING",
+    "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING",
+    "VERTEX_ATTRIB_ARRAY_DIVISOR",
+    "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE",
+    "VERTEX_ATTRIB_ARRAY_ENABLED",
+    "VERTEX_ATTRIB_ARRAY_INTEGER",
+    "VERTEX_ATTRIB_ARRAY_NORMALIZED",
+    "VERTEX_ATTRIB_ARRAY_POINTER",
+    "VERTEX_ATTRIB_ARRAY_SIZE",
+    "VERTEX_ATTRIB_ARRAY_STRIDE",
+    "VERTEX_ATTRIB_ARRAY_TYPE",
+    "VERTEX_SHADER",
+    "VERTICAL",
+    "VERTICAL_AXIS",
+    "VER_ERR",
+    "VIEWPORT",
+    "VIEWPORT_RULE",
+    "VRDisplay",
+    "VRDisplayCapabilities",
+    "VRDisplayEvent",
+    "VREyeParameters",
+    "VRFieldOfView",
+    "VRFrameData",
+    "VRPose",
+    "VRStageParameters",
+    "VTTCue",
+    "VTTRegion",
+    "ValidityState",
+    "VideoColorSpace",
+    "VideoDecoder",
+    "VideoEncoder",
+    "VideoFrame",
+    "VideoPlaybackQuality",
+    "VideoStreamTrack",
+    "ViewTimeline",
+    "ViewTransition",
+    "ViewTransitionTypeSet",
+    "ViewType",
+    "Viewport",
+    "VirtualKeyboard",
+    "VirtualKeyboardGeometryChangeEvent",
+    "VisibilityStateEntry",
+    "VisualViewport",
+    "WAIT_FAILED",
+    "WEBKIT_FILTER_RULE",
+    "WEBKIT_KEYFRAMES_RULE",
+    "WEBKIT_KEYFRAME_RULE",
+    "WEBKIT_REGION_RULE",
+    "WGSLLanguageFeatures",
+    "WINDOW_ID_CURRENT",
+    "WINDOW_ID_NONE",
+    "WRITE",
+    "WRONG_DOCUMENT_ERR",
+    "WakeLock",
+    "WakeLockSentinel",
+    "WasmAnyRef",
+    "WaveShaperNode",
+    "WeakMap",
+    "WeakRef",
+    "WeakSet",
+    "WebAssembly",
+    "WebGL2RenderingContext",
+    "WebGLActiveInfo",
+    "WebGLBuffer",
+    "WebGLContextEvent",
+    "WebGLFramebuffer",
+    "WebGLObject",
+    "WebGLProgram",
+    "WebGLQuery",
+    "WebGLRenderbuffer",
+    "WebGLRenderingContext",
+    "WebGLSampler",
+    "WebGLShader",
+    "WebGLShaderPrecisionFormat",
+    "WebGLSync",
+    "WebGLTexture",
+    "WebGLTransformFeedback",
+    "WebGLUniformLocation",
+    "WebGLVertexArray",
+    "WebGLVertexArrayObject",
+    "WebKitAnimationEvent",
+    "WebKitBlobBuilder",
+    "WebKitCSSFilterRule",
+    "WebKitCSSFilterValue",
+    "WebKitCSSKeyframeRule",
+    "WebKitCSSKeyframesRule",
+    "WebKitCSSMatrix",
+    "WebKitCSSRegionRule",
+    "WebKitCSSTransformValue",
+    "WebKitDataCue",
+    "WebKitGamepad",
+    "WebKitMediaKeyError",
+    "WebKitMediaKeyMessageEvent",
+    "WebKitMediaKeySession",
+    "WebKitMediaKeys",
+    "WebKitMediaSource",
+    "WebKitMutationObserver",
+    "WebKitNamespace",
+    "WebKitPlaybackTargetAvailabilityEvent",
+    "WebKitPoint",
+    "WebKitShadowRoot",
+    "WebKitSourceBuffer",
+    "WebKitSourceBufferList",
+    "WebKitTransitionEvent",
+    "WebSocket",
+    "WebSocketError",
+    "WebSocketStream",
+    "WebTransport",
+    "WebTransportBidirectionalStream",
+    "WebTransportDatagramDuplexStream",
+    "WebTransportError",
+    "WebTransportReceiveStream",
+    "WebTransportSendStream",
+    "WebkitAlignContent",
+    "WebkitAlignItems",
+    "WebkitAlignSelf",
+    "WebkitAnimation",
+    "WebkitAnimationDelay",
+    "WebkitAnimationDirection",
+    "WebkitAnimationDuration",
+    "WebkitAnimationFillMode",
+    "WebkitAnimationIterationCount",
+    "WebkitAnimationName",
+    "WebkitAnimationPlayState",
+    "WebkitAnimationTimingFunction",
+    "WebkitAppearance",
+    "WebkitBackfaceVisibility",
+    "WebkitBackgroundClip",
+    "WebkitBackgroundOrigin",
+    "WebkitBackgroundSize",
+    "WebkitBorderBottomLeftRadius",
+    "WebkitBorderBottomRightRadius",
+    "WebkitBorderImage",
+    "WebkitBorderRadius",
+    "WebkitBorderTopLeftRadius",
+    "WebkitBorderTopRightRadius",
+    "WebkitBoxAlign",
+    "WebkitBoxDirection",
+    "WebkitBoxFlex",
+    "WebkitBoxOrdinalGroup",
+    "WebkitBoxOrient",
+    "WebkitBoxPack",
+    "WebkitBoxShadow",
+    "WebkitBoxSizing",
+    "WebkitClipPath",
+    "WebkitFilter",
+    "WebkitFlex",
+    "WebkitFlexBasis",
+    "WebkitFlexDirection",
+    "WebkitFlexFlow",
+    "WebkitFlexGrow",
+    "WebkitFlexShrink",
+    "WebkitFlexWrap",
+    "WebkitFontFeatureSettings",
+    "WebkitJustifyContent",
+    "WebkitLineClamp",
+    "WebkitMask",
+    "WebkitMaskClip",
+    "WebkitMaskComposite",
+    "WebkitMaskImage",
+    "WebkitMaskOrigin",
+    "WebkitMaskPosition",
+    "WebkitMaskPositionX",
+    "WebkitMaskPositionY",
+    "WebkitMaskRepeat",
+    "WebkitMaskSize",
+    "WebkitOrder",
+    "WebkitPerspective",
+    "WebkitPerspectiveOrigin",
+    "WebkitTextFillColor",
+    "WebkitTextSecurity",
+    "WebkitTextSizeAdjust",
+    "WebkitTextStroke",
+    "WebkitTextStrokeColor",
+    "WebkitTextStrokeWidth",
+    "WebkitTransform",
+    "WebkitTransformOrigin",
+    "WebkitTransformStyle",
+    "WebkitTransition",
+    "WebkitTransitionDelay",
+    "WebkitTransitionDuration",
+    "WebkitTransitionProperty",
+    "WebkitTransitionTimingFunction",
+    "WebkitUserSelect",
+    "WheelEvent",
+    "Window",
+    "WindowControlsOverlay",
+    "WindowControlsOverlayGeometryChangeEvent",
+    "WindowState",
+    "WindowType",
+    "Worker",
+    "Worklet",
+    "WritableStream",
+    "WritableStreamDefaultController",
+    "WritableStreamDefaultWriter",
+    "XMLDocument",
+    "XMLHttpRequest",
+    "XMLHttpRequestEventTarget",
+    "XMLHttpRequestException",
+    "XMLHttpRequestProgressEvent",
+    "XMLHttpRequestUpload",
+    "XMLSerializer",
+    "XMLStylesheetProcessingInstruction",
+    "XPathEvaluator",
+    "XPathException",
+    "XPathExpression",
+    "XPathNSResolver",
+    "XPathResult",
+    "XRAnchor",
+    "XRAnchorSet",
+    "XRBoundedReferenceSpace",
+    "XRCPUDepthInformation",
+    "XRCamera",
+    "XRDOMOverlayState",
+    "XRDepthInformation",
+    "XRFrame",
+    "XRHand",
+    "XRHitTestResult",
+    "XRHitTestSource",
+    "XRInputSource",
+    "XRInputSourceArray",
+    "XRInputSourceEvent",
+    "XRInputSourcesChangeEvent",
+    "XRJointPose",
+    "XRJointSpace",
+    "XRLayer",
+    "XRLightEstimate",
+    "XRLightProbe",
+    "XRPose",
+    "XRRay",
+    "XRReferenceSpace",
+    "XRReferenceSpaceEvent",
+    "XRRenderState",
+    "XRRigidTransform",
+    "XRSession",
+    "XRSessionEvent",
+    "XRSpace",
+    "XRSystem",
+    "XRTransientInputHitTestResult",
+    "XRTransientInputHitTestSource",
+    "XRView",
+    "XRViewerPose",
+    "XRViewport",
+    "XRWebGLBinding",
+    "XRWebGLDepthInformation",
+    "XRWebGLLayer",
+    "XSLTProcessor",
+    "ZERO",
+    "ZonedDateTime",
+    "ZoomSettings",
+    "ZoomSettingsMode",
+    "ZoomSettingsScope",
+    "_XD0M_",
+    "_YD0M_",
+    "__REACT_DEVTOOLS_GLOBAL_HOOK__",
+    "__brand",
+    "__defineGetter__",
+    "__defineSetter__",
+    "__lookupGetter__",
+    "__lookupSetter__",
+    "__opera",
+    "__proto__",
+    "_browserjsran",
+    "a",
+    "aLink",
+    "abbr",
+    "abort",
+    "aborted",
+    "aboutConfigPrefs",
+    "abs",
+    "absolute",
+    "acceleration",
+    "accelerationIncludingGravity",
+    "accelerator",
+    "accent-color",
+    "accentColor",
+    "accept",
+    "acceptCharset",
+    "acceptNode",
+    "access",
+    "accessKey",
+    "accessKeyLabel",
+    "accuracy",
+    "acos",
+    "acosh",
+    "action",
+    "actionURL",
+    "actions",
+    "activated",
+    "activation",
+    "activationStart",
+    "active",
+    "activeCues",
+    "activeElement",
+    "activeSourceBuffers",
+    "activeSourceCount",
+    "activeTexture",
+    "activeVRDisplays",
+    "activeViewTransition",
+    "activityLog",
+    "actualBoundingBoxAscent",
+    "actualBoundingBoxDescent",
+    "actualBoundingBoxLeft",
+    "actualBoundingBoxRight",
+    "adAuctionComponents",
+    "adAuctionHeaders",
+    "adapterInfo",
+    "add",
+    "addAll",
+    "addBehavior",
+    "addCandidate",
+    "addColorStop",
+    "addCue",
+    "addElement",
+    "addEventListener",
+    "addFilter",
+    "addFromString",
+    "addFromUri",
+    "addIceCandidate",
+    "addImport",
+    "addListener",
+    "addModule",
+    "addNamed",
+    "addPageRule",
+    "addPath",
+    "addPointer",
+    "addRange",
+    "addRegion",
+    "addRule",
+    "addSearchEngine",
+    "addSourceBuffer",
+    "addStream",
+    "addTeardown",
+    "addTextTrack",
+    "addTrack",
+    "addTransceiver",
+    "addWakeLockListener",
+    "added",
+    "addedNodes",
+    "additionalName",
+    "additiveSymbols",
+    "addons",
+    "address",
+    "addressLine",
+    "addressModeU",
+    "addressModeV",
+    "addressModeW",
+    "adopt",
+    "adoptNode",
+    "adoptedCallback",
+    "adoptedStyleSheets",
+    "adr",
+    "advance",
+    "after",
+    "alarms",
+    "album",
+    "alert",
+    "algorithm",
+    "align",
+    "align-content",
+    "align-items",
+    "align-self",
+    "alignContent",
+    "alignItems",
+    "alignSelf",
+    "alignmentBaseline",
+    "alinkColor",
+    "all",
+    "allSettled",
+    "allocationSize",
+    "allow",
+    "allowFullscreen",
+    "allowPaymentRequest",
+    "allowedDirections",
+    "allowedFeatures",
+    "allowedToPlay",
+    "allowsFeature",
+    "alpha",
+    "alphaMode",
+    "alphaToCoverageEnabled",
+    "alphabeticBaseline",
+    "alt",
+    "altGraphKey",
+    "altHtml",
+    "altKey",
+    "altLeft",
+    "alternate",
+    "alternateSetting",
+    "alternates",
+    "altitude",
+    "altitudeAccuracy",
+    "altitudeAngle",
+    "amplitude",
+    "ancestorOrigins",
+    "anchor",
+    "anchorName",
+    "anchorNode",
+    "anchorOffset",
+    "anchorScope",
+    "anchorSpace",
+    "anchors",
+    "and",
+    "angle",
+    "angularAcceleration",
+    "angularVelocity",
+    "animVal",
+    "animate",
+    "animated",
+    "animatedInstanceRoot",
+    "animatedNormalizedPathSegList",
+    "animatedPathSegList",
+    "animatedPoints",
+    "animation",
+    "animation-composition",
+    "animation-delay",
+    "animation-direction",
+    "animation-duration",
+    "animation-fill-mode",
+    "animation-iteration-count",
+    "animation-name",
+    "animation-play-state",
+    "animation-timing-function",
+    "animationComposition",
+    "animationDelay",
+    "animationDirection",
+    "animationDuration",
+    "animationFillMode",
+    "animationIterationCount",
+    "animationName",
+    "animationPlayState",
+    "animationStartTime",
+    "animationTimingFunction",
+    "animationsPaused",
+    "anniversary",
+    "annotation",
+    "antialias",
+    "anticipatedRemoval",
+    "any",
+    "app",
+    "appCodeName",
+    "appMinorVersion",
+    "appName",
+    "appNotifications",
+    "appVersion",
+    "appearance",
+    "append",
+    "appendBuffer",
+    "appendChild",
+    "appendData",
+    "appendItem",
+    "appendMedium",
+    "appendNamed",
+    "appendRule",
+    "appendStream",
+    "appendWindowEnd",
+    "appendWindowStart",
+    "applets",
+    "applicationCache",
+    "applicationServerKey",
+    "apply",
+    "applyConstraints",
+    "applyElement",
+    "arc",
+    "arcTo",
+    "arch",
+    "architecture",
+    "archive",
+    "areas",
+    "arguments",
+    "ariaActiveDescendantElement",
+    "ariaAtomic",
+    "ariaAutoComplete",
+    "ariaBrailleLabel",
+    "ariaBrailleRoleDescription",
+    "ariaBusy",
+    "ariaChecked",
+    "ariaColCount",
+    "ariaColIndex",
+    "ariaColIndexText",
+    "ariaColSpan",
+    "ariaControlsElements",
+    "ariaCurrent",
+    "ariaDescribedByElements",
+    "ariaDescription",
+    "ariaDetailsElements",
+    "ariaDisabled",
+    "ariaErrorMessageElements",
+    "ariaExpanded",
+    "ariaFlowToElements",
+    "ariaHasPopup",
+    "ariaHidden",
+    "ariaInvalid",
+    "ariaKeyShortcuts",
+    "ariaLabel",
+    "ariaLabelledByElements",
+    "ariaLevel",
+    "ariaLive",
+    "ariaModal",
+    "ariaMultiLine",
+    "ariaMultiSelectable",
+    "ariaNotify",
+    "ariaOrientation",
+    "ariaOwnsElements",
+    "ariaPlaceholder",
+    "ariaPosInSet",
+    "ariaPressed",
+    "ariaReadOnly",
+    "ariaRelevant",
+    "ariaRequired",
+    "ariaRoleDescription",
+    "ariaRowCount",
+    "ariaRowIndex",
+    "ariaRowIndexText",
+    "ariaRowSpan",
+    "ariaSelected",
+    "ariaSetSize",
+    "ariaSort",
+    "ariaValueMax",
+    "ariaValueMin",
+    "ariaValueNow",
+    "ariaValueText",
+    "arrayBuffer",
+    "arrayLayerCount",
+    "arrayStride",
+    "artist",
+    "artwork",
+    "as",
+    "asIntN",
+    "asUintN",
+    "ascentOverride",
+    "asin",
+    "asinh",
+    "aspect",
+    "aspect-ratio",
+    "aspectRatio",
+    "assert",
+    "assign",
+    "assignedElements",
+    "assignedNodes",
+    "assignedSlot",
+    "async",
+    "asyncDispose",
+    "asyncIterator",
+    "at",
+    "atEnd",
+    "atan",
+    "atan2",
+    "atanh",
+    "atob",
+    "attachEvent",
+    "attachInternals",
+    "attachShader",
+    "attachShadow",
+    "attachedElements",
+    "attachments",
+    "attack",
+    "attestationObject",
+    "attrChange",
+    "attrName",
+    "attributeChangedCallback",
+    "attributeFilter",
+    "attributeName",
+    "attributeNamespace",
+    "attributeOldValue",
+    "attributeStyleMap",
+    "attributes",
+    "attribution",
+    "attributionSrc",
+    "audioBitrateMode",
+    "audioBitsPerSecond",
+    "audioTracks",
+    "audioWorklet",
+    "authenticatedSignedWrites",
+    "authenticatorAttachment",
+    "authenticatorData",
+    "autoIncrement",
+    "autobuffer",
+    "autocapitalize",
+    "autocomplete",
+    "autocorrect",
+    "autofocus",
+    "automationRate",
+    "autoplay",
+    "availHeight",
+    "availLeft",
+    "availTop",
+    "availWidth",
+    "availability",
+    "available",
+    "averageLatency",
+    "aversion",
+    "ax",
+    "axes",
+    "axis",
+    "ay",
+    "azimuth",
+    "azimuthAngle",
+    "b",
+    "back",
+    "backdrop-filter",
+    "backdropFilter",
+    "backends",
+    "backface-visibility",
+    "backfaceVisibility",
+    "background",
+    "background-attachment",
+    "background-blend-mode",
+    "background-clip",
+    "background-color",
+    "background-image",
+    "background-origin",
+    "background-position",
+    "background-position-x",
+    "background-position-y",
+    "background-repeat",
+    "background-size",
+    "backgroundAttachment",
+    "backgroundBlendMode",
+    "backgroundClip",
+    "backgroundColor",
+    "backgroundFetch",
+    "backgroundImage",
+    "backgroundOrigin",
+    "backgroundPosition",
+    "backgroundPositionX",
+    "backgroundPositionY",
+    "backgroundRepeat",
+    "backgroundSize",
+    "badInput",
+    "badge",
+    "balance",
+    "baseArrayLayer",
+    "baseFrequencyX",
+    "baseFrequencyY",
+    "baseLatency",
+    "baseLayer",
+    "baseMipLevel",
+    "baseNode",
+    "baseOffset",
+    "basePalette",
+    "baseURI",
+    "baseVal",
+    "baseline-source",
+    "baselineShift",
+    "baselineSource",
+    "batchUpdate",
+    "battery",
+    "bday",
+    "before",
+    "beginComputePass",
+    "beginElement",
+    "beginElementAt",
+    "beginOcclusionQuery",
+    "beginPath",
+    "beginQuery",
+    "beginRenderPass",
+    "beginTransformFeedback",
+    "beginningOfPassWriteIndex",
+    "behavior",
+    "behaviorCookie",
+    "behaviorPart",
+    "behaviorUrns",
+    "beta",
+    "bezierCurveTo",
+    "bgColor",
+    "bgProperties",
+    "bias",
+    "big",
+    "bigint64",
+    "biguint64",
+    "binaryType",
+    "bind",
+    "bindAttribLocation",
+    "bindBuffer",
+    "bindBufferBase",
+    "bindBufferRange",
+    "bindFramebuffer",
+    "bindGroupLayouts",
+    "bindRenderbuffer",
+    "bindSampler",
+    "bindTexture",
+    "bindTransformFeedback",
+    "bindVertexArray",
+    "binding",
+    "bitness",
+    "blend",
+    "blendColor",
+    "blendEquation",
+    "blendEquationSeparate",
+    "blendFunc",
+    "blendFuncSeparate",
+    "blink",
+    "blitFramebuffer",
+    "blob",
+    "block-size",
+    "blockDirection",
+    "blockSize",
+    "blockedURI",
+    "blockedURL",
+    "blocking",
+    "blockingDuration",
+    "blue",
+    "bluetooth",
+    "blur",
+    "body",
+    "bodyUsed",
+    "bold",
+    "bookmarks",
+    "booleanValue",
+    "boost",
+    "border",
+    "border-block",
+    "border-block-color",
+    "border-block-end",
+    "border-block-end-color",
+    "border-block-end-style",
+    "border-block-end-width",
+    "border-block-start",
+    "border-block-start-color",
+    "border-block-start-style",
+    "border-block-start-width",
+    "border-block-style",
+    "border-block-width",
+    "border-bottom",
+    "border-bottom-color",
+    "border-bottom-left-radius",
+    "border-bottom-right-radius",
+    "border-bottom-style",
+    "border-bottom-width",
+    "border-collapse",
+    "border-color",
+    "border-end-end-radius",
+    "border-end-start-radius",
+    "border-image",
+    "border-image-outset",
+    "border-image-repeat",
+    "border-image-slice",
+    "border-image-source",
+    "border-image-width",
+    "border-inline",
+    "border-inline-color",
+    "border-inline-end",
+    "border-inline-end-color",
+    "border-inline-end-style",
+    "border-inline-end-width",
+    "border-inline-start",
+    "border-inline-start-color",
+    "border-inline-start-style",
+    "border-inline-start-width",
+    "border-inline-style",
+    "border-inline-width",
+    "border-left",
+    "border-left-color",
+    "border-left-style",
+    "border-left-width",
+    "border-radius",
+    "border-right",
+    "border-right-color",
+    "border-right-style",
+    "border-right-width",
+    "border-spacing",
+    "border-start-end-radius",
+    "border-start-start-radius",
+    "border-style",
+    "border-top",
+    "border-top-color",
+    "border-top-left-radius",
+    "border-top-right-radius",
+    "border-top-style",
+    "border-top-width",
+    "border-width",
+    "borderBlock",
+    "borderBlockColor",
+    "borderBlockEnd",
+    "borderBlockEndColor",
+    "borderBlockEndStyle",
+    "borderBlockEndWidth",
+    "borderBlockStart",
+    "borderBlockStartColor",
+    "borderBlockStartStyle",
+    "borderBlockStartWidth",
+    "borderBlockStyle",
+    "borderBlockWidth",
+    "borderBottom",
+    "borderBottomColor",
+    "borderBottomLeftRadius",
+    "borderBottomRightRadius",
+    "borderBottomStyle",
+    "borderBottomWidth",
+    "borderBoxSize",
+    "borderCollapse",
+    "borderColor",
+    "borderColorDark",
+    "borderColorLight",
+    "borderEndEndRadius",
+    "borderEndStartRadius",
+    "borderImage",
+    "borderImageOutset",
+    "borderImageRepeat",
+    "borderImageSlice",
+    "borderImageSource",
+    "borderImageWidth",
+    "borderInline",
+    "borderInlineColor",
+    "borderInlineEnd",
+    "borderInlineEndColor",
+    "borderInlineEndStyle",
+    "borderInlineEndWidth",
+    "borderInlineStart",
+    "borderInlineStartColor",
+    "borderInlineStartStyle",
+    "borderInlineStartWidth",
+    "borderInlineStyle",
+    "borderInlineWidth",
+    "borderLeft",
+    "borderLeftColor",
+    "borderLeftStyle",
+    "borderLeftWidth",
+    "borderRadius",
+    "borderRight",
+    "borderRightColor",
+    "borderRightStyle",
+    "borderRightWidth",
+    "borderSpacing",
+    "borderStartEndRadius",
+    "borderStartStartRadius",
+    "borderStyle",
+    "borderTop",
+    "borderTopColor",
+    "borderTopLeftRadius",
+    "borderTopRightRadius",
+    "borderTopStyle",
+    "borderTopWidth",
+    "borderWidth",
+    "bottom",
+    "bottomMargin",
+    "bound",
+    "boundElements",
+    "boundingClientRect",
+    "boundingHeight",
+    "boundingLeft",
+    "boundingRect",
+    "boundingTop",
+    "boundingWidth",
+    "bounds",
+    "boundsGeometry",
+    "box-decoration-break",
+    "box-shadow",
+    "box-sizing",
+    "boxDecorationBreak",
+    "boxShadow",
+    "boxSizing",
+    "brand",
+    "brands",
+    "break-after",
+    "break-before",
+    "break-inside",
+    "breakAfter",
+    "breakBefore",
+    "breakInside",
+    "broadcast",
+    "browser",
+    "browserLanguage",
+    "browserSettings",
+    "browsingData",
+    "browsingTopics",
+    "btoa",
+    "bubbles",
+    "buffer",
+    "bufferData",
+    "bufferDepth",
+    "bufferSize",
+    "bufferSubData",
+    "buffered",
+    "bufferedAmount",
+    "bufferedAmountLowThreshold",
+    "buffers",
+    "buildID",
+    "buildNumber",
+    "button",
+    "buttonID",
+    "buttons",
+    "byobRequest",
+    "byteLength",
+    "byteOffset",
+    "bytes",
+    "bytesPerRow",
+    "bytesWritten",
+    "c",
+    "cache",
+    "caches",
+    "calendar",
+    "call",
+    "caller",
+    "camera",
+    "canBeFormatted",
+    "canBeMounted",
+    "canBeShared",
+    "canConstructInDedicatedWorker",
+    "canGoBack",
+    "canGoForward",
+    "canHaveChildren",
+    "canHaveHTML",
+    "canInsertDTMF",
+    "canIntercept",
+    "canLoadAdAuctionFencedFrame",
+    "canLoadOpaqueURL",
+    "canMakePayment",
+    "canParse",
+    "canPlayType",
+    "canPresent",
+    "canShare",
+    "canTransition",
+    "canTrickleIceCandidates",
+    "cancel",
+    "cancelAndHoldAtTime",
+    "cancelAnimationFrame",
+    "cancelBubble",
+    "cancelIdleCallback",
+    "cancelScheduledValues",
+    "cancelVideoFrameCallback",
+    "cancelWatchAvailability",
+    "cancelable",
+    "candidate",
+    "canonicalUUID",
+    "canvas",
+    "cap",
+    "capabilities",
+    "caption",
+    "caption-side",
+    "captionSide",
+    "captivePortal",
+    "capture",
+    "captureEvents",
+    "captureStackTrace",
+    "captureStream",
+    "captureTab",
+    "captureVisibleTab",
+    "caret-color",
+    "caretBidiLevel",
+    "caretColor",
+    "caretPositionFromPoint",
+    "caretRangeFromPoint",
+    "cast",
+    "catch",
+    "category",
+    "cause",
+    "cbrt",
+    "cd",
+    "ceil",
+    "cellIndex",
+    "cellPadding",
+    "cellSpacing",
+    "cells",
+    "ch",
+    "chOff",
+    "chain",
+    "challenge",
+    "changeType",
+    "changed",
+    "changedTouches",
+    "channel",
+    "channelCount",
+    "channelCountMode",
+    "channelInterpretation",
+    "chapterInfo",
+    "char",
+    "charAt",
+    "charCode",
+    "charCodeAt",
+    "charIndex",
+    "charLength",
+    "characterBounds",
+    "characterBoundsRangeStart",
+    "characterData",
+    "characterDataOldValue",
+    "characterSet",
+    "characterVariant",
+    "characteristic",
+    "charging",
+    "chargingTime",
+    "charset",
+    "check",
+    "checkDCE",
+    "checkEnclosure",
+    "checkFramebufferStatus",
+    "checkIntersection",
+    "checkValidity",
+    "checkVisibility",
+    "checked",
+    "childElementCount",
+    "childList",
+    "childNodes",
+    "children",
+    "chrome",
+    "ciphertext",
+    "cite",
+    "city",
+    "claimInterface",
+    "claimed",
+    "classList",
+    "className",
+    "classid",
+    "clear",
+    "clearAppBadge",
+    "clearAttributes",
+    "clearBuffer",
+    "clearBufferfi",
+    "clearBufferfv",
+    "clearBufferiv",
+    "clearBufferuiv",
+    "clearColor",
+    "clearData",
+    "clearDepth",
+    "clearHalt",
+    "clearImmediate",
+    "clearInterval",
+    "clearLiveSeekableRange",
+    "clearMarks",
+    "clearMaxGCPauseAccumulator",
+    "clearMeasures",
+    "clearOriginJoinedAdInterestGroups",
+    "clearParameters",
+    "clearRect",
+    "clearResourceTimings",
+    "clearShadow",
+    "clearStencil",
+    "clearTimeout",
+    "clearValue",
+    "clearWatch",
+    "click",
+    "clickCount",
+    "clientDataJSON",
+    "clientHeight",
+    "clientInformation",
+    "clientLeft",
+    "clientRect",
+    "clientRects",
+    "clientTop",
+    "clientWaitSync",
+    "clientWidth",
+    "clientX",
+    "clientY",
+    "clip",
+    "clip-path",
+    "clip-rule",
+    "clipBottom",
+    "clipLeft",
+    "clipPath",
+    "clipPathUnits",
+    "clipRight",
+    "clipRule",
+    "clipTop",
+    "clipboard",
+    "clipboardData",
+    "clonable",
+    "clone",
+    "cloneContents",
+    "cloneNode",
+    "cloneRange",
+    "close",
+    "closeCode",
+    "closePath",
+    "closed",
+    "closedBy",
+    "closest",
+    "clz",
+    "clz32",
+    "cm",
+    "cmp",
+    "code",
+    "codeBase",
+    "codePointAt",
+    "codeType",
+    "codedHeight",
+    "codedRect",
+    "codedWidth",
+    "colSpan",
+    "collapse",
+    "collapseToEnd",
+    "collapseToStart",
+    "collapsed",
+    "collect",
+    "collections",
+    "colno",
+    "color",
+    "color-adjust",
+    "color-interpolation",
+    "color-interpolation-filters",
+    "color-scheme",
+    "colorAdjust",
+    "colorAttachments",
+    "colorDepth",
+    "colorFormats",
+    "colorInterpolation",
+    "colorInterpolationFilters",
+    "colorMask",
+    "colorScheme",
+    "colorSpace",
+    "colorType",
+    "cols",
+    "column-count",
+    "column-fill",
+    "column-gap",
+    "column-rule",
+    "column-rule-color",
+    "column-rule-style",
+    "column-rule-width",
+    "column-span",
+    "column-width",
+    "columnCount",
+    "columnFill",
+    "columnGap",
+    "columnNumber",
+    "columnRule",
+    "columnRuleColor",
+    "columnRuleStyle",
+    "columnRuleWidth",
+    "columnSpan",
+    "columnWidth",
+    "columns",
+    "command",
+    "commandForElement",
+    "commands",
+    "commit",
+    "commitLoadTime",
+    "commitPreferences",
+    "commitStyles",
+    "committed",
+    "commonAncestorContainer",
+    "compact",
+    "compare",
+    "compareBoundaryPoints",
+    "compareDocumentPosition",
+    "compareEndPoints",
+    "compareExchange",
+    "compareNode",
+    "comparePoint",
+    "compatMode",
+    "compatible",
+    "compile",
+    "compileShader",
+    "compileStreaming",
+    "complete",
+    "completed",
+    "component",
+    "componentFromPoint",
+    "composed",
+    "composedPath",
+    "composite",
+    "compositionEndOffset",
+    "compositionStartOffset",
+    "compressedTexImage2D",
+    "compressedTexImage3D",
+    "compressedTexSubImage2D",
+    "compressedTexSubImage3D",
+    "compute",
+    "computedStyleMap",
+    "concat",
+    "conditionText",
+    "coneInnerAngle",
+    "coneOuterAngle",
+    "coneOuterGain",
+    "config",
+    "configURL",
+    "configurable",
+    "configuration",
+    "configurationName",
+    "configurationValue",
+    "configurations",
+    "configure",
+    "confirm",
+    "confirmComposition",
+    "confirmSiteSpecificTrackingException",
+    "confirmWebWideTrackingException",
+    "congestionControl",
+    "connect",
+    "connectEnd",
+    "connectNative",
+    "connectShark",
+    "connectStart",
+    "connected",
+    "connectedCallback",
+    "connectedMoveCallback",
+    "connection",
+    "connectionInfo",
+    "connectionList",
+    "connectionSpeed",
+    "connectionState",
+    "connections",
+    "console",
+    "consolidate",
+    "constants",
+    "constraint",
+    "constrictionActive",
+    "construct",
+    "constructor",
+    "contactID",
+    "contain",
+    "contain-intrinsic-block-size",
+    "contain-intrinsic-height",
+    "contain-intrinsic-inline-size",
+    "contain-intrinsic-size",
+    "contain-intrinsic-width",
+    "containIntrinsicBlockSize",
+    "containIntrinsicHeight",
+    "containIntrinsicInlineSize",
+    "containIntrinsicSize",
+    "containIntrinsicWidth",
+    "container",
+    "container-name",
+    "container-type",
+    "containerId",
+    "containerName",
+    "containerQuery",
+    "containerSrc",
+    "containerType",
+    "contains",
+    "containsNode",
+    "content",
+    "content-visibility",
+    "contentBoxSize",
+    "contentDocument",
+    "contentEditable",
+    "contentEncoding",
+    "contentHint",
+    "contentOverflow",
+    "contentRect",
+    "contentScriptType",
+    "contentStyleType",
+    "contentType",
+    "contentVisibility",
+    "contentWindow",
+    "context",
+    "contextId",
+    "contextIds",
+    "contextMenu",
+    "contextMenus",
+    "contextType",
+    "contextTypes",
+    "contextmenu",
+    "contextualIdentities",
+    "continue",
+    "continuePrimaryKey",
+    "continuous",
+    "control",
+    "controlTransferIn",
+    "controlTransferOut",
+    "controller",
+    "controls",
+    "controlsList",
+    "convertPointFromNode",
+    "convertQuadFromNode",
+    "convertRectFromNode",
+    "convertToBlob",
+    "convertToSpecifiedUnits",
+    "cookie",
+    "cookieEnabled",
+    "cookieStore",
+    "cookies",
+    "coords",
+    "copyBufferSubData",
+    "copyBufferToBuffer",
+    "copyBufferToTexture",
+    "copyExternalImageToTexture",
+    "copyFromChannel",
+    "copyTexImage2D",
+    "copyTexSubImage2D",
+    "copyTexSubImage3D",
+    "copyTextureToBuffer",
+    "copyTextureToTexture",
+    "copyTo",
+    "copyToChannel",
+    "copyWithin",
+    "correspondingElement",
+    "correspondingUseElement",
+    "corruptedVideoFrames",
+    "cos",
+    "cosh",
+    "count",
+    "countReset",
+    "counter-increment",
+    "counter-reset",
+    "counter-set",
+    "counterIncrement",
+    "counterReset",
+    "counterSet",
+    "country",
+    "cpuClass",
+    "cpuSleepAllowed",
+    "cqb",
+    "cqh",
+    "cqi",
+    "cqmax",
+    "cqmin",
+    "cqw",
+    "create",
+    "createAnalyser",
+    "createAnchor",
+    "createAnswer",
+    "createAttribute",
+    "createAttributeNS",
+    "createAuctionNonce",
+    "createBidirectionalStream",
+    "createBindGroup",
+    "createBindGroupLayout",
+    "createBiquadFilter",
+    "createBuffer",
+    "createBufferSource",
+    "createCDATASection",
+    "createCSSStyleSheet",
+    "createCaption",
+    "createChannelMerger",
+    "createChannelSplitter",
+    "createCommandEncoder",
+    "createComment",
+    "createComputePipeline",
+    "createComputePipelineAsync",
+    "createConicGradient",
+    "createConstantSource",
+    "createContextualFragment",
+    "createControlRange",
+    "createConvolver",
+    "createDTMFSender",
+    "createDataChannel",
+    "createDelay",
+    "createDelayNode",
+    "createDocument",
+    "createDocumentFragment",
+    "createDocumentType",
+    "createDynamicsCompressor",
+    "createElement",
+    "createElementNS",
+    "createEncodedStreams",
+    "createEntityReference",
+    "createEvent",
+    "createEventObject",
+    "createExpression",
+    "createFramebuffer",
+    "createFunction",
+    "createGain",
+    "createGainNode",
+    "createHTML",
+    "createHTMLDocument",
+    "createIIRFilter",
+    "createImageBitmap",
+    "createImageData",
+    "createIndex",
+    "createJavaScriptNode",
+    "createLinearGradient",
+    "createMediaElementSource",
+    "createMediaKeys",
+    "createMediaStreamDestination",
+    "createMediaStreamSource",
+    "createMediaStreamTrackSource",
+    "createMutableFile",
+    "createNSResolver",
+    "createNodeIterator",
+    "createNotification",
+    "createObjectStore",
+    "createObjectURL",
+    "createOffer",
+    "createOscillator",
+    "createPanner",
+    "createPattern",
+    "createPeriodicWave",
+    "createPipelineLayout",
+    "createPolicy",
+    "createPopup",
+    "createProcessingInstruction",
+    "createProgram",
+    "createQuery",
+    "createQuerySet",
+    "createRadialGradient",
+    "createRange",
+    "createRangeCollection",
+    "createReader",
+    "createRenderBundleEncoder",
+    "createRenderPipeline",
+    "createRenderPipelineAsync",
+    "createRenderbuffer",
+    "createSVGAngle",
+    "createSVGLength",
+    "createSVGMatrix",
+    "createSVGNumber",
+    "createSVGPathSegArcAbs",
+    "createSVGPathSegArcRel",
+    "createSVGPathSegClosePath",
+    "createSVGPathSegCurvetoCubicAbs",
+    "createSVGPathSegCurvetoCubicRel",
+    "createSVGPathSegCurvetoCubicSmoothAbs",
+    "createSVGPathSegCurvetoCubicSmoothRel",
+    "createSVGPathSegCurvetoQuadraticAbs",
+    "createSVGPathSegCurvetoQuadraticRel",
+    "createSVGPathSegCurvetoQuadraticSmoothAbs",
+    "createSVGPathSegCurvetoQuadraticSmoothRel",
+    "createSVGPathSegLinetoAbs",
+    "createSVGPathSegLinetoHorizontalAbs",
+    "createSVGPathSegLinetoHorizontalRel",
+    "createSVGPathSegLinetoRel",
+    "createSVGPathSegLinetoVerticalAbs",
+    "createSVGPathSegLinetoVerticalRel",
+    "createSVGPathSegMovetoAbs",
+    "createSVGPathSegMovetoRel",
+    "createSVGPoint",
+    "createSVGRect",
+    "createSVGTransform",
+    "createSVGTransformFromMatrix",
+    "createSampler",
+    "createScript",
+    "createScriptProcessor",
+    "createScriptURL",
+    "createSession",
+    "createShader",
+    "createShaderModule",
+    "createShadowRoot",
+    "createStereoPanner",
+    "createStyleSheet",
+    "createTBody",
+    "createTFoot",
+    "createTHead",
+    "createTask",
+    "createTextNode",
+    "createTextRange",
+    "createTexture",
+    "createTouch",
+    "createTouchList",
+    "createTransformFeedback",
+    "createTreeWalker",
+    "createUnidirectionalStream",
+    "createVertexArray",
+    "createView",
+    "createWaveShaper",
+    "createWorklet",
+    "createWritable",
+    "creationTime",
+    "credentialless",
+    "credentials",
+    "criticalCHRestart",
+    "cropTo",
+    "crossOrigin",
+    "crossOriginIsolated",
+    "crypto",
+    "csi",
+    "csp",
+    "cssFloat",
+    "cssRules",
+    "cssText",
+    "cssValueType",
+    "ctrlKey",
+    "ctrlLeft",
+    "cues",
+    "cullFace",
+    "cullMode",
+    "currentCSSZoom",
+    "currentDirection",
+    "currentEntry",
+    "currentLocalDescription",
+    "currentNode",
+    "currentPage",
+    "currentRect",
+    "currentRemoteDescription",
+    "currentScale",
+    "currentScreen",
+    "currentScript",
+    "currentSrc",
+    "currentState",
+    "currentStyle",
+    "currentTarget",
+    "currentTime",
+    "currentTranslate",
+    "currentView",
+    "cursor",
+    "curve",
+    "customElements",
+    "customError",
+    "cx",
+    "cy",
+    "d",
+    "data",
+    "dataFld",
+    "dataFormatAs",
+    "dataLoss",
+    "dataLossMessage",
+    "dataPageSize",
+    "dataSrc",
+    "dataTransfer",
+    "database",
+    "databases",
+    "datagrams",
+    "dataset",
+    "dateStyle",
+    "dateTime",
+    "day",
+    "dayPeriod",
+    "days",
+    "db",
+    "debug",
+    "debuggerEnabled",
+    "declarativeNetRequest",
+    "declare",
+    "decode",
+    "decodeAudioData",
+    "decodeQueueSize",
+    "decodeURI",
+    "decodeURIComponent",
+    "decodedBodySize",
+    "decoding",
+    "decodingInfo",
+    "decreaseZoomLevel",
+    "decrypt",
+    "default",
+    "defaultCharset",
+    "defaultChecked",
+    "defaultMuted",
+    "defaultPlaybackRate",
+    "defaultPolicy",
+    "defaultPrevented",
+    "defaultQueue",
+    "defaultRequest",
+    "defaultSelected",
+    "defaultStatus",
+    "defaultURL",
+    "defaultValue",
+    "defaultView",
+    "defaultstatus",
+    "defer",
+    "define",
+    "defineMagicFunction",
+    "defineMagicVariable",
+    "defineProperties",
+    "defineProperty",
+    "deg",
+    "delay",
+    "delayTime",
+    "delegatesFocus",
+    "delete",
+    "deleteBuffer",
+    "deleteCaption",
+    "deleteCell",
+    "deleteContents",
+    "deleteData",
+    "deleteDatabase",
+    "deleteFramebuffer",
+    "deleteFromDocument",
+    "deleteIndex",
+    "deleteMedium",
+    "deleteObjectStore",
+    "deleteProgram",
+    "deleteProperty",
+    "deleteQuery",
+    "deleteRenderbuffer",
+    "deleteRow",
+    "deleteRule",
+    "deleteSampler",
+    "deleteShader",
+    "deleteSync",
+    "deleteTFoot",
+    "deleteTHead",
+    "deleteTexture",
+    "deleteTransformFeedback",
+    "deleteVertexArray",
+    "deleted",
+    "deliverChangeRecords",
+    "deliveredFrames",
+    "deliveredFramesDuration",
+    "delivery",
+    "deliveryInfo",
+    "deliveryStatus",
+    "deliveryTimestamp",
+    "deliveryType",
+    "delta",
+    "deltaMode",
+    "deltaX",
+    "deltaY",
+    "deltaZ",
+    "dependentLocality",
+    "deprecatedReplaceInURN",
+    "deprecatedRunAdAuctionEnforcesKAnonymity",
+    "deprecatedURNToURL",
+    "depthActive",
+    "depthBias",
+    "depthBiasClamp",
+    "depthBiasSlopeScale",
+    "depthClearValue",
+    "depthCompare",
+    "depthDataFormat",
+    "depthFailOp",
+    "depthFar",
+    "depthFunc",
+    "depthLoadOp",
+    "depthMask",
+    "depthNear",
+    "depthOrArrayLayers",
+    "depthRange",
+    "depthReadOnly",
+    "depthStencil",
+    "depthStencilAttachment",
+    "depthStencilFormat",
+    "depthStoreOp",
+    "depthType",
+    "depthUsage",
+    "depthWriteEnabled",
+    "deref",
+    "deriveBits",
+    "deriveKey",
+    "descentOverride",
+    "description",
+    "deselectAll",
+    "designMode",
+    "desiredSize",
+    "destination",
+    "destinationURL",
+    "destroy",
+    "detach",
+    "detachEvent",
+    "detachShader",
+    "detached",
+    "detail",
+    "details",
+    "detect",
+    "detectLanguage",
+    "detune",
+    "device",
+    "deviceClass",
+    "deviceId",
+    "deviceMemory",
+    "devicePixelContentBoxSize",
+    "devicePixelRatio",
+    "devicePosture",
+    "deviceProtocol",
+    "deviceSubclass",
+    "deviceVersionMajor",
+    "deviceVersionMinor",
+    "deviceVersionSubminor",
+    "deviceXDPI",
+    "deviceYDPI",
+    "devtools",
+    "devtools_panels",
+    "didTimeout",
+    "difference",
+    "diffuseConstant",
+    "digest",
+    "dimension",
+    "dimensions",
+    "dir",
+    "dirName",
+    "direction",
+    "dirxml",
+    "disable",
+    "disablePictureInPicture",
+    "disableRemotePlayback",
+    "disableVertexAttribArray",
+    "disabled",
+    "discard",
+    "discardedFrames",
+    "dischargingTime",
+    "disconnect",
+    "disconnectShark",
+    "disconnectedCallback",
+    "dispatchEvent",
+    "dispatchWorkgroups",
+    "dispatchWorkgroupsIndirect",
+    "display",
+    "displayHeight",
+    "displayId",
+    "displayName",
+    "displayWidth",
+    "dispose",
+    "disposeAsync",
+    "disposed",
+    "disposition",
+    "distanceModel",
+    "div",
+    "divisor",
+    "djsapi",
+    "djsproxy",
+    "dns",
+    "doImport",
+    "doNotTrack",
+    "doScroll",
+    "doctype",
+    "document",
+    "documentElement",
+    "documentId",
+    "documentIds",
+    "documentLifecycle",
+    "documentMode",
+    "documentOrigin",
+    "documentOrigins",
+    "documentPictureInPicture",
+    "documentURI",
+    "documentURL",
+    "documentUrl",
+    "documentUrls",
+    "dolphin",
+    "dolphinGameCenter",
+    "dolphininfo",
+    "dolphinmeta",
+    "dom",
+    "domComplete",
+    "domContentLoadedEventEnd",
+    "domContentLoadedEventStart",
+    "domInteractive",
+    "domLoading",
+    "domOverlayState",
+    "domain",
+    "domainLookupEnd",
+    "domainLookupStart",
+    "dominant-baseline",
+    "dominantBaseline",
+    "done",
+    "dopplerFactor",
+    "dotAll",
+    "downDegrees",
+    "downlink",
+    "download",
+    "downloadRequest",
+    "downloadTotal",
+    "downloaded",
+    "downloads",
+    "dpcm",
+    "dpi",
+    "dppx",
+    "dragDrop",
+    "draggable",
+    "draw",
+    "drawArrays",
+    "drawArraysInstanced",
+    "drawArraysInstancedANGLE",
+    "drawBuffers",
+    "drawCustomFocusRing",
+    "drawElements",
+    "drawElementsInstanced",
+    "drawElementsInstancedANGLE",
+    "drawFocusIfNeeded",
+    "drawImage",
+    "drawImageFromRect",
+    "drawIndexed",
+    "drawIndexedIndirect",
+    "drawIndirect",
+    "drawRangeElements",
+    "drawSystemFocusRing",
+    "drawingBufferColorSpace",
+    "drawingBufferFormat",
+    "drawingBufferHeight",
+    "drawingBufferStorage",
+    "drawingBufferWidth",
+    "drop",
+    "dropEffect",
+    "droppedVideoFrames",
+    "dropzone",
+    "dstFactor",
+    "dtmf",
+    "dump",
+    "dumpProfile",
+    "duplex",
+    "duplicate",
+    "durability",
+    "duration",
+    "dvb",
+    "dvh",
+    "dvi",
+    "dvmax",
+    "dvmin",
+    "dvname",
+    "dvnum",
+    "dvw",
+    "dx",
+    "dy",
+    "dynamicId",
+    "dynsrc",
+    "e",
+    "edgeMode",
+    "editContext",
+    "effect",
+    "effectAllowed",
+    "effectiveDirective",
+    "effectiveType",
+    "effects",
+    "elapsedTime",
+    "element",
+    "elementFromPoint",
+    "elementTiming",
+    "elements",
+    "elementsFromPoint",
+    "elevation",
+    "ellipse",
+    "em",
+    "emHeightAscent",
+    "emHeightDescent",
+    "email",
+    "embeds",
+    "emit",
+    "emma",
+    "empty",
+    "empty-cells",
+    "emptyCells",
+    "emptyHTML",
+    "emptyScript",
+    "emulatedPosition",
+    "enable",
+    "enableBackground",
+    "enableDelegations",
+    "enableStyleSheetsForSet",
+    "enableVertexAttribArray",
+    "enabled",
+    "enabledFeatures",
+    "enabledPlugin",
+    "encode",
+    "encodeInto",
+    "encodeQueueSize",
+    "encodeURI",
+    "encodeURIComponent",
+    "encodedBodySize",
+    "encoding",
+    "encodingInfo",
+    "encrypt",
+    "enctype",
+    "end",
+    "endContainer",
+    "endElement",
+    "endElementAt",
+    "endOcclusionQuery",
+    "endOfPassWriteIndex",
+    "endOfStream",
+    "endOffset",
+    "endQuery",
+    "endTime",
+    "endTransformFeedback",
+    "ended",
+    "endpoint",
+    "endpointNumber",
+    "endpoints",
+    "endsWith",
+    "enqueue",
+    "enterKeyHint",
+    "entities",
+    "entries",
+    "entry",
+    "entryPoint",
+    "entryType",
+    "enumerable",
+    "enumerate",
+    "enumerateDevices",
+    "enumerateEditable",
+    "environmentBlendMode",
+    "equals",
+    "era",
+    "error",
+    "errorCode",
+    "errorDetail",
+    "errorText",
+    "escape",
+    "estimate",
+    "eval",
+    "evaluate",
+    "event",
+    "eventCounts",
+    "eventPhase",
+    "events",
+    "every",
+    "ex",
+    "exception",
+    "exchange",
+    "exec",
+    "execCommand",
+    "execCommandShowHelp",
+    "execScript",
+    "executeBundles",
+    "executionStart",
+    "exitFullscreen",
+    "exitPictureInPicture",
+    "exitPointerLock",
+    "exitPresent",
+    "exp",
+    "expand",
+    "expandEntityReferences",
+    "expando",
+    "expansion",
+    "expectedContextLanguages",
+    "expectedImprovement",
+    "expectedInputLanguages",
+    "experiments",
+    "expiration",
+    "expirationTime",
+    "expires",
+    "expiryDate",
+    "explicitOriginalTarget",
+    "expm1",
+    "exponent",
+    "exponentialRampToValueAtTime",
+    "exportKey",
+    "exports",
+    "extend",
+    "extension",
+    "extensionTypes",
+    "extensions",
+    "extentNode",
+    "extentOffset",
+    "external",
+    "externalResourcesRequired",
+    "externalTexture",
+    "extractContents",
+    "extractable",
+    "eye",
+    "f",
+    "f16round",
+    "face",
+    "factoryReset",
+    "failOp",
+    "failureReason",
+    "fallback",
+    "family",
+    "familyName",
+    "farthestViewportElement",
+    "fastSeek",
+    "fatal",
+    "featureId",
+    "featurePolicy",
+    "featureSettings",
+    "features",
+    "fence",
+    "fenceSync",
+    "fetch",
+    "fetchLater",
+    "fetchPriority",
+    "fetchStart",
+    "fftSize",
+    "fgColor",
+    "fieldOfView",
+    "file",
+    "fileCreatedDate",
+    "fileHandle",
+    "fileModifiedDate",
+    "fileName",
+    "fileSize",
+    "fileUpdatedDate",
+    "filename",
+    "files",
+    "filesystem",
+    "fill",
+    "fill-opacity",
+    "fill-rule",
+    "fillJointRadii",
+    "fillLightMode",
+    "fillOpacity",
+    "fillPoses",
+    "fillRect",
+    "fillRule",
+    "fillStyle",
+    "fillText",
+    "filter",
+    "filterResX",
+    "filterResY",
+    "filterUnits",
+    "filters",
+    "finalResponseHeadersStart",
+    "finally",
+    "find",
+    "findIndex",
+    "findLast",
+    "findLastIndex",
+    "findRule",
+    "findText",
+    "finish",
+    "finishDocumentLoadTime",
+    "finishLoadTime",
+    "finished",
+    "fireEvent",
+    "firesTouchEvents",
+    "first",
+    "firstChild",
+    "firstElementChild",
+    "firstInterimResponseStart",
+    "firstPage",
+    "firstPaintAfterLoadTime",
+    "firstPaintTime",
+    "firstUIEventTimestamp",
+    "fixed",
+    "flags",
+    "flat",
+    "flatMap",
+    "flex",
+    "flex-basis",
+    "flex-direction",
+    "flex-flow",
+    "flex-grow",
+    "flex-shrink",
+    "flex-wrap",
+    "flexBasis",
+    "flexDirection",
+    "flexFlow",
+    "flexGrow",
+    "flexShrink",
+    "flexWrap",
+    "flip",
+    "flipX",
+    "flipY",
+    "float",
+    "float32",
+    "float64",
+    "flood-color",
+    "flood-opacity",
+    "floodColor",
+    "floodOpacity",
+    "floor",
+    "flush",
+    "focus",
+    "focusNode",
+    "focusOffset",
+    "font",
+    "font-family",
+    "font-feature-settings",
+    "font-kerning",
+    "font-language-override",
+    "font-optical-sizing",
+    "font-palette",
+    "font-size",
+    "font-size-adjust",
+    "font-stretch",
+    "font-style",
+    "font-synthesis",
+    "font-synthesis-position",
+    "font-synthesis-small-caps",
+    "font-synthesis-style",
+    "font-synthesis-weight",
+    "font-variant",
+    "font-variant-alternates",
+    "font-variant-caps",
+    "font-variant-east-asian",
+    "font-variant-ligatures",
+    "font-variant-numeric",
+    "font-variant-position",
+    "font-variation-settings",
+    "font-weight",
+    "fontBoundingBoxAscent",
+    "fontBoundingBoxDescent",
+    "fontFamily",
+    "fontFeatureSettings",
+    "fontKerning",
+    "fontLanguageOverride",
+    "fontOpticalSizing",
+    "fontPalette",
+    "fontSize",
+    "fontSizeAdjust",
+    "fontSmoothingEnabled",
+    "fontStretch",
+    "fontStyle",
+    "fontSynthesis",
+    "fontSynthesisPosition",
+    "fontSynthesisSmallCaps",
+    "fontSynthesisStyle",
+    "fontSynthesisWeight",
+    "fontVariant",
+    "fontVariantAlternates",
+    "fontVariantCaps",
+    "fontVariantEastAsian",
+    "fontVariantEmoji",
+    "fontVariantLigatures",
+    "fontVariantNumeric",
+    "fontVariantPosition",
+    "fontVariationSettings",
+    "fontWeight",
+    "fontcolor",
+    "fontfaces",
+    "fonts",
+    "fontsize",
+    "for",
+    "forEach",
+    "force",
+    "forceFallbackAdapter",
+    "forceRedraw",
+    "forced-color-adjust",
+    "forcedColorAdjust",
+    "forcedStyleAndLayoutDuration",
+    "forget",
+    "form",
+    "formAction",
+    "formData",
+    "formEnctype",
+    "formMethod",
+    "formNoValidate",
+    "formTarget",
+    "format",
+    "formatToParts",
+    "forms",
+    "forward",
+    "forwardWheel",
+    "forwardX",
+    "forwardY",
+    "forwardZ",
+    "foundation",
+    "fr",
+    "fractionalSecondDigits",
+    "fragment",
+    "fragmentDirective",
+    "frame",
+    "frameBorder",
+    "frameCount",
+    "frameElement",
+    "frameId",
+    "frameIds",
+    "frameSpacing",
+    "framebuffer",
+    "framebufferHeight",
+    "framebufferRenderbuffer",
+    "framebufferTexture2D",
+    "framebufferTextureLayer",
+    "framebufferWidth",
+    "frames",
+    "freeSpace",
+    "freeze",
+    "frequency",
+    "frequencyBinCount",
+    "from",
+    "fromAsync",
+    "fromBase64",
+    "fromCharCode",
+    "fromCodePoint",
+    "fromElement",
+    "fromEntries",
+    "fromFloat32Array",
+    "fromFloat64Array",
+    "fromHex",
+    "fromMatrix",
+    "fromPoint",
+    "fromQuad",
+    "fromRect",
+    "frontFace",
+    "fround",
+    "fullName",
+    "fullPath",
+    "fullRange",
+    "fullScreen",
+    "fullVersionList",
+    "fullscreen",
+    "fullscreenElement",
+    "fullscreenEnabled",
+    "fx",
+    "fy",
+    "g",
+    "gain",
+    "gamepad",
+    "gamma",
+    "gap",
+    "gatheringState",
+    "gatt",
+    "geckoProfiler",
+    "genderIdentity",
+    "generateCertificate",
+    "generateKey",
+    "generateMipmap",
+    "generateRequest",
+    "geolocation",
+    "gestureObject",
+    "get",
+    "getAcceptLanguages",
+    "getActiveAttrib",
+    "getActiveUniform",
+    "getActiveUniformBlockName",
+    "getActiveUniformBlockParameter",
+    "getActiveUniforms",
+    "getAdjacentText",
+    "getAll",
+    "getAllKeys",
+    "getAllRecords",
+    "getAllResponseHeaders",
+    "getAllowlistForFeature",
+    "getAnimations",
+    "getAsFile",
+    "getAsFileSystemHandle",
+    "getAsString",
+    "getAttachedShaders",
+    "getAttribLocation",
+    "getAttribute",
+    "getAttributeNS",
+    "getAttributeNames",
+    "getAttributeNode",
+    "getAttributeNodeNS",
+    "getAttributeType",
+    "getAudioTracks",
+    "getAuthenticatorData",
+    "getAutoplayPolicy",
+    "getAvailability",
+    "getBBox",
+    "getBackgroundPage",
+    "getBadgeBackgroundColor",
+    "getBadgeText",
+    "getBadgeTextColor",
+    "getBattery",
+    "getBigInt64",
+    "getBigUint64",
+    "getBindGroupLayout",
+    "getBlob",
+    "getBookmark",
+    "getBoundingClientRect",
+    "getBounds",
+    "getBoxQuads",
+    "getBrowserInfo",
+    "getBufferParameter",
+    "getBufferSubData",
+    "getByteFrequencyData",
+    "getByteTimeDomainData",
+    "getCSSCanvasContext",
+    "getCTM",
+    "getCameraImage",
+    "getCandidateWindowClientRect",
+    "getCanonicalLocales",
+    "getCapabilities",
+    "getCaptureHandle",
+    "getChannelData",
+    "getCharNumAtPosition",
+    "getCharacteristic",
+    "getCharacteristics",
+    "getClientCapabilities",
+    "getClientExtensionResults",
+    "getClientRect",
+    "getClientRects",
+    "getCoalescedEvents",
+    "getCompilationInfo",
+    "getComposedRanges",
+    "getCompositionAlternatives",
+    "getComputedStyle",
+    "getComputedTextLength",
+    "getComputedTiming",
+    "getConfiguration",
+    "getConstraints",
+    "getContext",
+    "getContextAttributes",
+    "getContexts",
+    "getContributingSources",
+    "getCounterValue",
+    "getCueAsHTML",
+    "getCueById",
+    "getCurrent",
+    "getCurrentPosition",
+    "getCurrentTexture",
+    "getCurrentTime",
+    "getData",
+    "getDatabaseNames",
+    "getDate",
+    "getDay",
+    "getDefaultComputedStyle",
+    "getDepthInMeters",
+    "getDepthInformation",
+    "getDescriptor",
+    "getDescriptors",
+    "getDestinationInsertionPoints",
+    "getDevices",
+    "getDirectory",
+    "getDirectoryHandle",
+    "getDisplayMedia",
+    "getDistributedNodes",
+    "getEditable",
+    "getElementById",
+    "getElementsByClassName",
+    "getElementsByName",
+    "getElementsByTagName",
+    "getElementsByTagNameNS",
+    "getEnclosureList",
+    "getEndPositionOfChar",
+    "getEntries",
+    "getEntriesByName",
+    "getEntriesByType",
+    "getError",
+    "getExtension",
+    "getExtentOfChar",
+    "getEyeParameters",
+    "getFeature",
+    "getFiberRoots",
+    "getFile",
+    "getFileHandle",
+    "getFiles",
+    "getFilesAndDirectories",
+    "getFingerprints",
+    "getFloat16",
+    "getFloat32",
+    "getFloat64",
+    "getFloatFrequencyData",
+    "getFloatTimeDomainData",
+    "getFloatValue",
+    "getFragDataLocation",
+    "getFrameData",
+    "getFrameId",
+    "getFramebufferAttachmentParameter",
+    "getFrequencyResponse",
+    "getFullYear",
+    "getGamepads",
+    "getHTML",
+    "getHeaderExtensionsToNegotiate",
+    "getHighEntropyValues",
+    "getHitTestResults",
+    "getHitTestResultsForTransientInput",
+    "getHours",
+    "getIdentityAssertion",
+    "getIds",
+    "getImageData",
+    "getIndexedParameter",
+    "getInfo",
+    "getInnerHTML",
+    "getInstalledRelatedApps",
+    "getInt16",
+    "getInt32",
+    "getInt8",
+    "getInterestGroupAdAuctionData",
+    "getInternalModuleRanges",
+    "getInternalformatParameter",
+    "getIntersectionList",
+    "getItem",
+    "getItems",
+    "getJointPose",
+    "getKey",
+    "getKeyframes",
+    "getLastFocused",
+    "getLayers",
+    "getLayoutMap",
+    "getLightEstimate",
+    "getLineDash",
+    "getLocalCandidates",
+    "getLocalParameters",
+    "getLocalStreams",
+    "getManagedConfiguration",
+    "getManifest",
+    "getMappedRange",
+    "getMarks",
+    "getMatchedCSSRules",
+    "getMaxGCPauseSinceClear",
+    "getMeasures",
+    "getMessage",
+    "getMetadata",
+    "getMilliseconds",
+    "getMinutes",
+    "getModifierState",
+    "getMonth",
+    "getName",
+    "getNamedItem",
+    "getNamedItemNS",
+    "getNativeFramebufferScaleFactor",
+    "getNegotiatedHeaderExtensions",
+    "getNestedConfigs",
+    "getNotifications",
+    "getNotifier",
+    "getNumberOfChars",
+    "getOffsetReferenceSpace",
+    "getOrInsert",
+    "getOrInsertComputed",
+    "getOutputTimestamp",
+    "getOverrideHistoryNavigationMode",
+    "getOverrideStyle",
+    "getOwnPropertyDescriptor",
+    "getOwnPropertyDescriptors",
+    "getOwnPropertyNames",
+    "getOwnPropertySymbols",
+    "getPackageDirectoryEntry",
+    "getParameter",
+    "getParameters",
+    "getParent",
+    "getPathData",
+    "getPathSegAtLength",
+    "getPathSegmentAtLength",
+    "getPermissionWarningsByManifest",
+    "getPhotoCapabilities",
+    "getPhotoSettings",
+    "getPlatformInfo",
+    "getPointAtLength",
+    "getPopup",
+    "getPorts",
+    "getPose",
+    "getPredictedEvents",
+    "getPreference",
+    "getPreferenceDefault",
+    "getPreferredCanvasFormat",
+    "getPresentationAttribute",
+    "getPreventDefault",
+    "getPrimaryService",
+    "getPrimaryServices",
+    "getProgramInfoLog",
+    "getProgramParameter",
+    "getPropertyCSSValue",
+    "getPropertyPriority",
+    "getPropertyShorthand",
+    "getPropertyType",
+    "getPropertyValue",
+    "getPrototypeOf",
+    "getPublicKey",
+    "getPublicKeyAlgorithm",
+    "getQuery",
+    "getQueryParameter",
+    "getRGBColorValue",
+    "getRandomValues",
+    "getRangeAt",
+    "getReader",
+    "getReceivers",
+    "getRectValue",
+    "getReflectionCubeMap",
+    "getRegistration",
+    "getRegistrations",
+    "getRemoteCandidates",
+    "getRemoteCertificates",
+    "getRemoteParameters",
+    "getRemoteStreams",
+    "getRenderbufferParameter",
+    "getResponseHeader",
+    "getRoot",
+    "getRootNode",
+    "getRotationOfChar",
+    "getSVGDocument",
+    "getSamplerParameter",
+    "getScreenCTM",
+    "getScreenDetails",
+    "getSeconds",
+    "getSelectedCandidatePair",
+    "getSelection",
+    "getSelf",
+    "getSenders",
+    "getService",
+    "getSetCookie",
+    "getSettings",
+    "getShaderInfoLog",
+    "getShaderParameter",
+    "getShaderPrecisionFormat",
+    "getShaderSource",
+    "getSignals",
+    "getSimpleDuration",
+    "getSiteIcons",
+    "getSources",
+    "getSpeculativeParserUrls",
+    "getStartPositionOfChar",
+    "getStartTime",
+    "getState",
+    "getStats",
+    "getStatusForPolicy",
+    "getStorageUpdates",
+    "getStreamById",
+    "getStringValue",
+    "getSubStringLength",
+    "getSubscription",
+    "getSubscriptions",
+    "getSupportedConstraints",
+    "getSupportedExtensions",
+    "getSupportedFormats",
+    "getSupportedZoomLevels",
+    "getSyncParameter",
+    "getSynchronizationSources",
+    "getTags",
+    "getTargetRanges",
+    "getTexParameter",
+    "getTextFormats",
+    "getTime",
+    "getTimezoneOffset",
+    "getTiming",
+    "getTitle",
+    "getTitlebarAreaRect",
+    "getTotalLength",
+    "getTrackById",
+    "getTracks",
+    "getTransceivers",
+    "getTransform",
+    "getTransformFeedbackVarying",
+    "getTransformToElement",
+    "getTransports",
+    "getType",
+    "getTypeMapping",
+    "getUILanguage",
+    "getURL",
+    "getUTCDate",
+    "getUTCDay",
+    "getUTCFullYear",
+    "getUTCHours",
+    "getUTCMilliseconds",
+    "getUTCMinutes",
+    "getUTCMonth",
+    "getUTCSeconds",
+    "getUint16",
+    "getUint32",
+    "getUint8",
+    "getUniform",
+    "getUniformBlockIndex",
+    "getUniformIndices",
+    "getUniformLocation",
+    "getUserInfo",
+    "getUserMedia",
+    "getUserSettings",
+    "getVRDisplays",
+    "getValues",
+    "getVarDate",
+    "getVariableValue",
+    "getVertexAttrib",
+    "getVertexAttribOffset",
+    "getVideoPlaybackQuality",
+    "getVideoTracks",
+    "getViewerPose",
+    "getViewport",
+    "getViews",
+    "getVoices",
+    "getWakeLockState",
+    "getWriter",
+    "getYear",
+    "getZoom",
+    "getZoomSettings",
+    "givenName",
+    "global",
+    "globalAlpha",
+    "globalCompositeOperation",
+    "globalPrivacyControl",
+    "globalThis",
+    "glyphOrientationHorizontal",
+    "glyphOrientationVertical",
+    "glyphRef",
+    "go",
+    "goBack",
+    "goForward",
+    "gpu",
+    "grabFrame",
+    "grad",
+    "gradientTransform",
+    "gradientUnits",
+    "grammars",
+    "green",
+    "grid",
+    "grid-area",
+    "grid-auto-columns",
+    "grid-auto-flow",
+    "grid-auto-rows",
+    "grid-column",
+    "grid-column-end",
+    "grid-column-gap",
+    "grid-column-start",
+    "grid-gap",
+    "grid-row",
+    "grid-row-end",
+    "grid-row-gap",
+    "grid-row-start",
+    "grid-template",
+    "grid-template-areas",
+    "grid-template-columns",
+    "grid-template-rows",
+    "gridArea",
+    "gridAutoColumns",
+    "gridAutoFlow",
+    "gridAutoRows",
+    "gridColumn",
+    "gridColumnEnd",
+    "gridColumnGap",
+    "gridColumnStart",
+    "gridGap",
+    "gridRow",
+    "gridRowEnd",
+    "gridRowGap",
+    "gridRowStart",
+    "gridTemplate",
+    "gridTemplateAreas",
+    "gridTemplateColumns",
+    "gridTemplateRows",
+    "gripSpace",
+    "group",
+    "groupBy",
+    "groupCollapsed",
+    "groupEnd",
+    "groupId",
+    "groups",
+    "grow",
+    "growable",
+    "guestProcessId",
+    "guestRenderFrameRoutingId",
+    "hadRecentInput",
+    "hand",
+    "handedness",
+    "hangingBaseline",
+    "hapticActuators",
+    "hardwareConcurrency",
+    "has",
+    "hasAttribute",
+    "hasAttributeNS",
+    "hasAttributes",
+    "hasBeenActive",
+    "hasChildNodes",
+    "hasComposition",
+    "hasDynamicOffset",
+    "hasEnrolledInstrument",
+    "hasExtension",
+    "hasExternalDisplay",
+    "hasFeature",
+    "hasFocus",
+    "hasIndices",
+    "hasInstance",
+    "hasLayout",
+    "hasOrientation",
+    "hasOwn",
+    "hasOwnProperty",
+    "hasPointerCapture",
+    "hasPosition",
+    "hasPrivateToken",
+    "hasReading",
+    "hasRedemptionRecord",
+    "hasRegExpGroups",
+    "hasStorageAccess",
+    "hasUAVisualTransition",
+    "hasUnpartitionedCookieAccess",
+    "hash",
+    "hashChange",
+    "head",
+    "headers",
+    "heading",
+    "height",
+    "hid",
+    "hidden",
+    "hide",
+    "hideFocus",
+    "hidePopover",
+    "high",
+    "highWaterMark",
+    "highlight",
+    "highlights",
+    "highlightsFromPoint",
+    "hint",
+    "hints",
+    "history",
+    "honorificPrefix",
+    "honorificSuffix",
+    "horizontalOverflow",
+    "host",
+    "hostCandidate",
+    "hostname",
+    "hour",
+    "hour12",
+    "hourCycle",
+    "hours",
+    "href",
+    "hrefTranslate",
+    "hreflang",
+    "hspace",
+    "html5TagCheckInerface",
+    "htmlFor",
+    "htmlText",
+    "httpEquiv",
+    "httpRequestStatusCode",
+    "hwTimestamp",
+    "hyphenate-character",
+    "hyphenateCharacter",
+    "hyphenateLimitChars",
+    "hyphens",
+    "hypot",
+    "i18n",
+    "ic",
+    "iccId",
+    "iceConnectionState",
+    "iceGatheringState",
+    "iceTransport",
+    "icon",
+    "iconURL",
+    "id",
+    "identifier",
+    "identity",
+    "ideographicBaseline",
+    "idle",
+    "idpLoginUrl",
+    "ignoreBOM",
+    "ignoreCase",
+    "ignoreDepthValues",
+    "image",
+    "image-orientation",
+    "image-rendering",
+    "imageHeight",
+    "imageOrientation",
+    "imageRendering",
+    "imageSizes",
+    "imageSmoothingEnabled",
+    "imageSmoothingQuality",
+    "imageSrcset",
+    "imageWidth",
+    "images",
+    "ime-mode",
+    "imeMode",
+    "implementation",
+    "importExternalTexture",
+    "importKey",
+    "importNode",
+    "importStylesheet",
+    "imports",
+    "impp",
+    "imul",
+    "in",
+    "in1",
+    "in2",
+    "inBandMetadataTrackDispatchType",
+    "inIncognitoContext",
+    "inRange",
+    "includes",
+    "incognito",
+    "incomingBidirectionalStreams",
+    "incomingHighWaterMark",
+    "incomingMaxAge",
+    "incomingUnidirectionalStreams",
+    "increaseZoomLevel",
+    "incremental",
+    "indeterminate",
+    "index",
+    "indexNames",
+    "indexOf",
+    "indexedDB",
+    "indicate",
+    "indices",
+    "inert",
+    "inertiaDestinationX",
+    "inertiaDestinationY",
+    "info",
+    "inherits",
+    "init",
+    "initAnimationEvent",
+    "initBeforeLoadEvent",
+    "initClipboardEvent",
+    "initCloseEvent",
+    "initCommandEvent",
+    "initCompositionEvent",
+    "initCustomEvent",
+    "initData",
+    "initDataType",
+    "initDeviceMotionEvent",
+    "initDeviceOrientationEvent",
+    "initDragEvent",
+    "initErrorEvent",
+    "initEvent",
+    "initFocusEvent",
+    "initGestureEvent",
+    "initHashChangeEvent",
+    "initKeyEvent",
+    "initKeyboardEvent",
+    "initMSManipulationEvent",
+    "initMessageEvent",
+    "initMouseEvent",
+    "initMouseScrollEvent",
+    "initMouseWheelEvent",
+    "initMutationEvent",
+    "initNSMouseEvent",
+    "initOverflowEvent",
+    "initPageEvent",
+    "initPageTransitionEvent",
+    "initPointerEvent",
+    "initPopStateEvent",
+    "initProgressEvent",
+    "initScrollAreaEvent",
+    "initSimpleGestureEvent",
+    "initStorageEvent",
+    "initTextEvent",
+    "initTimeEvent",
+    "initTouchEvent",
+    "initTransitionEvent",
+    "initUIEvent",
+    "initWebKitAnimationEvent",
+    "initWebKitTransitionEvent",
+    "initWebKitWheelEvent",
+    "initWheelEvent",
+    "initialTime",
+    "initialValue",
+    "initialize",
+    "initiatorType",
+    "inject",
+    "ink",
+    "inline-size",
+    "inlineSize",
+    "inlineVerticalFieldOfView",
+    "inner",
+    "innerHTML",
+    "innerHeight",
+    "innerText",
+    "innerWidth",
+    "input",
+    "inputBuffer",
+    "inputEncoding",
+    "inputMethod",
+    "inputMode",
+    "inputQuota",
+    "inputSource",
+    "inputSources",
+    "inputType",
+    "inputs",
+    "insertAdjacentElement",
+    "insertAdjacentHTML",
+    "insertAdjacentText",
+    "insertBefore",
+    "insertCell",
+    "insertDTMF",
+    "insertData",
+    "insertDebugMarker",
+    "insertItemBefore",
+    "insertNode",
+    "insertRow",
+    "insertRule",
+    "inset",
+    "inset-block",
+    "inset-block-end",
+    "inset-block-start",
+    "inset-inline",
+    "inset-inline-end",
+    "inset-inline-start",
+    "insetBlock",
+    "insetBlockEnd",
+    "insetBlockStart",
+    "insetInline",
+    "insetInlineEnd",
+    "insetInlineStart",
+    "inspect",
+    "install",
+    "installing",
+    "instanceRoot",
+    "instantiate",
+    "instantiateStreaming",
+    "instruments",
+    "int16",
+    "int32",
+    "int8",
+    "integrity",
+    "interactionCount",
+    "interactionId",
+    "interactionMode",
+    "intercept",
+    "interestForElement",
+    "interfaceClass",
+    "interfaceName",
+    "interfaceNumber",
+    "interfaceProtocol",
+    "interfaceSubclass",
+    "interfaces",
+    "interimResults",
+    "internalSubset",
+    "interpretation",
+    "intersection",
+    "intersectionRatio",
+    "intersectionRect",
+    "intersectsNode",
+    "interval",
+    "invalidIteratorState",
+    "invalidateFramebuffer",
+    "invalidateSubFramebuffer",
+    "inverse",
+    "invertSelf",
+    "invoker",
+    "invokerType",
+    "is",
+    "is2D",
+    "isActive",
+    "isAllowedFileSchemeAccess",
+    "isAllowedIncognitoAccess",
+    "isAlternate",
+    "isArray",
+    "isAutoSelected",
+    "isBingCurrentSearchDefault",
+    "isBuffer",
+    "isCandidateWindowVisible",
+    "isChar",
+    "isCollapsed",
+    "isComposing",
+    "isConcatSpreadable",
+    "isConditionalMediationAvailable",
+    "isConfigSupported",
+    "isConnected",
+    "isContentEditable",
+    "isContentHandlerRegistered",
+    "isContextLost",
+    "isDefaultNamespace",
+    "isDirectory",
+    "isDisabled",
+    "isDisjointFrom",
+    "isEnabled",
+    "isEqual",
+    "isEqualNode",
+    "isError",
+    "isExtended",
+    "isExtensible",
+    "isExternalCTAP2SecurityKeySupported",
+    "isFallbackAdapter",
+    "isFile",
+    "isFinite",
+    "isFirstPersonObserver",
+    "isFramebuffer",
+    "isFrozen",
+    "isGenerator",
+    "isHTML",
+    "isHistoryNavigation",
+    "isId",
+    "isIdentity",
+    "isInjected",
+    "isInputPending",
+    "isInteger",
+    "isInternal",
+    "isIntersecting",
+    "isLockFree",
+    "isMap",
+    "isMultiLine",
+    "isNaN",
+    "isOpen",
+    "isPointInFill",
+    "isPointInPath",
+    "isPointInRange",
+    "isPointInStroke",
+    "isPrefAlternate",
+    "isPresenting",
+    "isPrimary",
+    "isProgram",
+    "isPropertyImplicit",
+    "isProtocolHandlerRegistered",
+    "isPrototypeOf",
+    "isQuery",
+    "isRawJSON",
+    "isRenderbuffer",
+    "isSafeInteger",
+    "isSameEntry",
+    "isSameNode",
+    "isSampler",
+    "isScript",
+    "isScriptURL",
+    "isSealed",
+    "isSecureContext",
+    "isSessionSupported",
+    "isShader",
+    "isSubsetOf",
+    "isSupersetOf",
+    "isSupported",
+    "isSync",
+    "isTextEdit",
+    "isTexture",
+    "isTransformFeedback",
+    "isTrusted",
+    "isTypeSupported",
+    "isUserVerifyingPlatformAuthenticatorAvailable",
+    "isVertexArray",
+    "isView",
+    "isVisible",
+    "isWellFormed",
+    "isochronousTransferIn",
+    "isochronousTransferOut",
+    "isolation",
+    "italics",
+    "item",
+    "itemId",
+    "itemProp",
+    "itemRef",
+    "itemScope",
+    "itemType",
+    "itemValue",
+    "items",
+    "iterateNext",
+    "iterationComposite",
+    "iterator",
+    "javaEnabled",
+    "jitterBufferTarget",
+    "jobTitle",
+    "join",
+    "joinAdInterestGroup",
+    "jointName",
+    "json",
+    "justify-content",
+    "justify-items",
+    "justify-self",
+    "justifyContent",
+    "justifyItems",
+    "justifySelf",
+    "k1",
+    "k2",
+    "k3",
+    "k4",
+    "kHz",
+    "keepalive",
+    "kernelMatrix",
+    "kernelUnitLengthX",
+    "kernelUnitLengthY",
+    "kerning",
+    "key",
+    "keyCode",
+    "keyFor",
+    "keyIdentifier",
+    "keyLightEnabled",
+    "keyLocation",
+    "keyPath",
+    "keyStatuses",
+    "keySystem",
+    "keyText",
+    "keyUsage",
+    "keyboard",
+    "keys",
+    "keytype",
+    "kind",
+    "knee",
+    "knownSources",
+    "label",
+    "labels",
+    "lang",
+    "language",
+    "languages",
+    "largeArcFlag",
+    "last",
+    "lastChild",
+    "lastElementChild",
+    "lastError",
+    "lastEventId",
+    "lastIndex",
+    "lastIndexOf",
+    "lastInputTime",
+    "lastMatch",
+    "lastMessageSubject",
+    "lastMessageType",
+    "lastModified",
+    "lastModifiedDate",
+    "lastPage",
+    "lastParen",
+    "lastState",
+    "lastStyleSheetSet",
+    "latency",
+    "latitude",
+    "launchQueue",
+    "layerName",
+    "layerX",
+    "layerY",
+    "layout",
+    "layoutFlow",
+    "layoutGrid",
+    "layoutGridChar",
+    "layoutGridLine",
+    "layoutGridMode",
+    "layoutGridType",
+    "lbound",
+    "leaveAdInterestGroup",
+    "left",
+    "leftContext",
+    "leftDegrees",
+    "leftMargin",
+    "leftProjectionMatrix",
+    "leftViewMatrix",
+    "length",
+    "lengthAdjust",
+    "lengthComputable",
+    "letter-spacing",
+    "letterSpacing",
+    "level",
+    "lh",
+    "lighting-color",
+    "lightingColor",
+    "limitingConeAngle",
+    "limits",
+    "line",
+    "line-break",
+    "line-height",
+    "lineAlign",
+    "lineBreak",
+    "lineCap",
+    "lineDashOffset",
+    "lineGapOverride",
+    "lineHeight",
+    "lineJoin",
+    "lineNum",
+    "lineNumber",
+    "linePos",
+    "lineTo",
+    "lineWidth",
+    "linearAcceleration",
+    "linearRampToValueAtTime",
+    "linearVelocity",
+    "lineno",
+    "lines",
+    "link",
+    "linkColor",
+    "linkProgram",
+    "links",
+    "list",
+    "list-style",
+    "list-style-image",
+    "list-style-position",
+    "list-style-type",
+    "listStyle",
+    "listStyleImage",
+    "listStylePosition",
+    "listStyleType",
+    "listener",
+    "listeners",
+    "load",
+    "loadEventEnd",
+    "loadEventStart",
+    "loadOp",
+    "loadTime",
+    "loadTimes",
+    "loaded",
+    "loading",
+    "localDescription",
+    "localName",
+    "localService",
+    "localStorage",
+    "locale",
+    "localeCompare",
+    "location",
+    "locationbar",
+    "lock",
+    "locked",
+    "lockedFile",
+    "locks",
+    "lodMaxClamp",
+    "lodMinClamp",
+    "log",
+    "log10",
+    "log1p",
+    "log2",
+    "logicalXDPI",
+    "logicalYDPI",
+    "login",
+    "loglevel",
+    "longDesc",
+    "longitude",
+    "lookupNamespaceURI",
+    "lookupPrefix",
+    "loop",
+    "loopEnd",
+    "loopStart",
+    "looping",
+    "lost",
+    "low",
+    "lower",
+    "lowerBound",
+    "lowerOpen",
+    "lowsrc",
+    "lvb",
+    "lvh",
+    "lvi",
+    "lvmax",
+    "lvmin",
+    "lvw",
+    "m11",
+    "m12",
+    "m13",
+    "m14",
+    "m21",
+    "m22",
+    "m23",
+    "m24",
+    "m31",
+    "m32",
+    "m33",
+    "m34",
+    "m41",
+    "m42",
+    "m43",
+    "m44",
+    "magFilter",
+    "makeXRCompatible",
+    "managed",
+    "management",
+    "manifest",
+    "manufacturer",
+    "manufacturerName",
+    "map",
+    "mapAsync",
+    "mapState",
+    "mappedAtCreation",
+    "mapping",
+    "margin",
+    "margin-block",
+    "margin-block-end",
+    "margin-block-start",
+    "margin-bottom",
+    "margin-inline",
+    "margin-inline-end",
+    "margin-inline-start",
+    "margin-left",
+    "margin-right",
+    "margin-top",
+    "marginBlock",
+    "marginBlockEnd",
+    "marginBlockStart",
+    "marginBottom",
+    "marginHeight",
+    "marginInline",
+    "marginInlineEnd",
+    "marginInlineStart",
+    "marginLeft",
+    "marginRight",
+    "marginTop",
+    "marginWidth",
+    "mark",
+    "marker",
+    "marker-end",
+    "marker-mid",
+    "marker-offset",
+    "marker-start",
+    "markerEnd",
+    "markerHeight",
+    "markerMid",
+    "markerOffset",
+    "markerStart",
+    "markerUnits",
+    "markerWidth",
+    "marks",
+    "mask",
+    "mask-clip",
+    "mask-composite",
+    "mask-image",
+    "mask-mode",
+    "mask-origin",
+    "mask-position",
+    "mask-position-x",
+    "mask-position-y",
+    "mask-repeat",
+    "mask-size",
+    "mask-type",
+    "maskClip",
+    "maskComposite",
+    "maskContentUnits",
+    "maskImage",
+    "maskMode",
+    "maskOrigin",
+    "maskPosition",
+    "maskPositionX",
+    "maskPositionY",
+    "maskRepeat",
+    "maskSize",
+    "maskType",
+    "maskUnits",
+    "match",
+    "matchAll",
+    "matchMedia",
+    "matchMedium",
+    "matchPatterns",
+    "matches",
+    "math-depth",
+    "math-style",
+    "mathDepth",
+    "mathShift",
+    "mathStyle",
+    "matrix",
+    "matrixTransform",
+    "max",
+    "max-block-size",
+    "max-height",
+    "max-inline-size",
+    "max-width",
+    "maxActions",
+    "maxAlternatives",
+    "maxAnisotropy",
+    "maxBindGroups",
+    "maxBindGroupsPlusVertexBuffers",
+    "maxBindingsPerBindGroup",
+    "maxBlockSize",
+    "maxBufferSize",
+    "maxByteLength",
+    "maxChannelCount",
+    "maxChannels",
+    "maxColorAttachmentBytesPerSample",
+    "maxColorAttachments",
+    "maxComputeInvocationsPerWorkgroup",
+    "maxComputeWorkgroupSizeX",
+    "maxComputeWorkgroupSizeY",
+    "maxComputeWorkgroupSizeZ",
+    "maxComputeWorkgroupStorageSize",
+    "maxComputeWorkgroupsPerDimension",
+    "maxConnectionsPerServer",
+    "maxDatagramSize",
+    "maxDecibels",
+    "maxDistance",
+    "maxDrawCount",
+    "maxDynamicStorageBuffersPerPipelineLayout",
+    "maxDynamicUniformBuffersPerPipelineLayout",
+    "maxHeight",
+    "maxInlineSize",
+    "maxInterStageShaderComponents",
+    "maxInterStageShaderVariables",
+    "maxLayers",
+    "maxLength",
+    "maxMessageSize",
+    "maxPacketLifeTime",
+    "maxRetransmits",
+    "maxSampledTexturesPerShaderStage",
+    "maxSamplersPerShaderStage",
+    "maxStorageBufferBindingSize",
+    "maxStorageBuffersPerShaderStage",
+    "maxStorageTexturesPerShaderStage",
+    "maxTextureArrayLayers",
+    "maxTextureDimension1D",
+    "maxTextureDimension2D",
+    "maxTextureDimension3D",
+    "maxTouchPoints",
+    "maxUniformBufferBindingSize",
+    "maxUniformBuffersPerShaderStage",
+    "maxValue",
+    "maxVertexAttributes",
+    "maxVertexBufferArrayStride",
+    "maxVertexBuffers",
+    "maxWidth",
+    "maximumLatency",
+    "measure",
+    "measureInputUsage",
+    "measureText",
+    "media",
+    "mediaCapabilities",
+    "mediaDevices",
+    "mediaElement",
+    "mediaGroup",
+    "mediaKeys",
+    "mediaSession",
+    "mediaStream",
+    "mediaText",
+    "meetOrSlice",
+    "memory",
+    "menubar",
+    "menus",
+    "menusChild",
+    "menusInternal",
+    "mergeAttributes",
+    "message",
+    "messageClass",
+    "messageHandlers",
+    "messageType",
+    "messages",
+    "metaKey",
+    "metadata",
+    "method",
+    "methodDetails",
+    "methodName",
+    "microseconds",
+    "mid",
+    "milliseconds",
+    "mimeType",
+    "mimeTypes",
+    "min",
+    "min-block-size",
+    "min-height",
+    "min-inline-size",
+    "min-width",
+    "minBindingSize",
+    "minBlockSize",
+    "minDecibels",
+    "minFilter",
+    "minHeight",
+    "minInlineSize",
+    "minLength",
+    "minStorageBufferOffsetAlignment",
+    "minUniformBufferOffsetAlignment",
+    "minValue",
+    "minWidth",
+    "minimumLatency",
+    "minute",
+    "minutes",
+    "mipLevel",
+    "mipLevelCount",
+    "mipmapFilter",
+    "miterLimit",
+    "mix-blend-mode",
+    "mixBlendMode",
+    "mm",
+    "mobile",
+    "mode",
+    "model",
+    "modify",
+    "module",
+    "month",
+    "months",
+    "mount",
+    "move",
+    "moveBefore",
+    "moveBy",
+    "moveEnd",
+    "moveFirst",
+    "moveFocusDown",
+    "moveFocusLeft",
+    "moveFocusRight",
+    "moveFocusUp",
+    "moveInSuccession",
+    "moveNext",
+    "moveRow",
+    "moveStart",
+    "moveTo",
+    "moveToBookmark",
+    "moveToElementText",
+    "moveToPoint",
+    "movementX",
+    "movementY",
+    "mozAdd",
+    "mozAnimationStartTime",
+    "mozAnon",
+    "mozApps",
+    "mozAudioCaptured",
+    "mozAudioChannelType",
+    "mozAutoplayEnabled",
+    "mozCancelAnimationFrame",
+    "mozCancelFullScreen",
+    "mozCancelRequestAnimationFrame",
+    "mozCaptureStream",
+    "mozCaptureStreamUntilEnded",
+    "mozClearDataAt",
+    "mozContact",
+    "mozContacts",
+    "mozCreateFileHandle",
+    "mozCurrentTransform",
+    "mozCurrentTransformInverse",
+    "mozCursor",
+    "mozDash",
+    "mozDashOffset",
+    "mozDecodedFrames",
+    "mozExitPointerLock",
+    "mozFillRule",
+    "mozFragmentEnd",
+    "mozFrameDelay",
+    "mozFullScreen",
+    "mozFullScreenElement",
+    "mozFullScreenEnabled",
+    "mozGetAll",
+    "mozGetAllKeys",
+    "mozGetAsFile",
+    "mozGetDataAt",
+    "mozGetMetadata",
+    "mozGetUserMedia",
+    "mozHasAudio",
+    "mozHasItem",
+    "mozHidden",
+    "mozImageSmoothingEnabled",
+    "mozIndexedDB",
+    "mozInnerScreenX",
+    "mozInnerScreenY",
+    "mozInputSource",
+    "mozIsTextField",
+    "mozItem",
+    "mozItemCount",
+    "mozItems",
+    "mozLength",
+    "mozLockOrientation",
+    "mozMatchesSelector",
+    "mozMovementX",
+    "mozMovementY",
+    "mozOpaque",
+    "mozOrientation",
+    "mozPaintCount",
+    "mozPaintedFrames",
+    "mozParsedFrames",
+    "mozPay",
+    "mozPointerLockElement",
+    "mozPresentedFrames",
+    "mozPreservesPitch",
+    "mozPressure",
+    "mozPrintCallback",
+    "mozRTCIceCandidate",
+    "mozRTCPeerConnection",
+    "mozRTCSessionDescription",
+    "mozRemove",
+    "mozRequestAnimationFrame",
+    "mozRequestFullScreen",
+    "mozRequestPointerLock",
+    "mozSetDataAt",
+    "mozSetImageElement",
+    "mozSourceNode",
+    "mozSrcObject",
+    "mozSystem",
+    "mozTCPSocket",
+    "mozTextStyle",
+    "mozTypesAt",
+    "mozUnlockOrientation",
+    "mozUserCancelled",
+    "mozVisibilityState",
+    "ms",
+    "msAnimation",
+    "msAnimationDelay",
+    "msAnimationDirection",
+    "msAnimationDuration",
+    "msAnimationFillMode",
+    "msAnimationIterationCount",
+    "msAnimationName",
+    "msAnimationPlayState",
+    "msAnimationStartTime",
+    "msAnimationTimingFunction",
+    "msBackfaceVisibility",
+    "msBlockProgression",
+    "msCSSOMElementFloatMetrics",
+    "msCaching",
+    "msCachingEnabled",
+    "msCancelRequestAnimationFrame",
+    "msCapsLockWarningOff",
+    "msClearImmediate",
+    "msClose",
+    "msContentZoomChaining",
+    "msContentZoomFactor",
+    "msContentZoomLimit",
+    "msContentZoomLimitMax",
+    "msContentZoomLimitMin",
+    "msContentZoomSnap",
+    "msContentZoomSnapPoints",
+    "msContentZoomSnapType",
+    "msContentZooming",
+    "msConvertURL",
+    "msCrypto",
+    "msDoNotTrack",
+    "msElementsFromPoint",
+    "msElementsFromRect",
+    "msExitFullscreen",
+    "msExtendedCode",
+    "msFillRule",
+    "msFirstPaint",
+    "msFlex",
+    "msFlexAlign",
+    "msFlexDirection",
+    "msFlexFlow",
+    "msFlexItemAlign",
+    "msFlexLinePack",
+    "msFlexNegative",
+    "msFlexOrder",
+    "msFlexPack",
+    "msFlexPositive",
+    "msFlexPreferredSize",
+    "msFlexWrap",
+    "msFlowFrom",
+    "msFlowInto",
+    "msFontFeatureSettings",
+    "msFullscreenElement",
+    "msFullscreenEnabled",
+    "msGetInputContext",
+    "msGetRegionContent",
+    "msGetUntransformedBounds",
+    "msGraphicsTrustStatus",
+    "msGridColumn",
+    "msGridColumnAlign",
+    "msGridColumnSpan",
+    "msGridColumns",
+    "msGridRow",
+    "msGridRowAlign",
+    "msGridRowSpan",
+    "msGridRows",
+    "msHidden",
+    "msHighContrastAdjust",
+    "msHyphenateLimitChars",
+    "msHyphenateLimitLines",
+    "msHyphenateLimitZone",
+    "msHyphens",
+    "msImageSmoothingEnabled",
+    "msImeAlign",
+    "msIndexedDB",
+    "msInterpolationMode",
+    "msIsStaticHTML",
+    "msKeySystem",
+    "msKeys",
+    "msLaunchUri",
+    "msLockOrientation",
+    "msManipulationViewsEnabled",
+    "msMatchMedia",
+    "msMatchesSelector",
+    "msMaxTouchPoints",
+    "msOrientation",
+    "msOverflowStyle",
+    "msPerspective",
+    "msPerspectiveOrigin",
+    "msPlayToDisabled",
+    "msPlayToPreferredSourceUri",
+    "msPlayToPrimary",
+    "msPointerEnabled",
+    "msRegionOverflow",
+    "msReleasePointerCapture",
+    "msRequestAnimationFrame",
+    "msRequestFullscreen",
+    "msSaveBlob",
+    "msSaveOrOpenBlob",
+    "msScrollChaining",
+    "msScrollLimit",
+    "msScrollLimitXMax",
+    "msScrollLimitXMin",
+    "msScrollLimitYMax",
+    "msScrollLimitYMin",
+    "msScrollRails",
+    "msScrollSnapPointsX",
+    "msScrollSnapPointsY",
+    "msScrollSnapType",
+    "msScrollSnapX",
+    "msScrollSnapY",
+    "msScrollTranslation",
+    "msSetImmediate",
+    "msSetMediaKeys",
+    "msSetPointerCapture",
+    "msTextCombineHorizontal",
+    "msTextSizeAdjust",
+    "msToBlob",
+    "msTouchAction",
+    "msTouchSelect",
+    "msTraceAsyncCallbackCompleted",
+    "msTraceAsyncCallbackStarting",
+    "msTraceAsyncOperationCompleted",
+    "msTraceAsyncOperationStarting",
+    "msTransform",
+    "msTransformOrigin",
+    "msTransformStyle",
+    "msTransition",
+    "msTransitionDelay",
+    "msTransitionDuration",
+    "msTransitionProperty",
+    "msTransitionTimingFunction",
+    "msUnlockOrientation",
+    "msUpdateAsyncCallbackRelation",
+    "msUserSelect",
+    "msVisibilityState",
+    "msWrapFlow",
+    "msWrapMargin",
+    "msWrapThrough",
+    "msWriteProfilerMark",
+    "msZoom",
+    "msZoomTo",
+    "mt",
+    "mul",
+    "multiEntry",
+    "multiSelectionObj",
+    "multiline",
+    "multiple",
+    "multiply",
+    "multiplySelf",
+    "multisample",
+    "multisampled",
+    "mutableFile",
+    "muted",
+    "n",
+    "nacl_arch",
+    "name",
+    "nameList",
+    "nameProp",
+    "namedItem",
+    "namedRecordset",
+    "names",
+    "namespaceURI",
+    "namespaces",
+    "nanoseconds",
+    "nativeApplication",
+    "nativeMap",
+    "nativeObjectCreate",
+    "nativeSet",
+    "nativeWeakMap",
+    "naturalHeight",
+    "naturalWidth",
+    "navigate",
+    "navigation",
+    "navigationMode",
+    "navigationPreload",
+    "navigationStart",
+    "navigationType",
+    "navigator",
+    "near",
+    "nearestViewportElement",
+    "negative",
+    "negotiated",
+    "netscape",
+    "networkState",
+    "networkStatus",
+    "newScale",
+    "newState",
+    "newTranslate",
+    "newURL",
+    "newValue",
+    "newValueSpecifiedUnits",
+    "newVersion",
+    "newhome",
+    "next",
+    "nextElementSibling",
+    "nextHopProtocol",
+    "nextNode",
+    "nextPage",
+    "nextSibling",
+    "nickname",
+    "noHref",
+    "noModule",
+    "noResize",
+    "noShade",
+    "noValidate",
+    "noWrap",
+    "node",
+    "nodeName",
+    "nodeType",
+    "nodeValue",
+    "nonce",
+    "normDepthBufferFromNormView",
+    "normalize",
+    "normalizedPathSegList",
+    "normandyAddonStudy",
+    "notRestoredReasons",
+    "notationName",
+    "notations",
+    "note",
+    "noteGrainOn",
+    "noteOff",
+    "noteOn",
+    "notifications",
+    "notify",
+    "now",
+    "npnNegotiatedProtocol",
+    "numOctaves",
+    "number",
+    "numberOfChannels",
+    "numberOfFrames",
+    "numberOfInputs",
+    "numberOfItems",
+    "numberOfOutputs",
+    "numberValue",
+    "numberingSystem",
+    "numeric",
+    "oMatchesSelector",
+    "object",
+    "object-fit",
+    "object-position",
+    "objectFit",
+    "objectPosition",
+    "objectStore",
+    "objectStoreNames",
+    "objectType",
+    "observe",
+    "observedAttributes",
+    "occlusionQuerySet",
+    "of",
+    "off",
+    "offscreenBuffering",
+    "offset",
+    "offset-anchor",
+    "offset-distance",
+    "offset-path",
+    "offset-position",
+    "offset-rotate",
+    "offsetAnchor",
+    "offsetDistance",
+    "offsetHeight",
+    "offsetLeft",
+    "offsetNode",
+    "offsetParent",
+    "offsetPath",
+    "offsetPosition",
+    "offsetRotate",
+    "offsetTop",
+    "offsetWidth",
+    "offsetX",
+    "offsetY",
+    "ok",
+    "oldState",
+    "oldURL",
+    "oldValue",
+    "oldVersion",
+    "olderShadowRoot",
+    "omnibox",
+    "on",
+    "onActivated",
+    "onAdded",
+    "onAttached",
+    "onBoundsChanged",
+    "onBrowserUpdateAvailable",
+    "onClicked",
+    "onCommitFiberRoot",
+    "onCommitFiberUnmount",
+    "onConnect",
+    "onConnectExternal",
+    "onConnectNative",
+    "onCreated",
+    "onDetached",
+    "onDisabled",
+    "onEnabled",
+    "onFocusChanged",
+    "onHighlighted",
+    "onInstalled",
+    "onLine",
+    "onMessage",
+    "onMessageExternal",
+    "onMoved",
+    "onPerformanceWarning",
+    "onPostCommitFiberRoot",
+    "onRemoved",
+    "onReplaced",
+    "onRestartRequired",
+    "onStartup",
+    "onSubmittedWorkDone",
+    "onSuspend",
+    "onSuspendCanceled",
+    "onUninstalled",
+    "onUpdateAvailable",
+    "onUpdated",
+    "onUserScriptConnect",
+    "onUserScriptMessage",
+    "onUserSettingsChanged",
+    "onZoomChange",
+    "onabort",
+    "onabsolutedeviceorientation",
+    "onactivate",
+    "onactive",
+    "onaddsourcebuffer",
+    "onaddstream",
+    "onaddtrack",
+    "onafterprint",
+    "onafterscriptexecute",
+    "onafterupdate",
+    "onanimationcancel",
+    "onanimationend",
+    "onanimationiteration",
+    "onanimationstart",
+    "onappinstalled",
+    "onaudioend",
+    "onaudioprocess",
+    "onaudiostart",
+    "onautocomplete",
+    "onautocompleteerror",
+    "onauxclick",
+    "onbeforeactivate",
+    "onbeforecopy",
+    "onbeforecut",
+    "onbeforedeactivate",
+    "onbeforeeditfocus",
+    "onbeforeinput",
+    "onbeforeinstallprompt",
+    "onbeforematch",
+    "onbeforepaste",
+    "onbeforeprint",
+    "onbeforescriptexecute",
+    "onbeforetoggle",
+    "onbeforeunload",
+    "onbeforeupdate",
+    "onbeforexrselect",
+    "onbegin",
+    "onblocked",
+    "onblur",
+    "onbounce",
+    "onboundary",
+    "onbufferedamountlow",
+    "oncached",
+    "oncancel",
+    "oncandidatewindowhide",
+    "oncandidatewindowshow",
+    "oncandidatewindowupdate",
+    "oncanplay",
+    "oncanplaythrough",
+    "oncapturehandlechange",
+    "once",
+    "oncellchange",
+    "onchange",
+    "oncharacterboundsupdate",
+    "oncharacteristicvaluechanged",
+    "onchargingchange",
+    "onchargingtimechange",
+    "onchecking",
+    "onclick",
+    "onclose",
+    "onclosing",
+    "oncommand",
+    "oncompassneedscalibration",
+    "oncomplete",
+    "oncompositionend",
+    "oncompositionstart",
+    "onconnect",
+    "onconnecting",
+    "onconnectionavailable",
+    "onconnectionstatechange",
+    "oncontentvisibilityautostatechange",
+    "oncontextlost",
+    "oncontextmenu",
+    "oncontextrestored",
+    "oncontrollerchange",
+    "oncontrolselect",
+    "oncopy",
+    "oncuechange",
+    "oncurrententrychange",
+    "oncurrentscreenchange",
+    "oncut",
+    "ondataavailable",
+    "ondatachannel",
+    "ondatasetchanged",
+    "ondatasetcomplete",
+    "ondblclick",
+    "ondeactivate",
+    "ondequeue",
+    "ondevicechange",
+    "ondevicelight",
+    "ondevicemotion",
+    "ondeviceorientation",
+    "ondeviceorientationabsolute",
+    "ondeviceproximity",
+    "ondischargingtimechange",
+    "ondisconnect",
+    "ondisplay",
+    "ondispose",
+    "ondownloading",
+    "ondownloadprogress",
+    "ondrag",
+    "ondragend",
+    "ondragenter",
+    "ondragexit",
+    "ondragleave",
+    "ondragover",
+    "ondragstart",
+    "ondrop",
+    "ondurationchange",
+    "onemptied",
+    "onencrypted",
+    "onend",
+    "onended",
+    "onenter",
+    "onenterpictureinpicture",
+    "onerror",
+    "onerrorupdate",
+    "onexit",
+    "onfencedtreeclick",
+    "onfilterchange",
+    "onfinish",
+    "onfocus",
+    "onfocusin",
+    "onfocusout",
+    "onformdata",
+    "onfreeze",
+    "onfullscreenchange",
+    "onfullscreenerror",
+    "ongamepadconnected",
+    "ongamepaddisconnected",
+    "ongatheringstatechange",
+    "ongattserverdisconnected",
+    "ongeometrychange",
+    "ongesturechange",
+    "ongestureend",
+    "ongesturestart",
+    "ongotpointercapture",
+    "onhashchange",
+    "onhelp",
+    "onicecandidate",
+    "onicecandidateerror",
+    "oniceconnectionstatechange",
+    "onicegatheringstatechange",
+    "oninactive",
+    "oninput",
+    "oninputreport",
+    "oninputsourceschange",
+    "oninvalid",
+    "onkeydown",
+    "onkeypress",
+    "onkeystatuseschange",
+    "onkeyup",
+    "onlanguagechange",
+    "onlayoutcomplete",
+    "onleavepictureinpicture",
+    "onlevelchange",
+    "onload",
+    "onloadT",
+    "onloadeddata",
+    "onloadedmetadata",
+    "onloadend",
+    "onloading",
+    "onloadingdone",
+    "onloadingerror",
+    "onloadstart",
+    "onlosecapture",
+    "onlostpointercapture",
+    "only",
+    "onmanagedconfigurationchange",
+    "onmark",
+    "onmessage",
+    "onmessageerror",
+    "onmidimessage",
+    "onmousedown",
+    "onmouseenter",
+    "onmouseleave",
+    "onmousemove",
+    "onmouseout",
+    "onmouseover",
+    "onmouseup",
+    "onmousewheel",
+    "onmove",
+    "onmoveend",
+    "onmovestart",
+    "onmozfullscreenchange",
+    "onmozfullscreenerror",
+    "onmozorientationchange",
+    "onmozpointerlockchange",
+    "onmozpointerlockerror",
+    "onmscontentzoom",
+    "onmsfullscreenchange",
+    "onmsfullscreenerror",
+    "onmsgesturechange",
+    "onmsgesturedoubletap",
+    "onmsgestureend",
+    "onmsgesturehold",
+    "onmsgesturestart",
+    "onmsgesturetap",
+    "onmsgotpointercapture",
+    "onmsinertiastart",
+    "onmslostpointercapture",
+    "onmsmanipulationstatechanged",
+    "onmsneedkey",
+    "onmsorientationchange",
+    "onmspointercancel",
+    "onmspointerdown",
+    "onmspointerenter",
+    "onmspointerhover",
+    "onmspointerleave",
+    "onmspointermove",
+    "onmspointerout",
+    "onmspointerover",
+    "onmspointerup",
+    "onmssitemodejumplistitemremoved",
+    "onmsthumbnailclick",
+    "onmute",
+    "onnavigate",
+    "onnavigateerror",
+    "onnavigatesuccess",
+    "onnegotiationneeded",
+    "onnomatch",
+    "onnoupdate",
+    "onobsolete",
+    "onoffline",
+    "ononline",
+    "onopen",
+    "onorientationchange",
+    "onpagechange",
+    "onpagehide",
+    "onpagereveal",
+    "onpageshow",
+    "onpageswap",
+    "onpaste",
+    "onpause",
+    "onpayerdetailchange",
+    "onpaymentmethodchange",
+    "onplay",
+    "onplaying",
+    "onpluginstreamstart",
+    "onpointercancel",
+    "onpointerdown",
+    "onpointerenter",
+    "onpointerleave",
+    "onpointerlockchange",
+    "onpointerlockerror",
+    "onpointermove",
+    "onpointerout",
+    "onpointerover",
+    "onpointerrawupdate",
+    "onpointerup",
+    "onpopstate",
+    "onprerenderingchange",
+    "onprioritychange",
+    "onprocessorerror",
+    "onprogress",
+    "onpropertychange",
+    "onratechange",
+    "onreading",
+    "onreadystatechange",
+    "onreflectionchange",
+    "onrejectionhandled",
+    "onrelease",
+    "onremove",
+    "onremovesourcebuffer",
+    "onremovestream",
+    "onremovetrack",
+    "onrepeat",
+    "onreset",
+    "onresize",
+    "onresizeend",
+    "onresizestart",
+    "onresourcetimingbufferfull",
+    "onresult",
+    "onresume",
+    "onrowenter",
+    "onrowexit",
+    "onrowsdelete",
+    "onrowsinserted",
+    "onscreenschange",
+    "onscroll",
+    "onscrollend",
+    "onscrollsnapchange",
+    "onscrollsnapchanging",
+    "onsearch",
+    "onsecuritypolicyviolation",
+    "onseeked",
+    "onseeking",
+    "onselect",
+    "onselectedcandidatepairchange",
+    "onselectend",
+    "onselectionchange",
+    "onselectstart",
+    "onshippingaddresschange",
+    "onshippingoptionchange",
+    "onshow",
+    "onsignalingstatechange",
+    "onsinkchange",
+    "onslotchange",
+    "onsoundend",
+    "onsoundstart",
+    "onsourceclose",
+    "onsourceclosed",
+    "onsourceended",
+    "onsourceopen",
+    "onspeechend",
+    "onspeechstart",
+    "onsqueeze",
+    "onsqueezeend",
+    "onsqueezestart",
+    "onstalled",
+    "onstart",
+    "onstatechange",
+    "onstop",
+    "onstorage",
+    "onstoragecommit",
+    "onsubmit",
+    "onsuccess",
+    "onsuspend",
+    "onterminate",
+    "ontextformatupdate",
+    "ontextinput",
+    "ontextupdate",
+    "ontimeout",
+    "ontimeupdate",
+    "ontoggle",
+    "ontonechange",
+    "ontouchcancel",
+    "ontouchend",
+    "ontouchmove",
+    "ontouchstart",
+    "ontrack",
+    "ontransitioncancel",
+    "ontransitionend",
+    "ontransitionrun",
+    "ontransitionstart",
+    "onuncapturederror",
+    "onunhandledrejection",
+    "onunload",
+    "onunmute",
+    "onupdate",
+    "onupdateend",
+    "onupdatefound",
+    "onupdateready",
+    "onupdatestart",
+    "onupgradeneeded",
+    "onuserproximity",
+    "onversionchange",
+    "onvisibilitychange",
+    "onvoiceschanged",
+    "onvolumechange",
+    "onvrdisplayactivate",
+    "onvrdisplayconnect",
+    "onvrdisplaydeactivate",
+    "onvrdisplaydisconnect",
+    "onvrdisplaypresentchange",
+    "onwaiting",
+    "onwaitingforkey",
+    "onwarning",
+    "onwebkitanimationend",
+    "onwebkitanimationiteration",
+    "onwebkitanimationstart",
+    "onwebkitcurrentplaybacktargetiswirelesschanged",
+    "onwebkitfullscreenchange",
+    "onwebkitfullscreenerror",
+    "onwebkitkeyadded",
+    "onwebkitkeyerror",
+    "onwebkitkeymessage",
+    "onwebkitneedkey",
+    "onwebkitorientationchange",
+    "onwebkitplaybacktargetavailabilitychanged",
+    "onwebkitpointerlockchange",
+    "onwebkitpointerlockerror",
+    "onwebkitresourcetimingbufferfull",
+    "onwebkittransitionend",
+    "onwheel",
+    "onzoom",
+    "onzoomlevelchange",
+    "opacity",
+    "open",
+    "openCursor",
+    "openDatabase",
+    "openKeyCursor",
+    "openOptionsPage",
+    "openOrClosedShadowRoot",
+    "openPopup",
+    "opened",
+    "opener",
+    "opera",
+    "operation",
+    "operationType",
+    "operator",
+    "opr",
+    "optimum",
+    "options",
+    "or",
+    "order",
+    "orderX",
+    "orderY",
+    "ordered",
+    "org",
+    "organization",
+    "orient",
+    "orientAngle",
+    "orientType",
+    "orientation",
+    "orientationX",
+    "orientationY",
+    "orientationZ",
+    "origin",
+    "originAgentCluster",
+    "originalPolicy",
+    "originalTarget",
+    "ornaments",
+    "orphans",
+    "os",
+    "oscpu",
+    "outerHTML",
+    "outerHeight",
+    "outerText",
+    "outerWidth",
+    "outgoingHighWaterMark",
+    "outgoingMaxAge",
+    "outline",
+    "outline-color",
+    "outline-offset",
+    "outline-style",
+    "outline-width",
+    "outlineColor",
+    "outlineOffset",
+    "outlineStyle",
+    "outlineWidth",
+    "outputBuffer",
+    "outputChannelCount",
+    "outputLanguage",
+    "outputLatency",
+    "outputs",
+    "overallProgress",
+    "overflow",
+    "overflow-anchor",
+    "overflow-block",
+    "overflow-clip-margin",
+    "overflow-inline",
+    "overflow-wrap",
+    "overflow-x",
+    "overflow-y",
+    "overflowAnchor",
+    "overflowBlock",
+    "overflowClipMargin",
+    "overflowInline",
+    "overflowWrap",
+    "overflowX",
+    "overflowY",
+    "overlaysContent",
+    "overrideColors",
+    "overrideMimeType",
+    "oversample",
+    "overscroll-behavior",
+    "overscroll-behavior-block",
+    "overscroll-behavior-inline",
+    "overscroll-behavior-x",
+    "overscroll-behavior-y",
+    "overscrollBehavior",
+    "overscrollBehaviorBlock",
+    "overscrollBehaviorInline",
+    "overscrollBehaviorX",
+    "overscrollBehaviorY",
+    "ownKeys",
+    "ownerDocument",
+    "ownerElement",
+    "ownerNode",
+    "ownerRule",
+    "ownerSVGElement",
+    "owningElement",
+    "p1",
+    "p2",
+    "p3",
+    "p4",
+    "packetSize",
+    "packets",
+    "pad",
+    "padEnd",
+    "padStart",
+    "padding",
+    "padding-block",
+    "padding-block-end",
+    "padding-block-start",
+    "padding-bottom",
+    "padding-inline",
+    "padding-inline-end",
+    "padding-inline-start",
+    "padding-left",
+    "padding-right",
+    "padding-top",
+    "paddingBlock",
+    "paddingBlockEnd",
+    "paddingBlockStart",
+    "paddingBottom",
+    "paddingInline",
+    "paddingInlineEnd",
+    "paddingInlineStart",
+    "paddingLeft",
+    "paddingRight",
+    "paddingTop",
+    "page",
+    "page-break-after",
+    "page-break-before",
+    "page-break-inside",
+    "page-orientation",
+    "pageAction",
+    "pageBreakAfter",
+    "pageBreakBefore",
+    "pageBreakInside",
+    "pageCount",
+    "pageLeft",
+    "pageOrientation",
+    "pageT",
+    "pageTop",
+    "pageX",
+    "pageXOffset",
+    "pageY",
+    "pageYOffset",
+    "pages",
+    "paint-order",
+    "paintOrder",
+    "paintRequests",
+    "paintTime",
+    "paintType",
+    "paintWorklet",
+    "palette",
+    "pan",
+    "panningModel",
+    "parameterData",
+    "parameters",
+    "parent",
+    "parentElement",
+    "parentNode",
+    "parentRule",
+    "parentStyleSheet",
+    "parentTextEdit",
+    "parentWindow",
+    "parse",
+    "parseAll",
+    "parseCreationOptionsFromJSON",
+    "parseFloat",
+    "parseFromString",
+    "parseHTMLUnsafe",
+    "parseInt",
+    "parseRequestOptionsFromJSON",
+    "part",
+    "participants",
+    "passOp",
+    "passive",
+    "password",
+    "pasteHTML",
+    "path",
+    "pathLength",
+    "pathSegList",
+    "pathSegType",
+    "pathSegTypeAsLetter",
+    "pathname",
+    "pattern",
+    "patternContentUnits",
+    "patternMismatch",
+    "patternTransform",
+    "patternUnits",
+    "pause",
+    "pauseAnimations",
+    "pauseDepthSensing",
+    "pauseDuration",
+    "pauseOnExit",
+    "pauseProfilers",
+    "pauseTransformFeedback",
+    "paused",
+    "payerEmail",
+    "payerName",
+    "payerPhone",
+    "paymentManager",
+    "pc",
+    "pdfViewerEnabled",
+    "peerIdentity",
+    "pending",
+    "pendingLocalDescription",
+    "pendingRemoteDescription",
+    "percent",
+    "performance",
+    "periodicSync",
+    "permission",
+    "permissionState",
+    "permissions",
+    "persist",
+    "persisted",
+    "persistentDeviceId",
+    "personalbar",
+    "perspective",
+    "perspective-origin",
+    "perspectiveOrigin",
+    "phone",
+    "phoneticFamilyName",
+    "phoneticGivenName",
+    "photo",
+    "phrase",
+    "phrases",
+    "pictureInPictureChild",
+    "pictureInPictureElement",
+    "pictureInPictureEnabled",
+    "pictureInPictureWindow",
+    "ping",
+    "pipeThrough",
+    "pipeTo",
+    "pitch",
+    "pixelBottom",
+    "pixelDepth",
+    "pixelFormat",
+    "pixelHeight",
+    "pixelLeft",
+    "pixelRight",
+    "pixelStorei",
+    "pixelTop",
+    "pixelUnitToMillimeterX",
+    "pixelUnitToMillimeterY",
+    "pixelWidth",
+    "pkcs11",
+    "place-content",
+    "place-items",
+    "place-self",
+    "placeContent",
+    "placeItems",
+    "placeSelf",
+    "placeholder",
+    "platform",
+    "platformVersion",
+    "platforms",
+    "play",
+    "playEffect",
+    "playState",
+    "playbackRate",
+    "playbackState",
+    "playbackTime",
+    "played",
+    "playoutDelayHint",
+    "playsInline",
+    "plugins",
+    "pluginspage",
+    "pname",
+    "pointer-events",
+    "pointerBeforeReferenceNode",
+    "pointerEnabled",
+    "pointerEvents",
+    "pointerId",
+    "pointerLockElement",
+    "pointerType",
+    "points",
+    "pointsAtX",
+    "pointsAtY",
+    "pointsAtZ",
+    "polygonOffset",
+    "pop",
+    "popDebugGroup",
+    "popErrorScope",
+    "popover",
+    "popoverTargetAction",
+    "popoverTargetElement",
+    "populateMatrix",
+    "popupWindowFeatures",
+    "popupWindowName",
+    "popupWindowURI",
+    "port",
+    "port1",
+    "port2",
+    "ports",
+    "posBottom",
+    "posHeight",
+    "posLeft",
+    "posRight",
+    "posTop",
+    "posWidth",
+    "pose",
+    "position",
+    "position-anchor",
+    "position-area",
+    "positionAlign",
+    "positionAnchor",
+    "positionArea",
+    "positionTry",
+    "positionTryFallbacks",
+    "positionVisibility",
+    "positionX",
+    "positionY",
+    "positionZ",
+    "postError",
+    "postMessage",
+    "postTask",
+    "postalCode",
+    "poster",
+    "postscriptName",
+    "pow",
+    "powerEfficient",
+    "powerOff",
+    "powerPreference",
+    "preMultiplySelf",
+    "precision",
+    "preferredReflectionFormat",
+    "preferredStyleSheetSet",
+    "preferredStylesheetSet",
+    "prefix",
+    "preload",
+    "premultipliedAlpha",
+    "prepend",
+    "prerendering",
+    "presentation",
+    "presentationArea",
+    "presentationStyle",
+    "presentationTime",
+    "preserveAlpha",
+    "preserveAspectRatio",
+    "preserveAspectRatioString",
+    "preservesPitch",
+    "pressed",
+    "pressure",
+    "prevValue",
+    "preventDefault",
+    "preventExtensions",
+    "preventSilentAccess",
+    "previousElementSibling",
+    "previousNode",
+    "previousPage",
+    "previousPriority",
+    "previousRect",
+    "previousScale",
+    "previousSibling",
+    "previousTranslate",
+    "primaries",
+    "primaryKey",
+    "primaryLightDirection",
+    "primaryLightIntensity",
+    "primitive",
+    "primitiveType",
+    "primitiveUnits",
+    "principals",
+    "print",
+    "print-color-adjust",
+    "printColorAdjust",
+    "printPreview",
+    "priority",
+    "privacy",
+    "privateKey",
+    "privateToken",
+    "probablySupportsContext",
+    "probeSpace",
+    "process",
+    "processIceMessage",
+    "processLocally",
+    "processingEnd",
+    "processingStart",
+    "processorOptions",
+    "product",
+    "productId",
+    "productName",
+    "productSub",
+    "profile",
+    "profileEnd",
+    "profiles",
+    "projectionMatrix",
+    "promise",
+    "promising",
+    "prompt",
+    "properties",
+    "propertyIsEnumerable",
+    "propertyName",
+    "protectedAudience",
+    "protocol",
+    "protocolLong",
+    "prototype",
+    "provider",
+    "proxy",
+    "pseudoClass",
+    "pseudoElement",
+    "pt",
+    "publicId",
+    "publicKey",
+    "published",
+    "pulse",
+    "push",
+    "pushDebugGroup",
+    "pushErrorScope",
+    "pushManager",
+    "pushNotification",
+    "pushState",
+    "put",
+    "putImageData",
+    "px",
+    "quadraticCurveTo",
+    "qualifier",
+    "quaternion",
+    "query",
+    "queryCommandEnabled",
+    "queryCommandIndeterm",
+    "queryCommandState",
+    "queryCommandSupported",
+    "queryCommandText",
+    "queryCommandValue",
+    "queryFeatureSupport",
+    "queryLocalFonts",
+    "queryPermission",
+    "querySelector",
+    "querySelectorAll",
+    "querySet",
+    "queue",
+    "queueMicrotask",
+    "quota",
+    "quote",
+    "quotes",
+    "r",
+    "r1",
+    "r2",
+    "race",
+    "rad",
+    "radiogroup",
+    "radius",
+    "radiusX",
+    "radiusY",
+    "random",
+    "randomUUID",
+    "range",
+    "rangeCount",
+    "rangeEnd",
+    "rangeMax",
+    "rangeMin",
+    "rangeOffset",
+    "rangeOverflow",
+    "rangeParent",
+    "rangeStart",
+    "rangeUnderflow",
+    "rate",
+    "ratio",
+    "raw",
+    "rawId",
+    "rawJSON",
+    "rawValueToMeters",
+    "rcap",
+    "rch",
+    "read",
+    "readAsArrayBuffer",
+    "readAsBinaryString",
+    "readAsBlob",
+    "readAsDataURL",
+    "readAsText",
+    "readBuffer",
+    "readEntries",
+    "readOnly",
+    "readPixels",
+    "readReportRequested",
+    "readText",
+    "readValue",
+    "readable",
+    "ready",
+    "readyState",
+    "reason",
+    "reasons",
+    "reboot",
+    "receiveFeatureReport",
+    "receivedAlert",
+    "receiver",
+    "receivers",
+    "recipient",
+    "recommendedViewportScale",
+    "reconnect",
+    "recordNumber",
+    "recordsAvailable",
+    "recordset",
+    "rect",
+    "red",
+    "redEyeReduction",
+    "redirect",
+    "redirectCount",
+    "redirectEnd",
+    "redirectStart",
+    "redirected",
+    "reduce",
+    "reduceRight",
+    "reduction",
+    "refDistance",
+    "refX",
+    "refY",
+    "referenceNode",
+    "referenceSpace",
+    "referrer",
+    "referrerPolicy",
+    "refresh",
+    "region",
+    "regionAnchorX",
+    "regionAnchorY",
+    "regionId",
+    "regions",
+    "register",
+    "registerContentHandler",
+    "registerElement",
+    "registerInternalModuleStart",
+    "registerInternalModuleStop",
+    "registerProperty",
+    "registerProtocolHandler",
+    "reject",
+    "rel",
+    "relList",
+    "relatedAddress",
+    "relatedNode",
+    "relatedPort",
+    "relatedTarget",
+    "relayProtocol",
+    "release",
+    "releaseCapture",
+    "releaseEvents",
+    "releaseInterface",
+    "releaseLock",
+    "releasePointerCapture",
+    "releaseShaderCompiler",
+    "released",
+    "reliability",
+    "reliable",
+    "reliableWrite",
+    "reload",
+    "rem",
+    "remainingSpace",
+    "remote",
+    "remoteDescription",
+    "remove",
+    "removeAllRanges",
+    "removeAttribute",
+    "removeAttributeNS",
+    "removeAttributeNode",
+    "removeBehavior",
+    "removeChild",
+    "removeCue",
+    "removeEntry",
+    "removeEventListener",
+    "removeFilter",
+    "removeImport",
+    "removeItem",
+    "removeListener",
+    "removeNamedItem",
+    "removeNamedItemNS",
+    "removeNode",
+    "removeParameter",
+    "removeProperty",
+    "removeRange",
+    "removeRegion",
+    "removeRule",
+    "removeSiteSpecificTrackingException",
+    "removeSourceBuffer",
+    "removeStream",
+    "removeTrack",
+    "removeVariable",
+    "removeWakeLockListener",
+    "removeWebWideTrackingException",
+    "removed",
+    "removedNodes",
+    "renderBlockingStatus",
+    "renderHeight",
+    "renderStart",
+    "renderState",
+    "renderTime",
+    "renderWidth",
+    "renderbufferStorage",
+    "renderbufferStorageMultisample",
+    "renderedBuffer",
+    "rendererInterfaces",
+    "renderers",
+    "renderingMode",
+    "renotify",
+    "repeat",
+    "repetitionCount",
+    "replace",
+    "replaceAdjacentText",
+    "replaceAll",
+    "replaceChild",
+    "replaceChildren",
+    "replaceData",
+    "replaceId",
+    "replaceItem",
+    "replaceNode",
+    "replaceState",
+    "replaceSync",
+    "replaceTrack",
+    "replaceWholeText",
+    "replaceWith",
+    "reportError",
+    "reportEvent",
+    "reportId",
+    "reportOnly",
+    "reportValidity",
+    "request",
+    "requestAdapter",
+    "requestAdapterInfo",
+    "requestAnimationFrame",
+    "requestAutocomplete",
+    "requestClose",
+    "requestData",
+    "requestDevice",
+    "requestFrame",
+    "requestFullscreen",
+    "requestHitTestSource",
+    "requestHitTestSourceForTransientInput",
+    "requestId",
+    "requestIdleCallback",
+    "requestLightProbe",
+    "requestMIDIAccess",
+    "requestMediaKeySystemAccess",
+    "requestPermission",
+    "requestPictureInPicture",
+    "requestPointerLock",
+    "requestPort",
+    "requestPresent",
+    "requestPresenter",
+    "requestReferenceSpace",
+    "requestSession",
+    "requestStart",
+    "requestStorageAccess",
+    "requestStorageAccessFor",
+    "requestSubmit",
+    "requestTime",
+    "requestUpdateCheck",
+    "requestVideoFrameCallback",
+    "requestViewportScale",
+    "requestWindow",
+    "requested",
+    "requestingWindow",
+    "requireInteraction",
+    "required",
+    "requiredExtensions",
+    "requiredFeatures",
+    "requiredLimits",
+    "reset",
+    "resetLatency",
+    "resetPose",
+    "resetTransform",
+    "resetZoomLevel",
+    "resizable",
+    "resize",
+    "resizeBy",
+    "resizeTo",
+    "resolve",
+    "resolveQuerySet",
+    "resolveTarget",
+    "resource",
+    "respond",
+    "respondWithNewView",
+    "response",
+    "responseBody",
+    "responseEnd",
+    "responseReady",
+    "responseStart",
+    "responseStatus",
+    "responseText",
+    "responseType",
+    "responseURL",
+    "responseXML",
+    "restart",
+    "restartAfterDelay",
+    "restartIce",
+    "restore",
+    "restrictTo",
+    "result",
+    "resultIndex",
+    "resultType",
+    "results",
+    "resume",
+    "resumeDepthSensing",
+    "resumeProfilers",
+    "resumeTransformFeedback",
+    "retry",
+    "returnType",
+    "returnValue",
+    "rev",
+    "reverse",
+    "reversed",
+    "revocable",
+    "revokeObjectURL",
+    "rex",
+    "rgbColor",
+    "ric",
+    "right",
+    "rightContext",
+    "rightDegrees",
+    "rightMargin",
+    "rightProjectionMatrix",
+    "rightViewMatrix",
+    "rlh",
+    "role",
+    "rolloffFactor",
+    "root",
+    "rootBounds",
+    "rootElement",
+    "rootMargin",
+    "rotate",
+    "rotateAxisAngle",
+    "rotateAxisAngleSelf",
+    "rotateFromVector",
+    "rotateFromVectorSelf",
+    "rotateSelf",
+    "rotation",
+    "rotationAngle",
+    "rotationRate",
+    "round",
+    "roundRect",
+    "row-gap",
+    "rowGap",
+    "rowIndex",
+    "rowSpan",
+    "rows",
+    "rowsPerImage",
+    "rtcpTransport",
+    "rtt",
+    "ruby-align",
+    "ruby-position",
+    "rubyAlign",
+    "rubyOverhang",
+    "rubyPosition",
+    "rules",
+    "run",
+    "runAdAuction",
+    "runtime",
+    "runtimeStyle",
+    "rx",
+    "ry",
+    "s",
+    "safari",
+    "sameDocument",
+    "sample",
+    "sampleCount",
+    "sampleCoverage",
+    "sampleInterval",
+    "sampleRate",
+    "sampleType",
+    "sampler",
+    "samplerParameterf",
+    "samplerParameteri",
+    "sandbox",
+    "save",
+    "saveAsPDF",
+    "saveData",
+    "scale",
+    "scale3d",
+    "scale3dSelf",
+    "scaleNonUniform",
+    "scaleNonUniformSelf",
+    "scaleSelf",
+    "scheduler",
+    "scheduling",
+    "scheme",
+    "scissor",
+    "scope",
+    "scopeName",
+    "scoped",
+    "screen",
+    "screenBrightness",
+    "screenEnabled",
+    "screenLeft",
+    "screenPixelToMillimeterX",
+    "screenPixelToMillimeterY",
+    "screenState",
+    "screenTop",
+    "screenX",
+    "screenY",
+    "screens",
+    "scriptURL",
+    "scripting",
+    "scripts",
+    "scroll",
+    "scroll-behavior",
+    "scroll-margin",
+    "scroll-margin-block",
+    "scroll-margin-block-end",
+    "scroll-margin-block-start",
+    "scroll-margin-bottom",
+    "scroll-margin-inline",
+    "scroll-margin-inline-end",
+    "scroll-margin-inline-start",
+    "scroll-margin-left",
+    "scroll-margin-right",
+    "scroll-margin-top",
+    "scroll-padding",
+    "scroll-padding-block",
+    "scroll-padding-block-end",
+    "scroll-padding-block-start",
+    "scroll-padding-bottom",
+    "scroll-padding-inline",
+    "scroll-padding-inline-end",
+    "scroll-padding-inline-start",
+    "scroll-padding-left",
+    "scroll-padding-right",
+    "scroll-padding-top",
+    "scroll-snap-align",
+    "scroll-snap-stop",
+    "scroll-snap-type",
+    "scrollAmount",
+    "scrollBehavior",
+    "scrollBy",
+    "scrollByLines",
+    "scrollByPages",
+    "scrollDelay",
+    "scrollHeight",
+    "scrollIntoView",
+    "scrollIntoViewIfNeeded",
+    "scrollLeft",
+    "scrollLeftMax",
+    "scrollMargin",
+    "scrollMarginBlock",
+    "scrollMarginBlockEnd",
+    "scrollMarginBlockStart",
+    "scrollMarginBottom",
+    "scrollMarginInline",
+    "scrollMarginInlineEnd",
+    "scrollMarginInlineStart",
+    "scrollMarginLeft",
+    "scrollMarginRight",
+    "scrollMarginTop",
+    "scrollMaxX",
+    "scrollMaxY",
+    "scrollPadding",
+    "scrollPaddingBlock",
+    "scrollPaddingBlockEnd",
+    "scrollPaddingBlockStart",
+    "scrollPaddingBottom",
+    "scrollPaddingInline",
+    "scrollPaddingInlineEnd",
+    "scrollPaddingInlineStart",
+    "scrollPaddingLeft",
+    "scrollPaddingRight",
+    "scrollPaddingTop",
+    "scrollRestoration",
+    "scrollSnapAlign",
+    "scrollSnapStop",
+    "scrollSnapType",
+    "scrollTo",
+    "scrollTop",
+    "scrollTopMax",
+    "scrollWidth",
+    "scrollX",
+    "scrollY",
+    "scrollbar-color",
+    "scrollbar-gutter",
+    "scrollbar-width",
+    "scrollbar3dLightColor",
+    "scrollbarArrowColor",
+    "scrollbarBaseColor",
+    "scrollbarColor",
+    "scrollbarDarkShadowColor",
+    "scrollbarFaceColor",
+    "scrollbarGutter",
+    "scrollbarHighlightColor",
+    "scrollbarShadowColor",
+    "scrollbarTrackColor",
+    "scrollbarWidth",
+    "scrollbars",
+    "scrolling",
+    "scrollingElement",
+    "sctp",
+    "sctpCauseCode",
+    "sdp",
+    "sdpLineNumber",
+    "sdpMLineIndex",
+    "sdpMid",
+    "seal",
+    "search",
+    "searchBox",
+    "searchBoxJavaBridge_",
+    "searchParams",
+    "second",
+    "seconds",
+    "sectionRowIndex",
+    "secureConnectionStart",
+    "securePaymentConfirmationAvailability",
+    "security",
+    "seed",
+    "seek",
+    "seekToNextFrame",
+    "seekable",
+    "seeking",
+    "segments",
+    "select",
+    "selectAllChildren",
+    "selectAlternateInterface",
+    "selectAudioOutput",
+    "selectConfiguration",
+    "selectNode",
+    "selectNodeContents",
+    "selectNodes",
+    "selectSingleNode",
+    "selectSubString",
+    "selectURL",
+    "selected",
+    "selectedIndex",
+    "selectedOptions",
+    "selectedStyleSheetSet",
+    "selectedStylesheetSet",
+    "selectedTrack",
+    "selection",
+    "selectionDirection",
+    "selectionEnd",
+    "selectionStart",
+    "selector",
+    "selectorText",
+    "self",
+    "send",
+    "sendAsBinary",
+    "sendBeacon",
+    "sendFeatureReport",
+    "sendMessage",
+    "sendNativeMessage",
+    "sendOrder",
+    "sendReport",
+    "sender",
+    "sentAlert",
+    "sentTimestamp",
+    "separator",
+    "serial",
+    "serialNumber",
+    "serializable",
+    "serializeToString",
+    "serverTiming",
+    "service",
+    "serviceWorker",
+    "session",
+    "sessionId",
+    "sessionStorage",
+    "sessions",
+    "set",
+    "setActionHandler",
+    "setActive",
+    "setAlpha",
+    "setAppBadge",
+    "setAttribute",
+    "setAttributeNS",
+    "setAttributeNode",
+    "setAttributeNodeNS",
+    "setAttributionReporting",
+    "setBadgeBackgroundColor",
+    "setBadgeText",
+    "setBadgeTextColor",
+    "setBaseAndExtent",
+    "setBigInt64",
+    "setBigUint64",
+    "setBindGroup",
+    "setBingCurrentSearchDefault",
+    "setBlendConstant",
+    "setCameraActive",
+    "setCapture",
+    "setCaptureHandleConfig",
+    "setCodecPreferences",
+    "setColor",
+    "setCompositeOperation",
+    "setConfiguration",
+    "setConsumer",
+    "setCurrentTime",
+    "setCustomValidity",
+    "setData",
+    "setDate",
+    "setDragImage",
+    "setEnabled",
+    "setEnd",
+    "setEndAfter",
+    "setEndBefore",
+    "setEndPoint",
+    "setExpires",
+    "setFillColor",
+    "setFilterRes",
+    "setFloat16",
+    "setFloat32",
+    "setFloat64",
+    "setFloatValue",
+    "setFocusBehavior",
+    "setFormValue",
+    "setFromBase64",
+    "setFromHex",
+    "setFullYear",
+    "setHTMLUnsafe",
+    "setHeaderExtensionsToNegotiate",
+    "setHeaderValue",
+    "setHours",
+    "setIcon",
+    "setIdentityProvider",
+    "setImmediate",
+    "setIndexBuffer",
+    "setInt16",
+    "setInt32",
+    "setInt8",
+    "setInterval",
+    "setItem",
+    "setKeyframes",
+    "setLineCap",
+    "setLineDash",
+    "setLineJoin",
+    "setLineWidth",
+    "setLiveSeekableRange",
+    "setLocalDescription",
+    "setMatrix",
+    "setMatrixValue",
+    "setMediaKeys",
+    "setMicrophoneActive",
+    "setMilliseconds",
+    "setMinutes",
+    "setMiterLimit",
+    "setMonth",
+    "setNamedItem",
+    "setNamedItemNS",
+    "setNonUserCodeExceptions",
+    "setOrientToAngle",
+    "setOrientToAuto",
+    "setOrientation",
+    "setOverrideHistoryNavigationMode",
+    "setPaint",
+    "setParameter",
+    "setParameters",
+    "setPathData",
+    "setPeriodicWave",
+    "setPipeline",
+    "setPointerCapture",
+    "setPopup",
+    "setPosition",
+    "setPositionState",
+    "setPreference",
+    "setPriority",
+    "setPrivateToken",
+    "setProperty",
+    "setPrototypeOf",
+    "setRGBColor",
+    "setRGBColorICCColor",
+    "setRadius",
+    "setRangeText",
+    "setRemoteDescription",
+    "setReportEventDataForAutomaticBeacons",
+    "setRequestHeader",
+    "setResizable",
+    "setResourceTimingBufferSize",
+    "setRotate",
+    "setScale",
+    "setScissorRect",
+    "setSeconds",
+    "setSelectionRange",
+    "setServerCertificate",
+    "setShadow",
+    "setSharedStorageContext",
+    "setSignals",
+    "setSinkId",
+    "setSkewX",
+    "setSkewY",
+    "setStart",
+    "setStartAfter",
+    "setStartBefore",
+    "setStatus",
+    "setStdDeviation",
+    "setStencilReference",
+    "setStreams",
+    "setStrictMode",
+    "setStringValue",
+    "setStrokeColor",
+    "setSuggestResult",
+    "setTargetAtTime",
+    "setTargetValueAtTime",
+    "setTime",
+    "setTimeout",
+    "setTitle",
+    "setTransform",
+    "setTranslate",
+    "setUTCDate",
+    "setUTCFullYear",
+    "setUTCHours",
+    "setUTCMilliseconds",
+    "setUTCMinutes",
+    "setUTCMonth",
+    "setUTCSeconds",
+    "setUint16",
+    "setUint32",
+    "setUint8",
+    "setUninstallURL",
+    "setUpdateUrlData",
+    "setUri",
+    "setValidity",
+    "setValueAtTime",
+    "setValueCurveAtTime",
+    "setVariable",
+    "setVelocity",
+    "setVersion",
+    "setVertexBuffer",
+    "setViewport",
+    "setYear",
+    "setZoom",
+    "setZoomSettings",
+    "settingName",
+    "settingValue",
+    "sex",
+    "shaderLocation",
+    "shaderSource",
+    "shadowBlur",
+    "shadowColor",
+    "shadowOffsetX",
+    "shadowOffsetY",
+    "shadowRoot",
+    "shadowRootClonable",
+    "shadowRootDelegatesFocus",
+    "shadowRootMode",
+    "shadowRootSerializable",
+    "shape",
+    "shape-image-threshold",
+    "shape-margin",
+    "shape-outside",
+    "shape-rendering",
+    "shapeImageThreshold",
+    "shapeMargin",
+    "shapeOutside",
+    "shapeRendering",
+    "share",
+    "sharedContext",
+    "sharedStorage",
+    "sharedStorageWritable",
+    "sheet",
+    "shift",
+    "shiftKey",
+    "shiftLeft",
+    "shippingAddress",
+    "shippingOption",
+    "shippingType",
+    "show",
+    "showDirectoryPicker",
+    "showHelp",
+    "showModal",
+    "showModalDialog",
+    "showModelessDialog",
+    "showNotification",
+    "showOpenFilePicker",
+    "showPicker",
+    "showPopover",
+    "showSaveFilePicker",
+    "sidebar",
+    "sidebarAction",
+    "sign",
+    "signal",
+    "signalAllAcceptedCredentials",
+    "signalCurrentUserDetails",
+    "signalUnknownCredential",
+    "signalingState",
+    "signature",
+    "silent",
+    "sin",
+    "singleNodeValue",
+    "sinh",
+    "sinkId",
+    "sittingToStandingTransform",
+    "size",
+    "sizeAdjust",
+    "sizeToContent",
+    "sizeX",
+    "sizeZ",
+    "sizes",
+    "skewX",
+    "skewXSelf",
+    "skewY",
+    "skewYSelf",
+    "skipTransition",
+    "skipped",
+    "slice",
+    "slope",
+    "slot",
+    "slotAssignment",
+    "small",
+    "smil",
+    "smooth",
+    "smoothingTimeConstant",
+    "snapTargetBlock",
+    "snapTargetInline",
+    "snapToLines",
+    "snapshotItem",
+    "snapshotLength",
+    "some",
+    "sort",
+    "sortingCode",
+    "source",
+    "sourceBuffer",
+    "sourceBuffers",
+    "sourceCapabilities",
+    "sourceCharPosition",
+    "sourceElement",
+    "sourceFile",
+    "sourceFunctionName",
+    "sourceIndex",
+    "sourceLanguage",
+    "sourceMap",
+    "sourceURL",
+    "sources",
+    "spacing",
+    "span",
+    "speak",
+    "speakAs",
+    "speaking",
+    "species",
+    "specified",
+    "specularConstant",
+    "specularExponent",
+    "speechSynthesis",
+    "speed",
+    "speedOfSound",
+    "spellcheck",
+    "sphericalHarmonicsCoefficients",
+    "splice",
+    "split",
+    "splitText",
+    "spreadMethod",
+    "sqrt",
+    "src",
+    "srcElement",
+    "srcFactor",
+    "srcFilter",
+    "srcObject",
+    "srcUrn",
+    "srcdoc",
+    "srclang",
+    "srcset",
+    "stack",
+    "stackTraceLimit",
+    "stacktrace",
+    "stageParameters",
+    "standalone",
+    "standby",
+    "start",
+    "startContainer",
+    "startE",
+    "startIce",
+    "startLoadTime",
+    "startMessages",
+    "startNotifications",
+    "startOffset",
+    "startProfiling",
+    "startRendering",
+    "startShark",
+    "startTime",
+    "startViewTransition",
+    "startsWith",
+    "state",
+    "states",
+    "stats",
+    "status",
+    "statusCode",
+    "statusMessage",
+    "statusText",
+    "statusbar",
+    "stdDeviationX",
+    "stdDeviationY",
+    "stencilBack",
+    "stencilClearValue",
+    "stencilFront",
+    "stencilFunc",
+    "stencilFuncSeparate",
+    "stencilLoadOp",
+    "stencilMask",
+    "stencilMaskSeparate",
+    "stencilOp",
+    "stencilOpSeparate",
+    "stencilReadMask",
+    "stencilReadOnly",
+    "stencilStoreOp",
+    "stencilWriteMask",
+    "step",
+    "stepDown",
+    "stepMismatch",
+    "stepMode",
+    "stepUp",
+    "sticky",
+    "stitchTiles",
+    "stop",
+    "stop-color",
+    "stop-opacity",
+    "stopColor",
+    "stopImmediatePropagation",
+    "stopNotifications",
+    "stopOpacity",
+    "stopProfiling",
+    "stopPropagation",
+    "stopShark",
+    "stopped",
+    "storage",
+    "storageArea",
+    "storageBuckets",
+    "storageName",
+    "storageStatus",
+    "storageTexture",
+    "store",
+    "storeOp",
+    "storeSiteSpecificTrackingException",
+    "storeWebWideTrackingException",
+    "stpVersion",
+    "stream",
+    "streamErrorCode",
+    "streams",
+    "stretch",
+    "strike",
+    "string",
+    "stringValue",
+    "stringify",
+    "stripIndexFormat",
+    "stroke",
+    "stroke-dasharray",
+    "stroke-dashoffset",
+    "stroke-linecap",
+    "stroke-linejoin",
+    "stroke-miterlimit",
+    "stroke-opacity",
+    "stroke-width",
+    "strokeDasharray",
+    "strokeDashoffset",
+    "strokeLinecap",
+    "strokeLinejoin",
+    "strokeMiterlimit",
+    "strokeOpacity",
+    "strokeRect",
+    "strokeStyle",
+    "strokeText",
+    "strokeWidth",
+    "structuredClone",
+    "style",
+    "styleAndLayoutStart",
+    "styleFloat",
+    "styleMap",
+    "styleMedia",
+    "styleSheet",
+    "styleSheetSets",
+    "styleSheets",
+    "styleset",
+    "stylistic",
+    "sub",
+    "subarray",
+    "subgroupMaxSize",
+    "subgroupMinSize",
+    "subject",
+    "submit",
+    "submitFrame",
+    "submitter",
+    "subscribe",
+    "substr",
+    "substring",
+    "substringData",
+    "subtle",
+    "subtree",
+    "suffix",
+    "suffixes",
+    "sumPrecise",
+    "summarize",
+    "summarizeStreaming",
+    "summary",
+    "sup",
+    "supported",
+    "supportedContentEncodings",
+    "supportedEntryTypes",
+    "supportedValuesOf",
+    "supports",
+    "supportsFiber",
+    "supportsSession",
+    "supportsText",
+    "suppressed",
+    "surfaceScale",
+    "surroundContents",
+    "suspend",
+    "suspendRedraw",
+    "svb",
+    "svh",
+    "svi",
+    "svmax",
+    "svmin",
+    "svw",
+    "swapCache",
+    "swapNode",
+    "swash",
+    "sweepFlag",
+    "switchMap",
+    "symbols",
+    "symmetricDifference",
+    "sync",
+    "syntax",
+    "sysexEnabled",
+    "system",
+    "systemCode",
+    "systemId",
+    "systemLanguage",
+    "systemXDPI",
+    "systemYDPI",
+    "tBodies",
+    "tFoot",
+    "tHead",
+    "tab",
+    "tab-size",
+    "tabId",
+    "tabIds",
+    "tabIndex",
+    "tabSize",
+    "table",
+    "table-layout",
+    "tableLayout",
+    "tableValues",
+    "tabs",
+    "tag",
+    "tagName",
+    "tagUrn",
+    "tags",
+    "taintEnabled",
+    "take",
+    "takePhoto",
+    "takeRecords",
+    "takeUntil",
+    "tan",
+    "tangentialPressure",
+    "tanh",
+    "target",
+    "targetAddressSpace",
+    "targetElement",
+    "targetLanguage",
+    "targetRayMode",
+    "targetRaySpace",
+    "targetTouches",
+    "targetURL",
+    "targetX",
+    "targetY",
+    "targets",
+    "tcpType",
+    "tee",
+    "tel",
+    "telemetry",
+    "terminate",
+    "test",
+    "texImage2D",
+    "texImage3D",
+    "texParameterf",
+    "texParameteri",
+    "texStorage2D",
+    "texStorage3D",
+    "texSubImage2D",
+    "texSubImage3D",
+    "text",
+    "text-align",
+    "text-align-last",
+    "text-anchor",
+    "text-combine-upright",
+    "text-decoration",
+    "text-decoration-color",
+    "text-decoration-line",
+    "text-decoration-skip-ink",
+    "text-decoration-style",
+    "text-decoration-thickness",
+    "text-emphasis",
+    "text-emphasis-color",
+    "text-emphasis-position",
+    "text-emphasis-style",
+    "text-indent",
+    "text-justify",
+    "text-orientation",
+    "text-overflow",
+    "text-rendering",
+    "text-shadow",
+    "text-transform",
+    "text-underline-offset",
+    "text-underline-position",
+    "text-wrap",
+    "text-wrap-mode",
+    "text-wrap-style",
+    "textAlign",
+    "textAlignLast",
+    "textAnchor",
+    "textAutospace",
+    "textBaseline",
+    "textCombineUpright",
+    "textContent",
+    "textDecoration",
+    "textDecorationBlink",
+    "textDecorationColor",
+    "textDecorationInset",
+    "textDecorationLine",
+    "textDecorationLineThrough",
+    "textDecorationNone",
+    "textDecorationOverline",
+    "textDecorationSkipInk",
+    "textDecorationStyle",
+    "textDecorationThickness",
+    "textDecorationUnderline",
+    "textEmphasis",
+    "textEmphasisColor",
+    "textEmphasisPosition",
+    "textEmphasisStyle",
+    "textIndent",
+    "textJustify",
+    "textJustifyTrim",
+    "textKashida",
+    "textKashidaSpace",
+    "textLength",
+    "textOrientation",
+    "textOverflow",
+    "textRendering",
+    "textShadow",
+    "textTracks",
+    "textTransform",
+    "textUnderlineOffset",
+    "textUnderlinePosition",
+    "textWrap",
+    "textWrapMode",
+    "textWrapStyle",
+    "texture",
+    "theme",
+    "then",
+    "threadId",
+    "threshold",
+    "thresholds",
+    "throwIfAborted",
+    "tiltX",
+    "tiltY",
+    "time",
+    "timeEnd",
+    "timeLog",
+    "timeOrigin",
+    "timeRemaining",
+    "timeStamp",
+    "timeStyle",
+    "timeZone",
+    "timeZoneName",
+    "timecode",
+    "timeline",
+    "timelineTime",
+    "timeout",
+    "timestamp",
+    "timestampOffset",
+    "timestampWrites",
+    "timing",
+    "title",
+    "titlebarAreaRect",
+    "tlsChannelId",
+    "to",
+    "toArray",
+    "toBase64",
+    "toBlob",
+    "toDataURL",
+    "toDateString",
+    "toElement",
+    "toExponential",
+    "toFixed",
+    "toFloat32Array",
+    "toFloat64Array",
+    "toGMTString",
+    "toHex",
+    "toISOString",
+    "toJSON",
+    "toLocaleDateString",
+    "toLocaleFormat",
+    "toLocaleLowerCase",
+    "toLocaleString",
+    "toLocaleTimeString",
+    "toLocaleUpperCase",
+    "toLowerCase",
+    "toMatrix",
+    "toMethod",
+    "toPrecision",
+    "toPrimitive",
+    "toReversed",
+    "toSdp",
+    "toSorted",
+    "toSource",
+    "toSpliced",
+    "toStaticHTML",
+    "toString",
+    "toStringTag",
+    "toSum",
+    "toTemporalInstant",
+    "toTimeString",
+    "toUTCString",
+    "toUpperCase",
+    "toWellFormed",
+    "toggle",
+    "toggleAttribute",
+    "toggleLongPressEnabled",
+    "togglePopover",
+    "toggleReaderMode",
+    "token",
+    "tone",
+    "toneBuffer",
+    "tooLong",
+    "tooShort",
+    "toolbar",
+    "top",
+    "topMargin",
+    "topSites",
+    "topology",
+    "total",
+    "totalFrameDelay",
+    "totalFrames",
+    "totalFramesDuration",
+    "totalVideoFrames",
+    "touch-action",
+    "touchAction",
+    "touched",
+    "touches",
+    "trace",
+    "track",
+    "trackVisibility",
+    "trackedAnchors",
+    "tracks",
+    "tran",
+    "transaction",
+    "transactions",
+    "transceiver",
+    "transfer",
+    "transferControlToOffscreen",
+    "transferFromImageBitmap",
+    "transferImageBitmap",
+    "transferIn",
+    "transferOut",
+    "transferSize",
+    "transferToFixedLength",
+    "transferToImageBitmap",
+    "transform",
+    "transform-box",
+    "transform-origin",
+    "transform-style",
+    "transformBox",
+    "transformFeedbackVaryings",
+    "transformOrigin",
+    "transformPoint",
+    "transformString",
+    "transformStyle",
+    "transformToDocument",
+    "transformToFragment",
+    "transition",
+    "transition-behavior",
+    "transition-delay",
+    "transition-duration",
+    "transition-property",
+    "transition-timing-function",
+    "transitionBehavior",
+    "transitionDelay",
+    "transitionDuration",
+    "transitionProperty",
+    "transitionTimingFunction",
+    "translate",
+    "translateSelf",
+    "translateStreaming",
+    "translationX",
+    "translationY",
+    "transport",
+    "traverseTo",
+    "trim",
+    "trimEnd",
+    "trimLeft",
+    "trimRight",
+    "trimStart",
+    "trueSpeed",
+    "trunc",
+    "truncate",
+    "trustedTypes",
+    "try",
+    "turn",
+    "twist",
+    "type",
+    "typeDetail",
+    "typeMismatch",
+    "typeMustMatch",
+    "types",
+    "u2f",
+    "ubound",
+    "uint16",
+    "uint32",
+    "uint8",
+    "uint8Clamped",
+    "unadjustedMovement",
+    "unclippedDepth",
+    "unconfigure",
+    "undefined",
+    "underlineStyle",
+    "underlineThickness",
+    "unescape",
+    "uneval",
+    "ungroup",
+    "unicode",
+    "unicode-bidi",
+    "unicodeBidi",
+    "unicodeRange",
+    "unicodeSets",
+    "uniform1f",
+    "uniform1fv",
+    "uniform1i",
+    "uniform1iv",
+    "uniform1ui",
+    "uniform1uiv",
+    "uniform2f",
+    "uniform2fv",
+    "uniform2i",
+    "uniform2iv",
+    "uniform2ui",
+    "uniform2uiv",
+    "uniform3f",
+    "uniform3fv",
+    "uniform3i",
+    "uniform3iv",
+    "uniform3ui",
+    "uniform3uiv",
+    "uniform4f",
+    "uniform4fv",
+    "uniform4i",
+    "uniform4iv",
+    "uniform4ui",
+    "uniform4uiv",
+    "uniformBlockBinding",
+    "uniformMatrix2fv",
+    "uniformMatrix2x3fv",
+    "uniformMatrix2x4fv",
+    "uniformMatrix3fv",
+    "uniformMatrix3x2fv",
+    "uniformMatrix3x4fv",
+    "uniformMatrix4fv",
+    "uniformMatrix4x2fv",
+    "uniformMatrix4x3fv",
+    "uninstallSelf",
+    "union",
+    "unique",
+    "uniqueID",
+    "uniqueNumber",
+    "unit",
+    "unitType",
+    "units",
+    "unloadEventEnd",
+    "unloadEventStart",
+    "unlock",
+    "unmap",
+    "unmount",
+    "unobserve",
+    "unpackColorSpace",
+    "unpause",
+    "unpauseAnimations",
+    "unreadCount",
+    "unregister",
+    "unregisterContentHandler",
+    "unregisterProtocolHandler",
+    "unscopables",
+    "unselectable",
+    "unshift",
+    "unsubscribe",
+    "unsuspendRedraw",
+    "unsuspendRedrawAll",
+    "unwatch",
+    "unwrapKey",
+    "upDegrees",
+    "upX",
+    "upY",
+    "upZ",
+    "update",
+    "updateAdInterestGroups",
+    "updateCallbackDone",
+    "updateCharacterBounds",
+    "updateCommands",
+    "updateControlBounds",
+    "updateCurrentEntry",
+    "updateIce",
+    "updateInkTrailStartPoint",
+    "updateInterval",
+    "updatePlaybackRate",
+    "updateRangeEnd",
+    "updateRangeStart",
+    "updateRenderState",
+    "updateSelection",
+    "updateSelectionBounds",
+    "updateSettings",
+    "updateText",
+    "updateTiming",
+    "updateViaCache",
+    "updateWith",
+    "updated",
+    "updating",
+    "upgrade",
+    "upload",
+    "uploadTotal",
+    "uploaded",
+    "upper",
+    "upperBound",
+    "upperOpen",
+    "uri",
+    "url",
+    "urn",
+    "urns",
+    "usage",
+    "usages",
+    "usb",
+    "usbVersionMajor",
+    "usbVersionMinor",
+    "usbVersionSubminor",
+    "use",
+    "useCurrentView",
+    "useMap",
+    "useProgram",
+    "usedSpace",
+    "user-select",
+    "userActivation",
+    "userAgent",
+    "userAgentAllowsProtocol",
+    "userAgentData",
+    "userChoice",
+    "userHandle",
+    "userHint",
+    "userInitiated",
+    "userLanguage",
+    "userSelect",
+    "userState",
+    "userVisibleOnly",
+    "username",
+    "usernameFragment",
+    "utterance",
+    "uuid",
+    "v8BreakIterator",
+    "vAlign",
+    "vLink",
+    "valid",
+    "validate",
+    "validateProgram",
+    "validationMessage",
+    "validity",
+    "value",
+    "valueAsDate",
+    "valueAsNumber",
+    "valueAsString",
+    "valueInSpecifiedUnits",
+    "valueMissing",
+    "valueOf",
+    "valueText",
+    "valueType",
+    "values",
+    "variable",
+    "variant",
+    "variationSettings",
+    "vb",
+    "vector-effect",
+    "vectorEffect",
+    "velocityAngular",
+    "velocityExpansion",
+    "velocityX",
+    "velocityY",
+    "vendor",
+    "vendorId",
+    "vendorSub",
+    "verify",
+    "version",
+    "vertex",
+    "vertexAttrib1f",
+    "vertexAttrib1fv",
+    "vertexAttrib2f",
+    "vertexAttrib2fv",
+    "vertexAttrib3f",
+    "vertexAttrib3fv",
+    "vertexAttrib4f",
+    "vertexAttrib4fv",
+    "vertexAttribDivisor",
+    "vertexAttribDivisorANGLE",
+    "vertexAttribI4i",
+    "vertexAttribI4iv",
+    "vertexAttribI4ui",
+    "vertexAttribI4uiv",
+    "vertexAttribIPointer",
+    "vertexAttribPointer",
+    "vertical",
+    "vertical-align",
+    "verticalAlign",
+    "verticalOverflow",
+    "vh",
+    "vi",
+    "vibrate",
+    "vibrationActuator",
+    "videoBitsPerSecond",
+    "videoHeight",
+    "videoTracks",
+    "videoWidth",
+    "view",
+    "viewBox",
+    "viewBoxString",
+    "viewDimension",
+    "viewFormats",
+    "viewTarget",
+    "viewTargetString",
+    "viewTransition",
+    "viewTransitionClass",
+    "viewTransitionName",
+    "viewport",
+    "viewportAnchorX",
+    "viewportAnchorY",
+    "viewportElement",
+    "views",
+    "violatedDirective",
+    "virtualKeyboard",
+    "virtualKeyboardPolicy",
+    "visibility",
+    "visibilityState",
+    "visible",
+    "visibleRect",
+    "visualViewport",
+    "vlinkColor",
+    "vmax",
+    "vmin",
+    "voice",
+    "voiceURI",
+    "volume",
+    "vrml",
+    "vspace",
+    "vw",
+    "w",
+    "wait",
+    "waitAsync",
+    "waitSync",
+    "waiting",
+    "wake",
+    "wakeLock",
+    "wand",
+    "warmup",
+    "warn",
+    "wasAlternateProtocolAvailable",
+    "wasClean",
+    "wasDiscarded",
+    "wasFetchedViaSpdy",
+    "wasNpnNegotiated",
+    "watch",
+    "watchAvailability",
+    "watchPosition",
+    "webNavigation",
+    "webRequest",
+    "webdriver",
+    "webkitAddKey",
+    "webkitAlignContent",
+    "webkitAlignItems",
+    "webkitAlignSelf",
+    "webkitAnimation",
+    "webkitAnimationDelay",
+    "webkitAnimationDirection",
+    "webkitAnimationDuration",
+    "webkitAnimationFillMode",
+    "webkitAnimationIterationCount",
+    "webkitAnimationName",
+    "webkitAnimationPlayState",
+    "webkitAnimationTimingFunction",
+    "webkitAppearance",
+    "webkitAudioContext",
+    "webkitAudioDecodedByteCount",
+    "webkitAudioPannerNode",
+    "webkitBackfaceVisibility",
+    "webkitBackground",
+    "webkitBackgroundAttachment",
+    "webkitBackgroundClip",
+    "webkitBackgroundColor",
+    "webkitBackgroundImage",
+    "webkitBackgroundOrigin",
+    "webkitBackgroundPosition",
+    "webkitBackgroundPositionX",
+    "webkitBackgroundPositionY",
+    "webkitBackgroundRepeat",
+    "webkitBackgroundSize",
+    "webkitBackingStorePixelRatio",
+    "webkitBorderBottomLeftRadius",
+    "webkitBorderBottomRightRadius",
+    "webkitBorderImage",
+    "webkitBorderImageOutset",
+    "webkitBorderImageRepeat",
+    "webkitBorderImageSlice",
+    "webkitBorderImageSource",
+    "webkitBorderImageWidth",
+    "webkitBorderRadius",
+    "webkitBorderTopLeftRadius",
+    "webkitBorderTopRightRadius",
+    "webkitBoxAlign",
+    "webkitBoxDirection",
+    "webkitBoxFlex",
+    "webkitBoxOrdinalGroup",
+    "webkitBoxOrient",
+    "webkitBoxPack",
+    "webkitBoxShadow",
+    "webkitBoxSizing",
+    "webkitCancelAnimationFrame",
+    "webkitCancelFullScreen",
+    "webkitCancelKeyRequest",
+    "webkitCancelRequestAnimationFrame",
+    "webkitClearResourceTimings",
+    "webkitClipPath",
+    "webkitClosedCaptionsVisible",
+    "webkitConvertPointFromNodeToPage",
+    "webkitConvertPointFromPageToNode",
+    "webkitCreateShadowRoot",
+    "webkitCurrentFullScreenElement",
+    "webkitCurrentPlaybackTargetIsWireless",
+    "webkitDecodedFrameCount",
+    "webkitDirectionInvertedFromDevice",
+    "webkitDisplayingFullscreen",
+    "webkitDroppedFrameCount",
+    "webkitEnterFullScreen",
+    "webkitEnterFullscreen",
+    "webkitEntries",
+    "webkitExitFullScreen",
+    "webkitExitFullscreen",
+    "webkitExitPointerLock",
+    "webkitFilter",
+    "webkitFlex",
+    "webkitFlexBasis",
+    "webkitFlexDirection",
+    "webkitFlexFlow",
+    "webkitFlexGrow",
+    "webkitFlexShrink",
+    "webkitFlexWrap",
+    "webkitFontFeatureSettings",
+    "webkitFullScreenKeyboardInputAllowed",
+    "webkitFullscreenElement",
+    "webkitFullscreenEnabled",
+    "webkitGenerateKeyRequest",
+    "webkitGetAsEntry",
+    "webkitGetDatabaseNames",
+    "webkitGetEntries",
+    "webkitGetEntriesByName",
+    "webkitGetEntriesByType",
+    "webkitGetFlowByName",
+    "webkitGetGamepads",
+    "webkitGetImageDataHD",
+    "webkitGetNamedFlows",
+    "webkitGetRegionFlowRanges",
+    "webkitGetUserMedia",
+    "webkitHasClosedCaptions",
+    "webkitHidden",
+    "webkitIDBCursor",
+    "webkitIDBDatabase",
+    "webkitIDBDatabaseError",
+    "webkitIDBDatabaseException",
+    "webkitIDBFactory",
+    "webkitIDBIndex",
+    "webkitIDBKeyRange",
+    "webkitIDBObjectStore",
+    "webkitIDBRequest",
+    "webkitIDBTransaction",
+    "webkitImageSmoothingEnabled",
+    "webkitIndexedDB",
+    "webkitInitMessageEvent",
+    "webkitIsFullScreen",
+    "webkitJustifyContent",
+    "webkitKeys",
+    "webkitLineClamp",
+    "webkitLineDashOffset",
+    "webkitLockOrientation",
+    "webkitMask",
+    "webkitMaskClip",
+    "webkitMaskComposite",
+    "webkitMaskImage",
+    "webkitMaskOrigin",
+    "webkitMaskPosition",
+    "webkitMaskPositionX",
+    "webkitMaskPositionY",
+    "webkitMaskRepeat",
+    "webkitMaskSize",
+    "webkitMatchesSelector",
+    "webkitMediaStream",
+    "webkitNotifications",
+    "webkitOfflineAudioContext",
+    "webkitOrder",
+    "webkitOrientation",
+    "webkitPeerConnection00",
+    "webkitPersistentStorage",
+    "webkitPerspective",
+    "webkitPerspectiveOrigin",
+    "webkitPointerLockElement",
+    "webkitPostMessage",
+    "webkitPreservesPitch",
+    "webkitPutImageDataHD",
+    "webkitRTCPeerConnection",
+    "webkitRegionOverset",
+    "webkitRelativePath",
+    "webkitRequestAnimationFrame",
+    "webkitRequestFileSystem",
+    "webkitRequestFullScreen",
+    "webkitRequestFullscreen",
+    "webkitRequestPointerLock",
+    "webkitResolveLocalFileSystemURL",
+    "webkitSetMediaKeys",
+    "webkitSetResourceTimingBufferSize",
+    "webkitShadowRoot",
+    "webkitShowPlaybackTargetPicker",
+    "webkitSlice",
+    "webkitSpeechGrammar",
+    "webkitSpeechGrammarList",
+    "webkitSpeechRecognition",
+    "webkitSpeechRecognitionError",
+    "webkitSpeechRecognitionEvent",
+    "webkitStorageInfo",
+    "webkitSupportsFullscreen",
+    "webkitTemporaryStorage",
+    "webkitTextFillColor",
+    "webkitTextSecurity",
+    "webkitTextSizeAdjust",
+    "webkitTextStroke",
+    "webkitTextStrokeColor",
+    "webkitTextStrokeWidth",
+    "webkitTransform",
+    "webkitTransformOrigin",
+    "webkitTransformStyle",
+    "webkitTransition",
+    "webkitTransitionDelay",
+    "webkitTransitionDuration",
+    "webkitTransitionProperty",
+    "webkitTransitionTimingFunction",
+    "webkitURL",
+    "webkitUnlockOrientation",
+    "webkitUserSelect",
+    "webkitVideoDecodedByteCount",
+    "webkitVisibilityState",
+    "webkitWirelessVideoPlaybackDisabled",
+    "webkitdirectory",
+    "webkitdropzone",
+    "webstore",
+    "weekday",
+    "weeks",
+    "weight",
+    "wgslLanguageFeatures",
+    "whatToShow",
+    "wheelDelta",
+    "wheelDeltaX",
+    "wheelDeltaY",
+    "when",
+    "whenDefined",
+    "which",
+    "white-space",
+    "white-space-collapse",
+    "whiteSpace",
+    "whiteSpaceCollapse",
+    "wholeText",
+    "widows",
+    "width",
+    "will-change",
+    "willChange",
+    "willValidate",
+    "window",
+    "windowAttribution",
+    "windowControlsOverlay",
+    "windowId",
+    "windowIds",
+    "windows",
+    "with",
+    "withCredentials",
+    "withResolvers",
+    "word-break",
+    "word-spacing",
+    "word-wrap",
+    "wordBreak",
+    "wordSpacing",
+    "wordWrap",
+    "workerCacheLookupStart",
+    "workerFinalSourceType",
+    "workerMatchedSourceType",
+    "workerRouterEvaluationStart",
+    "workerStart",
+    "worklet",
+    "wow64",
+    "wrap",
+    "wrapKey",
+    "writable",
+    "writableAuxiliaries",
+    "write",
+    "writeBuffer",
+    "writeMask",
+    "writeText",
+    "writeTexture",
+    "writeTimestamp",
+    "writeValue",
+    "writeValueWithResponse",
+    "writeValueWithoutResponse",
+    "writeWithoutResponse",
+    "writeln",
+    "writing-mode",
+    "writingMode",
+    "writingSuggestions",
+    "x",
+    "x1",
+    "x2",
+    "xChannelSelector",
+    "xmlEncoding",
+    "xmlStandalone",
+    "xmlVersion",
+    "xmlbase",
+    "xmllang",
+    "xmlspace",
+    "xor",
+    "xr",
+    "y",
+    "y1",
+    "y2",
+    "yChannelSelector",
+    "yandex",
+    "year",
+    "years",
+    "yield",
+    "z",
+    "z-index",
+    "zIndex",
+    "zoom",
+    "zoomAndPan",
+    "zoomLevel",
+    "zoomRectScreen",
+];
+
+/***********************************************************************
+
+  A JavaScript tokenizer / parser / beautifier / compressor.
+  https://github.com/mishoo/UglifyJS2
+
+  -------------------------------- (C) ---------------------------------
+
+                           Author: Mihai Bazon
+                         <mihai.bazon@gmail.com>
+                       http://mihai.bazon.net/blog
+
+  Distributed under the BSD license:
+
+    Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+        * Redistributions of source code must retain the above
+          copyright notice, this list of conditions and the following
+          disclaimer.
+
+        * Redistributions in binary form must reproduce the above
+          copyright notice, this list of conditions and the following
+          disclaimer in the documentation and/or other materials
+          provided with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+
+ ***********************************************************************/
+
+function find_builtins(reserved) {
+    domprops.forEach(add);
+
+    // Compatibility fix for some standard defined globals not defined on every js environment
+    var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"];
+    var objects = {};
+    var global_ref = typeof global === "object" ? global : self;
+
+    new_globals.forEach(function (new_global) {
+        objects[new_global] = global_ref[new_global] || function() {};
+    });
+
+    [
+        "null",
+        "true",
+        "false",
+        "NaN",
+        "Infinity",
+        "-Infinity",
+        "undefined",
+    ].forEach(add);
+    [ Object, Array, Function, Number,
+      String, Boolean, Error, Math,
+      Date, RegExp, objects.Symbol, ArrayBuffer,
+      DataView, decodeURI, decodeURIComponent,
+      encodeURI, encodeURIComponent, eval, EvalError,
+      Float32Array, Float64Array, Int8Array, Int16Array,
+      Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat,
+      parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError,
+      objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array,
+      Uint8ClampedArray, Uint16Array, Uint32Array, URIError,
+      objects.WeakMap, objects.WeakSet
+    ].forEach(function(ctor) {
+        Object.getOwnPropertyNames(ctor).map(add);
+        if (ctor.prototype) {
+            Object.getOwnPropertyNames(ctor.prototype).map(add);
+        }
+    });
+    function add(name) {
+        reserved.add(name);
+    }
+}
+
+function reserve_quoted_keys(ast, reserved) {
+    function add(name) {
+        push_uniq(reserved, name);
+    }
+
+    ast.walk(new TreeWalker(function(node) {
+        if (node instanceof AST_ObjectKeyVal && node.quote) {
+            add(node.key);
+        } else if (node instanceof AST_ObjectProperty && node.quote) {
+            add(node.key.name);
+        } else if (node instanceof AST_Sub) {
+            addStrings(node.property, add);
+        }
+    }));
+}
+
+function addStrings(node, add) {
+    node.walk(new TreeWalker(function(node) {
+        if (node instanceof AST_Sequence) {
+            addStrings(node.tail_node(), add);
+        } else if (node instanceof AST_String) {
+            add(node.value);
+        } else if (node instanceof AST_Conditional) {
+            addStrings(node.consequent, add);
+            addStrings(node.alternative, add);
+        }
+        return true;
+    }));
+}
+
+function mangle_private_properties(ast, options) {
+    var cprivate = -1;
+    var private_cache = new Map();
+    var nth_identifier = options.nth_identifier || base54;
+
+    ast =  ast.transform(new TreeTransformer(function(node) {
+        if (
+            node instanceof AST_ClassPrivateProperty
+            || node instanceof AST_PrivateMethod
+            || node instanceof AST_PrivateGetter
+            || node instanceof AST_PrivateSetter
+            || node instanceof AST_PrivateIn
+        ) {
+            node.key.name = mangle_private(node.key.name);
+        } else if (node instanceof AST_DotHash) {
+            node.property = mangle_private(node.property);
+        }
+    }));
+    return ast;
+
+    function mangle_private(name) {
+        let mangled = private_cache.get(name);
+        if (!mangled) {
+            mangled = nth_identifier.get(++cprivate);
+            private_cache.set(name, mangled);
+        }
+
+        return mangled;
+    }
+}
+
+function find_annotated_props(ast) {
+    var annotated_props = new Set();
+    walk(ast, node => {
+        if (
+            node instanceof AST_ClassPrivateProperty
+            || node instanceof AST_PrivateMethod
+            || node instanceof AST_PrivateGetter
+            || node instanceof AST_PrivateSetter
+            || node instanceof AST_DotHash
+        ) ; else if (node instanceof AST_ObjectKeyVal) {
+            if (typeof node.key == "string" && has_annotation(node, _MANGLEPROP)) {
+                annotated_props.add(node.key);
+            }
+        } else if (node instanceof AST_ObjectProperty) {
+            // setter or getter, since KeyVal is handled above
+            if (has_annotation(node, _MANGLEPROP)) {
+                annotated_props.add(node.key.name);
+            }
+        } else if (node instanceof AST_Dot) {
+            if (has_annotation(node, _MANGLEPROP)) {
+                annotated_props.add(node.property);
+            }
+        } else if (node instanceof AST_Sub) {
+            if (node.property instanceof AST_String && has_annotation(node, _MANGLEPROP)) {
+                annotated_props.add(node.property.value);
+            }
+        }
+    });
+    return annotated_props;
+}
+
+function mangle_properties(ast, options, annotated_props = find_annotated_props(ast)) {
+    options = defaults(options, {
+        builtins: false,
+        cache: null,
+        debug: false,
+        keep_quoted: false,
+        nth_identifier: base54,
+        only_cache: false,
+        regex: null,
+        reserved: null,
+        undeclared: false,
+        only_annotated: false,
+    }, true);
+
+    var nth_identifier = options.nth_identifier;
+
+    var reserved_option = options.reserved;
+    if (!Array.isArray(reserved_option)) reserved_option = [reserved_option];
+    var reserved = new Set(reserved_option);
+    if (!options.builtins) find_builtins(reserved);
+
+    var cname = -1;
+
+    var cache;
+    if (options.cache) {
+        cache = options.cache.props;
+    } else {
+        cache = new Map();
+    }
+
+    var only_annotated = options.only_annotated;
+    var regex = options.regex && new RegExp(options.regex);
+
+    // note debug is either false (disabled), or a string of the debug suffix to use (enabled).
+    // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
+    // the same as passing an empty string.
+    var debug = options.debug !== false;
+    var debug_name_suffix;
+    if (debug) {
+        debug_name_suffix = (options.debug === true ? "" : options.debug);
+    }
+
+    var names_to_mangle = new Set();
+    var unmangleable = new Set();
+    // Track each already-mangled name to prevent nth_identifier from generating
+    // the same name.
+    cache.forEach((mangled_name) => unmangleable.add(mangled_name));
+
+    var keep_quoted = !!options.keep_quoted;
+
+    // step 1: find candidates to mangle
+    ast.walk(new TreeWalker(function(node) {
+        if (
+            node instanceof AST_ClassPrivateProperty
+            || node instanceof AST_PrivateMethod
+            || node instanceof AST_PrivateGetter
+            || node instanceof AST_PrivateSetter
+            || node instanceof AST_DotHash
+        ) ; else if (node instanceof AST_ObjectKeyVal) {
+            if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
+                add(node.key);
+            }
+        } else if (node instanceof AST_ObjectProperty) {
+            // setter or getter, since KeyVal is handled above
+            if (!keep_quoted || !node.quote) {
+                add(node.key.name);
+            }
+        } else if (node instanceof AST_Dot) {
+            var declared = !!options.undeclared;
+            if (!declared) {
+                var root = node;
+                while (root.expression) {
+                    root = root.expression;
+                }
+                declared = !(root.thedef && root.thedef.undeclared);
+            }
+            if (declared &&
+                (!keep_quoted || !node.quote)) {
+                add(node.property);
+            }
+        } else if (node instanceof AST_Sub) {
+            if (!keep_quoted) {
+                addStrings(node.property, add);
+            }
+        } else if (node instanceof AST_Call
+            && node.expression.print_to_string() == "Object.defineProperty") {
+            addStrings(node.args[1], add);
+        } else if (node instanceof AST_Binary && node.operator === "in") {
+            addStrings(node.left, add);
+        } else if (node instanceof AST_String && has_annotation(node, _KEY)) {
+            add(node.value);
+        }
+    }));
+
+    // step 2: transform the tree, renaming properties
+    return ast.transform(new TreeTransformer(function(node) {
+        if (
+            node instanceof AST_ClassPrivateProperty
+            || node instanceof AST_PrivateMethod
+            || node instanceof AST_PrivateGetter
+            || node instanceof AST_PrivateSetter
+            || node instanceof AST_DotHash
+        ) ; else if (node instanceof AST_ObjectKeyVal) {
+            if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
+                node.key = mangle(node.key);
+            }
+        } else if (node instanceof AST_ObjectProperty) {
+            // setter, getter, method or class field
+            if (!keep_quoted || !node.quote) {
+                if (!node.computed_key()) {
+                    node.key.name = mangle(node.key.name);
+                }
+            }
+        } else if (node instanceof AST_Dot) {
+            if (!keep_quoted || !node.quote) {
+                node.property = mangle(node.property);
+            }
+        } else if (!keep_quoted && node instanceof AST_Sub) {
+            node.property = mangleStrings(node.property);
+        } else if (node instanceof AST_Call
+            && node.expression.print_to_string() == "Object.defineProperty") {
+            node.args[1] = mangleStrings(node.args[1]);
+        } else if (node instanceof AST_Binary && node.operator === "in") {
+            node.left = mangleStrings(node.left);
+        } else if (node instanceof AST_String && has_annotation(node, _KEY)) {
+            // Clear _KEY annotation to prevent double mangling
+            clear_annotation(node, _KEY);
+            node.value = mangle(node.value);
+        }
+    }));
+
+    // only function declarations after this line
+
+    function can_mangle(name) {
+        if (unmangleable.has(name)) return false;
+        if (reserved.has(name)) return false;
+        if (options.only_cache) {
+            return cache.has(name);
+        }
+        if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
+        return true;
+    }
+
+    function should_mangle(name) {
+        if (only_annotated && !annotated_props.has(name)) return false;
+        if (regex && !regex.test(name)) {
+            return annotated_props.has(name);
+        }
+        if (reserved.has(name)) return false;
+        return cache.has(name)
+            || names_to_mangle.has(name);
+    }
+
+    function add(name) {
+        if (can_mangle(name)) {
+            names_to_mangle.add(name);
+        }
+
+        if (!should_mangle(name)) {
+            unmangleable.add(name);
+        }
+    }
+
+    function mangle(name) {
+        if (!should_mangle(name)) {
+            return name;
+        }
+
+        var mangled = cache.get(name);
+        if (!mangled) {
+            if (debug) {
+                // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
+                var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
+
+                if (can_mangle(debug_mangled)) {
+                    mangled = debug_mangled;
+                }
+            }
+
+            // either debug mode is off, or it is on and we could not use the mangled name
+            if (!mangled) {
+                do {
+                    mangled = nth_identifier.get(++cname);
+                } while (!can_mangle(mangled));
+            }
+
+            cache.set(name, mangled);
+        }
+        return mangled;
+    }
+
+    function mangleStrings(node) {
+        return node.transform(new TreeTransformer(function(node) {
+            if (node instanceof AST_Sequence) {
+                var last = node.expressions.length - 1;
+                node.expressions[last] = mangleStrings(node.expressions[last]);
+            } else if (node instanceof AST_String) {
+                // Clear _KEY annotation to prevent double mangling
+                clear_annotation(node, _KEY);
+                node.value = mangle(node.value);
+            } else if (node instanceof AST_Conditional) {
+                node.consequent = mangleStrings(node.consequent);
+                node.alternative = mangleStrings(node.alternative);
+            }
+            return node;
+        }));
+    }
+}
+
+// to/from base64 functions
+// Prefer built-in Buffer, if available, then use hack
+// https://developer.mozilla.org/en-US/docs/Glossary/Base64#The_Unicode_Problem
+var to_ascii = typeof Buffer !== "undefined"
+    ? (b64) => Buffer.from(b64, "base64").toString()
+    : (b64) => decodeURIComponent(escape(atob(b64)));
+var to_base64 = typeof Buffer !== "undefined"
+    ? (str) => Buffer.from(str).toString("base64")
+    : (str) => btoa(unescape(encodeURIComponent(str)));
+
+function read_source_map(code) {
+    var match = /(?:^|[^.])\/\/# sourceMappingURL=data:application\/json(;[\w=-]*)?;base64,([+/0-9A-Za-z]*=*)\s*$/.exec(code);
+    if (!match) {
+        console.warn("inline source map not found");
+        return null;
+    }
+    return to_ascii(match[2]);
+}
+
+function set_shorthand(name, options, keys) {
+    if (options[name]) {
+        keys.forEach(function(key) {
+            if (options[key]) {
+                if (typeof options[key] != "object") options[key] = {};
+                if (!(name in options[key])) options[key][name] = options[name];
+            }
+        });
+    }
+}
+
+function init_cache(cache) {
+    if (!cache) return;
+    if (!("props" in cache)) {
+        cache.props = new Map();
+    } else if (!(cache.props instanceof Map)) {
+        cache.props = map_from_object(cache.props);
+    }
+}
+
+function cache_to_json(cache) {
+    return {
+        props: map_to_object(cache.props)
+    };
+}
+
+function log_input(files, options, fs, debug_folder) {
+    if (!(fs && fs.writeFileSync && fs.mkdirSync)) {
+        return;
+    }
+
+    try {
+        fs.mkdirSync(debug_folder);
+    } catch (e) {
+        if (e.code !== "EEXIST") throw e;
+    }
+
+    const log_path = `${debug_folder}/terser-debug-${(Math.random() * 9999999) | 0}.log`;
+
+    options = options || {};
+
+    const options_str = JSON.stringify(options, (_key, thing) => {
+        if (typeof thing === "function") return "[Function " + thing.toString() + "]";
+        if (thing instanceof RegExp) return "[RegExp " + thing.toString() + "]";
+        return thing;
+    }, 4);
+
+    const files_str = (file) => {
+        if (typeof file === "object" && options.parse && options.parse.spidermonkey) {
+            return JSON.stringify(file, null, 2);
+        } else if (typeof file === "object") {
+            return Object.keys(file)
+                .map((key) => key + ": " + files_str(file[key]))
+                .join("\n\n");
+        } else if (typeof file === "string") {
+            return "```\n" + file + "\n```";
+        } else {
+            return file; // What do?
+        }
+    };
+
+    fs.writeFileSync(log_path, "Options: \n" + options_str + "\n\nInput files:\n\n" + files_str(files) + "\n");
+}
+
+function* minify_sync_or_async(files, options, _fs_module) {
+    if (
+        _fs_module
+        && typeof process === "object"
+        && process.env
+        && typeof process.env.TERSER_DEBUG_DIR === "string"
+    ) {
+        log_input(files, options, _fs_module, process.env.TERSER_DEBUG_DIR);
+    }
+
+    options = defaults(options, {
+        compress: {},
+        ecma: undefined,
+        enclose: false,
+        ie8: false,
+        keep_classnames: undefined,
+        keep_fnames: false,
+        mangle: {},
+        module: false,
+        nameCache: null,
+        output: null,
+        format: null,
+        parse: {},
+        rename: undefined,
+        safari10: false,
+        sourceMap: false,
+        spidermonkey: false,
+        timings: false,
+        toplevel: false,
+        warnings: false,
+        wrap: false,
+    }, true);
+
+    var timings = options.timings && {
+        start: Date.now()
+    };
+    if (options.keep_classnames === undefined) {
+        options.keep_classnames = options.keep_fnames;
+    }
+    if (options.rename === undefined) {
+        options.rename = options.compress && options.mangle;
+    }
+    if (options.output && options.format) {
+        throw new Error("Please only specify either output or format option, preferrably format.");
+    }
+    options.format = options.format || options.output || {};
+    set_shorthand("ecma", options, [ "parse", "compress", "format" ]);
+    set_shorthand("ie8", options, [ "compress", "mangle", "format" ]);
+    set_shorthand("keep_classnames", options, [ "compress", "mangle" ]);
+    set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
+    set_shorthand("module", options, [ "parse", "compress", "mangle" ]);
+    set_shorthand("safari10", options, [ "mangle", "format" ]);
+    set_shorthand("toplevel", options, [ "compress", "mangle" ]);
+    set_shorthand("warnings", options, [ "compress" ]); // legacy
+    var quoted_props;
+    if (options.mangle) {
+        options.mangle = defaults(options.mangle, {
+            cache: options.nameCache && (options.nameCache.vars || {}),
+            eval: false,
+            ie8: false,
+            keep_classnames: false,
+            keep_fnames: false,
+            module: false,
+            nth_identifier: base54,
+            properties: false,
+            reserved: [],
+            safari10: false,
+            toplevel: false,
+        }, true);
+        if (options.mangle.properties) {
+            if (typeof options.mangle.properties != "object") {
+                options.mangle.properties = {};
+            }
+            if (options.mangle.properties.keep_quoted) {
+                quoted_props = options.mangle.properties.reserved;
+                if (!Array.isArray(quoted_props)) quoted_props = [];
+                options.mangle.properties.reserved = quoted_props;
+            }
+            if (options.nameCache && !("cache" in options.mangle.properties)) {
+                options.mangle.properties.cache = options.nameCache.props || {};
+            }
+        }
+        init_cache(options.mangle.cache);
+        init_cache(options.mangle.properties.cache);
+    }
+    if (options.sourceMap) {
+        options.sourceMap = defaults(options.sourceMap, {
+            asObject: false,
+            content: null,
+            filename: null,
+            includeSources: false,
+            root: null,
+            url: null,
+        }, true);
+    }
+
+    // -- Parse phase --
+    if (timings) timings.parse = Date.now();
+    var toplevel;
+    if (files instanceof AST_Toplevel) {
+        toplevel = files;
+    } else {
+        if (typeof files == "string" || (options.parse.spidermonkey && !Array.isArray(files))) {
+            files = [ files ];
+        }
+        options.parse = options.parse || {};
+        options.parse.toplevel = null;
+
+        if (options.parse.spidermonkey) {
+            options.parse.toplevel = AST_Node.from_mozilla_ast(Object.keys(files).reduce(function(toplevel, name) {
+                if (!toplevel) return files[name];
+                toplevel.body = toplevel.body.concat(files[name].body);
+                return toplevel;
+            }, null));
+        } else {
+            delete options.parse.spidermonkey;
+
+            for (var name in files) if (HOP(files, name)) {
+                options.parse.filename = name;
+                options.parse.toplevel = parse(files[name], options.parse);
+                if (options.sourceMap && options.sourceMap.content == "inline") {
+                    if (Object.keys(files).length > 1)
+                        throw new Error("inline source map only works with singular input");
+                    options.sourceMap.content = read_source_map(files[name]);
+                }
+            }
+        }
+        if (options.parse.toplevel === null) {
+            throw new Error("no source file given");
+        }
+
+        toplevel = options.parse.toplevel;
+    }
+    if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
+        reserve_quoted_keys(toplevel, quoted_props);
+    }
+    var annotated_props;
+    if (options.mangle && options.mangle.properties) {
+        annotated_props = find_annotated_props(toplevel);
+    }
+    if (options.wrap) {
+        toplevel = toplevel.wrap_commonjs(options.wrap);
+    }
+    if (options.enclose) {
+        toplevel = toplevel.wrap_enclose(options.enclose);
+    }
+    if (timings) timings.rename = Date.now();
+
+    // -- Compress phase --
+    if (timings) timings.compress = Date.now();
+    if (options.compress) {
+        toplevel = new Compressor(options.compress, {
+            mangle_options: options.mangle
+        }).compress(toplevel);
+    }
+
+    // -- Mangle phase --
+    if (timings) timings.scope = Date.now();
+    if (options.mangle) toplevel.figure_out_scope(options.mangle);
+    if (timings) timings.mangle = Date.now();
+    if (options.mangle) {
+        toplevel.compute_char_frequency(options.mangle);
+        toplevel.mangle_names(options.mangle);
+        toplevel = mangle_private_properties(toplevel, options.mangle);
+    }
+    if (timings) timings.properties = Date.now();
+    if (options.mangle && options.mangle.properties) {
+        toplevel = mangle_properties(toplevel, options.mangle.properties, annotated_props);
+    }
+
+    // Format phase
+    if (timings) timings.format = Date.now();
+    var result = {};
+    if (options.format.ast) {
+        result.ast = toplevel;
+    }
+    if (options.format.spidermonkey) {
+        result.ast = toplevel.to_mozilla_ast();
+    }
+    let format_options;
+    if (!HOP(options.format, "code") || options.format.code) {
+        // Make a shallow copy so that we can modify without mutating the user's input.
+        format_options = {...options.format};
+        if (!format_options.ast) {
+            // Destroy stuff to save RAM. (unless the deprecated `ast` option is on)
+            format_options._destroy_ast = true;
+
+            walk(toplevel, node => {
+                if (node instanceof AST_Scope) {
+                    node.variables = undefined;
+                    node.enclosed = undefined;
+                    node.parent_scope = undefined;
+                }
+                if (node.block_scope) {
+                    node.block_scope.variables = undefined;
+                    node.block_scope.enclosed = undefined;
+                    node.block_scope.parent_scope = undefined;
+                }
+            });
+        }
+
+        if (options.sourceMap) {
+            if (options.sourceMap.includeSources && files instanceof AST_Toplevel) {
+                throw new Error("original source content unavailable");
+            }
+            format_options.source_map = yield* SourceMap({
+                file: options.sourceMap.filename,
+                orig: options.sourceMap.content,
+                root: options.sourceMap.root,
+                files: options.sourceMap.includeSources ? files : null,
+            });
+        }
+        delete format_options.ast;
+        delete format_options.code;
+        delete format_options.spidermonkey;
+        var stream = OutputStream(format_options);
+        toplevel.print(stream);
+        result.code = stream.get();
+        if (options.sourceMap) {
+            Object.defineProperty(result, "map", {
+                configurable: true,
+                enumerable: true,
+                get() {
+                    const map = format_options.source_map.getEncoded();
+                    return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map));
+                },
+                set(value) {
+                    Object.defineProperty(result, "map", {
+                        value,
+                        writable: true,
+                    });
+                }
+            });
+            result.decoded_map = format_options.source_map.getDecoded();
+            if (options.sourceMap.url == "inline") {
+                var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map;
+                result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap);
+            } else if (options.sourceMap.url) {
+                result.code += "\n//# sourceMappingURL=" + options.sourceMap.url;
+            }
+        }
+    }
+    if (options.nameCache && options.mangle) {
+        if (options.mangle.cache) options.nameCache.vars = cache_to_json(options.mangle.cache);
+        if (options.mangle.properties && options.mangle.properties.cache) {
+            options.nameCache.props = cache_to_json(options.mangle.properties.cache);
+        }
+    }
+    if (format_options && format_options.source_map) {
+        format_options.source_map.destroy();
+    }
+    if (timings) {
+        timings.end = Date.now();
+        result.timings = {
+            parse: 1e-3 * (timings.rename - timings.parse),
+            rename: 1e-3 * (timings.compress - timings.rename),
+            compress: 1e-3 * (timings.scope - timings.compress),
+            scope: 1e-3 * (timings.mangle - timings.scope),
+            mangle: 1e-3 * (timings.properties - timings.mangle),
+            properties: 1e-3 * (timings.format - timings.properties),
+            format: 1e-3 * (timings.end - timings.format),
+            total: 1e-3 * (timings.end - timings.start)
+        };
+    }
+    return result;
+}
+
+async function minify(files, options, _fs_module) {
+    const gen = minify_sync_or_async(files, options, _fs_module);
+
+    let yielded;
+    let val;
+    do {
+        val = gen.next(await yielded);
+        yielded = val.value;
+    } while (!val.done);
+
+    return val.value;
+}
+
+function minify_sync(files, options, _fs_module) {
+    const gen = minify_sync_or_async(files, options, _fs_module);
+
+    let yielded;
+    let val;
+    do {
+        if (yielded && typeof yielded.then === "function") {
+            throw new Error("minify_sync cannot be used with the legacy source-map module");
+        }
+        val = gen.next(yielded);
+        yielded = val.value;
+    } while (!val.done);
+
+    return val.value;
+}
+
+async function run_cli({ program, packageJson, fs, path }) {
+    const skip_keys = new Set([ "cname", "parent_scope", "scope", "uses_eval", "uses_with" ]);
+    var files = {};
+    var options = {
+        compress: false,
+        mangle: false
+    };
+    const default_options = await _default_options();
+    program.version(packageJson.name + " " + packageJson.version);
+    program.parseArgv = program.parse;
+    program.parse = undefined;
+
+    if (process.argv.includes("ast")) program.helpInformation = describe_ast;
+    else if (process.argv.includes("options")) program.helpInformation = function() {
+        var text = [];
+        for (var option in default_options) {
+            text.push("--" + (option === "sourceMap" ? "source-map" : option) + " options:");
+            text.push(format_object(default_options[option]));
+            text.push("");
+        }
+        return text.join("\n");
+    };
+
+    program.option("-p, --parse <options>", "Specify parser options.", parse_js());
+    program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
+    program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
+    program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
+    program.option("-f, --format [options]", "Format options.", parse_js());
+    program.option("-b, --beautify [options]", "Alias for --format.", parse_js());
+    program.option("-o, --output <file>", "Output file (default STDOUT).");
+    program.option("--comments [filter]", "Preserve copyright comments in the output.");
+    program.option("--config-file <file>", "Read minify() options from JSON file.");
+    program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
+    program.option("--ecma <version>", "Specify ECMAScript release: 5, 2015, 2016 or 2017...");
+    program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed output in a big function with configurable arguments and values.");
+    program.option("--ie8", "Support non-standard Internet Explorer 8.");
+    program.option("--keep-classnames", "Do not mangle/drop class names.");
+    program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
+    program.option("--module", "Input is an ES6 module");
+    program.option("--name-cache <file>", "File to hold mangled name mappings.");
+    program.option("--rename", "Force symbol expansion.");
+    program.option("--no-rename", "Disable symbol expansion.");
+    program.option("--safari10", "Support non-standard Safari 10.");
+    program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
+    program.option("--timings", "Display operations run time on STDERR.");
+    program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
+    program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
+    program.arguments("[files...]").parseArgv(process.argv);
+    if (program.configFile) {
+        options = JSON.parse(read_file(program.configFile));
+    }
+    if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
+        fatal("ERROR: cannot write source map to STDOUT");
+    }
+
+    [
+        "compress",
+        "enclose",
+        "ie8",
+        "mangle",
+        "module",
+        "safari10",
+        "sourceMap",
+        "toplevel",
+        "wrap"
+    ].forEach(function(name) {
+        if (name in program) {
+            options[name] = program[name];
+        }
+    });
+
+    if ("ecma" in program) {
+        if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
+        const ecma = program.ecma | 0;
+        if (ecma > 5 && ecma < 2015)
+            options.ecma = ecma + 2009;
+        else
+            options.ecma = ecma;
+    }
+    if (program.format || program.beautify) {
+        const chosenOption = program.format || program.beautify;
+        options.format = typeof chosenOption === "object" ? chosenOption : {};
+    }
+    if (program.comments) {
+        if (typeof options.format != "object") options.format = {};
+        options.format.comments = typeof program.comments == "string" ? (program.comments == "false" ? false : program.comments) : "some";
+    }
+    if (program.define) {
+        if (typeof options.compress != "object") options.compress = {};
+        if (typeof options.compress.global_defs != "object") options.compress.global_defs = {};
+        for (var expr in program.define) {
+            options.compress.global_defs[expr] = program.define[expr];
+        }
+    }
+    if (program.keepClassnames) {
+        options.keep_classnames = true;
+    }
+    if (program.keepFnames) {
+        options.keep_fnames = true;
+    }
+    if (program.mangleProps) {
+        if (program.mangleProps.domprops) {
+            delete program.mangleProps.domprops;
+        } else {
+            if (typeof program.mangleProps != "object") program.mangleProps = {};
+            if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
+        }
+        if (typeof options.mangle != "object") options.mangle = {};
+        options.mangle.properties = program.mangleProps;
+    }
+    if (program.nameCache) {
+        options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
+    }
+    if (program.output == "ast") {
+        options.format = {
+            ast: true,
+            code: false
+        };
+    }
+    if (program.parse) {
+        if (!program.parse.acorn && !program.parse.spidermonkey) {
+            options.parse = program.parse;
+        } else if (program.sourceMap && program.sourceMap.content == "inline") {
+            fatal("ERROR: inline source map only works with built-in parser");
+        }
+    }
+    if (~program.rawArgs.indexOf("--rename")) {
+        options.rename = true;
+    } else if (!program.rename) {
+        options.rename = false;
+    }
+
+    let convert_path = name => name;
+    if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
+        convert_path = function() {
+            var base = program.sourceMap.base;
+            delete options.sourceMap.base;
+            return function(name) {
+                return path.relative(base, name);
+            };
+        }();
+    }
+
+    let filesList;
+    if (options.files && options.files.length) {
+        filesList = options.files;
+
+        delete options.files;
+    } else if (program.args.length) {
+        filesList = program.args;
+    }
+
+    if (filesList) {
+        simple_glob(filesList).forEach(function(name) {
+            files[convert_path(name)] = read_file(name);
+        });
+    } else {
+        await new Promise((resolve) => {
+            var chunks = [];
+            process.stdin.setEncoding("utf8");
+            process.stdin.on("data", function(chunk) {
+                chunks.push(chunk);
+            }).on("end", function() {
+                files = [ chunks.join("") ];
+                resolve();
+            });
+            process.stdin.resume();
+        });
+    }
+
+    await run_cli();
+
+    function convert_ast(fn) {
+        return AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
+    }
+
+    async function run_cli() {
+        var content = program.sourceMap && program.sourceMap.content;
+        if (content && content !== "inline") {
+            options.sourceMap.content = read_file(content, content);
+        }
+        if (program.timings) options.timings = true;
+
+        try {
+            if (program.parse) {
+                if (program.parse.acorn) {
+                    files = convert_ast(function(toplevel, name) {
+                        return require("acorn").parse(files[name], {
+                            ecmaVersion: 2024,
+                            locations: true,
+                            program: toplevel,
+                            sourceFile: name,
+                            sourceType: options.module || program.parse.module ? "module" : "script"
+                        });
+                    });
+                } else if (program.parse.spidermonkey) {
+                    files = convert_ast(function(toplevel, name) {
+                        var obj = JSON.parse(files[name]);
+                        if (!toplevel) return obj;
+                        toplevel.body = toplevel.body.concat(obj.body);
+                        return toplevel;
+                    });
+                }
+            }
+        } catch (ex) {
+            fatal(ex);
+        }
+
+        let result;
+        try {
+            result = await minify(files, options, fs);
+        } catch (ex) {
+            if (ex.name == "SyntaxError") {
+                print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
+                var col = ex.col;
+                var lines = files[ex.filename].split(/\r?\n/);
+                var line = lines[ex.line - 1];
+                if (!line && !col) {
+                    line = lines[ex.line - 2];
+                    col = line.length;
+                }
+                if (line) {
+                    var limit = 70;
+                    if (col > limit) {
+                        line = line.slice(col - limit);
+                        col = limit;
+                    }
+                    print_error(line.slice(0, 80));
+                    print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
+                }
+            }
+            if (ex.defs) {
+                print_error("Supported options:");
+                print_error(format_object(ex.defs));
+            }
+            fatal(ex);
+            return;
+        }
+
+        if (program.output == "ast") {
+            if (!options.compress && !options.mangle) {
+                result.ast.figure_out_scope({});
+            }
+            console.log(JSON.stringify(result.ast, function(key, value) {
+                if (value) switch (key) {
+                  case "thedef":
+                    return symdef(value);
+                  case "enclosed":
+                    return value.length ? value.map(symdef) : undefined;
+                  case "variables":
+                  case "globals":
+                    return value.size ? collect_from_map(value, symdef) : undefined;
+                }
+                if (skip_keys.has(key)) return;
+                if (value instanceof AST_Token) return;
+                if (value instanceof Map) return;
+                if (value instanceof AST_Node) {
+                    var result = {
+                        _class: "AST_" + value.TYPE
+                    };
+                    if (value.block_scope) {
+                        result.variables = value.block_scope.variables;
+                        result.enclosed = value.block_scope.enclosed;
+                    }
+                    value.CTOR.PROPS.forEach(function(prop) {
+                        if (prop !== "block_scope") {
+                            result[prop] = value[prop];
+                        }
+                    });
+                    return result;
+                }
+                return value;
+            }, 2));
+        } else if (program.output == "spidermonkey") {
+            try {
+                const minified = await minify(
+                    result.code,
+                    {
+                        compress: false,
+                        mangle: false,
+                        format: {
+                            ast: true,
+                            code: false
+                        }
+                    },
+                    fs
+                );
+                console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2));
+            } catch (ex) {
+                fatal(ex);
+                return;
+            }
+        } else if (program.output) {
+            fs.mkdirSync(path.dirname(program.output), { recursive: true });
+            fs.writeFileSync(program.output, result.code);
+            if (options.sourceMap && options.sourceMap.url !== "inline" && result.map) {
+                fs.writeFileSync(program.output + ".map", result.map);
+            }
+        } else {
+            console.log(result.code);
+        }
+        if (program.nameCache) {
+            fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
+        }
+        if (result.timings) for (var phase in result.timings) {
+            print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
+        }
+    }
+
+    function fatal(message) {
+        if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:");
+        print_error(message);
+        process.exit(1);
+    }
+
+    // A file glob function that only supports "*" and "?" wildcards in the basename.
+    // Example: "foo/bar/*baz??.*.js"
+    // Argument `glob` may be a string or an array of strings.
+    // Returns an array of strings. Garbage in, garbage out.
+    function simple_glob(glob) {
+        if (Array.isArray(glob)) {
+            return [].concat.apply([], glob.map(simple_glob));
+        }
+        if (glob && glob.match(/[*?]/)) {
+            var dir = path.dirname(glob);
+            try {
+                var entries = fs.readdirSync(dir);
+            } catch (ex) {}
+            if (entries) {
+                var pattern = "^" + path.basename(glob)
+                    .replace(/[.+^$[\]\\(){}]/g, "\\$&")
+                    .replace(/\*/g, "[^/\\\\]*")
+                    .replace(/\?/g, "[^/\\\\]") + "$";
+                var mod = process.platform === "win32" ? "i" : "";
+                var rx = new RegExp(pattern, mod);
+                var results = entries.filter(function(name) {
+                    return rx.test(name);
+                }).map(function(name) {
+                    return path.join(dir, name);
+                });
+                if (results.length) return results;
+            }
+        }
+        return [ glob ];
+    }
+
+    function read_file(path, default_value) {
+        try {
+            return fs.readFileSync(path, "utf8");
+        } catch (ex) {
+            if ((ex.code == "ENOENT" || ex.code == "ENAMETOOLONG") && default_value != null) return default_value;
+            fatal(ex);
+        }
+    }
+
+    function parse_js(flag) {
+        return function(value, options) {
+            options = options || {};
+            try {
+                walk(parse(value, { expression: true }), node => {
+                    if (node instanceof AST_Assign) {
+                        var name = node.left.print_to_string();
+                        var value = node.right;
+                        if (flag) {
+                            options[name] = value;
+                        } else if (value instanceof AST_Array) {
+                            options[name] = value.elements.map(to_string);
+                        } else if (value instanceof AST_RegExp) {
+                            value = value.value;
+                            options[name] = new RegExp(value.source, value.flags);
+                        } else {
+                            options[name] = to_string(value);
+                        }
+                        return true;
+                    }
+                    if (node instanceof AST_Symbol || node instanceof AST_PropAccess) {
+                        var name = node.print_to_string();
+                        options[name] = true;
+                        return true;
+                    }
+                    if (!(node instanceof AST_Sequence)) throw node;
+
+                    function to_string(value) {
+                        return value instanceof AST_Constant ? value.getValue() : value.print_to_string({
+                            quote_keys: true
+                        });
+                    }
+                });
+            } catch(ex) {
+                if (flag) {
+                    fatal("Error parsing arguments for '" + flag + "': " + value);
+                } else {
+                    options[value] = null;
+                }
+            }
+            return options;
+        };
+    }
+
+    function symdef(def) {
+        var ret = (1e6 + def.id) + " " + def.name;
+        if (def.mangled_name) ret += " " + def.mangled_name;
+        return ret;
+    }
+
+    function collect_from_map(map, callback) {
+        var result = [];
+        map.forEach(function (def) {
+            result.push(callback(def));
+        });
+        return result;
+    }
+
+    function format_object(obj) {
+        var lines = [];
+        var padding = "";
+        Object.keys(obj).map(function(name) {
+            if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
+            return [ name, JSON.stringify(obj[name]) ];
+        }).forEach(function(tokens) {
+            lines.push("  " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
+        });
+        return lines.join("\n");
+    }
+
+    function print_error(msg) {
+        process.stderr.write(msg);
+        process.stderr.write("\n");
+    }
+
+    function describe_ast() {
+        var out = OutputStream({ beautify: true });
+        function doitem(ctor) {
+            out.print("AST_" + ctor.TYPE);
+            const props = ctor.SELF_PROPS.filter(prop => !/^\$/.test(prop));
+
+            if (props.length > 0) {
+                out.space();
+                out.with_parens(function() {
+                    props.forEach(function(prop, i) {
+                        if (i) out.space();
+                        out.print(prop);
+                    });
+                });
+            }
+
+            if (ctor.documentation) {
+                out.space();
+                out.print_string(ctor.documentation);
+            }
+
+            if (ctor.SUBCLASSES.length > 0) {
+                out.space();
+                out.with_block(function() {
+                    ctor.SUBCLASSES.forEach(function(ctor) {
+                        out.indent();
+                        doitem(ctor);
+                        out.newline();
+                    });
+                });
+            }
+        }
+        doitem(AST_Node);
+        return out + "\n";
+    }
+}
+
+async function _default_options() {
+    const defs = {};
+
+    Object.keys(infer_options({ 0: 0 })).forEach((component) => {
+        const options = infer_options({
+            [component]: {0: 0}
+        });
+
+        if (options) defs[component] = options;
+    });
+    return defs;
+}
+
+async function infer_options(options) {
+    try {
+        await minify("", options);
+    } catch (error) {
+        return error.defs;
+    }
+}
+
+exports._default_options = _default_options;
+exports._run_cli = run_cli;
+exports.minify = minify;
+exports.minify_sync = minify_sync;
+
+}));
Index: frontend/node_modules/terser/dist/package.json
===================================================================
--- frontend/node_modules/terser/dist/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
+++ frontend/node_modules/terser/dist/package.json	(revision 9af201e94b5a79beb92a30858fc54de4bc3b9449)
@@ -0,0 +1,10 @@
+{
+  "name": "dist",
+  "private": true,
+  "version": "1.0.0",
+  "main": "bundle.min.js",
+  "type": "commonjs",
+  "author": "",
+  "license": "BSD-2-Clause",
+  "description": "A package to hold the Terser dist bundle as commonjs while keeping the rest of it ESM. Nothing to see here."
+}
