/**
 * pacem v0.51.10-faraday (https://js.pacem.it)
 * Copyright 2025 Pacem (https://pacem.it)
 * Licensed under Apache-2.0
 */
var Pacem;
(function (Pacem) {
    class Arrays {
        static range(min, max, items = 2) {
            let x = min;
            const step = (max - min) / (items - 1);
            const output = [];
            if (step > 0) {
                while (output.length < items) {
                    output.push(x.roundoff());
                    x += step;
                }
            }
            return output;
        }
        static chunkify(source, size) {
            if (Pacem.NullChecker.isNullOrEmpty(source)) {
                return [];
            }
            if (size <= 0 || size % 1 !== 0) {
                throw new Error('Provide a positive integer number.');
            }
            const length = Math.ceil(source.length / size);
            return Array.from({ length }, (_, index) => {
                const start = index * size, end = start + size;
                return source.slice(start, end);
            });
        }
    }
    Pacem.Arrays = Arrays;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    class Blobs {
        static blobToDataURL(blob) {
            return new Promise((resolve, _) => {
                const a = new FileReader();
                a.onload = (e) => { resolve(e.target.result); };
                a.readAsDataURL(blob);
            });
        }
        static _b64ToUint8Array(bstr) {
            let n = bstr.length;
            const u8arr = new Uint8Array(n);
            while (n--) {
                u8arr[n] = bstr.charCodeAt(n);
            }
            return u8arr;
        }
        static base64ToBlob(bstr, options) {
            const u8arr = Blobs._b64ToUint8Array(atob(bstr));
            return new Blob([u8arr], options);
        }
        static dataURLToBlob(dataurl) {
            const coma = dataurl.indexOf(',');
            if (coma === -1) {
                return Blobs.base64ToBlob(dataurl);
            }
            else {
                const bstr = dataurl.substring(coma + 1), data = dataurl.substring(0, coma);
                const mime = data.match(/:(.*?);/)[1];
                return Blobs.base64ToBlob(bstr, { type: mime });
            }
        }
        static blobToText(blob, encoding) {
            return new Promise((resolve, _) => {
                blob.arrayBuffer().then(b => {
                    const decoder = new TextDecoder(encoding);
                    const output = decoder.decode(b);
                    resolve(output);
                });
            });
        }
        static textToBlob(content, type = 'text/plain') {
            const encoder = new TextEncoder();
            const byteArray = encoder.encode(content);
            return new Blob([byteArray], { type });
        }
    }
    Pacem.Blobs = Blobs;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Browsers;
    (function (Browsers) {
        const browserVersion = (userAgent, regex) => {
            const match = userAgent.match(regex);
            return match ? match[2] : null;
        };
        function detect(userAgent = navigator.userAgent) {
            let browser = 'unknown';
            let version = null;
            if (/ucbrowser/i.test(userAgent)) {
                browser = 'UCBrowser';
            }
            else if (/edg/i.test(userAgent)) {
                browser = 'Edge';
            }
            else if (/googlebot/i.test(userAgent)) {
                browser = 'GoogleBot';
            }
            else if (/chromium/i.test(userAgent)) {
                browser = 'Chromium';
            }
            else if (/firefox|fxios/i.test(userAgent) && !/seamonkey/i.test(userAgent)) {
                browser = 'Firefox';
            }
            else if (/; msie|trident/i.test(userAgent) && !/ucbrowser/i.test(userAgent)) {
                browser = 'IE';
            }
            else if (/chrome|crios/i.test(userAgent) && !/opr|opera|chromium|edg|ucbrowser|googlebot/i.test(userAgent)) {
                browser = 'Chrome';
            }
            else if (/safari/i.test(userAgent) && !/chromium|edg|ucbrowser|chrome|crios|opr|opera|fxios|firefox/i.test(userAgent)) {
                browser = 'Safari';
            }
            else if (/opr|opera/i.test(userAgent)) {
                browser = 'Opera';
            }
            switch (browser) {
                case 'UCBrowser':
                    version = browserVersion(userAgent, /(ucbrowser)\/([\d\.]+)/i);
                    break;
                case 'Edge':
                    version = browserVersion(userAgent, /(edge|edga|edgios|edg)\/([\d\.]+)/i);
                    break;
                case 'GoogleBot':
                    version = browserVersion(userAgent, /(googlebot)\/([\d\.]+)/i);
                    break;
                case 'Chromium':
                    version = browserVersion(userAgent, /(chromium)\/([\d\.]+)/i);
                    break;
                case 'Firefox':
                    version = browserVersion(userAgent, /(firefox|fxios)\/([\d\.]+)/i);
                    break;
                case 'Chrome':
                    version = browserVersion(userAgent, /(chrome|crios)\/([\d\.]+)/i);
                    break;
                case 'Safari':
                    version = browserVersion(userAgent, /(safari)\/([\d\.]+)/i);
                    break;
                case 'Opera':
                    version = browserVersion(userAgent, /(opera|opr)\/([\d\.]+)/i);
                    break;
                case 'IE': {
                    const tridentVersion = browserVersion(userAgent, /(trident)\/([\d\.]+)/i);
                    version = tridentVersion ? `${parseFloat(tridentVersion) + 4.0}` : '7.0';
                    break;
                }
                default:
                    version = '0.0.0.0';
                    break;
            }
            return { name: browser, version };
        }
        Browsers.detect = detect;
    })(Browsers = Pacem.Browsers || (Pacem.Browsers = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    const HSL_PATTERN = /^hsl\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*\)$/;
    const HSLA_PATTERN = /^hsla\s*\(\s*([\d\.]+)\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)%\s*,\s*([\d\.]+)\)$/;
    const RGB_PATTERN = /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/;
    const RGBA_PATTERN = /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\)$/;
    const HEX_PATTERN = /^#[a-f0-9]{6}$/;
    const HEX_SHORT_PATTERN = /^#[a-f0-9]{3}$/;
    ;
    ;
    ;
    function isRgb(clr) {
        const base = !Pacem.NullChecker.isNullOrEmpty(clr) && typeof clr === 'object' && 'r' in clr && 'g' in clr && 'b' in clr
            && typeof clr.r === 'number' && typeof clr.b === 'number' && typeof clr.g === 'number';
        if (!base) {
            return false;
        }
        clr.a ??= 1;
        return clr.r >= 0 && clr.r <= 1
            && clr.g >= 0 && clr.g <= 1
            && clr.b >= 0 && clr.b <= 1
            && clr.a >= 0 && clr.a <= 1;
    }
    function isHsl(clr) {
        const base = !Pacem.NullChecker.isNullOrEmpty(clr) && typeof clr === 'object' && 'h' in clr && 's' in clr && 'l' in clr
            && typeof clr.h === 'number' && typeof clr.s === 'number' && typeof clr.l === 'number';
        if (!base) {
            return false;
        }
        clr.a ??= 1;
        return clr.h >= 0 && clr.h <= 360
            && clr.s >= 0 && clr.s <= 1
            && clr.l >= 0 && clr.l <= 1
            && clr.a >= 0 && clr.a <= 1;
    }
    function luminance(rgb) {
        const r = rgb.r, g = rgb.g, b = rgb.b;
        const l = .5 * (Math.max(r, g, b) + Math.min(r, g, b));
        return l.clamp(0, 1);
    }
    const cieUtils = {
        adjustRgbChannel: (v) => {
            return v <= .03928 ? (v / 12.92) : Math.pow((v + .055) / 1.055, 2.4);
        },
        adjustRgbChannelInv: (v) => {
            return v <= .00304 ? (v * 12.92) : 1.055 * (Math.pow(v, 1 / 2.4) - .055);
        },
        adjustRgb: (rgb) => {
            const rgbOut = { r: cieUtils.adjustRgbChannel(rgb.r), g: cieUtils.adjustRgbChannel(rgb.g), b: cieUtils.adjustRgbChannel(rgb.b), a: rgb.a };
            return rgbOut;
        },
        adjustRgbInv: (rgb) => {
            const rgbOut = { r: cieUtils.adjustRgbChannelInv(rgb.r), g: cieUtils.adjustRgbChannelInv(rgb.g), b: cieUtils.adjustRgbChannelInv(rgb.b), a: rgb.a };
            return rgbOut;
        },
        X: (adjustedRgb) => {
            return .4125 * adjustedRgb.r + .3576 * adjustedRgb.g + .1804 * adjustedRgb.b;
        },
        Y: (adjustedRgb) => {
            return .2126 * adjustedRgb.r + .7152 * adjustedRgb.g + .0722 * adjustedRgb.b;
        },
        Z: (adjustedRgb) => {
            return .0193 * adjustedRgb.r + .1191 * adjustedRgb.g + .9503 * adjustedRgb.b;
        },
        relativeLuminance: (rgb) => {
            const adjRgb = cieUtils.adjustRgb(rgb);
            return cieUtils.Y(adjRgb);
        },
        rgbToCieXYZ: (rgb) => {
            const adjRgb = cieUtils.adjustRgb(rgb);
            const xyz = { x: cieUtils.X(adjRgb), y: cieUtils.Y(adjRgb), z: cieUtils.Z(adjRgb), a: rgb.a };
            return xyz;
        },
        cieXYZToRgb: (xyz) => {
            const r = 3.2410 * xyz.x - 1.5374 * xyz.y - .4986 * xyz.z, g = -.9692 * xyz.x + 1.8760 * xyz.y + .0416 * xyz.z, b = .0556 * xyz.x - .2040 * xyz.y + 1.0570 * xyz.z;
            return cieUtils.adjustRgbInv({ r, g, b, a: xyz.a });
        },
        contrastRatio: (rgb1, rgb2) => {
            const l1 = cieUtils.relativeLuminance(rgb1) + .05, l2 = cieUtils.relativeLuminance(rgb2) + .05;
            return l1 > l2 ?
                l1 / l2
                :
                    l2 / l1;
        }
    };
    function saturation(rgb, l) {
        const r = rgb.r, g = rgb.g, b = rgb.b;
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        const s = (l === 0 || l === 1) ? 0 : (max - min) / (1 - Math.abs(2 * l - 1));
        return s.clamp(0, 1);
    }
    function hueHexagon(rgb) {
        const r = rgb.r, g = rgb.g, b = rgb.b;
        const deg = Math.atan2(Math.sqrt(3) * (g - b), 2 * r - g - b) * 180 / Math.PI;
        return (deg + 360) % 360;
    }
    function hueCircle(rgb) {
        const r = rgb.r, g = rgb.g, b = rgb.b;
        const max = Math.max(r, g, b);
        const min = Math.min(r, g, b);
        let hue = 0;
        if (max !== min) {
            if (max === r) {
                hue = (60 * ((g - b) / (max - min)) + 360) % 360;
            }
            else if (max === g) {
                hue = (60 * ((b - r) / (max - min)) + 120) % 360;
            }
            else {
                hue = (60 * ((r - g) / (max - min)) + 240) % 360;
            }
        }
        return hue.clamp(0, 360);
    }
    function hexify(v) {
        return Pacem.Strings.leftPad(v.toString(16), 2, '0');
    }
    class Colors {
        static WCAG_MINIMUM_CONTRAST = 3.0;
        static WCAG_NORMAL_TEXT_CONTRAST = 4.5;
        static WCAG_SAFE_CONTRAST = 7.0;
        static _clampRGB(rgb) {
            const clmp = (n) => Math.min(1.0, Math.max(0, n));
            if (rgb[3] == null) {
                rgb[3] = 1.0;
            }
            return { r: clmp(rgb[0]), g: clmp(rgb[1]), b: clmp(rgb[2]), a: Math.min(1, Math.max(0, rgb[3])) };
        }
        static _normalize(rgb) {
            return [rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0, rgb[3]];
        }
        static parse(clr) {
            clr = (clr || '').toLowerCase();
            if (RGB_PATTERN.test(clr)) {
                let rgbArr = RGB_PATTERN.exec(clr);
                return this._clampRGB(this._normalize([parseInt(rgbArr[1]), parseInt(rgbArr[2]), parseInt(rgbArr[3]), 1]));
            }
            if (RGBA_PATTERN.test(clr)) {
                let rgbArr = RGBA_PATTERN.exec(clr);
                return this._clampRGB(this._normalize([parseInt(rgbArr[1]), parseInt(rgbArr[2]), parseInt(rgbArr[3]), parseFloat(rgbArr[4])]));
            }
            if (HEX_PATTERN.test(clr)) {
                let hex = HEX_PATTERN.exec(clr)[0];
                return this._clampRGB(this._normalize([parseInt('0x' + hex.substr(1, 2)), parseInt('0x' + hex.substr(3, 2)), parseInt('0x' + hex.substr(5, 2)), 1]));
            }
            if (HEX_SHORT_PATTERN.test(clr)) {
                let hex = HEX_SHORT_PATTERN.exec(clr)[0];
                let r = hex.substr(1, 1), g = hex.substr(2, 1), b = hex.substr(3, 1);
                return this._clampRGB(this._normalize([parseInt('0x' + r + r), parseInt('0x' + g + g), parseInt('0x' + b + b), 1]));
            }
            if (HSL_PATTERN.test(clr)) {
                let hslArr = HSL_PATTERN.exec(clr);
                const hsl = { h: parseFloat(hslArr[1]), s: parseFloat(hslArr[2]) * .01, l: parseFloat(hslArr[3]) * .01 };
                return this.rgb(hsl);
            }
            if (HSLA_PATTERN.test(clr)) {
                let hslaArr = HSLA_PATTERN.exec(clr);
                const hsla = { h: parseFloat(hslaArr[1]), s: parseFloat(hslaArr[2]) * .01, l: parseFloat(hslaArr[3]) * .01, a: parseFloat(hslaArr[4]) };
                return this.rgb(hsla);
            }
        }
        static hsl(rgb) {
            const l = luminance(rgb), s = saturation(rgb, l), h = hueCircle(rgb);
            return { h, s, l, a: rgb.a };
        }
        static cieXYZ(clr) {
            if (isHsl(clr)) {
                clr = this.rgb(clr);
            }
            return cieUtils.rgbToCieXYZ(clr);
        }
        static rgb(clr) {
            if (isHsl(clr)) {
                const h = clr.h, s = clr.s, l = clr.l, h6 = h / 60.0;
                const C = (1 - Math.abs(2 * l - 1)) * s;
                const X = C * (1 - Math.abs(h6 % 2 - 1));
                const m = l - C / 2;
                const compose = (r, g, b) => this._clampRGB([r + m, g + m, b + m, clr.a]);
                if (h6 <= 1) {
                    return compose(C, X, 0);
                }
                else if (h6 <= 2) {
                    return compose(X, C, 0);
                }
                else if (h6 <= 3) {
                    return compose(0, C, X);
                }
                else if (h6 <= 4) {
                    return compose(0, X, C);
                }
                else if (h6 <= 5) {
                    return compose(X, 0, C);
                }
                else if (h6 <= 6) {
                    return compose(C, 0, X);
                }
            }
            else {
                const rgb = cieUtils.cieXYZToRgb(clr);
                return this._clampRGB([rgb.r, rgb.g, rgb.b, rgb.a]);
            }
        }
        static stringify(clr, arg1 = 1) {
            if (isHsl(clr)) {
                arg1 ??= 1;
                clr.a ??= 1;
                const precision = typeof arg1 === 'number' ? arg1 : 1;
                return `hsla(${clr.h.roundoff(precision)},${(clr.s * 100).roundoff(precision)}%,${(clr.l * 100).roundoff(precision)}%,${clr.a.roundoff()})`;
            }
            else if (isRgb(clr)) {
                arg1 ??= true;
                clr.a ??= 1;
                const hex = typeof arg1 === 'boolean' ? arg1 : !!arg1, r = Math.round(clr.r * 255), g = Math.round(clr.g * 255), b = Math.round(clr.b * 255), a = clr.a.roundoff();
                if (a === 1) {
                    if (hex) {
                        return ('#' + hexify(r) + hexify(g) + hexify(b)).toUpperCase();
                    }
                    return `rgb(${r},${g},${b})`;
                }
                return `rgba(${r},${g},${b},${a})`;
            }
            return undefined;
        }
        static contrastRatio(clr1, clr2) {
            if (isHsl(clr1)) {
                clr1 = this.rgb(clr1);
            }
            if (isHsl(clr2)) {
                clr2 = this.rgb(clr2);
            }
            return cieUtils.contrastRatio(clr1, clr2);
        }
        static luminance(clr) {
            if (isHsl(clr)) {
                clr = Colors.rgb(clr);
            }
            return cieUtils.relativeLuminance(clr);
        }
        static lighten(clr, amount = 0.1) {
            amount ||= 0;
            if (isHsl(clr)) {
                const l = Math.min(1, Math.max(0, clr.l + amount));
                return Object.assign({}, clr, { l });
            }
            if (isRgb(clr)) {
                const hsl = this.lighten(this.hsl(clr), amount);
                return this.rgb(hsl);
            }
            return clr;
        }
        static darken(clr, amount = 0.1) {
            return this.lighten(clr, -amount);
        }
        static saturate(clr, amount = 0.1) {
            amount ||= 0;
            if (isHsl(clr)) {
                const s = Math.min(1, Math.max(0, clr.s + amount));
                return Object.assign({}, clr, { s });
            }
            if (isRgb(clr)) {
                const hsl = this.saturate(this.hsl(clr), amount);
                return this.rgb(hsl);
            }
            return clr;
        }
        static desaturate(clr, amount = 0.1) {
            return this.saturate(clr, -amount);
        }
        static interpolate(clr1, clr2, weight1, weight2) {
            weight1 ??= .5;
            weight2 ??= weight1;
            const weight = (weight1 + weight2).roundoff();
            const ratio1 = (weight1 / weight).roundoff(), ratio2 = (weight2 / weight).roundoff();
            const rgb = isRgb(clr1), hsl = isHsl(clr1);
            const toCieXYZ = (c) => {
                if (isRgb(c) || isHsl(c)) {
                    return Colors.cieXYZ(c);
                }
                return c;
            };
            clr1 = toCieXYZ(clr1);
            clr2 = toCieXYZ(clr2);
            const clr = {
                x: (clr1.x * ratio1 + clr2.x * ratio2).roundoff(),
                y: (clr1.y * ratio1 + clr2.y * ratio2).roundoff(),
                z: (clr1.z * ratio1 + clr2.z * ratio2).roundoff(),
                a: (clr1.a * ratio1 + clr2.a * ratio2).roundoff(),
            };
            if (rgb) {
                return Colors.rgb(clr);
            }
            if (hsl) {
                return Colors.hsl(Colors.rgb(clr));
            }
            return clr;
        }
    }
    Pacem.Colors = Colors;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    const JSON_DATE_PATTERN = /^\/Date\([\d]+\)\/$/i;
    class Dates {
        static parse(input) {
            let d;
            if (typeof input === 'string') {
                if (JSON_DATE_PATTERN.test(input))
                    d = parseInt(input.substring(6));
                else
                    d = Date.parse(input);
                return new Date(d);
            }
            else if (typeof input === 'number') {
                return new Date(input);
            }
            else
                return input;
        }
        static isLeapYear(year) {
            return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
        }
        static daysInMonth(year, month) {
            return [31, (Dates.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
        }
        static isDate(date) {
            return date instanceof Date && !isNaN(date.valueOf());
        }
        static dateOnly(datetime) {
            return new Date(datetime.getFullYear(), datetime.getMonth(), datetime.getDate());
        }
        static addMonths(input, value) {
            let n = input.getDate(), i = new Date(input), month = i.getMonth() + value, years = 0;
            while (month < 0) {
                month += 12;
                years--;
            }
            i.setDate(1);
            i.setMonth(month % 12);
            i.setFullYear(i.getFullYear() + years + Math.floor(month / 12));
            i.setDate(Math.min(n, Dates.daysInMonth(i.getFullYear(), i.getMonth())));
            return i;
        }
        static addDays(input, value) {
            return new Date(input.valueOf() + value * 86400000);
        }
        static daysBetween(start, end) {
            return (end.valueOf() - start.valueOf()) / 86400000;
        }
    }
    Pacem.Dates = Dates;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    const FLOAT_PATTERN = /[-+]?([\d]+(\.[\d]+(e-[\d]+)?)?|[\d]*(\.[\d]+(e-[\d]+)?))/g;
    function parseAsNumericalArray(input) {
        const arr = [];
        let reg = input.match(FLOAT_PATTERN);
        if (reg && reg.length > 0) {
            reg.forEach(i => arr.push(parseFloat(i)));
        }
        return arr;
    }
    Pacem.parseAsNumericalArray = parseAsNumericalArray;
    class Angle {
        static isAngle(obj) {
            return typeof obj === 'object'
                && 'vertex' in obj && Point.isPoint(obj['vertex'])
                && 'start' in obj && Point.isPoint(obj['start'])
                && 'end' in obj && Point.isPoint(obj['end']);
        }
        static value(angle) {
            if (Pacem.NullChecker.isNullOrEmpty(angle) || !Angle.isAngle(angle)) {
                return Number.NaN;
            }
            const { vertex, start, end } = angle;
            return Angle.angleBetween(vertex, start, end);
        }
        static angleBetween(vertex, start, end) {
            const v1 = { x: start.x - vertex.x, y: start.y - vertex.y }, v2 = { x: end.x - vertex.x, y: end.y - vertex.y };
            const dot = v1.x * v2.x + v1.y * v2.y;
            const cross = v1.x * v2.y - v1.y * v2.x;
            return -Math.atan2(cross, dot);
        }
    }
    Pacem.Angle = Angle;
    ;
    class Size {
        static parse(sz) {
            let arr = parseAsNumericalArray(sz);
            if (arr && arr.length === 2) {
                return { width: arr[0], height: arr[1] };
            }
            throw new Error(`Cannot parse "${sz}" as a valid Size.`);
        }
        static isSize(obj) {
            return typeof obj === 'object'
                && 'width' in obj && typeof obj['width'] === 'number'
                && 'height' in obj && typeof obj['height'] === 'number';
        }
    }
    Pacem.Size = Size;
    class Point {
        static parse(pt) {
            let arr = parseAsNumericalArray(pt);
            if (arr && arr.length === 2) {
                return { x: arr[0], y: arr[1] };
            }
            throw new Error(`Cannot parse "${pt}" as a valid Point.`);
        }
        static isPoint(obj) {
            return typeof obj === 'object'
                && 'x' in obj && typeof obj['x'] === 'number'
                && 'y' in obj && typeof obj['y'] === 'number';
        }
        static distance(p1, p2) {
            return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
        }
        static subtract(p, from) {
            return { x: from.x - p.x, y: from.y - p.y };
        }
        static add(...points) {
            var point = { x: 0, y: 0 };
            for (var p of points) {
                point.x += p.x;
                point.y += p.y;
            }
            return point;
        }
        static multiply(p, f) {
            return { x: p.x * f, y: p.y * f };
        }
    }
    Pacem.Point = Point;
    class Rect {
        static parse(rect) {
            let arr = parseAsNumericalArray(rect);
            if (arr && arr.length === 4) {
                return { x: arr[0], y: arr[1], width: arr[2], height: arr[3] };
            }
            throw new Error(`Cannot parse "${rect}" as a valid Rect.`);
        }
        static isRect(obj) {
            return Point.isPoint(obj) && Size.isSize(obj);
        }
        static _stretch(from, to) {
            return { a: to.width / from.width, b: 0, c: 0, d: to.height / from.height, e: to.x - from.x, f: to.y - from.y };
        }
        static _contain(from, to, align, valign) {
            let scale = 1;
            const fromRatio = from.width / from.height, toRatio = to.width / to.height;
            if (fromRatio >= toRatio) {
                scale = to.width / from.width;
            }
            else {
                scale = to.height / from.height;
            }
            const w = from.width * scale, h = from.height * scale;
            const translation = this._align({ x: from.x, y: from.y, width: w, height: h }, to, align, valign);
            return Pacem.Matrix2D.translate({ a: scale, b: 0, c: 0, d: scale, e: 0, f: 0 }, translation);
        }
        static _cover(from, to, align, valign) {
            let scale = 1;
            const fromRatio = from.width / from.height, toRatio = to.width / to.height;
            if (fromRatio < toRatio) {
                scale = to.width / from.width;
            }
            else {
                scale = to.height / from.height;
            }
            const w = from.width * scale, h = from.height * scale;
            const translation = this._align({ x: from.x, y: from.y, width: w, height: h }, to, align, valign);
            return Pacem.Matrix2D.translate({ a: scale, b: 0, c: 0, d: scale, e: 0, f: 0 }, translation);
        }
        static _align(from, to, align, valign) {
            let x = 0, y = 0;
            switch (align) {
                case 'left':
                    x = to.x - from.x;
                    break;
                case 'right':
                    x = (to.x + to.width - from.width) - from.x;
                    break;
                default:
                    x = (to.x + to.width * .5 - from.width * .5) - from.x;
                    break;
            }
            switch (valign) {
                case 'top':
                    y = to.y - from.y;
                    break;
                case 'bottom':
                    y = (to.y + to.height - from.height) - from.y;
                    break;
                default:
                    y = (to.y + to.height * .5 - from.height * .5) - from.y;
                    break;
            }
            return { x, y };
        }
        static findTransform(a, b, mode = 'stretch', align = 'center', valign = 'middle') {
            switch (mode) {
                case 'contain':
                    return this._contain(a, b, align, valign);
                case 'cover':
                    return this._cover(a, b, align, valign);
                default:
                    return this._stretch(a, b);
            }
        }
        static intersect(...rects) {
            const empty = { x: 0, y: 0, height: 0, width: 0 }, arr = Array.from(rects || []);
            if (arr.length <= 0) {
                return empty;
            }
            var rect = arr[0];
            for (var i = 1; i < arr.length; i++) {
                const r = arr[i];
                const x = Math.max(r.x, rect.x), y = Math.max(r.y, rect.y), xw = Math.min(r.x + r.width, rect.x + rect.width), xh = Math.min(r.y + r.height, rect.y + rect.height), w = xw - x, h = xh - y;
                if (w < 0 || h <= 0) {
                    return empty;
                }
                rect = { x: x, y: y, width: w, height: h };
            }
            return rect;
        }
        static expand(rect, ...args) {
            const arr = Array.from(args || []);
            let x0 = rect.x, y0 = rect.y, x1 = x0, y1 = y0;
            if (Rect.isRect(rect)) {
                x1 += rect.width;
                y1 += rect.height;
            }
            for (let p of arr) {
                x0 = Math.min(p.x, x0);
                y0 = Math.min(p.y, y0);
                x1 = Math.max(p.x, x1);
                y1 = Math.max(p.y, y1);
            }
            return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
        }
    }
    Pacem.Rect = Rect;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    class HistoryService {
        constructor(state, maxlength) {
            this.#current = state;
            this.#maxlength = maxlength;
        }
        #backwards = [];
        #forwards = [];
        #maxlength;
        #current;
        get current() {
            return this.#current;
        }
        get canUndo() {
            return this.#backwards.length > 0;
        }
        get canRedo() {
            return this.#forwards.length > 0;
        }
        set maxlength(v) {
            this.#maxlength = v;
        }
        undo() {
            if (this.canUndo) {
                const back = this.#backwards, fore = this.#forwards, current = this.#current;
                fore.unshift(current);
                this.#current = back.pop();
            }
        }
        redo() {
            if (this.canRedo) {
                const back = this.#backwards, fore = this.#forwards, current = this.#current;
                back.push(current);
                this.#current = fore.shift();
            }
        }
        push(state) {
            this.#forwards.splice(0);
            this.#backwards.push(this.#current);
            this.#current = state;
            const max = this.#maxlength, queue = this.#backwards;
            if (max > 0 && queue.length > max) {
                queue.splice(0, queue.length - max);
            }
        }
        reset() {
            this.#forwards.splice(0);
            this.#backwards.splice(0);
        }
    }
    Pacem.HistoryService = HistoryService;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    const DefaultImagingResizeOptions = {
        mode: 'stretch',
        align: 'center',
        valign: 'middle',
        quality: 1,
        type: 'image/jpeg'
    };
    class Imaging {
        static async loadImage(url) {
            const response = await fetch(url);
            if (!response.ok) {
                return null;
            }
            const blob = await response.blob();
            return blob;
        }
        static async resizeImage(img, width, height, options) {
            if (width <= 0 || height <= 0 || isNaN(width) || isNaN(height)) {
                throw new Error('Invalid target size');
            }
            if (typeof img === 'string') {
                img = await Imaging.loadImage(img);
            }
            const el = await self.createImageBitmap(img);
            const origWidth = el.width, origHeight = el.height;
            const cnv = new OffscreenCanvas(origWidth, origHeight);
            const ctx = cnv.getContext('2d');
            ctx.imageSmoothingEnabled =
                ctx['mozImageSmoothingEnabled'] =
                    ctx['oImageSmoothingEnabled'] =
                        ctx['webkitImageSmoothingEnabled'] =
                            true;
            const { quality, type, mode, align, valign, background } = Object.assign({}, DefaultImagingResizeOptions, options ?? {});
            const from = { width: origWidth, height: origHeight, x: 0, y: 0 }, to = { x: 0, y: 0, width, height };
            const transformMatrix = Pacem.Rect.findTransform(from, to, mode, align, valign);
            cnv.width = width;
            cnv.height = height;
            if (background) {
                ctx.fillStyle = background;
                ctx.fillRect(0, 0, cnv.width, cnv.height);
            }
            ctx.setTransform(transformMatrix);
            ctx.drawImage(el, 0, 0);
            const retval = await cnv.convertToBlob({ quality, type });
            return retval;
        }
    }
    Pacem.Imaging = Imaging;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    class Keys {
        static #seed;
        static uniqueId() {
            let seed = Keys.#seed || Date.now();
            return Keys.#seed = ++seed;
        }
        static uniqueCode() {
            const newid = Keys.uniqueId();
            return newid.toBase62();
        }
        static randomString(length) {
            let retval = '';
            do {
                retval += (Math.random() * 62).toBase62();
            } while (retval.length < length);
            return retval;
        }
    }
    Pacem.Keys = Keys;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    ;
    class Matrix2D {
        static isIdentity(m) {
            return m.a === 1 && m.d === 1 && m.b === 0 && m.f === 0 && m.c === 0 && m.e === 0;
        }
        static get identity() {
            return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 };
        }
        static copy(m) {
            return { a: m.a, b: m.b, c: m.c, d: m.d, e: m.e, f: m.f };
        }
        static scale(m, sx, sy = sx) {
            return { a: m.a * sx, b: m.b, c: m.c, d: m.d * sy, e: m.e, f: m.f };
        }
        static translate(m, t) {
            return { a: m.a, b: m.b, c: m.c, d: m.d, e: m.e + t.x, f: m.f + t.y };
        }
        static rotate(m, rad) {
            const cos = Math.cos(rad), sin = Math.sin(rad);
            return Matrix2D.multiply(m, { a: cos, b: sin, c: -sin, d: cos, e: 0, f: 0 });
        }
        static multiply(m1, m2) {
            if ("x" in m1 && "y" in m1) {
                if (typeof m2 === 'number') {
                    return { x: m1.x * m2, y: m1.y * m2 };
                }
                else {
                    return { x: m1.x * m2.a + m1.y * m2.c + m2.e, y: m1.x * m2.b + m1.y * m2.d + m2.f };
                }
            }
            if (typeof m2 === 'number') {
                return {
                    a: m1.a * m2, b: m1.b * m2, c: m1.c * m2, d: m1.d * m2, e: m1.e * m2, f: m1.f * m2
                };
            }
            return {
                a: m1.a * m2.a + m1.b * m2.c,
                b: m1.a * m2.b + m1.b * m2.d,
                c: m1.c * m2.a + m1.d * m2.c,
                d: m1.c * m2.b + m1.d * m2.d,
                e: m1.e * m2.a + m1.f * m2.c + m2.e,
                f: m1.e * m2.b + m1.f * m2.d + m2.f
            };
        }
        static det(m) {
            return m.a * m.d - m.c * m.b;
        }
        static invert(m) {
            const det = this.det(m);
            if (det === 0) {
                return null;
            }
            const invdet = 1 / det;
            return this.multiply({
                a: m.d,
                b: -m.b,
                c: -m.c,
                d: m.a,
                e: -m.e * m.d + m.c * m.f,
                f: m.e * m.b - m.a * m.f
            }, invdet);
        }
        static toComponents(m, transformOrigin = { x: 0, y: 0 }) {
            const scaleX = Math.sqrt(m.a * m.a + m.c * m.c);
            const scaleY = Math.sqrt(m.b * m.b + m.d * m.d);
            const cos = scaleX != 0 ? m.a / scaleX : 0;
            const sin = scaleX != 0 ? m.c / scaleX : 0;
            const rotation = Math.atan2(sin, cos);
            const { x: px, y: py } = transformOrigin;
            const translation = {
                x: m.e - px * (scaleX * cos - 1) + py * scaleX * sin,
                y: m.f - py * (scaleY * cos - 1) - px * scaleY * sin,
            };
            return {
                scaleX, scaleY, rotation,
                translation
            };
        }
    }
    Pacem.Matrix2D = Matrix2D;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    class NullChecker {
        static isNull(o) {
            return o === null || o === void 0;
        }
        static isEmpty(o) {
            try {
                return (Array.isArray(o) && o.length === 0)
                    || (typeof o === 'string' && o === '')
                    || (typeof o === 'object' && Object.keys(o).length === 0 && !Pacem.Dates.isDate(o) && !(o instanceof RegExp) && !(o instanceof FileSystemDirectoryHandle) && !(o instanceof FileSystemFileHandle));
            }
            catch (e) {
                return false;
            }
        }
        static isNullOrEmpty(o) {
            return NullChecker.isNull(o) || NullChecker.isEmpty(o);
        }
    }
    Pacem.NullChecker = NullChecker;
})(Pacem || (Pacem = {}));
Number.prototype.isCloseTo = function (other, precision = 14) {
    return this.toFixed(precision) === other.toFixed(precision);
};
Number.prototype.roundoff = function (precision = 14) {
    return parseFloat(this.toFixed(precision));
};
Number.prototype.clamp = function (min, max) {
    let value = this;
    if (min != null && !isNaN(min)) {
        value = Math.max(value, min);
    }
    if (max != null && !isNaN(max)) {
        value = Math.min(value, max);
    }
    return value;
};
Number.prototype.toBase62 = function () {
    var alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    var temp = this;
    var sb = '';
    while (temp != 0) {
        var mod = temp % 62;
        sb = alphabet.charAt(mod) + sb;
        temp = Math.floor(temp / 62);
    }
    return sb;
};
Number.prototype.toBase36 = function () {
    return this.toString(36);
};
var Pacem;
(function (Pacem) {
    class Numbers {
        static round(x, step = 1.0) {
            return Math.round(x / step) * step;
        }
        static log(x, base) {
            return Math.log10(x) / Math.log10(base);
        }
        static rebase(v, from, to) {
            const vStr = v.toString();
            const firstPass = parseInt(vStr, from);
            if (!vStr.endsWith(firstPass.toString(from))) {
                return Number.NaN.toString();
            }
            return parseInt(v.toString(), from).toString(to);
        }
    }
    Pacem.Numbers = Numbers;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    function lcs(aTokens, bTokens) {
        const m = aTokens.length;
        const n = bTokens.length;
        const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
        for (let i = 1; i <= m; i++) {
            for (let j = 1; j <= n; j++) {
                if (aTokens[i - 1] === bTokens[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return dp;
    }
    function diffInternal(aTokens, bTokens, dp, joiner = '') {
        const m = aTokens.length;
        const n = bTokens.length;
        const result = [];
        let i = m, j = n;
        let currentToken = null;
        const finalizeToken = () => {
            if (currentToken) {
                result.push(currentToken);
                currentToken = null;
            }
        };
        while (i > 0 || j > 0) {
            var currentType = null;
            let currentValue = null;
            if (i > 0 && j > 0 && aTokens[i - 1] === bTokens[j - 1]) {
                currentType = '=';
                currentValue = aTokens[i - 1];
                i--;
                j--;
            }
            else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
                currentType = '+';
                currentValue = bTokens[j - 1];
                j--;
            }
            else if (i > 0 && (j === 0 || dp[i - 1][j] > dp[i][j - 1])) {
                currentType = '-';
                currentValue = aTokens[i - 1];
                i--;
            }
            if (currentType && currentValue !== null) {
                if (currentToken && currentToken.type === currentType) {
                    currentToken.value = currentValue + (currentToken.value ? joiner : '') + currentToken.value;
                }
                else {
                    finalizeToken();
                    currentToken = { type: currentType, value: currentValue };
                }
            }
            else {
                finalizeToken();
            }
        }
        finalizeToken();
        return result.reverse();
    }
    function diffChars(a, b) {
        const aTokens = a.split('');
        const bTokens = b.split('');
        const dp = lcs(aTokens, bTokens);
        return diffInternal(aTokens, bTokens, dp, '');
    }
    function diffWords(a, b) {
        const wordRegex = /(\S+|\s+)/g;
        const aTokens = a.match(wordRegex) || [];
        const bTokens = b.match(wordRegex) || [];
        const dp = lcs(aTokens, bTokens);
        return diffInternal(aTokens, bTokens, dp, '');
    }
    function diffLines(a, b) {
        const lineRegex = /\r?\n/;
        const aTokens = a.split(lineRegex);
        const bTokens = b.split(lineRegex);
        const dp = lcs(aTokens, bTokens);
        return diffInternal(aTokens, bTokens, dp, '\n');
    }
    class Strings {
        static leftPad(v, targetLength, padChar) {
            let retval = v.toString();
            while (retval.length < targetLength)
                retval = padChar + retval;
            return retval;
        }
        static format(template, ...args) {
            const array = Array.from(args);
            let retval = template;
            for (let j = 0; j < array.length; j++) {
                const regex = new RegExp('(^|[^\\{])\\{' + j + '\\}($|[^\\}])', 'g');
                retval = retval.replaceAll(regex, (match, ...args0) => {
                    return match.replace('{' + j + '}', array[j]);
                });
            }
            const check = /(^|[^\{}])\{(\d+)\}($|[^\}])/.exec(retval);
            if (!Pacem.NullChecker.isNullOrEmpty(check)) {
                throw new Error(`Missing argument at index ${check[2]}.`);
            }
            return retval;
        }
        static diff(a, b, mode = 'char') {
            switch (mode) {
                case 'line':
                    return diffLines(a, b);
                case 'word':
                    return diffWords(a, b);
                default:
                    return diffChars(a, b);
            }
        }
    }
    Pacem.Strings = Strings;
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Compile;
    (function (Compile) {
        class LexerClass {
            tokenize(input, grammar) {
                const tokens = [];
                while (input) {
                    const start = input.length;
                    for (let rule of grammar) {
                        const newTokens = rule.exec(input, this), length = newTokens?.length;
                        if (length > 0) {
                            Array.prototype.push.apply(tokens, newTokens);
                            const last = newTokens[length - 1];
                            input = input.substr((last.index || 0) + last.raw.length);
                            break;
                        }
                    }
                    if (input.length >= start) {
                        throw new Error(`Cannot parse\n"${input}"\n using the provided grammar.`);
                    }
                }
                return tokens;
            }
        }
        class Parser {
            _lexer;
            constructor(_lexer = new LexerClass()) {
                this._lexer = _lexer;
            }
            parse(input, grammar, renderer) {
                const tokens = this._lexer.tokenize(input, grammar);
                return renderer.render(tokens);
            }
        }
        Compile.Parser = Parser;
    })(Compile = Pacem.Compile || (Pacem.Compile = {}));
})(Pacem || (Pacem = {}));
var Pacem;
(function (Pacem) {
    var Compile;
    (function (Compile) {
        var Markdown;
        (function (Markdown) {
            function htmlEncode(input) {
                return (input ?? '').replace(/</g, '&lt;');
            }
            function extractReference(input) {
                if (Pacem.NullChecker.isNullOrEmpty(input)) {
                    return void 0;
                }
                if (/^\(/.test(input) && /\)$/.test(input)) {
                    return void 0;
                }
                if (/^\[/.test(input) && /\]$/.test(input)) {
                    input = input.substr(1, input.length - 2);
                }
                return input;
            }
            function regexMatchIndex(arr) {
                return arr?.index || void 0;
            }
            function extractUrl(input) {
                if (Pacem.NullChecker.isNullOrEmpty(input)) {
                    return void 0;
                }
                if (/^\[/.test(input) && /\]$/.test(input)) {
                    return void 0;
                }
                if (/^\(/.test(input) && /\)$/.test(input)) {
                    input = input.substr(1, input.length - 2);
                }
                return input;
            }
            function normalizeReference(input) {
                return input?.replace(/[^\w]+/g, ' ').trim().replace(/ +/g, '-').toLowerCase();
            }
            function match(input, pattern, fn) {
                const arr = pattern.exec(input);
                if (arr && arr.length) {
                    return fn(arr);
                }
                return null;
            }
            const COMMENT = /(<!--)([\s\S]*?)(-->|$)/;
            const HR = /^ {0,3}(={3,}|_{3,}|-{3,})(\r?\n|$)/;
            const HEADING = /^ {0,3}(#{1,6})\s+([^\n]+)(\r?\n|$)+/;
            const HEADING1 = /^ {0,3}([^\n]+)(\r?\n=+(\r?\n|$))+/;
            const HEADING2 = /^ {0,3}([^\n]+)(\r?\n-+(\r?\n|$))+/;
            const CODEBLOCK = /^ {4,}.+(\r?\n {4,}.+)*(\r?\n|$)+/;
            const FENCES = /^ {0,3}``` *([^\n]*)\r?\n(([\s\S](?!\r?\n {0,3}```))*.(\r?\n)+) {0,3}```(\r?\n|$)+/;
            const BLOCKQUOTE = /^ {0,3}> *([^\n]+)(\r?\n {0,3}> *([^\n]*))*(\r?\n|$)+/;
            const ULIST = /^( {0,3}([-+]).*\r?\n|$)((?!(?: {0,3}(?:\d+[.\)]|\r?\n\S))).*(\r?\n|$))*/;
            const OLIST = /^( {0,3}(\d+[.\)]).*\r?\n|$)((?!(?: {0,3}(?:[+-]|\r?\n\S))).*(\r?\n|$))*/;
            const LISTITEM = /^(?:[-+*]|\d+[.\)])/m;
            const PARAGRAPH = /^(?! {4,})(.+(\n(?! {0,3}```)(?! {0,3}([-+]|\d+[.\)]))(?! {4,})(?! {0,3}>).+)*)/;
            const REF = /^ {0,3}(!?)\[([^\]]+)\]: +(\S+)(?: +['"\(](.+)['"\)])?(\r?\n|$)+/;
            const IMAGE_OR_LINK = /!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?(\[[^\[\]]*\]|\([^\(\)]*\))?/;
            const EMPHASIZED_LINK = /(\*\*?|__?)(\[[^\]]*]\([^\)]+\))\1/;
            const CODE = /(?:(?<!\\)`)(.+?)(?:(?<!\\)`)/;
            const EMPHASIZE = /(\*\*?|__?)((?!\1\s?)(?:(?!\1)[\S\s])*[^\s])\1/;
            const STRIKE = /(~~?|__?)(?!\1\s?)([^\s][\s\S]*?(?!\1)[^\s])\1/;
            const QUOTE = /(:")(?!":\s?)([^\s][\s\S]*?(?!":)[^\s])":/;
            const SPACE = /^\s+/;
            const LINEBREAK = / {2,}\r?\n/;
            const TEXT = /^[^\r\n]+/;
            let MARKDOWN_TYPES;
            (function (MARKDOWN_TYPES) {
                MARKDOWN_TYPES["Html"] = "html";
                MARKDOWN_TYPES["Text"] = "text";
                MARKDOWN_TYPES["Paragraph"] = "paragraph";
                MARKDOWN_TYPES["BlockQuote"] = "blockquote";
                MARKDOWN_TYPES["Space"] = "space";
                MARKDOWN_TYPES["Heading"] = "heading";
                MARKDOWN_TYPES["Bold"] = "bold";
                MARKDOWN_TYPES["Italic"] = "italic";
                MARKDOWN_TYPES["CodeBlock"] = "codeblock";
                MARKDOWN_TYPES["Code"] = "code";
                MARKDOWN_TYPES["Image"] = "img";
                MARKDOWN_TYPES["ImageLike"] = "imglike";
                MARKDOWN_TYPES["Link"] = "link";
                MARKDOWN_TYPES["LinkLike"] = "linklike";
                MARKDOWN_TYPES["LineBreak"] = "br";
                MARKDOWN_TYPES["StrikeThrough"] = "strike";
                MARKDOWN_TYPES["Quote"] = "quote";
                MARKDOWN_TYPES["HorizontalRule"] = "hr";
                MARKDOWN_TYPES["OrderedList"] = "ol";
                MARKDOWN_TYPES["UnorderedList"] = "ul";
                MARKDOWN_TYPES["ListItem"] = "listitem";
                MARKDOWN_TYPES["Reference"] = "ref";
            })(MARKDOWN_TYPES || (MARKDOWN_TYPES = {}));
            let MARKDOWN_RULES;
            (function (MARKDOWN_RULES) {
                MARKDOWN_RULES[MARKDOWN_RULES["Comment"] = 0] = "Comment";
                MARKDOWN_RULES[MARKDOWN_RULES["Reference"] = 1] = "Reference";
                MARKDOWN_RULES[MARKDOWN_RULES["HorizontalRule"] = 2] = "HorizontalRule";
                MARKDOWN_RULES[MARKDOWN_RULES["Heading"] = 3] = "Heading";
                MARKDOWN_RULES[MARKDOWN_RULES["Heading1"] = 4] = "Heading1";
                MARKDOWN_RULES[MARKDOWN_RULES["Heading2"] = 5] = "Heading2";
                MARKDOWN_RULES[MARKDOWN_RULES["CodeBlock"] = 6] = "CodeBlock";
                MARKDOWN_RULES[MARKDOWN_RULES["Fences"] = 7] = "Fences";
                MARKDOWN_RULES[MARKDOWN_RULES["BlockQuote"] = 8] = "BlockQuote";
                MARKDOWN_RULES[MARKDOWN_RULES["OrderedList"] = 9] = "OrderedList";
                MARKDOWN_RULES[MARKDOWN_RULES["UnorderedList"] = 10] = "UnorderedList";
                MARKDOWN_RULES[MARKDOWN_RULES["Paragraph"] = 11] = "Paragraph";
                MARKDOWN_RULES[MARKDOWN_RULES["EmphasizedLink"] = 12] = "EmphasizedLink";
                MARKDOWN_RULES[MARKDOWN_RULES["ImageOrLink"] = 13] = "ImageOrLink";
                MARKDOWN_RULES[MARKDOWN_RULES["Emphasize"] = 14] = "Emphasize";
                MARKDOWN_RULES[MARKDOWN_RULES["StrikeThrough"] = 15] = "StrikeThrough";
                MARKDOWN_RULES[MARKDOWN_RULES["Quote"] = 16] = "Quote";
                MARKDOWN_RULES[MARKDOWN_RULES["Code"] = 17] = "Code";
                MARKDOWN_RULES[MARKDOWN_RULES["LineBreak"] = 18] = "LineBreak";
                MARKDOWN_RULES[MARKDOWN_RULES["Text"] = 254] = "Text";
                MARKDOWN_RULES[MARKDOWN_RULES["Space"] = 255] = "Space";
            })(MARKDOWN_RULES || (MARKDOWN_RULES = {}));
            function getGrammar(extra = []) {
                const inert = {
                    [MARKDOWN_RULES.Comment]: {
                        exec: (input, lexer) => match(input, COMMENT, arr => {
                            const index = regexMatchIndex(arr);
                            const output = [{
                                    type: MARKDOWN_TYPES.Html, index, raw: arr[0], text: arr[2]
                                }];
                            if (index > 0) {
                                const left = input.substr(0, index), tokens = lexer.tokenize(left, blockRules);
                                Array.prototype.unshift.apply(output, tokens);
                            }
                            return output;
                        })
                    },
                    [MARKDOWN_RULES.Reference]: {
                        exec: (input) => match(input, REF, arr => {
                            const index = regexMatchIndex(arr), raw = arr[0], text = raw, image = arr[1] === '!', id = arr[2], url = arr[3], title = arr[4];
                            return [{
                                    type: MARKDOWN_TYPES.Reference, index, raw, text, id, image, url, title
                                }];
                        })
                    },
                };
                const blockExtra = [], inlineExtra = [], codeExtra = {};
                for (let r of extra) {
                    let rule, type = 'inline';
                    if ('type' in r) {
                        type = r.type;
                        rule = r.rule;
                    }
                    else {
                        rule = r;
                    }
                    switch (type) {
                        case 'block':
                            blockExtra.push(rule);
                            break;
                        case 'code':
                            if ('lang' in r) {
                                const key = r.lang.toLowerCase();
                                (codeExtra[key] = codeExtra[key] || []).push(rule);
                            }
                            break;
                        default:
                            const inlineRule = {
                                exec: (input, lexer) => {
                                    const output = rule.exec(input, lexer);
                                    inPlaceInlineExec(input, output, lexer);
                                    return output;
                                }
                            };
                            inlineExtra.push(inlineRule);
                            break;
                    }
                }
                const inlinelowpriority = {
                    [MARKDOWN_RULES.Text]: {
                        exec: (input) => match(input, TEXT, arr => {
                            const raw = arr[0], text = raw;
                            return [{
                                    index: regexMatchIndex(arr), raw, text, type: MARKDOWN_TYPES.Text
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Space]: {
                        exec: (input) => match(input, SPACE, arr => {
                            const raw = arr[0];
                            return [{
                                    type: MARKDOWN_TYPES.Space, raw, text: raw
                                }];
                        })
                    }
                };
                const inline = {
                    [MARKDOWN_RULES.ImageOrLink]: {
                        exec: (input, lexer) => inlineMatch(input, IMAGE_OR_LINK, lexer, arr => {
                            const index = regexMatchIndex(arr), raw = arr[0], image = raw.charAt(0) === '!', text = arr[1], url = extractUrl(arr[2]), ref = normalizeReference(extractReference(arr[2]) ?? text);
                            if (image) {
                                return [{
                                        index, type: url ? MARKDOWN_TYPES.Image : MARKDOWN_TYPES.ImageLike,
                                        raw, text, src: url, ref,
                                        tokens: lexer.tokenize(text, inlineRules)
                                    }];
                            }
                            else {
                                return [{
                                        index, type: url ? MARKDOWN_TYPES.Link : MARKDOWN_TYPES.LinkLike,
                                        raw, text, href: url, ref,
                                        tokens: lexer.tokenize(text, inlineRules)
                                    }];
                            }
                        })
                    },
                    [MARKDOWN_RULES.Code]: {
                        exec: (input, lexer) => inlineMatch(input, CODE, lexer, arr => {
                            const text = htmlEncode(arr[1]);
                            return [{
                                    type: MARKDOWN_TYPES.Code, raw: arr[0], text, index: regexMatchIndex(arr)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.EmphasizedLink]: {
                        exec: (input, lexer) => inlineMatch(input, EMPHASIZED_LINK, lexer, arr => {
                            if (arr.length < 3 || Pacem.NullChecker.isNullOrEmpty(arr[2])) {
                                return null;
                            }
                            const type = arr[1].length > 1 ? MARKDOWN_TYPES.Bold : MARKDOWN_TYPES.Italic, text = arr[2];
                            return [{
                                    index: regexMatchIndex(arr),
                                    type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Emphasize]: {
                        exec: (input, lexer) => inlineMatch(input, EMPHASIZE, lexer, arr => {
                            if (arr.length < 3 || Pacem.NullChecker.isNullOrEmpty(arr[2])) {
                                return null;
                            }
                            const type = arr[1].length > 1 ? MARKDOWN_TYPES.Bold : MARKDOWN_TYPES.Italic, text = arr[2];
                            return [{
                                    index: regexMatchIndex(arr),
                                    type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.StrikeThrough]: {
                        exec: (input, lexer) => inlineMatch(input, STRIKE, lexer, arr => {
                            if (arr.length < 3 || Pacem.NullChecker.isNullOrEmpty(arr[2])) {
                                return null;
                            }
                            const type = MARKDOWN_TYPES.StrikeThrough, text = arr[2];
                            return [{
                                    index: regexMatchIndex(arr),
                                    type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Quote]: {
                        exec: (input, lexer) => inlineMatch(input, QUOTE, lexer, arr => {
                            if (arr.length < 3 || Pacem.NullChecker.isNullOrEmpty(arr[2])) {
                                return null;
                            }
                            const type = MARKDOWN_TYPES.Quote, text = arr[2];
                            return [{
                                    index: regexMatchIndex(arr),
                                    type, raw: arr[0], text, tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.LineBreak]: {
                        exec: (input, lexer) => inlineMatch(input, LINEBREAK, lexer, arr => {
                            const raw = arr[0], text = raw;
                            return [{
                                    index: regexMatchIndex(arr), raw, text, type: MARKDOWN_TYPES.LineBreak
                                }];
                        })
                    },
                };
                const inPlaceInlineExec = (input, output, lexer) => {
                    const index = output?.length > 0 && output[0].index;
                    if (index > 0) {
                        const left = input.substr(0, index);
                        const tokens = lexer.tokenize(left, inlineRules) || [];
                        Array.prototype.unshift.apply(output, tokens);
                    }
                };
                const inlineMatch = (input, pattern, lexer, fn) => {
                    const output = match(input, pattern, arr => {
                        if (pattern != CODE) {
                            const codeCheck = CODE.exec(input);
                            if (codeCheck
                                && codeCheck.length
                                && codeCheck.index < arr.index) {
                                return null;
                            }
                        }
                        return fn(arr);
                    });
                    inPlaceInlineExec(input, output, lexer);
                    return output;
                };
                const inlineRules = Object.values(inline);
                Array.prototype.push.apply(inlineRules, inlineExtra);
                inlineRules.push(inlinelowpriority[MARKDOWN_RULES.Text], inlinelowpriority[MARKDOWN_RULES.Space]);
                const getLangGrammar = (lang) => {
                    const retval = [inlinelowpriority[MARKDOWN_RULES.Text], inlinelowpriority[MARKDOWN_RULES.Space]];
                    const key = lang?.toLowerCase() || '';
                    if (key && key in codeExtra) {
                        Array.prototype.unshift.apply(retval, codeExtra[key]);
                    }
                    return retval;
                };
                const lowpriority = {
                    [MARKDOWN_RULES.Paragraph]: {
                        exec: (input, lexer) => match(input, PARAGRAPH, arr => {
                            const raw = arr[0], text = raw;
                            return [{
                                    type: MARKDOWN_TYPES.Paragraph, raw, text,
                                    tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Space]: inlinelowpriority[MARKDOWN_RULES.Space]
                };
                const tokenizeListItem = (text, lexer) => {
                    const grammar = !/^ {0,3}(`{3,}|$|>|[+-]\s|\d+[.\)])/m.test(text) ? inlineRules : blockRules;
                    return lexer.tokenize(text, grammar);
                };
                const block = {
                    [MARKDOWN_RULES.HorizontalRule]: {
                        exec: (input, lexer) => match(input, HR, arr => {
                            const raw = arr[0], text = raw;
                            return [{
                                    type: MARKDOWN_TYPES.HorizontalRule, raw, text
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Heading]: {
                        exec: (input, lexer) => match(input, HEADING, arr => {
                            const text = arr[2];
                            return [{
                                    type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: arr[1].length, ref: normalizeReference(text),
                                    tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Heading1]: {
                        exec: (input, lexer) => match(input, HEADING1, arr => {
                            const text = arr[1];
                            return [{
                                    type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: 1, ref: normalizeReference(text),
                                    tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Heading2]: {
                        exec: (input, lexer) => match(input, HEADING2, arr => {
                            const text = arr[1];
                            return [{
                                    type: MARKDOWN_TYPES.Heading, raw: arr[0], text, level: 2, ref: normalizeReference(text),
                                    tokens: lexer.tokenize(text, inlineRules)
                                }];
                        })
                    },
                    [MARKDOWN_RULES.CodeBlock]: {
                        exec: (input, lexer) => match(input, CODEBLOCK, arr => {
                            const raw = arr[0], text = htmlEncode(raw);
                            return [{
                                    type: MARKDOWN_TYPES.CodeBlock, raw, text,
                                    tokens: lexer.tokenize(text, [])
                                }];
                        })
                    },
                    [MARKDOWN_RULES.Fences]: {
                        exec: (input, lexer) => match(input, FENCES, arr => {
                            const text = htmlEncode(arr[2]), lang = arr[1]?.toLowerCase();
                            return [{
                                    type: MARKDOWN_TYPES.CodeBlock, raw: arr[0], text, lang,
                                    tokens: lexer.tokenize(text, getLangGrammar(lang))
                                }];
                        })
                    },
                    [MARKDOWN_RULES.BlockQuote]: {
                        exec: (input, lexer) => match(input, BLOCKQUOTE, arr => {
                            const raw = arr[0], text = raw.replace(/^ {0,3}> */gm, '');
                            return [{
                                    type: MARKDOWN_TYPES.BlockQuote, raw, text,
                                    tokens: lexer.tokenize(text, [
                                        lowpriority[MARKDOWN_RULES.Paragraph],
                                        lowpriority[MARKDOWN_RULES.Space]
                                    ])
                                }];
                        })
                    },
                    [MARKDOWN_RULES.OrderedList]: {
                        exec: (input, lexer) => match(input, OLIST, arr => {
                            const raw = arr[0], items = raw.replace(/^ {0,3}/gm, '').split(LISTITEM).filter(i => !Pacem.NullChecker.isNullOrEmpty(i)).map(i => i.trim());
                            return [{
                                    type: MARKDOWN_TYPES.OrderedList, start: parseInt(/\d/.exec(arr[0])[0]), raw, text: raw, tokens: items.map(i => {
                                        return {
                                            type: MARKDOWN_TYPES.ListItem, raw: i, text: i, tokens: tokenizeListItem(i, lexer)
                                        };
                                    })
                                }];
                        })
                    },
                    [MARKDOWN_RULES.UnorderedList]: {
                        exec: (input, lexer) => match(input, ULIST, arr => {
                            const raw = arr[0], items = raw.replace(/^ {0,3}/gm, '').split(LISTITEM).filter(i => !Pacem.NullChecker.isNullOrEmpty(i)).map(i => i.trim());
                            return [{
                                    type: MARKDOWN_TYPES.UnorderedList, raw, text: raw, tokens: items.map(i => {
                                        return {
                                            type: MARKDOWN_TYPES.ListItem, raw: i, text: i, tokens: tokenizeListItem(i, lexer)
                                        };
                                    })
                                }];
                        })
                    }
                };
                const blockRules = Object.values(block);
                Array.prototype.push.apply(blockRules, blockExtra);
                blockRules.push(lowpriority[MARKDOWN_RULES.Paragraph], lowpriority[MARKDOWN_RULES.Space]);
                return [
                    inert[MARKDOWN_RULES.Comment],
                    inert[MARKDOWN_RULES.Reference]
                ].concat(blockRules);
            }
            const CARRIAGE_RETURN_PLACEHOLDER = '\0';
            const TRIM_INSIDE = /[ \r\n]*\0+[ \r\n]*/g;
            function trim(input) {
                return input?.replace(TRIM_INSIDE, '\n').trim();
            }
            class HtmlRenderer {
                _extraItemRender;
                constructor(_extraItemRender = (token, __) => token?.text || '') {
                    this._extraItemRender = _extraItemRender;
                }
                _renderContent = (token) => {
                    const children = token.tokens;
                    if (Pacem.NullChecker.isNullOrEmpty(children)) {
                        return token.text;
                    }
                    return this._render(children);
                };
                _rendeItem(token, allTokens) {
                    const r = this._renderContent, R = CARRIAGE_RETURN_PLACEHOLDER;
                    switch (token?.type) {
                        case MARKDOWN_TYPES.Reference:
                            return '';
                        case MARKDOWN_TYPES.Html:
                            return token.raw;
                        case MARKDOWN_TYPES.BlockQuote:
                            return `<blockquote>\n${r(token)}</blockquote>${R}`;
                        case MARKDOWN_TYPES.Bold:
                            return `<b>${r(token)}</b>`;
                        case MARKDOWN_TYPES.CodeBlock:
                            const lang = token['lang'];
                            return `<pre>${R}<code${(lang ? (' class="' + lang + '"') : '')}>${r(token)}</code>${R}</pre>${R}`;
                        case MARKDOWN_TYPES.Code:
                            return `<code>${r(token)}</code>`;
                        case MARKDOWN_TYPES.HorizontalRule:
                            return `<hr />${R}`;
                        case MARKDOWN_TYPES.Heading:
                            const hlevel = token['level'], hid = token['ref'];
                            return `<h${hlevel} id="${hid}">${r(token)}</h${hlevel}>${R}`;
                        case MARKDOWN_TYPES.Image:
                        case MARKDOWN_TYPES.ImageLike:
                            const itk = token;
                            let isrc = itk.src, ititle = '';
                            const alt = itk.text, iref = itk.ref;
                            if (!isrc && iref) {
                                const ireftk = allTokens.find(t => t.type === MARKDOWN_TYPES.Reference && t['image'] === true && t['id']?.toLowerCase() === iref.toLowerCase());
                                if (ireftk) {
                                    isrc = ireftk.url;
                                    ititle = ireftk.title ?? '';
                                }
                            }
                            return isrc ? `<img src="${isrc}" alt="${alt}"${(ititle ? (' title="' + ititle + '"') : '')} />` : `![${r(token)}]`;
                        case MARKDOWN_TYPES.Italic:
                            return `<i>${r(token)}</i>`;
                        case MARKDOWN_TYPES.StrikeThrough:
                            return `<s>${r(token)}</s>`;
                        case MARKDOWN_TYPES.Quote:
                            return `<q>${r(token)}</q>`;
                        case MARKDOWN_TYPES.LineBreak:
                            return '<br />' + R;
                        case MARKDOWN_TYPES.OrderedList:
                            return `<ol start="${token['start']}">\n${r(token)}</ol>${R}`;
                        case MARKDOWN_TYPES.UnorderedList:
                            return `<ul>\n${r(token)}</ul>${R}`;
                        case MARKDOWN_TYPES.ListItem:
                            return `\t<li>${r(token)}</li>${R}`;
                        case MARKDOWN_TYPES.Link:
                        case MARKDOWN_TYPES.LinkLike:
                            const atk = token;
                            let ahref = atk.href, atitle = '';
                            const aref = atk.ref;
                            if (!ahref && aref) {
                                const areftk = allTokens.find(t => t.type === MARKDOWN_TYPES.Reference && t['image'] !== true && t['id']?.toLowerCase() === aref.toLowerCase());
                                if (areftk) {
                                    ahref = areftk.url;
                                    atitle = areftk.title ?? '';
                                }
                            }
                            return ahref ? `<a href="${ahref}"${(atitle ? (' title="' + atitle + '"') : '')}>${r(token)}</a>` : `[${r(token)}]`;
                        case MARKDOWN_TYPES.Paragraph:
                            return `<p>${r(token)}</p>${R}`;
                        case MARKDOWN_TYPES.Text:
                        case MARKDOWN_TYPES.Space:
                            return token.text;
                    }
                    return this._extraItemRender(token, allTokens);
                }
                _render(tree) {
                    let acc = '';
                    for (let token of tree || []) {
                        acc += this._rendeItem(token, tree);
                    }
                    return acc;
                }
                render(tree) {
                    return trim(this._render(tree));
                }
            }
            class TokenRenderer {
                _render(token) {
                    return Pacem.NullChecker.isNullOrEmpty(token) ? '' : JSON.stringify(token);
                }
                render(tree) {
                    return '[' + tree.filter(i => !Pacem.NullChecker.isNullOrEmpty(i)).map(this._render).join(',') + ']';
                }
            }
            function isRenderer(obj) {
                return obj && typeof obj === 'object' && typeof obj.render === 'function';
            }
            class Parser extends Pacem.Compile.Parser {
                toHtml(input, extraGrammar, extraItemRenderer) {
                    const renderer = new HtmlRenderer(extraItemRenderer);
                    if (Pacem.NullChecker.isNullOrEmpty(extraGrammar)) {
                        return this.parse(input, renderer);
                    }
                    return this.parse(input, getGrammar(extraGrammar), renderer);
                }
                tokenize(input, extraGrammar) {
                    const json = this.parse(input, getGrammar(extraGrammar), new TokenRenderer());
                    return JSON.parse(json);
                }
                parse(input, grammarOrRenderer = getGrammar(), renderer = new HtmlRenderer()) {
                    if (isRenderer(grammarOrRenderer)) {
                        return super.parse(input, getGrammar(), grammarOrRenderer);
                    }
                    else {
                        return super.parse(input, grammarOrRenderer, renderer);
                    }
                }
            }
            Markdown.Parser = Parser;
        })(Markdown = Compile.Markdown || (Compile.Markdown = {}));
    })(Compile = Pacem.Compile || (Pacem.Compile = {}));
})(Pacem || (Pacem = {}));
