import { watch, defineComponent, toRefs, ref, nextTick, onMounted, onBeforeUnmount, onActivated, onDeactivated, h, resolveComponent, openBlock, createElementBlock, createVNode } from "vue";
var tinymce$2 = { exports: {} };
(function(module) {
  (function() {
    var typeOf$1 = function(x) {
      if (x === null) {
        return "null";
      }
      if (x === void 0) {
        return "undefined";
      }
      var t = typeof x;
      if (t === "object" && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === "Array")) {
        return "array";
      }
      if (t === "object" && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === "String")) {
        return "string";
      }
      return t;
    };
    var isEquatableType = function(x) {
      return [
        "undefined",
        "boolean",
        "number",
        "string",
        "function",
        "xml",
        "null"
      ].indexOf(x) !== -1;
    };
    var sort$1 = function(xs, compareFn) {
      var clone2 = Array.prototype.slice.call(xs);
      return clone2.sort(compareFn);
    };
    var contramap = function(eqa, f) {
      return eq$2(function(x, y) {
        return eqa.eq(f(x), f(y));
      });
    };
    var eq$2 = function(f) {
      return { eq: f };
    };
    var tripleEq = eq$2(function(x, y) {
      return x === y;
    });
    var eqString = tripleEq;
    var eqArray = function(eqa) {
      return eq$2(function(x, y) {
        if (x.length !== y.length) {
          return false;
        }
        var len = x.length;
        for (var i = 0; i < len; i++) {
          if (!eqa.eq(x[i], y[i])) {
            return false;
          }
        }
        return true;
      });
    };
    var eqSortedArray = function(eqa, compareFn) {
      return contramap(eqArray(eqa), function(xs) {
        return sort$1(xs, compareFn);
      });
    };
    var eqRecord = function(eqa) {
      return eq$2(function(x, y) {
        var kx = Object.keys(x);
        var ky = Object.keys(y);
        if (!eqSortedArray(eqString).eq(kx, ky)) {
          return false;
        }
        var len = kx.length;
        for (var i = 0; i < len; i++) {
          var q = kx[i];
          if (!eqa.eq(x[q], y[q])) {
            return false;
          }
        }
        return true;
      });
    };
    var eqAny = eq$2(function(x, y) {
      if (x === y) {
        return true;
      }
      var tx = typeOf$1(x);
      var ty = typeOf$1(y);
      if (tx !== ty) {
        return false;
      }
      if (isEquatableType(tx)) {
        return x === y;
      } else if (tx === "array") {
        return eqArray(eqAny).eq(x, y);
      } else if (tx === "object") {
        return eqRecord(eqAny).eq(x, y);
      }
      return false;
    });
    const getPrototypeOf$1 = Object.getPrototypeOf;
    const hasProto = (v, constructor, predicate) => {
      var _a;
      if (predicate(v, constructor.prototype)) {
        return true;
      } else {
        return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
      }
    };
    const typeOf = (x) => {
      const t = typeof x;
      if (x === null) {
        return "null";
      } else if (t === "object" && Array.isArray(x)) {
        return "array";
      } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
        return "string";
      } else {
        return t;
      }
    };
    const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
    const isSimpleType = (type2) => (value2) => typeof value2 === type2;
    const eq$1 = (t) => (a) => t === a;
    const is$4 = (value2, constructor) => isObject(value2) && hasProto(value2, constructor, (o, proto) => getPrototypeOf$1(o) === proto);
    const isString = isType$1("string");
    const isObject = isType$1("object");
    const isPlainObject = (value2) => is$4(value2, Object);
    const isArray$1 = isType$1("array");
    const isNull = eq$1(null);
    const isBoolean = isSimpleType("boolean");
    const isUndefined = eq$1(void 0);
    const isNullable = (a) => a === null || a === void 0;
    const isNonNullable = (a) => !isNullable(a);
    const isFunction = isSimpleType("function");
    const isNumber = isSimpleType("number");
    const isArrayOf = (value2, pred) => {
      if (isArray$1(value2)) {
        for (let i = 0, len = value2.length; i < len; ++i) {
          if (!pred(value2[i])) {
            return false;
          }
        }
        return true;
      }
      return false;
    };
    const noop = () => {
    };
    const compose = (fa, fb) => {
      return (...args) => {
        return fa(fb.apply(null, args));
      };
    };
    const compose1 = (fbc, fab) => (a) => fbc(fab(a));
    const constant = (value2) => {
      return () => {
        return value2;
      };
    };
    const identity = (x) => {
      return x;
    };
    const tripleEquals = (a, b) => {
      return a === b;
    };
    function curry(fn, ...initialArgs) {
      return (...restArgs) => {
        const all2 = initialArgs.concat(restArgs);
        return fn.apply(null, all2);
      };
    }
    const not = (f) => (t) => !f(t);
    const die = (msg) => {
      return () => {
        throw new Error(msg);
      };
    };
    const apply$1 = (f) => {
      return f();
    };
    const call = (f) => {
      f();
    };
    const never = constant(false);
    const always = constant(true);
    class Optional {
      constructor(tag, value2) {
        this.tag = tag;
        this.value = value2;
      }
      static some(value2) {
        return new Optional(true, value2);
      }
      static none() {
        return Optional.singletonNone;
      }
      fold(onNone, onSome) {
        if (this.tag) {
          return onSome(this.value);
        } else {
          return onNone();
        }
      }
      isSome() {
        return this.tag;
      }
      isNone() {
        return !this.tag;
      }
      map(mapper) {
        if (this.tag) {
          return Optional.some(mapper(this.value));
        } else {
          return Optional.none();
        }
      }
      bind(binder2) {
        if (this.tag) {
          return binder2(this.value);
        } else {
          return Optional.none();
        }
      }
      exists(predicate) {
        return this.tag && predicate(this.value);
      }
      forall(predicate) {
        return !this.tag || predicate(this.value);
      }
      filter(predicate) {
        if (!this.tag || predicate(this.value)) {
          return this;
        } else {
          return Optional.none();
        }
      }
      getOr(replacement) {
        return this.tag ? this.value : replacement;
      }
      or(replacement) {
        return this.tag ? this : replacement;
      }
      getOrThunk(thunk) {
        return this.tag ? this.value : thunk();
      }
      orThunk(thunk) {
        return this.tag ? this : thunk();
      }
      getOrDie(message) {
        if (!this.tag) {
          throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
        } else {
          return this.value;
        }
      }
      static from(value2) {
        return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
      }
      getOrNull() {
        return this.tag ? this.value : null;
      }
      getOrUndefined() {
        return this.value;
      }
      each(worker) {
        if (this.tag) {
          worker(this.value);
        }
      }
      toArray() {
        return this.tag ? [this.value] : [];
      }
      toString() {
        return this.tag ? `some(${this.value})` : "none()";
      }
    }
    Optional.singletonNone = new Optional(false);
    const nativeSlice = Array.prototype.slice;
    const nativeIndexOf = Array.prototype.indexOf;
    const nativePush = Array.prototype.push;
    const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
    const indexOf$1 = (xs, x) => {
      const r2 = rawIndexOf(xs, x);
      return r2 === -1 ? Optional.none() : Optional.some(r2);
    };
    const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
    const exists = (xs, pred) => {
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        if (pred(x, i)) {
          return true;
        }
      }
      return false;
    };
    const map$3 = (xs, f) => {
      const len = xs.length;
      const r2 = new Array(len);
      for (let i = 0; i < len; i++) {
        const x = xs[i];
        r2[i] = f(x, i);
      }
      return r2;
    };
    const each$f = (xs, f) => {
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        f(x, i);
      }
    };
    const eachr = (xs, f) => {
      for (let i = xs.length - 1; i >= 0; i--) {
        const x = xs[i];
        f(x, i);
      }
    };
    const partition$2 = (xs, pred) => {
      const pass = [];
      const fail = [];
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        const arr = pred(x, i) ? pass : fail;
        arr.push(x);
      }
      return {
        pass,
        fail
      };
    };
    const filter$6 = (xs, pred) => {
      const r2 = [];
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        if (pred(x, i)) {
          r2.push(x);
        }
      }
      return r2;
    };
    const foldr = (xs, f, acc) => {
      eachr(xs, (x, i) => {
        acc = f(acc, x, i);
      });
      return acc;
    };
    const foldl = (xs, f, acc) => {
      each$f(xs, (x, i) => {
        acc = f(acc, x, i);
      });
      return acc;
    };
    const findUntil$1 = (xs, pred, until) => {
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        if (pred(x, i)) {
          return Optional.some(x);
        } else if (until(x, i)) {
          break;
        }
      }
      return Optional.none();
    };
    const find$2 = (xs, pred) => {
      return findUntil$1(xs, pred, never);
    };
    const findIndex$2 = (xs, pred) => {
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        if (pred(x, i)) {
          return Optional.some(i);
        }
      }
      return Optional.none();
    };
    const flatten = (xs) => {
      const r2 = [];
      for (let i = 0, len = xs.length; i < len; ++i) {
        if (!isArray$1(xs[i])) {
          throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
        }
        nativePush.apply(r2, xs[i]);
      }
      return r2;
    };
    const bind$3 = (xs, f) => flatten(map$3(xs, f));
    const forall = (xs, pred) => {
      for (let i = 0, len = xs.length; i < len; ++i) {
        const x = xs[i];
        if (pred(x, i) !== true) {
          return false;
        }
      }
      return true;
    };
    const reverse = (xs) => {
      const r2 = nativeSlice.call(xs, 0);
      r2.reverse();
      return r2;
    };
    const difference = (a1, a2) => filter$6(a1, (x) => !contains$2(a2, x));
    const mapToObject = (xs, f) => {
      const r2 = {};
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        r2[String(x)] = f(x, i);
      }
      return r2;
    };
    const sort = (xs, comparator) => {
      const copy2 = nativeSlice.call(xs, 0);
      copy2.sort(comparator);
      return copy2;
    };
    const get$b = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
    const head = (xs) => get$b(xs, 0);
    const last$3 = (xs) => get$b(xs, xs.length - 1);
    const from = isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x);
    const findMap = (arr, f) => {
      for (let i = 0; i < arr.length; i++) {
        const r2 = f(arr[i], i);
        if (r2.isSome()) {
          return r2;
        }
      }
      return Optional.none();
    };
    const unique$1 = (xs, comparator) => {
      const r2 = [];
      const isDuplicated = isFunction(comparator) ? (x) => exists(r2, (i) => comparator(i, x)) : (x) => contains$2(r2, x);
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        if (!isDuplicated(x)) {
          r2.push(x);
        }
      }
      return r2;
    };
    const keys = Object.keys;
    const hasOwnProperty$2 = Object.hasOwnProperty;
    const each$e = (obj, f) => {
      const props = keys(obj);
      for (let k = 0, len = props.length; k < len; k++) {
        const i = props[k];
        const x = obj[i];
        f(x, i);
      }
    };
    const map$2 = (obj, f) => {
      return tupleMap(obj, (x, i) => ({
        k: i,
        v: f(x, i)
      }));
    };
    const tupleMap = (obj, f) => {
      const r2 = {};
      each$e(obj, (x, i) => {
        const tuple = f(x, i);
        r2[tuple.k] = tuple.v;
      });
      return r2;
    };
    const objAcc = (r2) => (x, i) => {
      r2[i] = x;
    };
    const internalFilter = (obj, pred, onTrue, onFalse) => {
      const r2 = {};
      each$e(obj, (x, i) => {
        (pred(x, i) ? onTrue : onFalse)(x, i);
      });
      return r2;
    };
    const bifilter = (obj, pred) => {
      const t = {};
      const f = {};
      internalFilter(obj, pred, objAcc(t), objAcc(f));
      return {
        t,
        f
      };
    };
    const filter$5 = (obj, pred) => {
      const t = {};
      internalFilter(obj, pred, objAcc(t), noop);
      return t;
    };
    const mapToArray = (obj, f) => {
      const r2 = [];
      each$e(obj, (value2, name2) => {
        r2.push(f(value2, name2));
      });
      return r2;
    };
    const values = (obj) => {
      return mapToArray(obj, identity);
    };
    const get$a = (obj, key) => {
      return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
    };
    const has$2 = (obj, key) => hasOwnProperty$2.call(obj, key);
    const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== void 0 && obj[key] !== null;
    const equal$1 = (a1, a2, eq2 = eqAny) => eqRecord(eq2).eq(a1, a2);
    const stringArray = (a) => {
      const all2 = {};
      each$f(a, (key) => {
        all2[key] = {};
      });
      return keys(all2);
    };
    const isArray = Array.isArray;
    const toArray$1 = (obj) => {
      if (!isArray(obj)) {
        const array = [];
        for (let i = 0, l = obj.length; i < l; i++) {
          array[i] = obj[i];
        }
        return array;
      } else {
        return obj;
      }
    };
    const each$d = (o, cb, s) => {
      let n, l;
      if (!o) {
        return false;
      }
      s = s || o;
      if (o.length !== void 0) {
        for (n = 0, l = o.length; n < l; n++) {
          if (cb.call(s, o[n], n, o) === false) {
            return false;
          }
        }
      } else {
        for (n in o) {
          if (has$2(o, n)) {
            if (cb.call(s, o[n], n, o) === false) {
              return false;
            }
          }
        }
      }
      return true;
    };
    const map$1 = (array, callback) => {
      const out = [];
      each$d(array, (item, index2) => {
        out.push(callback(item, index2, array));
      });
      return out;
    };
    const filter$4 = (a, f) => {
      const o = [];
      each$d(a, (v, index2) => {
        if (!f || f(v, index2, a)) {
          o.push(v);
        }
      });
      return o;
    };
    const indexOf = (a, v) => {
      if (a) {
        for (let i = 0, l = a.length; i < l; i++) {
          if (a[i] === v) {
            return i;
          }
        }
      }
      return -1;
    };
    const reduce = (collection, iteratee, accumulator, thisArg) => {
      let acc = isUndefined(accumulator) ? collection[0] : accumulator;
      for (let i = 0; i < collection.length; i++) {
        acc = iteratee.call(thisArg, acc, collection[i], i);
      }
      return acc;
    };
    const findIndex$1 = (array, predicate, thisArg) => {
      let i, l;
      for (i = 0, l = array.length; i < l; i++) {
        if (predicate.call(thisArg, array[i], i, array)) {
          return i;
        }
      }
      return -1;
    };
    const last$2 = (collection) => collection[collection.length - 1];
    const cached = (f) => {
      let called = false;
      let r2;
      return (...args) => {
        if (!called) {
          called = true;
          r2 = f.apply(null, args);
        }
        return r2;
      };
    };
    const DeviceType = (os2, browser2, userAgent2, mediaMatch2) => {
      const isiPad = os2.isiOS() && /ipad/i.test(userAgent2) === true;
      const isiPhone = os2.isiOS() && !isiPad;
      const isMobile = os2.isiOS() || os2.isAndroid();
      const isTouch2 = isMobile || mediaMatch2("(pointer:coarse)");
      const isTablet2 = isiPad || !isiPhone && isMobile && mediaMatch2("(min-device-width:768px)");
      const isPhone2 = isiPhone || isMobile && !isTablet2;
      const iOSwebview = browser2.isSafari() && os2.isiOS() && /safari/i.test(userAgent2) === false;
      const isDesktop = !isPhone2 && !isTablet2 && !iOSwebview;
      return {
        isiPad: constant(isiPad),
        isiPhone: constant(isiPhone),
        isTablet: constant(isTablet2),
        isPhone: constant(isPhone2),
        isTouch: constant(isTouch2),
        isAndroid: os2.isAndroid,
        isiOS: os2.isiOS,
        isWebView: constant(iOSwebview),
        isDesktop: constant(isDesktop)
      };
    };
    const firstMatch = (regexes, s) => {
      for (let i = 0; i < regexes.length; i++) {
        const x = regexes[i];
        if (x.test(s)) {
          return x;
        }
      }
      return void 0;
    };
    const find$1 = (regexes, agent) => {
      const r2 = firstMatch(regexes, agent);
      if (!r2) {
        return {
          major: 0,
          minor: 0
        };
      }
      const group = (i) => {
        return Number(agent.replace(r2, "$" + i));
      };
      return nu$3(group(1), group(2));
    };
    const detect$5 = (versionRegexes, agent) => {
      const cleanedAgent = String(agent).toLowerCase();
      if (versionRegexes.length === 0) {
        return unknown$2();
      }
      return find$1(versionRegexes, cleanedAgent);
    };
    const unknown$2 = () => {
      return nu$3(0, 0);
    };
    const nu$3 = (major, minor) => {
      return {
        major,
        minor
      };
    };
    const Version = {
      nu: nu$3,
      detect: detect$5,
      unknown: unknown$2
    };
    const detectBrowser$1 = (browsers2, userAgentData) => {
      return findMap(userAgentData.brands, (uaBrand) => {
        const lcBrand = uaBrand.brand.toLowerCase();
        return find$2(browsers2, (browser2) => {
          var _a;
          return lcBrand === ((_a = browser2.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
        }).map((info) => ({
          current: info.name,
          version: Version.nu(parseInt(uaBrand.version, 10), 0)
        }));
      });
    };
    const detect$4 = (candidates, userAgent2) => {
      const agent = String(userAgent2).toLowerCase();
      return find$2(candidates, (candidate) => {
        return candidate.search(agent);
      });
    };
    const detectBrowser = (browsers2, userAgent2) => {
      return detect$4(browsers2, userAgent2).map((browser2) => {
        const version = Version.detect(browser2.versionRegexes, userAgent2);
        return {
          current: browser2.name,
          version
        };
      });
    };
    const detectOs = (oses2, userAgent2) => {
      return detect$4(oses2, userAgent2).map((os2) => {
        const version = Version.detect(os2.versionRegexes, userAgent2);
        return {
          current: os2.name,
          version
        };
      });
    };
    const removeFromStart = (str, numChars) => {
      return str.substring(numChars);
    };
    const checkRange = (str, substr, start2) => substr === "" || str.length >= substr.length && str.substr(start2, start2 + substr.length) === substr;
    const removeLeading = (str, prefix) => {
      return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
    };
    const contains$1 = (str, substr) => {
      return str.indexOf(substr) !== -1;
    };
    const startsWith = (str, prefix) => {
      return checkRange(str, prefix, 0);
    };
    const endsWith = (str, suffix) => {
      return checkRange(str, suffix, str.length - suffix.length);
    };
    const blank = (r2) => (s) => s.replace(r2, "");
    const trim$3 = blank(/^\s+|\s+$/g);
    const lTrim = blank(/^\s+/g);
    const rTrim = blank(/\s+$/g);
    const isNotEmpty = (s) => s.length > 0;
    const isEmpty$3 = (s) => !isNotEmpty(s);
    const repeat = (s, count2) => count2 <= 0 ? "" : new Array(count2 + 1).join(s);
    const toInt = (value2, radix = 10) => {
      const num = parseInt(value2, radix);
      return isNaN(num) ? Optional.none() : Optional.some(num);
    };
    const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
    const checkContains = (target) => {
      return (uastring) => {
        return contains$1(uastring, target);
      };
    };
    const browsers = [
      {
        name: "Edge",
        versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
        search: (uastring) => {
          return contains$1(uastring, "edge/") && contains$1(uastring, "chrome") && contains$1(uastring, "safari") && contains$1(uastring, "applewebkit");
        }
      },
      {
        name: "Chromium",
        brand: "Chromium",
        versionRegexes: [
          /.*?chrome\/([0-9]+)\.([0-9]+).*/,
          normalVersionRegex
        ],
        search: (uastring) => {
          return contains$1(uastring, "chrome") && !contains$1(uastring, "chromeframe");
        }
      },
      {
        name: "IE",
        versionRegexes: [
          /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
          /.*?rv:([0-9]+)\.([0-9]+).*/
        ],
        search: (uastring) => {
          return contains$1(uastring, "msie") || contains$1(uastring, "trident");
        }
      },
      {
        name: "Opera",
        versionRegexes: [
          normalVersionRegex,
          /.*?opera\/([0-9]+)\.([0-9]+).*/
        ],
        search: checkContains("opera")
      },
      {
        name: "Firefox",
        versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
        search: checkContains("firefox")
      },
      {
        name: "Safari",
        versionRegexes: [
          normalVersionRegex,
          /.*?cpu os ([0-9]+)_([0-9]+).*/
        ],
        search: (uastring) => {
          return (contains$1(uastring, "safari") || contains$1(uastring, "mobile/")) && contains$1(uastring, "applewebkit");
        }
      }
    ];
    const oses = [
      {
        name: "Windows",
        search: checkContains("win"),
        versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
      },
      {
        name: "iOS",
        search: (uastring) => {
          return contains$1(uastring, "iphone") || contains$1(uastring, "ipad");
        },
        versionRegexes: [
          /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
          /.*cpu os ([0-9]+)_([0-9]+).*/,
          /.*cpu iphone os ([0-9]+)_([0-9]+).*/
        ]
      },
      {
        name: "Android",
        search: checkContains("android"),
        versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
      },
      {
        name: "macOS",
        search: checkContains("mac os x"),
        versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
      },
      {
        name: "Linux",
        search: checkContains("linux"),
        versionRegexes: []
      },
      {
        name: "Solaris",
        search: checkContains("sunos"),
        versionRegexes: []
      },
      {
        name: "FreeBSD",
        search: checkContains("freebsd"),
        versionRegexes: []
      },
      {
        name: "ChromeOS",
        search: checkContains("cros"),
        versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
      }
    ];
    const PlatformInfo = {
      browsers: constant(browsers),
      oses: constant(oses)
    };
    const edge = "Edge";
    const chromium = "Chromium";
    const ie = "IE";
    const opera = "Opera";
    const firefox = "Firefox";
    const safari = "Safari";
    const unknown$1 = () => {
      return nu$2({
        current: void 0,
        version: Version.unknown()
      });
    };
    const nu$2 = (info) => {
      const current = info.current;
      const version = info.version;
      const isBrowser = (name2) => () => current === name2;
      return {
        current,
        version,
        isEdge: isBrowser(edge),
        isChromium: isBrowser(chromium),
        isIE: isBrowser(ie),
        isOpera: isBrowser(opera),
        isFirefox: isBrowser(firefox),
        isSafari: isBrowser(safari)
      };
    };
    const Browser = {
      unknown: unknown$1,
      nu: nu$2,
      edge: constant(edge),
      chromium: constant(chromium),
      ie: constant(ie),
      opera: constant(opera),
      firefox: constant(firefox),
      safari: constant(safari)
    };
    const windows = "Windows";
    const ios = "iOS";
    const android = "Android";
    const linux = "Linux";
    const macos = "macOS";
    const solaris = "Solaris";
    const freebsd = "FreeBSD";
    const chromeos = "ChromeOS";
    const unknown = () => {
      return nu$1({
        current: void 0,
        version: Version.unknown()
      });
    };
    const nu$1 = (info) => {
      const current = info.current;
      const version = info.version;
      const isOS = (name2) => () => current === name2;
      return {
        current,
        version,
        isWindows: isOS(windows),
        isiOS: isOS(ios),
        isAndroid: isOS(android),
        isMacOS: isOS(macos),
        isLinux: isOS(linux),
        isSolaris: isOS(solaris),
        isFreeBSD: isOS(freebsd),
        isChromeOS: isOS(chromeos)
      };
    };
    const OperatingSystem = {
      unknown,
      nu: nu$1,
      windows: constant(windows),
      ios: constant(ios),
      android: constant(android),
      linux: constant(linux),
      macos: constant(macos),
      solaris: constant(solaris),
      freebsd: constant(freebsd),
      chromeos: constant(chromeos)
    };
    const detect$3 = (userAgent2, userAgentDataOpt, mediaMatch2) => {
      const browsers2 = PlatformInfo.browsers();
      const oses2 = PlatformInfo.oses();
      const browser2 = userAgentDataOpt.bind((userAgentData) => detectBrowser$1(browsers2, userAgentData)).orThunk(() => detectBrowser(browsers2, userAgent2)).fold(Browser.unknown, Browser.nu);
      const os2 = detectOs(oses2, userAgent2).fold(OperatingSystem.unknown, OperatingSystem.nu);
      const deviceType2 = DeviceType(os2, browser2, userAgent2, mediaMatch2);
      return {
        browser: browser2,
        os: os2,
        deviceType: deviceType2
      };
    };
    const PlatformDetection = { detect: detect$3 };
    const mediaMatch = (query) => window.matchMedia(query).matches;
    let platform$2 = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
    const detect$2 = () => platform$2();
    const userAgent = navigator.userAgent;
    const platform$1 = detect$2();
    const browser$1 = platform$1.browser;
    const os = platform$1.os;
    const deviceType = platform$1.deviceType;
    const windowsPhone = userAgent.indexOf("Windows Phone") !== -1;
    const Env = {
      transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
      documentMode: browser$1.isIE() ? document.documentMode || 7 : 10,
      cacheSuffix: null,
      container: null,
      canHaveCSP: !browser$1.isIE(),
      windowsPhone,
      browser: {
        current: browser$1.current,
        version: browser$1.version,
        isChromium: browser$1.isChromium,
        isEdge: browser$1.isEdge,
        isFirefox: browser$1.isFirefox,
        isIE: browser$1.isIE,
        isOpera: browser$1.isOpera,
        isSafari: browser$1.isSafari
      },
      os: {
        current: os.current,
        version: os.version,
        isAndroid: os.isAndroid,
        isChromeOS: os.isChromeOS,
        isFreeBSD: os.isFreeBSD,
        isiOS: os.isiOS,
        isLinux: os.isLinux,
        isMacOS: os.isMacOS,
        isSolaris: os.isSolaris,
        isWindows: os.isWindows
      },
      deviceType: {
        isDesktop: deviceType.isDesktop,
        isiPad: deviceType.isiPad,
        isiPhone: deviceType.isiPhone,
        isPhone: deviceType.isPhone,
        isTablet: deviceType.isTablet,
        isTouch: deviceType.isTouch,
        isWebView: deviceType.isWebView
      }
    };
    const whiteSpaceRegExp$1 = /^\s*|\s*$/g;
    const trim$2 = (str) => {
      return str === null || str === void 0 ? "" : ("" + str).replace(whiteSpaceRegExp$1, "");
    };
    const is$3 = (obj, type2) => {
      if (!type2) {
        return obj !== void 0;
      }
      if (type2 === "array" && isArray(obj)) {
        return true;
      }
      return typeof obj === type2;
    };
    const makeMap$4 = (items, delim, map2) => {
      let i;
      items = items || [];
      delim = delim || ",";
      if (typeof items === "string") {
        items = items.split(delim);
      }
      map2 = map2 || {};
      i = items.length;
      while (i--) {
        map2[items[i]] = {};
      }
      return map2;
    };
    const hasOwnProperty$1 = has$2;
    const extend$3 = (obj, ...exts) => {
      for (let i = 0; i < exts.length; i++) {
        const ext = exts[i];
        for (const name2 in ext) {
          if (has$2(ext, name2)) {
            const value2 = ext[name2];
            if (value2 !== void 0) {
              obj[name2] = value2;
            }
          }
        }
      }
      return obj;
    };
    const walk$4 = function(o, f, n, s) {
      s = s || this;
      if (o) {
        if (n) {
          o = o[n];
        }
        each$d(o, (o2, i) => {
          if (f.call(s, o2, i, n) === false) {
            return false;
          }
          walk$4(o2, f, n, s);
        });
      }
    };
    const resolve$2 = (n, o) => {
      let i, l;
      o = o || window;
      n = n.split(".");
      for (i = 0, l = n.length; i < l; i++) {
        o = o[n[i]];
        if (!o) {
          break;
        }
      }
      return o;
    };
    const explode$3 = (s, d) => {
      if (!s || is$3(s, "array")) {
        return s;
      }
      return map$1(s.split(d || ","), trim$2);
    };
    const _addCacheSuffix = (url) => {
      const cacheSuffix = Env.cacheSuffix;
      if (cacheSuffix) {
        url += (url.indexOf("?") === -1 ? "?" : "&") + cacheSuffix;
      }
      return url;
    };
    const Tools = {
      trim: trim$2,
      isArray,
      is: is$3,
      toArray: toArray$1,
      makeMap: makeMap$4,
      each: each$d,
      map: map$1,
      grep: filter$4,
      inArray: indexOf,
      hasOwn: hasOwnProperty$1,
      extend: extend$3,
      walk: walk$4,
      resolve: resolve$2,
      explode: explode$3,
      _addCacheSuffix
    };
    const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
    const cat = (arr) => {
      const r2 = [];
      const push = (x) => {
        r2.push(x);
      };
      for (let i = 0; i < arr.length; i++) {
        arr[i].each(push);
      }
      return r2;
    };
    const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
    const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
    const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
    typeof window !== "undefined" ? window : Function("return this;")();
    const COMMENT = 8;
    const DOCUMENT = 9;
    const DOCUMENT_FRAGMENT = 11;
    const ELEMENT = 1;
    const TEXT = 3;
    const name = (element) => {
      const r2 = element.dom.nodeName;
      return r2.toLowerCase();
    };
    const type$1 = (element) => element.dom.nodeType;
    const isType = (t) => (element) => type$1(element) === t;
    const isComment$1 = (element) => type$1(element) === COMMENT || name(element) === "#comment";
    const isElement$7 = isType(ELEMENT);
    const isText$a = isType(TEXT);
    const isDocument$2 = isType(DOCUMENT);
    const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
    const isTag = (tag) => (e) => isElement$7(e) && name(e) === tag;
    const rawSet = (dom2, key, value2) => {
      if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
        dom2.setAttribute(key, value2 + "");
      } else {
        console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value2, ":: Element ", dom2);
        throw new Error("Attribute value was not simple");
      }
    };
    const set$2 = (element, key, value2) => {
      rawSet(element.dom, key, value2);
    };
    const setAll$1 = (element, attrs) => {
      const dom2 = element.dom;
      each$e(attrs, (v, k) => {
        rawSet(dom2, k, v);
      });
    };
    const get$9 = (element, key) => {
      const v = element.dom.getAttribute(key);
      return v === null ? void 0 : v;
    };
    const getOpt = (element, key) => Optional.from(get$9(element, key));
    const has$1 = (element, key) => {
      const dom2 = element.dom;
      return dom2 && dom2.hasAttribute ? dom2.hasAttribute(key) : false;
    };
    const remove$b = (element, key) => {
      element.dom.removeAttribute(key);
    };
    const hasNone = (element) => {
      const attrs = element.dom.attributes;
      return attrs === void 0 || attrs === null || attrs.length === 0;
    };
    const clone$4 = (element) => foldl(element.dom.attributes, (acc, attr) => {
      acc[attr.name] = attr.value;
      return acc;
    }, {});
    const read$4 = (element, attr) => {
      const value2 = get$9(element, attr);
      return value2 === void 0 || value2 === "" ? [] : value2.split(" ");
    };
    const add$4 = (element, attr, id) => {
      const old = read$4(element, attr);
      const nu2 = old.concat([id]);
      set$2(element, attr, nu2.join(" "));
      return true;
    };
    const remove$a = (element, attr, id) => {
      const nu2 = filter$6(read$4(element, attr), (v) => v !== id);
      if (nu2.length > 0) {
        set$2(element, attr, nu2.join(" "));
      } else {
        remove$b(element, attr);
      }
      return false;
    };
    const supports = (element) => element.dom.classList !== void 0;
    const get$8 = (element) => read$4(element, "class");
    const add$3 = (element, clazz) => add$4(element, "class", clazz);
    const remove$9 = (element, clazz) => remove$a(element, "class", clazz);
    const toggle$2 = (element, clazz) => {
      if (contains$2(get$8(element), clazz)) {
        return remove$9(element, clazz);
      } else {
        return add$3(element, clazz);
      }
    };
    const add$2 = (element, clazz) => {
      if (supports(element)) {
        element.dom.classList.add(clazz);
      } else {
        add$3(element, clazz);
      }
    };
    const cleanClass = (element) => {
      const classList = supports(element) ? element.dom.classList : get$8(element);
      if (classList.length === 0) {
        remove$b(element, "class");
      }
    };
    const remove$8 = (element, clazz) => {
      if (supports(element)) {
        const classList = element.dom.classList;
        classList.remove(clazz);
      } else {
        remove$9(element, clazz);
      }
      cleanClass(element);
    };
    const toggle$1 = (element, clazz) => {
      const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
      cleanClass(element);
      return result;
    };
    const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
    const isSupported$1 = (dom2) => dom2.style !== void 0 && isFunction(dom2.style.getPropertyValue);
    const fromHtml$1 = (html2, scope) => {
      const doc = scope || document;
      const div = doc.createElement("div");
      div.innerHTML = html2;
      if (!div.hasChildNodes() || div.childNodes.length > 1) {
        const message = "HTML does not have a single root node";
        console.error(message, html2);
        throw new Error(message);
      }
      return fromDom$2(div.childNodes[0]);
    };
    const fromTag = (tag, scope) => {
      const doc = scope || document;
      const node = doc.createElement(tag);
      return fromDom$2(node);
    };
    const fromText = (text2, scope) => {
      const doc = scope || document;
      const node = doc.createTextNode(text2);
      return fromDom$2(node);
    };
    const fromDom$2 = (node) => {
      if (node === null || node === void 0) {
        throw new Error("Node cannot be null or undefined");
      }
      return { dom: node };
    };
    const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
    const SugarElement = {
      fromHtml: fromHtml$1,
      fromTag,
      fromText,
      fromDom: fromDom$2,
      fromPoint: fromPoint$2
    };
    const toArray = (target, f) => {
      const r2 = [];
      const recurse = (e) => {
        r2.push(e);
        return f(e);
      };
      let cur = f(target);
      do {
        cur = cur.bind(recurse);
      } while (cur.isSome());
      return r2;
    };
    const is$1 = (element, selector) => {
      const dom2 = element.dom;
      if (dom2.nodeType !== ELEMENT) {
        return false;
      } else {
        const elem = dom2;
        if (elem.matches !== void 0) {
          return elem.matches(selector);
        } else if (elem.msMatchesSelector !== void 0) {
          return elem.msMatchesSelector(selector);
        } else if (elem.webkitMatchesSelector !== void 0) {
          return elem.webkitMatchesSelector(selector);
        } else if (elem.mozMatchesSelector !== void 0) {
          return elem.mozMatchesSelector(selector);
        } else {
          throw new Error("Browser lacks native selectors");
        }
      }
    };
    const bypassSelector = (dom2) => dom2.nodeType !== ELEMENT && dom2.nodeType !== DOCUMENT && dom2.nodeType !== DOCUMENT_FRAGMENT || dom2.childElementCount === 0;
    const all = (selector, scope) => {
      const base = scope === void 0 ? document : scope.dom;
      return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
    };
    const one = (selector, scope) => {
      const base = scope === void 0 ? document : scope.dom;
      return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
    };
    const eq = (e1, e2) => e1.dom === e2.dom;
    const contains = (e1, e2) => {
      const d1 = e1.dom;
      const d2 = e2.dom;
      return d1 === d2 ? false : d1.contains(d2);
    };
    const owner$1 = (element) => SugarElement.fromDom(element.dom.ownerDocument);
    const documentOrOwner = (dos) => isDocument$2(dos) ? dos : owner$1(dos);
    const documentElement = (element) => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
    const defaultView = (element) => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
    const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
    const parentElement = (element) => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
    const parents$1 = (element, isRoot2) => {
      const stop2 = isFunction(isRoot2) ? isRoot2 : never;
      let dom2 = element.dom;
      const ret = [];
      while (dom2.parentNode !== null && dom2.parentNode !== void 0) {
        const rawParent = dom2.parentNode;
        const p = SugarElement.fromDom(rawParent);
        ret.push(p);
        if (stop2(p) === true) {
          break;
        } else {
          dom2 = rawParent;
        }
      }
      return ret;
    };
    const siblings = (element) => {
      const filterSelf = (elements) => filter$6(elements, (x) => !eq(element, x));
      return parent(element).map(children).map(filterSelf).getOr([]);
    };
    const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
    const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
    const prevSiblings = (element) => reverse(toArray(element, prevSibling));
    const nextSiblings = (element) => toArray(element, nextSibling);
    const children = (element) => map$3(element.dom.childNodes, SugarElement.fromDom);
    const child$1 = (element, index2) => {
      const cs = element.dom.childNodes;
      return Optional.from(cs[index2]).map(SugarElement.fromDom);
    };
    const firstChild = (element) => child$1(element, 0);
    const lastChild = (element) => child$1(element, element.dom.childNodes.length - 1);
    const childNodesCount = (element) => element.dom.childNodes.length;
    const getHead = (doc) => {
      const b = doc.dom.head;
      if (b === null || b === void 0) {
        throw new Error("Head is not available yet");
      }
      return SugarElement.fromDom(b);
    };
    const isShadowRoot = (dos) => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
    const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
    const isSupported = constant(supported);
    const getRootNode = supported ? (e) => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
    const getStyleContainer = (dos) => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
    const getShadowRoot = (e) => {
      const r2 = getRootNode(e);
      return isShadowRoot(r2) ? Optional.some(r2) : Optional.none();
    };
    const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
    const getOriginalEventTarget = (event) => {
      if (isSupported() && isNonNullable(event.target)) {
        const el = SugarElement.fromDom(event.target);
        if (isElement$7(el) && isOpenShadowHost(el)) {
          if (event.composed && event.composedPath) {
            const composedPath = event.composedPath();
            if (composedPath) {
              return head(composedPath);
            }
          }
        }
      }
      return Optional.from(event.target);
    };
    const isOpenShadowHost = (element) => isNonNullable(element.dom.shadowRoot);
    const inBody = (element) => {
      const dom2 = isText$a(element) ? element.dom.parentNode : element.dom;
      if (dom2 === void 0 || dom2 === null || dom2.ownerDocument === null) {
        return false;
      }
      const doc = dom2.ownerDocument;
      return getShadowRoot(SugarElement.fromDom(dom2)).fold(() => doc.body.contains(dom2), compose1(inBody, getShadowHost));
    };
    const internalSet = (dom2, property, value2) => {
      if (!isString(value2)) {
        console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value2, ":: Element ", dom2);
        throw new Error("CSS value must be a string: " + value2);
      }
      if (isSupported$1(dom2)) {
        dom2.style.setProperty(property, value2);
      }
    };
    const internalRemove = (dom2, property) => {
      if (isSupported$1(dom2)) {
        dom2.style.removeProperty(property);
      }
    };
    const set$1 = (element, property, value2) => {
      const dom2 = element.dom;
      internalSet(dom2, property, value2);
    };
    const setAll = (element, css) => {
      const dom2 = element.dom;
      each$e(css, (v, k) => {
        internalSet(dom2, k, v);
      });
    };
    const get$7 = (element, property) => {
      const dom2 = element.dom;
      const styles = window.getComputedStyle(dom2);
      const r2 = styles.getPropertyValue(property);
      return r2 === "" && !inBody(element) ? getUnsafeProperty(dom2, property) : r2;
    };
    const getUnsafeProperty = (dom2, property) => isSupported$1(dom2) ? dom2.style.getPropertyValue(property) : "";
    const getRaw$1 = (element, property) => {
      const dom2 = element.dom;
      const raw = getUnsafeProperty(dom2, property);
      return Optional.from(raw).filter((r2) => r2.length > 0);
    };
    const getAllRaw = (element) => {
      const css = {};
      const dom2 = element.dom;
      if (isSupported$1(dom2)) {
        for (let i = 0; i < dom2.style.length; i++) {
          const ruleName = dom2.style.item(i);
          css[ruleName] = dom2.style[ruleName];
        }
      }
      return css;
    };
    const remove$7 = (element, property) => {
      const dom2 = element.dom;
      internalRemove(dom2, property);
      if (is$2(getOpt(element, "style").map(trim$3), "")) {
        remove$b(element, "style");
      }
    };
    const reflow = (e) => e.dom.offsetWidth;
    const before$3 = (marker, element) => {
      const parent$1 = parent(marker);
      parent$1.each((v) => {
        v.dom.insertBefore(element.dom, marker.dom);
      });
    };
    const after$4 = (marker, element) => {
      const sibling2 = nextSibling(marker);
      sibling2.fold(() => {
        const parent$1 = parent(marker);
        parent$1.each((v) => {
          append$1(v, element);
        });
      }, (v) => {
        before$3(v, element);
      });
    };
    const prepend = (parent2, element) => {
      const firstChild$1 = firstChild(parent2);
      firstChild$1.fold(() => {
        append$1(parent2, element);
      }, (v) => {
        parent2.dom.insertBefore(element.dom, v.dom);
      });
    };
    const append$1 = (parent2, element) => {
      parent2.dom.appendChild(element.dom);
    };
    const wrap$2 = (element, wrapper) => {
      before$3(element, wrapper);
      append$1(wrapper, element);
    };
    const after$3 = (marker, elements) => {
      each$f(elements, (x, i) => {
        const e = i === 0 ? marker : elements[i - 1];
        after$4(e, x);
      });
    };
    const append = (parent2, elements) => {
      each$f(elements, (x) => {
        append$1(parent2, x);
      });
    };
    const empty = (element) => {
      element.dom.textContent = "";
      each$f(children(element), (rogue) => {
        remove$6(rogue);
      });
    };
    const remove$6 = (element) => {
      const dom2 = element.dom;
      if (dom2.parentNode !== null) {
        dom2.parentNode.removeChild(dom2);
      }
    };
    const unwrap = (wrapper) => {
      const children$1 = children(wrapper);
      if (children$1.length > 0) {
        after$3(wrapper, children$1);
      }
      remove$6(wrapper);
    };
    const fromHtml = (html2, scope) => {
      const doc = scope || document;
      const div = doc.createElement("div");
      div.innerHTML = html2;
      return children(SugarElement.fromDom(div));
    };
    const fromDom$1 = (nodes) => map$3(nodes, SugarElement.fromDom);
    const get$6 = (element) => element.dom.innerHTML;
    const set = (element, content) => {
      const owner2 = owner$1(element);
      const docDom = owner2.dom;
      const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
      const contentElements = fromHtml(content, docDom);
      append(fragment, contentElements);
      empty(element);
      append$1(element, fragment);
    };
    const getOuter = (element) => {
      const container = SugarElement.fromTag("div");
      const clone2 = SugarElement.fromDom(element.dom.cloneNode(true));
      append$1(container, clone2);
      return get$6(container);
    };
    const mkEvent = (target, x, y, stop2, prevent, kill, raw) => ({
      target,
      x,
      y,
      stop: stop2,
      prevent,
      kill,
      raw
    });
    const fromRawEvent = (rawEvent) => {
      const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
      const stop2 = () => rawEvent.stopPropagation();
      const prevent = () => rawEvent.preventDefault();
      const kill = compose(prevent, stop2);
      return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop2, prevent, kill, rawEvent);
    };
    const handle$1 = (filter2, handler) => (rawEvent) => {
      if (filter2(rawEvent)) {
        handler(fromRawEvent(rawEvent));
      }
    };
    const binder = (element, event, filter2, handler, useCapture) => {
      const wrapped = handle$1(filter2, handler);
      element.dom.addEventListener(event, wrapped, useCapture);
      return { unbind: curry(unbind, element, event, wrapped, useCapture) };
    };
    const bind$2 = (element, event, filter2, handler) => binder(element, event, filter2, handler, false);
    const unbind = (element, event, handler, useCapture) => {
      element.dom.removeEventListener(event, handler, useCapture);
    };
    const r = (left, top) => {
      const translate2 = (x, y) => r(left + x, top + y);
      return {
        left,
        top,
        translate: translate2
      };
    };
    const SugarPosition = r;
    const boxPosition = (dom2) => {
      const box = dom2.getBoundingClientRect();
      return SugarPosition(box.left, box.top);
    };
    const firstDefinedOrZero = (a, b) => {
      if (a !== void 0) {
        return a;
      } else {
        return b !== void 0 ? b : 0;
      }
    };
    const absolute = (element) => {
      const doc = element.dom.ownerDocument;
      const body = doc.body;
      const win = doc.defaultView;
      const html2 = doc.documentElement;
      if (body === element.dom) {
        return SugarPosition(body.offsetLeft, body.offsetTop);
      }
      const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html2.scrollTop);
      const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html2.scrollLeft);
      const clientTop = firstDefinedOrZero(html2.clientTop, body.clientTop);
      const clientLeft = firstDefinedOrZero(html2.clientLeft, body.clientLeft);
      return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
    };
    const viewport = (element) => {
      const dom2 = element.dom;
      const doc = dom2.ownerDocument;
      const body = doc.body;
      if (body === dom2) {
        return SugarPosition(body.offsetLeft, body.offsetTop);
      }
      if (!inBody(element)) {
        return SugarPosition(0, 0);
      }
      return boxPosition(dom2);
    };
    const get$5 = (_DOC) => {
      const doc = _DOC !== void 0 ? _DOC.dom : document;
      const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
      const y = doc.body.scrollTop || doc.documentElement.scrollTop;
      return SugarPosition(x, y);
    };
    const to = (x, y, _DOC) => {
      const doc = _DOC !== void 0 ? _DOC.dom : document;
      const win = doc.defaultView;
      if (win) {
        win.scrollTo(x, y);
      }
    };
    const intoView = (element, alignToTop) => {
      const isSafari = detect$2().browser.isSafari();
      if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
        element.dom.scrollIntoViewIfNeeded(false);
      } else {
        element.dom.scrollIntoView(alignToTop);
      }
    };
    const get$4 = (_win) => {
      const win = _win === void 0 ? window : _win;
      if (detect$2().browser.isFirefox()) {
        return Optional.none();
      } else {
        return Optional.from(win.visualViewport);
      }
    };
    const bounds = (x, y, width, height) => ({
      x,
      y,
      width,
      height,
      right: x + width,
      bottom: y + height
    });
    const getBounds = (_win) => {
      const win = _win === void 0 ? window : _win;
      const doc = win.document;
      const scroll = get$5(SugarElement.fromDom(doc));
      return get$4(win).fold(() => {
        const html2 = win.document.documentElement;
        const width = html2.clientWidth;
        const height = html2.clientHeight;
        return bounds(scroll.left, scroll.top, width, height);
      }, (visualViewport) => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
    };
    const isNodeType = (type2) => {
      return (node) => {
        return !!node && node.nodeType === type2;
      };
    };
    const isRestrictedNode = (node) => !!node && !Object.getPrototypeOf(node);
    const isElement$6 = isNodeType(1);
    const matchNodeNames = (names) => {
      const lowercasedNames = names.map((s) => s.toLowerCase());
      return (node) => {
        if (node && node.nodeName) {
          const nodeName = node.nodeName.toLowerCase();
          return contains$2(lowercasedNames, nodeName);
        }
        return false;
      };
    };
    const matchStyleValues = (name2, values2) => {
      const items = values2.toLowerCase().split(" ");
      return (node) => {
        if (isElement$6(node)) {
          for (let i = 0; i < items.length; i++) {
            const computed = node.ownerDocument.defaultView.getComputedStyle(node, null);
            const cssValue = computed ? computed.getPropertyValue(name2) : null;
            if (cssValue === items[i]) {
              return true;
            }
          }
        }
        return false;
      };
    };
    const hasAttribute = (attrName) => {
      return (node) => {
        return isElement$6(node) && node.hasAttribute(attrName);
      };
    };
    const hasAttributeValue = (attrName, attrValue) => {
      return (node) => {
        return isElement$6(node) && node.getAttribute(attrName) === attrValue;
      };
    };
    const isBogus$2 = (node) => isElement$6(node) && node.hasAttribute("data-mce-bogus");
    const isBogusAll$1 = (node) => isElement$6(node) && node.getAttribute("data-mce-bogus") === "all";
    const isTable$3 = (node) => isElement$6(node) && node.tagName === "TABLE";
    const hasContentEditableState = (value2) => {
      return (node) => {
        if (isElement$6(node)) {
          if (node.contentEditable === value2) {
            return true;
          }
          if (node.getAttribute("data-mce-contenteditable") === value2) {
            return true;
          }
        }
        return false;
      };
    };
    const isTextareaOrInput = matchNodeNames([
      "textarea",
      "input"
    ]);
    const isText$9 = isNodeType(3);
    const isCData = isNodeType(4);
    const isPi = isNodeType(7);
    const isComment = isNodeType(8);
    const isDocument$1 = isNodeType(9);
    const isDocumentFragment = isNodeType(11);
    const isBr$6 = matchNodeNames(["br"]);
    const isImg = matchNodeNames(["img"]);
    const isContentEditableTrue$5 = hasContentEditableState("true");
    const isContentEditableFalse$b = hasContentEditableState("false");
    const isTableCell$5 = matchNodeNames([
      "td",
      "th"
    ]);
    const isMedia$2 = matchNodeNames([
      "video",
      "audio",
      "object",
      "embed"
    ]);
    const browser = detect$2().browser;
    const firstElement = (nodes) => find$2(nodes, isElement$7);
    const getTableCaptionDeltaY = (elm) => {
      if (browser.isFirefox() && name(elm) === "table") {
        return firstElement(children(elm)).filter((elm2) => {
          return name(elm2) === "caption";
        }).bind((caption) => {
          return firstElement(nextSiblings(caption)).map((body) => {
            const bodyTop = body.dom.offsetTop;
            const captionTop = caption.dom.offsetTop;
            const captionHeight = caption.dom.offsetHeight;
            return bodyTop <= captionTop ? -captionHeight : 0;
          });
        }).getOr(0);
      } else {
        return 0;
      }
    };
    const hasChild = (elm, child2) => elm.children && contains$2(elm.children, child2);
    const getPos = (body, elm, rootElm) => {
      let x = 0, y = 0;
      const doc = body.ownerDocument;
      rootElm = rootElm ? rootElm : body;
      if (elm) {
        if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), "position") === "static") {
          const pos = elm.getBoundingClientRect();
          x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
          y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
          return {
            x,
            y
          };
        }
        let offsetParent = elm;
        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
          const castOffsetParent = offsetParent;
          x += castOffsetParent.offsetLeft || 0;
          y += castOffsetParent.offsetTop || 0;
          offsetParent = castOffsetParent.offsetParent;
        }
        offsetParent = elm.parentNode;
        while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
          x -= offsetParent.scrollLeft || 0;
          y -= offsetParent.scrollTop || 0;
          offsetParent = offsetParent.parentNode;
        }
        y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
      }
      return {
        x,
        y
      };
    };
    var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot2) => {
      if (is2(scope, a)) {
        return Optional.some(scope);
      } else if (isFunction(isRoot2) && isRoot2(scope)) {
        return Optional.none();
      } else {
        return ancestor2(scope, a, isRoot2);
      }
    };
    const ancestor$3 = (scope, predicate, isRoot2) => {
      let element = scope.dom;
      const stop2 = isFunction(isRoot2) ? isRoot2 : never;
      while (element.parentNode) {
        element = element.parentNode;
        const el = SugarElement.fromDom(element);
        if (predicate(el)) {
          return Optional.some(el);
        } else if (stop2(el)) {
          break;
        }
      }
      return Optional.none();
    };
    const closest$4 = (scope, predicate, isRoot2) => {
      const is2 = (s, test) => test(s);
      return ClosestOrAncestor(is2, ancestor$3, scope, predicate, isRoot2);
    };
    const sibling$1 = (scope, predicate) => {
      const element = scope.dom;
      if (!element.parentNode) {
        return Optional.none();
      }
      return child(SugarElement.fromDom(element.parentNode), (x) => !eq(scope, x) && predicate(x));
    };
    const child = (scope, predicate) => {
      const pred = (node) => predicate(SugarElement.fromDom(node));
      const result = find$2(scope.dom.childNodes, pred);
      return result.map(SugarElement.fromDom);
    };
    const descendant$1 = (scope, predicate) => {
      const descend2 = (node) => {
        for (let i = 0; i < node.childNodes.length; i++) {
          const child2 = SugarElement.fromDom(node.childNodes[i]);
          if (predicate(child2)) {
            return Optional.some(child2);
          }
          const res = descend2(node.childNodes[i]);
          if (res.isSome()) {
            return res;
          }
        }
        return Optional.none();
      };
      return descend2(scope.dom);
    };
    const ancestor$2 = (scope, selector, isRoot2) => ancestor$3(scope, (e) => is$1(e, selector), isRoot2);
    const descendant = (scope, selector) => one(selector, scope);
    const closest$3 = (scope, selector, isRoot2) => {
      const is2 = (element, selector2) => is$1(element, selector2);
      return ClosestOrAncestor(is2, ancestor$2, scope, selector, isRoot2);
    };
    const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
      let idCount = 0;
      const loadedStates = {};
      const edos = SugarElement.fromDom(documentOrShadowRoot);
      const doc = documentOrOwner(edos);
      const maxLoadTime = settings.maxLoadTime || 5e3;
      const _setReferrerPolicy = (referrerPolicy) => {
        settings.referrerPolicy = referrerPolicy;
      };
      const addStyle = (element) => {
        append$1(getStyleContainer(edos), element);
      };
      const removeStyle = (id) => {
        const styleContainer = getStyleContainer(edos);
        descendant(styleContainer, "#" + id).each(remove$6);
      };
      const getOrCreateState = (url) => get$a(loadedStates, url).getOrThunk(() => ({
        id: "mce-u" + idCount++,
        passed: [],
        failed: [],
        count: 0
      }));
      const load = (url) => new Promise((success, failure) => {
        let link;
        const urlWithSuffix = Tools._addCacheSuffix(url);
        const state = getOrCreateState(urlWithSuffix);
        loadedStates[urlWithSuffix] = state;
        state.count++;
        const resolve2 = (callbacks, status) => {
          each$f(callbacks, call);
          state.status = status;
          state.passed = [];
          state.failed = [];
          if (link) {
            link.onload = null;
            link.onerror = null;
            link = null;
          }
        };
        const passed = () => resolve2(state.passed, 2);
        const failed = () => resolve2(state.failed, 3);
        const wait = (testCallback, waitCallback) => {
          if (!testCallback()) {
            if (Date.now() - startTime < maxLoadTime) {
              setTimeout(waitCallback);
            } else {
              failed();
            }
          }
        };
        const waitForWebKitLinkLoaded = () => {
          wait(() => {
            const styleSheets = documentOrShadowRoot.styleSheets;
            let i = styleSheets.length;
            while (i--) {
              const styleSheet = styleSheets[i];
              const owner2 = styleSheet.ownerNode;
              if (owner2 && owner2.id === link.id) {
                passed();
                return true;
              }
            }
            return false;
          }, waitForWebKitLinkLoaded);
        };
        if (success) {
          state.passed.push(success);
        }
        if (failure) {
          state.failed.push(failure);
        }
        if (state.status === 1) {
          return;
        }
        if (state.status === 2) {
          passed();
          return;
        }
        if (state.status === 3) {
          failed();
          return;
        }
        state.status = 1;
        const linkElem = SugarElement.fromTag("link", doc.dom);
        setAll$1(linkElem, {
          rel: "stylesheet",
          type: "text/css",
          id: state.id
        });
        const startTime = Date.now();
        if (settings.contentCssCors) {
          set$2(linkElem, "crossOrigin", "anonymous");
        }
        if (settings.referrerPolicy) {
          set$2(linkElem, "referrerpolicy", settings.referrerPolicy);
        }
        link = linkElem.dom;
        link.onload = waitForWebKitLinkLoaded;
        link.onerror = failed;
        addStyle(linkElem);
        set$2(linkElem, "href", urlWithSuffix);
      });
      const loadAll = (urls) => {
        const loadedUrls = Promise.allSettled(map$3(urls, (url) => load(url).then(constant(url))));
        return loadedUrls.then((results) => {
          const parts = partition$2(results, (r2) => r2.status === "fulfilled");
          if (parts.fail.length > 0) {
            return Promise.reject(map$3(parts.fail, (result) => result.reason));
          } else {
            return map$3(parts.pass, (result) => result.value);
          }
        });
      };
      const unload = (url) => {
        const urlWithSuffix = Tools._addCacheSuffix(url);
        get$a(loadedStates, urlWithSuffix).each((state) => {
          const count2 = --state.count;
          if (count2 === 0) {
            delete loadedStates[urlWithSuffix];
            removeStyle(state.id);
          }
        });
      };
      const unloadAll = (urls) => {
        each$f(urls, (url) => {
          unload(url);
        });
      };
      return {
        load,
        loadAll,
        unload,
        unloadAll,
        _setReferrerPolicy
      };
    };
    const create$d = () => {
      const map2 = /* @__PURE__ */ new WeakMap();
      const forElement = (referenceElement, settings) => {
        const root = getRootNode(referenceElement);
        const rootDom = root.dom;
        return Optional.from(map2.get(rootDom)).getOrThunk(() => {
          const sl = StyleSheetLoader(rootDom, settings);
          map2.set(rootDom, sl);
          return sl;
        });
      };
      return { forElement };
    };
    const instance = create$d();
    class DomTreeWalker {
      constructor(startNode, rootNode) {
        this.node = startNode;
        this.rootNode = rootNode;
        this.current = this.current.bind(this);
        this.next = this.next.bind(this);
        this.prev = this.prev.bind(this);
        this.prev2 = this.prev2.bind(this);
      }
      current() {
        return this.node;
      }
      next(shallow2) {
        this.node = this.findSibling(this.node, "firstChild", "nextSibling", shallow2);
        return this.node;
      }
      prev(shallow2) {
        this.node = this.findSibling(this.node, "lastChild", "previousSibling", shallow2);
        return this.node;
      }
      prev2(shallow2) {
        this.node = this.findPreviousNode(this.node, shallow2);
        return this.node;
      }
      findSibling(node, startName, siblingName, shallow2) {
        let sibling2, parent2;
        if (node) {
          if (!shallow2 && node[startName]) {
            return node[startName];
          }
          if (node !== this.rootNode) {
            sibling2 = node[siblingName];
            if (sibling2) {
              return sibling2;
            }
            for (parent2 = node.parentNode; parent2 && parent2 !== this.rootNode; parent2 = parent2.parentNode) {
              sibling2 = parent2[siblingName];
              if (sibling2) {
                return sibling2;
              }
            }
          }
        }
      }
      findPreviousNode(node, shallow2) {
        let sibling2, parent2, child2;
        if (node) {
          sibling2 = node.previousSibling;
          if (this.rootNode && sibling2 === this.rootNode) {
            return;
          }
          if (sibling2) {
            if (!shallow2) {
              for (child2 = sibling2.lastChild; child2; child2 = child2.lastChild) {
                if (!child2.lastChild) {
                  return child2;
                }
              }
            }
            return sibling2;
          }
          parent2 = node.parentNode;
          if (parent2 && parent2 !== this.rootNode) {
            return parent2;
          }
        }
      }
    }
    const blocks = [
      "article",
      "aside",
      "details",
      "div",
      "dt",
      "figcaption",
      "footer",
      "form",
      "fieldset",
      "header",
      "hgroup",
      "html",
      "main",
      "nav",
      "section",
      "summary",
      "body",
      "p",
      "dl",
      "multicol",
      "dd",
      "figure",
      "address",
      "center",
      "blockquote",
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6",
      "listing",
      "xmp",
      "pre",
      "plaintext",
      "menu",
      "dir",
      "ul",
      "ol",
      "li",
      "hr",
      "table",
      "tbody",
      "thead",
      "tfoot",
      "th",
      "tr",
      "td",
      "caption"
    ];
    const tableCells = [
      "td",
      "th"
    ];
    const tableSections = [
      "thead",
      "tbody",
      "tfoot"
    ];
    const textBlocks = [
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6",
      "p",
      "div",
      "address",
      "pre",
      "form",
      "blockquote",
      "center",
      "dir",
      "fieldset",
      "header",
      "footer",
      "article",
      "section",
      "hgroup",
      "aside",
      "nav",
      "figure"
    ];
    const headings = [
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6"
    ];
    const listItems$1 = [
      "li",
      "dd",
      "dt"
    ];
    const lists = [
      "ul",
      "ol",
      "dl"
    ];
    const wsElements = [
      "pre",
      "script",
      "textarea",
      "style"
    ];
    const wrapBlockElements = ["pre"].concat(headings);
    const lazyLookup = (items) => {
      let lookup2;
      return (node) => {
        lookup2 = lookup2 ? lookup2 : mapToObject(items, always);
        return has$2(lookup2, name(node));
      };
    };
    const isBlock$2 = lazyLookup(blocks);
    const isTable$2 = (node) => name(node) === "table";
    const isInline$1 = (node) => isElement$7(node) && !isBlock$2(node);
    const isBr$5 = (node) => isElement$7(node) && name(node) === "br";
    const isTextBlock$2 = lazyLookup(textBlocks);
    const isList = lazyLookup(lists);
    const isListItem = lazyLookup(listItems$1);
    const isTableSection = lazyLookup(tableSections);
    const isTableCell$4 = lazyLookup(tableCells);
    const isWsPreserveElement = lazyLookup(wsElements);
    const isWrapBlockElement = lazyLookup(wrapBlockElements);
    const isWrapElement = (node) => isWrapBlockElement(node) || isInline$1(node);
    const ancestor$1 = (scope, selector, isRoot2) => ancestor$2(scope, selector, isRoot2).isSome();
    const zeroWidth = "\uFEFF";
    const nbsp = "\xA0";
    const isZwsp$1 = (char) => char === zeroWidth;
    const removeZwsp = (s) => s.replace(/\uFEFF/g, "");
    const ZWSP$1 = zeroWidth;
    const isZwsp = isZwsp$1;
    const trim$1 = removeZwsp;
    const isElement$5 = isElement$6;
    const isText$8 = isText$9;
    const isCaretContainerBlock$1 = (node) => {
      if (isText$8(node)) {
        node = node.parentNode;
      }
      return isElement$5(node) && node.hasAttribute("data-mce-caret");
    };
    const isCaretContainerInline = (node) => isText$8(node) && isZwsp(node.data);
    const isCaretContainer$2 = (node) => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
    const hasContent = (node) => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
    const insertInline$1 = (node, before2) => {
      const doc = node.ownerDocument;
      const textNode = doc.createTextNode(ZWSP$1);
      const parentNode = node.parentNode;
      if (!before2) {
        const sibling2 = node.nextSibling;
        if (isText$8(sibling2)) {
          if (isCaretContainer$2(sibling2)) {
            return sibling2;
          }
          if (startsWithCaretContainer$1(sibling2)) {
            sibling2.splitText(1);
            return sibling2;
          }
        }
        if (node.nextSibling) {
          parentNode.insertBefore(textNode, node.nextSibling);
        } else {
          parentNode.appendChild(textNode);
        }
      } else {
        const sibling2 = node.previousSibling;
        if (isText$8(sibling2)) {
          if (isCaretContainer$2(sibling2)) {
            return sibling2;
          }
          if (endsWithCaretContainer$1(sibling2)) {
            return sibling2.splitText(sibling2.data.length - 1);
          }
        }
        parentNode.insertBefore(textNode, node);
      }
      return textNode;
    };
    const isBeforeInline = (pos) => {
      const container = pos.container();
      if (!isText$9(container)) {
        return false;
      }
      return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
    };
    const isAfterInline = (pos) => {
      const container = pos.container();
      if (!isText$9(container)) {
        return false;
      }
      return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
    };
    const createBogusBr = () => {
      const br = document.createElement("br");
      br.setAttribute("data-mce-bogus", "1");
      return br;
    };
    const insertBlock = (blockName, node, before2) => {
      const doc = node.ownerDocument;
      const blockNode = doc.createElement(blockName);
      blockNode.setAttribute("data-mce-caret", before2 ? "before" : "after");
      blockNode.setAttribute("data-mce-bogus", "all");
      blockNode.appendChild(createBogusBr());
      const parentNode = node.parentNode;
      if (!before2) {
        if (node.nextSibling) {
          parentNode.insertBefore(blockNode, node.nextSibling);
        } else {
          parentNode.appendChild(blockNode);
        }
      } else {
        parentNode.insertBefore(blockNode, node);
      }
      return blockNode;
    };
    const startsWithCaretContainer$1 = (node) => isText$8(node) && node.data[0] === ZWSP$1;
    const endsWithCaretContainer$1 = (node) => isText$8(node) && node.data[node.data.length - 1] === ZWSP$1;
    const trimBogusBr = (elm) => {
      const brs = elm.getElementsByTagName("br");
      const lastBr = brs[brs.length - 1];
      if (isBogus$2(lastBr)) {
        lastBr.parentNode.removeChild(lastBr);
      }
    };
    const showCaretContainerBlock = (caretContainer) => {
      if (caretContainer && caretContainer.hasAttribute("data-mce-caret")) {
        trimBogusBr(caretContainer);
        caretContainer.removeAttribute("data-mce-caret");
        caretContainer.removeAttribute("data-mce-bogus");
        caretContainer.removeAttribute("style");
        caretContainer.removeAttribute("data-mce-style");
        caretContainer.removeAttribute("_moz_abspos");
        return caretContainer;
      }
      return null;
    };
    const isRangeInCaretContainerBlock = (range2) => isCaretContainerBlock$1(range2.startContainer);
    const isContentEditableTrue$4 = isContentEditableTrue$5;
    const isContentEditableFalse$a = isContentEditableFalse$b;
    const isBr$4 = isBr$6;
    const isText$7 = isText$9;
    const isInvalidTextElement = matchNodeNames([
      "script",
      "style",
      "textarea"
    ]);
    const isAtomicInline = matchNodeNames([
      "img",
      "input",
      "textarea",
      "hr",
      "iframe",
      "video",
      "audio",
      "object",
      "embed"
    ]);
    const isTable$1 = matchNodeNames(["table"]);
    const isCaretContainer$1 = isCaretContainer$2;
    const isCaretCandidate$3 = (node) => {
      if (isCaretContainer$1(node)) {
        return false;
      }
      if (isText$7(node)) {
        return !isInvalidTextElement(node.parentNode);
      }
      return isAtomicInline(node) || isBr$4(node) || isTable$1(node) || isNonUiContentEditableFalse(node);
    };
    const isUnselectable = (node) => isElement$6(node) && node.getAttribute("unselectable") === "true";
    const isNonUiContentEditableFalse = (node) => isUnselectable(node) === false && isContentEditableFalse$a(node);
    const isInEditable = (node, root) => {
      for (node = node.parentNode; node && node !== root; node = node.parentNode) {
        if (isNonUiContentEditableFalse(node)) {
          return false;
        }
        if (isContentEditableTrue$4(node)) {
          return true;
        }
      }
      return true;
    };
    const isAtomicContentEditableFalse = (node) => {
      if (!isNonUiContentEditableFalse(node)) {
        return false;
      }
      return foldl(from(node.getElementsByTagName("*")), (result, elm) => {
        return result || isContentEditableTrue$4(elm);
      }, false) !== true;
    };
    const isAtomic$1 = (node) => isAtomicInline(node) || isAtomicContentEditableFalse(node);
    const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
    const whiteSpaceRegExp = /^[ \t\r\n]*$/;
    const isWhitespaceText = (text2) => whiteSpaceRegExp.test(text2);
    const isCollapsibleWhitespace$1 = (c) => " \f	\v".indexOf(c) !== -1;
    const isNewLineChar = (c) => c === "\n" || c === "\r";
    const isNewline = (text2, idx) => idx < text2.length && idx >= 0 ? isNewLineChar(text2[idx]) : false;
    const normalize$4 = (text2, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
      const tabSpace = repeat(" ", tabSpaces);
      const normalizedText = text2.replace(/\t/g, tabSpace);
      const result = foldl(normalizedText, (acc, c) => {
        if (isCollapsibleWhitespace$1(c) || c === nbsp) {
          if (acc.pcIsSpace || acc.str === "" && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
            return {
              pcIsSpace: false,
              str: acc.str + nbsp
            };
          } else {
            return {
              pcIsSpace: true,
              str: acc.str + " "
            };
          }
        } else {
          return {
            pcIsSpace: isNewLineChar(c),
            str: acc.str + c
          };
        }
      }, {
        pcIsSpace: false,
        str: ""
      });
      return result.str;
    };
    const hasWhitespacePreserveParent = (node, rootNode) => {
      const rootElement = SugarElement.fromDom(rootNode);
      const startNode = SugarElement.fromDom(node);
      return ancestor$1(startNode, "pre,code", curry(eq, rootElement));
    };
    const isWhitespace$1 = (node, rootNode) => {
      return isText$9(node) && isWhitespaceText(node.data) && hasWhitespacePreserveParent(node, rootNode) === false;
    };
    const isNamedAnchor = (node) => {
      return isElement$6(node) && node.nodeName === "A" && !node.hasAttribute("href") && (node.hasAttribute("name") || node.hasAttribute("id"));
    };
    const isContent$1 = (node, rootNode) => {
      return isCaretCandidate$3(node) && isWhitespace$1(node, rootNode) === false || isNamedAnchor(node) || isBookmark(node);
    };
    const isBookmark = hasAttribute("data-mce-bookmark");
    const isBogus$1 = hasAttribute("data-mce-bogus");
    const isBogusAll = hasAttributeValue("data-mce-bogus", "all");
    const isEmptyNode = (targetNode, skipBogus) => {
      let brCount = 0;
      if (isContent$1(targetNode, targetNode)) {
        return false;
      } else {
        let node = targetNode.firstChild;
        if (!node) {
          return true;
        }
        const walker = new DomTreeWalker(node, targetNode);
        do {
          if (skipBogus) {
            if (isBogusAll(node)) {
              node = walker.next(true);
              continue;
            }
            if (isBogus$1(node)) {
              node = walker.next();
              continue;
            }
          }
          if (isBr$6(node)) {
            brCount++;
            node = walker.next();
            continue;
          }
          if (isContent$1(node, targetNode)) {
            return false;
          }
          node = walker.next();
        } while (node);
        return brCount <= 1;
      }
    };
    const isEmpty$2 = (elm, skipBogus = true) => isEmptyNode(elm.dom, skipBogus);
    const isSpan = (node) => node.nodeName.toLowerCase() === "span";
    const isInlineContent = (node, root) => isNonNullable(node) && (isContent$1(node, root) || isInline$1(SugarElement.fromDom(node)));
    const surroundedByInlineContent = (node, root) => {
      const prev2 = new DomTreeWalker(node, root).prev(false);
      const next2 = new DomTreeWalker(node, root).next(false);
      const prevIsInline = isUndefined(prev2) || isInlineContent(prev2, root);
      const nextIsInline = isUndefined(next2) || isInlineContent(next2, root);
      return prevIsInline && nextIsInline;
    };
    const isBookmarkNode$2 = (node) => isSpan(node) && node.getAttribute("data-mce-type") === "bookmark";
    const isKeepTextNode = (node, root) => isText$9(node) && node.data.length > 0 && surroundedByInlineContent(node, root);
    const isKeepElement = (node) => isElement$6(node) ? node.childNodes.length > 0 : false;
    const isDocument = (node) => isDocumentFragment(node) || isDocument$1(node);
    const trimNode = (dom2, node, root) => {
      const rootNode = root || node;
      if (isElement$6(node) && isBookmarkNode$2(node)) {
        return node;
      }
      const children2 = node.childNodes;
      for (let i = children2.length - 1; i >= 0; i--) {
        trimNode(dom2, children2[i], rootNode);
      }
      if (isElement$6(node)) {
        const currentChildren = node.childNodes;
        if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
          node.parentNode.insertBefore(currentChildren[0], node);
        }
      }
      if (!isDocument(node) && !isContent$1(node, rootNode) && !isKeepElement(node) && !isKeepTextNode(node, rootNode)) {
        dom2.remove(node);
      }
      return node;
    };
    const makeMap$3 = Tools.makeMap;
    const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
    const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
    const rawCharsRegExp = /[<>&\"\']/g;
    const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
    const asciiMap = {
      128: "\u20AC",
      130: "\u201A",
      131: "\u0192",
      132: "\u201E",
      133: "\u2026",
      134: "\u2020",
      135: "\u2021",
      136: "\u02C6",
      137: "\u2030",
      138: "\u0160",
      139: "\u2039",
      140: "\u0152",
      142: "\u017D",
      145: "\u2018",
      146: "\u2019",
      147: "\u201C",
      148: "\u201D",
      149: "\u2022",
      150: "\u2013",
      151: "\u2014",
      152: "\u02DC",
      153: "\u2122",
      154: "\u0161",
      155: "\u203A",
      156: "\u0153",
      158: "\u017E",
      159: "\u0178"
    };
    const baseEntities = {
      '"': "&quot;",
      "'": "&#39;",
      "<": "&lt;",
      ">": "&gt;",
      "&": "&amp;",
      "`": "&#96;"
    };
    const reverseEntities = {
      "&lt;": "<",
      "&gt;": ">",
      "&amp;": "&",
      "&quot;": '"',
      "&apos;": `'`
    };
    const nativeDecode = (text2) => {
      const elm = SugarElement.fromTag("div").dom;
      elm.innerHTML = text2;
      return elm.textContent || elm.innerText || text2;
    };
    const buildEntitiesLookup = (items, radix) => {
      let i, chr, entity;
      const lookup2 = {};
      if (items) {
        items = items.split(",");
        radix = radix || 10;
        for (i = 0; i < items.length; i += 2) {
          chr = String.fromCharCode(parseInt(items[i], radix));
          if (!baseEntities[chr]) {
            entity = "&" + items[i + 1] + ";";
            lookup2[chr] = entity;
            lookup2[entity] = chr;
          }
        }
        return lookup2;
      }
    };
    const namedEntities = buildEntitiesLookup("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro", 32);
    const encodeRaw = (text2, attr) => text2.replace(attr ? attrsCharsRegExp : textCharsRegExp, (chr) => {
      return baseEntities[chr] || chr;
    });
    const encodeAllRaw = (text2) => ("" + text2).replace(rawCharsRegExp, (chr) => {
      return baseEntities[chr] || chr;
    });
    const encodeNumeric = (text2, attr) => text2.replace(attr ? attrsCharsRegExp : textCharsRegExp, (chr) => {
      if (chr.length > 1) {
        return "&#" + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ";";
      }
      return baseEntities[chr] || "&#" + chr.charCodeAt(0) + ";";
    });
    const encodeNamed = (text2, attr, entities) => {
      entities = entities || namedEntities;
      return text2.replace(attr ? attrsCharsRegExp : textCharsRegExp, (chr) => {
        return baseEntities[chr] || entities[chr] || chr;
      });
    };
    const getEncodeFunc = (name2, entities) => {
      const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
      const encodeNamedAndNumeric = (text2, attr) => text2.replace(attr ? attrsCharsRegExp : textCharsRegExp, (chr) => {
        if (baseEntities[chr] !== void 0) {
          return baseEntities[chr];
        }
        if (entitiesMap[chr] !== void 0) {
          return entitiesMap[chr];
        }
        if (chr.length > 1) {
          return "&#" + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ";";
        }
        return "&#" + chr.charCodeAt(0) + ";";
      });
      const encodeCustomNamed = (text2, attr) => {
        return encodeNamed(text2, attr, entitiesMap);
      };
      const nameMap = makeMap$3(name2.replace(/\+/g, ","));
      if (nameMap.named && nameMap.numeric) {
        return encodeNamedAndNumeric;
      }
      if (nameMap.named) {
        if (entities) {
          return encodeCustomNamed;
        }
        return encodeNamed;
      }
      if (nameMap.numeric) {
        return encodeNumeric;
      }
      return encodeRaw;
    };
    const decode = (text2) => text2.replace(entityRegExp, (all2, numeric) => {
      if (numeric) {
        if (numeric.charAt(0).toLowerCase() === "x") {
          numeric = parseInt(numeric.substr(1), 16);
        } else {
          numeric = parseInt(numeric, 10);
        }
        if (numeric > 65535) {
          numeric -= 65536;
          return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
        }
        return asciiMap[numeric] || String.fromCharCode(numeric);
      }
      return reverseEntities[all2] || namedEntities[all2] || nativeDecode(all2);
    });
    const Entities = {
      encodeRaw,
      encodeAllRaw,
      encodeNumeric,
      encodeNamed,
      getEncodeFunc,
      decode
    };
    const mapCache = {}, dummyObj = {};
    const makeMap$2 = Tools.makeMap, each$c = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode, inArray = Tools.inArray;
    const split$1 = (items, delim) => {
      items = Tools.trim(items);
      return items ? items.split(delim || " ") : [];
    };
    const createMap = (defaultValue, extendWith) => {
      const value2 = makeMap$2(defaultValue, " ", makeMap$2(defaultValue.toUpperCase(), " "));
      return extend$2(value2, extendWith);
    };
    const getTextRootBlockElements = (schema) => createMap("td th li dt dd figcaption caption details summary", schema.getTextBlockElements());
    const compileSchema = (type2) => {
      const schema = {};
      let globalAttributes, blockContent;
      let phrasingContent, flowContent, html4BlockContent, html4PhrasingContent;
      const add2 = (name2, attributes = "", children2 = "") => {
        const childNames = split$1(children2);
        const names = split$1(name2);
        let ni = names.length;
        while (ni--) {
          const attributesOrder = split$1([
            globalAttributes,
            attributes
          ].join(" "));
          schema[names[ni]] = {
            attributes: mapToObject(attributesOrder, () => ({})),
            attributesOrder,
            children: mapToObject(childNames, constant(dummyObj))
          };
        }
      };
      const addAttrs = (name2, attributes) => {
        const names = split$1(name2);
        const attrs = split$1(attributes);
        let ni = names.length;
        while (ni--) {
          const schemaItem = schema[names[ni]];
          for (let i = 0, l = attrs.length; i < l; i++) {
            schemaItem.attributes[attrs[i]] = {};
            schemaItem.attributesOrder.push(attrs[i]);
          }
        }
      };
      if (mapCache[type2]) {
        return mapCache[type2];
      }
      globalAttributes = "id accesskey class dir lang style tabindex title role";
      blockContent = "address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul";
      phrasingContent = "a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment";
      if (type2 !== "html4") {
        globalAttributes += " contenteditable contextmenu draggable dropzone hidden spellcheck translate";
        blockContent += " article aside details dialog figure main header footer hgroup section nav";
        phrasingContent += " audio canvas command datalist mark meter output picture progress time wbr video ruby bdi keygen";
      }
      if (type2 !== "html5-strict") {
        globalAttributes += " xml:lang";
        html4PhrasingContent = "acronym applet basefont big font strike tt";
        phrasingContent = [
          phrasingContent,
          html4PhrasingContent
        ].join(" ");
        each$c(split$1(html4PhrasingContent), (name2) => {
          add2(name2, "", phrasingContent);
        });
        html4BlockContent = "center dir isindex noframes";
        blockContent = [
          blockContent,
          html4BlockContent
        ].join(" ");
        flowContent = [
          blockContent,
          phrasingContent
        ].join(" ");
        each$c(split$1(html4BlockContent), (name2) => {
          add2(name2, "", flowContent);
        });
      }
      flowContent = flowContent || [
        blockContent,
        phrasingContent
      ].join(" ");
      add2("html", "manifest", "head body");
      add2("head", "", "base command link meta noscript script style title");
      add2("title hr noscript br");
      add2("base", "href target");
      add2("link", "href rel media hreflang type sizes hreflang");
      add2("meta", "name http-equiv content charset");
      add2("style", "media type scoped");
      add2("script", "src async defer type charset");
      add2("body", "onafterprint onbeforeprint onbeforeunload onblur onerror onfocus onhashchange onload onmessage onoffline ononline onpagehide onpageshow onpopstate onresize onscroll onstorage onunload", flowContent);
      add2("address dt dd div caption", "", flowContent);
      add2("h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn", "", phrasingContent);
      add2("blockquote", "cite", flowContent);
      add2("ol", "reversed start type", "li");
      add2("ul", "", "li");
      add2("li", "value", flowContent);
      add2("dl", "", "dt dd");
      add2("a", "href target rel media hreflang type", phrasingContent);
      add2("q", "cite", phrasingContent);
      add2("ins del", "cite datetime", flowContent);
      add2("img", "src sizes srcset alt usemap ismap width height");
      add2("iframe", "src name width height", flowContent);
      add2("embed", "src type width height");
      add2("object", "data type typemustmatch name usemap form width height", [
        flowContent,
        "param"
      ].join(" "));
      add2("param", "name value");
      add2("map", "name", [
        flowContent,
        "area"
      ].join(" "));
      add2("area", "alt coords shape href target rel media hreflang type");
      add2("table", "border", "caption colgroup thead tfoot tbody tr" + (type2 === "html4" ? " col" : ""));
      add2("colgroup", "span", "col");
      add2("col", "span");
      add2("tbody thead tfoot", "", "tr");
      add2("tr", "", "td th");
      add2("td", "colspan rowspan headers", flowContent);
      add2("th", "colspan rowspan headers scope abbr", flowContent);
      add2("form", "accept-charset action autocomplete enctype method name novalidate target", flowContent);
      add2("fieldset", "disabled form name", [
        flowContent,
        "legend"
      ].join(" "));
      add2("label", "form for", phrasingContent);
      add2("input", "accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate formtarget height list max maxlength min multiple name pattern readonly required size src step type value width");
      add2("button", "disabled form formaction formenctype formmethod formnovalidate formtarget name type value", type2 === "html4" ? flowContent : phrasingContent);
      add2("select", "disabled form multiple name required size", "option optgroup");
      add2("optgroup", "disabled label", "option");
      add2("option", "disabled label selected value");
      add2("textarea", "cols dirname disabled form maxlength name readonly required rows wrap");
      add2("menu", "type label", [
        flowContent,
        "li"
      ].join(" "));
      add2("noscript", "", flowContent);
      if (type2 !== "html4") {
        add2("wbr");
        add2("ruby", "", [
          phrasingContent,
          "rt rp"
        ].join(" "));
        add2("figcaption", "", flowContent);
        add2("mark rt rp summary bdi", "", phrasingContent);
        add2("canvas", "width height", flowContent);
        add2("video", "src crossorigin poster preload autoplay mediagroup loop muted controls width height buffered", [
          flowContent,
          "track source"
        ].join(" "));
        add2("audio", "src crossorigin preload autoplay mediagroup loop muted controls buffered volume", [
          flowContent,
          "track source"
        ].join(" "));
        add2("picture", "", "img source");
        add2("source", "src srcset type media sizes");
        add2("track", "kind src srclang label default");
        add2("datalist", "", [
          phrasingContent,
          "option"
        ].join(" "));
        add2("article section nav aside main header footer", "", flowContent);
        add2("hgroup", "", "h1 h2 h3 h4 h5 h6");
        add2("figure", "", [
          flowContent,
          "figcaption"
        ].join(" "));
        add2("time", "datetime", phrasingContent);
        add2("dialog", "open", flowContent);
        add2("command", "type label icon disabled checked radiogroup command");
        add2("output", "for form name", phrasingContent);
        add2("progress", "value max", phrasingContent);
        add2("meter", "value min max low high optimum", phrasingContent);
        add2("details", "open", [
          flowContent,
          "summary"
        ].join(" "));
        add2("keygen", "autofocus challenge disabled form keytype name");
      }
      if (type2 !== "html5-strict") {
        addAttrs("script", "language xml:space");
        addAttrs("style", "xml:space");
        addAttrs("object", "declare classid code codebase codetype archive standby align border hspace vspace");
        addAttrs("embed", "align name hspace vspace");
        addAttrs("param", "valuetype type");
        addAttrs("a", "charset name rev shape coords");
        addAttrs("br", "clear");
        addAttrs("applet", "codebase archive code object alt name width height align hspace vspace");
        addAttrs("img", "name longdesc align border hspace vspace");
        addAttrs("iframe", "longdesc frameborder marginwidth marginheight scrolling align");
        addAttrs("font basefont", "size color face");
        addAttrs("input", "usemap align");
        addAttrs("select");
        addAttrs("textarea");
        addAttrs("h1 h2 h3 h4 h5 h6 div p legend caption", "align");
        addAttrs("ul", "type compact");
        addAttrs("li", "type");
        addAttrs("ol dl menu dir", "compact");
        addAttrs("pre", "width xml:space");
        addAttrs("hr", "align noshade size width");
        addAttrs("isindex", "prompt");
        addAttrs("table", "summary width frame rules cellspacing cellpadding align bgcolor");
        addAttrs("col", "width align char charoff valign");
        addAttrs("colgroup", "width align char charoff valign");
        addAttrs("thead", "align char charoff valign");
        addAttrs("tr", "align char charoff valign bgcolor");
        addAttrs("th", "axis align char charoff valign nowrap bgcolor width height");
        addAttrs("form", "accept");
        addAttrs("td", "abbr axis scope align char charoff valign nowrap bgcolor width height");
        addAttrs("tfoot", "align char charoff valign");
        addAttrs("tbody", "align char charoff valign");
        addAttrs("area", "nohref");
        addAttrs("body", "background bgcolor text link vlink alink");
      }
      if (type2 !== "html4") {
        addAttrs("input button select textarea", "autofocus");
        addAttrs("input textarea", "placeholder");
        addAttrs("a", "download");
        addAttrs("link script img", "crossorigin");
        addAttrs("img", "loading");
        addAttrs("iframe", "sandbox seamless allowfullscreen loading");
      }
      if (type2 !== "html4") {
        each$f([
          schema.video,
          schema.audio
        ], (item) => {
          delete item.children.audio;
          delete item.children.video;
        });
      }
      each$c(split$1("a form meter progress dfn"), (name2) => {
        if (schema[name2]) {
          delete schema[name2].children[name2];
        }
      });
      delete schema.caption.children.table;
      delete schema.script;
      mapCache[type2] = schema;
      return schema;
    };
    const compileElementMap = (value2, mode) => {
      let styles;
      if (value2) {
        styles = {};
        if (typeof value2 === "string") {
          value2 = { "*": value2 };
        }
        each$c(value2, (value3, key) => {
          styles[key] = styles[key.toUpperCase()] = mode === "map" ? makeMap$2(value3, /[, ]/) : explode$2(value3, /[, ]/);
        });
      }
      return styles;
    };
    const Schema = (settings) => {
      var _a;
      const elements = {};
      const children2 = {};
      let patternElements = [];
      const customElementsMap = {}, specialElements = {};
      const createLookupTable = (option2, defaultValue, extendWith) => {
        let value2 = settings[option2];
        if (!value2) {
          value2 = mapCache[option2];
          if (!value2) {
            value2 = createMap(defaultValue, extendWith);
            mapCache[option2] = value2;
          }
        } else {
          value2 = makeMap$2(value2, /[, ]/, makeMap$2(value2.toUpperCase(), /[, ]/));
        }
        return value2;
      };
      settings = settings || {};
      const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : "html5";
      const schemaItems = compileSchema(schemaType);
      if (settings.verify_html === false) {
        settings.valid_elements = "*[*]";
      }
      const validStyles = compileElementMap(settings.valid_styles);
      const invalidStyles = compileElementMap(settings.invalid_styles, "map");
      const validClasses = compileElementMap(settings.valid_classes, "map");
      const whitespaceElementsMap = createLookupTable("whitespace_elements", "pre script noscript style textarea video audio iframe object code");
      const selfClosingElementsMap = createLookupTable("self_closing_elements", "colgroup dd dt li option p td tfoot th thead tr");
      const voidElementsMap = createLookupTable("void_elements", "area base basefont br col frame hr img input isindex link meta param embed source wbr track");
      const boolAttrMap = createLookupTable("boolean_attributes", "checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls allowfullscreen");
      const nonEmptyOrMoveCaretBeforeOnEnter = "td th iframe video audio object script code";
      const nonEmptyElementsMap = createLookupTable("non_empty_elements", nonEmptyOrMoveCaretBeforeOnEnter + " pre", voidElementsMap);
      const moveCaretBeforeOnEnterElementsMap = createLookupTable("move_caret_before_on_enter_elements", nonEmptyOrMoveCaretBeforeOnEnter + " table", voidElementsMap);
      const textBlockElementsMap = createLookupTable("text_block_elements", "h1 h2 h3 h4 h5 h6 p div address pre form blockquote center dir fieldset header footer article section hgroup aside main nav figure");
      const blockElementsMap = createLookupTable("block_elements", "hr table tbody thead tfoot th tr td li ol ul caption dl dt dd noscript menu isindex option datalist select optgroup figcaption details summary", textBlockElementsMap);
      const textInlineElementsMap = createLookupTable("text_inline_elements", "span strong b em i font s strike u var cite dfn code mark q sup sub samp");
      each$c("script noscript iframe noframes noembed title style textarea xmp plaintext".split(" "), (name2) => {
        specialElements[name2] = new RegExp("</" + name2 + "[^>]*>", "gi");
      });
      const patternToRegExp = (str) => new RegExp("^" + str.replace(/([?+*])/g, ".$1") + "$");
      const addValidElements = (validElements) => {
        let ei, el, ai, al, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder, prefix, outputName, globalAttributes, globalAttributesOrder, value2;
        const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/, attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/, hasPatternsRegExp = /[*?+]/;
        if (validElements) {
          const validElementsArr = split$1(validElements, ",");
          if (elements["@"]) {
            globalAttributes = elements["@"].attributes;
            globalAttributesOrder = elements["@"].attributesOrder;
          }
          for (ei = 0, el = validElementsArr.length; ei < el; ei++) {
            matches = elementRuleRegExp.exec(validElementsArr[ei]);
            if (matches) {
              prefix = matches[1];
              elementName = matches[2];
              outputName = matches[3];
              attrData = matches[5];
              attributes = {};
              attributesOrder = [];
              element = {
                attributes,
                attributesOrder
              };
              if (prefix === "#") {
                element.paddEmpty = true;
              }
              if (prefix === "-") {
                element.removeEmpty = true;
              }
              if (matches[4] === "!") {
                element.removeEmptyAttrs = true;
              }
              if (globalAttributes) {
                each$e(globalAttributes, (value3, key) => {
                  attributes[key] = value3;
                });
                attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
              }
              if (attrData) {
                attrData = split$1(attrData, "|");
                for (ai = 0, al = attrData.length; ai < al; ai++) {
                  matches = attrRuleRegExp.exec(attrData[ai]);
                  if (matches) {
                    attr = {};
                    attrType = matches[1];
                    attrName = matches[2].replace(/[\\:]:/g, ":");
                    prefix = matches[3];
                    value2 = matches[4];
                    if (attrType === "!") {
                      element.attributesRequired = element.attributesRequired || [];
                      element.attributesRequired.push(attrName);
                      attr.required = true;
                    }
                    if (attrType === "-") {
                      delete attributes[attrName];
                      attributesOrder.splice(inArray(attributesOrder, attrName), 1);
                      continue;
                    }
                    if (prefix) {
                      if (prefix === "=") {
                        element.attributesDefault = element.attributesDefault || [];
                        element.attributesDefault.push({
                          name: attrName,
                          value: value2
                        });
                        attr.defaultValue = value2;
                      }
                      if (prefix === "~") {
                        element.attributesForced = element.attributesForced || [];
                        element.attributesForced.push({
                          name: attrName,
                          value: value2
                        });
                        attr.forcedValue = value2;
                      }
                      if (prefix === "<") {
                        attr.validValues = makeMap$2(value2, "?");
                      }
                    }
                    if (hasPatternsRegExp.test(attrName)) {
                      element.attributePatterns = element.attributePatterns || [];
                      attr.pattern = patternToRegExp(attrName);
                      element.attributePatterns.push(attr);
                    } else {
                      if (!attributes[attrName]) {
                        attributesOrder.push(attrName);
                      }
                      attributes[attrName] = attr;
                    }
                  }
                }
              }
              if (!globalAttributes && elementName === "@") {
                globalAttributes = attributes;
                globalAttributesOrder = attributesOrder;
              }
              if (outputName) {
                element.outputName = elementName;
                elements[outputName] = element;
              }
              if (hasPatternsRegExp.test(elementName)) {
                element.pattern = patternToRegExp(elementName);
                patternElements.push(element);
              } else {
                elements[elementName] = element;
              }
            }
          }
        }
      };
      const setValidElements = (validElements) => {
        patternElements = [];
        each$f(keys(elements), (name2) => {
          delete elements[name2];
        });
        addValidElements(validElements);
        each$c(schemaItems, (element, name2) => {
          children2[name2] = element.children;
        });
      };
      const addCustomElements = (customElements) => {
        const customElementRegExp = /^(~)?(.+)$/;
        if (customElements) {
          mapCache.text_block_elements = mapCache.block_elements = null;
          each$c(split$1(customElements, ","), (rule) => {
            const matches = customElementRegExp.exec(rule), inline = matches[1] === "~", cloneName = inline ? "span" : "div", name2 = matches[2];
            children2[name2] = children2[cloneName];
            customElementsMap[name2] = cloneName;
            nonEmptyElementsMap[name2.toUpperCase()] = {};
            nonEmptyElementsMap[name2] = {};
            if (!inline) {
              blockElementsMap[name2.toUpperCase()] = {};
              blockElementsMap[name2] = {};
            }
            if (!elements[name2]) {
              let customRule = elements[cloneName];
              customRule = extend$2({}, customRule);
              delete customRule.removeEmptyAttrs;
              delete customRule.removeEmpty;
              elements[name2] = customRule;
            }
            each$c(children2, (element, elmName) => {
              if (element[cloneName]) {
                children2[elmName] = element = extend$2({}, children2[elmName]);
                element[name2] = element[cloneName];
              }
            });
          });
        }
      };
      const addValidChildren = (validChildren) => {
        const childRuleRegExp = /^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/;
        mapCache[schemaType] = null;
        if (validChildren) {
          each$c(split$1(validChildren, ","), (rule) => {
            const matches = childRuleRegExp.exec(rule);
            let parent2, prefix;
            if (matches) {
              prefix = matches[1];
              if (prefix) {
                parent2 = children2[matches[2]];
              } else {
                parent2 = children2[matches[2]] = { "#comment": {} };
              }
              parent2 = children2[matches[2]];
              each$c(split$1(matches[3], "|"), (child2) => {
                if (prefix === "-") {
                  delete parent2[child2];
                } else {
                  parent2[child2] = {};
                }
              });
            }
          });
        }
      };
      const getElementRule = (name2) => {
        let element = elements[name2], i;
        if (element) {
          return element;
        }
        i = patternElements.length;
        while (i--) {
          element = patternElements[i];
          if (element.pattern.test(name2)) {
            return element;
          }
        }
      };
      if (!settings.valid_elements) {
        each$c(schemaItems, (element, name2) => {
          elements[name2] = {
            attributes: element.attributes,
            attributesOrder: element.attributesOrder
          };
          children2[name2] = element.children;
        });
        each$c(split$1("strong/b em/i"), (item) => {
          const items = split$1(item, "/");
          elements[items[1]].outputName = items[0];
        });
        each$c(textInlineElementsMap, (_val, name2) => {
          if (elements[name2]) {
            if (settings.padd_empty_block_inline_children) {
              elements[name2].paddInEmptyBlock = true;
            }
            elements[name2].removeEmpty = true;
          }
        });
        each$c(split$1("ol ul blockquote a table tbody"), (name2) => {
          if (elements[name2]) {
            elements[name2].removeEmpty = true;
          }
        });
        each$c(split$1("p h1 h2 h3 h4 h5 h6 th td pre div address caption li"), (name2) => {
          elements[name2].paddEmpty = true;
        });
        each$c(split$1("span"), (name2) => {
          elements[name2].removeEmptyAttrs = true;
        });
      } else {
        setValidElements(settings.valid_elements);
      }
      addCustomElements(settings.custom_elements);
      addValidChildren(settings.valid_children);
      addValidElements(settings.extended_valid_elements);
      addValidChildren("+ol[ul|ol],+ul[ul|ol]");
      each$c({
        dd: "dl",
        dt: "dl",
        li: "ul ol",
        td: "tr",
        th: "tr",
        tr: "tbody thead tfoot",
        tbody: "table",
        thead: "table",
        tfoot: "table",
        legend: "fieldset",
        area: "map",
        param: "video audio object"
      }, (parents2, item) => {
        if (elements[item]) {
          elements[item].parentsRequired = split$1(parents2);
        }
      });
      if (settings.invalid_elements) {
        each$c(explode$2(settings.invalid_elements), (item) => {
          if (elements[item]) {
            delete elements[item];
          }
        });
      }
      if (!getElementRule("span")) {
        addValidElements("span[!data-mce-type|*]");
      }
      const getValidStyles = constant(validStyles);
      const getInvalidStyles = constant(invalidStyles);
      const getValidClasses = constant(validClasses);
      const getBoolAttrs = constant(boolAttrMap);
      const getBlockElements = constant(blockElementsMap);
      const getTextBlockElements = constant(textBlockElementsMap);
      const getTextInlineElements = constant(textInlineElementsMap);
      const getVoidElements = constant(Object.seal(voidElementsMap));
      const getSelfClosingElements = constant(selfClosingElementsMap);
      const getNonEmptyElements = constant(nonEmptyElementsMap);
      const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
      const getWhitespaceElements = constant(whitespaceElementsMap);
      const getSpecialElements = constant(Object.seal(specialElements));
      const isValidChild = (name2, child2) => {
        const parent2 = children2[name2.toLowerCase()];
        return !!(parent2 && parent2[child2.toLowerCase()]);
      };
      const isValid2 = (name2, attr) => {
        let attrPatterns, i;
        const rule = getElementRule(name2);
        if (rule) {
          if (attr) {
            if (rule.attributes[attr]) {
              return true;
            }
            attrPatterns = rule.attributePatterns;
            if (attrPatterns) {
              i = attrPatterns.length;
              while (i--) {
                if (attrPatterns[i].pattern.test(attr)) {
                  return true;
                }
              }
            }
          } else {
            return true;
          }
        }
        return false;
      };
      const getCustomElements = constant(customElementsMap);
      return {
        type: schemaType,
        children: children2,
        elements,
        getValidStyles,
        getValidClasses,
        getBlockElements,
        getInvalidStyles,
        getVoidElements,
        getTextBlockElements,
        getTextInlineElements,
        getBoolAttrs,
        getElementRule,
        getSelfClosingElements,
        getNonEmptyElements,
        getMoveCaretBeforeOnEnterElements,
        getWhitespaceElements,
        getSpecialElements,
        isValidChild,
        isValid: isValid2,
        getCustomElements,
        addValidElements,
        setValidElements,
        addCustomElements,
        addValidChildren
      };
    };
    const Styles = (settings, schema) => {
      const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
      const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
      const trimRightRegExp = /\s+$/;
      let i;
      const encodingLookup = {};
      let validStyles;
      let invalidStyles;
      const invisibleChar = zeroWidth;
      settings = settings || {};
      if (schema) {
        validStyles = schema.getValidStyles();
        invalidStyles = schema.getInvalidStyles();
      }
      const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(" ");
      for (i = 0; i < encodingItems.length; i++) {
        encodingLookup[encodingItems[i]] = invisibleChar + i;
        encodingLookup[invisibleChar + i] = encodingItems[i];
      }
      const self = {
        parse: (css) => {
          const styles = {};
          let matches, name2, value2, isEncoded;
          const urlConverter = settings.url_converter;
          const urlConverterScope = settings.url_converter_scope || self;
          const compress = (prefix, suffix, noJoin) => {
            const top = styles[prefix + "-top" + suffix];
            if (!top) {
              return;
            }
            const right = styles[prefix + "-right" + suffix];
            if (!right) {
              return;
            }
            const bottom = styles[prefix + "-bottom" + suffix];
            if (!bottom) {
              return;
            }
            const left = styles[prefix + "-left" + suffix];
            if (!left) {
              return;
            }
            const box = [
              top,
              right,
              bottom,
              left
            ];
            i = box.length - 1;
            while (i--) {
              if (box[i] !== box[i + 1]) {
                break;
              }
            }
            if (i > -1 && noJoin) {
              return;
            }
            styles[prefix + suffix] = i === -1 ? box[0] : box.join(" ");
            delete styles[prefix + "-top" + suffix];
            delete styles[prefix + "-right" + suffix];
            delete styles[prefix + "-bottom" + suffix];
            delete styles[prefix + "-left" + suffix];
          };
          const canCompress = (key) => {
            let value3 = styles[key], i2;
            if (!value3) {
              return;
            }
            value3 = value3.split(" ");
            i2 = value3.length;
            while (i2--) {
              if (value3[i2] !== value3[0]) {
                return false;
              }
            }
            styles[key] = value3[0];
            return true;
          };
          const compress2 = (target, a, b, c) => {
            if (!canCompress(a)) {
              return;
            }
            if (!canCompress(b)) {
              return;
            }
            if (!canCompress(c)) {
              return;
            }
            styles[target] = styles[a] + " " + styles[b] + " " + styles[c];
            delete styles[a];
            delete styles[b];
            delete styles[c];
          };
          const encode = (str) => {
            isEncoded = true;
            return encodingLookup[str];
          };
          const decode2 = (str, keepSlashes) => {
            if (isEncoded) {
              str = str.replace(/\uFEFF[0-9]/g, (str2) => {
                return encodingLookup[str2];
              });
            }
            if (!keepSlashes) {
              str = str.replace(/\\([\'\";:])/g, "$1");
            }
            return str;
          };
          const decodeSingleHexSequence = (escSeq) => {
            return String.fromCharCode(parseInt(escSeq.slice(1), 16));
          };
          const decodeHexSequences = (value3) => {
            return value3.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
          };
          const processUrl = (match2, url, url2, url3, str, str2) => {
            str = str || str2;
            if (str) {
              str = decode2(str);
              return `'` + str.replace(/\'/g, `\\'`) + `'`;
            }
            url = decode2(url || url2 || url3);
            if (!settings.allow_script_urls) {
              const scriptUrl = url.replace(/[\s\r\n]+/g, "");
              if (/(java|vb)script:/i.test(scriptUrl)) {
                return "";
              }
              if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
                return "";
              }
            }
            if (urlConverter) {
              url = urlConverter.call(urlConverterScope, url, "style");
            }
            return `url('` + url.replace(/\'/g, `\\'`) + `')`;
          };
          if (css) {
            css = css.replace(/[\u0000-\u001F]/g, "");
            css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, (str) => {
              return str.replace(/[;:]/g, encode);
            });
            while (matches = styleRegExp.exec(css)) {
              styleRegExp.lastIndex = matches.index + matches[0].length;
              name2 = matches[1].replace(trimRightRegExp, "").toLowerCase();
              value2 = matches[2].replace(trimRightRegExp, "");
              if (name2 && value2) {
                name2 = decodeHexSequences(name2);
                value2 = decodeHexSequences(value2);
                if (name2.indexOf(invisibleChar) !== -1 || name2.indexOf('"') !== -1) {
                  continue;
                }
                if (!settings.allow_script_urls && (name2 === "behavior" || /expression\s*\(|\/\*|\*\//.test(value2))) {
                  continue;
                }
                if (name2 === "font-weight" && value2 === "700") {
                  value2 = "bold";
                } else if (name2 === "color" || name2 === "background-color") {
                  value2 = value2.toLowerCase();
                }
                value2 = value2.replace(urlOrStrRegExp, processUrl);
                styles[name2] = isEncoded ? decode2(value2, true) : value2;
              }
            }
            compress("border", "", true);
            compress("border", "-width");
            compress("border", "-color");
            compress("border", "-style");
            compress("padding", "");
            compress("margin", "");
            compress2("border", "border-width", "border-style", "border-color");
            if (styles.border === "medium none") {
              delete styles.border;
            }
            if (styles["border-image"] === "none") {
              delete styles["border-image"];
            }
          }
          return styles;
        },
        serialize: (styles, elementName) => {
          let css = "";
          const serializeStyles = (name2) => {
            let value2;
            const styleList = validStyles[name2];
            if (styleList) {
              for (let i2 = 0, l = styleList.length; i2 < l; i2++) {
                name2 = styleList[i2];
                value2 = styles[name2];
                if (value2) {
                  css += (css.length > 0 ? " " : "") + name2 + ": " + value2 + ";";
                }
              }
            }
          };
          const isValid2 = (name2, elementName2) => {
            let styleMap = invalidStyles["*"];
            if (styleMap && styleMap[name2]) {
              return false;
            }
            styleMap = invalidStyles[elementName2];
            return !(styleMap && styleMap[name2]);
          };
          if (elementName && validStyles) {
            serializeStyles("*");
            serializeStyles(elementName);
          } else {
            each$e(styles, (value2, name2) => {
              if (value2 && (!invalidStyles || isValid2(name2, elementName))) {
                css += (css.length > 0 ? " " : "") + name2 + ": " + value2 + ";";
              }
            });
          }
          return css;
        }
      };
      return self;
    };
    const deprecated = {
      keyLocation: true,
      layerX: true,
      layerY: true,
      returnValue: true,
      webkitMovementX: true,
      webkitMovementY: true,
      keyIdentifier: true,
      mozPressure: true
    };
    const isNativeEvent = (event) => event instanceof Event || isFunction(event.initEvent);
    const hasIsDefaultPrevented = (event) => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
    const needsNormalizing = (event) => isNullable(event.preventDefault) || isNativeEvent(event);
    const clone$3 = (originalEvent, data2) => {
      const event = data2 !== null && data2 !== void 0 ? data2 : {};
      for (const name2 in originalEvent) {
        if (!has$2(deprecated, name2)) {
          event[name2] = originalEvent[name2];
        }
      }
      if (isNonNullable(event.composedPath)) {
        event.composedPath = () => originalEvent.composedPath();
      }
      return event;
    };
    const normalize$3 = (type2, originalEvent, fallbackTarget, data2) => {
      var _a;
      const event = clone$3(originalEvent, data2);
      event.type = type2;
      if (isNullable(event.target)) {
        event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
      }
      if (needsNormalizing(originalEvent)) {
        event.preventDefault = () => {
          event.defaultPrevented = true;
          event.isDefaultPrevented = always;
          if (isFunction(originalEvent.preventDefault)) {
            originalEvent.preventDefault();
          }
        };
        event.stopPropagation = () => {
          event.cancelBubble = true;
          event.isPropagationStopped = always;
          if (isFunction(originalEvent.stopPropagation)) {
            originalEvent.stopPropagation();
          }
        };
        event.stopImmediatePropagation = () => {
          event.isImmediatePropagationStopped = always;
          event.stopPropagation();
        };
        if (!hasIsDefaultPrevented(event)) {
          event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
          event.isPropagationStopped = event.cancelBubble === true ? always : never;
          event.isImmediatePropagationStopped = never;
        }
      }
      return event;
    };
    const eventExpandoPrefix = "mce-data-";
    const mouseEventRe = /^(?:mouse|contextmenu)|click/;
    const addEvent = (target, name2, callback, capture) => {
      if (target.addEventListener) {
        target.addEventListener(name2, callback, capture || false);
      } else if (target.attachEvent) {
        target.attachEvent("on" + name2, callback);
      }
    };
    const removeEvent = (target, name2, callback, capture) => {
      if (target.removeEventListener) {
        target.removeEventListener(name2, callback, capture || false);
      } else if (target.detachEvent) {
        target.detachEvent("on" + name2, callback);
      }
    };
    const isMouseEvent = (event) => isNonNullable(event) && mouseEventRe.test(event.type);
    const fix = (originalEvent, data2) => {
      const event = normalize$3(originalEvent.type, originalEvent, document, data2);
      if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
        const eventDoc = event.target.ownerDocument || document;
        const doc = eventDoc.documentElement;
        const body = eventDoc.body;
        const mouseEvent = event;
        mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
        mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
      }
      return event;
    };
    const bindOnReady = (win, callback, eventUtils) => {
      const doc = win.document, event = { type: "ready" };
      if (eventUtils.domLoaded) {
        callback(event);
        return;
      }
      const isDocReady = () => {
        return doc.readyState === "complete" || doc.readyState === "interactive" && doc.body;
      };
      const readyHandler = () => {
        removeEvent(win, "DOMContentLoaded", readyHandler);
        removeEvent(win, "load", readyHandler);
        if (!eventUtils.domLoaded) {
          eventUtils.domLoaded = true;
          callback(event);
        }
        win = null;
      };
      if (isDocReady()) {
        readyHandler();
      } else {
        addEvent(win, "DOMContentLoaded", readyHandler);
      }
      if (!eventUtils.domLoaded) {
        addEvent(win, "load", readyHandler);
      }
    };
    class EventUtils {
      constructor() {
        this.domLoaded = false;
        this.events = {};
        this.count = 1;
        this.expando = eventExpandoPrefix + (+new Date()).toString(32);
        this.hasMouseEnterLeave = "onmouseenter" in document.documentElement;
        this.hasFocusIn = "onfocusin" in document.documentElement;
        this.count = 1;
      }
      bind(target, names, callback, scope) {
        const self = this;
        let id, callbackList, i, name2, fakeName, nativeHandler, capture;
        const win = window;
        const defaultNativeHandler = (evt) => {
          self.executeHandlers(fix(evt || win.event), id);
        };
        if (!target || target.nodeType === 3 || target.nodeType === 8) {
          return;
        }
        if (!target[self.expando]) {
          id = self.count++;
          target[self.expando] = id;
          self.events[id] = {};
        } else {
          id = target[self.expando];
        }
        scope = scope || target;
        const namesList = names.split(" ");
        i = namesList.length;
        while (i--) {
          name2 = namesList[i];
          nativeHandler = defaultNativeHandler;
          fakeName = capture = false;
          if (name2 === "DOMContentLoaded") {
            name2 = "ready";
          }
          if (self.domLoaded && name2 === "ready" && target.readyState === "complete") {
            callback.call(scope, fix({ type: name2 }));
            continue;
          }
          if (!self.hasMouseEnterLeave) {
            fakeName = self.mouseEnterLeave[name2];
            if (fakeName) {
              nativeHandler = (evt) => {
                const current = evt.currentTarget;
                let related = evt.relatedTarget;
                if (related && current.contains) {
                  related = current.contains(related);
                } else {
                  while (related && related !== current) {
                    related = related.parentNode;
                  }
                }
                if (!related) {
                  evt = fix(evt || win.event);
                  evt.type = evt.type === "mouseout" ? "mouseleave" : "mouseenter";
                  evt.target = current;
                  self.executeHandlers(evt, id);
                }
              };
            }
          }
          if (!self.hasFocusIn && (name2 === "focusin" || name2 === "focusout")) {
            capture = true;
            fakeName = name2 === "focusin" ? "focus" : "blur";
            nativeHandler = (evt) => {
              evt = fix(evt || win.event);
              evt.type = evt.type === "focus" ? "focusin" : "focusout";
              self.executeHandlers(evt, id);
            };
          }
          callbackList = self.events[id][name2];
          if (!callbackList) {
            self.events[id][name2] = callbackList = [{
              func: callback,
              scope
            }];
            callbackList.fakeName = fakeName;
            callbackList.capture = capture;
            callbackList.nativeHandler = nativeHandler;
            if (name2 === "ready") {
              bindOnReady(target, nativeHandler, self);
            } else {
              addEvent(target, fakeName || name2, nativeHandler, capture);
            }
          } else {
            if (name2 === "ready" && self.domLoaded) {
              callback(fix({ type: name2 }));
            } else {
              callbackList.push({
                func: callback,
                scope
              });
            }
          }
        }
        target = callbackList = null;
        return callback;
      }
      unbind(target, names, callback) {
        let callbackList, i, ci, name2, eventMap;
        if (!target || target.nodeType === 3 || target.nodeType === 8) {
          return this;
        }
        const id = target[this.expando];
        if (id) {
          eventMap = this.events[id];
          if (names) {
            const namesList = names.split(" ");
            i = namesList.length;
            while (i--) {
              name2 = namesList[i];
              callbackList = eventMap[name2];
              if (callbackList) {
                if (callback) {
                  ci = callbackList.length;
                  while (ci--) {
                    if (callbackList[ci].func === callback) {
                      const nativeHandler = callbackList.nativeHandler;
                      const fakeName = callbackList.fakeName, capture = callbackList.capture;
                      callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
                      callbackList.nativeHandler = nativeHandler;
                      callbackList.fakeName = fakeName;
                      callbackList.capture = capture;
                      eventMap[name2] = callbackList;
                    }
                  }
                }
                if (!callback || callbackList.length === 0) {
                  delete eventMap[name2];
                  removeEvent(target, callbackList.fakeName || name2, callbackList.nativeHandler, callbackList.capture);
                }
              }
            }
          } else {
            each$e(eventMap, (callbackList2, name3) => {
              removeEvent(target, callbackList2.fakeName || name3, callbackList2.nativeHandler, callbackList2.capture);
            });
            eventMap = {};
          }
          for (name2 in eventMap) {
            if (has$2(eventMap, name2)) {
              return this;
            }
          }
          delete this.events[id];
          try {
            delete target[this.expando];
          } catch (ex) {
            target[this.expando] = null;
          }
        }
        return this;
      }
      fire(target, name2, args) {
        return this.dispatch(target, name2, args);
      }
      dispatch(target, name2, args) {
        let id;
        if (!target || target.nodeType === 3 || target.nodeType === 8) {
          return this;
        }
        const event = fix({
          type: name2,
          target
        }, args);
        do {
          id = target[this.expando];
          if (id) {
            this.executeHandlers(event, id);
          }
          target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
        } while (target && !event.isPropagationStopped());
        return this;
      }
      clean(target) {
        let i, children2;
        if (!target || target.nodeType === 3 || target.nodeType === 8) {
          return this;
        }
        if (target[this.expando]) {
          this.unbind(target);
        }
        if (!target.getElementsByTagName) {
          target = target.document;
        }
        if (target && target.getElementsByTagName) {
          this.unbind(target);
          children2 = target.getElementsByTagName("*");
          i = children2.length;
          while (i--) {
            target = children2[i];
            if (target[this.expando]) {
              this.unbind(target);
            }
          }
        }
        return this;
      }
      destroy() {
        this.events = {};
      }
      cancel(e) {
        if (e) {
          e.preventDefault();
          e.stopImmediatePropagation();
        }
        return false;
      }
      executeHandlers(evt, id) {
        const container = this.events[id];
        const callbackList = container && container[evt.type];
        if (callbackList) {
          for (let i = 0, l = callbackList.length; i < l; i++) {
            const callback = callbackList[i];
            if (callback && callback.func.call(callback.scope, evt) === false) {
              evt.preventDefault();
            }
            if (evt.isImmediatePropagationStopped()) {
              return;
            }
          }
        }
      }
    }
    EventUtils.Event = new EventUtils();
    const each$b = Tools.each;
    const grep = Tools.grep;
    const internalStyleName = "data-mce-style";
    const legacySetAttribute = (elm, name2, value2) => {
      if (isNullable(value2) || value2 === "") {
        remove$b(elm, name2);
      } else {
        set$2(elm, name2, value2);
      }
    };
    const setupAttrHooks = (styles, settings, getContext2) => {
      const keepValues = settings.keep_values;
      const keepUrlHook = {
        set: (elm, value2, name2) => {
          const sugarElm = SugarElement.fromDom(elm);
          if (isFunction(settings.url_converter) && isNonNullable(value2)) {
            value2 = settings.url_converter.call(settings.url_converter_scope || getContext2(), value2, name2, elm[0]);
          }
          const internalName = "data-mce-" + name2;
          legacySetAttribute(sugarElm, internalName, value2);
          legacySetAttribute(sugarElm, name2, value2);
        },
        get: (elm, name2) => {
          const sugarElm = SugarElement.fromDom(elm);
          return get$9(sugarElm, "data-mce-" + name2) || get$9(sugarElm, name2);
        }
      };
      const attrHooks = {
        style: {
          set: (elm, value2) => {
            const sugarElm = SugarElement.fromDom(elm);
            if (isObject(value2)) {
              setAll(sugarElm, value2);
              return;
            }
            if (keepValues) {
              legacySetAttribute(sugarElm, internalStyleName, value2);
            }
            remove$b(sugarElm, "style");
            if (isString(value2)) {
              setAll(sugarElm, styles.parse(value2));
            }
          },
          get: (elm) => {
            const sugarElm = SugarElement.fromDom(elm);
            const value2 = get$9(sugarElm, internalStyleName) || get$9(sugarElm, "style");
            return styles.serialize(styles.parse(value2), name(sugarElm));
          }
        }
      };
      if (keepValues) {
        attrHooks.href = attrHooks.src = keepUrlHook;
      }
      return attrHooks;
    };
    const updateInternalStyleAttr = (styles, elm) => {
      const rawValue = get$9(elm, "style");
      const value2 = styles.serialize(styles.parse(rawValue), name(elm));
      legacySetAttribute(elm, internalStyleName, value2);
    };
    const findNodeIndex = (node, normalized) => {
      let idx = 0, lastNodeType, nodeType;
      if (node) {
        for (lastNodeType = node.nodeType, node = node.previousSibling; node; node = node.previousSibling) {
          nodeType = node.nodeType;
          if (normalized && nodeType === 3) {
            if (nodeType === lastNodeType || !node.nodeValue.length) {
              continue;
            }
          }
          idx++;
          lastNodeType = nodeType;
        }
      }
      return idx;
    };
    const numericalCssMap = Tools.makeMap("fill-opacity font-weight line-height opacity orphans widows z-index zoom", " ");
    const camelCaseToHyphens = (name2) => name2.replace(/[A-Z]/g, (v) => "-" + v.toLowerCase());
    const DOMUtils = (doc, settings = {}) => {
      const addedStyles = {};
      const win = window;
      const files = {};
      let counter = 0;
      const stdMode = true;
      const boxModel = true;
      const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
        contentCssCors: settings.contentCssCors,
        referrerPolicy: settings.referrerPolicy
      });
      const boundEvents = [];
      const schema = settings.schema ? settings.schema : Schema({});
      const styles = Styles({
        url_converter: settings.url_converter,
        url_converter_scope: settings.url_converter_scope
      }, settings.schema);
      const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
      const blockElementsMap = schema.getBlockElements();
      const isBlock2 = (node) => {
        if (isString(node)) {
          return has$2(blockElementsMap, node);
        } else {
          return isElement$6(node) && has$2(blockElementsMap, node.nodeName);
        }
      };
      const get2 = (elm) => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
      const _get = (elm) => {
        const value2 = get2(elm);
        return isNonNullable(value2) ? SugarElement.fromDom(value2) : null;
      };
      const getAttrib = (elm, name2, defaultVal) => {
        let value2;
        const $elm = _get(elm);
        if (isNonNullable($elm) && isElement$7($elm)) {
          const hook = attrHooks[name2];
          if (hook && hook.get) {
            value2 = hook.get($elm.dom, name2);
          } else {
            value2 = get$9($elm, name2);
          }
        }
        return isNonNullable(value2) ? value2 : defaultVal !== null && defaultVal !== void 0 ? defaultVal : "";
      };
      const getAttribs = (elm) => {
        const node = get2(elm);
        return isNullable(node) ? [] : node.attributes;
      };
      const setAttrib = (elm, name2, value2) => {
        run(elm, (e) => {
          if (isElement$6(e)) {
            const $elm = SugarElement.fromDom(e);
            if (value2 === "") {
              value2 = null;
            }
            const originalValue = get$9($elm, name2);
            const hook = attrHooks[name2];
            if (hook && hook.set) {
              hook.set($elm.dom, value2, name2);
            } else {
              legacySetAttribute($elm, name2, value2);
            }
            if (originalValue !== value2 && settings.onSetAttrib) {
              settings.onSetAttrib({
                attrElm: $elm,
                attrName: name2,
                attrValue: value2
              });
            }
          }
        });
      };
      const clone2 = (node, deep2) => {
        return node.cloneNode(deep2);
      };
      const getRoot = () => settings.root_element || doc.body;
      const getViewPort = (argWin) => {
        const vp = getBounds(argWin);
        return {
          x: vp.x,
          y: vp.y,
          w: vp.width,
          h: vp.height
        };
      };
      const getPos$1 = (elm, rootElm) => getPos(doc.body, get2(elm), rootElm);
      const setStyle = (elm, name2, value2) => {
        const convertStyleToString = (cssValue, cssName) => {
          if (isString(cssValue)) {
            return cssValue;
          } else if (isNumber(cssValue)) {
            return has$2(numericalCssMap, cssName) ? cssValue + "" : cssValue + "px";
          } else {
            return map$2(cssValue, convertStyleToString);
          }
        };
        const applyStyle2 = ($elm, cssName, cssValue) => {
          const normalizedName = camelCaseToHyphens(cssName);
          if (isNullable(cssValue) || cssValue === "") {
            remove$7($elm, normalizedName);
          } else {
            set$1($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
          }
        };
        run(elm, (e) => {
          const $elm = SugarElement.fromDom(e);
          if (isString(name2)) {
            applyStyle2($elm, name2, value2);
          } else {
            each$e(name2, (v, n) => {
              applyStyle2($elm, n, v);
            });
          }
          if (settings.update_styles) {
            updateInternalStyleAttr(styles, $elm);
          }
        });
      };
      const setStyles = (elm, stylesArg) => {
        setStyle(elm, stylesArg);
      };
      const getStyle2 = (elm, name2, computed) => {
        const $elm = get2(elm);
        if (isNullable($elm) || !isElement$6($elm)) {
          return void 0;
        }
        if (computed) {
          return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name2));
        } else {
          name2 = name2.replace(/-(\D)/g, (a, b) => b.toUpperCase());
          if (name2 === "float") {
            name2 = "cssFloat";
          }
          return $elm.style ? $elm.style[name2] : void 0;
        }
      };
      const getSize = (elm) => {
        let w, h2;
        const $elm = get2(elm);
        w = getStyle2($elm, "width");
        h2 = getStyle2($elm, "height");
        if (w.indexOf("px") === -1) {
          w = 0;
        }
        if (h2.indexOf("px") === -1) {
          h2 = 0;
        }
        return {
          w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
          h: parseInt(h2, 10) || $elm.offsetHeight || $elm.clientHeight
        };
      };
      const getRect = (elm) => {
        const $elm = get2(elm);
        const pos = getPos$1($elm);
        const size = getSize($elm);
        return {
          x: pos.x,
          y: pos.y,
          w: size.w,
          h: size.h
        };
      };
      const is2 = (elm, selector) => {
        if (!elm) {
          return false;
        }
        const elms = isArray$1(elm) ? elm : [elm];
        return exists(elms, (e) => {
          return is$1(SugarElement.fromDom(e), selector);
        });
      };
      const getParents2 = (elm, selector, root, collect) => {
        const result = [];
        let selectorVal;
        let node = get2(elm);
        collect = collect === void 0;
        root = root || (getRoot().nodeName !== "BODY" ? getRoot().parentNode : null);
        if (isString(selector)) {
          selectorVal = selector;
          if (selector === "*") {
            selector = isElement$6;
          } else {
            selector = (node2) => is2(node2, selectorVal);
          }
        }
        while (node) {
          if (node === root || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
            break;
          }
          if (!selector || selector(node)) {
            if (collect) {
              result.push(node);
            } else {
              return [node];
            }
          }
          node = node.parentNode;
        }
        return collect ? result : null;
      };
      const getParent = (node, selector, root) => {
        const parents2 = getParents2(node, selector, root, false);
        return parents2 && parents2.length > 0 ? parents2[0] : null;
      };
      const _findSib = (node, selector, name2) => {
        let func = selector;
        if (node) {
          if (isString(selector)) {
            func = (node2) => {
              return is2(node2, selector);
            };
          }
          for (node = node[name2]; node; node = node[name2]) {
            if (isFunction(func) && func(node)) {
              return node;
            }
          }
        }
        return null;
      };
      const getNext = (node, selector) => _findSib(node, selector, "nextSibling");
      const getPrev = (node, selector) => _findSib(node, selector, "previousSibling");
      const select2 = (selector, scope) => {
        var _a, _b;
        const elm = (_b = (_a = get2(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
        return from(elm.querySelectorAll(selector));
      };
      const run = function(elm, func, scope) {
        const context2 = scope !== null && scope !== void 0 ? scope : this;
        const node = isString(elm) ? get2(elm) : elm;
        if (!node) {
          return false;
        }
        if (isArray$1(node) && (node.length || node.length === 0)) {
          const result = [];
          each$b(node, (elm2, i) => {
            if (elm2) {
              result.push(func.call(context2, isString(elm2) ? get2(elm2) : elm2, i));
            }
          });
          return result;
        } else {
          return func.call(context2, node);
        }
      };
      const setAttribs = (elm, attrs) => {
        run(elm, ($elm) => {
          each$e(attrs, (value2, name2) => {
            setAttrib($elm, name2, value2);
          });
        });
      };
      const setHTML = (elm, html2) => {
        run(elm, (e) => {
          const $elm = SugarElement.fromDom(e);
          set($elm, html2);
        });
      };
      const add2 = (parentElm, name2, attrs, html2, create3) => run(parentElm, (parentElm2) => {
        const newElm = isString(name2) ? doc.createElement(name2) : name2;
        if (isNonNullable(attrs)) {
          setAttribs(newElm, attrs);
        }
        if (html2) {
          if (!isString(html2) && html2.nodeType) {
            newElm.appendChild(html2);
          } else if (isString(html2)) {
            setHTML(newElm, html2);
          }
        }
        return !create3 ? parentElm2.appendChild(newElm) : newElm;
      });
      const create2 = (name2, attrs, html2) => add2(doc.createElement(name2), name2, attrs, html2, true);
      const decode2 = Entities.decode;
      const encode = Entities.encodeAllRaw;
      const createHTML = (name2, attrs, html2 = "") => {
        let outHtml = "", key;
        outHtml += "<" + name2;
        for (key in attrs) {
          if (hasNonNullableKey(attrs, key)) {
            outHtml += " " + key + '="' + encode(attrs[key]) + '"';
          }
        }
        if (isEmpty$3(html2) && has$2(schema.getVoidElements(), name2)) {
          return outHtml + " />";
        } else {
          return outHtml + ">" + html2 + "</" + name2 + ">";
        }
      };
      const createFragment2 = (html2) => {
        let node;
        const container = doc.createElement("div");
        const frag = doc.createDocumentFragment();
        frag.appendChild(container);
        if (html2) {
          container.innerHTML = html2;
        }
        while (node = container.firstChild) {
          frag.appendChild(node);
        }
        frag.removeChild(container);
        return frag;
      };
      const remove2 = (node, keepChildren) => {
        return run(node, (n) => {
          const $node = SugarElement.fromDom(n);
          if (keepChildren) {
            each$f(children($node), (child2) => {
              if (isText$a(child2) && child2.dom.length === 0) {
                remove$6(child2);
              } else {
                before$3($node, child2);
              }
            });
          }
          remove$6($node);
          return $node.dom;
        });
      };
      const removeAllAttribs = (e) => run(e, (e2) => {
        const attrs = e2.attributes;
        for (let i = attrs.length - 1; i >= 0; i--) {
          e2.removeAttributeNode(attrs.item(i));
        }
      });
      const parseStyle = (cssText) => styles.parse(cssText);
      const serializeStyle = (stylesArg, name2) => styles.serialize(stylesArg, name2);
      const addStyle = (cssText) => {
        let head2, styleElm;
        if (self !== DOMUtils.DOM && doc === document) {
          if (addedStyles[cssText]) {
            return;
          }
          addedStyles[cssText] = true;
        }
        styleElm = doc.getElementById("mceDefaultStyles");
        if (!styleElm) {
          styleElm = doc.createElement("style");
          styleElm.id = "mceDefaultStyles";
          styleElm.type = "text/css";
          head2 = doc.getElementsByTagName("head")[0];
          if (head2.firstChild) {
            head2.insertBefore(styleElm, head2.firstChild);
          } else {
            head2.appendChild(styleElm);
          }
        }
        if (styleElm.styleSheet) {
          styleElm.styleSheet.cssText += cssText;
        } else {
          styleElm.appendChild(doc.createTextNode(cssText));
        }
      };
      const loadCSS = (urls) => {
        if (!urls) {
          urls = "";
        }
        each$f(urls.split(","), (url) => {
          files[url] = true;
          styleSheetLoader.load(url).catch(noop);
        });
      };
      const toggleClass2 = (elm, cls, state) => {
        run(elm, (e) => {
          if (isElement$6(e)) {
            const $elm = SugarElement.fromDom(e);
            const classes = cls.split(" ");
            each$f(classes, (c) => {
              if (isNonNullable(state)) {
                const fn = state ? add$2 : remove$8;
                fn($elm, c);
              } else {
                toggle$1($elm, c);
              }
            });
          }
        });
      };
      const addClass = (elm, cls) => {
        toggleClass2(elm, cls, true);
      };
      const removeClass = (elm, cls) => {
        toggleClass2(elm, cls, false);
      };
      const hasClass2 = (elm, cls) => {
        const $elm = _get(elm);
        const classes = cls.split(" ");
        return forall(classes, (c) => has($elm, c));
      };
      const show = (elm) => {
        run(elm, (e) => remove$7(SugarElement.fromDom(e), "display"));
      };
      const hide = (elm) => {
        run(elm, (e) => set$1(SugarElement.fromDom(e), "display", "none"));
      };
      const isHidden = (elm) => {
        const $elm = _get(elm);
        return is$2(getRaw$1($elm, "display"), "none");
      };
      const uniqueId2 = (prefix) => (!prefix ? "mce_" : prefix) + counter++;
      const getOuterHTML = (elm) => {
        const $elm = _get(elm);
        return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
      };
      const setOuterHTML = (elm, html2) => {
        run(elm, ($elm) => {
          if (isElement$6($elm)) {
            $elm.outerHTML = html2;
          }
        });
      };
      const insertAfter2 = (node, reference) => {
        const referenceNode = get2(reference);
        return run(node, (node2) => {
          const parent2 = referenceNode.parentNode;
          const nextSibling2 = referenceNode.nextSibling;
          if (nextSibling2) {
            parent2.insertBefore(node2, nextSibling2);
          } else {
            parent2.appendChild(node2);
          }
          return node2;
        });
      };
      const replace = (newElm, oldElm, keepChildren) => run(oldElm, (oldElm2) => {
        if (isArray$1(oldElm2)) {
          newElm = newElm.cloneNode(true);
        }
        if (keepChildren) {
          each$b(grep(oldElm2.childNodes), (node) => {
            newElm.appendChild(node);
          });
        }
        return oldElm2.parentNode.replaceChild(newElm, oldElm2);
      });
      const rename = (elm, name2) => {
        let newElm;
        if (elm.nodeName !== name2.toUpperCase()) {
          newElm = create2(name2);
          each$b(getAttribs(elm), (attrNode) => {
            setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
          });
          replace(newElm, elm, true);
        }
        return newElm || elm;
      };
      const findCommonAncestor = (a, b) => {
        let ps = a, pe;
        while (ps) {
          pe = b;
          while (pe && ps !== pe) {
            pe = pe.parentNode;
          }
          if (ps === pe) {
            break;
          }
          ps = ps.parentNode;
        }
        if (!ps && a.ownerDocument) {
          return a.ownerDocument.documentElement;
        }
        return ps;
      };
      const isNonEmptyElement2 = (node) => {
        if (isElement$6(node)) {
          const isNamedAnchor2 = node.nodeName.toLowerCase() === "a" && !getAttrib(node, "href") && getAttrib(node, "id");
          if (getAttrib(node, "name") || getAttrib(node, "data-mce-bookmark") || isNamedAnchor2) {
            return true;
          }
        }
        return false;
      };
      const isEmpty2 = (node, elements) => {
        let type2, name2, brCount = 0;
        if (isNonEmptyElement2(node)) {
          return false;
        }
        node = node.firstChild;
        if (node) {
          const walker = new DomTreeWalker(node, node.parentNode);
          const whitespace = schema ? schema.getWhitespaceElements() : {};
          elements = elements || (schema ? schema.getNonEmptyElements() : null);
          do {
            type2 = node.nodeType;
            if (isElement$6(node)) {
              const bogusVal = node.getAttribute("data-mce-bogus");
              if (bogusVal) {
                node = walker.next(bogusVal === "all");
                continue;
              }
              name2 = node.nodeName.toLowerCase();
              if (elements && elements[name2]) {
                if (name2 === "br") {
                  brCount++;
                  node = walker.next();
                  continue;
                }
                return false;
              }
              if (isNonEmptyElement2(node)) {
                return false;
              }
            }
            if (type2 === 8) {
              return false;
            }
            if (type2 === 3 && !isWhitespaceText(node.nodeValue)) {
              return false;
            }
            if (type2 === 3 && node.parentNode && whitespace[node.parentNode.nodeName] && isWhitespaceText(node.nodeValue)) {
              return false;
            }
            node = walker.next();
          } while (node);
        }
        return brCount <= 1;
      };
      const createRng = () => doc.createRange();
      const split2 = (parentElm, splitElm, replacementElm) => {
        let range2 = createRng();
        let beforeFragment;
        let afterFragment;
        let parentNode;
        if (parentElm && splitElm) {
          range2.setStart(parentElm.parentNode, findNodeIndex(parentElm));
          range2.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
          beforeFragment = range2.extractContents();
          range2 = createRng();
          range2.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
          range2.setEnd(parentElm.parentNode, findNodeIndex(parentElm) + 1);
          afterFragment = range2.extractContents();
          parentNode = parentElm.parentNode;
          parentNode.insertBefore(trimNode(self, beforeFragment), parentElm);
          if (replacementElm) {
            parentNode.insertBefore(replacementElm, parentElm);
          } else {
            parentNode.insertBefore(splitElm, parentElm);
          }
          parentNode.insertBefore(trimNode(self, afterFragment), parentElm);
          remove2(parentElm);
          return replacementElm || splitElm;
        }
      };
      const bind2 = (target, name2, func, scope) => {
        if (isArray$1(target)) {
          let i = target.length;
          const rv = [];
          while (i--) {
            rv[i] = bind2(target[i], name2, func, scope);
          }
          return rv;
        } else {
          if (settings.collect && (target === doc || target === win)) {
            boundEvents.push([
              target,
              name2,
              func,
              scope
            ]);
          }
          return events.bind(target, name2, func, scope || self);
        }
      };
      const unbind2 = (target, name2, func) => {
        if (isArray$1(target)) {
          let i = target.length;
          const rv = [];
          while (i--) {
            rv[i] = unbind2(target[i], name2, func);
          }
          return rv;
        } else {
          if (boundEvents.length > 0 && (target === doc || target === win)) {
            let i = boundEvents.length;
            while (i--) {
              const item = boundEvents[i];
              if (target === item[0] && (!name2 || name2 === item[1]) && (!func || func === item[2])) {
                events.unbind(item[0], item[1], item[2]);
              }
            }
          }
          return events.unbind(target, name2, func);
        }
      };
      const dispatch = (target, name2, evt) => events.dispatch(target, name2, evt);
      const fire = (target, name2, evt) => events.dispatch(target, name2, evt);
      const getContentEditable = (node) => {
        if (node && isElement$6(node)) {
          const contentEditable = node.getAttribute("data-mce-contenteditable");
          if (contentEditable && contentEditable !== "inherit") {
            return contentEditable;
          }
          return node.contentEditable !== "inherit" ? node.contentEditable : null;
        } else {
          return null;
        }
      };
      const getContentEditableParent = (node) => {
        const root = getRoot();
        let state = null;
        for (; node && node !== root; node = node.parentNode) {
          state = getContentEditable(node);
          if (state !== null) {
            break;
          }
        }
        return state;
      };
      const destroy2 = () => {
        if (boundEvents.length > 0) {
          let i = boundEvents.length;
          while (i--) {
            const item = boundEvents[i];
            events.unbind(item[0], item[1], item[2]);
          }
        }
        each$e(files, (_, url) => {
          styleSheetLoader.unload(url);
          delete files[url];
        });
      };
      const isChildOf = (node, parent2) => {
        return node === parent2 || parent2.contains(node);
      };
      const dumpRng = (r2) => "startContainer: " + r2.startContainer.nodeName + ", startOffset: " + r2.startOffset + ", endContainer: " + r2.endContainer.nodeName + ", endOffset: " + r2.endOffset;
      const self = {
        doc,
        settings,
        win,
        files,
        stdMode,
        boxModel,
        styleSheetLoader,
        boundEvents,
        styles,
        schema,
        events,
        isBlock: isBlock2,
        root: null,
        clone: clone2,
        getRoot,
        getViewPort,
        getRect,
        getSize,
        getParent,
        getParents: getParents2,
        get: get2,
        getNext,
        getPrev,
        select: select2,
        is: is2,
        add: add2,
        create: create2,
        createHTML,
        createFragment: createFragment2,
        remove: remove2,
        setStyle,
        getStyle: getStyle2,
        setStyles,
        removeAllAttribs,
        setAttrib,
        setAttribs,
        getAttrib,
        getPos: getPos$1,
        parseStyle,
        serializeStyle,
        addStyle,
        loadCSS,
        addClass,
        removeClass,
        hasClass: hasClass2,
        toggleClass: toggleClass2,
        show,
        hide,
        isHidden,
        uniqueId: uniqueId2,
        setHTML,
        getOuterHTML,
        setOuterHTML,
        decode: decode2,
        encode,
        insertAfter: insertAfter2,
        replace,
        rename,
        findCommonAncestor,
        run,
        getAttribs,
        isEmpty: isEmpty2,
        createRng,
        nodeIndex: findNodeIndex,
        split: split2,
        bind: bind2,
        unbind: unbind2,
        fire,
        dispatch,
        getContentEditable,
        getContentEditableParent,
        destroy: destroy2,
        isChildOf,
        dumpRng
      };
      const attrHooks = setupAttrHooks(styles, settings, constant(self));
      return self;
    };
    DOMUtils.DOM = DOMUtils(document);
    DOMUtils.nodeIndex = findNodeIndex;
    const DOM$b = DOMUtils.DOM;
    const QUEUED = 0;
    const LOADING = 1;
    const LOADED = 2;
    const FAILED = 3;
    class ScriptLoader2 {
      constructor(settings = {}) {
        this.states = {};
        this.queue = [];
        this.scriptLoadedCallbacks = {};
        this.queueLoadedCallbacks = [];
        this.loading = false;
        this.settings = settings;
      }
      _setReferrerPolicy(referrerPolicy) {
        this.settings.referrerPolicy = referrerPolicy;
      }
      loadScript(url) {
        return new Promise((resolve2, reject) => {
          const dom2 = DOM$b;
          let elm;
          const cleanup = () => {
            dom2.remove(id);
            if (elm) {
              elm.onerror = elm.onload = elm = null;
            }
          };
          const done = () => {
            cleanup();
            resolve2();
          };
          const error2 = () => {
            cleanup();
            reject("Failed to load script: " + url);
          };
          const id = dom2.uniqueId();
          elm = document.createElement("script");
          elm.id = id;
          elm.type = "text/javascript";
          elm.src = Tools._addCacheSuffix(url);
          if (this.settings.referrerPolicy) {
            dom2.setAttrib(elm, "referrerpolicy", this.settings.referrerPolicy);
          }
          elm.onload = done;
          elm.onerror = error2;
          (document.getElementsByTagName("head")[0] || document.body).appendChild(elm);
        });
      }
      isDone(url) {
        return this.states[url] === LOADED;
      }
      markDone(url) {
        this.states[url] = LOADED;
      }
      add(url) {
        const self = this;
        self.queue.push(url);
        const state = self.states[url];
        if (state === void 0) {
          self.states[url] = QUEUED;
        }
        return new Promise((resolve2, reject) => {
          if (!self.scriptLoadedCallbacks[url]) {
            self.scriptLoadedCallbacks[url] = [];
          }
          self.scriptLoadedCallbacks[url].push({
            resolve: resolve2,
            reject
          });
        });
      }
      load(url) {
        return this.add(url);
      }
      remove(url) {
        delete this.states[url];
        delete this.scriptLoadedCallbacks[url];
      }
      loadQueue() {
        const queue = this.queue;
        this.queue = [];
        return this.loadScripts(queue);
      }
      loadScripts(scripts) {
        const self = this;
        const execCallbacks = (name2, url) => {
          get$a(self.scriptLoadedCallbacks, url).each((callbacks) => {
            each$f(callbacks, (callback) => callback[name2](url));
          });
          delete self.scriptLoadedCallbacks[url];
        };
        const processResults = (results) => {
          const failures = filter$6(results, (result) => result.status === "rejected");
          if (failures.length > 0) {
            return Promise.reject(bind$3(failures, ({ reason }) => isArray$1(reason) ? reason : [reason]));
          } else {
            return Promise.resolve();
          }
        };
        const load = (urls) => Promise.allSettled(map$3(urls, (url) => {
          if (self.states[url] === LOADED) {
            execCallbacks("resolve", url);
            return Promise.resolve();
          } else if (self.states[url] === FAILED) {
            execCallbacks("reject", url);
            return Promise.reject(url);
          } else {
            self.states[url] = LOADING;
            return self.loadScript(url).then(() => {
              self.states[url] = LOADED;
              execCallbacks("resolve", url);
              const queue = self.queue;
              if (queue.length > 0) {
                self.queue = [];
                return load(queue).then(processResults);
              }
            }, () => {
              self.states[url] = FAILED;
              execCallbacks("reject", url);
              return Promise.reject(url);
            });
          }
        }));
        const processQueue = (urls) => {
          self.loading = true;
          return load(urls).then((results) => {
            self.loading = false;
            const nextQueuedItem = self.queueLoadedCallbacks.shift();
            Optional.from(nextQueuedItem).each(call);
            return processResults(results);
          });
        };
        const uniqueScripts = stringArray(scripts);
        if (self.loading) {
          return new Promise((resolve2, reject) => {
            self.queueLoadedCallbacks.push(() => processQueue(uniqueScripts).then(resolve2, reject));
          });
        } else {
          return processQueue(uniqueScripts);
        }
      }
    }
    ScriptLoader2.ScriptLoader = new ScriptLoader2();
    const Cell = (initial) => {
      let value2 = initial;
      const get2 = () => {
        return value2;
      };
      const set2 = (v) => {
        value2 = v;
      };
      return {
        get: get2,
        set: set2
      };
    };
    const isRaw = (str) => isObject(str) && has$2(str, "raw");
    const isTokenised = (str) => isArray$1(str) && str.length > 1;
    const data = {};
    const currentCode = Cell("en");
    const getLanguageData = () => get$a(data, currentCode.get());
    const getData$1 = () => map$2(data, (value2) => ({ ...value2 }));
    const setCode = (newCode) => {
      if (newCode) {
        currentCode.set(newCode);
      }
    };
    const getCode = () => currentCode.get();
    const add$1 = (code, items) => {
      let langData = data[code];
      if (!langData) {
        data[code] = langData = {};
      }
      each$e(items, (translation, name2) => {
        langData[name2.toLowerCase()] = translation;
      });
    };
    const translate = (text2) => {
      const langData = getLanguageData().getOr({});
      const toString = (obj) => {
        if (isFunction(obj)) {
          return Object.prototype.toString.call(obj);
        }
        return !isEmpty2(obj) ? "" + obj : "";
      };
      const isEmpty2 = (text3) => text3 === "" || text3 === null || text3 === void 0;
      const getLangData = (text3) => {
        const textstr = toString(text3);
        return get$a(langData, textstr.toLowerCase()).map(toString).getOr(textstr);
      };
      const removeContext = (str) => str.replace(/{context:\w+}$/, "");
      if (isEmpty2(text2)) {
        return "";
      }
      if (isRaw(text2)) {
        return toString(text2.raw);
      }
      if (isTokenised(text2)) {
        const values2 = text2.slice(1);
        const substitued = getLangData(text2[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values2, $2) ? toString(values2[$2]) : $1);
        return removeContext(substitued);
      }
      return removeContext(getLangData(text2));
    };
    const isRtl$1 = () => getLanguageData().bind((items) => get$a(items, "_dir")).exists((dir) => dir === "rtl");
    const hasCode = (code) => has$2(data, code);
    const I18n = {
      getData: getData$1,
      setCode,
      getCode,
      add: add$1,
      translate,
      isRtl: isRtl$1,
      hasCode
    };
    const AddOnManager = () => {
      const items = [];
      const urls = {};
      const lookup2 = {};
      const _listeners = [];
      const runListeners = (name2, state) => {
        const matchedListeners = filter$6(_listeners, (listener) => listener.name === name2 && listener.state === state);
        each$f(matchedListeners, (listener) => listener.resolve());
      };
      const isLoaded = (name2) => has$2(urls, name2);
      const isAdded = (name2) => has$2(lookup2, name2);
      const get2 = (name2) => {
        if (lookup2[name2]) {
          return lookup2[name2].instance;
        }
        return void 0;
      };
      const loadLanguagePack = (name2, languages) => {
        const language = I18n.getCode();
        const wrappedLanguages = "," + (languages || "") + ",";
        if (!language || languages && wrappedLanguages.indexOf("," + language + ",") === -1) {
          return;
        }
        ScriptLoader2.ScriptLoader.add(urls[name2] + "/langs/" + language + ".js");
      };
      const requireLangPack = (name2, languages) => {
        if (AddOnManager.languageLoad !== false) {
          if (isLoaded(name2)) {
            loadLanguagePack(name2, languages);
          } else {
            waitFor(name2, "loaded").then(() => loadLanguagePack(name2, languages));
          }
        }
      };
      const add2 = (id, addOn) => {
        items.push(addOn);
        lookup2[id] = { instance: addOn };
        runListeners(id, "added");
        return addOn;
      };
      const remove2 = (name2) => {
        delete urls[name2];
        delete lookup2[name2];
      };
      const createUrl = (baseUrl, dep) => {
        if (isString(dep)) {
          return isString(baseUrl) ? {
            prefix: "",
            resource: dep,
            suffix: ""
          } : {
            prefix: baseUrl.prefix,
            resource: dep,
            suffix: baseUrl.suffix
          };
        } else {
          return dep;
        }
      };
      const load = (name2, addOnUrl) => {
        if (urls[name2]) {
          return Promise.resolve();
        }
        let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
        if (urlString.indexOf("/") !== 0 && urlString.indexOf("://") === -1) {
          urlString = AddOnManager.baseURL + "/" + urlString;
        }
        urls[name2] = urlString.substring(0, urlString.lastIndexOf("/"));
        const done = () => {
          runListeners(name2, "loaded");
          return Promise.resolve();
        };
        if (lookup2[name2]) {
          return done();
        } else {
          return ScriptLoader2.ScriptLoader.add(urlString).then(done);
        }
      };
      const waitFor = (name2, state = "added") => {
        if (state === "added" && isAdded(name2)) {
          return Promise.resolve();
        } else if (state === "loaded" && isLoaded(name2)) {
          return Promise.resolve();
        } else {
          return new Promise((resolve2) => {
            _listeners.push({
              name: name2,
              state,
              resolve: resolve2
            });
          });
        }
      };
      return {
        items,
        urls,
        lookup: lookup2,
        get: get2,
        requireLangPack,
        add: add2,
        remove: remove2,
        createUrl,
        load,
        waitFor
      };
    };
    AddOnManager.languageLoad = true;
    AddOnManager.baseURL = "";
    AddOnManager.PluginManager = AddOnManager();
    AddOnManager.ThemeManager = AddOnManager();
    AddOnManager.ModelManager = AddOnManager();
    const singleton = (doRevoke) => {
      const subject = Cell(Optional.none());
      const revoke = () => subject.get().each(doRevoke);
      const clear2 = () => {
        revoke();
        subject.set(Optional.none());
      };
      const isSet = () => subject.get().isSome();
      const get2 = () => subject.get();
      const set2 = (s) => {
        revoke();
        subject.set(Optional.some(s));
      };
      return {
        clear: clear2,
        isSet,
        get: get2,
        set: set2
      };
    };
    const value$2 = () => {
      const subject = singleton(noop);
      const on2 = (f) => subject.get().each(f);
      return {
        ...subject,
        on: on2
      };
    };
    const first$1 = (fn, rate) => {
      let timer = null;
      const cancel = () => {
        if (!isNull(timer)) {
          clearTimeout(timer);
          timer = null;
        }
      };
      const throttle = (...args) => {
        if (isNull(timer)) {
          timer = setTimeout(() => {
            timer = null;
            fn.apply(null, args);
          }, rate);
        }
      };
      return {
        cancel,
        throttle
      };
    };
    const last$1 = (fn, rate) => {
      let timer = null;
      const cancel = () => {
        if (!isNull(timer)) {
          clearTimeout(timer);
          timer = null;
        }
      };
      const throttle = (...args) => {
        cancel();
        timer = setTimeout(() => {
          timer = null;
          fn.apply(null, args);
        }, rate);
      };
      return {
        cancel,
        throttle
      };
    };
    const descendants$1 = (scope, predicate) => {
      let result = [];
      each$f(children(scope), (x) => {
        if (predicate(x)) {
          result = result.concat([x]);
        }
        result = result.concat(descendants$1(x, predicate));
      });
      return result;
    };
    const descendants = (scope, selector) => all(selector, scope);
    const annotation = constant("mce-annotation");
    const dataAnnotation = constant("data-mce-annotation");
    const dataAnnotationId = constant("data-mce-annotation-uid");
    const dataAnnotationActive = constant("data-mce-annotation-active");
    const dataAnnotationClasses = constant("data-mce-annotation-classes");
    const dataAnnotationAttributes = constant("data-mce-annotation-attrs");
    const isRoot$1 = (root) => (node) => eq(node, root);
    const identify = (editor, annotationName) => {
      const rng = editor.selection.getRng();
      const start2 = SugarElement.fromDom(rng.startContainer);
      const root = SugarElement.fromDom(editor.getBody());
      const selector = annotationName.fold(() => "." + annotation(), (an) => `[${dataAnnotation()}="${an}"]`);
      const newStart = child$1(start2, rng.startOffset).getOr(start2);
      const closest2 = closest$3(newStart, selector, isRoot$1(root));
      const getAttr = (c, property) => {
        if (has$1(c, property)) {
          return Optional.some(get$9(c, property));
        } else {
          return Optional.none();
        }
      };
      return closest2.bind((c) => getAttr(c, `${dataAnnotationId()}`).bind((uid) => getAttr(c, `${dataAnnotation()}`).map((name2) => {
        const elements = findMarkers(editor, uid);
        return {
          uid,
          name: name2,
          elements
        };
      })));
    };
    const isAnnotation = (elem) => isElement$7(elem) && has(elem, annotation());
    const isBogusElement = (elem, root) => has$1(elem, "data-mce-bogus") || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
    const findMarkers = (editor, uid) => {
      const body = SugarElement.fromDom(editor.getBody());
      const descendants$12 = descendants(body, `[${dataAnnotationId()}="${uid}"]`);
      return filter$6(descendants$12, (descendant2) => !isBogusElement(descendant2, body));
    };
    const findAll = (editor, name2) => {
      const body = SugarElement.fromDom(editor.getBody());
      const markers = descendants(body, `[${dataAnnotation()}="${name2}"]`);
      const directory = {};
      each$f(markers, (m) => {
        if (!isBogusElement(m, body)) {
          const uid = get$9(m, dataAnnotationId());
          const nodesAlready = get$a(directory, uid).getOr([]);
          directory[uid] = nodesAlready.concat([m]);
        }
      });
      return directory;
    };
    const setup$x = (editor, registry2) => {
      const changeCallbacks = Cell({});
      const initData = () => ({
        listeners: [],
        previous: value$2()
      });
      const withCallbacks = (name2, f) => {
        updateCallbacks(name2, (data2) => {
          f(data2);
          return data2;
        });
      };
      const updateCallbacks = (name2, f) => {
        const callbackMap = changeCallbacks.get();
        const data2 = get$a(callbackMap, name2).getOrThunk(initData);
        const outputData = f(data2);
        callbackMap[name2] = outputData;
        changeCallbacks.set(callbackMap);
      };
      const fireCallbacks = (name2, uid, elements) => {
        withCallbacks(name2, (data2) => {
          each$f(data2.listeners, (f) => f(true, name2, {
            uid,
            nodes: map$3(elements, (elem) => elem.dom)
          }));
        });
      };
      const fireNoAnnotation = (name2) => {
        withCallbacks(name2, (data2) => {
          each$f(data2.listeners, (f) => f(false, name2));
        });
      };
      const toggleActiveAttr = (uid, state) => {
        each$f(findMarkers(editor, uid), (elem) => {
          if (state) {
            set$2(elem, dataAnnotationActive(), "true");
          } else {
            remove$b(elem, dataAnnotationActive());
          }
        });
      };
      const onNodeChange = last$1(() => {
        const annotations = sort(registry2.getNames());
        each$f(annotations, (name2) => {
          updateCallbacks(name2, (data2) => {
            const prev2 = data2.previous.get();
            identify(editor, Optional.some(name2)).fold(() => {
              prev2.each((uid) => {
                fireNoAnnotation(name2);
                data2.previous.clear();
                toggleActiveAttr(uid, false);
              });
            }, ({ uid, name: name3, elements }) => {
              if (!is$2(prev2, uid)) {
                prev2.each((uid2) => toggleActiveAttr(uid2, false));
                fireCallbacks(name3, uid, elements);
                data2.previous.set(uid);
                toggleActiveAttr(uid, true);
              }
            });
            return {
              previous: data2.previous,
              listeners: data2.listeners
            };
          });
        });
      }, 30);
      editor.on("remove", () => {
        onNodeChange.cancel();
      });
      editor.on("NodeChange", () => {
        onNodeChange.throttle();
      });
      const addListener = (name2, f) => {
        updateCallbacks(name2, (data2) => ({
          previous: data2.previous,
          listeners: data2.listeners.concat([f])
        }));
      };
      return { addListener };
    };
    const setup$w = (editor, registry2) => {
      const dataAnnotation$1 = dataAnnotation();
      const identifyParserNode = (node) => Optional.from(node.attr(dataAnnotation$1)).bind(registry2.lookup);
      const removeDirectAnnotation2 = (node) => {
        var _a, _b;
        node.attr(dataAnnotationId(), null);
        node.attr(dataAnnotation(), null);
        node.attr(dataAnnotationActive(), null);
        const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map((names) => names.split(",")).getOr([]);
        const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map((names) => names.split(",")).getOr([]);
        each$f(customAttrNames, (name2) => node.attr(name2, null));
        const classList = (_b = (_a = node.attr("class")) === null || _a === void 0 ? void 0 : _a.split(" ")) !== null && _b !== void 0 ? _b : [];
        const newClassList = difference(classList, [annotation()].concat(customClasses));
        node.attr("class", newClassList.length > 0 ? newClassList.join(" ") : null);
        node.attr(dataAnnotationClasses(), null);
        node.attr(dataAnnotationAttributes(), null);
      };
      editor.serializer.addTempAttr(dataAnnotationActive());
      editor.serializer.addAttributeFilter(dataAnnotation$1, (nodes) => {
        for (const node of nodes) {
          identifyParserNode(node).each((settings) => {
            if (settings.persistent === false) {
              if (node.name === "span") {
                node.unwrap();
              } else {
                removeDirectAnnotation2(node);
              }
            }
          });
        }
      });
    };
    const create$c = () => {
      const annotations = {};
      const register2 = (name2, settings) => {
        annotations[name2] = {
          name: name2,
          settings
        };
      };
      const lookup2 = (name2) => get$a(annotations, name2).map((a) => a.settings);
      const getNames = () => keys(annotations);
      return {
        register: register2,
        lookup: lookup2,
        getNames
      };
    };
    let unique2 = 0;
    const generate$1 = (prefix) => {
      const date = new Date();
      const time = date.getTime();
      const random = Math.floor(Math.random() * 1e9);
      unique2++;
      return prefix + "_" + random + unique2 + String(time);
    };
    const add = (element, classes) => {
      each$f(classes, (x) => {
        add$2(element, x);
      });
    };
    const remove$5 = (element, classes) => {
      each$f(classes, (x) => {
        remove$8(element, x);
      });
    };
    const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
    const shallow$1 = (original) => clone$2(original, false);
    const deep$1 = (original) => clone$2(original, true);
    const shallowAs = (original, tag) => {
      const nu2 = SugarElement.fromTag(tag);
      const attributes = clone$4(original);
      setAll$1(nu2, attributes);
      return nu2;
    };
    const mutate = (original, tag) => {
      const nu2 = shallowAs(original, tag);
      after$4(original, nu2);
      const children$1 = children(original);
      append(nu2, children$1);
      remove$6(original);
      return nu2;
    };
    const TextWalker = (startNode, rootNode, isBoundary2 = never) => {
      const walker = new DomTreeWalker(startNode, rootNode);
      const walk2 = (direction) => {
        let next2;
        do {
          next2 = walker[direction]();
        } while (next2 && !isText$9(next2) && !isBoundary2(next2));
        return Optional.from(next2).filter(isText$9);
      };
      return {
        current: () => Optional.from(walker.current()).filter(isText$9),
        next: () => walk2("next"),
        prev: () => walk2("prev"),
        prev2: () => walk2("prev2")
      };
    };
    const TextSeeker = (dom2, isBoundary2) => {
      const isBlockBoundary = isBoundary2 ? isBoundary2 : (node) => dom2.isBlock(node) || isBr$6(node) || isContentEditableFalse$b(node);
      const walk2 = (node, offset, walker, process2) => {
        if (isText$9(node)) {
          const newOffset = process2(node, offset, node.data);
          if (newOffset !== -1) {
            return Optional.some({
              container: node,
              offset: newOffset
            });
          }
        }
        return walker().bind((next2) => walk2(next2.container, next2.offset, walker, process2));
      };
      const backwards = (node, offset, process2, root) => {
        const walker = TextWalker(node, root, isBlockBoundary);
        return walk2(node, offset, () => walker.prev().map((prev2) => ({
          container: prev2,
          offset: prev2.length
        })), process2).getOrNull();
      };
      const forwards = (node, offset, process2, root) => {
        const walker = TextWalker(node, root, isBlockBoundary);
        return walk2(node, offset, () => walker.next().map((next2) => ({
          container: next2,
          offset: 0
        })), process2).getOrNull();
      };
      return {
        backwards,
        forwards
      };
    };
    const round$2 = Math.round;
    const clone$1 = (rect) => {
      if (!rect) {
        return {
          left: 0,
          top: 0,
          bottom: 0,
          right: 0,
          width: 0,
          height: 0
        };
      }
      return {
        left: round$2(rect.left),
        top: round$2(rect.top),
        bottom: round$2(rect.bottom),
        right: round$2(rect.right),
        width: round$2(rect.width),
        height: round$2(rect.height)
      };
    };
    const collapse = (rect, toStart) => {
      rect = clone$1(rect);
      if (toStart) {
        rect.right = rect.left;
      } else {
        rect.left = rect.left + rect.width;
        rect.right = rect.left;
      }
      rect.width = 0;
      return rect;
    };
    const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
    const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
    const isAbove$1 = (rect1, rect2) => {
      const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
      if (rect1.bottom - halfHeight < rect2.top) {
        return true;
      }
      if (rect1.top > rect2.bottom) {
        return false;
      }
      return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
    };
    const isBelow$1 = (rect1, rect2) => {
      if (rect1.top > rect2.bottom) {
        return true;
      }
      if (rect1.bottom < rect2.top) {
        return false;
      }
      return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
    };
    const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
    const boundingClientRectFromRects = (rects) => {
      return foldl(rects, (acc, rect) => {
        return acc.fold(() => Optional.some(rect), (prevRect) => {
          const left = Math.min(rect.left, prevRect.left);
          const top = Math.min(rect.top, prevRect.top);
          const right = Math.max(rect.right, prevRect.right);
          const bottom = Math.max(rect.bottom, prevRect.bottom);
          return Optional.some({
            top,
            right,
            bottom,
            left,
            width: right - left,
            height: bottom - top
          });
        });
      }, Optional.none());
    };
    const distanceToRectEdgeFromXY = (rect, x, y) => {
      const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
      const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
      return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
    };
    const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
    const clamp$2 = (value2, min2, max2) => Math.min(Math.max(value2, min2), max2);
    const getSelectedNode = (range2) => {
      const startContainer = range2.startContainer, startOffset = range2.startOffset;
      if (startContainer === range2.endContainer && startContainer.hasChildNodes() && range2.endOffset === startOffset + 1) {
        return startContainer.childNodes[startOffset];
      }
      return null;
    };
    const getNode$1 = (container, offset) => {
      if (isElement$6(container) && container.hasChildNodes()) {
        const childNodes = container.childNodes;
        const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
        return childNodes[safeOffset];
      } else {
        return container;
      }
    };
    const getNodeUnsafe = (container, offset) => {
      if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
        return void 0;
      } else {
        return getNode$1(container, offset);
      }
    };
    const extendingChars = new RegExp("[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E3-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962-\u0963\u0981\u09BC\u09BE\u09C1-\u09C4\u09CD\u09D7\u09E2-\u09E3\u0A01-\u0A02\u0A3C\u0A41-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A51\u0A70-\u0A71\u0A75\u0A81-\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7-\u0AC8\u0ACD\u0AE2-\u0AE3\u0B01\u0B3C\u0B3E\u0B3F\u0B41-\u0B44\u0B4D\u0B56\u0B57\u0B62-\u0B63\u0B82\u0BBE\u0BC0\u0BCD\u0BD7\u0C00\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C62-\u0C63\u0C81\u0CBC\u0CBF\u0CC2\u0CC6\u0CCC-\u0CCD\u0CD5-\u0CD6\u0CE2-\u0CE3\u0D01\u0D3E\u0D41-\u0D44\u0D4D\u0D57\u0D62-\u0D63\u0DCA\u0DCF\u0DD2-\u0DD4\u0DD6\u0DDF\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD\u0F18-\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86-\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039-\u103A\u103D-\u103E\u1058-\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085-\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17B4-\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193B\u1A17-\u1A18\u1A1B\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1AB0-\u1ABD\u1ABE\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80-\u1B81\u1BA2-\u1BA5\u1BA8-\u1BA9\u1BAB-\u1BAD\u1BE6\u1BE8-\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1CF8-\u1CF9\u1DC0-\u1DF5\u1DFC-\u1DFF\u200C-\u200D\u20D0-\u20DC\u20DD-\u20E0\u20E1\u20E2-\u20E4\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u302E-\u302F\u3099-\u309A\uA66F\uA670-\uA672\uA674-\uA67D\uA69E-\uA69F\uA6F0-\uA6F1\uA802\uA806\uA80B\uA825-\uA826\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uA9E5\uAA29-\uAA2E\uAA31-\uAA32\uAA35-\uAA36\uAA43\uAA4C\uAA7C\uAAB0\uAAB2-\uAAB4\uAAB7-\uAAB8\uAABE-\uAABF\uAAC1\uAAEC-\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE2F\uFF9E-\uFF9F]");
    const isExtendingChar = (ch) => typeof ch === "string" && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
    const or = (...args) => {
      return (x) => {
        for (let i = 0; i < args.length; i++) {
          if (args[i](x)) {
            return true;
          }
        }
        return false;
      };
    };
    const and = (...args) => {
      return (x) => {
        for (let i = 0; i < args.length; i++) {
          if (!args[i](x)) {
            return false;
          }
        }
        return true;
      };
    };
    const isElement$4 = isElement$6;
    const isCaretCandidate$2 = isCaretCandidate$3;
    const isBlock$1 = matchStyleValues("display", "block table");
    const isFloated = matchStyleValues("float", "left right");
    const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
    const isNotPre = not(matchStyleValues("white-space", "pre pre-line pre-wrap"));
    const isText$6 = isText$9;
    const isBr$3 = isBr$6;
    const nodeIndex$1 = DOMUtils.nodeIndex;
    const resolveIndex$1 = getNodeUnsafe;
    const createRange$1 = (doc) => "createRange" in doc ? doc.createRange() : DOMUtils.DOM.createRng();
    const isWhiteSpace$1 = (chr) => chr && /[\r\n\t ]/.test(chr);
    const isRange = (rng) => !!rng.setStart && !!rng.setEnd;
    const isHiddenWhiteSpaceRange = (range2) => {
      const container = range2.startContainer;
      const offset = range2.startOffset;
      if (isWhiteSpace$1(range2.toString()) && isNotPre(container.parentNode) && isText$9(container)) {
        const text2 = container.data;
        if (isWhiteSpace$1(text2[offset - 1]) || isWhiteSpace$1(text2[offset + 1])) {
          return true;
        }
      }
      return false;
    };
    const getBrClientRect = (brNode) => {
      const doc = brNode.ownerDocument;
      const rng = createRange$1(doc);
      const nbsp$1 = doc.createTextNode(nbsp);
      const parentNode = brNode.parentNode;
      parentNode.insertBefore(nbsp$1, brNode);
      rng.setStart(nbsp$1, 0);
      rng.setEnd(nbsp$1, 1);
      const clientRect = clone$1(rng.getBoundingClientRect());
      parentNode.removeChild(nbsp$1);
      return clientRect;
    };
    const getBoundingClientRectWebKitText = (rng) => {
      const sc = rng.startContainer;
      const ec = rng.endContainer;
      const so = rng.startOffset;
      const eo = rng.endOffset;
      if (sc === ec && isText$9(ec) && so === 0 && eo === 1) {
        const newRng = rng.cloneRange();
        newRng.setEndAfter(ec);
        return getBoundingClientRect$1(newRng);
      } else {
        return null;
      }
    };
    const isZeroRect = (r2) => r2.left === 0 && r2.right === 0 && r2.top === 0 && r2.bottom === 0;
    const getBoundingClientRect$1 = (item) => {
      let clientRect;
      const clientRects = item.getClientRects();
      if (clientRects.length > 0) {
        clientRect = clone$1(clientRects[0]);
      } else {
        clientRect = clone$1(item.getBoundingClientRect());
      }
      if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
        return getBrClientRect(item);
      }
      if (isZeroRect(clientRect) && isRange(item)) {
        return getBoundingClientRectWebKitText(item);
      }
      return clientRect;
    };
    const collapseAndInflateWidth = (clientRect, toStart) => {
      const newClientRect = collapse(clientRect, toStart);
      newClientRect.width = 1;
      newClientRect.right = newClientRect.left + 1;
      return newClientRect;
    };
    const getCaretPositionClientRects = (caretPosition) => {
      const clientRects = [];
      const addUniqueAndValidRect = (clientRect) => {
        if (clientRect.height === 0) {
          return;
        }
        if (clientRects.length > 0) {
          if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
            return;
          }
        }
        clientRects.push(clientRect);
      };
      const addCharacterOffset = (container2, offset2) => {
        const range2 = createRange$1(container2.ownerDocument);
        if (offset2 < container2.data.length) {
          if (isExtendingChar(container2.data[offset2])) {
            return clientRects;
          }
          if (isExtendingChar(container2.data[offset2 - 1])) {
            range2.setStart(container2, offset2);
            range2.setEnd(container2, offset2 + 1);
            if (!isHiddenWhiteSpaceRange(range2)) {
              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range2), false));
              return clientRects;
            }
          }
        }
        if (offset2 > 0) {
          range2.setStart(container2, offset2 - 1);
          range2.setEnd(container2, offset2);
          if (!isHiddenWhiteSpaceRange(range2)) {
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range2), false));
          }
        }
        if (offset2 < container2.data.length) {
          range2.setStart(container2, offset2);
          range2.setEnd(container2, offset2 + 1);
          if (!isHiddenWhiteSpaceRange(range2)) {
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range2), true));
          }
        }
      };
      const container = caretPosition.container();
      const offset = caretPosition.offset();
      if (isText$6(container)) {
        addCharacterOffset(container, offset);
        return clientRects;
      }
      if (isElement$4(container)) {
        if (caretPosition.isAtEnd()) {
          const node = resolveIndex$1(container, offset);
          if (isText$6(node)) {
            addCharacterOffset(node, node.data.length);
          }
          if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
          }
        } else {
          const node = resolveIndex$1(container, offset);
          if (isText$6(node)) {
            addCharacterOffset(node, 0);
          }
          if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
            return clientRects;
          }
          const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
          if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
            if (isBlock$1(beforeNode) || isBlock$1(node) || !isValidElementCaretCandidate(node)) {
              addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
            }
          }
          if (isValidElementCaretCandidate(node)) {
            addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
          }
        }
      }
      return clientRects;
    };
    const CaretPosition = (container, offset, clientRects) => {
      const isAtStart = () => {
        if (isText$6(container)) {
          return offset === 0;
        }
        return offset === 0;
      };
      const isAtEnd = () => {
        if (isText$6(container)) {
          return offset >= container.data.length;
        }
        return offset >= container.childNodes.length;
      };
      const toRange = () => {
        const range2 = createRange$1(container.ownerDocument);
        range2.setStart(container, offset);
        range2.setEnd(container, offset);
        return range2;
      };
      const getClientRects2 = () => {
        if (!clientRects) {
          clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
        }
        return clientRects;
      };
      const isVisible = () => getClientRects2().length > 0;
      const isEqual2 = (caretPosition) => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
      const getNode2 = (before2) => resolveIndex$1(container, before2 ? offset - 1 : offset);
      return {
        container: constant(container),
        offset: constant(offset),
        toRange,
        getClientRects: getClientRects2,
        isVisible,
        isAtStart,
        isAtEnd,
        isEqual: isEqual2,
        getNode: getNode2
      };
    };
    CaretPosition.fromRangeStart = (range2) => CaretPosition(range2.startContainer, range2.startOffset);
    CaretPosition.fromRangeEnd = (range2) => CaretPosition(range2.endContainer, range2.endOffset);
    CaretPosition.after = (node) => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
    CaretPosition.before = (node) => CaretPosition(node.parentNode, nodeIndex$1(node));
    CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$3(pos1.getClientRects()), isAbove$1).getOr(false);
    CaretPosition.isBelow = (pos1, pos2) => lift2(last$3(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
    CaretPosition.isAtStart = (pos) => pos ? pos.isAtStart() : false;
    CaretPosition.isAtEnd = (pos) => pos ? pos.isAtEnd() : false;
    CaretPosition.isTextPosition = (pos) => pos ? isText$9(pos.container()) : false;
    CaretPosition.isElementPosition = (pos) => CaretPosition.isTextPosition(pos) === false;
    const trimEmptyTextNode$1 = (dom2, node) => {
      if (isText$9(node) && node.data.length === 0) {
        dom2.remove(node);
      }
    };
    const insertNode = (dom2, rng, node) => {
      rng.insertNode(node);
      trimEmptyTextNode$1(dom2, node.previousSibling);
      trimEmptyTextNode$1(dom2, node.nextSibling);
    };
    const insertFragment = (dom2, rng, frag) => {
      const firstChild2 = Optional.from(frag.firstChild);
      const lastChild2 = Optional.from(frag.lastChild);
      rng.insertNode(frag);
      firstChild2.each((child2) => trimEmptyTextNode$1(dom2, child2.previousSibling));
      lastChild2.each((child2) => trimEmptyTextNode$1(dom2, child2.nextSibling));
    };
    const rangeInsertNode = (dom2, rng, node) => {
      if (isDocumentFragment(node)) {
        insertFragment(dom2, rng, node);
      } else {
        insertNode(dom2, rng, node);
      }
    };
    const isText$5 = isText$9;
    const isBogus = isBogus$2;
    const nodeIndex = DOMUtils.nodeIndex;
    const normalizedParent = (node) => {
      const parentNode = node.parentNode;
      if (isBogus(parentNode)) {
        return normalizedParent(parentNode);
      }
      return parentNode;
    };
    const getChildNodes = (node) => {
      if (!node) {
        return [];
      }
      return reduce(node.childNodes, (result, node2) => {
        if (isBogus(node2) && node2.nodeName !== "BR") {
          result = result.concat(getChildNodes(node2));
        } else {
          result.push(node2);
        }
        return result;
      }, []);
    };
    const normalizedTextOffset = (node, offset) => {
      while (node = node.previousSibling) {
        if (!isText$5(node)) {
          break;
        }
        offset += node.data.length;
      }
      return offset;
    };
    const equal = (a) => (b) => a === b;
    const normalizedNodeIndex = (node) => {
      let nodes, index2;
      nodes = getChildNodes(normalizedParent(node));
      index2 = findIndex$1(nodes, equal(node), node);
      nodes = nodes.slice(0, index2 + 1);
      const numTextFragments = reduce(nodes, (result, node2, i) => {
        if (isText$5(node2) && isText$5(nodes[i - 1])) {
          result++;
        }
        return result;
      }, 0);
      nodes = filter$4(nodes, matchNodeNames([node.nodeName]));
      index2 = findIndex$1(nodes, equal(node), node);
      return index2 - numTextFragments;
    };
    const createPathItem = (node) => {
      let name2;
      if (isText$5(node)) {
        name2 = "text()";
      } else {
        name2 = node.nodeName.toLowerCase();
      }
      return name2 + "[" + normalizedNodeIndex(node) + "]";
    };
    const parentsUntil$1 = (root, node, predicate) => {
      const parents2 = [];
      for (node = node.parentNode; node !== root; node = node.parentNode) {
        if (predicate && predicate(node)) {
          break;
        }
        parents2.push(node);
      }
      return parents2;
    };
    const create$b = (root, caretPosition) => {
      let container, offset, path = [], outputOffset, childNodes, parents2;
      container = caretPosition.container();
      offset = caretPosition.offset();
      if (isText$5(container)) {
        outputOffset = normalizedTextOffset(container, offset);
      } else {
        childNodes = container.childNodes;
        if (offset >= childNodes.length) {
          outputOffset = "after";
          offset = childNodes.length - 1;
        } else {
          outputOffset = "before";
        }
        container = childNodes[offset];
      }
      path.push(createPathItem(container));
      parents2 = parentsUntil$1(root, container);
      parents2 = filter$4(parents2, not(isBogus$2));
      path = path.concat(map$1(parents2, (node) => {
        return createPathItem(node);
      }));
      return path.reverse().join("/") + "," + outputOffset;
    };
    const resolvePathItem = (node, name2, index2) => {
      let nodes = getChildNodes(node);
      nodes = filter$4(nodes, (node2, index3) => {
        return !isText$5(node2) || !isText$5(nodes[index3 - 1]);
      });
      nodes = filter$4(nodes, matchNodeNames([name2]));
      return nodes[index2];
    };
    const findTextPosition = (container, offset) => {
      let node = container, targetOffset = 0, dataLen;
      while (isText$5(node)) {
        dataLen = node.data.length;
        if (offset >= targetOffset && offset <= targetOffset + dataLen) {
          container = node;
          offset = offset - targetOffset;
          break;
        }
        if (!isText$5(node.nextSibling)) {
          container = node;
          offset = dataLen;
          break;
        }
        targetOffset += dataLen;
        node = node.nextSibling;
      }
      if (isText$5(container) && offset > container.data.length) {
        offset = container.data.length;
      }
      return CaretPosition(container, offset);
    };
    const resolve$1 = (root, path) => {
      let offset;
      if (!path) {
        return null;
      }
      const parts = path.split(",");
      const paths = parts[0].split("/");
      offset = parts.length > 1 ? parts[1] : "before";
      const container = reduce(paths, (result, value2) => {
        const match2 = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value2);
        if (!match2) {
          return null;
        }
        if (match2[1] === "text()") {
          match2[1] = "#text";
        }
        return resolvePathItem(result, match2[1], parseInt(match2[2], 10));
      }, root);
      if (!container) {
        return null;
      }
      if (!isText$5(container)) {
        if (offset === "after") {
          offset = nodeIndex(container) + 1;
        } else {
          offset = nodeIndex(container);
        }
        return CaretPosition(container.parentNode, offset);
      }
      return findTextPosition(container, parseInt(offset, 10));
    };
    const isContentEditableFalse$9 = isContentEditableFalse$b;
    const getNormalizedTextOffset = (trim2, container, offset) => {
      let node, trimmedOffset;
      trimmedOffset = trim2(container.data.slice(0, offset)).length;
      for (node = container.previousSibling; node && isText$9(node); node = node.previousSibling) {
        trimmedOffset += trim2(node.data).length;
      }
      return trimmedOffset;
    };
    const getPoint = (dom2, trim2, normalized, rng, start2) => {
      let container = rng[start2 ? "startContainer" : "endContainer"];
      let offset = rng[start2 ? "startOffset" : "endOffset"];
      const point2 = [];
      let childNodes, after2 = 0;
      const root = dom2.getRoot();
      if (isText$9(container)) {
        point2.push(normalized ? getNormalizedTextOffset(trim2, container, offset) : offset);
      } else {
        childNodes = container.childNodes;
        if (offset >= childNodes.length && childNodes.length) {
          after2 = 1;
          offset = Math.max(0, childNodes.length - 1);
        }
        point2.push(dom2.nodeIndex(childNodes[offset], normalized) + after2);
      }
      for (; container && container !== root; container = container.parentNode) {
        point2.push(dom2.nodeIndex(container, normalized));
      }
      return point2;
    };
    const getLocation = (trim2, selection, normalized, rng) => {
      const dom2 = selection.dom;
      const start2 = getPoint(dom2, trim2, normalized, rng, true);
      const forward = selection.isForward();
      const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
      if (!selection.isCollapsed()) {
        const end2 = getPoint(dom2, trim2, normalized, rng, false);
        return {
          start: start2,
          end: end2,
          forward,
          ...fakeCaret
        };
      } else {
        return {
          start: start2,
          forward,
          ...fakeCaret
        };
      }
    };
    const findIndex = (dom2, name2, element) => {
      let count2 = 0;
      Tools.each(dom2.select(name2), (node) => {
        if (node.getAttribute("data-mce-bogus") === "all") {
          return;
        }
        if (node === element) {
          return false;
        }
        count2++;
      });
      return count2;
    };
    const moveEndPoint$1 = (rng, start2) => {
      let container, offset;
      const prefix = start2 ? "start" : "end";
      container = rng[prefix + "Container"];
      offset = rng[prefix + "Offset"];
      if (isElement$6(container) && container.nodeName === "TR") {
        const childNodes = container.childNodes;
        container = childNodes[Math.min(start2 ? offset : offset - 1, childNodes.length - 1)];
        if (container) {
          offset = start2 ? 0 : container.childNodes.length;
          rng["set" + (start2 ? "Start" : "End")](container, offset);
        }
      }
    };
    const normalizeTableCellSelection = (rng) => {
      moveEndPoint$1(rng, true);
      moveEndPoint$1(rng, false);
      return rng;
    };
    const findSibling = (node, offset) => {
      let sibling2;
      if (isElement$6(node)) {
        node = getNode$1(node, offset);
        if (isContentEditableFalse$9(node)) {
          return node;
        }
      }
      if (isCaretContainer$2(node)) {
        if (isText$9(node) && isCaretContainerBlock$1(node)) {
          node = node.parentNode;
        }
        sibling2 = node.previousSibling;
        if (isContentEditableFalse$9(sibling2)) {
          return sibling2;
        }
        sibling2 = node.nextSibling;
        if (isContentEditableFalse$9(sibling2)) {
          return sibling2;
        }
      }
    };
    const findAdjacentContentEditableFalseElm = (rng) => {
      return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
    };
    const getOffsetBookmark = (trim2, normalized, selection) => {
      const element = selection.getNode();
      let name2 = element ? element.nodeName : null;
      const rng = selection.getRng();
      if (isContentEditableFalse$9(element) || name2 === "IMG") {
        return {
          name: name2,
          index: findIndex(selection.dom, name2, element)
        };
      }
      const sibling2 = findAdjacentContentEditableFalseElm(rng);
      if (sibling2) {
        name2 = sibling2.tagName;
        return {
          name: name2,
          index: findIndex(selection.dom, name2, sibling2)
        };
      }
      return getLocation(trim2, selection, normalized, rng);
    };
    const getCaretBookmark = (selection) => {
      const rng = selection.getRng();
      return {
        start: create$b(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
        end: create$b(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
        forward: selection.isForward()
      };
    };
    const getRangeBookmark = (selection) => {
      return {
        rng: selection.getRng(),
        forward: selection.isForward()
      };
    };
    const createBookmarkSpan = (dom2, id, filled) => {
      const args = {
        "data-mce-type": "bookmark",
        id,
        "style": "overflow:hidden;line-height:0px"
      };
      return filled ? dom2.create("span", args, "&#xFEFF;") : dom2.create("span", args);
    };
    const getPersistentBookmark = (selection, filled) => {
      const dom2 = selection.dom;
      let rng = selection.getRng();
      const id = dom2.uniqueId();
      const collapsed = selection.isCollapsed();
      const element = selection.getNode();
      const name2 = element.nodeName;
      const forward = selection.isForward();
      if (name2 === "IMG") {
        return {
          name: name2,
          index: findIndex(dom2, name2, element)
        };
      }
      const rng2 = normalizeTableCellSelection(rng.cloneRange());
      if (!collapsed) {
        rng2.collapse(false);
        const endBookmarkNode = createBookmarkSpan(dom2, id + "_end", filled);
        rangeInsertNode(dom2, rng2, endBookmarkNode);
      }
      rng = normalizeTableCellSelection(rng);
      rng.collapse(true);
      const startBookmarkNode = createBookmarkSpan(dom2, id + "_start", filled);
      rangeInsertNode(dom2, rng, startBookmarkNode);
      selection.moveToBookmark({
        id,
        keep: true,
        forward
      });
      return {
        id,
        forward
      };
    };
    const getBookmark$2 = (selection, type2, normalized) => {
      if (type2 === 2) {
        return getOffsetBookmark(trim$1, normalized, selection);
      } else if (type2 === 3) {
        return getCaretBookmark(selection);
      } else if (type2) {
        return getRangeBookmark(selection);
      } else {
        return getPersistentBookmark(selection, false);
      }
    };
    const getUndoBookmark = curry(getOffsetBookmark, identity, true);
    const value$1 = (value2) => {
      const applyHelper = (fn) => fn(value2);
      const constHelper = constant(value2);
      const outputHelper = () => output;
      const output = {
        tag: true,
        inner: value2,
        fold: (_onError, onValue) => onValue(value2),
        isValue: always,
        isError: never,
        map: (mapper) => Result.value(mapper(value2)),
        mapError: outputHelper,
        bind: applyHelper,
        exists: applyHelper,
        forall: applyHelper,
        getOr: constHelper,
        or: outputHelper,
        getOrThunk: constHelper,
        orThunk: outputHelper,
        getOrDie: constHelper,
        each: (fn) => {
          fn(value2);
        },
        toOptional: () => Optional.some(value2)
      };
      return output;
    };
    const error = (error2) => {
      const outputHelper = () => output;
      const output = {
        tag: false,
        inner: error2,
        fold: (onError, _onValue) => onError(error2),
        isValue: never,
        isError: always,
        map: outputHelper,
        mapError: (mapper) => Result.error(mapper(error2)),
        bind: outputHelper,
        exists: never,
        forall: always,
        getOr: identity,
        or: identity,
        getOrThunk: apply$1,
        orThunk: apply$1,
        getOrDie: die(String(error2)),
        each: noop,
        toOptional: Optional.none
      };
      return output;
    };
    const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
    const Result = {
      value: value$1,
      error,
      fromOption
    };
    const generate = (cases) => {
      if (!isArray$1(cases)) {
        throw new Error("cases must be an array");
      }
      if (cases.length === 0) {
        throw new Error("there must be at least one case");
      }
      const constructors = [];
      const adt2 = {};
      each$f(cases, (acase, count2) => {
        const keys$1 = keys(acase);
        if (keys$1.length !== 1) {
          throw new Error("one and only one name per case");
        }
        const key = keys$1[0];
        const value2 = acase[key];
        if (adt2[key] !== void 0) {
          throw new Error("duplicate key detected:" + key);
        } else if (key === "cata") {
          throw new Error("cannot have a case named cata (sorry)");
        } else if (!isArray$1(value2)) {
          throw new Error("case arguments must be an array");
        }
        constructors.push(key);
        adt2[key] = (...args) => {
          const argLength = args.length;
          if (argLength !== value2.length) {
            throw new Error("Wrong number of arguments to case " + key + ". Expected " + value2.length + " (" + value2 + "), got " + argLength);
          }
          const match2 = (branches) => {
            const branchKeys = keys(branches);
            if (constructors.length !== branchKeys.length) {
              throw new Error("Wrong number of arguments to match. Expected: " + constructors.join(",") + "\nActual: " + branchKeys.join(","));
            }
            const allReqd = forall(constructors, (reqKey) => {
              return contains$2(branchKeys, reqKey);
            });
            if (!allReqd) {
              throw new Error("Not all branches were specified when using match. Specified: " + branchKeys.join(", ") + "\nRequired: " + constructors.join(", "));
            }
            return branches[key].apply(null, args);
          };
          return {
            fold: (...foldArgs) => {
              if (foldArgs.length !== cases.length) {
                throw new Error("Wrong number of arguments to fold. Expected " + cases.length + ", got " + foldArgs.length);
              }
              const target = foldArgs[count2];
              return target.apply(null, args);
            },
            match: match2,
            log: (label) => {
              console.log(label, {
                constructors,
                constructor: key,
                params: args
              });
            }
          };
        };
      });
      return adt2;
    };
    const Adt = { generate };
    Adt.generate([
      {
        bothErrors: [
          "error1",
          "error2"
        ]
      },
      {
        firstError: [
          "error1",
          "value2"
        ]
      },
      {
        secondError: [
          "value1",
          "error2"
        ]
      },
      {
        bothValues: [
          "value1",
          "value2"
        ]
      }
    ]);
    const partition$1 = (results) => {
      const errors = [];
      const values2 = [];
      each$f(results, (result) => {
        result.fold((err) => {
          errors.push(err);
        }, (value2) => {
          values2.push(value2);
        });
      });
      return {
        errors,
        values: values2
      };
    };
    const isInlinePattern = (pattern) => pattern.type === "inline-command" || pattern.type === "inline-format";
    const isBlockPattern = (pattern) => pattern.type === "block-command" || pattern.type === "block-format";
    const sortPatterns = (patterns) => sort(patterns, (a, b) => {
      if (a.start.length === b.start.length) {
        return 0;
      }
      return a.start.length > b.start.length ? -1 : 1;
    });
    const normalizePattern = (pattern) => {
      const err = (message) => Result.error({
        message,
        pattern
      });
      const formatOrCmd = (name2, onFormat, onCommand) => {
        if (pattern.format !== void 0) {
          let formats;
          if (isArray$1(pattern.format)) {
            if (!forall(pattern.format, isString)) {
              return err(name2 + " pattern has non-string items in the `format` array");
            }
            formats = pattern.format;
          } else if (isString(pattern.format)) {
            formats = [pattern.format];
          } else {
            return err(name2 + " pattern has non-string `format` parameter");
          }
          return Result.value(onFormat(formats));
        } else if (pattern.cmd !== void 0) {
          if (!isString(pattern.cmd)) {
            return err(name2 + " pattern has non-string `cmd` parameter");
          }
          return Result.value(onCommand(pattern.cmd, pattern.value));
        } else {
          return err(name2 + " pattern is missing both `format` and `cmd` parameters");
        }
      };
      if (!isObject(pattern)) {
        return err("Raw pattern is not an object");
      }
      if (!isString(pattern.start)) {
        return err("Raw pattern is missing `start` parameter");
      }
      if (pattern.end !== void 0) {
        if (!isString(pattern.end)) {
          return err("Inline pattern has non-string `end` parameter");
        }
        if (pattern.start.length === 0 && pattern.end.length === 0) {
          return err("Inline pattern has empty `start` and `end` parameters");
        }
        let start2 = pattern.start;
        let end2 = pattern.end;
        if (end2.length === 0) {
          end2 = start2;
          start2 = "";
        }
        return formatOrCmd("Inline", (format) => ({
          type: "inline-format",
          start: start2,
          end: end2,
          format
        }), (cmd, value2) => ({
          type: "inline-command",
          start: start2,
          end: end2,
          cmd,
          value: value2
        }));
      } else if (pattern.replacement !== void 0) {
        if (!isString(pattern.replacement)) {
          return err("Replacement pattern has non-string `replacement` parameter");
        }
        if (pattern.start.length === 0) {
          return err("Replacement pattern has empty `start` parameter");
        }
        return Result.value({
          type: "inline-command",
          start: "",
          end: pattern.start,
          cmd: "mceInsertContent",
          value: pattern.replacement
        });
      } else {
        if (pattern.start.length === 0) {
          return err("Block pattern has empty `start` parameter");
        }
        return formatOrCmd("Block", (formats) => ({
          type: "block-format",
          start: pattern.start,
          format: formats[0]
        }), (command, commandValue) => ({
          type: "block-command",
          start: pattern.start,
          cmd: command,
          value: commandValue
        }));
      }
    };
    const getBlockPatterns = (patterns) => sortPatterns(filter$6(patterns, isBlockPattern));
    const getInlinePatterns = (patterns) => filter$6(patterns, isInlinePattern);
    const createPatternSet = (patterns) => ({
      inlinePatterns: getInlinePatterns(patterns),
      blockPatterns: getBlockPatterns(patterns)
    });
    const fromRawPatterns = (patterns) => {
      const normalized = partition$1(map$3(patterns, normalizePattern));
      each$f(normalized.errors, (err) => console.error(err.message, err.pattern));
      return normalized.values;
    };
    const deviceDetection$1 = detect$2().deviceType;
    const isTouch = deviceDetection$1.isTouch();
    const DOM$a = DOMUtils.DOM;
    const getHash = (value2) => {
      const items = value2.indexOf("=") > 0 ? value2.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value2.split(",");
      return foldl(items, (output, item) => {
        const arr = item.split("=");
        const key = arr[0];
        const val = arr.length > 1 ? arr[1] : key;
        output[trim$3(key)] = trim$3(val);
        return output;
      }, {});
    };
    const isRegExp = (x) => is$4(x, RegExp);
    const option = (name2) => (editor) => editor.options.get(name2);
    const stringOrObjectProcessor = (value2) => isString(value2) || isObject(value2);
    const bodyOptionProcessor = (editor, defaultValue = "") => (value2) => {
      const valid = isString(value2);
      if (valid) {
        if (value2.indexOf("=") !== -1) {
          const bodyObj = getHash(value2);
          return {
            value: get$a(bodyObj, editor.id).getOr(defaultValue),
            valid
          };
        } else {
          return {
            value: value2,
            valid
          };
        }
      } else {
        return {
          valid: false,
          message: "Must be a string."
        };
      }
    };
    const register$7 = (editor) => {
      const registerOption = editor.options.register;
      registerOption("id", {
        processor: "string",
        default: editor.id
      });
      registerOption("selector", { processor: "string" });
      registerOption("target", { processor: "object" });
      registerOption("suffix", { processor: "string" });
      registerOption("cache_suffix", { processor: "string" });
      registerOption("base_url", { processor: "string" });
      registerOption("referrer_policy", {
        processor: "string",
        default: ""
      });
      registerOption("language_load", { processor: "boolean" });
      registerOption("inline", {
        processor: "boolean",
        default: false
      });
      registerOption("iframe_attrs", {
        processor: "object",
        default: {}
      });
      registerOption("doctype", {
        processor: "string",
        default: "<!DOCTYPE html>"
      });
      registerOption("document_base_url", {
        processor: "string",
        default: editor.documentBaseUrl
      });
      registerOption("body_id", {
        processor: bodyOptionProcessor(editor, "tinymce"),
        default: "tinymce"
      });
      registerOption("body_class", {
        processor: bodyOptionProcessor(editor),
        default: ""
      });
      registerOption("content_security_policy", {
        processor: "string",
        default: ""
      });
      registerOption("br_in_pre", {
        processor: "boolean",
        default: true
      });
      registerOption("forced_root_block", {
        processor: (value2) => {
          const valid = isString(value2) && isNotEmpty(value2);
          if (valid) {
            return {
              value: value2,
              valid
            };
          } else {
            return {
              valid: false,
              message: "Must be a non-empty string."
            };
          }
        },
        default: "p"
      });
      registerOption("forced_root_block_attrs", {
        processor: "object",
        default: {}
      });
      registerOption("newline_behavior", {
        processor: (value2) => {
          const valid = contains$2([
            "block",
            "linebreak",
            "invert",
            "default"
          ], value2);
          return valid ? {
            value: value2,
            valid
          } : {
            valid: false,
            message: "Must be one of: block, linebreak, invert or default."
          };
        },
        default: "default"
      });
      registerOption("br_newline_selector", {
        processor: "string",
        default: ".mce-toc h2,figcaption,caption"
      });
      registerOption("no_newline_selector", {
        processor: "string",
        default: ""
      });
      registerOption("keep_styles", {
        processor: "boolean",
        default: true
      });
      registerOption("end_container_on_empty_block", {
        processor: (value2) => {
          if (isBoolean(value2)) {
            return {
              valid: true,
              value: value2
            };
          } else if (isString(value2)) {
            return {
              valid: true,
              value: value2
            };
          } else {
            return {
              valid: false,
              message: "Must be boolean or a string"
            };
          }
        },
        default: "blockquote"
      });
      registerOption("font_size_style_values", {
        processor: "string",
        default: "xx-small,x-small,small,medium,large,x-large,xx-large"
      });
      registerOption("font_size_legacy_values", {
        processor: "string",
        default: "xx-small,small,medium,large,x-large,xx-large,300%"
      });
      registerOption("font_size_classes", {
        processor: "string",
        default: ""
      });
      registerOption("automatic_uploads", {
        processor: "boolean",
        default: true
      });
      registerOption("images_reuse_filename", {
        processor: "boolean",
        default: false
      });
      registerOption("images_replace_blob_uris", {
        processor: "boolean",
        default: true
      });
      registerOption("icons", {
        processor: "string",
        default: ""
      });
      registerOption("icons_url", {
        processor: "string",
        default: ""
      });
      registerOption("images_upload_url", {
        processor: "string",
        default: ""
      });
      registerOption("images_upload_base_path", {
        processor: "string",
        default: ""
      });
      registerOption("images_upload_base_path", {
        processor: "string",
        default: ""
      });
      registerOption("images_upload_credentials", {
        processor: "boolean",
        default: false
      });
      registerOption("images_upload_handler", { processor: "function" });
      registerOption("language", {
        processor: "string",
        default: "en"
      });
      registerOption("language_url", {
        processor: "string",
        default: ""
      });
      registerOption("entity_encoding", {
        processor: "string",
        default: "named"
      });
      registerOption("indent", {
        processor: "boolean",
        default: true
      });
      registerOption("indent_before", {
        processor: "string",
        default: "p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist"
      });
      registerOption("indent_after", {
        processor: "string",
        default: "p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist"
      });
      registerOption("indent_use_margin", {
        processor: "boolean",
        default: false
      });
      registerOption("indentation", {
        processor: "string",
        default: "40px"
      });
      registerOption("content_css", {
        processor: (value2) => {
          const valid = value2 === false || isString(value2) || isArrayOf(value2, isString);
          if (valid) {
            if (isString(value2)) {
              return {
                value: map$3(value2.split(","), trim$3),
                valid
              };
            } else if (isArray$1(value2)) {
              return {
                value: value2,
                valid
              };
            } else if (value2 === false) {
              return {
                value: [],
                valid
              };
            } else {
              return {
                value: value2,
                valid
              };
            }
          } else {
            return {
              valid: false,
              message: "Must be false, a string or an array of strings."
            };
          }
        },
        default: isInline(editor) ? [] : ["default"]
      });
      registerOption("content_style", { processor: "string" });
      registerOption("content_css_cors", {
        processor: "boolean",
        default: false
      });
      registerOption("font_css", {
        processor: (value2) => {
          const valid = isString(value2) || isArrayOf(value2, isString);
          if (valid) {
            const newValue = isArray$1(value2) ? value2 : map$3(value2.split(","), trim$3);
            return {
              value: newValue,
              valid
            };
          } else {
            return {
              valid: false,
              message: "Must be a string or an array of strings."
            };
          }
        },
        default: []
      });
      registerOption("inline_boundaries", {
        processor: "boolean",
        default: true
      });
      registerOption("inline_boundaries_selector", {
        processor: "string",
        default: "a[href],code,span.mce-annotation"
      });
      registerOption("object_resizing", {
        processor: (value2) => {
          const valid = isBoolean(value2) || isString(value2);
          if (valid) {
            if (value2 === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
              return {
                value: "",
                valid
              };
            } else {
              return {
                value: value2 === true ? "table,img,figure.image,div,video,iframe" : value2,
                valid
              };
            }
          } else {
            return {
              valid: false,
              message: "Must be boolean or a string"
            };
          }
        },
        default: !isTouch
      });
      registerOption("resize_img_proportional", {
        processor: "boolean",
        default: true
      });
      registerOption("event_root", { processor: "object" });
      registerOption("service_message", { processor: "string" });
      registerOption("theme", {
        processor: (value2) => value2 === false || isString(value2) || isFunction(value2),
        default: "silver"
      });
      registerOption("theme_url", { processor: "string" });
      registerOption("formats", { processor: "object" });
      registerOption("format_empty_lines", {
        processor: "boolean",
        default: false
      });
      registerOption("preview_styles", {
        processor: (value2) => {
          const valid = value2 === false || isString(value2);
          if (valid) {
            return {
              value: value2 === false ? "" : value2,
              valid
            };
          } else {
            return {
              valid: false,
              message: "Must be false or a string"
            };
          }
        },
        default: "font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow"
      });
      registerOption("custom_ui_selector", {
        processor: "string",
        default: ""
      });
      registerOption("hidden_input", {
        processor: "boolean",
        default: true
      });
      registerOption("submit_patch", {
        processor: "boolean",
        default: true
      });
      registerOption("encoding", { processor: "string" });
      registerOption("add_form_submit_trigger", {
        processor: "boolean",
        default: true
      });
      registerOption("add_unload_trigger", {
        processor: "boolean",
        default: true
      });
      registerOption("custom_undo_redo_levels", {
        processor: "number",
        default: 0
      });
      registerOption("disable_nodechange", {
        processor: "boolean",
        default: false
      });
      registerOption("readonly", {
        processor: "boolean",
        default: false
      });
      registerOption("plugins", {
        processor: "string[]",
        default: []
      });
      registerOption("external_plugins", { processor: "object" });
      registerOption("forced_plugins", { processor: "string[]" });
      registerOption("model", {
        processor: "string",
        default: editor.hasPlugin("rtc") ? "plugin" : "dom"
      });
      registerOption("model_url", { processor: "string" });
      registerOption("block_unsupported_drop", {
        processor: "boolean",
        default: true
      });
      registerOption("visual", {
        processor: "boolean",
        default: true
      });
      registerOption("visual_table_class", {
        processor: "string",
        default: "mce-item-table"
      });
      registerOption("visual_anchor_class", {
        processor: "string",
        default: "mce-item-anchor"
      });
      registerOption("iframe_aria_text", {
        processor: "string",
        default: "Rich Text Area. Press ALT-0 for help."
      });
      registerOption("setup", { processor: "function" });
      registerOption("init_instance_callback", { processor: "function" });
      registerOption("url_converter", {
        processor: "function",
        default: editor.convertURL
      });
      registerOption("url_converter_scope", {
        processor: "object",
        default: editor
      });
      registerOption("urlconverter_callback", { processor: "function" });
      registerOption("allow_conditional_comments", {
        processor: "boolean",
        default: false
      });
      registerOption("allow_html_data_urls", {
        processor: "boolean",
        default: false
      });
      registerOption("allow_svg_data_urls", { processor: "boolean" });
      registerOption("allow_html_in_named_anchor", {
        processor: "boolean",
        default: false
      });
      registerOption("allow_script_urls", {
        processor: "boolean",
        default: false
      });
      registerOption("allow_unsafe_link_target", {
        processor: "boolean",
        default: false
      });
      registerOption("convert_fonts_to_spans", {
        processor: "boolean",
        default: true,
        deprecated: true
      });
      registerOption("fix_list_elements", {
        processor: "boolean",
        default: false
      });
      registerOption("preserve_cdata", {
        processor: "boolean",
        default: false
      });
      registerOption("remove_trailing_brs", { processor: "boolean" });
      registerOption("inline_styles", {
        processor: "boolean",
        default: true,
        deprecated: true
      });
      registerOption("element_format", {
        processor: "string",
        default: "html"
      });
      registerOption("entities", { processor: "string" });
      registerOption("schema", {
        processor: "string",
        default: "html5"
      });
      registerOption("convert_urls", {
        processor: "boolean",
        default: true
      });
      registerOption("relative_urls", {
        processor: "boolean",
        default: true
      });
      registerOption("remove_script_host", {
        processor: "boolean",
        default: true
      });
      registerOption("custom_elements", { processor: "string" });
      registerOption("extended_valid_elements", { processor: "string" });
      registerOption("invalid_elements", { processor: "string" });
      registerOption("invalid_styles", { processor: stringOrObjectProcessor });
      registerOption("valid_children", { processor: "string" });
      registerOption("valid_classes", { processor: stringOrObjectProcessor });
      registerOption("valid_elements", { processor: "string" });
      registerOption("valid_styles", { processor: stringOrObjectProcessor });
      registerOption("verify_html", {
        processor: "boolean",
        default: true
      });
      registerOption("auto_focus", { processor: (value2) => isString(value2) || value2 === true });
      registerOption("browser_spellcheck", {
        processor: "boolean",
        default: false
      });
      registerOption("protect", { processor: "array" });
      registerOption("images_file_types", {
        processor: "string",
        default: "jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp"
      });
      registerOption("deprecation_warnings", {
        processor: "boolean",
        default: true
      });
      registerOption("a11y_advanced_options", {
        processor: "boolean",
        default: false
      });
      registerOption("api_key", { processor: "string" });
      registerOption("paste_block_drop", {
        processor: "boolean",
        default: false
      });
      registerOption("paste_data_images", {
        processor: "boolean",
        default: true
      });
      registerOption("paste_preprocess", { processor: "function" });
      registerOption("paste_postprocess", { processor: "function" });
      registerOption("paste_webkit_styles", {
        processor: "string",
        default: "none"
      });
      registerOption("paste_remove_styles_if_webkit", {
        processor: "boolean",
        default: true
      });
      registerOption("paste_merge_formats", {
        processor: "boolean",
        default: true
      });
      registerOption("smart_paste", {
        processor: "boolean",
        default: true
      });
      registerOption("paste_as_text", {
        processor: "boolean",
        default: false
      });
      registerOption("paste_tab_spaces", {
        processor: "number",
        default: 4
      });
      registerOption("text_patterns", {
        processor: (value2) => {
          if (isArrayOf(value2, isObject) || value2 === false) {
            const patterns = value2 === false ? [] : value2;
            return {
              value: fromRawPatterns(patterns),
              valid: true
            };
          } else {
            return {
              valid: false,
              message: "Must be an array of objects or false."
            };
          }
        },
        default: [
          {
            start: "*",
            end: "*",
            format: "italic"
          },
          {
            start: "**",
            end: "**",
            format: "bold"
          },
          {
            start: "#",
            format: "h1"
          },
          {
            start: "##",
            format: "h2"
          },
          {
            start: "###",
            format: "h3"
          },
          {
            start: "####",
            format: "h4"
          },
          {
            start: "#####",
            format: "h5"
          },
          {
            start: "######",
            format: "h6"
          },
          {
            start: "1. ",
            cmd: "InsertOrderedList"
          },
          {
            start: "* ",
            cmd: "InsertUnorderedList"
          },
          {
            start: "- ",
            cmd: "InsertUnorderedList"
          }
        ]
      });
      registerOption("noneditable_class", {
        processor: "string",
        default: "mceNonEditable"
      });
      registerOption("editable_class", {
        processor: "string",
        default: "mceEditable"
      });
      registerOption("noneditable_regexp", {
        processor: (value2) => {
          if (isArrayOf(value2, isRegExp)) {
            return {
              value: value2,
              valid: true
            };
          } else if (isRegExp(value2)) {
            return {
              value: [value2],
              valid: true
            };
          } else {
            return {
              valid: false,
              message: "Must be a RegExp or an array of RegExp."
            };
          }
        },
        default: []
      });
      registerOption("table_tab_navigation", {
        processor: "boolean",
        default: true
      });
      editor.on("ScriptsLoaded", () => {
        registerOption("directionality", {
          processor: "string",
          default: I18n.isRtl() ? "rtl" : void 0
        });
        registerOption("placeholder", {
          processor: "string",
          default: DOM$a.getAttrib(editor.getElement(), "placeholder")
        });
      });
    };
    const getIframeAttrs = option("iframe_attrs");
    const getDocType = option("doctype");
    const getDocumentBaseUrl = option("document_base_url");
    const getBodyId = option("body_id");
    const getBodyClass = option("body_class");
    const getContentSecurityPolicy = option("content_security_policy");
    const shouldPutBrInPre$1 = option("br_in_pre");
    const getForcedRootBlock = option("forced_root_block");
    const getForcedRootBlockAttrs = option("forced_root_block_attrs");
    const getNewlineBehavior = option("newline_behavior");
    const getBrNewLineSelector = option("br_newline_selector");
    const getNoNewLineSelector = option("no_newline_selector");
    const shouldKeepStyles = option("keep_styles");
    const shouldEndContainerOnEmptyBlock = option("end_container_on_empty_block");
    const isAutomaticUploadsEnabled = option("automatic_uploads");
    const shouldReuseFileName = option("images_reuse_filename");
    const shouldReplaceBlobUris = option("images_replace_blob_uris");
    const getIconPackName = option("icons");
    const getIconsUrl = option("icons_url");
    const getImageUploadUrl = option("images_upload_url");
    const getImageUploadBasePath = option("images_upload_base_path");
    const getImagesUploadCredentials = option("images_upload_credentials");
    const getImagesUploadHandler = option("images_upload_handler");
    const shouldUseContentCssCors = option("content_css_cors");
    const getReferrerPolicy = option("referrer_policy");
    const getLanguageCode = option("language");
    const getLanguageUrl = option("language_url");
    const shouldIndentUseMargin = option("indent_use_margin");
    const getIndentation = option("indentation");
    const getContentCss = option("content_css");
    const getContentStyle = option("content_style");
    const getFontCss = option("font_css");
    const getDirectionality = option("directionality");
    const getInlineBoundarySelector = option("inline_boundaries_selector");
    const getObjectResizing = option("object_resizing");
    const getResizeImgProportional = option("resize_img_proportional");
    const getPlaceholder = option("placeholder");
    const getEventRoot = option("event_root");
    const getServiceMessage = option("service_message");
    const getTheme = option("theme");
    const getThemeUrl = option("theme_url");
    const getModel = option("model");
    const getModelUrl = option("model_url");
    const isInlineBoundariesEnabled = option("inline_boundaries");
    const getFormats = option("formats");
    const getPreviewStyles = option("preview_styles");
    const canFormatEmptyLines = option("format_empty_lines");
    const getCustomUiSelector = option("custom_ui_selector");
    const isInline = option("inline");
    const hasHiddenInput = option("hidden_input");
    const shouldPatchSubmit = option("submit_patch");
    const shouldAddFormSubmitTrigger = option("add_form_submit_trigger");
    const shouldAddUnloadTrigger = option("add_unload_trigger");
    const getCustomUndoRedoLevels = option("custom_undo_redo_levels");
    const shouldDisableNodeChange = option("disable_nodechange");
    const isReadOnly$1 = option("readonly");
    const hasContentCssCors = option("content_css_cors");
    const getPlugins = option("plugins");
    const getExternalPlugins$1 = option("external_plugins");
    const shouldBlockUnsupportedDrop = option("block_unsupported_drop");
    const isVisualAidsEnabled = option("visual");
    const getVisualAidsTableClass = option("visual_table_class");
    const getVisualAidsAnchorClass = option("visual_anchor_class");
    const getIframeAriaText = option("iframe_aria_text");
    const getSetupCallback = option("setup");
    const getInitInstanceCallback = option("init_instance_callback");
    const getUrlConverterCallback = option("urlconverter_callback");
    const getAutoFocus = option("auto_focus");
    const shouldBrowserSpellcheck = option("browser_spellcheck");
    const getProtect = option("protect");
    const shouldPasteBlockDrop = option("paste_block_drop");
    const shouldPasteDataImages = option("paste_data_images");
    const getPastePreProcess = option("paste_preprocess");
    const getPastePostProcess = option("paste_postprocess");
    const getPasteWebkitStyles = option("paste_webkit_styles");
    const shouldPasteRemoveWebKitStyles = option("paste_remove_styles_if_webkit");
    const shouldPasteMergeFormats = option("paste_merge_formats");
    const isSmartPasteEnabled = option("smart_paste");
    const isPasteAsTextEnabled = option("paste_as_text");
    const getPasteTabSpaces = option("paste_tab_spaces");
    const shouldAllowHtmlDataUrls = option("allow_html_data_urls");
    const getTextPatterns = option("text_patterns");
    const getNonEditableClass = option("noneditable_class");
    const getEditableClass = option("editable_class");
    const getNonEditableRegExps = option("noneditable_regexp");
    const getFontStyleValues = (editor) => Tools.explode(editor.options.get("font_size_style_values"));
    const getFontSizeClasses = (editor) => Tools.explode(editor.options.get("font_size_classes"));
    const isEncodingXml = (editor) => editor.options.get("encoding") === "xml";
    const getAllowedImageFileTypes = (editor) => Tools.explode(editor.options.get("images_file_types"));
    const hasTableTabNavigation = option("table_tab_navigation");
    const isElement$3 = isElement$6;
    const isText$4 = isText$9;
    const removeNode$1 = (node) => {
      const parentNode = node.parentNode;
      if (parentNode) {
        parentNode.removeChild(node);
      }
    };
    const trimCount = (text2) => {
      const trimmedText = trim$1(text2);
      return {
        count: text2.length - trimmedText.length,
        text: trimmedText
      };
    };
    const deleteZwspChars = (caretContainer) => {
      let idx;
      while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
        caretContainer.deleteData(idx, 1);
      }
    };
    const removeUnchanged = (caretContainer, pos) => {
      remove$4(caretContainer);
      return pos;
    };
    const removeTextAndReposition = (caretContainer, pos) => {
      const before2 = trimCount(caretContainer.data.substr(0, pos.offset()));
      const after2 = trimCount(caretContainer.data.substr(pos.offset()));
      const text2 = before2.text + after2.text;
      if (text2.length > 0) {
        deleteZwspChars(caretContainer);
        return CaretPosition(caretContainer, pos.offset() - before2.count);
      } else {
        return pos;
      }
    };
    const removeElementAndReposition = (caretContainer, pos) => {
      const parentNode = pos.container();
      const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map((index2) => {
        return index2 < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
      }).getOr(pos);
      remove$4(caretContainer);
      return newPosition;
    };
    const removeTextCaretContainer = (caretContainer, pos) => isText$4(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
    const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
    const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
    const remove$4 = (caretContainerNode) => {
      if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
        if (hasContent(caretContainerNode)) {
          caretContainerNode.removeAttribute("data-mce-caret");
        } else {
          removeNode$1(caretContainerNode);
        }
      }
      if (isText$4(caretContainerNode)) {
        deleteZwspChars(caretContainerNode);
        if (caretContainerNode.data.length === 0) {
          removeNode$1(caretContainerNode);
        }
      }
    };
    const isContentEditableFalse$8 = isContentEditableFalse$b;
    const isMedia$1 = isMedia$2;
    const isTableCell$3 = isTableCell$5;
    const inlineFakeCaretSelector = "*[contentEditable=false],video,audio,embed,object";
    const getAbsoluteClientRect = (root, element, before2) => {
      const clientRect = collapse(element.getBoundingClientRect(), before2);
      let scrollX;
      let scrollY;
      if (root.tagName === "BODY") {
        const docElm = root.ownerDocument.documentElement;
        scrollX = root.scrollLeft || docElm.scrollLeft;
        scrollY = root.scrollTop || docElm.scrollTop;
      } else {
        const rootRect = root.getBoundingClientRect();
        scrollX = root.scrollLeft - rootRect.left;
        scrollY = root.scrollTop - rootRect.top;
      }
      clientRect.left += scrollX;
      clientRect.right += scrollX;
      clientRect.top += scrollY;
      clientRect.bottom += scrollY;
      clientRect.width = 1;
      let margin = element.offsetWidth - element.clientWidth;
      if (margin > 0) {
        if (before2) {
          margin *= -1;
        }
        clientRect.left += margin;
        clientRect.right += margin;
      }
      return clientRect;
    };
    const trimInlineCaretContainers = (root) => {
      const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
      for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
        const node = fakeCaretTargetNodes[i].dom;
        let sibling2 = node.previousSibling;
        if (endsWithCaretContainer$1(sibling2)) {
          const data2 = sibling2.data;
          if (data2.length === 1) {
            sibling2.parentNode.removeChild(sibling2);
          } else {
            sibling2.deleteData(data2.length - 1, 1);
          }
        }
        sibling2 = node.nextSibling;
        if (startsWithCaretContainer$1(sibling2)) {
          const data2 = sibling2.data;
          if (data2.length === 1) {
            sibling2.parentNode.removeChild(sibling2);
          } else {
            sibling2.deleteData(0, 1);
          }
        }
      }
    };
    const FakeCaret = (editor, root, isBlock2, hasFocus2) => {
      const lastVisualCaret = value$2();
      let cursorInterval;
      let caretContainerNode;
      const caretBlock = getForcedRootBlock(editor);
      const dom2 = editor.dom;
      const show = (before2, element) => {
        let rng;
        hide();
        if (isTableCell$3(element)) {
          return null;
        }
        if (isBlock2(element)) {
          caretContainerNode = insertBlock(caretBlock, element, before2);
          const clientRect = getAbsoluteClientRect(root, element, before2);
          dom2.setStyle(caretContainerNode, "top", clientRect.top);
          const caret = dom2.create("div", {
            "class": "mce-visual-caret",
            "data-mce-bogus": "all"
          });
          dom2.setStyles(caret, { ...clientRect });
          dom2.add(root, caret);
          lastVisualCaret.set({
            caret,
            element,
            before: before2
          });
          if (before2) {
            dom2.addClass(caret, "mce-visual-caret-before");
          }
          startBlink();
          rng = element.ownerDocument.createRange();
          rng.setStart(caretContainerNode, 0);
          rng.setEnd(caretContainerNode, 0);
        } else {
          caretContainerNode = insertInline$1(element, before2);
          rng = element.ownerDocument.createRange();
          if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
            rng.setStart(caretContainerNode, 0);
            rng.setEnd(caretContainerNode, 0);
          } else {
            rng.setStart(caretContainerNode, 1);
            rng.setEnd(caretContainerNode, 1);
          }
          return rng;
        }
        return rng;
      };
      const hide = () => {
        trimInlineCaretContainers(root);
        if (caretContainerNode) {
          remove$4(caretContainerNode);
          caretContainerNode = null;
        }
        lastVisualCaret.on((caretState) => {
          dom2.remove(caretState.caret);
          lastVisualCaret.clear();
        });
        if (cursorInterval) {
          clearInterval(cursorInterval);
          cursorInterval = void 0;
        }
      };
      const startBlink = () => {
        cursorInterval = setInterval(() => {
          lastVisualCaret.on((caretState) => {
            if (hasFocus2()) {
              dom2.toggleClass(caretState.caret, "mce-visual-caret-hidden");
            } else {
              dom2.addClass(caretState.caret, "mce-visual-caret-hidden");
            }
          });
        }, 500);
      };
      const reposition2 = () => {
        lastVisualCaret.on((caretState) => {
          const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
          dom2.setStyles(caretState.caret, { ...clientRect });
        });
      };
      const destroy2 = () => clearInterval(cursorInterval);
      const getCss = () => ".mce-visual-caret {position: absolute;background-color: black;background-color: currentcolor;}.mce-visual-caret-hidden {display: none;}*[data-mce-caret] {position: absolute;left: -1000px;right: auto;top: 0;margin: 0;padding: 0;}";
      return {
        show,
        hide,
        getCss,
        reposition: reposition2,
        destroy: destroy2
      };
    };
    const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
    const isInlineFakeCaretTarget = (node) => isContentEditableFalse$8(node) || isMedia$1(node);
    const isFakeCaretTarget = (node) => isInlineFakeCaretTarget(node) || isTable$3(node) && isFakeCaretTableBrowser();
    const isContentEditableTrue$3 = isContentEditableTrue$5;
    const isContentEditableFalse$7 = isContentEditableFalse$b;
    const isMedia = isMedia$2;
    const isBlockLike = matchStyleValues("display", "block table table-cell table-caption list-item");
    const isCaretContainer = isCaretContainer$2;
    const isCaretContainerBlock = isCaretContainerBlock$1;
    const isElement$2 = isElement$6;
    const isCaretCandidate$1 = isCaretCandidate$3;
    const isForwards = (direction) => direction > 0;
    const isBackwards = (direction) => direction < 0;
    const skipCaretContainers = (walk2, shallow2) => {
      let node;
      while (node = walk2(shallow2)) {
        if (!isCaretContainerBlock(node)) {
          return node;
        }
      }
      return null;
    };
    const findNode = (node, direction, predicateFn, rootNode, shallow2) => {
      const walker = new DomTreeWalker(node, rootNode);
      const isCefOrCaretContainer = isContentEditableFalse$7(node) || isCaretContainerBlock(node);
      if (isBackwards(direction)) {
        if (isCefOrCaretContainer) {
          node = skipCaretContainers(walker.prev.bind(walker), true);
          if (predicateFn(node)) {
            return node;
          }
        }
        while (node = skipCaretContainers(walker.prev.bind(walker), shallow2)) {
          if (predicateFn(node)) {
            return node;
          }
        }
      }
      if (isForwards(direction)) {
        if (isCefOrCaretContainer) {
          node = skipCaretContainers(walker.next.bind(walker), true);
          if (predicateFn(node)) {
            return node;
          }
        }
        while (node = skipCaretContainers(walker.next.bind(walker), shallow2)) {
          if (predicateFn(node)) {
            return node;
          }
        }
      }
      return null;
    };
    const getEditingHost = (node, rootNode) => {
      const isCETrue = (node2) => isContentEditableTrue$3(node2.dom);
      const isRoot2 = (node2) => node2.dom === rootNode;
      return ancestor$3(SugarElement.fromDom(node), isCETrue, isRoot2).map((elm) => elm.dom).getOr(rootNode);
    };
    const getParentBlock$3 = (node, rootNode) => {
      while (node && node !== rootNode) {
        if (isBlockLike(node)) {
          return node;
        }
        node = node.parentNode;
      }
      return null;
    };
    const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
    const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
      if (!caretPosition) {
        return null;
      }
      const container = caretPosition.container();
      const offset = caretPosition.offset();
      if (!isElement$2(container)) {
        return null;
      }
      return container.childNodes[offset + relativeOffset];
    };
    const beforeAfter = (before2, node) => {
      const range2 = node.ownerDocument.createRange();
      if (before2) {
        range2.setStartBefore(node);
        range2.setEndBefore(node);
      } else {
        range2.setStartAfter(node);
        range2.setEndAfter(node);
      }
      return range2;
    };
    const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
    const lean = (left, root, node) => {
      const siblingName = left ? "previousSibling" : "nextSibling";
      while (node && node !== root) {
        let sibling2 = node[siblingName];
        if (isCaretContainer(sibling2)) {
          sibling2 = sibling2[siblingName];
        }
        if (isContentEditableFalse$7(sibling2) || isMedia(sibling2)) {
          if (isNodesInSameBlock(root, sibling2, node)) {
            return sibling2;
          }
          break;
        }
        if (isCaretCandidate$1(sibling2)) {
          break;
        }
        node = node.parentNode;
      }
      return null;
    };
    const before$2 = curry(beforeAfter, true);
    const after$2 = curry(beforeAfter, false);
    const normalizeRange = (direction, root, range2) => {
      let node;
      const leanLeft = curry(lean, true, root);
      const leanRight2 = curry(lean, false, root);
      let container = range2.startContainer;
      const offset = range2.startOffset;
      if (isCaretContainerBlock$1(container)) {
        if (!isElement$2(container)) {
          container = container.parentNode;
        }
        const location = container.getAttribute("data-mce-caret");
        if (location === "before") {
          node = container.nextSibling;
          if (isFakeCaretTarget(node)) {
            return before$2(node);
          }
        }
        if (location === "after") {
          node = container.previousSibling;
          if (isFakeCaretTarget(node)) {
            return after$2(node);
          }
        }
      }
      if (!range2.collapsed) {
        return range2;
      }
      if (isText$9(container)) {
        if (isCaretContainer(container)) {
          if (direction === 1) {
            node = leanRight2(container);
            if (node) {
              return before$2(node);
            }
            node = leanLeft(container);
            if (node) {
              return after$2(node);
            }
          }
          if (direction === -1) {
            node = leanLeft(container);
            if (node) {
              return after$2(node);
            }
            node = leanRight2(container);
            if (node) {
              return before$2(node);
            }
          }
          return range2;
        }
        if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
          if (direction === 1) {
            node = leanRight2(container);
            if (node) {
              return before$2(node);
            }
          }
          return range2;
        }
        if (startsWithCaretContainer$1(container) && offset <= 1) {
          if (direction === -1) {
            node = leanLeft(container);
            if (node) {
              return after$2(node);
            }
          }
          return range2;
        }
        if (offset === container.data.length) {
          node = leanRight2(container);
          if (node) {
            return before$2(node);
          }
          return range2;
        }
        if (offset === 0) {
          node = leanLeft(container);
          if (node) {
            return after$2(node);
          }
          return range2;
        }
      }
      return range2;
    };
    const getRelativeCefElm = (forward, caretPosition) => Optional.from(getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition)).filter(isContentEditableFalse$7);
    const getNormalizedRangeEndPoint = (direction, root, range2) => {
      const normalizedRange = normalizeRange(direction, root, range2);
      if (direction === -1) {
        return CaretPosition.fromRangeStart(normalizedRange);
      }
      return CaretPosition.fromRangeEnd(normalizedRange);
    };
    const getElementFromPosition = (pos) => Optional.from(pos.getNode()).map(SugarElement.fromDom);
    const getElementFromPrevPosition = (pos) => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
    const getVisualCaretPosition = (walkFn, caretPosition) => {
      while (caretPosition = walkFn(caretPosition)) {
        if (caretPosition.isVisible()) {
          return caretPosition;
        }
      }
      return caretPosition;
    };
    const isMoveInsideSameBlock = (from2, to2) => {
      const inSameBlock = isInSameBlock(from2, to2);
      if (!inSameBlock && isBr$6(from2.getNode())) {
        return true;
      }
      return inSameBlock;
    };
    var HDirection;
    (function(HDirection2) {
      HDirection2[HDirection2["Backwards"] = -1] = "Backwards";
      HDirection2[HDirection2["Forwards"] = 1] = "Forwards";
    })(HDirection || (HDirection = {}));
    const isContentEditableFalse$6 = isContentEditableFalse$b;
    const isText$3 = isText$9;
    const isElement$1 = isElement$6;
    const isBr$2 = isBr$6;
    const isCaretCandidate = isCaretCandidate$3;
    const isAtomic = isAtomic$1;
    const isEditableCaretCandidate = isEditableCaretCandidate$1;
    const getParents$3 = (node, root) => {
      const parents2 = [];
      while (node && node !== root) {
        parents2.push(node);
        node = node.parentNode;
      }
      return parents2;
    };
    const nodeAtIndex = (container, offset) => {
      if (container.hasChildNodes() && offset < container.childNodes.length) {
        return container.childNodes[offset];
      }
      return null;
    };
    const getCaretCandidatePosition = (direction, node) => {
      if (isForwards(direction)) {
        if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
          return CaretPosition.before(node);
        }
        if (isText$3(node)) {
          return CaretPosition(node, 0);
        }
      }
      if (isBackwards(direction)) {
        if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
          return CaretPosition.after(node);
        }
        if (isText$3(node)) {
          return CaretPosition(node, node.data.length);
        }
      }
      if (isBackwards(direction)) {
        if (isBr$2(node)) {
          return CaretPosition.before(node);
        }
        return CaretPosition.after(node);
      }
      return CaretPosition.before(node);
    };
    const moveForwardFromBr = (root, nextNode) => {
      const nextSibling2 = nextNode.nextSibling;
      if (nextSibling2 && isCaretCandidate(nextSibling2)) {
        if (isText$3(nextSibling2)) {
          return CaretPosition(nextSibling2, 0);
        } else {
          return CaretPosition.before(nextSibling2);
        }
      } else {
        return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
      }
    };
    const findCaretPosition$1 = (direction, startPos, root) => {
      let node;
      let nextNode;
      let innerNode;
      let caretPosition;
      if (!isElement$1(root) || !startPos) {
        return null;
      }
      if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
        caretPosition = CaretPosition.after(root.lastChild);
        if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
          return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
        }
      } else {
        caretPosition = startPos;
      }
      const container = caretPosition.container();
      let offset = caretPosition.offset();
      if (isText$3(container)) {
        if (isBackwards(direction) && offset > 0) {
          return CaretPosition(container, --offset);
        }
        if (isForwards(direction) && offset < container.length) {
          return CaretPosition(container, ++offset);
        }
        node = container;
      } else {
        if (isBackwards(direction) && offset > 0) {
          nextNode = nodeAtIndex(container, offset - 1);
          if (isCaretCandidate(nextNode)) {
            if (!isAtomic(nextNode)) {
              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
              if (innerNode) {
                if (isText$3(innerNode)) {
                  return CaretPosition(innerNode, innerNode.data.length);
                }
                return CaretPosition.after(innerNode);
              }
            }
            if (isText$3(nextNode)) {
              return CaretPosition(nextNode, nextNode.data.length);
            }
            return CaretPosition.before(nextNode);
          }
        }
        if (isForwards(direction) && offset < container.childNodes.length) {
          nextNode = nodeAtIndex(container, offset);
          if (isCaretCandidate(nextNode)) {
            if (isBr$2(nextNode)) {
              return moveForwardFromBr(root, nextNode);
            }
            if (!isAtomic(nextNode)) {
              innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
              if (innerNode) {
                if (isText$3(innerNode)) {
                  return CaretPosition(innerNode, 0);
                }
                return CaretPosition.before(innerNode);
              }
            }
            if (isText$3(nextNode)) {
              return CaretPosition(nextNode, 0);
            }
            return CaretPosition.after(nextNode);
          }
        }
        node = nextNode ? nextNode : caretPosition.getNode();
      }
      if (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart()) {
        node = findNode(node, direction, always, root, true);
        if (isEditableCaretCandidate(node, root)) {
          return getCaretCandidatePosition(direction, node);
        }
      }
      nextNode = findNode(node, direction, isEditableCaretCandidate, root);
      const rootContentEditableFalseElm = last$2(filter$6(getParents$3(container, root), isContentEditableFalse$6));
      if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
        if (isForwards(direction)) {
          caretPosition = CaretPosition.after(rootContentEditableFalseElm);
        } else {
          caretPosition = CaretPosition.before(rootContentEditableFalseElm);
        }
        return caretPosition;
      }
      if (nextNode) {
        return getCaretCandidatePosition(direction, nextNode);
      }
      return null;
    };
    const CaretWalker = (root) => ({
      next: (caretPosition) => {
        return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
      },
      prev: (caretPosition) => {
        return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
      }
    });
    const walkToPositionIn = (forward, root, start2) => {
      const position = forward ? CaretPosition.before(start2) : CaretPosition.after(start2);
      return fromPosition(forward, root, position);
    };
    const afterElement = (node) => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
    const isBeforeOrStart = (position) => {
      if (CaretPosition.isTextPosition(position)) {
        return position.offset() === 0;
      } else {
        return isCaretCandidate$3(position.getNode());
      }
    };
    const isAfterOrEnd = (position) => {
      if (CaretPosition.isTextPosition(position)) {
        const container = position.container();
        return position.offset() === container.data.length;
      } else {
        return isCaretCandidate$3(position.getNode(true));
      }
    };
    const isBeforeAfterSameElement = (from2, to2) => !CaretPosition.isTextPosition(from2) && !CaretPosition.isTextPosition(to2) && from2.getNode() === to2.getNode(true);
    const isAtBr = (position) => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
    const shouldSkipPosition = (forward, from2, to2) => {
      if (forward) {
        return !isBeforeAfterSameElement(from2, to2) && !isAtBr(from2) && isAfterOrEnd(from2) && isBeforeOrStart(to2);
      } else {
        return !isBeforeAfterSameElement(to2, from2) && isBeforeOrStart(from2) && isAfterOrEnd(to2);
      }
    };
    const fromPosition = (forward, root, pos) => {
      const walker = CaretWalker(root);
      return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
    };
    const navigate = (forward, root, from2) => fromPosition(forward, root, from2).bind((to2) => {
      if (isInSameBlock(from2, to2, root) && shouldSkipPosition(forward, from2, to2)) {
        return fromPosition(forward, root, to2);
      } else {
        return Optional.some(to2);
      }
    });
    const navigateIgnore = (forward, root, from2, ignoreFilter) => navigate(forward, root, from2).bind((pos) => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
    const positionIn = (forward, element) => {
      const startNode = forward ? element.firstChild : element.lastChild;
      if (isText$9(startNode)) {
        return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
      } else if (startNode) {
        if (isCaretCandidate$3(startNode)) {
          return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
        } else {
          return walkToPositionIn(forward, element, startNode);
        }
      } else {
        return Optional.none();
      }
    };
    const nextPosition = curry(fromPosition, true);
    const prevPosition = curry(fromPosition, false);
    const firstPositionIn = curry(positionIn, true);
    const lastPositionIn = curry(positionIn, false);
    const CARET_ID$1 = "_mce_caret";
    const isCaretNode = (node) => isElement$6(node) && node.id === CARET_ID$1;
    const getParentCaretContainer = (body, node) => {
      while (node && node !== body) {
        if (node.id === CARET_ID$1) {
          return node;
        }
        node = node.parentNode;
      }
      return null;
    };
    const isStringPathBookmark = (bookmark) => isString(bookmark.start);
    const isRangeBookmark = (bookmark) => has$2(bookmark, "rng");
    const isIdBookmark = (bookmark) => has$2(bookmark, "id");
    const isIndexBookmark = (bookmark) => has$2(bookmark, "name");
    const isPathBookmark = (bookmark) => Tools.isArray(bookmark.start);
    const isForwardBookmark = (bookmark) => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
    const addBogus = (dom2, node) => {
      if (isElement$6(node) && dom2.isBlock(node) && !node.innerHTML) {
        node.innerHTML = '<br data-mce-bogus="1" />';
      }
      return node;
    };
    const resolveCaretPositionBookmark = (dom2, bookmark) => {
      const range2 = dom2.createRng();
      const startPos = resolve$1(dom2.getRoot(), bookmark.start);
      range2.setStart(startPos.container(), startPos.offset());
      const endPos = resolve$1(dom2.getRoot(), bookmark.end);
      range2.setEnd(endPos.container(), endPos.offset());
      return {
        range: range2,
        forward: isForwardBookmark(bookmark)
      };
    };
    const insertZwsp = (node, rng) => {
      const textNode = node.ownerDocument.createTextNode(ZWSP$1);
      node.appendChild(textNode);
      rng.setStart(textNode, 0);
      rng.setEnd(textNode, 0);
    };
    const isEmpty$1 = (node) => node.hasChildNodes() === false;
    const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, (pos) => {
      rng.setStart(pos.container(), pos.offset());
      rng.setEnd(pos.container(), pos.offset());
      return true;
    });
    const padEmptyCaretContainer = (root, node, rng) => {
      if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
        insertZwsp(node, rng);
        return true;
      } else {
        return false;
      }
    };
    const setEndPoint = (dom2, start2, bookmark, rng) => {
      const point2 = bookmark[start2 ? "start" : "end"];
      let i, node, offset, children2;
      const root = dom2.getRoot();
      if (point2) {
        offset = point2[0];
        for (node = root, i = point2.length - 1; i >= 1; i--) {
          children2 = node.childNodes;
          if (padEmptyCaretContainer(root, node, rng)) {
            return true;
          }
          if (point2[i] > children2.length - 1) {
            if (padEmptyCaretContainer(root, node, rng)) {
              return true;
            }
            return tryFindRangePosition(node, rng);
          }
          node = children2[point2[i]];
        }
        if (node.nodeType === 3) {
          offset = Math.min(point2[0], node.nodeValue.length);
        }
        if (node.nodeType === 1) {
          offset = Math.min(point2[0], node.childNodes.length);
        }
        if (start2) {
          rng.setStart(node, offset);
        } else {
          rng.setEnd(node, offset);
        }
      }
      return true;
    };
    const isValidTextNode = (node) => isText$9(node) && node.data.length > 0;
    const restoreEndPoint = (dom2, suffix, bookmark) => {
      let marker = dom2.get(bookmark.id + "_" + suffix), node, idx, next2, prev2;
      const keep = bookmark.keep;
      let container, offset;
      if (marker) {
        node = marker.parentNode;
        if (suffix === "start") {
          if (!keep) {
            idx = dom2.nodeIndex(marker);
          } else {
            if (marker.hasChildNodes()) {
              node = marker.firstChild;
              idx = 1;
            } else if (isValidTextNode(marker.nextSibling)) {
              node = marker.nextSibling;
              idx = 0;
            } else if (isValidTextNode(marker.previousSibling)) {
              node = marker.previousSibling;
              idx = marker.previousSibling.data.length;
            } else {
              node = marker.parentNode;
              idx = dom2.nodeIndex(marker) + 1;
            }
          }
          container = node;
          offset = idx;
        } else {
          if (!keep) {
            idx = dom2.nodeIndex(marker);
          } else {
            if (marker.hasChildNodes()) {
              node = marker.firstChild;
              idx = 1;
            } else if (isValidTextNode(marker.previousSibling)) {
              node = marker.previousSibling;
              idx = marker.previousSibling.data.length;
            } else {
              node = marker.parentNode;
              idx = dom2.nodeIndex(marker);
            }
          }
          container = node;
          offset = idx;
        }
        if (!keep) {
          prev2 = marker.previousSibling;
          next2 = marker.nextSibling;
          Tools.each(Tools.grep(marker.childNodes), (node2) => {
            if (isText$9(node2)) {
              node2.nodeValue = node2.nodeValue.replace(/\uFEFF/g, "");
            }
          });
          while (marker = dom2.get(bookmark.id + "_" + suffix)) {
            dom2.remove(marker, true);
          }
          if (prev2 && next2 && prev2.nodeType === next2.nodeType && isText$9(prev2) && !Env.browser.isOpera()) {
            idx = prev2.nodeValue.length;
            prev2.appendData(next2.nodeValue);
            dom2.remove(next2);
            container = prev2;
            offset = idx;
          }
        }
        return Optional.some(CaretPosition(container, offset));
      } else {
        return Optional.none();
      }
    };
    const resolvePaths = (dom2, bookmark) => {
      const range2 = dom2.createRng();
      if (setEndPoint(dom2, true, bookmark, range2) && setEndPoint(dom2, false, bookmark, range2)) {
        return Optional.some({
          range: range2,
          forward: isForwardBookmark(bookmark)
        });
      } else {
        return Optional.none();
      }
    };
    const resolveId = (dom2, bookmark) => {
      const startPos = restoreEndPoint(dom2, "start", bookmark);
      const endPos = restoreEndPoint(dom2, "end", bookmark);
      return lift2(startPos, endPos.or(startPos), (spos, epos) => {
        const range2 = dom2.createRng();
        range2.setStart(addBogus(dom2, spos.container()), spos.offset());
        range2.setEnd(addBogus(dom2, epos.container()), epos.offset());
        return {
          range: range2,
          forward: isForwardBookmark(bookmark)
        };
      });
    };
    const resolveIndex = (dom2, bookmark) => Optional.from(dom2.select(bookmark.name)[bookmark.index]).map((elm) => {
      const range2 = dom2.createRng();
      range2.selectNode(elm);
      return {
        range: range2,
        forward: true
      };
    });
    const resolve = (selection, bookmark) => {
      const dom2 = selection.dom;
      if (bookmark) {
        if (isPathBookmark(bookmark)) {
          return resolvePaths(dom2, bookmark);
        } else if (isStringPathBookmark(bookmark)) {
          return Optional.some(resolveCaretPositionBookmark(dom2, bookmark));
        } else if (isIdBookmark(bookmark)) {
          return resolveId(dom2, bookmark);
        } else if (isIndexBookmark(bookmark)) {
          return resolveIndex(dom2, bookmark);
        } else if (isRangeBookmark(bookmark)) {
          return Optional.some({
            range: bookmark.rng,
            forward: isForwardBookmark(bookmark)
          });
        }
      }
      return Optional.none();
    };
    const getBookmark$1 = (selection, type2, normalized) => {
      return getBookmark$2(selection, type2, normalized);
    };
    const moveToBookmark = (selection, bookmark) => {
      resolve(selection, bookmark).each(({ range: range2, forward }) => {
        selection.setRng(range2, forward);
      });
    };
    const isBookmarkNode$1 = (node) => {
      return isElement$6(node) && node.tagName === "SPAN" && node.getAttribute("data-mce-type") === "bookmark";
    };
    const is = (expected) => (actual) => expected === actual;
    const isNbsp = is(nbsp);
    const isWhiteSpace = (chr) => chr !== "" && " \f\n\r	\v".indexOf(chr) !== -1;
    const isContent = (chr) => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$1(chr);
    const hexColour = (value2) => ({ value: value2 });
    const toHex = (component) => {
      const hex = component.toString(16);
      return (hex.length === 1 ? "0" + hex : hex).toUpperCase();
    };
    const fromRgba = (rgbaColour2) => {
      const value2 = toHex(rgbaColour2.red) + toHex(rgbaColour2.green) + toHex(rgbaColour2.blue);
      return hexColour(value2);
    };
    const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
    const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
    const rgbaColour = (red, green, blue, alpha) => ({
      red,
      green,
      blue,
      alpha
    });
    const fromStringValues = (red, green, blue, alpha) => {
      const r2 = parseInt(red, 10);
      const g = parseInt(green, 10);
      const b = parseInt(blue, 10);
      const a = parseFloat(alpha);
      return rgbaColour(r2, g, b, a);
    };
    const fromString = (rgbaString) => {
      if (rgbaString === "transparent") {
        return Optional.some(rgbaColour(0, 0, 0, 0));
      }
      const rgbMatch = rgbRegex.exec(rgbaString);
      if (rgbMatch !== null) {
        return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], "1"));
      }
      const rgbaMatch = rgbaRegex.exec(rgbaString);
      if (rgbaMatch !== null) {
        return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
      }
      return Optional.none();
    };
    const rgbaToHexString = (color) => fromString(color).map(fromRgba).map((h2) => "#" + h2.value).getOr(color);
    const isNode = (node) => !!node.nodeType;
    const isInlineBlock = (node) => {
      return node && /^(IMG)$/.test(node.nodeName);
    };
    const moveStart = (dom2, selection, rng) => {
      const offset = rng.startOffset;
      let container = rng.startContainer;
      if (container === rng.endContainer) {
        if (isInlineBlock(container.childNodes[offset])) {
          return;
        }
      }
      if (isElement$6(container)) {
        const nodes = container.childNodes;
        let walker;
        if (offset < nodes.length) {
          container = nodes[offset];
          walker = new DomTreeWalker(container, dom2.getParent(container, dom2.isBlock));
        } else {
          container = nodes[nodes.length - 1];
          walker = new DomTreeWalker(container, dom2.getParent(container, dom2.isBlock));
          walker.next(true);
        }
        for (let node = walker.current(); node; node = walker.next()) {
          if (isText$9(node) && !isWhiteSpaceNode$1(node)) {
            rng.setStart(node, 0);
            selection.setRng(rng);
            return;
          }
        }
      }
    };
    const getNonWhiteSpaceSibling = (node, next2, inc) => {
      if (node) {
        const nextName = next2 ? "nextSibling" : "previousSibling";
        for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
          if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
            return node;
          }
        }
      }
    };
    const isTextBlock$1 = (editor, name2) => {
      if (isNode(name2)) {
        name2 = name2.nodeName;
      }
      return !!editor.schema.getTextBlockElements()[name2.toLowerCase()];
    };
    const isValid = (ed, parent2, child2) => {
      return ed.schema.isValidChild(parent2, child2);
    };
    const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
      if (isNonNullable(node) && isText$9(node)) {
        const data2 = allowSpaces ? node.data.replace(/ /g, "\xA0") : node.data;
        return isWhitespaceText(data2);
      } else {
        return false;
      }
    };
    const isEmptyTextNode$1 = (node) => {
      return isNonNullable(node) && isText$9(node) && node.length === 0;
    };
    const replaceVars = (value2, vars) => {
      if (isFunction(value2)) {
        value2 = value2(vars);
      } else if (isNonNullable(vars)) {
        value2 = value2.replace(/%(\w+)/g, (str, name2) => {
          return vars[name2] || str;
        });
      }
      return value2;
    };
    const isEq$5 = (str1, str2) => {
      str1 = str1 || "";
      str2 = str2 || "";
      str1 = "" + (str1.nodeName || str1);
      str2 = "" + (str2.nodeName || str2);
      return str1.toLowerCase() === str2.toLowerCase();
    };
    const normalizeStyleValue = (value2, name2) => {
      if (name2 === "color" || name2 === "backgroundColor") {
        value2 = rgbaToHexString(value2);
      }
      if (name2 === "fontWeight" && value2 === 700) {
        value2 = "bold";
      }
      if (name2 === "fontFamily") {
        value2 = value2.replace(/[\'\"]/g, "").replace(/,\s+/g, ",");
      }
      return "" + value2;
    };
    const getStyle = (dom2, node, name2) => {
      return normalizeStyleValue(dom2.getStyle(node, name2), name2);
    };
    const getTextDecoration = (dom2, node) => {
      let decoration;
      dom2.getParent(node, (n) => {
        decoration = dom2.getStyle(n, "text-decoration");
        return decoration && decoration !== "none";
      });
      return decoration;
    };
    const getParents$2 = (dom2, node, selector) => {
      return dom2.getParents(node, selector, dom2.getRoot());
    };
    const isVariableFormatName = (editor, formatName) => {
      const hasVariableValues = (format) => {
        const isVariableValue = (val) => val.length > 1 && val.charAt(0) === "%";
        return exists([
          "styles",
          "attributes"
        ], (key) => get$a(format, key).exists((field2) => {
          const fieldValues = isArray$1(field2) ? field2 : values(field2);
          return exists(fieldValues, isVariableValue);
        }));
      };
      return exists(editor.formatter.get(formatName), hasVariableValues);
    };
    const areSimilarFormats = (editor, formatName, otherFormatName) => {
      const validKeys = [
        "inline",
        "block",
        "selector",
        "attributes",
        "styles",
        "classes"
      ];
      const filterObj = (format) => filter$5(format, (_, key) => exists(validKeys, (validKey) => validKey === key));
      return exists(editor.formatter.get(formatName), (fmt1) => {
        const filteredFmt1 = filterObj(fmt1);
        return exists(editor.formatter.get(otherFormatName), (fmt2) => {
          const filteredFmt2 = filterObj(fmt2);
          return equal$1(filteredFmt1, filteredFmt2);
        });
      });
    };
    const isBlockFormat = (format) => hasNonNullableKey(format, "block");
    const isSelectorFormat = (format) => hasNonNullableKey(format, "selector");
    const isInlineFormat = (format) => hasNonNullableKey(format, "inline");
    const isMixedFormat = (format) => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, "mixed"), true);
    const shouldExpandToSelector = (format) => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
    const isBookmarkNode = isBookmarkNode$1;
    const getParents$1 = getParents$2;
    const isWhiteSpaceNode = isWhiteSpaceNode$1;
    const isTextBlock = isTextBlock$1;
    const isBogusBr = (node) => {
      return isBr$6(node) && node.getAttribute("data-mce-bogus") && !node.nextSibling;
    };
    const findParentContentEditable = (dom2, node) => {
      let parent2 = node;
      while (parent2) {
        if (isElement$6(parent2) && dom2.getContentEditable(parent2)) {
          return dom2.getContentEditable(parent2) === "false" ? parent2 : node;
        }
        parent2 = parent2.parentNode;
      }
      return node;
    };
    const walkText = (start2, node, offset, predicate) => {
      const str = node.data;
      for (let i = offset; start2 ? i >= 0 : i < str.length; start2 ? i-- : i++) {
        if (predicate(str.charAt(i))) {
          return start2 ? i + 1 : i;
        }
      }
      return -1;
    };
    const findSpace = (start2, node, offset) => walkText(start2, node, offset, (c) => isNbsp(c) || isWhiteSpace(c));
    const findContent = (start2, node, offset) => walkText(start2, node, offset, isContent);
    const findWordEndPoint = (dom2, body, container, offset, start2, includeTrailingSpaces) => {
      let lastTextNode;
      const rootNode = dom2.getParent(container, dom2.isBlock) || body;
      const walk2 = (container2, offset2, pred) => {
        const textSeeker = TextSeeker(dom2);
        const walker = start2 ? textSeeker.backwards : textSeeker.forwards;
        return Optional.from(walker(container2, offset2, (text2, textOffset) => {
          if (isBookmarkNode(text2.parentNode)) {
            return -1;
          } else {
            lastTextNode = text2;
            return pred(start2, text2, textOffset);
          }
        }, rootNode));
      };
      const spaceResult = walk2(container, offset, findSpace);
      return spaceResult.bind((result) => includeTrailingSpaces ? walk2(result.container, result.offset + (start2 ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
        container: lastTextNode,
        offset: start2 ? 0 : lastTextNode.length
      }) : Optional.none());
    };
    const findSelectorEndPoint = (dom2, formatList, rng, container, siblingName) => {
      if (isText$9(container) && isEmpty$3(container.data) && container[siblingName]) {
        container = container[siblingName];
      }
      const parents2 = getParents$1(dom2, container);
      for (let i = 0; i < parents2.length; i++) {
        for (let y = 0; y < formatList.length; y++) {
          const curFormat = formatList[y];
          if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
            continue;
          }
          if (isSelectorFormat(curFormat) && dom2.is(parents2[i], curFormat.selector)) {
            return parents2[i];
          }
        }
      }
      return container;
    };
    const findBlockEndPoint = (editor, formatList, container, siblingName) => {
      let node = container;
      const dom2 = editor.dom;
      const root = dom2.getRoot();
      const format = formatList[0];
      if (isBlockFormat(format)) {
        node = format.wrapper ? null : dom2.getParent(container, format.block, root);
      }
      if (!node) {
        const scopeRoot = dom2.getParent(container, "LI,TD,TH");
        node = dom2.getParent(isText$9(container) ? container.parentNode : container, (node2) => node2 !== root && isTextBlock(editor, node2), scopeRoot);
      }
      if (node && isBlockFormat(format) && format.wrapper) {
        node = getParents$1(dom2, node, "ul,ol").reverse()[0] || node;
      }
      if (!node) {
        node = container;
        while (node[siblingName] && !dom2.isBlock(node[siblingName])) {
          node = node[siblingName];
          if (isEq$5(node, "br")) {
            break;
          }
        }
      }
      return node || container;
    };
    const isAtBlockBoundary$1 = (dom2, root, container, siblingName) => {
      const parent2 = container.parentNode;
      if (isNonNullable(container[siblingName])) {
        return false;
      } else if (parent2 === root || isNullable(parent2) || dom2.isBlock(parent2)) {
        return true;
      } else {
        return isAtBlockBoundary$1(dom2, root, parent2, siblingName);
      }
    };
    const findParentContainer = (dom2, formatList, container, offset, start2) => {
      let parent2 = container;
      const siblingName = start2 ? "previousSibling" : "nextSibling";
      const root = dom2.getRoot();
      if (isText$9(container) && !isWhiteSpaceNode(container)) {
        if (start2 ? offset > 0 : offset < container.data.length) {
          return container;
        }
      }
      while (true) {
        if (!formatList[0].block_expand && dom2.isBlock(parent2)) {
          return parent2;
        }
        for (let sibling2 = parent2[siblingName]; sibling2; sibling2 = sibling2[siblingName]) {
          const allowSpaces = isText$9(sibling2) && !isAtBlockBoundary$1(dom2, root, sibling2, siblingName);
          if (!isBookmarkNode(sibling2) && !isBogusBr(sibling2) && !isWhiteSpaceNode(sibling2, allowSpaces)) {
            return parent2;
          }
        }
        if (parent2 === root || parent2.parentNode === root) {
          container = parent2;
          break;
        }
        parent2 = parent2.parentNode;
      }
      return container;
    };
    const isSelfOrParentBookmark = (container) => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
    const expandRng = (editor, rng, formatList, includeTrailingSpace = false) => {
      let { startContainer, startOffset, endContainer, endOffset } = rng;
      const dom2 = editor.dom;
      const format = formatList[0];
      if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
        startContainer = getNode$1(startContainer, startOffset);
        if (isText$9(startContainer)) {
          startOffset = 0;
        }
      }
      if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
        endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
        if (isText$9(endContainer)) {
          endOffset = endContainer.nodeValue.length;
        }
      }
      startContainer = findParentContentEditable(dom2, startContainer);
      endContainer = findParentContentEditable(dom2, endContainer);
      if (isSelfOrParentBookmark(startContainer)) {
        startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
        if (rng.collapsed) {
          startContainer = startContainer.previousSibling || startContainer;
        } else {
          startContainer = startContainer.nextSibling || startContainer;
        }
        if (isText$9(startContainer)) {
          startOffset = rng.collapsed ? startContainer.length : 0;
        }
      }
      if (isSelfOrParentBookmark(endContainer)) {
        endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
        if (rng.collapsed) {
          endContainer = endContainer.nextSibling || endContainer;
        } else {
          endContainer = endContainer.previousSibling || endContainer;
        }
        if (isText$9(endContainer)) {
          endOffset = rng.collapsed ? 0 : endContainer.length;
        }
      }
      if (rng.collapsed) {
        const startPoint = findWordEndPoint(dom2, editor.getBody(), startContainer, startOffset, true, includeTrailingSpace);
        startPoint.each(({ container, offset }) => {
          startContainer = container;
          startOffset = offset;
        });
        const endPoint = findWordEndPoint(dom2, editor.getBody(), endContainer, endOffset, false, includeTrailingSpace);
        endPoint.each(({ container, offset }) => {
          endContainer = container;
          endOffset = offset;
        });
      }
      if (isInlineFormat(format) || format.block_expand) {
        if (!isInlineFormat(format) || (!isText$9(startContainer) || startOffset === 0)) {
          startContainer = findParentContainer(dom2, formatList, startContainer, startOffset, true);
        }
        if (!isInlineFormat(format) || (!isText$9(endContainer) || endOffset === endContainer.nodeValue.length)) {
          endContainer = findParentContainer(dom2, formatList, endContainer, endOffset, false);
        }
      }
      if (shouldExpandToSelector(format)) {
        startContainer = findSelectorEndPoint(dom2, formatList, rng, startContainer, "previousSibling");
        endContainer = findSelectorEndPoint(dom2, formatList, rng, endContainer, "nextSibling");
      }
      if (isBlockFormat(format) || isSelectorFormat(format)) {
        startContainer = findBlockEndPoint(editor, formatList, startContainer, "previousSibling");
        endContainer = findBlockEndPoint(editor, formatList, endContainer, "nextSibling");
        if (isBlockFormat(format)) {
          if (!dom2.isBlock(startContainer)) {
            startContainer = findParentContainer(dom2, formatList, startContainer, startOffset, true);
          }
          if (!dom2.isBlock(endContainer)) {
            endContainer = findParentContainer(dom2, formatList, endContainer, endOffset, false);
          }
        }
      }
      if (isElement$6(startContainer)) {
        startOffset = dom2.nodeIndex(startContainer);
        startContainer = startContainer.parentNode;
      }
      if (isElement$6(endContainer)) {
        endOffset = dom2.nodeIndex(endContainer) + 1;
        endContainer = endContainer.parentNode;
      }
      return {
        startContainer,
        startOffset,
        endContainer,
        endOffset
      };
    };
    const walk$3 = (dom2, rng, callback) => {
      const startOffset = rng.startOffset;
      const startContainer = getNode$1(rng.startContainer, startOffset);
      const endOffset = rng.endOffset;
      const endContainer = getNode$1(rng.endContainer, endOffset - 1);
      const exclude = (nodes) => {
        const firstNode = nodes[0];
        if (isText$9(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
          nodes.splice(0, 1);
        }
        const lastNode = nodes[nodes.length - 1];
        if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$9(lastNode)) {
          nodes.splice(nodes.length - 1, 1);
        }
        return nodes;
      };
      const collectSiblings = (node, name2, endNode) => {
        const siblings3 = [];
        for (; node && node !== endNode; node = node[name2]) {
          siblings3.push(node);
        }
        return siblings3;
      };
      const findEndPoint = (node, root) => dom2.getParent(node, (node2) => node2.parentNode === root, root);
      const walkBoundary = (startNode, endNode, next2) => {
        const siblingName = next2 ? "nextSibling" : "previousSibling";
        for (let node = startNode, parent2 = node.parentNode; node && node !== endNode; node = parent2) {
          parent2 = node.parentNode;
          const siblings3 = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
          if (siblings3.length) {
            if (!next2) {
              siblings3.reverse();
            }
            callback(exclude(siblings3));
          }
        }
      };
      if (startContainer === endContainer) {
        return callback(exclude([startContainer]));
      }
      const ancestor2 = dom2.findCommonAncestor(startContainer, endContainer);
      if (dom2.isChildOf(startContainer, endContainer)) {
        return walkBoundary(startContainer, ancestor2, true);
      }
      if (dom2.isChildOf(endContainer, startContainer)) {
        return walkBoundary(endContainer, ancestor2);
      }
      const startPoint = findEndPoint(startContainer, ancestor2) || startContainer;
      const endPoint = findEndPoint(endContainer, ancestor2) || endContainer;
      walkBoundary(startContainer, startPoint, true);
      const siblings2 = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, "nextSibling", endPoint === endContainer ? endPoint.nextSibling : endPoint);
      if (siblings2.length) {
        callback(exclude(siblings2));
      }
      walkBoundary(endContainer, endPoint);
    };
    const getRanges$1 = (selection) => {
      const ranges = [];
      if (selection) {
        for (let i = 0; i < selection.rangeCount; i++) {
          ranges.push(selection.getRangeAt(i));
        }
      }
      return ranges;
    };
    const getSelectedNodes = (ranges) => {
      return bind$3(ranges, (range2) => {
        const node = getSelectedNode(range2);
        return node ? [SugarElement.fromDom(node)] : [];
      });
    };
    const hasMultipleRanges = (selection) => {
      return getRanges$1(selection).length > 1;
    };
    const getCellsFromRanges = (ranges) => filter$6(getSelectedNodes(ranges), isTableCell$4);
    const getCellsFromElement = (elm) => descendants(elm, "td[data-mce-selected],th[data-mce-selected]");
    const getCellsFromElementOrRanges = (ranges, element) => {
      const selectedCells = getCellsFromElement(element);
      return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
    };
    const getCellsFromEditor = (editor) => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
    const getClosestTable = (cell2, isRoot2) => ancestor$2(cell2, "table", isRoot2);
    const getStartNode = (rng) => {
      const sc = rng.startContainer, so = rng.startOffset;
      if (isText$9(sc)) {
        return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
      } else {
        return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
      }
    };
    const getEndNode = (rng) => {
      const ec = rng.endContainer, eo = rng.endOffset;
      if (isText$9(ec)) {
        return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
      } else {
        return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
      }
    };
    const getFirstChildren = (node) => {
      return firstChild(node).fold(constant([node]), (child2) => {
        return [node].concat(getFirstChildren(child2));
      });
    };
    const getLastChildren$1 = (node) => {
      return lastChild(node).fold(constant([node]), (child2) => {
        if (name(child2) === "br") {
          return prevSibling(child2).map((sibling2) => {
            return [node].concat(getLastChildren$1(sibling2));
          }).getOr([]);
        } else {
          return [node].concat(getLastChildren$1(child2));
        }
      });
    };
    const hasAllContentsSelected = (elm, rng) => {
      return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
        const start2 = find$2(getFirstChildren(elm), curry(eq, startNode));
        const end2 = find$2(getLastChildren$1(elm), curry(eq, endNode));
        return start2.isSome() && end2.isSome();
      }).getOr(false);
    };
    const moveEndPoint = (dom2, rng, node, start2) => {
      const root = node, walker = new DomTreeWalker(node, root);
      const moveCaretBeforeOnEnterElementsMap = filter$5(dom2.schema.getMoveCaretBeforeOnEnterElements(), (_, name2) => !contains$2([
        "td",
        "th",
        "table"
      ], name2.toLowerCase()));
      do {
        if (isText$9(node) && Tools.trim(node.nodeValue).length !== 0) {
          if (start2) {
            rng.setStart(node, 0);
          } else {
            rng.setEnd(node, node.nodeValue.length);
          }
          return;
        }
        if (moveCaretBeforeOnEnterElementsMap[node.nodeName]) {
          if (start2) {
            rng.setStartBefore(node);
          } else {
            if (node.nodeName === "BR") {
              rng.setEndBefore(node);
            } else {
              rng.setEndAfter(node);
            }
          }
          return;
        }
      } while (node = start2 ? walker.next() : walker.prev());
      if (root.nodeName === "BODY") {
        if (start2) {
          rng.setStart(root, 0);
        } else {
          rng.setEnd(root, root.childNodes.length);
        }
      }
    };
    const hasAnyRanges = (editor) => {
      const sel = editor.selection.getSel();
      return sel && sel.rangeCount > 0;
    };
    const runOnRanges = (editor, executor) => {
      const fakeSelectionNodes = getCellsFromEditor(editor);
      if (fakeSelectionNodes.length > 0) {
        each$f(fakeSelectionNodes, (elem) => {
          const node = elem.dom;
          const fakeNodeRng = editor.dom.createRng();
          fakeNodeRng.setStartBefore(node);
          fakeNodeRng.setEndAfter(node);
          executor(fakeNodeRng, true);
        });
      } else {
        executor(editor.selection.getRng(), false);
      }
    };
    const preserve = (selection, fillBookmark, executor) => {
      const bookmark = getPersistentBookmark(selection, fillBookmark);
      executor(bookmark);
      selection.moveToBookmark(bookmark);
    };
    const NodeValue = (is2, name2) => {
      const get2 = (element) => {
        if (!is2(element)) {
          throw new Error("Can only get " + name2 + " value of a " + name2 + " node");
        }
        return getOption2(element).getOr("");
      };
      const getOption2 = (element) => is2(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
      const set2 = (element, value2) => {
        if (!is2(element)) {
          throw new Error("Can only set raw " + name2 + " value of a " + name2 + " node");
        }
        element.dom.nodeValue = value2;
      };
      return {
        get: get2,
        getOption: getOption2,
        set: set2
      };
    };
    const api$1 = NodeValue(isText$a, "text");
    const get$3 = (element) => api$1.get(element);
    const getOption = (element) => api$1.getOption(element);
    const validBlocks = [
      'pre[class*=language-][contenteditable="false"]',
      "figure.image",
      "div[data-ephox-embed-iri]",
      "div.tiny-pageembed",
      "div.mce-toc",
      "div[data-mce-toc]"
    ];
    const isZeroWidth = (elem) => isText$a(elem) && get$3(elem) === ZWSP$1;
    const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => "skipping", (parent2) => {
      if (nodeName === "br" || isZeroWidth(elem)) {
        return "valid";
      } else if (isAnnotation(elem)) {
        return "existing";
      } else if (isCaretNode(elem.dom)) {
        return "caret";
      } else if (exists(validBlocks, (selector) => is$1(elem, selector))) {
        return "valid-block";
      } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent2), wrapName)) {
        return "invalid-child";
      } else {
        return "valid";
      }
    });
    const applyWordGrab = (editor, rng) => {
      const r2 = expandRng(editor, rng, [{ inline: "span" }]);
      rng.setStart(r2.startContainer, r2.startOffset);
      rng.setEnd(r2.endContainer, r2.endOffset);
      editor.selection.setRng(rng);
    };
    const applyAnnotation = (elem, masterUId, data2, annotationName, decorate, directAnnotation) => {
      const { uid = masterUId, ...otherData } = data2;
      add$2(elem, annotation());
      set$2(elem, `${dataAnnotationId()}`, uid);
      set$2(elem, `${dataAnnotation()}`, annotationName);
      const { attributes = {}, classes = [] } = decorate(uid, otherData);
      setAll$1(elem, attributes);
      add(elem, classes);
      if (directAnnotation) {
        if (classes.length > 0) {
          set$2(elem, `${dataAnnotationClasses()}`, classes.join(","));
        }
        const attributeNames = keys(attributes);
        if (attributeNames.length > 0) {
          set$2(elem, `${dataAnnotationAttributes()}`, attributeNames.join(","));
        }
      }
    };
    const removeDirectAnnotation = (elem) => {
      remove$8(elem, annotation());
      remove$b(elem, `${dataAnnotationId()}`);
      remove$b(elem, `${dataAnnotation()}`);
      remove$b(elem, `${dataAnnotationActive()}`);
      const customAttrNames = getOpt(elem, `${dataAnnotationAttributes()}`).map((names) => names.split(",")).getOr([]);
      const customClasses = getOpt(elem, `${dataAnnotationClasses()}`).map((names) => names.split(",")).getOr([]);
      each$f(customAttrNames, (name2) => remove$b(elem, name2));
      remove$5(elem, customClasses);
      remove$b(elem, `${dataAnnotationClasses()}`);
      remove$b(elem, `${dataAnnotationAttributes()}`);
    };
    const makeAnnotation = (eDoc, uid, data2, annotationName, decorate) => {
      const master = SugarElement.fromTag("span", eDoc);
      applyAnnotation(master, uid, data2, annotationName, decorate, false);
      return master;
    };
    const annotate = (editor, rng, uid, annotationName, decorate, data2) => {
      const newWrappers = [];
      const master = makeAnnotation(editor.getDoc(), uid, data2, annotationName, decorate);
      const wrapper = value$2();
      const finishWrapper = () => {
        wrapper.clear();
      };
      const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
        const nu2 = shallow$1(master);
        newWrappers.push(nu2);
        wrapper.set(nu2);
        return nu2;
      });
      const processElements = (elems) => {
        each$f(elems, processElement);
      };
      const processElement = (elem) => {
        const ctx = context(editor, elem, "span", name(elem));
        switch (ctx) {
          case "invalid-child": {
            finishWrapper();
            const children$1 = children(elem);
            processElements(children$1);
            finishWrapper();
            break;
          }
          case "valid-block": {
            finishWrapper();
            applyAnnotation(elem, uid, data2, annotationName, decorate, true);
            break;
          }
          case "valid": {
            const w = getOrOpenWrapper();
            wrap$2(elem, w);
            break;
          }
        }
      };
      const processNodes = (nodes) => {
        const elems = map$3(nodes, SugarElement.fromDom);
        processElements(elems);
      };
      walk$3(editor.dom, rng, (nodes) => {
        finishWrapper();
        processNodes(nodes);
      });
      return newWrappers;
    };
    const annotateWithBookmark = (editor, name2, settings, data2) => {
      editor.undoManager.transact(() => {
        const selection = editor.selection;
        const initialRng = selection.getRng();
        const hasFakeSelection = getCellsFromEditor(editor).length > 0;
        const masterUid = generate$1("mce-annotation");
        if (initialRng.collapsed && !hasFakeSelection) {
          applyWordGrab(editor, initialRng);
        }
        if (selection.getRng().collapsed && !hasFakeSelection) {
          const wrapper = makeAnnotation(editor.getDoc(), masterUid, data2, name2, settings.decorate);
          set(wrapper, nbsp);
          selection.getRng().insertNode(wrapper.dom);
          selection.select(wrapper.dom);
        } else {
          preserve(selection, false, () => {
            runOnRanges(editor, (selectionRng) => {
              annotate(editor, selectionRng, masterUid, name2, settings.decorate, data2);
            });
          });
        }
      });
    };
    const Annotator = (editor) => {
      const registry2 = create$c();
      setup$w(editor, registry2);
      const changes = setup$x(editor, registry2);
      const isSpan2 = isTag("span");
      const removeAnnotations = (elements) => {
        each$f(elements, (element) => {
          if (isSpan2(element)) {
            unwrap(element);
          } else {
            removeDirectAnnotation(element);
          }
        });
      };
      return {
        register: (name2, settings) => {
          registry2.register(name2, settings);
        },
        annotate: (name2, data2) => {
          registry2.lookup(name2).each((settings) => {
            annotateWithBookmark(editor, name2, settings, data2);
          });
        },
        annotationChanged: (name2, callback) => {
          changes.addListener(name2, callback);
        },
        remove: (name2) => {
          const bookmark = editor.selection.getBookmark();
          identify(editor, Optional.some(name2)).each(({ elements }) => {
            removeAnnotations(elements);
          });
          editor.selection.moveToBookmark(bookmark);
        },
        removeAll: (name2) => {
          const bookmark = editor.selection.getBookmark();
          each$e(findAll(editor, name2), (elements, _) => {
            removeAnnotations(elements);
          });
          editor.selection.moveToBookmark(bookmark);
        },
        getAll: (name2) => {
          const directory = findAll(editor, name2);
          return map$2(directory, (elems) => map$3(elems, (elem) => elem.dom));
        }
      };
    };
    const BookmarkManager = (selection) => {
      return {
        getBookmark: curry(getBookmark$1, selection),
        moveToBookmark: curry(moveToBookmark, selection)
      };
    };
    BookmarkManager.isBookmarkNode = isBookmarkNode$1;
    const isXYWithinRange = (clientX, clientY, range2) => {
      if (range2.collapsed) {
        return false;
      } else {
        return exists(range2.getClientRects(), (rect) => containsXY(rect, clientX, clientY));
      }
    };
    const firePreProcess = (editor, args) => editor.dispatch("PreProcess", args);
    const firePostProcess = (editor, args) => editor.dispatch("PostProcess", args);
    const fireRemove = (editor) => editor.dispatch("remove");
    const fireDetach = (editor) => editor.dispatch("detach");
    const fireSwitchMode = (editor, mode) => editor.dispatch("SwitchMode", { mode });
    const fireObjectResizeStart = (editor, target, width, height, origin) => {
      editor.dispatch("ObjectResizeStart", {
        target,
        width,
        height,
        origin
      });
    };
    const fireObjectResized = (editor, target, width, height, origin) => {
      editor.dispatch("ObjectResized", {
        target,
        width,
        height,
        origin
      });
    };
    const firePreInit = (editor) => editor.dispatch("PreInit");
    const firePostRender = (editor) => editor.dispatch("PostRender");
    const fireInit = (editor) => editor.dispatch("Init");
    const firePlaceholderToggle = (editor, state) => editor.dispatch("PlaceholderToggle", { state });
    const fireError = (editor, errorType, error2) => editor.dispatch(errorType, error2);
    const fireFormatApply = (editor, format, node, vars) => editor.dispatch("FormatApply", {
      format,
      node,
      vars
    });
    const fireFormatRemove = (editor, format, node, vars) => editor.dispatch("FormatRemove", {
      format,
      node,
      vars
    });
    const fireBeforeSetContent = (editor, args) => editor.dispatch("BeforeSetContent", args);
    const fireSetContent = (editor, args) => editor.dispatch("SetContent", args);
    const fireBeforeGetContent = (editor, args) => editor.dispatch("BeforeGetContent", args);
    const fireGetContent = (editor, args) => editor.dispatch("GetContent", args);
    const fireAutocompleterStart = (editor, args) => editor.dispatch("AutocompleterStart", args);
    const fireAutocompleterUpdate = (editor, args) => editor.dispatch("AutocompleterUpdate", args);
    const fireAutocompleterEnd = (editor) => editor.dispatch("AutocompleterEnd");
    const firePastePreProcess = (editor, html2, internal) => editor.dispatch("PastePreProcess", {
      content: html2,
      internal
    });
    const firePastePostProcess = (editor, node, internal) => editor.dispatch("PastePostProcess", {
      node,
      internal
    });
    const firePastePlainTextToggle = (editor, state) => editor.dispatch("PastePlainTextToggle", { state });
    const VK = {
      BACKSPACE: 8,
      DELETE: 46,
      DOWN: 40,
      ENTER: 13,
      ESC: 27,
      LEFT: 37,
      RIGHT: 39,
      SPACEBAR: 32,
      TAB: 9,
      UP: 38,
      PAGE_UP: 33,
      PAGE_DOWN: 34,
      END: 35,
      HOME: 36,
      modifierPressed: (e) => {
        return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
      },
      metaKeyPressed: (e) => {
        return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
      }
    };
    const elementSelectionAttr = "data-mce-selected";
    const controlElmSelector = "table,img,figure.image,hr,video,span.mce-preview-object";
    const abs = Math.abs;
    const round$1 = Math.round;
    const resizeHandles = {
      nw: [
        0,
        0,
        -1,
        -1
      ],
      ne: [
        1,
        0,
        1,
        -1
      ],
      se: [
        1,
        1,
        1,
        1
      ],
      sw: [
        0,
        1,
        -1,
        1
      ]
    };
    const isTouchEvent = (evt) => evt.type === "longpress" || evt.type.indexOf("touch") === 0;
    const ControlSelection = (selection, editor) => {
      const dom2 = editor.dom;
      const editableDoc = editor.getDoc();
      const rootDocument = document;
      const rootElement = editor.getBody();
      let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
      let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
      let width;
      let height;
      let startScrollWidth;
      let startScrollHeight;
      const isImage2 = (elm) => isNonNullable(elm) && (isImg(elm) || dom2.is(elm, "figure.image"));
      const isMedia2 = (elm) => isMedia$2(elm) || dom2.hasClass(elm, "mce-preview-object");
      const isEventOnImageOutsideRange = (evt, range2) => {
        if (isTouchEvent(evt)) {
          const touch = evt.touches[0];
          return isImage2(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range2);
        } else {
          return isImage2(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range2);
        }
      };
      const contextMenuSelectImage = (evt) => {
        const target = evt.target;
        if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
          editor.selection.select(target);
        }
      };
      const getResizeTargets = (elm) => {
        if (dom2.is(elm, "figure.image")) {
          return [elm.querySelector("img")];
        } else if (dom2.hasClass(elm, "mce-preview-object") && isNonNullable(elm.firstElementChild)) {
          return [
            elm,
            elm.firstElementChild
          ];
        } else {
          return [elm];
        }
      };
      const isResizable = (elm) => {
        const selector = getObjectResizing(editor);
        if (!selector) {
          return false;
        }
        if (elm.getAttribute("data-mce-resize") === "false") {
          return false;
        }
        if (elm === editor.getBody()) {
          return false;
        }
        if (dom2.hasClass(elm, "mce-preview-object")) {
          return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
        } else {
          return is$1(SugarElement.fromDom(elm), selector);
        }
      };
      const createGhostElement = (elm) => {
        if (isMedia2(elm)) {
          return dom2.create("img", { src: Env.transparentSrc });
        } else {
          return elm.cloneNode(true);
        }
      };
      const setSizeProp = (element, name2, value2) => {
        if (isNonNullable(value2)) {
          const targets = getResizeTargets(element);
          each$f(targets, (target) => {
            if (target.style[name2] || !editor.schema.isValid(target.nodeName.toLowerCase(), name2)) {
              dom2.setStyle(target, name2, value2);
            } else {
              dom2.setAttrib(target, name2, "" + value2);
            }
          });
        }
      };
      const setGhostElmSize = (ghostElm, width2, height2) => {
        setSizeProp(ghostElm, "width", width2);
        setSizeProp(ghostElm, "height", height2);
      };
      const resizeGhostElement = (e) => {
        let deltaX, deltaY, proportional;
        let resizeHelperX, resizeHelperY;
        deltaX = e.screenX - startX;
        deltaY = e.screenY - startY;
        width = deltaX * selectedHandle[2] + startW;
        height = deltaY * selectedHandle[3] + startH;
        width = width < 5 ? 5 : width;
        height = height < 5 ? 5 : height;
        if ((isImage2(selectedElm) || isMedia2(selectedElm)) && getResizeImgProportional(editor) !== false) {
          proportional = !VK.modifierPressed(e);
        } else {
          proportional = VK.modifierPressed(e);
        }
        if (proportional) {
          if (abs(deltaX) > abs(deltaY)) {
            height = round$1(width * ratio);
            width = round$1(height / ratio);
          } else {
            width = round$1(height / ratio);
            height = round$1(width * ratio);
          }
        }
        setGhostElmSize(selectedElmGhost, width, height);
        resizeHelperX = selectedHandle.startPos.x + deltaX;
        resizeHelperY = selectedHandle.startPos.y + deltaY;
        resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
        resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
        dom2.setStyles(resizeHelper, {
          left: resizeHelperX,
          top: resizeHelperY,
          display: "block"
        });
        resizeHelper.innerHTML = width + " &times; " + height;
        if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
          dom2.setStyle(selectedElmGhost, "left", selectedElmX + (startW - width));
        }
        if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
          dom2.setStyle(selectedElmGhost, "top", selectedElmY + (startH - height));
        }
        deltaX = rootElement.scrollWidth - startScrollWidth;
        deltaY = rootElement.scrollHeight - startScrollHeight;
        if (deltaX + deltaY !== 0) {
          dom2.setStyles(resizeHelper, {
            left: resizeHelperX - deltaX,
            top: resizeHelperY - deltaY
          });
        }
        if (!resizeStarted) {
          fireObjectResizeStart(editor, selectedElm, startW, startH, "corner-" + selectedHandle.name);
          resizeStarted = true;
        }
      };
      const endGhostResize = () => {
        const wasResizeStarted = resizeStarted;
        resizeStarted = false;
        if (wasResizeStarted) {
          setSizeProp(selectedElm, "width", width);
          setSizeProp(selectedElm, "height", height);
        }
        dom2.unbind(editableDoc, "mousemove", resizeGhostElement);
        dom2.unbind(editableDoc, "mouseup", endGhostResize);
        if (rootDocument !== editableDoc) {
          dom2.unbind(rootDocument, "mousemove", resizeGhostElement);
          dom2.unbind(rootDocument, "mouseup", endGhostResize);
        }
        dom2.remove(selectedElmGhost);
        dom2.remove(resizeHelper);
        dom2.remove(resizeBackdrop);
        showResizeRect(selectedElm);
        if (wasResizeStarted) {
          fireObjectResized(editor, selectedElm, width, height, "corner-" + selectedHandle.name);
          dom2.setAttrib(selectedElm, "style", dom2.getAttrib(selectedElm, "style"));
        }
        editor.nodeChanged();
      };
      const showResizeRect = (targetElm) => {
        unbindResizeHandleEvents();
        const position = dom2.getPos(targetElm, rootElement);
        const selectedElmX2 = position.x;
        const selectedElmY2 = position.y;
        const rect = targetElm.getBoundingClientRect();
        const targetWidth = rect.width || rect.right - rect.left;
        const targetHeight = rect.height || rect.bottom - rect.top;
        if (selectedElm !== targetElm) {
          hideResizeRect();
          selectedElm = targetElm;
          width = height = 0;
        }
        const e = editor.dispatch("ObjectSelected", { target: targetElm });
        if (isResizable(targetElm) && !e.isDefaultPrevented()) {
          each$e(resizeHandles, (handle2, name2) => {
            let handleElm;
            const startDrag = (e2) => {
              const target = getResizeTargets(selectedElm)[0];
              startX = e2.screenX;
              startY = e2.screenY;
              startW = target.clientWidth;
              startH = target.clientHeight;
              ratio = startH / startW;
              selectedHandle = handle2;
              selectedHandle.name = name2;
              selectedHandle.startPos = {
                x: targetWidth * handle2[0] + selectedElmX2,
                y: targetHeight * handle2[1] + selectedElmY2
              };
              startScrollWidth = rootElement.scrollWidth;
              startScrollHeight = rootElement.scrollHeight;
              resizeBackdrop = dom2.add(rootElement, "div", {
                "class": "mce-resize-backdrop",
                "data-mce-bogus": "all"
              });
              dom2.setStyles(resizeBackdrop, {
                position: "fixed",
                left: "0",
                top: "0",
                width: "100%",
                height: "100%"
              });
              selectedElmGhost = createGhostElement(selectedElm);
              dom2.addClass(selectedElmGhost, "mce-clonedresizable");
              dom2.setAttrib(selectedElmGhost, "data-mce-bogus", "all");
              selectedElmGhost.contentEditable = "false";
              dom2.setStyles(selectedElmGhost, {
                left: selectedElmX2,
                top: selectedElmY2,
                margin: 0
              });
              setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
              selectedElmGhost.removeAttribute(elementSelectionAttr);
              rootElement.appendChild(selectedElmGhost);
              dom2.bind(editableDoc, "mousemove", resizeGhostElement);
              dom2.bind(editableDoc, "mouseup", endGhostResize);
              if (rootDocument !== editableDoc) {
                dom2.bind(rootDocument, "mousemove", resizeGhostElement);
                dom2.bind(rootDocument, "mouseup", endGhostResize);
              }
              resizeHelper = dom2.add(rootElement, "div", {
                "class": "mce-resize-helper",
                "data-mce-bogus": "all"
              }, startW + " &times; " + startH);
            };
            handleElm = dom2.get("mceResizeHandle" + name2);
            if (handleElm) {
              dom2.remove(handleElm);
            }
            handleElm = dom2.add(rootElement, "div", {
              "id": "mceResizeHandle" + name2,
              "data-mce-bogus": "all",
              "class": "mce-resizehandle",
              "unselectable": true,
              "style": "cursor:" + name2 + "-resize; margin:0; padding:0"
            });
            dom2.bind(handleElm, "mousedown", (e2) => {
              e2.stopImmediatePropagation();
              e2.preventDefault();
              startDrag(e2);
            });
            handle2.elm = handleElm;
            dom2.setStyles(handleElm, {
              left: targetWidth * handle2[0] + selectedElmX2 - handleElm.offsetWidth / 2,
              top: targetHeight * handle2[1] + selectedElmY2 - handleElm.offsetHeight / 2
            });
          });
        } else {
          hideResizeRect(false);
        }
      };
      const throttledShowResizeRect = first$1(showResizeRect, 0);
      const hideResizeRect = (removeSelected = true) => {
        throttledShowResizeRect.cancel();
        unbindResizeHandleEvents();
        if (selectedElm && removeSelected) {
          selectedElm.removeAttribute(elementSelectionAttr);
        }
        each$e(resizeHandles, (value2, name2) => {
          const handleElm = dom2.get("mceResizeHandle" + name2);
          if (handleElm) {
            dom2.unbind(handleElm);
            dom2.remove(handleElm);
          }
        });
      };
      const isChildOrEqual = (node, parent2) => isNonNullable(node) && dom2.isChildOf(node, parent2);
      const updateResizeRect = (e) => {
        if (resizeStarted || editor.removed || editor.composing) {
          return;
        }
        const targetElm = e.type === "mousedown" ? e.target : selection.getNode();
        const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map((e2) => e2.dom).getOrUndefined();
        const selectedValue = isNonNullable(controlElm) ? dom2.getAttrib(controlElm, elementSelectionAttr, "1") : "1";
        each$f(dom2.select(`img[${elementSelectionAttr}],hr[${elementSelectionAttr}]`), (img) => {
          img.removeAttribute(elementSelectionAttr);
        });
        if (isChildOrEqual(controlElm, rootElement)) {
          disableGeckoResize();
          const startElm = selection.getStart(true);
          if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
            dom2.setAttrib(controlElm, elementSelectionAttr, selectedValue);
            throttledShowResizeRect.throttle(controlElm);
            return;
          }
        }
        hideResizeRect();
      };
      const unbindResizeHandleEvents = () => {
        each$e(resizeHandles, (handle2) => {
          if (handle2.elm) {
            dom2.unbind(handle2.elm);
            delete handle2.elm;
          }
        });
      };
      const disableGeckoResize = () => {
        try {
          editor.getDoc().execCommand("enableObjectResizing", false, "false");
        } catch (ex) {
        }
      };
      editor.on("init", () => {
        disableGeckoResize();
        editor.on("NodeChange ResizeEditor ResizeWindow ResizeContent drop", updateResizeRect);
        editor.on("keyup compositionend", (e) => {
          if (selectedElm && selectedElm.nodeName === "TABLE") {
            updateResizeRect(e);
          }
        });
        editor.on("hide blur", hideResizeRect);
        editor.on("contextmenu longpress", contextMenuSelectImage, true);
      });
      editor.on("remove", unbindResizeHandleEvents);
      const destroy2 = () => {
        throttledShowResizeRect.cancel();
        selectedElm = selectedElmGhost = resizeBackdrop = null;
      };
      return {
        isResizable,
        showResizeRect,
        hideResizeRect,
        updateResizeRect,
        destroy: destroy2
      };
    };
    const setStart = (rng, situ) => {
      situ.fold((e) => {
        rng.setStartBefore(e.dom);
      }, (e, o) => {
        rng.setStart(e.dom, o);
      }, (e) => {
        rng.setStartAfter(e.dom);
      });
    };
    const setFinish = (rng, situ) => {
      situ.fold((e) => {
        rng.setEndBefore(e.dom);
      }, (e, o) => {
        rng.setEnd(e.dom, o);
      }, (e) => {
        rng.setEndAfter(e.dom);
      });
    };
    const relativeToNative = (win, startSitu, finishSitu) => {
      const range2 = win.document.createRange();
      setStart(range2, startSitu);
      setFinish(range2, finishSitu);
      return range2;
    };
    const exactToNative = (win, start2, soffset, finish, foffset) => {
      const rng = win.document.createRange();
      rng.setStart(start2.dom, soffset);
      rng.setEnd(finish.dom, foffset);
      return rng;
    };
    const adt$3 = Adt.generate([
      {
        ltr: [
          "start",
          "soffset",
          "finish",
          "foffset"
        ]
      },
      {
        rtl: [
          "start",
          "soffset",
          "finish",
          "foffset"
        ]
      }
    ]);
    const fromRange = (win, type2, range2) => type2(SugarElement.fromDom(range2.startContainer), range2.startOffset, SugarElement.fromDom(range2.endContainer), range2.endOffset);
    const getRanges = (win, selection) => selection.match({
      domRange: (rng) => {
        return {
          ltr: constant(rng),
          rtl: Optional.none
        };
      },
      relative: (startSitu, finishSitu) => {
        return {
          ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
          rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
        };
      },
      exact: (start2, soffset, finish, foffset) => {
        return {
          ltr: cached(() => exactToNative(win, start2, soffset, finish, foffset)),
          rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start2, soffset)))
        };
      }
    });
    const doDiagnose = (win, ranges) => {
      const rng = ranges.ltr();
      if (rng.collapsed) {
        const reversed = ranges.rtl().filter((rev) => rev.collapsed === false);
        return reversed.map((rev) => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
      } else {
        return fromRange(win, adt$3.ltr, rng);
      }
    };
    const diagnose = (win, selection) => {
      const ranges = getRanges(win, selection);
      return doDiagnose(win, ranges);
    };
    adt$3.ltr;
    adt$3.rtl;
    const create$a = (start2, soffset, finish, foffset) => ({
      start: start2,
      soffset,
      finish,
      foffset
    });
    const SimRange = { create: create$a };
    const caretPositionFromPoint = (doc, x, y) => {
      var _a, _b;
      return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind((pos) => {
        if (pos.offsetNode === null) {
          return Optional.none();
        }
        const r2 = doc.dom.createRange();
        r2.setStart(pos.offsetNode, pos.offset);
        r2.collapse();
        return Optional.some(r2);
      });
    };
    const caretRangeFromPoint = (doc, x, y) => {
      var _a, _b;
      return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
    };
    const availableSearch = (() => {
      if (document.caretPositionFromPoint) {
        return caretPositionFromPoint;
      } else if (document.caretRangeFromPoint) {
        return caretRangeFromPoint;
      } else {
        return Optional.none;
      }
    })();
    const fromPoint$1 = (win, x, y) => {
      const doc = SugarElement.fromDom(win.document);
      return availableSearch(doc, x, y).map((rng) => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
    };
    const adt$2 = Adt.generate([
      { before: ["element"] },
      {
        on: [
          "element",
          "offset"
        ]
      },
      { after: ["element"] }
    ]);
    const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
    const getStart$2 = (situ) => situ.fold(identity, identity, identity);
    const before$1 = adt$2.before;
    const on = adt$2.on;
    const after$1 = adt$2.after;
    const Situ = {
      before: before$1,
      on,
      after: after$1,
      cata,
      getStart: getStart$2
    };
    const adt$1 = Adt.generate([
      { domRange: ["rng"] },
      {
        relative: [
          "startSitu",
          "finishSitu"
        ]
      },
      {
        exact: [
          "start",
          "soffset",
          "finish",
          "foffset"
        ]
      }
    ]);
    const exactFromRange = (simRange) => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
    const getStart$1 = (selection) => selection.match({
      domRange: (rng) => SugarElement.fromDom(rng.startContainer),
      relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
      exact: (start2, _soffset, _finish, _foffset) => start2
    });
    const domRange = adt$1.domRange;
    const relative = adt$1.relative;
    const exact = adt$1.exact;
    const getWin = (selection) => {
      const start2 = getStart$1(selection);
      return defaultView(start2);
    };
    const range = SimRange.create;
    const SimSelection = {
      domRange,
      relative,
      exact,
      exactFromRange,
      getWin,
      range
    };
    const beforeSpecial = (element, offset) => {
      const name$1 = name(element);
      if (name$1 === "input") {
        return Situ.after(element);
      } else if (!contains$2([
        "br",
        "img"
      ], name$1)) {
        return Situ.on(element, offset);
      } else {
        return offset === 0 ? Situ.before(element) : Situ.after(element);
      }
    };
    const preprocessRelative = (startSitu, finishSitu) => {
      const start2 = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
      const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
      return SimSelection.relative(start2, finish);
    };
    const preprocessExact = (start2, soffset, finish, foffset) => {
      const startSitu = beforeSpecial(start2, soffset);
      const finishSitu = beforeSpecial(finish, foffset);
      return SimSelection.relative(startSitu, finishSitu);
    };
    const preprocess = (selection) => selection.match({
      domRange: (rng) => {
        const start2 = SugarElement.fromDom(rng.startContainer);
        const finish = SugarElement.fromDom(rng.endContainer);
        return preprocessExact(start2, rng.startOffset, finish, rng.endOffset);
      },
      relative: preprocessRelative,
      exact: preprocessExact
    });
    const fromElements = (elements, scope) => {
      const doc = scope || document;
      const fragment = doc.createDocumentFragment();
      each$f(elements, (element) => {
        fragment.appendChild(element.dom);
      });
      return SugarElement.fromDom(fragment);
    };
    const toNative = (selection) => {
      const win = SimSelection.getWin(selection).dom;
      const getDomRange = (start2, soffset, finish, foffset) => exactToNative(win, start2, soffset, finish, foffset);
      const filtered = preprocess(selection);
      return diagnose(win, filtered).match({
        ltr: getDomRange,
        rtl: getDomRange
      });
    };
    const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
    const fromPoint = (clientX, clientY, doc) => getAtPoint(doc.defaultView, clientX, clientY).map((simRange) => {
      const rng = doc.createRange();
      rng.setStart(simRange.start.dom, simRange.soffset);
      rng.setEnd(simRange.finish.dom, simRange.foffset);
      return rng;
    }).getOrUndefined();
    const isEq$4 = (rng1, rng2) => {
      return rng1 && rng2 && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
    };
    const findParent = (node, rootNode, predicate) => {
      while (node && node !== rootNode) {
        if (predicate(node)) {
          return node;
        }
        node = node.parentNode;
      }
      return null;
    };
    const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
    const hasParentWithName = (node, rootNode, name2) => hasParent$1(node, rootNode, (node2) => {
      return node2.nodeName === name2;
    });
    const isTable = (node) => node && node.nodeName === "TABLE";
    const isTableCell$2 = (node) => node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
    const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && hasParent$1(node, rootNode, isCaretNode) === false;
    const hasBrBeforeAfter = (dom2, node, left) => {
      const walker = new DomTreeWalker(node, dom2.getParent(node.parentNode, dom2.isBlock) || dom2.getRoot());
      while (node = walker[left ? "prev" : "next"]()) {
        if (isBr$6(node)) {
          return true;
        }
      }
    };
    const isPrevNode = (node, name2) => node.previousSibling && node.previousSibling.nodeName === name2;
    const hasContentEditableFalseParent = (body, node) => {
      while (node && node !== body) {
        if (isContentEditableFalse$b(node)) {
          return true;
        }
        node = node.parentNode;
      }
      return false;
    };
    const findTextNodeRelative = (dom2, isAfterNode, collapsed, left, startNode) => {
      let lastInlineElement;
      const body = dom2.getRoot();
      let node;
      const nonEmptyElementsMap = dom2.schema.getNonEmptyElements();
      const parentBlockContainer = dom2.getParent(startNode.parentNode, dom2.isBlock) || body;
      if (left && isBr$6(startNode) && isAfterNode && dom2.isEmpty(parentBlockContainer)) {
        return Optional.some(CaretPosition(startNode.parentNode, dom2.nodeIndex(startNode)));
      }
      const walker = new DomTreeWalker(startNode, parentBlockContainer);
      while (node = walker[left ? "prev" : "next"]()) {
        if (dom2.getContentEditableParent(node) === "false" || isCeFalseCaretContainer(node, body)) {
          return Optional.none();
        }
        if (isText$9(node) && node.nodeValue.length > 0) {
          if (hasParentWithName(node, body, "A") === false) {
            return Optional.some(CaretPosition(node, left ? node.nodeValue.length : 0));
          }
          return Optional.none();
        }
        if (dom2.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
          return Optional.none();
        }
        lastInlineElement = node;
      }
      if (isComment(lastInlineElement)) {
        return Optional.none();
      }
      if (collapsed && lastInlineElement) {
        return Optional.some(CaretPosition(lastInlineElement, 0));
      }
      return Optional.none();
    };
    const normalizeEndPoint = (dom2, collapsed, start2, rng) => {
      let container, offset;
      const body = dom2.getRoot();
      let node;
      let directionLeft, normalized = false;
      container = rng[(start2 ? "start" : "end") + "Container"];
      offset = rng[(start2 ? "start" : "end") + "Offset"];
      const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
      const nonEmptyElementsMap = dom2.schema.getNonEmptyElements();
      directionLeft = start2;
      if (isCaretContainer$2(container)) {
        return Optional.none();
      }
      if (isElement$6(container) && offset > container.childNodes.length - 1) {
        directionLeft = false;
      }
      if (isDocument$1(container)) {
        container = body;
        offset = 0;
      }
      if (container === body) {
        if (directionLeft) {
          node = container.childNodes[offset > 0 ? offset - 1 : 0];
          if (node) {
            if (isCaretContainer$2(node)) {
              return Optional.none();
            }
            if (nonEmptyElementsMap[node.nodeName] || isTable(node)) {
              return Optional.none();
            }
          }
        }
        if (container.hasChildNodes()) {
          offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
          container = container.childNodes[offset];
          offset = isText$9(container) && isAfterNode ? container.data.length : 0;
          if (!collapsed && container === body.lastChild && isTable(container)) {
            return Optional.none();
          }
          if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
            return Optional.none();
          }
          if (container.hasChildNodes() && isTable(container) === false) {
            node = container;
            const walker = new DomTreeWalker(container, body);
            do {
              if (isContentEditableFalse$b(node) || isCaretContainer$2(node)) {
                normalized = false;
                break;
              }
              if (isText$9(node) && node.nodeValue.length > 0) {
                offset = directionLeft ? 0 : node.nodeValue.length;
                container = node;
                normalized = true;
                break;
              }
              if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCell$2(node)) {
                offset = dom2.nodeIndex(node);
                container = node.parentNode;
                if (!directionLeft) {
                  offset++;
                }
                normalized = true;
                break;
              }
            } while (node = directionLeft ? walker.next() : walker.prev());
          }
        }
      }
      if (collapsed) {
        if (isText$9(container) && offset === 0) {
          findTextNodeRelative(dom2, isAfterNode, collapsed, true, container).each((pos) => {
            container = pos.container();
            offset = pos.offset();
            normalized = true;
          });
        }
        if (isElement$6(container)) {
          node = container.childNodes[offset];
          if (!node) {
            node = container.childNodes[offset - 1];
          }
          if (node && isBr$6(node) && !isPrevNode(node, "A") && !hasBrBeforeAfter(dom2, node, false) && !hasBrBeforeAfter(dom2, node, true)) {
            findTextNodeRelative(dom2, isAfterNode, collapsed, true, node).each((pos) => {
              container = pos.container();
              offset = pos.offset();
              normalized = true;
            });
          }
        }
      }
      if (directionLeft && !collapsed && isText$9(container) && offset === container.nodeValue.length) {
        findTextNodeRelative(dom2, isAfterNode, collapsed, false, container).each((pos) => {
          container = pos.container();
          offset = pos.offset();
          normalized = true;
        });
      }
      return normalized ? Optional.some(CaretPosition(container, offset)) : Optional.none();
    };
    const normalize$2 = (dom2, rng) => {
      const collapsed = rng.collapsed, normRng = rng.cloneRange();
      const startPos = CaretPosition.fromRangeStart(rng);
      normalizeEndPoint(dom2, collapsed, true, normRng).each((pos) => {
        if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
          normRng.setStart(pos.container(), pos.offset());
        }
      });
      if (!collapsed) {
        normalizeEndPoint(dom2, collapsed, false, normRng).each((pos) => {
          normRng.setEnd(pos.container(), pos.offset());
        });
      }
      if (collapsed) {
        normRng.collapse(true);
      }
      return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
    };
    const splitText = (node, offset) => {
      return node.splitText(offset);
    };
    const split = (rng) => {
      let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
      if (startContainer === endContainer && isText$9(startContainer)) {
        if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
          endContainer = splitText(startContainer, startOffset);
          startContainer = endContainer.previousSibling;
          if (endOffset > startOffset) {
            endOffset = endOffset - startOffset;
            startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
            endOffset = endContainer.nodeValue.length;
            startOffset = 0;
          } else {
            endOffset = 0;
          }
        }
      } else {
        if (isText$9(startContainer) && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
          startContainer = splitText(startContainer, startOffset);
          startOffset = 0;
        }
        if (isText$9(endContainer) && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
          endContainer = splitText(endContainer, endOffset).previousSibling;
          endOffset = endContainer.nodeValue.length;
        }
      }
      return {
        startContainer,
        startOffset,
        endContainer,
        endOffset
      };
    };
    const RangeUtils = (dom2) => {
      const walk2 = (rng, callback) => {
        return walk$3(dom2, rng, callback);
      };
      const split$12 = split;
      const normalize2 = (rng) => {
        return normalize$2(dom2, rng).fold(never, (normalizedRng) => {
          rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
          rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
          return true;
        });
      };
      return {
        walk: walk2,
        split: split$12,
        normalize: normalize2
      };
    };
    RangeUtils.compareRanges = isEq$4;
    RangeUtils.getCaretRangeFromPoint = fromPoint;
    RangeUtils.getSelectedNode = getSelectedNode;
    RangeUtils.getNode = getNode$1;
    const Dimension = (name2, getOffset) => {
      const set2 = (element, h2) => {
        if (!isNumber(h2) && !h2.match(/^[0-9]+$/)) {
          throw new Error(name2 + ".set accepts only positive integer values. Value was " + h2);
        }
        const dom2 = element.dom;
        if (isSupported$1(dom2)) {
          dom2.style[name2] = h2 + "px";
        }
      };
      const get2 = (element) => {
        const r2 = getOffset(element);
        if (r2 <= 0 || r2 === null) {
          const css = get$7(element, name2);
          return parseFloat(css) || 0;
        }
        return r2;
      };
      const getOuter2 = get2;
      const aggregate = (element, properties) => foldl(properties, (acc, property) => {
        const val = get$7(element, property);
        const value2 = val === void 0 ? 0 : parseInt(val, 10);
        return isNaN(value2) ? acc : acc + value2;
      }, 0);
      const max2 = (element, value2, properties) => {
        const cumulativeInclusions = aggregate(element, properties);
        const absoluteMax = value2 > cumulativeInclusions ? value2 - cumulativeInclusions : 0;
        return absoluteMax;
      };
      return {
        set: set2,
        get: get2,
        getOuter: getOuter2,
        aggregate,
        max: max2
      };
    };
    const api = Dimension("height", (element) => {
      const dom2 = element.dom;
      return inBody(element) ? dom2.getBoundingClientRect().height : dom2.offsetHeight;
    });
    const get$2 = (element) => api.get(element);
    const getDocument = () => SugarElement.fromDom(document);
    const walkUp = (navigation, doc) => {
      const frame = navigation.view(doc);
      return frame.fold(constant([]), (f) => {
        const parent2 = navigation.owner(f);
        const rest = walkUp(navigation, parent2);
        return [f].concat(rest);
      });
    };
    const pathTo = (element, navigation) => {
      const d = navigation.owner(element);
      return walkUp(navigation, d);
    };
    const view = (doc) => {
      var _a;
      const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
      return element.map(SugarElement.fromDom);
    };
    const owner = (element) => documentOrOwner(element);
    var Navigation = /* @__PURE__ */ Object.freeze({
      __proto__: null,
      view,
      owner
    });
    const find = (element) => {
      const doc = getDocument();
      const scroll = get$5(doc);
      const frames = pathTo(element, Navigation);
      const offset = viewport(element);
      const r2 = foldr(frames, (b, a) => {
        const loc = viewport(a);
        return {
          left: b.left + loc.left,
          top: b.top + loc.top
        };
      }, {
        left: 0,
        top: 0
      });
      return SugarPosition(r2.left + offset.left + scroll.left, r2.top + offset.top + scroll.top);
    };
    const excludeFromDescend = (element) => name(element) === "textarea";
    const fireScrollIntoViewEvent = (editor, data2) => {
      const scrollEvent = editor.dispatch("ScrollIntoView", data2);
      return scrollEvent.isDefaultPrevented();
    };
    const fireAfterScrollIntoViewEvent = (editor, data2) => {
      editor.dispatch("AfterScrollIntoView", data2);
    };
    const descend = (element, offset) => {
      const children$1 = children(element);
      if (children$1.length === 0 || excludeFromDescend(element)) {
        return {
          element,
          offset
        };
      } else if (offset < children$1.length && !excludeFromDescend(children$1[offset])) {
        return {
          element: children$1[offset],
          offset: 0
        };
      } else {
        const last2 = children$1[children$1.length - 1];
        if (excludeFromDescend(last2)) {
          return {
            element,
            offset
          };
        } else {
          if (name(last2) === "img") {
            return {
              element: last2,
              offset: 1
            };
          } else if (isText$a(last2)) {
            return {
              element: last2,
              offset: get$3(last2).length
            };
          } else {
            return {
              element: last2,
              offset: children(last2).length
            };
          }
        }
      }
    };
    const markerInfo = (element, cleanupFun) => {
      const pos = absolute(element);
      const height = get$2(element);
      return {
        element,
        bottom: pos.top + height,
        height,
        pos,
        cleanup: cleanupFun
      };
    };
    const createMarker$1 = (element, offset) => {
      const startPoint = descend(element, offset);
      const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + "</span>");
      before$3(startPoint.element, span);
      return markerInfo(span, () => remove$6(span));
    };
    const elementMarker = (element) => markerInfo(SugarElement.fromDom(element), noop);
    const withMarker = (editor, f, rng, alignToTop) => {
      preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
    };
    const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
      const data2 = {
        elm: marker.element.dom,
        alignToTop
      };
      if (fireScrollIntoViewEvent(editor, data2)) {
        return;
      }
      const scrollTop = get$5(doc).top;
      f(doc, scrollTop, marker, alignToTop);
      fireAfterScrollIntoViewEvent(editor, data2);
    };
    const applyWithMarker = (editor, f, rng, alignToTop) => {
      const body = SugarElement.fromDom(editor.getBody());
      const doc = SugarElement.fromDom(editor.getDoc());
      reflow(body);
      const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
      withScrollEvents(editor, doc, f, marker, alignToTop);
      marker.cleanup();
    };
    const withElement = (editor, element, f, alignToTop) => {
      const doc = SugarElement.fromDom(editor.getDoc());
      withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
    };
    const preserveWith = (editor, f, rng) => {
      const startElement = rng.startContainer;
      const startOffset = rng.startOffset;
      const endElement = rng.endContainer;
      const endOffset = rng.endOffset;
      f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
      const newRng = editor.dom.createRng();
      newRng.setStart(startElement, startOffset);
      newRng.setEnd(endElement, endOffset);
      editor.selection.setRng(rng);
    };
    const scrollToMarker = (marker, viewHeight, alignToTop, doc) => {
      const pos = marker.pos;
      if (alignToTop) {
        to(pos.left, pos.top, doc);
      } else {
        const y = pos.top - viewHeight + marker.height;
        to(pos.left, y, doc);
      }
    };
    const intoWindowIfNeeded = (doc, scrollTop, viewHeight, marker, alignToTop) => {
      const viewportBottom = viewHeight + scrollTop;
      const markerTop = marker.pos.top;
      const markerBottom = marker.bottom;
      const largerThanViewport = markerBottom - markerTop >= viewHeight;
      if (markerTop < scrollTop) {
        scrollToMarker(marker, viewHeight, alignToTop !== false, doc);
      } else if (markerTop > viewportBottom) {
        const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
        scrollToMarker(marker, viewHeight, align, doc);
      } else if (markerBottom > viewportBottom && !largerThanViewport) {
        scrollToMarker(marker, viewHeight, alignToTop === true, doc);
      }
    };
    const intoWindow = (doc, scrollTop, marker, alignToTop) => {
      const viewHeight = doc.dom.defaultView.innerHeight;
      intoWindowIfNeeded(doc, scrollTop, viewHeight, marker, alignToTop);
    };
    const intoFrame = (doc, scrollTop, marker, alignToTop) => {
      const frameViewHeight = doc.dom.defaultView.innerHeight;
      intoWindowIfNeeded(doc, scrollTop, frameViewHeight, marker, alignToTop);
      const op = find(marker.element);
      const viewportBounds = getBounds(window);
      if (op.top < viewportBounds.y) {
        intoView(marker.element, alignToTop !== false);
      } else if (op.top > viewportBounds.bottom) {
        intoView(marker.element, alignToTop === true);
      }
    };
    const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
    const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
    const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
    const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
    const scrollElementIntoView = (editor, element, alignToTop) => {
      const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
      scroller(editor, element, alignToTop);
    };
    const scrollRangeIntoView = (editor, rng, alignToTop) => {
      const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
      scroller(editor, rng, alignToTop);
    };
    const focus$1 = (element) => element.dom.focus();
    const hasFocus$1 = (element) => {
      const root = getRootNode(element).dom;
      return element.dom === root.activeElement;
    };
    const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
    const search = (element) => active$1(getRootNode(element)).filter((e) => element.dom.contains(e.dom));
    const clamp$1 = (offset, element) => {
      const max2 = isText$a(element) ? get$3(element).length : children(element).length + 1;
      if (offset > max2) {
        return max2;
      } else if (offset < 0) {
        return 0;
      }
      return offset;
    };
    const normalizeRng = (rng) => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
    const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
    const isRngInRoot = (root) => (rng) => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
    const shouldStore = (editor) => editor.inline;
    const nativeRangeToSelectionRange = (r2) => SimSelection.range(SugarElement.fromDom(r2.startContainer), r2.startOffset, SugarElement.fromDom(r2.endContainer), r2.endOffset);
    const readRange = (win) => {
      const selection = win.getSelection();
      const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
      return rng.map(nativeRangeToSelectionRange);
    };
    const getBookmark = (root) => {
      const win = defaultView(root);
      return readRange(win.dom).filter(isRngInRoot(root));
    };
    const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
    const bookmarkToNativeRng = (bookmark) => {
      const rng = document.createRange();
      try {
        rng.setStart(bookmark.start.dom, bookmark.soffset);
        rng.setEnd(bookmark.finish.dom, bookmark.foffset);
        return Optional.some(rng);
      } catch (_) {
        return Optional.none();
      }
    };
    const store = (editor) => {
      const newBookmark = shouldStore(editor) ? getBookmark(SugarElement.fromDom(editor.getBody())) : Optional.none();
      editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
    };
    const getRng = (editor) => {
      const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
      return bookmark.bind((x) => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
    };
    const restore = (editor) => {
      getRng(editor).each((rng) => editor.selection.setRng(rng));
    };
    const isEditorUIElement$1 = (elm) => {
      const className = elm.className.toString();
      return className.indexOf("tox-") !== -1 || className.indexOf("mce-") !== -1;
    };
    const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
    const wrappedSetTimeout = (callback, time) => {
      if (!isNumber(time)) {
        time = 0;
      }
      return setTimeout(callback, time);
    };
    const wrappedSetInterval = (callback, time) => {
      if (!isNumber(time)) {
        time = 0;
      }
      return setInterval(callback, time);
    };
    const Delay = {
      setEditorTimeout: (editor, callback, time) => {
        return wrappedSetTimeout(() => {
          if (!editor.removed) {
            callback();
          }
        }, time);
      },
      setEditorInterval: (editor, callback, time) => {
        const timer = wrappedSetInterval(() => {
          if (!editor.removed) {
            callback();
          } else {
            clearInterval(timer);
          }
        }, time);
        return timer;
      }
    };
    const isManualNodeChange = (e) => {
      return e.type === "nodechange" && e.selectionChange;
    };
    const registerPageMouseUp = (editor, throttledStore) => {
      const mouseUpPage = () => {
        throttledStore.throttle();
      };
      DOMUtils.DOM.bind(document, "mouseup", mouseUpPage);
      editor.on("remove", () => {
        DOMUtils.DOM.unbind(document, "mouseup", mouseUpPage);
      });
    };
    const registerMouseUp = (editor, throttledStore) => {
      editor.on("mouseup touchend", (_e) => {
        throttledStore.throttle();
      });
    };
    const registerEditorEvents = (editor, throttledStore) => {
      registerMouseUp(editor, throttledStore);
      editor.on("keyup NodeChange AfterSetSelectionRange", (e) => {
        if (!isManualNodeChange(e)) {
          store(editor);
        }
      });
    };
    const register$6 = (editor) => {
      const throttledStore = first$1(() => {
        store(editor);
      }, 0);
      editor.on("init", () => {
        if (editor.inline) {
          registerPageMouseUp(editor, throttledStore);
        }
        registerEditorEvents(editor, throttledStore);
      });
      editor.on("remove", () => {
        throttledStore.cancel();
      });
    };
    let documentFocusInHandler;
    const DOM$9 = DOMUtils.DOM;
    const isEditorUIElement = (elm) => {
      return FocusManager.isEditorUIElement(elm);
    };
    const isEditorContentAreaElement = (elm) => {
      const classList = elm.classList;
      if (classList !== void 0) {
        return classList.contains("tox-edit-area") || classList.contains("tox-edit-area__iframe") || classList.contains("mce-content-body");
      } else {
        return false;
      }
    };
    const isUIElement = (editor, elm) => {
      const customSelector = getCustomUiSelector(editor);
      const parent2 = DOM$9.getParent(elm, (elm2) => {
        return isEditorUIElement(elm2) || (customSelector ? editor.dom.is(elm2, customSelector) : false);
      });
      return parent2 !== null;
    };
    const getActiveElement = (editor) => {
      try {
        const root = getRootNode(SugarElement.fromDom(editor.getElement()));
        return active$1(root).fold(() => document.body, (x) => x.dom);
      } catch (ex) {
        return document.body;
      }
    };
    const registerEvents$1 = (editorManager, e) => {
      const editor = e.editor;
      register$6(editor);
      editor.on("focusin", () => {
        const focusedEditor = editorManager.focusedEditor;
        if (focusedEditor !== editor) {
          if (focusedEditor) {
            focusedEditor.dispatch("blur", { focusedEditor: editor });
          }
          editorManager.setActive(editor);
          editorManager.focusedEditor = editor;
          editor.dispatch("focus", { blurredEditor: focusedEditor });
          editor.focus(true);
        }
      });
      editor.on("focusout", () => {
        Delay.setEditorTimeout(editor, () => {
          const focusedEditor = editorManager.focusedEditor;
          if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
            editor.dispatch("blur", { focusedEditor: null });
            editorManager.focusedEditor = null;
          }
        });
      });
      if (!documentFocusInHandler) {
        documentFocusInHandler = (e2) => {
          const activeEditor = editorManager.activeEditor;
          if (activeEditor) {
            getOriginalEventTarget(e2).each((target) => {
              if (target.ownerDocument === document) {
                if (target !== document.body && !isUIElement(activeEditor, target) && editorManager.focusedEditor === activeEditor) {
                  activeEditor.dispatch("blur", { focusedEditor: null });
                  editorManager.focusedEditor = null;
                }
              }
            });
          }
        };
        DOM$9.bind(document, "focusin", documentFocusInHandler);
      }
    };
    const unregisterDocumentEvents = (editorManager, e) => {
      if (editorManager.focusedEditor === e.editor) {
        editorManager.focusedEditor = null;
      }
      if (!editorManager.activeEditor) {
        DOM$9.unbind(document, "focusin", documentFocusInHandler);
        documentFocusInHandler = null;
      }
    };
    const setup$v = (editorManager) => {
      editorManager.on("AddEditor", curry(registerEvents$1, editorManager));
      editorManager.on("RemoveEditor", curry(unregisterDocumentEvents, editorManager));
    };
    const getContentEditableHost = (editor, node) => editor.dom.getParent(node, (node2) => editor.dom.getContentEditable(node2) === "true");
    const getCollapsedNode = (rng) => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
    const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind((node) => {
      if (isTableSection(node)) {
        return Optional.some(node);
      } else if (contains(root, node) === false) {
        return Optional.some(root);
      } else {
        return Optional.none();
      }
    });
    const normalizeSelection = (editor, rng) => {
      getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind((elm) => {
        return firstPositionIn(elm.dom);
      }).fold(() => {
        editor.selection.normalize();
        return;
      }, (caretPos) => editor.selection.setRng(caretPos.toRange()));
    };
    const focusBody = (body) => {
      if (body.setActive) {
        try {
          body.setActive();
        } catch (ex) {
          body.focus();
        }
      } else {
        body.focus();
      }
    };
    const hasElementFocus = (elm) => hasFocus$1(elm) || search(elm).isSome();
    const hasIframeFocus = (editor) => editor.iframeElement && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
    const hasInlineFocus = (editor) => {
      const rawBody = editor.getBody();
      return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
    };
    const hasUiFocus = (editor) => {
      const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
      return active$1(dos).filter((elem) => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
    };
    const hasFocus = (editor) => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
    const hasEditorOrUiFocus = (editor) => hasFocus(editor) || hasUiFocus(editor);
    const focusEditor = (editor) => {
      const selection = editor.selection;
      const body = editor.getBody();
      let rng = selection.getRng();
      editor.quirks.refreshContentEditable();
      if (editor.bookmark !== void 0 && hasFocus(editor) === false) {
        getRng(editor).each((bookmarkRng) => {
          editor.selection.setRng(bookmarkRng);
          rng = bookmarkRng;
        });
      }
      const contentEditableHost = getContentEditableHost(editor, selection.getNode());
      if (editor.dom.isChildOf(contentEditableHost, body)) {
        focusBody(contentEditableHost);
        normalizeSelection(editor, rng);
        activateEditor(editor);
        return;
      }
      if (!editor.inline) {
        if (!Env.browser.isOpera()) {
          focusBody(body);
        }
        editor.getWin().focus();
      }
      if (Env.browser.isFirefox() || editor.inline) {
        focusBody(body);
        normalizeSelection(editor, rng);
      }
      activateEditor(editor);
    };
    const activateEditor = (editor) => editor.editorManager.setActive(editor);
    const focus = (editor, skipFocus) => {
      if (editor.removed) {
        return;
      }
      if (skipFocus) {
        activateEditor(editor);
      } else {
        focusEditor(editor);
      }
    };
    const getEndpointElement = (root, rng, start2, real, resolve2) => {
      const container = start2 ? rng.startContainer : rng.endContainer;
      const offset = start2 ? rng.startOffset : rng.endOffset;
      return Optional.from(container).map(SugarElement.fromDom).map((elm) => !real || !rng.collapsed ? child$1(elm, resolve2(elm, offset)).getOr(elm) : elm).bind((elm) => isElement$7(elm) ? Optional.some(elm) : parent(elm).filter(isElement$7)).map((elm) => elm.dom).getOr(root);
    };
    const getStart = (root, rng, real) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
    const getEnd$1 = (root, rng, real) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
    const skipEmptyTextNodes = (node, forwards) => {
      const orig = node;
      while (node && isText$9(node) && node.length === 0) {
        node = forwards ? node.nextSibling : node.previousSibling;
      }
      return node || orig;
    };
    const getNode = (root, rng) => {
      let elm, startContainer, endContainer;
      if (!rng) {
        return root;
      }
      startContainer = rng.startContainer;
      endContainer = rng.endContainer;
      const startOffset = rng.startOffset;
      const endOffset = rng.endOffset;
      elm = rng.commonAncestorContainer;
      if (!rng.collapsed) {
        if (startContainer === endContainer) {
          if (endOffset - startOffset < 2) {
            if (startContainer.hasChildNodes()) {
              elm = startContainer.childNodes[startOffset];
            }
          }
        }
        if (startContainer.nodeType === 3 && endContainer.nodeType === 3) {
          if (startContainer.length === startOffset) {
            startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
          } else {
            startContainer = startContainer.parentNode;
          }
          if (endOffset === 0) {
            endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
          } else {
            endContainer = endContainer.parentNode;
          }
          if (startContainer && startContainer === endContainer) {
            return startContainer;
          }
        }
      }
      if (elm && elm.nodeType === 3) {
        return elm.parentNode;
      }
      return elm;
    };
    const getSelectedBlocks = (dom2, rng, startElm, endElm) => {
      let node;
      const selectedBlocks = [];
      const root = dom2.getRoot();
      startElm = dom2.getParent(startElm || getStart(root, rng, rng.collapsed), dom2.isBlock);
      endElm = dom2.getParent(endElm || getEnd$1(root, rng, rng.collapsed), dom2.isBlock);
      if (startElm && startElm !== root) {
        selectedBlocks.push(startElm);
      }
      if (startElm && endElm && startElm !== endElm) {
        node = startElm;
        const walker = new DomTreeWalker(startElm, root);
        while ((node = walker.next()) && node !== endElm) {
          if (dom2.isBlock(node)) {
            selectedBlocks.push(node);
          }
        }
      }
      if (endElm && startElm !== endElm && endElm !== root) {
        selectedBlocks.push(endElm);
      }
      return selectedBlocks;
    };
    const select = (dom2, node, content) => Optional.from(node).map((node2) => {
      const idx = dom2.nodeIndex(node2);
      const rng = dom2.createRng();
      rng.setStart(node2.parentNode, idx);
      rng.setEnd(node2.parentNode, idx + 1);
      if (content) {
        moveEndPoint(dom2, rng, node2, true);
        moveEndPoint(dom2, rng, node2, false);
      }
      return rng;
    });
    const processRanges = (editor, ranges) => map$3(ranges, (range2) => {
      const evt = editor.dispatch("GetSelectionRange", { range: range2 });
      return evt.range !== range2 ? evt.range : range2;
    });
    const getEnd = (element) => name(element) === "img" ? 1 : getOption(element).fold(() => children(element).length, (v) => v.length);
    const isTextNodeWithCursorPosition = (el) => getOption(el).filter((text2) => text2.trim().length !== 0 || text2.indexOf(nbsp) > -1).isSome();
    const elementsWithCursorPosition = [
      "img",
      "br"
    ];
    const isCursorPosition = (elem) => {
      const hasCursorPosition = isTextNodeWithCursorPosition(elem);
      return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem));
    };
    const first = (element) => descendant$1(element, isCursorPosition);
    const last = (element) => descendantRtl(element, isCursorPosition);
    const descendantRtl = (scope, predicate) => {
      const descend2 = (element) => {
        const children$1 = children(element);
        for (let i = children$1.length - 1; i >= 0; i--) {
          const child2 = children$1[i];
          if (predicate(child2)) {
            return Optional.some(child2);
          }
          const res = descend2(child2);
          if (res.isSome()) {
            return res;
          }
        }
        return Optional.none();
      };
      return descend2(scope);
    };
    const autocompleteSelector = "[data-mce-autocompleter]";
    const create$9 = (editor, range2) => {
      if (findIn(SugarElement.fromDom(editor.getBody())).isNone()) {
        const wrapper = SugarElement.fromHtml('<span data-mce-autocompleter="1" data-mce-bogus="1"></span>', editor.getDoc());
        append$1(wrapper, SugarElement.fromDom(range2.extractContents()));
        range2.insertNode(wrapper.dom);
        parent(wrapper).each((elm) => elm.dom.normalize());
        last(wrapper).map((last2) => {
          editor.selection.setCursorLocation(last2.dom, getEnd(last2));
        });
      }
    };
    const detect$1 = (elm) => closest$3(elm, autocompleteSelector);
    const findIn = (elm) => descendant(elm, autocompleteSelector);
    const remove$3 = (editor, elm) => findIn(elm).each((wrapper) => {
      const bookmark = editor.selection.getBookmark();
      unwrap(wrapper);
      editor.selection.moveToBookmark(bookmark);
    });
    const typeLookup = {
      "#text": 3,
      "#comment": 8,
      "#cdata": 4,
      "#pi": 7,
      "#doctype": 10,
      "#document-fragment": 11
    };
    const walk$2 = (node, root, prev2) => {
      const startName = prev2 ? "lastChild" : "firstChild";
      const siblingName = prev2 ? "prev" : "next";
      if (node[startName]) {
        return node[startName];
      }
      if (node !== root) {
        let sibling2 = node[siblingName];
        if (sibling2) {
          return sibling2;
        }
        for (let parent2 = node.parent; parent2 && parent2 !== root; parent2 = parent2.parent) {
          sibling2 = parent2[siblingName];
          if (sibling2) {
            return sibling2;
          }
        }
      }
    };
    const isEmptyTextNode = (node) => {
      if (!isWhitespaceText(node.value)) {
        return false;
      }
      const parentNode = node.parent;
      if (parentNode && (parentNode.name !== "span" || parentNode.attr("style")) && /^[ ]+$/.test(node.value)) {
        return false;
      }
      return true;
    };
    const isNonEmptyElement = (node) => {
      const isNamedAnchor2 = node.name === "a" && !node.attr("href") && node.attr("id");
      return node.attr("name") || node.attr("id") && !node.firstChild || node.attr("data-mce-bookmark") || isNamedAnchor2;
    };
    class AstNode {
      constructor(name2, type2) {
        this.name = name2;
        this.type = type2;
        if (type2 === 1) {
          this.attributes = [];
          this.attributes.map = {};
        }
      }
      static create(name2, attrs) {
        const node = new AstNode(name2, typeLookup[name2] || 1);
        if (attrs) {
          each$e(attrs, (value2, attrName) => {
            node.attr(attrName, value2);
          });
        }
        return node;
      }
      replace(node) {
        const self = this;
        if (node.parent) {
          node.remove();
        }
        self.insert(node, self);
        self.remove();
        return self;
      }
      attr(name2, value2) {
        const self = this;
        let attrs;
        if (typeof name2 !== "string") {
          if (name2 !== void 0 && name2 !== null) {
            each$e(name2, (value3, key) => {
              self.attr(key, value3);
            });
          }
          return self;
        }
        if (attrs = self.attributes) {
          if (value2 !== void 0) {
            if (value2 === null) {
              if (name2 in attrs.map) {
                delete attrs.map[name2];
                let i = attrs.length;
                while (i--) {
                  if (attrs[i].name === name2) {
                    attrs.splice(i, 1);
                    return self;
                  }
                }
              }
              return self;
            }
            if (name2 in attrs.map) {
              let i = attrs.length;
              while (i--) {
                if (attrs[i].name === name2) {
                  attrs[i].value = value2;
                  break;
                }
              }
            } else {
              attrs.push({
                name: name2,
                value: value2
              });
            }
            attrs.map[name2] = value2;
            return self;
          }
          return attrs.map[name2];
        }
      }
      clone() {
        const self = this;
        const clone2 = new AstNode(self.name, self.type);
        let selfAttrs;
        if (selfAttrs = self.attributes) {
          const cloneAttrs = [];
          cloneAttrs.map = {};
          for (let i = 0, l = selfAttrs.length; i < l; i++) {
            const selfAttr = selfAttrs[i];
            if (selfAttr.name !== "id") {
              cloneAttrs[cloneAttrs.length] = {
                name: selfAttr.name,
                value: selfAttr.value
              };
              cloneAttrs.map[selfAttr.name] = selfAttr.value;
            }
          }
          clone2.attributes = cloneAttrs;
        }
        clone2.value = self.value;
        return clone2;
      }
      wrap(wrapper) {
        const self = this;
        self.parent.insert(wrapper, self);
        wrapper.append(self);
        return self;
      }
      unwrap() {
        const self = this;
        for (let node = self.firstChild; node; ) {
          const next2 = node.next;
          self.insert(node, self, true);
          node = next2;
        }
        self.remove();
      }
      remove() {
        const self = this, parent2 = self.parent, next2 = self.next, prev2 = self.prev;
        if (parent2) {
          if (parent2.firstChild === self) {
            parent2.firstChild = next2;
            if (next2) {
              next2.prev = null;
            }
          } else {
            prev2.next = next2;
          }
          if (parent2.lastChild === self) {
            parent2.lastChild = prev2;
            if (prev2) {
              prev2.next = null;
            }
          } else {
            next2.prev = prev2;
          }
          self.parent = self.next = self.prev = null;
        }
        return self;
      }
      append(node) {
        const self = this;
        if (node.parent) {
          node.remove();
        }
        const last2 = self.lastChild;
        if (last2) {
          last2.next = node;
          node.prev = last2;
          self.lastChild = node;
        } else {
          self.lastChild = self.firstChild = node;
        }
        node.parent = self;
        return node;
      }
      insert(node, refNode, before2) {
        if (node.parent) {
          node.remove();
        }
        const parent2 = refNode.parent || this;
        if (before2) {
          if (refNode === parent2.firstChild) {
            parent2.firstChild = node;
          } else {
            refNode.prev.next = node;
          }
          node.prev = refNode.prev;
          node.next = refNode;
          refNode.prev = node;
        } else {
          if (refNode === parent2.lastChild) {
            parent2.lastChild = node;
          } else {
            refNode.next.prev = node;
          }
          node.next = refNode.next;
          node.prev = refNode;
          refNode.next = node;
        }
        node.parent = parent2;
        return node;
      }
      getAll(name2) {
        const self = this;
        const collection = [];
        for (let node = self.firstChild; node; node = walk$2(node, self)) {
          if (node.name === name2) {
            collection.push(node);
          }
        }
        return collection;
      }
      children() {
        const self = this;
        const collection = [];
        for (let node = self.firstChild; node; node = node.next) {
          collection.push(node);
        }
        return collection;
      }
      empty() {
        const self = this;
        if (self.firstChild) {
          const nodes = [];
          for (let node = self.firstChild; node; node = walk$2(node, self)) {
            nodes.push(node);
          }
          let i = nodes.length;
          while (i--) {
            const node = nodes[i];
            node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
          }
        }
        self.firstChild = self.lastChild = null;
        return self;
      }
      isEmpty(elements, whitespace = {}, predicate) {
        const self = this;
        let node = self.firstChild;
        if (isNonEmptyElement(self)) {
          return false;
        }
        if (node) {
          do {
            if (node.type === 1) {
              if (node.attr("data-mce-bogus")) {
                continue;
              }
              if (elements[node.name]) {
                return false;
              }
              if (isNonEmptyElement(node)) {
                return false;
              }
            }
            if (node.type === 8) {
              return false;
            }
            if (node.type === 3 && !isEmptyTextNode(node)) {
              return false;
            }
            if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText(node.value)) {
              return false;
            }
            if (predicate && predicate(node)) {
              return false;
            }
          } while (node = walk$2(node, self));
        }
        return true;
      }
      walk(prev2) {
        return walk$2(this, null, prev2);
      }
    }
    const isConditionalComment = (html2, startIndex) => /^\s*\[if [\w\W]+\]>.*<!\[endif\](--!?)?>/.test(html2.substr(startIndex));
    const findCommentEndIndex = (html2, isBogus2, startIndex = 0) => {
      const lcHtml = html2.toLowerCase();
      if (lcHtml.indexOf("[if ", startIndex) !== -1 && isConditionalComment(lcHtml, startIndex)) {
        const endIfIndex = lcHtml.indexOf("[endif]", startIndex);
        return lcHtml.indexOf(">", endIfIndex);
      } else {
        if (isBogus2) {
          const endIndex = lcHtml.indexOf(">", startIndex);
          return endIndex !== -1 ? endIndex : lcHtml.length;
        } else {
          const endCommentRegexp = /--!?>/g;
          endCommentRegexp.lastIndex = startIndex;
          const match2 = endCommentRegexp.exec(html2);
          return match2 ? match2.index + match2[0].length : lcHtml.length;
        }
      }
    };
    const findMatchingEndTagIndex = (schema, html2, startIndex) => {
      const startTagRegExp = /<([!?\/])?([A-Za-z0-9\-_:.]+)/g;
      const endTagRegExp = /(?:\s(?:[^'">]+(?:"[^"]*"|'[^']*'))*[^"'>]*(?:"[^">]*|'[^'>]*)?|\s*|\/)>/g;
      const voidElements = schema.getVoidElements();
      let count2 = 1, index2 = startIndex;
      while (count2 !== 0) {
        startTagRegExp.lastIndex = index2;
        while (true) {
          const startMatch = startTagRegExp.exec(html2);
          if (startMatch === null) {
            return index2;
          } else if (startMatch[1] === "!") {
            if (startsWith(startMatch[2], "--")) {
              index2 = findCommentEndIndex(html2, false, startMatch.index + "!--".length);
            } else {
              index2 = findCommentEndIndex(html2, true, startMatch.index + 1);
            }
            break;
          } else {
            endTagRegExp.lastIndex = startTagRegExp.lastIndex;
            const endMatch = endTagRegExp.exec(html2);
            if (isNull(endMatch) || endMatch.index !== startTagRegExp.lastIndex) {
              continue;
            }
            if (startMatch[1] === "/") {
              count2 -= 1;
            } else if (!has$2(voidElements, startMatch[2])) {
              count2 += 1;
            }
            index2 = startTagRegExp.lastIndex + endMatch[0].length;
            break;
          }
        }
      }
      return index2;
    };
    const trimHtml$1 = (tempAttrs, html2) => {
      const trimContentRegExp = new RegExp(["\\s?(" + tempAttrs.join("|") + ')="[^"]+"'].join("|"), "gi");
      return html2.replace(trimContentRegExp, "");
    };
    const trimInternal = (serializer, html2) => {
      const bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
      const schema = serializer.schema;
      let content = trimHtml$1(serializer.getTempAttrs(), html2);
      const voidElements = schema.getVoidElements();
      let matches;
      while (matches = bogusAllRegExp.exec(content)) {
        const index2 = bogusAllRegExp.lastIndex;
        const matchLength = matches[0].length;
        let endTagIndex;
        if (voidElements[matches[1]]) {
          endTagIndex = index2;
        } else {
          endTagIndex = findMatchingEndTagIndex(schema, content, index2);
        }
        content = content.substring(0, index2 - matchLength) + content.substring(endTagIndex);
        bogusAllRegExp.lastIndex = index2 - matchLength;
      }
      return trim$1(content);
    };
    const trimExternal = trimInternal;
    const trimEmptyContents = (editor, html2) => {
      const blockName = getForcedRootBlock(editor);
      const emptyRegExp = new RegExp(`^(<${blockName}[^>]*>(&nbsp;|&#160;|\\s|\xA0|<br \\/>|)<\\/${blockName}>[\r
]*|<br \\/>[\r
]*)$`);
      return html2.replace(emptyRegExp, "");
    };
    const getContentFromBody = (editor, args, body) => {
      let content;
      if (args.format === "raw") {
        content = Tools.trim(trimExternal(editor.serializer, body.innerHTML));
      } else if (args.format === "text") {
        content = trim$1(body.innerText);
        content = content === "\n" ? "" : content;
      } else if (args.format === "tree") {
        content = editor.serializer.serialize(body, args);
      } else {
        content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
      }
      const shouldTrim = args.format !== "text" && !isWsPreserveElement(SugarElement.fromDom(body));
      return shouldTrim && isString(content) ? Tools.trim(content) : content;
    };
    const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === "tree" ? new AstNode("body", 11) : ""), (body) => getContentFromBody(editor, args, body));
    const each$a = Tools.each;
    const ElementUtils = (dom2) => {
      const compare = (node1, node2) => {
        if (node1.nodeName !== node2.nodeName) {
          return false;
        }
        const getAttribs = (node) => {
          const attribs = {};
          each$a(dom2.getAttribs(node), (attr) => {
            const name2 = attr.nodeName.toLowerCase();
            if (name2.indexOf("_") !== 0 && name2 !== "style" && name2.indexOf("data-") !== 0) {
              attribs[name2] = dom2.getAttrib(node, name2);
            }
          });
          return attribs;
        };
        const compareObjects = (obj1, obj2) => {
          let value2, name2;
          for (name2 in obj1) {
            if (has$2(obj1, name2)) {
              value2 = obj2[name2];
              if (typeof value2 === "undefined") {
                return false;
              }
              if (obj1[name2] !== value2) {
                return false;
              }
              delete obj2[name2];
            }
          }
          for (name2 in obj2) {
            if (has$2(obj2, name2)) {
              return false;
            }
          }
          return true;
        };
        if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
          return false;
        }
        if (!compareObjects(dom2.parseStyle(dom2.getAttrib(node1, "style")), dom2.parseStyle(dom2.getAttrib(node2, "style")))) {
          return false;
        }
        return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
      };
      return { compare };
    };
    const makeMap$1 = Tools.makeMap;
    const Writer = (settings) => {
      const html2 = [];
      settings = settings || {};
      const indent2 = settings.indent;
      const indentBefore = makeMap$1(settings.indent_before || "");
      const indentAfter = makeMap$1(settings.indent_after || "");
      const encode = Entities.getEncodeFunc(settings.entity_encoding || "raw", settings.entities);
      const htmlOutput = settings.element_format !== "xhtml";
      return {
        start: (name2, attrs, empty2) => {
          let i, l, attr, value2;
          if (indent2 && indentBefore[name2] && html2.length > 0) {
            value2 = html2[html2.length - 1];
            if (value2.length > 0 && value2 !== "\n") {
              html2.push("\n");
            }
          }
          html2.push("<", name2);
          if (attrs) {
            for (i = 0, l = attrs.length; i < l; i++) {
              attr = attrs[i];
              html2.push(" ", attr.name, '="', encode(attr.value, true), '"');
            }
          }
          if (!empty2 || htmlOutput) {
            html2[html2.length] = ">";
          } else {
            html2[html2.length] = " />";
          }
          if (empty2 && indent2 && indentAfter[name2] && html2.length > 0) {
            value2 = html2[html2.length - 1];
            if (value2.length > 0 && value2 !== "\n") {
              html2.push("\n");
            }
          }
        },
        end: (name2) => {
          let value2;
          html2.push("</", name2, ">");
          if (indent2 && indentAfter[name2] && html2.length > 0) {
            value2 = html2[html2.length - 1];
            if (value2.length > 0 && value2 !== "\n") {
              html2.push("\n");
            }
          }
        },
        text: (text2, raw) => {
          if (text2.length > 0) {
            html2[html2.length] = raw ? text2 : encode(text2);
          }
        },
        cdata: (text2) => {
          html2.push("<![CDATA[", text2, "]]>");
        },
        comment: (text2) => {
          html2.push("<!--", text2, "-->");
        },
        pi: (name2, text2) => {
          if (text2) {
            html2.push("<?", name2, " ", encode(text2), "?>");
          } else {
            html2.push("<?", name2, "?>");
          }
          if (indent2) {
            html2.push("\n");
          }
        },
        doctype: (text2) => {
          html2.push("<!DOCTYPE", text2, ">", indent2 ? "\n" : "");
        },
        reset: () => {
          html2.length = 0;
        },
        getContent: () => {
          return html2.join("").replace(/\n$/, "");
        }
      };
    };
    const HtmlSerializer = (settings, schema = Schema()) => {
      const writer = Writer(settings);
      settings = settings || {};
      settings.validate = "validate" in settings ? settings.validate : true;
      const serialize = (node) => {
        const validate2 = settings.validate;
        const handlers = {
          3: (node2) => {
            writer.text(node2.value, node2.raw);
          },
          8: (node2) => {
            writer.comment(node2.value);
          },
          7: (node2) => {
            writer.pi(node2.name, node2.value);
          },
          10: (node2) => {
            writer.doctype(node2.value);
          },
          4: (node2) => {
            writer.cdata(node2.value);
          },
          11: (node2) => {
            if (node2 = node2.firstChild) {
              do {
                walk2(node2);
              } while (node2 = node2.next);
            }
          }
        };
        writer.reset();
        const walk2 = (node2) => {
          const handler = handlers[node2.type];
          if (!handler) {
            const name2 = node2.name;
            const isEmpty2 = name2 in schema.getVoidElements();
            let attrs = node2.attributes;
            if (validate2 && attrs && attrs.length > 1) {
              const sortedAttrs = [];
              sortedAttrs.map = {};
              const elementRule = schema.getElementRule(node2.name);
              if (elementRule) {
                for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
                  const attrName = elementRule.attributesOrder[i];
                  if (attrName in attrs.map) {
                    const attrValue = attrs.map[attrName];
                    sortedAttrs.map[attrName] = attrValue;
                    sortedAttrs.push({
                      name: attrName,
                      value: attrValue
                    });
                  }
                }
                for (let i = 0, l = attrs.length; i < l; i++) {
                  const attrName = attrs[i].name;
                  if (!(attrName in sortedAttrs.map)) {
                    const attrValue = attrs.map[attrName];
                    sortedAttrs.map[attrName] = attrValue;
                    sortedAttrs.push({
                      name: attrName,
                      value: attrValue
                    });
                  }
                }
                attrs = sortedAttrs;
              }
            }
            writer.start(name2, attrs, isEmpty2);
            if (!isEmpty2) {
              let child2 = node2.firstChild;
              if (child2) {
                if ((name2 === "pre" || name2 === "textarea") && child2.type === 3 && child2.value[0] === "\n") {
                  writer.text("\n", true);
                }
                do {
                  walk2(child2);
                } while (child2 = child2.next);
              }
              writer.end(name2);
            }
          } else {
            handler(node2);
          }
        };
        if (node.type === 1 && !settings.inner) {
          walk2(node);
        } else if (node.type === 3) {
          handlers[3](node);
        } else {
          handlers[11](node);
        }
        return writer.getContent();
      };
      return { serialize };
    };
    const nonInheritableStyles = /* @__PURE__ */ new Set();
    (() => {
      const nonInheritableStylesArr = [
        "margin",
        "margin-left",
        "margin-right",
        "margin-top",
        "margin-bottom",
        "padding",
        "padding-left",
        "padding-right",
        "padding-top",
        "padding-bottom",
        "border",
        "border-width",
        "border-style",
        "border-color",
        "background",
        "background-attachment",
        "background-clip",
        "background-color",
        "background-image",
        "background-origin",
        "background-position",
        "background-repeat",
        "background-size",
        "float",
        "position",
        "left",
        "right",
        "top",
        "bottom",
        "z-index",
        "display",
        "transform",
        "width",
        "max-width",
        "min-width",
        "height",
        "max-height",
        "min-height",
        "overflow",
        "overflow-x",
        "overflow-y",
        "text-overflow",
        "vertical-align",
        "transition",
        "transition-delay",
        "transition-duration",
        "transition-property",
        "transition-timing-function"
      ];
      each$f(nonInheritableStylesArr, (style) => {
        nonInheritableStyles.add(style);
      });
    })();
    const shorthandStyleProps = [
      "font",
      "text-decoration",
      "text-emphasis"
    ];
    const getStyleProps = (dom2, node) => keys(dom2.parseStyle(dom2.getAttrib(node, "style")));
    const isNonInheritableStyle = (style) => nonInheritableStyles.has(style);
    const hasInheritableStyles = (dom2, node) => forall(getStyleProps(dom2, node), (style) => !isNonInheritableStyle(style));
    const getLonghandStyleProps = (styles) => filter$6(styles, (style) => exists(shorthandStyleProps, (prop) => startsWith(style, prop)));
    const hasStyleConflict = (dom2, node, parentNode) => {
      const nodeStyleProps = getStyleProps(dom2, node);
      const parentNodeStyleProps = getStyleProps(dom2, parentNode);
      const valueMismatch = (prop) => {
        var _a, _b;
        const nodeValue = (_a = dom2.getStyle(node, prop)) !== null && _a !== void 0 ? _a : "";
        const parentValue = (_b = dom2.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : "";
        return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
      };
      return exists(nodeStyleProps, (nodeStyleProp) => {
        const propExists = (props) => exists(props, (prop) => prop === nodeStyleProp);
        if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
          const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
          return exists(longhandProps, valueMismatch);
        } else {
          return valueMismatch(nodeStyleProp);
        }
      });
    };
    const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$9).exists((text2) => {
      const delta = forward ? 0 : -1;
      return predicate(text2.data.charAt(pos.offset() + delta));
    });
    const isBeforeSpace = curry(isChar, true, isWhiteSpace);
    const isAfterSpace = curry(isChar, false, isWhiteSpace);
    const isEmptyText = (pos) => {
      const container = pos.container();
      return isText$9(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
    };
    const matchesElementPosition = (before2, predicate) => (pos) => Optional.from(getChildNodeAtRelativeOffset(before2 ? 0 : -1, pos)).filter(predicate).isSome();
    const isImageBlock = (node) => isImg(node) && get$7(SugarElement.fromDom(node), "display") === "block";
    const isCefNode = (node) => isContentEditableFalse$b(node) && !isBogusAll$1(node);
    const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
    const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
    const isBeforeMedia = matchesElementPosition(true, isMedia$2);
    const isAfterMedia = matchesElementPosition(false, isMedia$2);
    const isBeforeTable = matchesElementPosition(true, isTable$3);
    const isAfterTable = matchesElementPosition(false, isTable$3);
    const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
    const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
    const getLastChildren = (elm) => {
      const children2 = [];
      let rawNode = elm.dom;
      while (rawNode) {
        children2.push(SugarElement.fromDom(rawNode));
        rawNode = rawNode.lastChild;
      }
      return children2;
    };
    const removeTrailingBr = (elm) => {
      const allBrs = descendants(elm, "br");
      const brs = filter$6(getLastChildren(elm).slice(-1), isBr$5);
      if (allBrs.length === brs.length) {
        each$f(brs, remove$6);
      }
    };
    const fillWithPaddingBr = (elm) => {
      empty(elm);
      append$1(elm, SugarElement.fromHtml('<br data-mce-bogus="1">'));
    };
    const trimBlockTrailingBr = (elm) => {
      lastChild(elm).each((lastChild2) => {
        prevSibling(lastChild2).each((lastChildPrevSibling) => {
          if (isBlock$2(elm) && isBr$5(lastChild2) && isBlock$2(lastChildPrevSibling)) {
            remove$6(lastChild2);
          }
        });
      });
    };
    const dropLast = (xs) => xs.slice(0, -1);
    const parentsUntil = (start2, root, predicate) => {
      if (contains(root, start2)) {
        return dropLast(parents$1(start2, (elm) => {
          return predicate(elm) || eq(elm, root);
        }));
      } else {
        return [];
      }
    };
    const parents = (start2, root) => parentsUntil(start2, root, never);
    const parentsAndSelf = (start2, root) => [start2].concat(parents(start2, root));
    const navigateIgnoreEmptyTextNodes = (forward, root, from2) => navigateIgnore(forward, root, from2, isEmptyText);
    const getClosestBlock$1 = (root, pos) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
    const isAtBeforeAfterBlockBoundary = (forward, root, pos) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall((newPos) => getClosestBlock$1(root, pos).fold(() => isInSameBlock(newPos, pos, root.dom) === false, (fromBlock) => isInSameBlock(newPos, pos, root.dom) === false && contains(fromBlock, SugarElement.fromDom(newPos.container()))));
    const isAtBlockBoundary = (forward, root, pos) => getClosestBlock$1(root, pos).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall((newPos) => isInSameBlock(newPos, pos, root.dom) === false), (parent2) => navigateIgnoreEmptyTextNodes(forward, parent2.dom, pos).isNone());
    const isAtStartOfBlock = curry(isAtBlockBoundary, false);
    const isAtEndOfBlock = curry(isAtBlockBoundary, true);
    const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
    const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
    const isBr$1 = (pos) => getElementFromPosition(pos).exists(isBr$5);
    const findBr = (forward, root, pos) => {
      const parentBlocks = filter$6(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
      const scope = head(parentBlocks).getOr(root);
      return fromPosition(forward, scope.dom, pos).filter(isBr$1);
    };
    const isBeforeBr$1 = (root, pos) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos).isSome();
    const isAfterBr = (root, pos) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos).isSome();
    const findPreviousBr = curry(findBr, false);
    const findNextBr = curry(findBr, true);
    const isInMiddleOfText = (pos) => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
    const getClosestBlock = (root, pos) => {
      const parentBlocks = filter$6(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
      return head(parentBlocks).getOr(root);
    };
    const hasSpaceBefore = (root, pos) => {
      if (isInMiddleOfText(pos)) {
        return isAfterSpace(pos);
      } else {
        return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos).dom, pos).exists(isAfterSpace);
      }
    };
    const hasSpaceAfter = (root, pos) => {
      if (isInMiddleOfText(pos)) {
        return isBeforeSpace(pos);
      } else {
        return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos).dom, pos).exists(isBeforeSpace);
      }
    };
    const isPreValue = (value2) => contains$2([
      "pre",
      "pre-wrap"
    ], value2);
    const isInPre = (pos) => getElementFromPosition(pos).bind((elm) => closest$4(elm, isElement$7)).exists((elm) => isPreValue(get$7(elm, "white-space")));
    const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
    const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
    const isAtLineBoundary = (root, pos) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos) || isAtEndOfBlock(root, pos) || isAfterBr(root, pos) || isBeforeBr$1(root, pos);
    const isCefBlock = (node) => isNonNullable(node) && isContentEditableFalse$b(node) && isBlockLike(node);
    const isSiblingCefBlock = (root) => (container) => isCefBlock(new DomTreeWalker(container, root).next());
    const isBeforeCefBlock = (root, pos) => {
      const nextPos = nextPosition(root.dom, pos).getOr(pos);
      const isNextCefBlock = isSiblingCefBlock(root.dom);
      return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
    };
    const needsToHaveNbsp = (root, pos) => {
      if (isInPre(pos)) {
        return false;
      } else {
        return isAtLineBoundary(root, pos) || hasSpaceBefore(root, pos) || hasSpaceAfter(root, pos);
      }
    };
    const needsToBeNbspLeft = (root, pos) => {
      if (isInPre(pos)) {
        return false;
      } else {
        return isAtStartOfBlock(root, pos) || isBeforeBlock(root, pos) || isAfterBr(root, pos) || hasSpaceBefore(root, pos);
      }
    };
    const leanRight = (pos) => {
      const container = pos.container();
      const offset = pos.offset();
      if (isText$9(container) && offset < container.data.length) {
        return CaretPosition(container, offset + 1);
      } else {
        return pos;
      }
    };
    const needsToBeNbspRight = (root, pos) => {
      if (isInPre(pos)) {
        return false;
      } else {
        return isAtEndOfBlock(root, pos) || isAfterBlock(root, pos) || isBeforeBr$1(root, pos) || hasSpaceAfter(root, pos) || isBeforeCefBlock(root, pos);
      }
    };
    const needsToBeNbsp = (root, pos) => needsToBeNbspLeft(root, pos) || needsToBeNbspRight(root, leanRight(pos));
    const isNbspAt = (text2, offset) => isNbsp(text2.charAt(offset));
    const hasNbsp = (pos) => {
      const container = pos.container();
      return isText$9(container) && contains$1(container.data, nbsp);
    };
    const normalizeNbspMiddle = (text2) => {
      const chars = text2.split("");
      return map$3(chars, (chr, i) => {
        if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
          return " ";
        } else {
          return chr;
        }
      }).join("");
    };
    const normalizeNbspAtStart = (root, node) => {
      const text2 = node.data;
      const firstPos = CaretPosition(node, 0);
      if (isNbspAt(text2, 0) && !needsToBeNbsp(root, firstPos)) {
        node.data = " " + text2.slice(1);
        return true;
      } else {
        return false;
      }
    };
    const normalizeNbspInMiddleOfTextNode = (node) => {
      const text2 = node.data;
      const newText = normalizeNbspMiddle(text2);
      if (newText !== text2) {
        node.data = newText;
        return true;
      } else {
        return false;
      }
    };
    const normalizeNbspAtEnd = (root, node) => {
      const text2 = node.data;
      const lastPos = CaretPosition(node, text2.length - 1);
      if (isNbspAt(text2, text2.length - 1) && !needsToBeNbsp(root, lastPos)) {
        node.data = text2.slice(0, -1) + " ";
        return true;
      } else {
        return false;
      }
    };
    const normalizeNbsps = (root, pos) => Optional.some(pos).filter(hasNbsp).bind((pos2) => {
      const container = pos2.container();
      const normalized = normalizeNbspAtStart(root, container) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container);
      return normalized ? Optional.some(pos2) : Optional.none();
    });
    const normalizeNbspsInEditor = (editor) => {
      const root = SugarElement.fromDom(editor.getBody());
      if (editor.selection.isCollapsed()) {
        normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng())).each((pos) => {
          editor.selection.setRng(pos.toRange());
        });
      }
    };
    const normalize$1 = (node, offset, count2) => {
      if (count2 === 0) {
        return;
      }
      const elm = SugarElement.fromDom(node);
      const root = ancestor$3(elm, isBlock$2).getOr(elm);
      const whitespace = node.data.slice(offset, offset + count2);
      const isEndOfContent = offset + count2 >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length));
      const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0));
      node.replaceData(offset, count2, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
    };
    const normalizeWhitespaceAfter = (node, offset) => {
      const content = node.data.slice(offset);
      const whitespaceCount = content.length - lTrim(content).length;
      normalize$1(node, offset, whitespaceCount);
    };
    const normalizeWhitespaceBefore = (node, offset) => {
      const content = node.data.slice(0, offset);
      const whitespaceCount = content.length - rTrim(content).length;
      normalize$1(node, offset - whitespaceCount, whitespaceCount);
    };
    const mergeTextNodes = (prevNode, nextNode, normalizeWhitespace, mergeToPrev = true) => {
      const whitespaceOffset = rTrim(prevNode.data).length;
      const newNode = mergeToPrev ? prevNode : nextNode;
      const removeNode2 = mergeToPrev ? nextNode : prevNode;
      if (mergeToPrev) {
        newNode.appendData(removeNode2.data);
      } else {
        newNode.insertData(0, removeNode2.data);
      }
      remove$6(SugarElement.fromDom(removeNode2));
      if (normalizeWhitespace) {
        normalizeWhitespaceAfter(newNode, whitespaceOffset);
      }
      return newNode;
    };
    const needsReposition = (pos, elm) => {
      const container = pos.container();
      const offset = pos.offset();
      return CaretPosition.isTextPosition(pos) === false && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
    };
    const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
    const beforeOrStartOf = (node) => isText$9(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
    const afterOrEndOf = (node) => isText$9(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
    const getPreviousSiblingCaretPosition = (elm) => {
      if (isCaretCandidate$3(elm.previousSibling)) {
        return Optional.some(afterOrEndOf(elm.previousSibling));
      } else {
        return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
      }
    };
    const getNextSiblingCaretPosition = (elm) => {
      if (isCaretCandidate$3(elm.nextSibling)) {
        return Optional.some(beforeOrStartOf(elm.nextSibling));
      } else {
        return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
      }
    };
    const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
      const startPosition = CaretPosition.before(elm.previousSibling ? elm.previousSibling : elm.parentNode);
      return prevPosition(rootElement, startPosition).fold(() => nextPosition(rootElement, CaretPosition.after(elm)), Optional.some);
    };
    const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).fold(() => prevPosition(rootElement, CaretPosition.before(elm)), Optional.some);
    const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
    const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
    const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
    const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
    const setSelection$1 = (editor, forward, pos) => {
      pos.fold(() => {
        editor.focus();
      }, (pos2) => {
        editor.selection.setRng(pos2.toRange(), forward);
      });
    };
    const eqRawNode = (rawNode) => (elm) => elm.dom === rawNode;
    const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
    const paddEmptyBlock = (elm) => {
      if (isEmpty$2(elm)) {
        const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
        empty(elm);
        append$1(elm, br);
        return Optional.some(CaretPosition.before(br.dom));
      } else {
        return Optional.none();
      }
    };
    const deleteNormalized = (elm, afterDeletePosOpt, normalizeWhitespace) => {
      const prevTextOpt = prevSibling(elm).filter(isText$a);
      const nextTextOpt = nextSibling(elm).filter(isText$a);
      remove$6(elm);
      return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev2, next2, pos) => {
        const prevNode = prev2.dom, nextNode = next2.dom;
        const offset = prevNode.data.length;
        mergeTextNodes(prevNode, nextNode, normalizeWhitespace);
        return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
      }).orThunk(() => {
        if (normalizeWhitespace) {
          prevTextOpt.each((elm2) => normalizeWhitespaceBefore(elm2.dom, elm2.dom.length));
          nextTextOpt.each((elm2) => normalizeWhitespaceAfter(elm2.dom, 0));
        }
        return afterDeletePosOpt;
      });
    };
    const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
    const deleteElement$2 = (editor, forward, elm, moveCaret2 = true) => {
      const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
      const parentBlock = ancestor$3(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
      const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, isInlineElement(editor, elm));
      if (editor.dom.isEmpty(editor.getBody())) {
        editor.setContent("");
        editor.selection.setCursorLocation();
      } else {
        parentBlock.bind(paddEmptyBlock).fold(() => {
          if (moveCaret2) {
            setSelection$1(editor, forward, normalizedAfterDeletePos);
          }
        }, (paddPos) => {
          if (moveCaret2) {
            setSelection$1(editor, forward, Optional.some(paddPos));
          }
        });
      }
    };
    const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
    const hasStrongRtl = (text2) => strongRtl.test(text2);
    const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor));
    const isRtl = (element) => DOMUtils.DOM.getStyle(element, "direction", true) === "rtl" || hasStrongRtl(element.textContent);
    const findInlineParents = (isInlineTarget2, rootNode, pos) => filter$6(DOMUtils.DOM.getParents(pos.container(), "*", rootNode), isInlineTarget2);
    const findRootInline = (isInlineTarget2, rootNode, pos) => {
      const parents2 = findInlineParents(isInlineTarget2, rootNode, pos);
      return Optional.from(parents2[parents2.length - 1]);
    };
    const hasSameParentBlock = (rootNode, node1, node2) => {
      const block1 = getParentBlock$3(node1, rootNode);
      const block2 = getParentBlock$3(node2, rootNode);
      return block1 && block1 === block2;
    };
    const isAtZwsp = (pos) => isBeforeInline(pos) || isAfterInline(pos);
    const normalizePosition = (forward, pos) => {
      if (!pos) {
        return pos;
      }
      const container = pos.container(), offset = pos.offset();
      if (forward) {
        if (isCaretContainerInline(container)) {
          if (isText$9(container.nextSibling)) {
            return CaretPosition(container.nextSibling, 0);
          } else {
            return CaretPosition.after(container);
          }
        } else {
          return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
        }
      } else {
        if (isCaretContainerInline(container)) {
          if (isText$9(container.previousSibling)) {
            return CaretPosition(container.previousSibling, container.previousSibling.data.length);
          } else {
            return CaretPosition.before(container);
          }
        } else {
          return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
        }
      }
    };
    const normalizeForwards = curry(normalizePosition, true);
    const normalizeBackwards = curry(normalizePosition, false);
    const execCommandIgnoreInputEvents = (editor, command) => {
      const inputBlocker = (e) => e.stopImmediatePropagation();
      editor.on("beforeinput input", inputBlocker, true);
      editor.getDoc().execCommand(command);
      editor.off("beforeinput input", inputBlocker);
    };
    const execDeleteCommand = (editor) => execCommandIgnoreInputEvents(editor, "Delete");
    const execForwardDeleteCommand = (editor) => execCommandIgnoreInputEvents(editor, "ForwardDelete");
    const isBeforeRoot = (rootNode) => (elm) => eq(rootNode, SugarElement.fromDom(elm.dom.parentNode));
    const isTextBlockOrListItem = (element) => isTextBlock$2(element) || isListItem(element);
    const getParentBlock$2 = (rootNode, elm) => {
      if (contains(rootNode, elm)) {
        return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
      } else {
        return Optional.none();
      }
    };
    const placeCaretInEmptyBody = (editor) => {
      const body = editor.getBody();
      const node = body.firstChild && editor.dom.isBlock(body.firstChild) ? body.firstChild : body;
      editor.selection.setCursorLocation(node, 0);
    };
    const paddEmptyBody = (editor) => {
      if (editor.dom.isEmpty(editor.getBody())) {
        editor.setContent("");
        placeCaretInEmptyBody(editor);
      }
    };
    const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
      const normalizedFirstPos = normalizePosition(true, firstPos);
      const normalizedLastPos = normalizePosition(false, lastPos);
      const normalizedFromPos = normalizePosition(false, fromPos);
      if (forward) {
        return nextPosition(elm, normalizedFromPos).exists((nextPos) => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
      } else {
        return prevPosition(elm, normalizedFromPos).exists((prevPos) => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
      }
    }).getOr(true);
    const freefallRtl = (root) => {
      const child2 = isComment$1(root) ? prevSibling(root) : lastChild(root);
      return child2.bind(freefallRtl).orThunk(() => Optional.some(root));
    };
    const deleteRangeContents = (editor, rng, root, moveSelection2 = true) => {
      rng.deleteContents();
      const lastNode = freefallRtl(root).getOr(root);
      const lastBlock = SugarElement.fromDom(editor.dom.getParent(lastNode.dom, editor.dom.isBlock));
      if (isEmpty$2(lastBlock)) {
        fillWithPaddingBr(lastBlock);
        if (moveSelection2) {
          editor.selection.setCursorLocation(lastBlock.dom, 0);
        }
      }
      if (!eq(root, lastBlock)) {
        const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
        each$f(additionalCleanupNodes.concat(children(root)), (node) => {
          if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(node)) {
            remove$6(node);
          }
        });
      }
    };
    const isRootFromElement = (root) => (cur) => eq(root, cur);
    const getTableCells = (table2) => descendants(table2, "td,th");
    const getTableDetailsFromRange = (rng, isRoot2) => {
      const getTable2 = (node) => getClosestTable(SugarElement.fromDom(node), isRoot2);
      const startTable = getTable2(rng.startContainer);
      const endTable = getTable2(rng.endContainer);
      const isStartInTable = startTable.isSome();
      const isEndInTable = endTable.isSome();
      const isSameTable = lift2(startTable, endTable, eq).getOr(false);
      const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
      return {
        startTable,
        endTable,
        isStartInTable,
        isEndInTable,
        isSameTable,
        isMultiTable
      };
    };
    const tableCellRng = (start2, end2) => ({
      start: start2,
      end: end2
    });
    const tableSelection = (rng, table2, cells2) => ({
      rng,
      table: table2,
      cells: cells2
    });
    const deleteAction = Adt.generate([
      {
        singleCellTable: [
          "rng",
          "cell"
        ]
      },
      { fullTable: ["table"] },
      {
        partialTable: [
          "cells",
          "outsideDetails"
        ]
      },
      {
        multiTable: [
          "startTableCells",
          "endTableCells",
          "betweenRng"
        ]
      }
    ]);
    const getClosestCell$1 = (container, isRoot2) => closest$3(SugarElement.fromDom(container), "td,th", isRoot2);
    const isExpandedCellRng = (cellRng) => !eq(cellRng.start, cellRng.end);
    const getTableFromCellRng = (cellRng, isRoot2) => getClosestTable(cellRng.start, isRoot2).bind((startParentTable) => getClosestTable(cellRng.end, isRoot2).bind((endParentTable) => someIf(eq(startParentTable, endParentTable), startParentTable)));
    const isSingleCellTable = (cellRng, isRoot2) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot2).exists((table2) => {
      const rows = table2.dom.rows;
      return rows.length === 1 && rows[0].cells.length === 1;
    });
    const getCellRng = (rng, isRoot2) => {
      const startCell = getClosestCell$1(rng.startContainer, isRoot2);
      const endCell = getClosestCell$1(rng.endContainer, isRoot2);
      return lift2(startCell, endCell, tableCellRng);
    };
    const getCellRangeFromStartTable = (isRoot2) => (startCell) => getClosestTable(startCell, isRoot2).bind((table2) => last$3(getTableCells(table2)).map((endCell) => tableCellRng(startCell, endCell)));
    const getCellRangeFromEndTable = (isRoot2) => (endCell) => getClosestTable(endCell, isRoot2).bind((table2) => head(getTableCells(table2)).map((startCell) => tableCellRng(startCell, endCell)));
    const getTableSelectionFromCellRng = (isRoot2) => (cellRng) => getTableFromCellRng(cellRng, isRoot2).map((table2) => tableSelection(cellRng, table2, getTableCells(table2)));
    const getTableSelections = (cellRng, selectionDetails, rng, isRoot2) => {
      if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
        return Optional.none();
      } else if (selectionDetails.isSameTable) {
        const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot2));
        return Optional.some({
          start: sameTableSelection,
          end: sameTableSelection
        });
      } else {
        const startCell = getClosestCell$1(rng.startContainer, isRoot2);
        const endCell = getClosestCell$1(rng.endContainer, isRoot2);
        const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot2)).bind(getTableSelectionFromCellRng(isRoot2));
        const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot2)).bind(getTableSelectionFromCellRng(isRoot2));
        return Optional.some({
          start: startTableSelection,
          end: endTableSelection
        });
      }
    };
    const getCellIndex = (cells2, cell2) => findIndex$2(cells2, (x) => eq(x, cell2));
    const getSelectedCells = (tableSelection2) => lift2(getCellIndex(tableSelection2.cells, tableSelection2.rng.start), getCellIndex(tableSelection2.cells, tableSelection2.rng.end), (startIndex, endIndex) => tableSelection2.cells.slice(startIndex, endIndex + 1));
    const isSingleCellTableContentSelected = (optCellRng, rng, isRoot2) => optCellRng.exists((cellRng) => isSingleCellTable(cellRng, isRoot2) && hasAllContentsSelected(cellRng.start, rng));
    const unselectCells = (rng, selectionDetails) => {
      const { startTable, endTable } = selectionDetails;
      const otherContentRng = rng.cloneRange();
      startTable.each((table2) => otherContentRng.setStartAfter(table2.dom));
      endTable.each((table2) => otherContentRng.setEndBefore(table2.dom));
      return otherContentRng;
    };
    const handleSingleTable = (cellRng, selectionDetails, rng, isRoot2) => getTableSelections(cellRng, selectionDetails, rng, isRoot2).bind(({ start: start2, end: end2 }) => start2.or(end2)).bind((tableSelection2) => {
      const { isSameTable } = selectionDetails;
      const selectedCells = getSelectedCells(tableSelection2).getOr([]);
      if (isSameTable && tableSelection2.cells.length === selectedCells.length) {
        return Optional.some(deleteAction.fullTable(tableSelection2.table));
      } else if (selectedCells.length > 0) {
        if (isSameTable) {
          return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
        } else {
          const otherContentRng = unselectCells(rng, selectionDetails);
          return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
            ...selectionDetails,
            rng: otherContentRng
          })));
        }
      } else {
        return Optional.none();
      }
    });
    const handleMultiTable = (cellRng, selectionDetails, rng, isRoot2) => getTableSelections(cellRng, selectionDetails, rng, isRoot2).bind(({ start: start2, end: end2 }) => {
      const startTableSelectedCells = start2.bind(getSelectedCells).getOr([]);
      const endTableSelectedCells = end2.bind(getSelectedCells).getOr([]);
      if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
        const otherContentRng = unselectCells(rng, selectionDetails);
        return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
      } else {
        return Optional.none();
      }
    });
    const getActionFromRange = (root, rng) => {
      const isRoot2 = isRootFromElement(root);
      const optCellRng = getCellRng(rng, isRoot2);
      const selectionDetails = getTableDetailsFromRange(rng, isRoot2);
      if (isSingleCellTableContentSelected(optCellRng, rng, isRoot2)) {
        return optCellRng.map((cellRng) => deleteAction.singleCellTable(rng, cellRng.start));
      } else if (selectionDetails.isMultiTable) {
        return handleMultiTable(optCellRng, selectionDetails, rng, isRoot2);
      } else {
        return handleSingleTable(optCellRng, selectionDetails, rng, isRoot2);
      }
    };
    const cleanCells = (cells2) => each$f(cells2, (cell2) => {
      remove$b(cell2, "contenteditable");
      fillWithPaddingBr(cell2);
    });
    const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
    const handleEmptyBlock = (editor, startInTable, emptyBlock2) => {
      emptyBlock2.each((block) => {
        if (startInTable) {
          remove$6(block);
        } else {
          fillWithPaddingBr(block);
          editor.selection.setCursorLocation(block.dom, 0);
        }
      });
    };
    const deleteContentInsideCell = (editor, cell2, rng, isFirstCellInSelection) => {
      const insideTableRng = rng.cloneRange();
      if (isFirstCellInSelection) {
        insideTableRng.setStart(rng.startContainer, rng.startOffset);
        insideTableRng.setEndAfter(cell2.dom.lastChild);
      } else {
        insideTableRng.setStartBefore(cell2.dom.firstChild);
        insideTableRng.setEnd(rng.endContainer, rng.endOffset);
      }
      deleteCellContents(editor, insideTableRng, cell2, false).each((action2) => action2());
    };
    const collapseAndRestoreCellSelection = (editor) => {
      const selectedCells = getCellsFromEditor(editor);
      const selectedNode = SugarElement.fromDom(editor.selection.getNode());
      if (isTableCell$5(selectedNode.dom) && isEmpty$2(selectedNode)) {
        editor.selection.setCursorLocation(selectedNode.dom, 0);
      } else {
        editor.selection.collapse(true);
      }
      if (selectedCells.length > 1 && exists(selectedCells, (cell2) => eq(cell2, selectedNode))) {
        set$2(selectedNode, "data-mce-selected", "1");
      }
    };
    const emptySingleTableCells = (editor, cells2, outsideDetails) => Optional.some(() => {
      const editorRng = editor.selection.getRng();
      const cellsToClean = outsideDetails.bind(({ rng, isStartInTable }) => {
        const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
        rng.deleteContents();
        handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(isEmpty$2));
        const endPointCell = isStartInTable ? cells2[0] : cells2[cells2.length - 1];
        deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
        if (!isEmpty$2(endPointCell)) {
          return Optional.some(isStartInTable ? cells2.slice(1) : cells2.slice(0, -1));
        } else {
          return Optional.none();
        }
      }).getOr(cells2);
      cleanCells(cellsToClean);
      collapseAndRestoreCellSelection(editor);
    });
    const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
      const rng = editor.selection.getRng();
      const startCell = startTableCells[0];
      const endCell = endTableCells[endTableCells.length - 1];
      deleteContentInsideCell(editor, startCell, rng, true);
      deleteContentInsideCell(editor, endCell, rng, false);
      const startTableCellsToClean = isEmpty$2(startCell) ? startTableCells : startTableCells.slice(1);
      const endTableCellsToClean = isEmpty$2(endCell) ? endTableCells : endTableCells.slice(0, -1);
      cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
      betweenRng.deleteContents();
      collapseAndRestoreCellSelection(editor);
    });
    const deleteCellContents = (editor, rng, cell2, moveSelection2 = true) => Optional.some(() => {
      deleteRangeContents(editor, rng, cell2, moveSelection2);
    });
    const deleteTableElement = (editor, table2) => Optional.some(() => deleteElement$2(editor, false, table2));
    const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind((action2) => action2.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
    const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
    const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), (caption) => deleteCaptionRange(editor, caption));
    const deleteRange$2 = (editor, startElm, selectedCells) => {
      const rootNode = SugarElement.fromDom(editor.getBody());
      const rng = editor.selection.getRng();
      return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
    };
    const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$4);
    const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag("caption"));
    const deleteBetweenCells = (editor, rootElm, forward, fromCell, from2) => navigate(forward, editor.getBody(), from2).bind((to2) => getParentCell(rootElm, SugarElement.fromDom(to2.getNode())).bind((toCell) => eq(toCell, fromCell) ? Optional.none() : Optional.some(noop)));
    const emptyElement = (editor, elm) => Optional.some(() => {
      fillWithPaddingBr(elm);
      editor.selection.setCursorLocation(elm.dom, 0);
    });
    const isDeleteOfLastCharPos = (fromCaption, forward, from2, to2) => firstPositionIn(fromCaption.dom).bind((first2) => lastPositionIn(fromCaption.dom).map((last2) => forward ? from2.isEqual(first2) && to2.isEqual(last2) : from2.isEqual(last2) && to2.isEqual(first2))).getOr(true);
    const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
    const validateCaretCaption = (rootElm, fromCaption, to2) => getParentCaption(rootElm, SugarElement.fromDom(to2.getNode())).fold(() => Optional.some(noop), (toCaption) => someIf(!eq(toCaption, fromCaption), noop));
    const deleteCaretInsideCaption = (editor, rootElm, forward, fromCaption, from2) => navigate(forward, editor.getBody(), from2).fold(() => Optional.some(noop), (to2) => isDeleteOfLastCharPos(fromCaption, forward, from2, to2) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to2));
    const deleteCaretCells = (editor, forward, rootElm, startElm) => {
      const from2 = CaretPosition.fromRangeStart(editor.selection.getRng());
      return getParentCell(rootElm, startElm).bind((fromCell) => isEmpty$2(fromCell) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from2));
    };
    const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
      const from2 = CaretPosition.fromRangeStart(editor.selection.getRng());
      return isEmpty$2(fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from2);
    };
    const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
    const isBeforeOrAfterTable = (editor, forward) => {
      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
      return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists((pos) => isNearTable(forward, pos));
    };
    const deleteCaret$3 = (editor, forward, startElm) => {
      const rootElm = SugarElement.fromDom(editor.getBody());
      return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), (fromCaption) => deleteCaretCaption(editor, forward, rootElm, fromCaption));
    };
    const backspaceDelete$9 = (editor, forward) => {
      const startElm = SugarElement.fromDom(editor.selection.getStart(true));
      const cells2 = getCellsFromEditor(editor);
      return editor.selection.isCollapsed() && cells2.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$2(editor, startElm, cells2);
    };
    const getContentEditableRoot$1 = (root, node) => {
      while (node && node !== root) {
        if (isContentEditableTrue$5(node) || isContentEditableFalse$b(node)) {
          return node;
        }
        node = node.parentNode;
      }
      return null;
    };
    const traverse = (node, fn) => {
      fn(node);
      if (node.firstChild) {
        traverse(node.firstChild, fn);
      }
      if (node.next) {
        traverse(node.next, fn);
      }
    };
    const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
      const name2 = node.name;
      for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
        const filter2 = nodeFilters[ni];
        if (filter2.name === name2) {
          const match2 = matches.nodes[name2];
          if (match2) {
            match2.nodes.push(node);
          } else {
            matches.nodes[name2] = {
              filter: filter2,
              nodes: [node]
            };
          }
        }
      }
      if (node.attributes) {
        for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
          const filter2 = attributeFilters[ai];
          const attrName = filter2.name;
          if (attrName in node.attributes.map) {
            const match2 = matches.attributes[attrName];
            if (match2) {
              match2.nodes.push(node);
            } else {
              matches.attributes[attrName] = {
                filter: filter2,
                nodes: [node]
              };
            }
          }
        }
      }
    };
    const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
      const matches = {
        nodes: {},
        attributes: {}
      };
      if (node.firstChild) {
        traverse(node.firstChild, (node2) => {
          matchNode$1(nodeFilters, attributeFilters, node2, matches);
        });
      }
      return matches;
    };
    const runFilters = (matches, args) => {
      const run = (matchRecord) => {
        each$e(matchRecord, (match2) => {
          const nodes = filter$6(match2.nodes, (node) => isNonNullable(node.parent));
          each$f(match2.filter.callbacks, (callback) => {
            callback(nodes, match2.filter.name, args);
          });
        });
      };
      run(matches.nodes);
      run(matches.attributes);
    };
    const filter$3 = (nodeFilters, attributeFilters, node, args = {}) => {
      const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
      runFilters(matches, args);
    };
    const paddEmptyNode = (settings, args, blockElements, node) => {
      if (args.insert && blockElements[node.name]) {
        node.empty().append(new AstNode("br", 1));
      } else {
        node.empty().append(new AstNode("#text", 3)).value = nbsp;
      }
    };
    const isPaddedWithNbsp = (node) => hasOnlyChild(node, "#text") && node.firstChild.value === nbsp;
    const hasOnlyChild = (node, name2) => node && node.firstChild && node.firstChild === node.lastChild && node.firstChild.name === name2;
    const isPadded = (schema, node) => {
      const rule = schema.getElementRule(node.name);
      return rule && rule.paddEmpty;
    };
    const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, (node2) => isPadded(schema, node2));
    const isLineBreakNode = (node, blockElements) => node && (node.name in blockElements || node.name === "br");
    const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
      if (schema.getSpecialElements()[node.name]) {
        node.empty().remove();
      } else {
        const children2 = node.children();
        for (const childNode of children2) {
          if (!schema.isValidChild(originalNodeParent.name, childNode.name)) {
            removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
          }
        }
        node.unwrap();
      }
    };
    const cleanInvalidNodes = (nodes, schema, onCreate = noop) => {
      const textBlockElements = schema.getTextBlockElements();
      const nonEmptyElements = schema.getNonEmptyElements();
      const whitespaceElements = schema.getWhitespaceElements();
      const nonSplittableElements = Tools.makeMap("tr,td,th,tbody,thead,tfoot,table");
      const fixed = /* @__PURE__ */ new Set();
      for (let ni = 0; ni < nodes.length; ni++) {
        const node = nodes[ni];
        let parent2;
        let newParent;
        let tempNode;
        if (!node.parent || fixed.has(node)) {
          continue;
        }
        if (textBlockElements[node.name] && node.parent.name === "li") {
          let sibling2 = node.next;
          while (sibling2) {
            if (textBlockElements[sibling2.name]) {
              sibling2.name = "li";
              fixed.add(sibling2);
              node.parent.insert(sibling2, node.parent);
            } else {
              break;
            }
            sibling2 = sibling2.next;
          }
          node.unwrap();
          continue;
        }
        const parents2 = [node];
        for (parent2 = node.parent; parent2 && !schema.isValidChild(parent2.name, node.name) && !nonSplittableElements[parent2.name]; parent2 = parent2.parent) {
          parents2.push(parent2);
        }
        if (parent2 && parents2.length > 1) {
          if (schema.isValidChild(parent2.name, node.name)) {
            parents2.reverse();
            newParent = parents2[0].clone();
            onCreate(newParent);
            let currentNode = newParent;
            for (let i = 0; i < parents2.length - 1; i++) {
              if (schema.isValidChild(currentNode.name, parents2[i].name)) {
                tempNode = parents2[i].clone();
                onCreate(tempNode);
                currentNode.append(tempNode);
              } else {
                tempNode = currentNode;
              }
              for (let childNode = parents2[i].firstChild; childNode && childNode !== parents2[i + 1]; ) {
                const nextNode = childNode.next;
                tempNode.append(childNode);
                childNode = nextNode;
              }
              currentNode = tempNode;
            }
            if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
              parent2.insert(newParent, parents2[0], true);
              parent2.insert(node, newParent);
            } else {
              parent2.insert(node, parents2[0], true);
            }
            parent2 = parents2[0];
            if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent2) || hasOnlyChild(parent2, "br")) {
              parent2.empty().remove();
            }
          } else {
            removeOrUnwrapInvalidNode(node, schema);
          }
        } else if (node.parent) {
          if (node.name === "li") {
            let sibling2 = node.prev;
            if (sibling2 && (sibling2.name === "ul" || sibling2.name === "ol")) {
              sibling2.append(node);
              continue;
            }
            sibling2 = node.next;
            if (sibling2 && (sibling2.name === "ul" || sibling2.name === "ol")) {
              sibling2.insert(node, sibling2.firstChild, true);
              continue;
            }
            const wrapper = new AstNode("ul", 1);
            onCreate(wrapper);
            node.wrap(wrapper);
            continue;
          }
          if (schema.isValidChild(node.parent.name, "div") && schema.isValidChild("div", node.name)) {
            const wrapper = new AstNode("div", 1);
            onCreate(wrapper);
            node.wrap(wrapper);
          } else {
            removeOrUnwrapInvalidNode(node, schema);
          }
        }
      }
    };
    const createRange = (sc, so, ec, eo) => {
      const rng = document.createRange();
      rng.setStart(sc, so);
      rng.setEnd(ec, eo);
      return rng;
    };
    const normalizeBlockSelectionRange = (rng) => {
      const startPos = CaretPosition.fromRangeStart(rng);
      const endPos = CaretPosition.fromRangeEnd(rng);
      const rootNode = rng.commonAncestorContainer;
      return fromPosition(false, rootNode, endPos).map((newEndPos) => {
        if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
          return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
        } else {
          return rng;
        }
      }).getOr(rng);
    };
    const normalize = (rng) => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
    const hasOnlyOneChild$1 = (node) => {
      return node.firstChild && node.firstChild === node.lastChild;
    };
    const isPaddingNode = (node) => {
      return node.name === "br" || node.value === nbsp;
    };
    const isPaddedEmptyBlock = (schema, node) => {
      const blockElements = schema.getBlockElements();
      return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
    };
    const isEmptyFragmentElement = (schema, node) => {
      const nonEmptyElements = schema.getNonEmptyElements();
      return node && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
    };
    const isListFragment = (schema, fragment) => {
      let firstChild2 = fragment.firstChild;
      let lastChild2 = fragment.lastChild;
      if (firstChild2 && firstChild2.name === "meta") {
        firstChild2 = firstChild2.next;
      }
      if (lastChild2 && lastChild2.attr("id") === "mce_marker") {
        lastChild2 = lastChild2.prev;
      }
      if (isEmptyFragmentElement(schema, lastChild2)) {
        lastChild2 = lastChild2.prev;
      }
      if (!firstChild2 || firstChild2 !== lastChild2) {
        return false;
      }
      return firstChild2.name === "ul" || firstChild2.name === "ol";
    };
    const cleanupDomFragment = (domFragment) => {
      const firstChild2 = domFragment.firstChild;
      const lastChild2 = domFragment.lastChild;
      if (firstChild2 && firstChild2.nodeName === "META") {
        firstChild2.parentNode.removeChild(firstChild2);
      }
      if (lastChild2 && lastChild2.id === "mce_marker") {
        lastChild2.parentNode.removeChild(lastChild2);
      }
      return domFragment;
    };
    const toDomFragment = (dom2, serializer, fragment) => {
      const html2 = serializer.serialize(fragment);
      const domFragment = dom2.createFragment(html2);
      return cleanupDomFragment(domFragment);
    };
    const listItems = (elm) => {
      return filter$6(elm.childNodes, (child2) => {
        return child2.nodeName === "LI";
      });
    };
    const isPadding = (node) => {
      return node.data === nbsp || isBr$6(node);
    };
    const isListItemPadded = (node) => {
      return node && node.firstChild && node.firstChild === node.lastChild && isPadding(node.firstChild);
    };
    const isEmptyOrPadded = (elm) => {
      return !elm.firstChild || isListItemPadded(elm);
    };
    const trimListItems = (elms) => {
      return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
    };
    const getParentLi = (dom2, node) => {
      const parentBlock = dom2.getParent(node, dom2.isBlock);
      return parentBlock && parentBlock.nodeName === "LI" ? parentBlock : null;
    };
    const isParentBlockLi = (dom2, node) => {
      return !!getParentLi(dom2, node);
    };
    const getSplit = (parentNode, rng) => {
      const beforeRng = rng.cloneRange();
      const afterRng = rng.cloneRange();
      beforeRng.setStartBefore(parentNode);
      afterRng.setEndAfter(parentNode);
      return [
        beforeRng.cloneContents(),
        afterRng.cloneContents()
      ];
    };
    const findFirstIn = (node, rootNode) => {
      const caretPos = CaretPosition.before(node);
      const caretWalker = CaretWalker(rootNode);
      const newCaretPos = caretWalker.next(caretPos);
      return newCaretPos ? newCaretPos.toRange() : null;
    };
    const findLastOf = (node, rootNode) => {
      const caretPos = CaretPosition.after(node);
      const caretWalker = CaretWalker(rootNode);
      const newCaretPos = caretWalker.prev(caretPos);
      return newCaretPos ? newCaretPos.toRange() : null;
    };
    const insertMiddle = (target, elms, rootNode, rng) => {
      const parts = getSplit(target, rng);
      const parentElm = target.parentNode;
      parentElm.insertBefore(parts[0], target);
      Tools.each(elms, (li) => {
        parentElm.insertBefore(li, target);
      });
      parentElm.insertBefore(parts[1], target);
      parentElm.removeChild(target);
      return findLastOf(elms[elms.length - 1], rootNode);
    };
    const insertBefore$1 = (target, elms, rootNode) => {
      const parentElm = target.parentNode;
      Tools.each(elms, (elm) => {
        parentElm.insertBefore(elm, target);
      });
      return findFirstIn(target, rootNode);
    };
    const insertAfter$1 = (target, elms, rootNode, dom2) => {
      dom2.insertAfter(elms.reverse(), target);
      return findLastOf(elms[0], rootNode);
    };
    const insertAtCaret$1 = (serializer, dom2, rng, fragment) => {
      const domFragment = toDomFragment(dom2, serializer, fragment);
      const liTarget = getParentLi(dom2, rng.startContainer);
      const liElms = trimListItems(listItems(domFragment.firstChild));
      const BEGINNING = 1, END = 2;
      const rootNode = dom2.getRoot();
      const isAt = (location) => {
        const caretPos = CaretPosition.fromRangeStart(rng);
        const caretWalker = CaretWalker(dom2.getRoot());
        const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
        return newPos ? getParentLi(dom2, newPos.getNode()) !== liTarget : true;
      };
      if (isAt(BEGINNING)) {
        return insertBefore$1(liTarget, liElms, rootNode);
      } else if (isAt(END)) {
        return insertAfter$1(liTarget, liElms, rootNode, dom2);
      }
      return insertMiddle(liTarget, liElms, rootNode, rng);
    };
    const wrappedElements = ["pre"];
    const shouldPasteContentOnly = (fragment, parentNode) => {
      const firstNode = fragment.firstChild;
      const isAFlattenableTag = contains$2(wrappedElements, firstNode.name);
      const isPastingInTheSameTag = firstNode.name === parentNode.tagName.toLowerCase();
      const lastNode = fragment.lastChild.attr("data-mce-type") === "bookmark" ? fragment.lastChild.prev : fragment.lastChild;
      const isCopingOnlyOneTag = firstNode === lastNode;
      return isCopingOnlyOneTag && isAFlattenableTag && isPastingInTheSameTag;
    };
    const isTableCell$1 = isTableCell$5;
    const isTableCellContentSelected = (dom2, rng, cell2) => {
      if (cell2 !== null) {
        const endCell = dom2.getParent(rng.endContainer, isTableCell$1);
        return cell2 === endCell && hasAllContentsSelected(SugarElement.fromDom(cell2), rng);
      } else {
        return false;
      }
    };
    const validInsertion = (editor, value2, parentNode) => {
      if (parentNode.getAttribute("data-mce-bogus") === "all") {
        parentNode.parentNode.insertBefore(editor.dom.createFragment(value2), parentNode);
      } else {
        const node = parentNode.firstChild;
        const node2 = parentNode.lastChild;
        if (!node || node === node2 && node.nodeName === "BR") {
          editor.dom.setHTML(parentNode, value2);
        } else {
          editor.selection.setContent(value2, { no_events: true });
        }
      }
    };
    const trimBrsFromTableCell = (dom2, elm) => {
      Optional.from(dom2.getParent(elm, "td,th")).map(SugarElement.fromDom).each(trimBlockTrailingBr);
    };
    const reduceInlineTextElements = (editor, merge2) => {
      const textInlineElements = editor.schema.getTextInlineElements();
      const dom2 = editor.dom;
      if (merge2) {
        const root = editor.getBody();
        const elementUtils = ElementUtils(dom2);
        Tools.each(dom2.select("*[data-mce-fragment]"), (node) => {
          const isInline2 = isNonNullable(textInlineElements[node.nodeName.toLowerCase()]);
          if (isInline2 && hasInheritableStyles(dom2, node)) {
            for (let parentNode = node.parentNode; isNonNullable(parentNode) && parentNode !== root; parentNode = parentNode.parentNode) {
              const styleConflict = hasStyleConflict(dom2, node, parentNode);
              if (styleConflict) {
                break;
              }
              if (elementUtils.compare(parentNode, node)) {
                dom2.remove(node, true);
                break;
              }
            }
          }
        });
      }
    };
    const markFragmentElements = (fragment) => {
      let node = fragment;
      while (node = node.walk()) {
        if (node.type === 1) {
          node.attr("data-mce-fragment", "1");
        }
      }
    };
    const unmarkFragmentElements = (elm) => {
      Tools.each(elm.getElementsByTagName("*"), (elm2) => {
        elm2.removeAttribute("data-mce-fragment");
      });
    };
    const isPartOfFragment = (node) => {
      return !!node.getAttribute("data-mce-fragment");
    };
    const canHaveChildren = (editor, node) => {
      return node && !editor.schema.getVoidElements()[node.nodeName];
    };
    const moveSelectionToMarker = (editor, marker) => {
      let nextRng;
      const dom2 = editor.dom;
      const selection = editor.selection;
      if (!marker) {
        return;
      }
      selection.scrollIntoView(marker);
      const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
      if (dom2.getContentEditable(parentEditableElm) === "false") {
        dom2.remove(marker);
        selection.select(parentEditableElm);
        return;
      }
      let rng = dom2.createRng();
      const node = marker.previousSibling;
      if (isText$9(node)) {
        rng.setStart(node, node.nodeValue.length);
        const node2 = marker.nextSibling;
        if (isText$9(node2)) {
          node.appendData(node2.data);
          node2.parentNode.removeChild(node2);
        }
      } else {
        rng.setStartBefore(marker);
        rng.setEndBefore(marker);
      }
      const findNextCaretRng = (rng2) => {
        let caretPos = CaretPosition.fromRangeStart(rng2);
        const caretWalker = CaretWalker(editor.getBody());
        caretPos = caretWalker.next(caretPos);
        if (caretPos) {
          return caretPos.toRange();
        }
      };
      const parentBlock = dom2.getParent(marker, dom2.isBlock);
      dom2.remove(marker);
      if (parentBlock && dom2.isEmpty(parentBlock)) {
        empty(SugarElement.fromDom(parentBlock));
        rng.setStart(parentBlock, 0);
        rng.setEnd(parentBlock, 0);
        if (!isTableCell$1(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
          rng = nextRng;
          dom2.remove(parentBlock);
        } else {
          dom2.add(parentBlock, dom2.create("br", { "data-mce-bogus": "1" }));
        }
      }
      selection.setRng(rng);
    };
    const deleteSelectedContent = (editor) => {
      const dom2 = editor.dom;
      const rng = normalize(editor.selection.getRng());
      editor.selection.setRng(rng);
      const startCell = dom2.getParent(rng.startContainer, isTableCell$1);
      if (isTableCellContentSelected(dom2, rng, startCell)) {
        deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
      } else {
        editor.getDoc().execCommand("Delete", false, null);
      }
    };
    const insertHtmlAtCaret = (editor, value2, details) => {
      let parentNode;
      let rng, node;
      const selection = editor.selection;
      const dom2 = editor.dom;
      const parser = editor.parser;
      const merge2 = details.merge;
      const serializer = HtmlSerializer({ validate: true }, editor.schema);
      const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
      if (value2.indexOf("{$caret}") === -1) {
        value2 += "{$caret}";
      }
      value2 = value2.replace(/\{\$caret\}/, bookmarkHtml);
      rng = selection.getRng();
      const caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
      const body = editor.getBody();
      if (caretElement === body && selection.isCollapsed()) {
        if (dom2.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom2.isEmpty(body.firstChild)) {
          rng = dom2.createRng();
          rng.setStart(body.firstChild, 0);
          rng.setEnd(body.firstChild, 0);
          selection.setRng(rng);
        }
      }
      if (!selection.isCollapsed()) {
        deleteSelectedContent(editor);
      }
      parentNode = selection.getNode();
      const parserArgs = {
        context: parentNode.nodeName.toLowerCase(),
        data: details.data,
        insert: true
      };
      const fragment = parser.parse(value2, parserArgs);
      if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom2, parentNode)) {
        rng = insertAtCaret$1(serializer, dom2, selection.getRng(), fragment);
        selection.setRng(rng);
        return value2;
      }
      if (details.paste === true && shouldPasteContentOnly(fragment, parentNode)) {
        fragment.firstChild.unwrap();
      }
      markFragmentElements(fragment);
      node = fragment.lastChild;
      if (node.attr("id") === "mce_marker") {
        const marker = node;
        for (node = node.prev; node; node = node.walk(true)) {
          if (node.type === 3 || !dom2.isBlock(node.name)) {
            if (editor.schema.isValidChild(node.parent.name, "span")) {
              node.parent.insert(marker, node, node.name === "br");
            }
            break;
          }
        }
      }
      editor._selectionOverrides.showBlockCaretContainer(parentNode);
      if (!parserArgs.invalid) {
        value2 = serializer.serialize(fragment);
        validInsertion(editor, value2, parentNode);
      } else {
        editor.selection.setContent(bookmarkHtml);
        parentNode = selection.getNode();
        const rootNode = editor.getBody();
        if (parentNode.nodeType === 9) {
          parentNode = node = rootNode;
        } else {
          node = parentNode;
        }
        while (node !== rootNode) {
          parentNode = node;
          node = node.parentNode;
        }
        value2 = parentNode === rootNode ? rootNode.innerHTML : dom2.getOuterHTML(parentNode);
        const root = parser.parse(value2);
        for (let markerNode = root; markerNode; markerNode = markerNode.walk()) {
          if (markerNode.attr("id") === "mce_marker") {
            markerNode.replace(fragment);
            break;
          }
        }
        const toExtract = fragment.children();
        const parent2 = fragment.parent.name;
        fragment.unwrap();
        const invalidChildren = filter$6(toExtract, (node2) => !editor.schema.isValidChild(parent2, node2.name));
        cleanInvalidNodes(invalidChildren, editor.schema);
        filter$3(parser.getNodeFilters(), parser.getAttributeFilters(), root);
        value2 = serializer.serialize(root);
        if (parentNode === rootNode) {
          dom2.setHTML(rootNode, value2);
        } else {
          dom2.setOuterHTML(parentNode, value2);
        }
      }
      reduceInlineTextElements(editor, merge2);
      moveSelectionToMarker(editor, dom2.get("mce_marker"));
      unmarkFragmentElements(editor.getBody());
      trimBrsFromTableCell(dom2, selection.getStart());
      return value2;
    };
    const isTreeNode = (content) => content instanceof AstNode;
    const moveSelection = (editor) => {
      if (hasFocus(editor)) {
        firstPositionIn(editor.getBody()).each((pos) => {
          const node = pos.getNode();
          const caretPos = isTable$3(node) ? firstPositionIn(node).getOr(pos) : pos;
          editor.selection.setRng(caretPos.toRange());
        });
      }
    };
    const setEditorHtml = (editor, html2, noSelection) => {
      editor.dom.setHTML(editor.getBody(), html2);
      if (noSelection !== true) {
        moveSelection(editor);
      }
    };
    const setContentString = (editor, body, content, args) => {
      if (content.length === 0 || /^\s+$/.test(content)) {
        const padd = '<br data-mce-bogus="1">';
        if (body.nodeName === "TABLE") {
          content = "<tr><td>" + padd + "</td></tr>";
        } else if (/^(UL|OL)$/.test(body.nodeName)) {
          content = "<li>" + padd + "</li>";
        }
        const forcedRootBlockName = getForcedRootBlock(editor);
        if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
          content = padd;
          content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
        } else if (!content) {
          content = padd;
        }
        setEditorHtml(editor, content, args.no_selection);
        return {
          content,
          html: content
        };
      } else {
        if (args.format !== "raw") {
          content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
            isRootContent: true,
            insert: true
          }));
        }
        const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
        setEditorHtml(editor, trimmedHtml, args.no_selection);
        return {
          content: trimmedHtml,
          html: trimmedHtml
        };
      }
    };
    const setContentTree = (editor, body, content, args) => {
      filter$3(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
      const html2 = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
      const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? html2 : Tools.trim(html2);
      setEditorHtml(editor, trimmedHtml, args.no_selection);
      return {
        content,
        html: trimmedHtml
      };
    };
    const setContentInternal = (editor, content, args) => {
      return Optional.from(editor.getBody()).map((body) => {
        if (isTreeNode(content)) {
          return setContentTree(editor, body, content, args);
        } else {
          return setContentString(editor, body, content, args);
        }
      }).getOr({
        content,
        html: isTreeNode(args.content) ? "" : args.content
      });
    };
    const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
    const ensureIsRoot = (isRoot2) => isFunction(isRoot2) ? isRoot2 : never;
    const ancestor = (scope, transform, isRoot2) => {
      let element = scope.dom;
      const stop2 = ensureIsRoot(isRoot2);
      while (element.parentNode) {
        element = element.parentNode;
        const el = SugarElement.fromDom(element);
        const transformed = transform(el);
        if (transformed.isSome()) {
          return transformed;
        } else if (stop2(el)) {
          break;
        }
      }
      return Optional.none();
    };
    const closest$2 = (scope, transform, isRoot2) => {
      const current = transform(scope);
      const stop2 = ensureIsRoot(isRoot2);
      return current.orThunk(() => stop2(scope) ? Optional.none() : ancestor(scope, transform, stop2));
    };
    const isEq$3 = isEq$5;
    const matchesUnInheritedFormatSelector = (ed, node, name2) => {
      const formatList = ed.formatter.get(name2);
      if (formatList) {
        for (let i = 0; i < formatList.length; i++) {
          const format = formatList[i];
          if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
            return true;
          }
        }
      }
      return false;
    };
    const matchParents = (editor, node, name2, vars, similar) => {
      const root = editor.dom.getRoot();
      if (node === root) {
        return false;
      }
      node = editor.dom.getParent(node, (node2) => {
        if (matchesUnInheritedFormatSelector(editor, node2, name2)) {
          return true;
        }
        return node2.parentNode === root || !!matchNode(editor, node2, name2, vars, true);
      });
      return !!matchNode(editor, node, name2, vars, similar);
    };
    const matchName = (dom2, node, format) => {
      if (isInlineFormat(format) && isEq$3(node, format.inline)) {
        return true;
      }
      if (isBlockFormat(format) && isEq$3(node, format.block)) {
        return true;
      }
      if (isSelectorFormat(format)) {
        return isElement$6(node) && dom2.is(node, format.selector);
      }
      return false;
    };
    const matchItems = (dom2, node, format, itemName, similar, vars) => {
      const items = format[itemName];
      if (isFunction(format.onmatch)) {
        return format.onmatch(node, format, itemName);
      }
      if (items) {
        if (isUndefined(items.length)) {
          for (const key in items) {
            if (has$2(items, key)) {
              const value2 = itemName === "attributes" ? dom2.getAttrib(node, key) : getStyle(dom2, node, key);
              const expectedValue = replaceVars(items[key], vars);
              const isEmptyValue = isNullable(value2) || isEmpty$3(value2);
              if (isEmptyValue && isNullable(expectedValue)) {
                continue;
              }
              if (similar && isEmptyValue && !format.exact) {
                return false;
              }
              if ((!similar || format.exact) && !isEq$3(value2, normalizeStyleValue(expectedValue, key))) {
                return false;
              }
            }
          }
        } else {
          for (let i = 0; i < items.length; i++) {
            if (itemName === "attributes" ? dom2.getAttrib(node, items[i]) : getStyle(dom2, node, items[i])) {
              return true;
            }
          }
        }
      }
      return true;
    };
    const matchNode = (ed, node, name2, vars, similar) => {
      const formatList = ed.formatter.get(name2);
      const dom2 = ed.dom;
      if (formatList && node) {
        for (let i = 0; i < formatList.length; i++) {
          const format = formatList[i];
          if (matchName(ed.dom, node, format) && matchItems(dom2, node, format, "attributes", similar, vars) && matchItems(dom2, node, format, "styles", similar, vars)) {
            const classes = format.classes;
            if (classes) {
              for (let x = 0; x < classes.length; x++) {
                if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
                  return;
                }
              }
            }
            return format;
          }
        }
      }
    };
    const match$2 = (editor, name2, vars, node, similar) => {
      if (node) {
        return matchParents(editor, node, name2, vars, similar);
      }
      node = editor.selection.getNode();
      if (matchParents(editor, node, name2, vars, similar)) {
        return true;
      }
      const startNode = editor.selection.getStart();
      if (startNode !== node) {
        if (matchParents(editor, startNode, name2, vars, similar)) {
          return true;
        }
      }
      return false;
    };
    const matchAll = (editor, names, vars) => {
      const matchedFormatNames = [];
      const checkedMap = {};
      const startElement = editor.selection.getStart();
      editor.dom.getParent(startElement, (node) => {
        for (let i = 0; i < names.length; i++) {
          const name2 = names[i];
          if (!checkedMap[name2] && matchNode(editor, node, name2, vars)) {
            checkedMap[name2] = true;
            matchedFormatNames.push(name2);
          }
        }
      }, editor.dom.getRoot());
      return matchedFormatNames;
    };
    const closest$1 = (editor, names) => {
      const isRoot2 = (elm) => eq(elm, SugarElement.fromDom(editor.getBody()));
      const match2 = (elm, name2) => matchNode(editor, elm.dom, name2) ? Optional.some(name2) : Optional.none();
      return Optional.from(editor.selection.getStart(true)).bind((rawElm) => closest$2(SugarElement.fromDom(rawElm), (elm) => findMap(names, (name2) => match2(elm, name2)), isRoot2)).getOrNull();
    };
    const canApply = (editor, name2) => {
      const formatList = editor.formatter.get(name2);
      const dom2 = editor.dom;
      if (formatList) {
        const startNode = editor.selection.getStart();
        const parents2 = getParents$2(dom2, startNode);
        for (let x = formatList.length - 1; x >= 0; x--) {
          const format = formatList[x];
          if (!isSelectorFormat(format)) {
            return true;
          }
          for (let i = parents2.length - 1; i >= 0; i--) {
            if (dom2.is(parents2[i], format.selector)) {
              return true;
            }
          }
        }
      }
      return false;
    };
    const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name2) => {
      const matchSimilar = isVariableFormatName(editor, name2);
      if (editor.formatter.matchNode(node, name2, {}, matchSimilar)) {
        return acc.concat([name2]);
      } else {
        return acc;
      }
    }, []);
    const ZWSP = ZWSP$1, CARET_ID = "_mce_caret";
    const importNode = (ownerDocument, node) => {
      return ownerDocument.importNode(node, true);
    };
    const getEmptyCaretContainers = (node) => {
      const nodes = [];
      while (node) {
        if (node.nodeType === 3 && node.nodeValue !== ZWSP || node.childNodes.length > 1) {
          return [];
        }
        if (node.nodeType === 1) {
          nodes.push(node);
        }
        node = node.firstChild;
      }
      return nodes;
    };
    const isCaretContainerEmpty = (node) => {
      return getEmptyCaretContainers(node).length > 0;
    };
    const findFirstTextNode = (node) => {
      if (node) {
        const walker = new DomTreeWalker(node, node);
        for (node = walker.current(); node; node = walker.next()) {
          if (isText$9(node)) {
            return node;
          }
        }
      }
      return null;
    };
    const createCaretContainer = (fill) => {
      const caretContainer = SugarElement.fromTag("span");
      setAll$1(caretContainer, {
        "id": CARET_ID,
        "data-mce-bogus": "1",
        "data-mce-type": "format-caret"
      });
      if (fill) {
        append$1(caretContainer, SugarElement.fromText(ZWSP));
      }
      return caretContainer;
    };
    const trimZwspFromCaretContainer = (caretContainerNode) => {
      const textNode = findFirstTextNode(caretContainerNode);
      if (textNode && textNode.nodeValue.charAt(0) === ZWSP) {
        textNode.deleteData(0, 1);
      }
      return textNode;
    };
    const removeCaretContainerNode = (editor, node, moveCaret2 = true) => {
      const dom2 = editor.dom, selection = editor.selection;
      if (isCaretContainerEmpty(node)) {
        deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret2);
      } else {
        const rng = selection.getRng();
        const block = dom2.getParent(node, dom2.isBlock);
        const startContainer = rng.startContainer;
        const startOffset = rng.startOffset;
        const endContainer = rng.endContainer;
        const endOffset = rng.endOffset;
        const textNode = trimZwspFromCaretContainer(node);
        dom2.remove(node, true);
        if (startContainer === textNode && startOffset > 0) {
          rng.setStart(textNode, startOffset - 1);
        }
        if (endContainer === textNode && endOffset > 0) {
          rng.setEnd(textNode, endOffset - 1);
        }
        if (block && dom2.isEmpty(block)) {
          fillWithPaddingBr(SugarElement.fromDom(block));
        }
        selection.setRng(rng);
      }
    };
    const removeCaretContainer = (editor, node, moveCaret2 = true) => {
      const dom2 = editor.dom, selection = editor.selection;
      if (!node) {
        node = getParentCaretContainer(editor.getBody(), selection.getStart());
        if (!node) {
          while (node = dom2.get(CARET_ID)) {
            removeCaretContainerNode(editor, node, false);
          }
        }
      } else {
        removeCaretContainerNode(editor, node, moveCaret2);
      }
    };
    const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
      const dom2 = editor.dom, block = dom2.getParent(formatNode, curry(isTextBlock$1, editor));
      if (block && dom2.isEmpty(block)) {
        formatNode.parentNode.replaceChild(caretContainer, formatNode);
      } else {
        removeTrailingBr(SugarElement.fromDom(formatNode));
        if (dom2.isEmpty(formatNode)) {
          formatNode.parentNode.replaceChild(caretContainer, formatNode);
        } else {
          dom2.insertAfter(caretContainer, formatNode);
        }
      }
    };
    const appendNode = (parentNode, node) => {
      parentNode.appendChild(node);
      return node;
    };
    const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
      const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
        return appendNode(parentNode, formatNode.cloneNode(false));
      }, caretContainer);
      return appendNode(innerMostFormatNode, innerMostFormatNode.ownerDocument.createTextNode(ZWSP));
    };
    const cleanFormatNode = (editor, caretContainer, formatNode, name2, vars, similar) => {
      const formatter = editor.formatter;
      const dom2 = editor.dom;
      const validFormats = filter$6(keys(formatter.get()), (formatName) => formatName !== name2 && !contains$1(formatName, "removeformat"));
      const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
      const uniqueFormats = filter$6(matchedFormats, (fmtName) => !areSimilarFormats(editor, fmtName, name2));
      if (uniqueFormats.length > 0) {
        const clonedFormatNode = formatNode.cloneNode(false);
        dom2.add(caretContainer, clonedFormatNode);
        formatter.remove(name2, vars, clonedFormatNode, similar);
        dom2.remove(clonedFormatNode);
        return Optional.some(clonedFormatNode);
      } else {
        return Optional.none();
      }
    };
    const applyCaretFormat = (editor, name2, vars) => {
      let caretContainer, textNode;
      const selection = editor.selection;
      const selectionRng = selection.getRng();
      let offset = selectionRng.startOffset;
      const container = selectionRng.startContainer;
      const text2 = container.nodeValue;
      caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
      if (caretContainer) {
        textNode = findFirstTextNode(caretContainer);
      }
      const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
      if (text2 && offset > 0 && offset < text2.length && wordcharRegex.test(text2.charAt(offset)) && wordcharRegex.test(text2.charAt(offset - 1))) {
        const bookmark = selection.getBookmark();
        selectionRng.collapse(true);
        let rng = expandRng(editor, selectionRng, editor.formatter.get(name2));
        rng = split(rng);
        editor.formatter.apply(name2, vars, rng);
        selection.moveToBookmark(bookmark);
      } else {
        if (!caretContainer || textNode.nodeValue !== ZWSP) {
          caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
          textNode = caretContainer.firstChild;
          selectionRng.insertNode(caretContainer);
          offset = 1;
          editor.formatter.apply(name2, vars, caretContainer);
        } else {
          editor.formatter.apply(name2, vars, caretContainer);
        }
        selection.setCursorLocation(textNode, offset);
      }
    };
    const removeCaretFormat = (editor, name2, vars, similar) => {
      const dom2 = editor.dom;
      const selection = editor.selection;
      let hasContentAfter, node, formatNode;
      const parents2 = [];
      const rng = selection.getRng();
      const container = rng.startContainer;
      const offset = rng.startOffset;
      node = container;
      if (container.nodeType === 3) {
        if (offset !== container.nodeValue.length) {
          hasContentAfter = true;
        }
        node = node.parentNode;
      }
      while (node) {
        if (matchNode(editor, node, name2, vars, similar)) {
          formatNode = node;
          break;
        }
        if (node.nextSibling) {
          hasContentAfter = true;
        }
        parents2.push(node);
        node = node.parentNode;
      }
      if (!formatNode) {
        return;
      }
      if (hasContentAfter) {
        const bookmark = selection.getBookmark();
        rng.collapse(true);
        let expandedRng = expandRng(editor, rng, editor.formatter.get(name2), true);
        expandedRng = split(expandedRng);
        editor.formatter.remove(name2, vars, expandedRng, similar);
        selection.moveToBookmark(bookmark);
      } else {
        const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
        const newCaretContainer = createCaretContainer(false).dom;
        insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null ? caretContainer : formatNode);
        const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name2, vars, similar);
        const caretTextNode = insertFormatNodesIntoCaretContainer(parents2.concat(cleanedFormatNode.toArray()), newCaretContainer);
        removeCaretContainerNode(editor, caretContainer, false);
        selection.setCursorLocation(caretTextNode, 1);
        if (dom2.isEmpty(formatNode)) {
          dom2.remove(formatNode);
        }
      }
    };
    const disableCaretContainer = (editor, keyCode) => {
      const selection = editor.selection, body = editor.getBody();
      removeCaretContainer(editor, null, false);
      if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
      }
      if (keyCode === 37 || keyCode === 39) {
        removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
      }
    };
    const setup$u = (editor) => {
      editor.on("mouseup keydown", (e) => {
        disableCaretContainer(editor, e.keyCode);
      });
    };
    const replaceWithCaretFormat = (targetNode, formatNodes) => {
      const caretContainer = createCaretContainer(false);
      const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
      before$3(SugarElement.fromDom(targetNode), caretContainer);
      remove$6(SugarElement.fromDom(targetNode));
      return CaretPosition(innerMost, 0);
    };
    const isFormatElement = (editor, element) => {
      const inlineElements = editor.schema.getTextInlineElements();
      return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$2(element.dom);
    };
    const isEmptyCaretFormatElement = (element) => {
      return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
    };
    const postProcessHooks = {};
    const filter$2 = filter$4;
    const each$9 = each$d;
    const addPostProcessHook = (name2, hook) => {
      const hooks = postProcessHooks[name2];
      if (!hooks) {
        postProcessHooks[name2] = [];
      }
      postProcessHooks[name2].push(hook);
    };
    const postProcess$1 = (name2, editor) => {
      each$9(postProcessHooks[name2], (hook) => {
        hook(editor);
      });
    };
    addPostProcessHook("pre", (editor) => {
      const rng = editor.selection.getRng();
      let blocks2;
      const hasPreSibling = (pre) => {
        return isPre(pre.previousSibling) && indexOf(blocks2, pre.previousSibling) !== -1;
      };
      const joinPre = (pre1, pre2) => {
        const sPre2 = SugarElement.fromDom(pre2);
        const doc = documentOrOwner(sPre2).dom;
        remove$6(sPre2);
        append(SugarElement.fromDom(pre1), [
          SugarElement.fromTag("br", doc),
          SugarElement.fromTag("br", doc),
          ...children(sPre2)
        ]);
      };
      const isPre = matchNodeNames(["pre"]);
      if (!rng.collapsed) {
        blocks2 = editor.selection.getSelectedBlocks();
        each$9(filter$2(filter$2(blocks2, isPre), hasPreSibling), (pre) => {
          joinPre(pre.previousSibling, pre);
        });
      }
    });
    const each$8 = Tools.each;
    const isElementNode$1 = (node) => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
    const findElementSibling = (node, siblingName) => {
      for (let sibling2 = node; sibling2; sibling2 = sibling2[siblingName]) {
        if (isText$9(sibling2) && isNotEmpty(sibling2.data)) {
          return node;
        }
        if (isElement$6(sibling2) && !isBookmarkNode$1(sibling2)) {
          return sibling2;
        }
      }
      return node;
    };
    const mergeSiblingsNodes = (dom2, prev2, next2) => {
      const elementUtils = ElementUtils(dom2);
      if (prev2 && next2) {
        prev2 = findElementSibling(prev2, "previousSibling");
        next2 = findElementSibling(next2, "nextSibling");
        if (elementUtils.compare(prev2, next2)) {
          for (let sibling2 = prev2.nextSibling; sibling2 && sibling2 !== next2; ) {
            const tmpSibling = sibling2;
            sibling2 = sibling2.nextSibling;
            prev2.appendChild(tmpSibling);
          }
          dom2.remove(next2);
          Tools.each(Tools.grep(next2.childNodes), (node) => {
            prev2.appendChild(node);
          });
          return prev2;
        }
      }
      return next2;
    };
    const mergeSiblings = (dom2, format, vars, node) => {
      if (node && format.merge_siblings !== false) {
        const newNode = mergeSiblingsNodes(dom2, getNonWhiteSpaceSibling(node), node);
        mergeSiblingsNodes(dom2, newNode, getNonWhiteSpaceSibling(newNode, true));
      }
    };
    const clearChildStyles = (dom2, format, node) => {
      if (format.clear_child_styles) {
        const selector = format.links ? "*:not(a)" : "*";
        each$8(dom2.select(selector, node), (node2) => {
          if (isElementNode$1(node2)) {
            each$8(format.styles, (value2, name2) => {
              dom2.setStyle(node2, name2, "");
            });
          }
        });
      }
    };
    const processChildElements = (node, filter2, process2) => {
      each$8(node.childNodes, (node2) => {
        if (isElementNode$1(node2)) {
          if (filter2(node2)) {
            process2(node2);
          }
          if (node2.hasChildNodes()) {
            processChildElements(node2, filter2, process2);
          }
        }
      });
    };
    const unwrapEmptySpan = (dom2, node) => {
      if (node.nodeName === "SPAN" && dom2.getAttribs(node).length === 0) {
        dom2.remove(node, true);
      }
    };
    const hasStyle = (dom2, name2) => (node) => !!(node && getStyle(dom2, node, name2));
    const applyStyle = (dom2, name2, value2) => (node) => {
      dom2.setStyle(node, name2, value2);
      if (node.getAttribute("style") === "") {
        node.removeAttribute("style");
      }
      unwrapEmptySpan(dom2, node);
    };
    const removeResult = Adt.generate([
      { keep: [] },
      { rename: ["name"] },
      { removed: [] }
    ]);
    const MCE_ATTR_RE = /^(src|href|style)$/;
    const each$7 = Tools.each;
    const isEq$2 = isEq$5;
    const isTableCellOrRow = (node) => /^(TR|TH|TD)$/.test(node.nodeName);
    const isChildOfInlineParent = (dom2, node, parent2) => dom2.isChildOf(node, parent2) && node !== parent2 && !dom2.isBlock(parent2);
    const getContainer = (ed, rng, start2) => {
      let container = rng[start2 ? "startContainer" : "endContainer"];
      let offset = rng[start2 ? "startOffset" : "endOffset"];
      if (isElement$6(container)) {
        const lastIdx = container.childNodes.length - 1;
        if (!start2 && offset) {
          offset--;
        }
        container = container.childNodes[offset > lastIdx ? lastIdx : offset];
      }
      if (isText$9(container) && start2 && offset >= container.nodeValue.length) {
        container = new DomTreeWalker(container, ed.getBody()).next() || container;
      }
      if (isText$9(container) && !start2 && offset === 0) {
        container = new DomTreeWalker(container, ed.getBody()).prev() || container;
      }
      return container;
    };
    const normalizeTableSelection = (node, start2) => {
      const prop = start2 ? "firstChild" : "lastChild";
      if (isTableCellOrRow(node) && node[prop]) {
        const childNode = node[prop];
        if (node.nodeName === "TR") {
          return childNode[prop] || childNode;
        } else {
          return childNode;
        }
      }
      return node;
    };
    const wrap$1 = (dom2, node, name2, attrs) => {
      const wrapper = dom2.create(name2, attrs);
      node.parentNode.insertBefore(wrapper, node);
      wrapper.appendChild(node);
      return wrapper;
    };
    const wrapWithSiblings = (dom2, node, next2, name2, attrs) => {
      const start2 = SugarElement.fromDom(node);
      const wrapper = SugarElement.fromDom(dom2.create(name2, attrs));
      const siblings2 = next2 ? nextSiblings(start2) : prevSiblings(start2);
      append(wrapper, siblings2);
      if (next2) {
        before$3(start2, wrapper);
        prepend(wrapper, start2);
      } else {
        after$4(start2, wrapper);
        append$1(wrapper, start2);
      }
      return wrapper.dom;
    };
    const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === "A";
    const removeNode = (ed, node, format) => {
      const parentNode = node.parentNode;
      let rootBlockElm;
      const dom2 = ed.dom;
      const forcedRootBlock = getForcedRootBlock(ed);
      if (isBlockFormat(format)) {
        if (parentNode === dom2.getRoot()) {
          if (!format.list_block || !isEq$2(node, format.list_block)) {
            each$f(from(node.childNodes), (node2) => {
              if (isValid(ed, forcedRootBlock, node2.nodeName.toLowerCase())) {
                if (!rootBlockElm) {
                  rootBlockElm = wrap$1(dom2, node2, forcedRootBlock);
                  dom2.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
                } else {
                  rootBlockElm.appendChild(node2);
                }
              } else {
                rootBlockElm = null;
              }
            });
          }
        }
      }
      if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
        return;
      }
      dom2.remove(node, true);
    };
    const removeFormatInternal = (ed, format, vars, node, compareNode) => {
      let stylesModified;
      const dom2 = ed.dom;
      if (!matchName(dom2, node, format) && !isColorFormatAndAnchor(node, format)) {
        return removeResult.keep();
      }
      const elm = node;
      if (isInlineFormat(format) && format.remove === "all" && isArray$1(format.preserve_attributes)) {
        const attrsToPreserve = filter$6(dom2.getAttribs(elm), (attr) => contains$2(format.preserve_attributes, attr.name.toLowerCase()));
        dom2.removeAllAttribs(elm);
        each$f(attrsToPreserve, (attr) => dom2.setAttrib(elm, attr.name, attr.value));
        if (attrsToPreserve.length > 0) {
          return removeResult.rename("span");
        }
      }
      if (format.remove !== "all") {
        each$7(format.styles, (value2, name2) => {
          value2 = normalizeStyleValue(replaceVars(value2, vars), name2 + "");
          if (isNumber(name2)) {
            name2 = value2;
            compareNode = null;
          }
          if (format.remove_similar || (!compareNode || isEq$2(getStyle(dom2, compareNode, name2), value2))) {
            dom2.setStyle(elm, name2, "");
          }
          stylesModified = true;
        });
        if (stylesModified && dom2.getAttrib(elm, "style") === "") {
          elm.removeAttribute("style");
          elm.removeAttribute("data-mce-style");
        }
        each$7(format.attributes, (value2, name2) => {
          let valueOut;
          value2 = replaceVars(value2, vars);
          if (isNumber(name2)) {
            name2 = value2;
            compareNode = null;
          }
          if (format.remove_similar || (!compareNode || isEq$2(dom2.getAttrib(compareNode, name2), value2))) {
            if (name2 === "class") {
              value2 = dom2.getAttrib(elm, name2);
              if (value2) {
                valueOut = "";
                each$f(value2.split(/\s+/), (cls) => {
                  if (/mce\-\w+/.test(cls)) {
                    valueOut += (valueOut ? " " : "") + cls;
                  }
                });
                if (valueOut) {
                  dom2.setAttrib(elm, name2, valueOut);
                  return;
                }
              }
            }
            if (MCE_ATTR_RE.test(name2)) {
              elm.removeAttribute("data-mce-" + name2);
            }
            if (name2 === "style" && matchNodeNames(["li"])(elm) && dom2.getStyle(elm, "list-style-type") === "none") {
              elm.removeAttribute(name2);
              dom2.setStyle(elm, "list-style-type", "none");
              return;
            }
            if (name2 === "class") {
              elm.removeAttribute("className");
            }
            elm.removeAttribute(name2);
          }
        });
        each$7(format.classes, (value2) => {
          value2 = replaceVars(value2, vars);
          if (!compareNode || dom2.hasClass(compareNode, value2)) {
            dom2.removeClass(elm, value2);
          }
        });
        const attrs = dom2.getAttribs(elm);
        for (let i = 0; i < attrs.length; i++) {
          const attrName = attrs[i].nodeName;
          if (attrName.indexOf("_") !== 0 && attrName.indexOf("data-") !== 0) {
            return removeResult.keep();
          }
        }
      }
      if (format.remove !== "none") {
        removeNode(ed, elm, format);
        return removeResult.removed();
      }
      return removeResult.keep();
    };
    const removeFormat$1 = (ed, format, vars, node, compareNode) => removeFormatInternal(ed, format, vars, node, compareNode).fold(never, (newName) => {
      ed.dom.rename(node, newName);
      return true;
    }, always);
    const findFormatRoot = (editor, container, name2, vars, similar) => {
      let formatRoot;
      each$f(getParents$2(editor.dom, container.parentNode).reverse(), (parent2) => {
        if (!formatRoot && parent2.id !== "_start" && parent2.id !== "_end") {
          const format = matchNode(editor, parent2, name2, vars, similar);
          if (format && format.split !== false) {
            formatRoot = parent2;
          }
        }
      });
      return formatRoot;
    };
    const removeFormatFromClone = (editor, format, vars, clone2) => removeFormatInternal(editor, format, vars, clone2, clone2).fold(constant(clone2), (newName) => {
      const fragment = editor.dom.createFragment();
      fragment.appendChild(clone2);
      return editor.dom.rename(clone2, newName);
    }, constant(null));
    const wrapAndSplit = (editor, formatList, formatRoot, container, target, split2, format, vars) => {
      let clone2, lastClone, firstClone;
      const dom2 = editor.dom;
      if (formatRoot) {
        const formatRootParent = formatRoot.parentNode;
        for (let parent2 = container.parentNode; parent2 && parent2 !== formatRootParent; parent2 = parent2.parentNode) {
          clone2 = dom2.clone(parent2, false);
          for (let i = 0; i < formatList.length; i++) {
            clone2 = removeFormatFromClone(editor, formatList[i], vars, clone2);
            if (clone2 === null) {
              break;
            }
          }
          if (clone2) {
            if (lastClone) {
              clone2.appendChild(lastClone);
            }
            if (!firstClone) {
              firstClone = clone2;
            }
            lastClone = clone2;
          }
        }
        if (split2 && (!format.mixed || !dom2.isBlock(formatRoot))) {
          container = dom2.split(formatRoot, container);
        }
        if (lastClone) {
          target.parentNode.insertBefore(lastClone, target);
          firstClone.appendChild(target);
          if (isInlineFormat(format)) {
            mergeSiblings(dom2, format, vars, lastClone);
          }
        }
      }
      return container;
    };
    const remove$2 = (ed, name2, vars, node, similar) => {
      const formatList = ed.formatter.get(name2);
      const format = formatList[0];
      let contentEditable = true;
      const dom2 = ed.dom;
      const selection = ed.selection;
      const splitToFormatRoot = (container) => {
        const formatRoot = findFormatRoot(ed, container, name2, vars, similar);
        return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
      };
      const isRemoveBookmarkNode = (node2) => isBookmarkNode$1(node2) && isElement$6(node2) && (node2.id === "_start" || node2.id === "_end");
      const removeNodeFormat = (node2) => exists(formatList, (fmt) => removeFormat$1(ed, fmt, vars, node2, node2));
      const process2 = (node2) => {
        let lastContentEditable = true;
        let hasContentEditableState2 = false;
        if (isElement$6(node2) && dom2.getContentEditable(node2)) {
          lastContentEditable = contentEditable;
          contentEditable = dom2.getContentEditable(node2) === "true";
          hasContentEditableState2 = true;
        }
        const children2 = from(node2.childNodes);
        if (contentEditable && !hasContentEditableState2) {
          const removed = removeNodeFormat(node2);
          const currentNodeMatches = removed || exists(formatList, (f) => matchName(dom2, node2, f));
          const parentNode = node2.parentNode;
          if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
            removeNodeFormat(parentNode);
          }
        }
        if (format.deep) {
          if (children2.length) {
            for (let i = 0; i < children2.length; i++) {
              process2(children2[i]);
            }
            if (hasContentEditableState2) {
              contentEditable = lastContentEditable;
            }
          }
        }
        const textDecorations = [
          "underline",
          "line-through",
          "overline"
        ];
        each$f(textDecorations, (decoration) => {
          if (isElement$6(node2) && ed.dom.getStyle(node2, "text-decoration") === decoration && node2.parentNode && getTextDecoration(dom2, node2.parentNode) === decoration) {
            removeFormat$1(ed, {
              deep: false,
              exact: true,
              inline: "span",
              styles: { textDecoration: decoration }
            }, null, node2);
          }
        });
      };
      const unwrap2 = (start2) => {
        const node2 = dom2.get(start2 ? "_start" : "_end");
        let out = node2[start2 ? "firstChild" : "lastChild"];
        if (isRemoveBookmarkNode(out)) {
          out = out[start2 ? "firstChild" : "lastChild"];
        }
        if (isText$9(out) && out.data.length === 0) {
          out = start2 ? node2.previousSibling || node2.nextSibling : node2.nextSibling || node2.previousSibling;
        }
        dom2.remove(node2, true);
        return out;
      };
      const removeRngStyle = (rng) => {
        let startContainer, endContainer;
        let expandedRng = expandRng(ed, rng, formatList, rng.collapsed);
        if (format.split) {
          expandedRng = split(expandedRng);
          startContainer = getContainer(ed, expandedRng, true);
          endContainer = getContainer(ed, expandedRng);
          if (startContainer !== endContainer) {
            startContainer = normalizeTableSelection(startContainer, true);
            endContainer = normalizeTableSelection(endContainer, false);
            if (isChildOfInlineParent(dom2, startContainer, endContainer)) {
              const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
              splitToFormatRoot(wrapWithSiblings(dom2, marker, true, "span", {
                "id": "_start",
                "data-mce-type": "bookmark"
              }));
              unwrap2(true);
              return;
            }
            if (isChildOfInlineParent(dom2, endContainer, startContainer)) {
              const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
              splitToFormatRoot(wrapWithSiblings(dom2, marker, false, "span", {
                "id": "_end",
                "data-mce-type": "bookmark"
              }));
              unwrap2(false);
              return;
            }
            startContainer = wrap$1(dom2, startContainer, "span", {
              "id": "_start",
              "data-mce-type": "bookmark"
            });
            endContainer = wrap$1(dom2, endContainer, "span", {
              "id": "_end",
              "data-mce-type": "bookmark"
            });
            const newRng = dom2.createRng();
            newRng.setStartAfter(startContainer);
            newRng.setEndBefore(endContainer);
            walk$3(dom2, newRng, (nodes) => {
              each$f(nodes, (n) => {
                if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
                  splitToFormatRoot(n);
                }
              });
            });
            splitToFormatRoot(startContainer);
            splitToFormatRoot(endContainer);
            startContainer = unwrap2(true);
            endContainer = unwrap2();
          } else {
            startContainer = endContainer = splitToFormatRoot(startContainer);
          }
          expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
          expandedRng.startOffset = dom2.nodeIndex(startContainer);
          expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
          expandedRng.endOffset = dom2.nodeIndex(endContainer) + 1;
        }
        walk$3(dom2, expandedRng, (nodes) => {
          each$f(nodes, process2);
        });
      };
      if (node) {
        if (isNode(node)) {
          const rng = dom2.createRng();
          rng.setStartBefore(node);
          rng.setEndAfter(node);
          removeRngStyle(rng);
        } else {
          removeRngStyle(node);
        }
        fireFormatRemove(ed, name2, node, vars);
        return;
      }
      if (dom2.getContentEditable(selection.getNode()) === "false") {
        node = selection.getNode();
        for (let i = 0; i < formatList.length; i++) {
          if (formatList[i].ceFalseOverride) {
            if (removeFormat$1(ed, formatList[i], vars, node, node)) {
              break;
            }
          }
        }
        fireFormatRemove(ed, name2, node, vars);
        return;
      }
      if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
        preserve(selection, true, () => {
          runOnRanges(ed, removeRngStyle);
        });
        if (isInlineFormat(format) && match$2(ed, name2, vars, selection.getStart())) {
          moveStart(dom2, selection, selection.getRng());
        }
        ed.nodeChanged();
      } else {
        removeCaretFormat(ed, name2, vars, similar);
      }
      fireFormatRemove(ed, name2, node, vars);
    };
    const each$6 = Tools.each;
    const mergeTextDecorationsAndColor = (dom2, format, vars, node) => {
      const processTextDecorationsAndColor = (n) => {
        if (n.nodeType === 1 && n.parentNode && n.parentNode.nodeType === 1) {
          const textDecoration = getTextDecoration(dom2, n.parentNode);
          if (dom2.getStyle(n, "color") && textDecoration) {
            dom2.setStyle(n, "text-decoration", textDecoration);
          } else if (dom2.getStyle(n, "text-decoration") === textDecoration) {
            dom2.setStyle(n, "text-decoration", null);
          }
        }
      };
      if (format.styles && (format.styles.color || format.styles.textDecoration)) {
        Tools.walk(node, processTextDecorationsAndColor, "childNodes");
        processTextDecorationsAndColor(node);
      }
    };
    const mergeBackgroundColorAndFontSize = (dom2, format, vars, node) => {
      if (format.styles && format.styles.backgroundColor) {
        processChildElements(node, hasStyle(dom2, "fontSize"), applyStyle(dom2, "backgroundColor", replaceVars(format.styles.backgroundColor, vars)));
      }
    };
    const mergeSubSup = (dom2, format, vars, node) => {
      if (isInlineFormat(format) && (format.inline === "sub" || format.inline === "sup")) {
        processChildElements(node, hasStyle(dom2, "fontSize"), applyStyle(dom2, "fontSize", ""));
        dom2.remove(dom2.select(format.inline === "sup" ? "sub" : "sup", node), true);
      }
    };
    const mergeWithChildren = (editor, formatList, vars, node) => {
      each$6(formatList, (format) => {
        if (isInlineFormat(format)) {
          each$6(editor.dom.select(format.inline, node), (child2) => {
            if (!isElementNode$1(child2)) {
              return;
            }
            removeFormat$1(editor, format, vars, child2, format.exact ? child2 : null);
          });
        }
        clearChildStyles(editor.dom, format, node);
      });
    };
    const mergeWithParents = (editor, format, name2, vars, node) => {
      if (matchNode(editor, node.parentNode, name2, vars)) {
        if (removeFormat$1(editor, format, vars, node)) {
          return;
        }
      }
      if (format.merge_with_parents) {
        editor.dom.getParent(node.parentNode, (parent2) => {
          if (matchNode(editor, parent2, name2, vars)) {
            removeFormat$1(editor, format, vars, node);
            return true;
          }
        });
      }
    };
    const each$5 = Tools.each;
    const isElementNode = (node) => {
      return isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
    };
    const canFormatBR = (editor, format, node, parentName) => {
      if (canFormatEmptyLines(editor) && isInlineFormat(format)) {
        const validBRParentElements = getTextRootBlockElements(editor.schema);
        const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), (sibling2) => isCaretNode(sibling2.dom));
        return hasNonNullableKey(validBRParentElements, parentName) && isEmpty$2(SugarElement.fromDom(node.parentNode), false) && !hasCaretNodeSibling;
      } else {
        return false;
      }
    };
    const applyFormat$1 = (ed, name2, vars, node) => {
      const formatList = ed.formatter.get(name2);
      const format = formatList[0];
      const isCollapsed = !node && ed.selection.isCollapsed();
      const dom2 = ed.dom;
      const selection = ed.selection;
      const setElementFormat = (elm, fmt = format) => {
        if (isFunction(fmt.onformat)) {
          fmt.onformat(elm, fmt, vars, node);
        }
        each$5(fmt.styles, (value2, name3) => {
          dom2.setStyle(elm, name3, replaceVars(value2, vars));
        });
        if (fmt.styles) {
          const styleVal = dom2.getAttrib(elm, "style");
          if (styleVal) {
            dom2.setAttrib(elm, "data-mce-style", styleVal);
          }
        }
        each$5(fmt.attributes, (value2, name3) => {
          dom2.setAttrib(elm, name3, replaceVars(value2, vars));
        });
        each$5(fmt.classes, (value2) => {
          value2 = replaceVars(value2, vars);
          if (!dom2.hasClass(elm, value2)) {
            dom2.addClass(elm, value2);
          }
        });
      };
      const applyNodeStyle = (formatList2, node2) => {
        let found = false;
        each$5(formatList2, (format2) => {
          if (!isSelectorFormat(format2)) {
            return false;
          }
          if (isNonNullable(format2.collapsed) && format2.collapsed !== isCollapsed) {
            return;
          }
          if (dom2.is(node2, format2.selector) && !isCaretNode(node2)) {
            setElementFormat(node2, format2);
            found = true;
            return false;
          }
        });
        return found;
      };
      const createWrapElement = (wrapName) => {
        if (isString(wrapName)) {
          const wrapElm = dom2.create(wrapName);
          setElementFormat(wrapElm);
          return wrapElm;
        } else {
          return null;
        }
      };
      const applyRngStyle = (dom3, rng, nodeSpecific) => {
        const newWrappers = [];
        let contentEditable = true;
        const wrapName = format.inline || format.block;
        const wrapElm = createWrapElement(wrapName);
        walk$3(dom3, rng, (nodes) => {
          let currentWrapElm;
          const process2 = (node2) => {
            let hasContentEditableState2 = false;
            let lastContentEditable = contentEditable;
            const nodeName = node2.nodeName.toLowerCase();
            const parentNode = node2.parentNode;
            const parentName = parentNode.nodeName.toLowerCase();
            if (isElement$6(node2) && dom3.getContentEditable(node2)) {
              lastContentEditable = contentEditable;
              contentEditable = dom3.getContentEditable(node2) === "true";
              hasContentEditableState2 = true;
            }
            if (isBr$6(node2) && !canFormatBR(ed, format, node2, parentName)) {
              currentWrapElm = null;
              if (isBlockFormat(format)) {
                dom3.remove(node2);
              }
              return;
            }
            if (isBlockFormat(format) && format.wrapper && matchNode(ed, node2, name2, vars)) {
              currentWrapElm = null;
              return;
            }
            if (contentEditable && !hasContentEditableState2 && isBlockFormat(format) && !format.wrapper && isTextBlock$1(ed, nodeName) && isValid(ed, parentName, wrapName)) {
              const elm = dom3.rename(node2, wrapName);
              setElementFormat(elm);
              newWrappers.push(elm);
              currentWrapElm = null;
              return;
            }
            if (isSelectorFormat(format)) {
              let found = applyNodeStyle(formatList, node2);
              if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
                found = applyNodeStyle(formatList, parentNode);
              }
              if (!isInlineFormat(format) || found) {
                currentWrapElm = null;
                return;
              }
            }
            if (contentEditable && !hasContentEditableState2 && isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName) && !(!nodeSpecific && isText$9(node2) && isZwsp(node2.data)) && !isCaretNode(node2) && (!isInlineFormat(format) || !dom3.isBlock(node2))) {
              if (!currentWrapElm) {
                currentWrapElm = dom3.clone(wrapElm, false);
                node2.parentNode.insertBefore(currentWrapElm, node2);
                newWrappers.push(currentWrapElm);
              }
              currentWrapElm.appendChild(node2);
            } else {
              currentWrapElm = null;
              each$f(from(node2.childNodes), process2);
              if (hasContentEditableState2) {
                contentEditable = lastContentEditable;
              }
              currentWrapElm = null;
            }
          };
          each$f(nodes, process2);
        });
        if (format.links === true) {
          each$f(newWrappers, (node2) => {
            const process2 = (node3) => {
              if (node3.nodeName === "A") {
                setElementFormat(node3, format);
              }
              each$f(from(node3.childNodes), process2);
            };
            process2(node2);
          });
        }
        each$f(newWrappers, (node2) => {
          const getChildCount = (node3) => {
            let count2 = 0;
            each$f(node3.childNodes, (node4) => {
              if (!isEmptyTextNode$1(node4) && !isBookmarkNode$1(node4)) {
                count2++;
              }
            });
            return count2;
          };
          const mergeStyles = (node3) => {
            const childElement = find$2(node3.childNodes, isElementNode).filter((child2) => matchName(dom3, child2, format));
            return childElement.map((child2) => {
              const clone2 = dom3.clone(child2, false);
              setElementFormat(clone2);
              dom3.replace(clone2, node3, true);
              dom3.remove(child2, true);
              return clone2;
            }).getOr(node3);
          };
          const childCount = getChildCount(node2);
          if ((newWrappers.length > 1 || !dom3.isBlock(node2)) && childCount === 0) {
            dom3.remove(node2, true);
            return;
          }
          if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
            if (!format.exact && childCount === 1) {
              node2 = mergeStyles(node2);
            }
            mergeWithChildren(ed, formatList, vars, node2);
            mergeWithParents(ed, format, name2, vars, node2);
            mergeBackgroundColorAndFontSize(dom3, format, vars, node2);
            mergeTextDecorationsAndColor(dom3, format, vars, node2);
            mergeSubSup(dom3, format, vars, node2);
            mergeSiblings(dom3, format, vars, node2);
          }
        });
      };
      if (dom2.getContentEditable(selection.getNode()) === "false") {
        node = selection.getNode();
        for (let i = 0, l = formatList.length; i < l; i++) {
          const formatItem = formatList[i];
          if (formatItem.ceFalseOverride && isSelectorFormat(formatItem) && dom2.is(node, formatItem.selector)) {
            setElementFormat(node, formatItem);
            break;
          }
        }
        fireFormatApply(ed, name2, node, vars);
        return;
      }
      if (format) {
        if (node) {
          if (isNode(node)) {
            if (!applyNodeStyle(formatList, node)) {
              const rng = dom2.createRng();
              rng.setStartBefore(node);
              rng.setEndAfter(node);
              applyRngStyle(dom2, expandRng(ed, rng, formatList), true);
            }
          } else {
            applyRngStyle(dom2, node, true);
          }
        } else {
          if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
            selection.setRng(normalize(selection.getRng()));
            preserve(selection, true, () => {
              runOnRanges(ed, (selectionRng, fake) => {
                const expandedRng = fake ? selectionRng : expandRng(ed, selectionRng, formatList);
                applyRngStyle(dom2, expandedRng, false);
              });
            });
            moveStart(dom2, selection, selection.getRng());
            ed.nodeChanged();
          } else {
            applyCaretFormat(ed, name2, vars);
          }
        }
        postProcess$1(name2, ed);
      }
      fireFormatApply(ed, name2, node, vars);
    };
    const hasVars = (value2) => has$2(value2, "vars");
    const setup$t = (registeredFormatListeners, editor) => {
      registeredFormatListeners.set({});
      editor.on("NodeChange", (e) => {
        updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
      });
      editor.on("FormatApply FormatRemove", (e) => {
        const element = Optional.from(e.node).map((nodeOrRange) => isNode(nodeOrRange) ? nodeOrRange : nodeOrRange.startContainer).bind((node) => isElement$6(node) ? Optional.some(node) : Optional.from(node.parentElement)).getOrThunk(() => fallbackElement(editor));
        updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
      });
    };
    const fallbackElement = (editor) => editor.selection.getStart();
    const matchingNode = (editor, parents2, format, similar, vars) => {
      const isMatchingNode = (node) => {
        const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
        return !isUndefined(matchingFormat);
      };
      const isUnableToMatch = (node) => {
        if (matchesUnInheritedFormatSelector(editor, node, format)) {
          return true;
        } else {
          if (!similar) {
            return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
          } else {
            return false;
          }
        }
      };
      return findUntil$1(parents2, isMatchingNode, isUnableToMatch);
    };
    const getParents = (editor, elm) => {
      const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
      return filter$6(getParents$2(editor.dom, element), (node) => isElement$6(node) && !isBogus$2(node));
    };
    const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
      const parents2 = getParents(editor, elm);
      each$e(registeredCallbacks, (data2, format) => {
        const runIfChanged = (spec) => {
          const match2 = matchingNode(editor, parents2, format, spec.similar, hasVars(spec) ? spec.vars : void 0);
          const isSet = match2.isSome();
          if (spec.state.get() !== isSet) {
            spec.state.set(isSet);
            const node = match2.getOr(elm);
            if (hasVars(spec)) {
              spec.callback(isSet, {
                node,
                format,
                parents: parents2
              });
            } else {
              each$f(spec.callbacks, (callback) => callback(isSet, {
                node,
                format,
                parents: parents2
              }));
            }
          }
        };
        each$f([
          data2.withSimilar,
          data2.withoutSimilar
        ], runIfChanged);
        each$f(data2.withVars, runIfChanged);
      });
    };
    const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
      const formatChangeItems = registeredFormatListeners.get();
      each$f(formats.split(","), (format) => {
        const group = get$a(formatChangeItems, format).getOrThunk(() => {
          const base = {
            withSimilar: {
              state: Cell(false),
              similar: true,
              callbacks: []
            },
            withoutSimilar: {
              state: Cell(false),
              similar: false,
              callbacks: []
            },
            withVars: []
          };
          formatChangeItems[format] = base;
          return base;
        });
        const getCurrent = () => {
          const parents2 = getParents(editor);
          return matchingNode(editor, parents2, format, similar, vars).isSome();
        };
        if (isUndefined(vars)) {
          const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
          toAppendTo.callbacks.push(callback);
          if (toAppendTo.callbacks.length === 1) {
            toAppendTo.state.set(getCurrent());
          }
        } else {
          group.withVars.push({
            state: Cell(getCurrent()),
            similar,
            vars,
            callback
          });
        }
      });
      registeredFormatListeners.set(formatChangeItems);
    };
    const removeListeners = (registeredFormatListeners, formats, callback) => {
      const formatChangeItems = registeredFormatListeners.get();
      each$f(formats.split(","), (format) => get$a(formatChangeItems, format).each((group) => {
        formatChangeItems[format] = {
          withSimilar: {
            ...group.withSimilar,
            callbacks: filter$6(group.withSimilar.callbacks, (cb) => cb !== callback)
          },
          withoutSimilar: {
            ...group.withoutSimilar,
            callbacks: filter$6(group.withoutSimilar.callbacks, (cb) => cb !== callback)
          },
          withVars: filter$6(group.withVars, (item) => item.callback !== callback)
        };
      }));
      registeredFormatListeners.set(formatChangeItems);
    };
    const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
      if (registeredFormatListeners.get() === null) {
        setup$t(registeredFormatListeners, editor);
      }
      addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
      return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
    };
    const toggle = (editor, name2, vars, node) => {
      const fmt = editor.formatter.get(name2);
      if (match$2(editor, name2, vars, node) && (!("toggle" in fmt[0]) || fmt[0].toggle)) {
        remove$2(editor, name2, vars, node);
      } else {
        applyFormat$1(editor, name2, vars, node);
      }
    };
    function _typeof(obj) {
      "@babel/helpers - typeof";
      return _typeof = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(obj2) {
        return typeof obj2;
      } : function(obj2) {
        return obj2 && typeof Symbol == "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
      }, _typeof(obj);
    }
    function _setPrototypeOf(o, p) {
      _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf2(o2, p2) {
        o2.__proto__ = p2;
        return o2;
      };
      return _setPrototypeOf(o, p);
    }
    function _isNativeReflectConstruct() {
      if (typeof Reflect === "undefined" || !Reflect.construct)
        return false;
      if (Reflect.construct.sham)
        return false;
      if (typeof Proxy === "function")
        return true;
      try {
        Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {
        }));
        return true;
      } catch (e) {
        return false;
      }
    }
    function _construct(Parent, args, Class) {
      if (_isNativeReflectConstruct()) {
        _construct = Reflect.construct;
      } else {
        _construct = function _construct2(Parent2, args2, Class2) {
          var a = [null];
          a.push.apply(a, args2);
          var Constructor = Function.bind.apply(Parent2, a);
          var instance2 = new Constructor();
          if (Class2)
            _setPrototypeOf(instance2, Class2.prototype);
          return instance2;
        };
      }
      return _construct.apply(null, arguments);
    }
    function _toConsumableArray(arr) {
      return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
    }
    function _arrayWithoutHoles(arr) {
      if (Array.isArray(arr))
        return _arrayLikeToArray(arr);
    }
    function _iterableToArray(iter) {
      if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null)
        return Array.from(iter);
    }
    function _unsupportedIterableToArray(o, minLen) {
      if (!o)
        return;
      if (typeof o === "string")
        return _arrayLikeToArray(o, minLen);
      var n = Object.prototype.toString.call(o).slice(8, -1);
      if (n === "Object" && o.constructor)
        n = o.constructor.name;
      if (n === "Map" || n === "Set")
        return Array.from(o);
      if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
        return _arrayLikeToArray(o, minLen);
    }
    function _arrayLikeToArray(arr, len) {
      if (len == null || len > arr.length)
        len = arr.length;
      for (var i = 0, arr2 = new Array(len); i < len; i++)
        arr2[i] = arr[i];
      return arr2;
    }
    function _nonIterableSpread() {
      throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
    }
    var hasOwnProperty = Object.hasOwnProperty, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
    var freeze = Object.freeze, seal = Object.seal, create$8 = Object.create;
    var _ref = typeof Reflect !== "undefined" && Reflect, apply = _ref.apply, construct = _ref.construct;
    if (!apply) {
      apply = function apply2(fun, thisValue, args) {
        return fun.apply(thisValue, args);
      };
    }
    if (!freeze) {
      freeze = function freeze2(x) {
        return x;
      };
    }
    if (!seal) {
      seal = function seal2(x) {
        return x;
      };
    }
    if (!construct) {
      construct = function construct2(Func, args) {
        return _construct(Func, _toConsumableArray(args));
      };
    }
    var arrayForEach = unapply(Array.prototype.forEach);
    var arrayPop = unapply(Array.prototype.pop);
    var arrayPush = unapply(Array.prototype.push);
    var stringToLowerCase = unapply(String.prototype.toLowerCase);
    var stringMatch = unapply(String.prototype.match);
    var stringReplace = unapply(String.prototype.replace);
    var stringIndexOf = unapply(String.prototype.indexOf);
    var stringTrim = unapply(String.prototype.trim);
    var regExpTest = unapply(RegExp.prototype.test);
    var typeErrorCreate = unconstruct(TypeError);
    function unapply(func) {
      return function(thisArg) {
        for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          args[_key - 1] = arguments[_key];
        }
        return apply(func, thisArg, args);
      };
    }
    function unconstruct(func) {
      return function() {
        for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
          args[_key2] = arguments[_key2];
        }
        return construct(func, args);
      };
    }
    function addToSet(set2, array) {
      if (setPrototypeOf) {
        setPrototypeOf(set2, null);
      }
      var l = array.length;
      while (l--) {
        var element = array[l];
        if (typeof element === "string") {
          var lcElement = stringToLowerCase(element);
          if (lcElement !== element) {
            if (!isFrozen(array)) {
              array[l] = lcElement;
            }
            element = lcElement;
          }
        }
        set2[element] = true;
      }
      return set2;
    }
    function clone(object) {
      var newObject = create$8(null);
      var property;
      for (property in object) {
        if (apply(hasOwnProperty, object, [property])) {
          newObject[property] = object[property];
        }
      }
      return newObject;
    }
    function lookupGetter(object, prop) {
      while (object !== null) {
        var desc = getOwnPropertyDescriptor(object, prop);
        if (desc) {
          if (desc.get) {
            return unapply(desc.get);
          }
          if (typeof desc.value === "function") {
            return unapply(desc.value);
          }
        }
        object = getPrototypeOf(object);
      }
      function fallbackValue(element) {
        console.warn("fallback value for", element);
        return null;
      }
      return fallbackValue;
    }
    var html$1 = freeze([
      "a",
      "abbr",
      "acronym",
      "address",
      "area",
      "article",
      "aside",
      "audio",
      "b",
      "bdi",
      "bdo",
      "big",
      "blink",
      "blockquote",
      "body",
      "br",
      "button",
      "canvas",
      "caption",
      "center",
      "cite",
      "code",
      "col",
      "colgroup",
      "content",
      "data",
      "datalist",
      "dd",
      "decorator",
      "del",
      "details",
      "dfn",
      "dialog",
      "dir",
      "div",
      "dl",
      "dt",
      "element",
      "em",
      "fieldset",
      "figcaption",
      "figure",
      "font",
      "footer",
      "form",
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6",
      "head",
      "header",
      "hgroup",
      "hr",
      "html",
      "i",
      "img",
      "input",
      "ins",
      "kbd",
      "label",
      "legend",
      "li",
      "main",
      "map",
      "mark",
      "marquee",
      "menu",
      "menuitem",
      "meter",
      "nav",
      "nobr",
      "ol",
      "optgroup",
      "option",
      "output",
      "p",
      "picture",
      "pre",
      "progress",
      "q",
      "rp",
      "rt",
      "ruby",
      "s",
      "samp",
      "section",
      "select",
      "shadow",
      "small",
      "source",
      "spacer",
      "span",
      "strike",
      "strong",
      "style",
      "sub",
      "summary",
      "sup",
      "table",
      "tbody",
      "td",
      "template",
      "textarea",
      "tfoot",
      "th",
      "thead",
      "time",
      "tr",
      "track",
      "tt",
      "u",
      "ul",
      "var",
      "video",
      "wbr"
    ]);
    var svg$1 = freeze([
      "svg",
      "a",
      "altglyph",
      "altglyphdef",
      "altglyphitem",
      "animatecolor",
      "animatemotion",
      "animatetransform",
      "circle",
      "clippath",
      "defs",
      "desc",
      "ellipse",
      "filter",
      "font",
      "g",
      "glyph",
      "glyphref",
      "hkern",
      "image",
      "line",
      "lineargradient",
      "marker",
      "mask",
      "metadata",
      "mpath",
      "path",
      "pattern",
      "polygon",
      "polyline",
      "radialgradient",
      "rect",
      "stop",
      "style",
      "switch",
      "symbol",
      "text",
      "textpath",
      "title",
      "tref",
      "tspan",
      "view",
      "vkern"
    ]);
    var svgFilters = freeze([
      "feBlend",
      "feColorMatrix",
      "feComponentTransfer",
      "feComposite",
      "feConvolveMatrix",
      "feDiffuseLighting",
      "feDisplacementMap",
      "feDistantLight",
      "feFlood",
      "feFuncA",
      "feFuncB",
      "feFuncG",
      "feFuncR",
      "feGaussianBlur",
      "feImage",
      "feMerge",
      "feMergeNode",
      "feMorphology",
      "feOffset",
      "fePointLight",
      "feSpecularLighting",
      "feSpotLight",
      "feTile",
      "feTurbulence"
    ]);
    var svgDisallowed = freeze([
      "animate",
      "color-profile",
      "cursor",
      "discard",
      "fedropshadow",
      "font-face",
      "font-face-format",
      "font-face-name",
      "font-face-src",
      "font-face-uri",
      "foreignobject",
      "hatch",
      "hatchpath",
      "mesh",
      "meshgradient",
      "meshpatch",
      "meshrow",
      "missing-glyph",
      "script",
      "set",
      "solidcolor",
      "unknown",
      "use"
    ]);
    var mathMl$1 = freeze([
      "math",
      "menclose",
      "merror",
      "mfenced",
      "mfrac",
      "mglyph",
      "mi",
      "mlabeledtr",
      "mmultiscripts",
      "mn",
      "mo",
      "mover",
      "mpadded",
      "mphantom",
      "mroot",
      "mrow",
      "ms",
      "mspace",
      "msqrt",
      "mstyle",
      "msub",
      "msup",
      "msubsup",
      "mtable",
      "mtd",
      "mtext",
      "mtr",
      "munder",
      "munderover"
    ]);
    var mathMlDisallowed = freeze([
      "maction",
      "maligngroup",
      "malignmark",
      "mlongdiv",
      "mscarries",
      "mscarry",
      "msgroup",
      "mstack",
      "msline",
      "msrow",
      "semantics",
      "annotation",
      "annotation-xml",
      "mprescripts",
      "none"
    ]);
    var text = freeze(["#text"]);
    var html = freeze([
      "accept",
      "action",
      "align",
      "alt",
      "autocapitalize",
      "autocomplete",
      "autopictureinpicture",
      "autoplay",
      "background",
      "bgcolor",
      "border",
      "capture",
      "cellpadding",
      "cellspacing",
      "checked",
      "cite",
      "class",
      "clear",
      "color",
      "cols",
      "colspan",
      "controls",
      "controlslist",
      "coords",
      "crossorigin",
      "datetime",
      "decoding",
      "default",
      "dir",
      "disabled",
      "disablepictureinpicture",
      "disableremoteplayback",
      "download",
      "draggable",
      "enctype",
      "enterkeyhint",
      "face",
      "for",
      "headers",
      "height",
      "hidden",
      "high",
      "href",
      "hreflang",
      "id",
      "inputmode",
      "integrity",
      "ismap",
      "kind",
      "label",
      "lang",
      "list",
      "loading",
      "loop",
      "low",
      "max",
      "maxlength",
      "media",
      "method",
      "min",
      "minlength",
      "multiple",
      "muted",
      "name",
      "nonce",
      "noshade",
      "novalidate",
      "nowrap",
      "open",
      "optimum",
      "pattern",
      "placeholder",
      "playsinline",
      "poster",
      "preload",
      "pubdate",
      "radiogroup",
      "readonly",
      "rel",
      "required",
      "rev",
      "reversed",
      "role",
      "rows",
      "rowspan",
      "spellcheck",
      "scope",
      "selected",
      "shape",
      "size",
      "sizes",
      "span",
      "srclang",
      "start",
      "src",
      "srcset",
      "step",
      "style",
      "summary",
      "tabindex",
      "title",
      "translate",
      "type",
      "usemap",
      "valign",
      "value",
      "width",
      "xmlns",
      "slot"
    ]);
    var svg = freeze([
      "accent-height",
      "accumulate",
      "additive",
      "alignment-baseline",
      "ascent",
      "attributename",
      "attributetype",
      "azimuth",
      "basefrequency",
      "baseline-shift",
      "begin",
      "bias",
      "by",
      "class",
      "clip",
      "clippathunits",
      "clip-path",
      "clip-rule",
      "color",
      "color-interpolation",
      "color-interpolation-filters",
      "color-profile",
      "color-rendering",
      "cx",
      "cy",
      "d",
      "dx",
      "dy",
      "diffuseconstant",
      "direction",
      "display",
      "divisor",
      "dur",
      "edgemode",
      "elevation",
      "end",
      "fill",
      "fill-opacity",
      "fill-rule",
      "filter",
      "filterunits",
      "flood-color",
      "flood-opacity",
      "font-family",
      "font-size",
      "font-size-adjust",
      "font-stretch",
      "font-style",
      "font-variant",
      "font-weight",
      "fx",
      "fy",
      "g1",
      "g2",
      "glyph-name",
      "glyphref",
      "gradientunits",
      "gradienttransform",
      "height",
      "href",
      "id",
      "image-rendering",
      "in",
      "in2",
      "k",
      "k1",
      "k2",
      "k3",
      "k4",
      "kerning",
      "keypoints",
      "keysplines",
      "keytimes",
      "lang",
      "lengthadjust",
      "letter-spacing",
      "kernelmatrix",
      "kernelunitlength",
      "lighting-color",
      "local",
      "marker-end",
      "marker-mid",
      "marker-start",
      "markerheight",
      "markerunits",
      "markerwidth",
      "maskcontentunits",
      "maskunits",
      "max",
      "mask",
      "media",
      "method",
      "mode",
      "min",
      "name",
      "numoctaves",
      "offset",
      "operator",
      "opacity",
      "order",
      "orient",
      "orientation",
      "origin",
      "overflow",
      "paint-order",
      "path",
      "pathlength",
      "patterncontentunits",
      "patterntransform",
      "patternunits",
      "points",
      "preservealpha",
      "preserveaspectratio",
      "primitiveunits",
      "r",
      "rx",
      "ry",
      "radius",
      "refx",
      "refy",
      "repeatcount",
      "repeatdur",
      "restart",
      "result",
      "rotate",
      "scale",
      "seed",
      "shape-rendering",
      "specularconstant",
      "specularexponent",
      "spreadmethod",
      "startoffset",
      "stddeviation",
      "stitchtiles",
      "stop-color",
      "stop-opacity",
      "stroke-dasharray",
      "stroke-dashoffset",
      "stroke-linecap",
      "stroke-linejoin",
      "stroke-miterlimit",
      "stroke-opacity",
      "stroke",
      "stroke-width",
      "style",
      "surfacescale",
      "systemlanguage",
      "tabindex",
      "targetx",
      "targety",
      "transform",
      "transform-origin",
      "text-anchor",
      "text-decoration",
      "text-rendering",
      "textlength",
      "type",
      "u1",
      "u2",
      "unicode",
      "values",
      "viewbox",
      "visibility",
      "version",
      "vert-adv-y",
      "vert-origin-x",
      "vert-origin-y",
      "width",
      "word-spacing",
      "wrap",
      "writing-mode",
      "xchannelselector",
      "ychannelselector",
      "x",
      "x1",
      "x2",
      "xmlns",
      "y",
      "y1",
      "y2",
      "z",
      "zoomandpan"
    ]);
    var mathMl = freeze([
      "accent",
      "accentunder",
      "align",
      "bevelled",
      "close",
      "columnsalign",
      "columnlines",
      "columnspan",
      "denomalign",
      "depth",
      "dir",
      "display",
      "displaystyle",
      "encoding",
      "fence",
      "frame",
      "height",
      "href",
      "id",
      "largeop",
      "length",
      "linethickness",
      "lspace",
      "lquote",
      "mathbackground",
      "mathcolor",
      "mathsize",
      "mathvariant",
      "maxsize",
      "minsize",
      "movablelimits",
      "notation",
      "numalign",
      "open",
      "rowalign",
      "rowlines",
      "rowspacing",
      "rowspan",
      "rspace",
      "rquote",
      "scriptlevel",
      "scriptminsize",
      "scriptsizemultiplier",
      "selection",
      "separator",
      "separators",
      "stretchy",
      "subscriptshift",
      "supscriptshift",
      "symmetric",
      "voffset",
      "width",
      "xmlns"
    ]);
    var xml = freeze([
      "xlink:href",
      "xml:id",
      "xlink:title",
      "xml:space",
      "xmlns:xlink"
    ]);
    var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
    var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
    var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
    var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
    var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
    var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
    var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
    var DOCTYPE_NAME = seal(/^html$/i);
    var getGlobal2 = function getGlobal3() {
      return typeof window === "undefined" ? null : window;
    };
    var _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTypes, document2) {
      if (_typeof(trustedTypes) !== "object" || typeof trustedTypes.createPolicy !== "function") {
        return null;
      }
      var suffix = null;
      var ATTR_NAME = "data-tt-policy-suffix";
      if (document2.currentScript && document2.currentScript.hasAttribute(ATTR_NAME)) {
        suffix = document2.currentScript.getAttribute(ATTR_NAME);
      }
      var policyName = "dompurify" + (suffix ? "#" + suffix : "");
      try {
        return trustedTypes.createPolicy(policyName, {
          createHTML: function createHTML(html2) {
            return html2;
          }
        });
      } catch (_) {
        console.warn("TrustedTypes policy " + policyName + " could not be created.");
        return null;
      }
    };
    function createDOMPurify() {
      var window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal2();
      var DOMPurify = function DOMPurify2(root) {
        return createDOMPurify(root);
      };
      DOMPurify.version = "2.3.8";
      DOMPurify.removed = [];
      if (!window2 || !window2.document || window2.document.nodeType !== 9) {
        DOMPurify.isSupported = false;
        return DOMPurify;
      }
      var originalDocument = window2.document;
      var document2 = window2.document;
      var DocumentFragment = window2.DocumentFragment, HTMLTemplateElement = window2.HTMLTemplateElement, Node2 = window2.Node, Element2 = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window2.HTMLFormElement, DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes;
      var ElementPrototype = Element2.prototype;
      var cloneNode = lookupGetter(ElementPrototype, "cloneNode");
      var getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
      var getChildNodes2 = lookupGetter(ElementPrototype, "childNodes");
      var getParentNode = lookupGetter(ElementPrototype, "parentNode");
      if (typeof HTMLTemplateElement === "function") {
        var template = document2.createElement("template");
        if (template.content && template.content.ownerDocument) {
          document2 = template.content.ownerDocument;
        }
      }
      var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
      var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML("") : "";
      var _document = document2, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
      var importNode2 = originalDocument.importNode;
      var documentMode = {};
      try {
        documentMode = clone(document2).documentMode ? document2.documentMode : {};
      } catch (_) {
      }
      var hooks = {};
      DOMPurify.isSupported = typeof getParentNode === "function" && implementation && typeof implementation.createHTMLDocument !== "undefined" && documentMode !== 9;
      var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE;
      var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
      var ALLOWED_TAGS = null;
      var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
      var ALLOWED_ATTR = null;
      var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
      var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
        tagNameCheck: {
          writable: true,
          configurable: false,
          enumerable: true,
          value: null
        },
        attributeNameCheck: {
          writable: true,
          configurable: false,
          enumerable: true,
          value: null
        },
        allowCustomizedBuiltInElements: {
          writable: true,
          configurable: false,
          enumerable: true,
          value: false
        }
      }));
      var FORBID_TAGS = null;
      var FORBID_ATTR = null;
      var ALLOW_ARIA_ATTR = true;
      var ALLOW_DATA_ATTR = true;
      var ALLOW_UNKNOWN_PROTOCOLS = false;
      var SAFE_FOR_TEMPLATES = false;
      var WHOLE_DOCUMENT = false;
      var SET_CONFIG = false;
      var FORCE_BODY = false;
      var RETURN_DOM = false;
      var RETURN_DOM_FRAGMENT = false;
      var RETURN_TRUSTED_TYPE = false;
      var SANITIZE_DOM = true;
      var KEEP_CONTENT = true;
      var IN_PLACE = false;
      var USE_PROFILES = {};
      var FORBID_CONTENTS = null;
      var DEFAULT_FORBID_CONTENTS = addToSet({}, [
        "annotation-xml",
        "audio",
        "colgroup",
        "desc",
        "foreignobject",
        "head",
        "iframe",
        "math",
        "mi",
        "mn",
        "mo",
        "ms",
        "mtext",
        "noembed",
        "noframes",
        "noscript",
        "plaintext",
        "script",
        "style",
        "svg",
        "template",
        "thead",
        "title",
        "video",
        "xmp"
      ]);
      var DATA_URI_TAGS = null;
      var DEFAULT_DATA_URI_TAGS = addToSet({}, [
        "audio",
        "video",
        "img",
        "source",
        "image",
        "track"
      ]);
      var URI_SAFE_ATTRIBUTES = null;
      var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
        "alt",
        "class",
        "for",
        "id",
        "label",
        "name",
        "pattern",
        "placeholder",
        "role",
        "summary",
        "title",
        "value",
        "style",
        "xmlns"
      ]);
      var MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML";
      var SVG_NAMESPACE = "http://www.w3.org/2000/svg";
      var HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
      var NAMESPACE = HTML_NAMESPACE;
      var IS_EMPTY_INPUT = false;
      var PARSER_MEDIA_TYPE;
      var SUPPORTED_PARSER_MEDIA_TYPES = [
        "application/xhtml+xml",
        "text/html"
      ];
      var DEFAULT_PARSER_MEDIA_TYPE = "text/html";
      var transformCaseFunc;
      var CONFIG = null;
      var formElement = document2.createElement("form");
      var isRegexOrFunction = function isRegexOrFunction2(testValue) {
        return testValue instanceof RegExp || testValue instanceof Function;
      };
      var _parseConfig = function _parseConfig2(cfg) {
        if (CONFIG && CONFIG === cfg) {
          return;
        }
        if (!cfg || _typeof(cfg) !== "object") {
          cfg = {};
        }
        cfg = clone(cfg);
        ALLOWED_TAGS = "ALLOWED_TAGS" in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
        ALLOWED_ATTR = "ALLOWED_ATTR" in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
        URI_SAFE_ATTRIBUTES = "ADD_URI_SAFE_ATTR" in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
        DATA_URI_TAGS = "ADD_DATA_URI_TAGS" in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
        FORBID_CONTENTS = "FORBID_CONTENTS" in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
        FORBID_TAGS = "FORBID_TAGS" in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
        FORBID_ATTR = "FORBID_ATTR" in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
        USE_PROFILES = "USE_PROFILES" in cfg ? cfg.USE_PROFILES : false;
        ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
        ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
        ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
        SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
        WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
        RETURN_DOM = cfg.RETURN_DOM || false;
        RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
        RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
        FORCE_BODY = cfg.FORCE_BODY || false;
        SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
        KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
        IN_PLACE = cfg.IN_PLACE || false;
        IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
        NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
          CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
        }
        if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
          CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
        }
        if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === "boolean") {
          CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
        }
        PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
        transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? function(x) {
          return x;
        } : stringToLowerCase;
        if (SAFE_FOR_TEMPLATES) {
          ALLOW_DATA_ATTR = false;
        }
        if (RETURN_DOM_FRAGMENT) {
          RETURN_DOM = true;
        }
        if (USE_PROFILES) {
          ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
          ALLOWED_ATTR = [];
          if (USE_PROFILES.html === true) {
            addToSet(ALLOWED_TAGS, html$1);
            addToSet(ALLOWED_ATTR, html);
          }
          if (USE_PROFILES.svg === true) {
            addToSet(ALLOWED_TAGS, svg$1);
            addToSet(ALLOWED_ATTR, svg);
            addToSet(ALLOWED_ATTR, xml);
          }
          if (USE_PROFILES.svgFilters === true) {
            addToSet(ALLOWED_TAGS, svgFilters);
            addToSet(ALLOWED_ATTR, svg);
            addToSet(ALLOWED_ATTR, xml);
          }
          if (USE_PROFILES.mathMl === true) {
            addToSet(ALLOWED_TAGS, mathMl$1);
            addToSet(ALLOWED_ATTR, mathMl);
            addToSet(ALLOWED_ATTR, xml);
          }
        }
        if (cfg.ADD_TAGS) {
          if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
            ALLOWED_TAGS = clone(ALLOWED_TAGS);
          }
          addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
        }
        if (cfg.ADD_ATTR) {
          if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
            ALLOWED_ATTR = clone(ALLOWED_ATTR);
          }
          addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
        }
        if (cfg.ADD_URI_SAFE_ATTR) {
          addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
        }
        if (cfg.FORBID_CONTENTS) {
          if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
            FORBID_CONTENTS = clone(FORBID_CONTENTS);
          }
          addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
        }
        if (KEEP_CONTENT) {
          ALLOWED_TAGS["#text"] = true;
        }
        if (WHOLE_DOCUMENT) {
          addToSet(ALLOWED_TAGS, [
            "html",
            "head",
            "body"
          ]);
        }
        if (ALLOWED_TAGS.table) {
          addToSet(ALLOWED_TAGS, ["tbody"]);
          delete FORBID_TAGS.tbody;
        }
        if (freeze) {
          freeze(cfg);
        }
        CONFIG = cfg;
      };
      var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
        "mi",
        "mo",
        "mn",
        "ms",
        "mtext"
      ]);
      var HTML_INTEGRATION_POINTS = addToSet({}, [
        "foreignobject",
        "desc",
        "title",
        "annotation-xml"
      ]);
      var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
        "title",
        "style",
        "font",
        "a",
        "script"
      ]);
      var ALL_SVG_TAGS = addToSet({}, svg$1);
      addToSet(ALL_SVG_TAGS, svgFilters);
      addToSet(ALL_SVG_TAGS, svgDisallowed);
      var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
      addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
      var _checkValidNamespace = function _checkValidNamespace2(element) {
        var parent2 = getParentNode(element);
        if (!parent2 || !parent2.tagName) {
          parent2 = {
            namespaceURI: HTML_NAMESPACE,
            tagName: "template"
          };
        }
        var tagName = stringToLowerCase(element.tagName);
        var parentTagName = stringToLowerCase(parent2.tagName);
        if (element.namespaceURI === SVG_NAMESPACE) {
          if (parent2.namespaceURI === HTML_NAMESPACE) {
            return tagName === "svg";
          }
          if (parent2.namespaceURI === MATHML_NAMESPACE) {
            return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
          }
          return Boolean(ALL_SVG_TAGS[tagName]);
        }
        if (element.namespaceURI === MATHML_NAMESPACE) {
          if (parent2.namespaceURI === HTML_NAMESPACE) {
            return tagName === "math";
          }
          if (parent2.namespaceURI === SVG_NAMESPACE) {
            return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName];
          }
          return Boolean(ALL_MATHML_TAGS[tagName]);
        }
        if (element.namespaceURI === HTML_NAMESPACE) {
          if (parent2.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
            return false;
          }
          if (parent2.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
            return false;
          }
          return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
        }
        return false;
      };
      var _forceRemove = function _forceRemove2(node) {
        arrayPush(DOMPurify.removed, { element: node });
        try {
          node.parentNode.removeChild(node);
        } catch (_) {
          try {
            node.outerHTML = emptyHTML;
          } catch (_2) {
            node.remove();
          }
        }
      };
      var _removeAttribute = function _removeAttribute2(name2, node) {
        try {
          arrayPush(DOMPurify.removed, {
            attribute: node.getAttributeNode(name2),
            from: node
          });
        } catch (_) {
          arrayPush(DOMPurify.removed, {
            attribute: null,
            from: node
          });
        }
        node.removeAttribute(name2);
        if (name2 === "is" && !ALLOWED_ATTR[name2]) {
          if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
            try {
              _forceRemove(node);
            } catch (_) {
            }
          } else {
            try {
              node.setAttribute(name2, "");
            } catch (_) {
            }
          }
        }
      };
      var _initDocument = function _initDocument2(dirty) {
        var doc;
        var leadingWhitespace;
        if (FORCE_BODY) {
          dirty = "<remove></remove>" + dirty;
        } else {
          var matches = stringMatch(dirty, /^[\r\n\t ]+/);
          leadingWhitespace = matches && matches[0];
        }
        if (PARSER_MEDIA_TYPE === "application/xhtml+xml") {
          dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + "</body></html>";
        }
        var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
        if (NAMESPACE === HTML_NAMESPACE) {
          try {
            doc = new DOMParser2().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
          } catch (_) {
          }
        }
        if (!doc || !doc.documentElement) {
          doc = implementation.createDocument(NAMESPACE, "template", null);
          try {
            doc.documentElement.innerHTML = IS_EMPTY_INPUT ? "" : dirtyPayload;
          } catch (_) {
          }
        }
        var body = doc.body || doc.documentElement;
        if (dirty && leadingWhitespace) {
          body.insertBefore(document2.createTextNode(leadingWhitespace), body.childNodes[0] || null);
        }
        if (NAMESPACE === HTML_NAMESPACE) {
          return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0];
        }
        return WHOLE_DOCUMENT ? doc.documentElement : body;
      };
      var _createIterator = function _createIterator2(root) {
        return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
      };
      var _isClobbered = function _isClobbered2(elm) {
        return elm instanceof HTMLFormElement && (typeof elm.nodeName !== "string" || typeof elm.textContent !== "string" || typeof elm.removeChild !== "function" || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== "function" || typeof elm.setAttribute !== "function" || typeof elm.namespaceURI !== "string" || typeof elm.insertBefore !== "function");
      };
      var _isNode = function _isNode2(object) {
        return _typeof(Node2) === "object" ? object instanceof Node2 : object && _typeof(object) === "object" && typeof object.nodeType === "number" && typeof object.nodeName === "string";
      };
      var _executeHook = function _executeHook2(entryPoint, currentNode, data2) {
        if (!hooks[entryPoint]) {
          return;
        }
        arrayForEach(hooks[entryPoint], function(hook) {
          hook.call(DOMPurify, currentNode, data2, CONFIG);
        });
      };
      var _sanitizeElements = function _sanitizeElements2(currentNode) {
        var content;
        _executeHook("beforeSanitizeElements", currentNode, null);
        if (_isClobbered(currentNode)) {
          _forceRemove(currentNode);
          return true;
        }
        if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
          _forceRemove(currentNode);
          return true;
        }
        var tagName = transformCaseFunc(currentNode.nodeName);
        _executeHook("uponSanitizeElement", currentNode, {
          tagName,
          allowedTags: ALLOWED_TAGS
        });
        if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
          _forceRemove(currentNode);
          return true;
        }
        if (tagName === "select" && regExpTest(/<template/i, currentNode.innerHTML)) {
          _forceRemove(currentNode);
          return true;
        }
        if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
          if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
              return false;
            if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
              return false;
          }
          if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
            var parentNode = getParentNode(currentNode) || currentNode.parentNode;
            var childNodes = getChildNodes2(currentNode) || currentNode.childNodes;
            if (childNodes && parentNode) {
              var childCount = childNodes.length;
              for (var i = childCount - 1; i >= 0; --i) {
                parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
              }
            }
          }
          _forceRemove(currentNode);
          return true;
        }
        if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
          _forceRemove(currentNode);
          return true;
        }
        if ((tagName === "noscript" || tagName === "noembed") && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
          _forceRemove(currentNode);
          return true;
        }
        if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
          content = currentNode.textContent;
          content = stringReplace(content, MUSTACHE_EXPR$1, " ");
          content = stringReplace(content, ERB_EXPR$1, " ");
          if (currentNode.textContent !== content) {
            arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
            currentNode.textContent = content;
          }
        }
        _executeHook("afterSanitizeElements", currentNode, null);
        return false;
      };
      var _isValidAttribute = function _isValidAttribute2(lcTag, lcName, value2) {
        if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value2 in document2 || value2 in formElement)) {
          return false;
        }
        if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName))
          ;
        else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName))
          ;
        else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
          if (_basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value2) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value2)))
            ;
          else {
            return false;
          }
        } else if (URI_SAFE_ATTRIBUTES[lcName])
          ;
        else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value2, ATTR_WHITESPACE$1, "")))
          ;
        else if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value2, "data:") === 0 && DATA_URI_TAGS[lcTag])
          ;
        else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value2, ATTR_WHITESPACE$1, "")))
          ;
        else if (!value2)
          ;
        else {
          return false;
        }
        return true;
      };
      var _basicCustomElementTest = function _basicCustomElementTest2(tagName) {
        return tagName.indexOf("-") > 0;
      };
      var _sanitizeAttributes = function _sanitizeAttributes2(currentNode) {
        var attr;
        var value2;
        var lcName;
        var l;
        _executeHook("beforeSanitizeAttributes", currentNode, null);
        var attributes = currentNode.attributes;
        if (!attributes) {
          return;
        }
        var hookEvent = {
          attrName: "",
          attrValue: "",
          keepAttr: true,
          allowedAttributes: ALLOWED_ATTR
        };
        l = attributes.length;
        while (l--) {
          attr = attributes[l];
          var _attr = attr, name2 = _attr.name, namespaceURI = _attr.namespaceURI;
          value2 = name2 === "value" ? attr.value : stringTrim(attr.value);
          lcName = transformCaseFunc(name2);
          var initValue = value2;
          hookEvent.attrName = lcName;
          hookEvent.attrValue = value2;
          hookEvent.keepAttr = true;
          hookEvent.forceKeepAttr = void 0;
          _executeHook("uponSanitizeAttribute", currentNode, hookEvent);
          value2 = hookEvent.attrValue;
          if (hookEvent.forceKeepAttr) {
            continue;
          }
          if (!hookEvent.keepAttr) {
            _removeAttribute(name2, currentNode);
            continue;
          }
          if (regExpTest(/\/>/i, value2)) {
            _removeAttribute(name2, currentNode);
            continue;
          }
          if (SAFE_FOR_TEMPLATES) {
            value2 = stringReplace(value2, MUSTACHE_EXPR$1, " ");
            value2 = stringReplace(value2, ERB_EXPR$1, " ");
          }
          var lcTag = transformCaseFunc(currentNode.nodeName);
          if (!_isValidAttribute(lcTag, lcName, value2)) {
            _removeAttribute(name2, currentNode);
            continue;
          }
          if (value2 !== initValue) {
            try {
              if (namespaceURI) {
                currentNode.setAttributeNS(namespaceURI, name2, value2);
              } else {
                currentNode.setAttribute(name2, value2);
              }
            } catch (_) {
              _removeAttribute(name2, currentNode);
            }
          }
        }
        _executeHook("afterSanitizeAttributes", currentNode, null);
      };
      var _sanitizeShadowDOM = function _sanitizeShadowDOM2(fragment) {
        var shadowNode;
        var shadowIterator = _createIterator(fragment);
        _executeHook("beforeSanitizeShadowDOM", fragment, null);
        while (shadowNode = shadowIterator.nextNode()) {
          _executeHook("uponSanitizeShadowNode", shadowNode, null);
          if (_sanitizeElements(shadowNode)) {
            continue;
          }
          if (shadowNode.content instanceof DocumentFragment) {
            _sanitizeShadowDOM2(shadowNode.content);
          }
          _sanitizeAttributes(shadowNode);
        }
        _executeHook("afterSanitizeShadowDOM", fragment, null);
      };
      DOMPurify.sanitize = function(dirty, cfg) {
        var body;
        var importedNode;
        var currentNode;
        var oldNode;
        var returnNode;
        IS_EMPTY_INPUT = !dirty;
        if (IS_EMPTY_INPUT) {
          dirty = "<!-->";
        }
        if (typeof dirty !== "string" && !_isNode(dirty)) {
          if (typeof dirty.toString !== "function") {
            throw typeErrorCreate("toString is not a function");
          } else {
            dirty = dirty.toString();
            if (typeof dirty !== "string") {
              throw typeErrorCreate("dirty is not a string, aborting");
            }
          }
        }
        if (!DOMPurify.isSupported) {
          if (_typeof(window2.toStaticHTML) === "object" || typeof window2.toStaticHTML === "function") {
            if (typeof dirty === "string") {
              return window2.toStaticHTML(dirty);
            }
            if (_isNode(dirty)) {
              return window2.toStaticHTML(dirty.outerHTML);
            }
          }
          return dirty;
        }
        if (!SET_CONFIG) {
          _parseConfig(cfg);
        }
        DOMPurify.removed = [];
        if (typeof dirty === "string") {
          IN_PLACE = false;
        }
        if (IN_PLACE) {
          if (dirty.nodeName) {
            var tagName = transformCaseFunc(dirty.nodeName);
            if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
              throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place");
            }
          }
        } else if (dirty instanceof Node2) {
          body = _initDocument("<!---->");
          importedNode = body.ownerDocument.importNode(dirty, true);
          if (importedNode.nodeType === 1 && importedNode.nodeName === "BODY") {
            body = importedNode;
          } else if (importedNode.nodeName === "HTML") {
            body = importedNode;
          } else {
            body.appendChild(importedNode);
          }
        } else {
          if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf("<") === -1) {
            return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
          }
          body = _initDocument(dirty);
          if (!body) {
            return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : "";
          }
        }
        if (body && FORCE_BODY) {
          _forceRemove(body.firstChild);
        }
        var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
        while (currentNode = nodeIterator.nextNode()) {
          if (currentNode.nodeType === 3 && currentNode === oldNode) {
            continue;
          }
          if (_sanitizeElements(currentNode)) {
            continue;
          }
          if (currentNode.content instanceof DocumentFragment) {
            _sanitizeShadowDOM(currentNode.content);
          }
          _sanitizeAttributes(currentNode);
          oldNode = currentNode;
        }
        oldNode = null;
        if (IN_PLACE) {
          return dirty;
        }
        if (RETURN_DOM) {
          if (RETURN_DOM_FRAGMENT) {
            returnNode = createDocumentFragment.call(body.ownerDocument);
            while (body.firstChild) {
              returnNode.appendChild(body.firstChild);
            }
          } else {
            returnNode = body;
          }
          if (ALLOWED_ATTR.shadowroot) {
            returnNode = importNode2.call(originalDocument, returnNode, true);
          }
          return returnNode;
        }
        var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
        if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
          serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML;
        }
        if (SAFE_FOR_TEMPLATES) {
          serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, " ");
          serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, " ");
        }
        return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
      };
      DOMPurify.setConfig = function(cfg) {
        _parseConfig(cfg);
        SET_CONFIG = true;
      };
      DOMPurify.clearConfig = function() {
        CONFIG = null;
        SET_CONFIG = false;
      };
      DOMPurify.isValidAttribute = function(tag, attr, value2) {
        if (!CONFIG) {
          _parseConfig({});
        }
        var lcTag = transformCaseFunc(tag);
        var lcName = transformCaseFunc(attr);
        return _isValidAttribute(lcTag, lcName, value2);
      };
      DOMPurify.addHook = function(entryPoint, hookFunction) {
        if (typeof hookFunction !== "function") {
          return;
        }
        hooks[entryPoint] = hooks[entryPoint] || [];
        arrayPush(hooks[entryPoint], hookFunction);
      };
      DOMPurify.removeHook = function(entryPoint) {
        if (hooks[entryPoint]) {
          return arrayPop(hooks[entryPoint]);
        }
      };
      DOMPurify.removeHooks = function(entryPoint) {
        if (hooks[entryPoint]) {
          hooks[entryPoint] = [];
        }
      };
      DOMPurify.removeAllHooks = function() {
        hooks = {};
      };
      return DOMPurify;
    }
    var purify = createDOMPurify();
    const explode$1 = Tools.explode;
    const create$7 = () => {
      const filters = {};
      const addFilter = (name2, callback) => {
        each$f(explode$1(name2), (name3) => {
          if (!has$2(filters, name3)) {
            filters[name3] = {
              name: name3,
              callbacks: []
            };
          }
          filters[name3].callbacks.push(callback);
        });
      };
      const getFilters = () => values(filters);
      const removeFilter = (name2, callback) => {
        each$f(explode$1(name2), (name3) => {
          if (has$2(filters, name3)) {
            if (isNonNullable(callback)) {
              const filter2 = filters[name3];
              const newCallbacks = filter$6(filter2.callbacks, (c) => c !== callback);
              if (newCallbacks.length > 0) {
                filter2.callbacks = newCallbacks;
              } else {
                delete filters[name3];
              }
            } else {
              delete filters[name3];
            }
          }
        });
      };
      return {
        addFilter,
        getFilters,
        removeFilter
      };
    };
    const removeAttrs = (node, names) => {
      each$f(names, (name2) => {
        node.attr(name2, null);
      });
    };
    const addFontToSpansFilter = (domParser, styles, fontSizes) => {
      domParser.addNodeFilter("font", (nodes) => {
        each$f(nodes, (node) => {
          const props = styles.parse(node.attr("style"));
          const color = node.attr("color");
          const face = node.attr("face");
          const size = node.attr("size");
          if (color) {
            props.color = color;
          }
          if (face) {
            props["font-family"] = face;
          }
          if (size) {
            props["font-size"] = fontSizes[parseInt(node.attr("size"), 10) - 1];
          }
          node.name = "span";
          node.attr("style", styles.serialize(props));
          removeAttrs(node, [
            "color",
            "face",
            "size"
          ]);
        });
      });
    };
    const addStrikeFilter = (domParser, schema, styles) => {
      domParser.addNodeFilter("strike", (nodes) => {
        const convertToSTag = schema.type !== "html4";
        each$f(nodes, (node) => {
          if (convertToSTag) {
            node.name = "s";
          } else {
            const props = styles.parse(node.attr("style"));
            props["text-decoration"] = "line-through";
            node.name = "span";
            node.attr("style", styles.serialize(props));
          }
        });
      });
    };
    const addFilters = (domParser, settings, schema) => {
      const styles = Styles();
      if (settings.convert_fonts_to_spans) {
        addFontToSpansFilter(domParser, styles, Tools.explode(settings.font_size_legacy_values));
      }
      addStrikeFilter(domParser, schema, styles);
    };
    const register$5 = (domParser, settings, schema) => {
      if (settings.inline_styles) {
        addFilters(domParser, settings, schema);
      }
    };
    const blobUriToBlob = (url) => fetch(url).then((res) => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject(`Cannot convert ${url} to Blob. Resource might not exist or is inaccessible.`));
    const extractBase64Data = (data2) => {
      const matches = /([a-z0-9+\/=\s]+)/i.exec(data2);
      return matches ? matches[1] : "";
    };
    const parseDataUri = (uri) => {
      const [type2, ...rest] = uri.split(",");
      const data2 = rest.join(",");
      const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type2);
      if (matches) {
        const base64Encoded = matches[2] === ";base64";
        const extractedData = base64Encoded ? extractBase64Data(data2) : decodeURIComponent(data2);
        return Optional.some({
          type: matches[1],
          data: extractedData,
          base64Encoded
        });
      } else {
        return Optional.none();
      }
    };
    const buildBlob = (type2, data2, base64Encoded = true) => {
      let str = data2;
      if (base64Encoded) {
        try {
          str = atob(data2);
        } catch (e) {
          return Optional.none();
        }
      }
      const arr = new Uint8Array(str.length);
      for (let i = 0; i < arr.length; i++) {
        arr[i] = str.charCodeAt(i);
      }
      return Optional.some(new Blob([arr], { type: type2 }));
    };
    const dataUriToBlob = (uri) => {
      return new Promise((resolve2, reject) => {
        parseDataUri(uri).bind(({ type: type2, data: data2, base64Encoded }) => buildBlob(type2, data2, base64Encoded)).fold(() => reject("Invalid data URI"), resolve2);
      });
    };
    const uriToBlob = (url) => {
      if (startsWith(url, "blob:")) {
        return blobUriToBlob(url);
      } else if (startsWith(url, "data:")) {
        return dataUriToBlob(url);
      } else {
        return Promise.reject("Unknown URI format");
      }
    };
    const blobToDataUri = (blob) => {
      return new Promise((resolve2, reject) => {
        const reader = new FileReader();
        reader.onloadend = () => {
          resolve2(reader.result);
        };
        reader.onerror = () => {
          reject(reader.error.message);
        };
        reader.readAsDataURL(blob);
      });
    };
    let count$1 = 0;
    const uniqueId$1 = (prefix) => {
      return (prefix || "blobid") + count$1++;
    };
    const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
      return parseDataUri(dataUri).bind(({ data: data2, type: type2, base64Encoded }) => {
        if (base64Only && !base64Encoded) {
          return Optional.none();
        } else {
          const base64 = base64Encoded ? data2 : btoa(data2);
          return generateBlobInfo(base64, type2);
        }
      });
    };
    const createBlobInfo$1 = (blobCache, blob, base64) => {
      const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
      blobCache.add(blobInfo);
      return blobInfo;
    };
    const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
      return processDataUri(dataUri, base64Only, (base64, type2) => Optional.from(blobCache.getByData(base64, type2)).orThunk(() => buildBlob(type2, base64).map((blob) => createBlobInfo$1(blobCache, blob, base64))));
    };
    const imageToBlobInfo = (blobCache, imageSrc) => {
      const invalidDataUri = () => Promise.reject("Invalid data URI");
      if (startsWith(imageSrc, "blob:")) {
        const blobInfo = blobCache.getByUri(imageSrc);
        if (isNonNullable(blobInfo)) {
          return Promise.resolve(blobInfo);
        } else {
          return uriToBlob(imageSrc).then((blob) => {
            return blobToDataUri(blob).then((dataUri) => {
              return processDataUri(dataUri, false, (base64) => {
                return Optional.some(createBlobInfo$1(blobCache, blob, base64));
              }).getOrThunk(invalidDataUri);
            });
          });
        }
      } else if (startsWith(imageSrc, "data:")) {
        return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, (blobInfo) => Promise.resolve(blobInfo));
      } else {
        return Promise.reject("Unknown image data format");
      }
    };
    const isBogusImage = (img) => isNonNullable(img.attr("data-mce-bogus"));
    const isInternalImageSource = (img) => img.attr("src") === Env.transparentSrc || isNonNullable(img.attr("data-mce-placeholder"));
    const registerBase64ImageFilter = (parser, settings) => {
      const { blob_cache: blobCache } = settings;
      const processImage = (img) => {
        const inputSrc = img.attr("src");
        if (isInternalImageSource(img) || isBogusImage(img)) {
          return;
        }
        dataUriToBlobInfo(blobCache, inputSrc, true).each((blobInfo) => {
          img.attr("src", blobInfo.blobUri());
        });
      };
      if (blobCache) {
        parser.addAttributeFilter("src", (nodes) => each$f(nodes, processImage));
      }
    };
    const register$4 = (parser, settings) => {
      const schema = parser.schema;
      if (settings.remove_trailing_brs) {
        parser.addNodeFilter("br", (nodes, _, args) => {
          const blockElements = Tools.extend({}, schema.getBlockElements());
          const nonEmptyElements = schema.getNonEmptyElements();
          const whitespaceElements = schema.getWhitespaceElements();
          blockElements.body = 1;
          for (let i = 0, l = nodes.length; i < l; i++) {
            let node = nodes[i];
            let parent2 = node.parent;
            if (blockElements[node.parent.name] && node === parent2.lastChild) {
              let prev2 = node.prev;
              while (prev2) {
                const prevName = prev2.name;
                if (prevName !== "span" || prev2.attr("data-mce-type") !== "bookmark") {
                  if (prevName === "br") {
                    node = null;
                  }
                  break;
                }
                prev2 = prev2.prev;
              }
              if (node) {
                node.remove();
                if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent2)) {
                  const elementRule = schema.getElementRule(parent2.name);
                  if (elementRule) {
                    if (elementRule.removeEmpty) {
                      parent2.remove();
                    } else if (elementRule.paddEmpty) {
                      paddEmptyNode(settings, args, blockElements, parent2);
                    }
                  }
                }
              }
            } else {
              let lastParent = node;
              while (parent2 && parent2.firstChild === lastParent && parent2.lastChild === lastParent) {
                lastParent = parent2;
                if (blockElements[parent2.name]) {
                  break;
                }
                parent2 = parent2.parent;
              }
              if (lastParent === parent2) {
                const textNode = new AstNode("#text", 3);
                textNode.value = nbsp;
                node.replace(textNode);
              }
            }
          }
        });
      }
      parser.addAttributeFilter("href", (nodes) => {
        let i = nodes.length;
        const appendRel = (rel) => {
          const parts = rel.split(" ").filter((p) => p.length > 0);
          return parts.concat(["noopener"]).sort().join(" ");
        };
        const addNoOpener = (rel) => {
          const newRel = rel ? Tools.trim(rel) : "";
          if (!/\b(noopener)\b/g.test(newRel)) {
            return appendRel(newRel);
          } else {
            return newRel;
          }
        };
        if (!settings.allow_unsafe_link_target) {
          while (i--) {
            const node = nodes[i];
            if (node.name === "a" && node.attr("target") === "_blank") {
              node.attr("rel", addNoOpener(node.attr("rel")));
            }
          }
        }
      });
      if (!settings.allow_html_in_named_anchor) {
        parser.addAttributeFilter("id,name", (nodes) => {
          let i = nodes.length, sibling2, prevSibling2, parent2, node;
          while (i--) {
            node = nodes[i];
            if (node.name === "a" && node.firstChild && !node.attr("href")) {
              parent2 = node.parent;
              sibling2 = node.lastChild;
              do {
                prevSibling2 = sibling2.prev;
                parent2.insert(sibling2, node);
                sibling2 = prevSibling2;
              } while (sibling2);
            }
          }
        });
      }
      if (settings.fix_list_elements) {
        parser.addNodeFilter("ul,ol", (nodes) => {
          let i = nodes.length, node, parentNode;
          while (i--) {
            node = nodes[i];
            parentNode = node.parent;
            if (parentNode.name === "ul" || parentNode.name === "ol") {
              if (node.prev && node.prev.name === "li") {
                node.prev.append(node);
              } else {
                const li = new AstNode("li", 1);
                li.attr("style", "list-style-type: none");
                node.wrap(li);
              }
            }
          }
        });
      }
      if (settings.validate && schema.getValidClasses()) {
        parser.addAttributeFilter("class", (nodes) => {
          const validClasses = schema.getValidClasses();
          let i = nodes.length;
          while (i--) {
            const node = nodes[i];
            const classList = node.attr("class").split(" ");
            let classValue = "";
            for (let ci = 0; ci < classList.length; ci++) {
              const className = classList[ci];
              let valid = false;
              let validClassesMap = validClasses["*"];
              if (validClassesMap && validClassesMap[className]) {
                valid = true;
              }
              validClassesMap = validClasses[node.name];
              if (!valid && validClassesMap && validClassesMap[className]) {
                valid = true;
              }
              if (valid) {
                if (classValue) {
                  classValue += " ";
                }
                classValue += className;
              }
            }
            if (!classValue.length) {
              classValue = null;
            }
            node.attr("class", classValue);
          }
        });
      }
      registerBase64ImageFilter(parser, settings);
    };
    const each$4 = Tools.each, trim = Tools.trim;
    const queryParts = "source protocol authority userInfo user password host port relative path directory file query anchor".split(" ");
    const DEFAULT_PORTS = {
      ftp: 21,
      http: 80,
      https: 443,
      mailto: 25
    };
    const safeSvgDataUrlElements = [
      "img",
      "video"
    ];
    const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
      if (isNonNullable(allowSvgDataUrls)) {
        return !allowSvgDataUrls;
      } else {
        return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
      }
    };
    const decodeUri = (encodedUri) => {
      try {
        return decodeURIComponent(encodedUri);
      } catch (ex) {
        return unescape(encodedUri);
      }
    };
    const isInvalidUri = (settings, uri, tagName) => {
      const decodedUri = decodeUri(uri);
      if (settings.allow_script_urls) {
        return false;
      } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
        return true;
      } else if (settings.allow_html_data_urls) {
        return false;
      } else if (/^data:image\//i.test(decodedUri)) {
        return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
      } else {
        return /^data:/i.test(decodedUri);
      }
    };
    class URI {
      constructor(url, settings) {
        url = trim(url);
        this.settings = settings || {};
        const baseUri = this.settings.base_uri;
        const self = this;
        if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
          self.source = url;
          return;
        }
        const isProtocolRelative = url.indexOf("//") === 0;
        if (url.indexOf("/") === 0 && !isProtocolRelative) {
          url = (baseUri ? baseUri.protocol || "http" : "http") + "://mce_host" + url;
        }
        if (!/^[\w\-]*:?\/\//.test(url)) {
          const baseUrl = this.settings.base_uri ? this.settings.base_uri.path : new URI(document.location.href).directory;
          if (this.settings.base_uri && this.settings.base_uri.protocol == "") {
            url = "//mce_host" + self.toAbsPath(baseUrl, url);
          } else {
            const match2 = /([^#?]*)([#?]?.*)/.exec(url);
            url = (baseUri && baseUri.protocol || "http") + "://mce_host" + self.toAbsPath(baseUrl, match2[1]) + match2[2];
          }
        }
        url = url.replace(/@@/g, "(mce_at)");
        const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
        each$4(queryParts, (v, i) => {
          let part = urlMatch[i];
          if (part) {
            part = part.replace(/\(mce_at\)/g, "@@");
          }
          self[v] = part;
        });
        if (baseUri) {
          if (!self.protocol) {
            self.protocol = baseUri.protocol;
          }
          if (!self.userInfo) {
            self.userInfo = baseUri.userInfo;
          }
          if (!self.port && self.host === "mce_host") {
            self.port = baseUri.port;
          }
          if (!self.host || self.host === "mce_host") {
            self.host = baseUri.host;
          }
          self.source = "";
        }
        if (isProtocolRelative) {
          self.protocol = "";
        }
      }
      static parseDataUri(uri) {
        let type2;
        const uriComponents = decodeURIComponent(uri).split(",");
        const matches = /data:([^;]+)/.exec(uriComponents[0]);
        if (matches) {
          type2 = matches[1];
        }
        return {
          type: type2,
          data: uriComponents[1]
        };
      }
      static isDomSafe(uri, context2, options = {}) {
        if (options.allow_script_urls) {
          return true;
        } else {
          const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, "");
          return !isInvalidUri(options, decodedUri, context2);
        }
      }
      static getDocumentBaseUrl(loc) {
        let baseUrl;
        if (loc.protocol.indexOf("http") !== 0 && loc.protocol !== "file:") {
          baseUrl = loc.href;
        } else {
          baseUrl = loc.protocol + "//" + loc.host + loc.pathname;
        }
        if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
          baseUrl = baseUrl.replace(/[\?#].*$/, "").replace(/[\/\\][^\/]+$/, "");
          if (!/[\/\\]$/.test(baseUrl)) {
            baseUrl += "/";
          }
        }
        return baseUrl;
      }
      setPath(path) {
        const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
        this.path = pathMatch[0];
        this.directory = pathMatch[1];
        this.file = pathMatch[2];
        this.source = "";
        this.getURI();
      }
      toRelative(uri) {
        let output;
        if (uri === "./") {
          return uri;
        }
        const relativeUri = new URI(uri, { base_uri: this });
        if (relativeUri.host !== "mce_host" && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== "") {
          return relativeUri.getURI();
        }
        const tu = this.getURI(), uu = relativeUri.getURI();
        if (tu === uu || tu.charAt(tu.length - 1) === "/" && tu.substr(0, tu.length - 1) === uu) {
          return tu;
        }
        output = this.toRelPath(this.path, relativeUri.path);
        if (relativeUri.query) {
          output += "?" + relativeUri.query;
        }
        if (relativeUri.anchor) {
          output += "#" + relativeUri.anchor;
        }
        return output;
      }
      toAbsolute(uri, noHost) {
        const absoluteUri = new URI(uri, { base_uri: this });
        return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
      }
      isSameOrigin(uri) {
        if (this.host == uri.host && this.protocol == uri.protocol) {
          if (this.port == uri.port) {
            return true;
          }
          const defaultPort = DEFAULT_PORTS[this.protocol];
          if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
            return true;
          }
        }
        return false;
      }
      toRelPath(base, path) {
        let breakPoint = 0, out = "", i, l;
        const normalizedBase = base.substring(0, base.lastIndexOf("/")).split("/");
        const items = path.split("/");
        if (normalizedBase.length >= items.length) {
          for (i = 0, l = normalizedBase.length; i < l; i++) {
            if (i >= items.length || normalizedBase[i] !== items[i]) {
              breakPoint = i + 1;
              break;
            }
          }
        }
        if (normalizedBase.length < items.length) {
          for (i = 0, l = items.length; i < l; i++) {
            if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
              breakPoint = i + 1;
              break;
            }
          }
        }
        if (breakPoint === 1) {
          return path;
        }
        for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
          out += "../";
        }
        for (i = breakPoint - 1, l = items.length; i < l; i++) {
          if (i !== breakPoint - 1) {
            out += "/" + items[i];
          } else {
            out += items[i];
          }
        }
        return out;
      }
      toAbsPath(base, path) {
        let i, nb = 0, o = [], outPath;
        const tr = /\/$/.test(path) ? "/" : "";
        let normalizedBase = base.split("/");
        const normalizedPath = path.split("/");
        each$4(normalizedBase, (k) => {
          if (k) {
            o.push(k);
          }
        });
        normalizedBase = o;
        for (i = normalizedPath.length - 1, o = []; i >= 0; i--) {
          if (normalizedPath[i].length === 0 || normalizedPath[i] === ".") {
            continue;
          }
          if (normalizedPath[i] === "..") {
            nb++;
            continue;
          }
          if (nb > 0) {
            nb--;
            continue;
          }
          o.push(normalizedPath[i]);
        }
        i = normalizedBase.length - nb;
        if (i <= 0) {
          outPath = reverse(o).join("/");
        } else {
          outPath = normalizedBase.slice(0, i).join("/") + "/" + reverse(o).join("/");
        }
        if (outPath.indexOf("/") !== 0) {
          outPath = "/" + outPath;
        }
        if (tr && outPath.lastIndexOf("/") !== outPath.length - 1) {
          outPath += tr;
        }
        return outPath;
      }
      getURI(noProtoHost = false) {
        let s;
        if (!this.source || noProtoHost) {
          s = "";
          if (!noProtoHost) {
            if (this.protocol) {
              s += this.protocol + "://";
            } else {
              s += "//";
            }
            if (this.userInfo) {
              s += this.userInfo + "@";
            }
            if (this.host) {
              s += this.host;
            }
            if (this.port) {
              s += ":" + this.port;
            }
          }
          if (this.path) {
            s += this.path;
          }
          if (this.query) {
            s += "?" + this.query;
          }
          if (this.anchor) {
            s += "#" + this.anchor;
          }
          this.source = s;
        }
        return this.source;
      }
    }
    const makeMap = Tools.makeMap, extend$1 = Tools.extend;
    const basePurifyConfig = {
      IN_PLACE: true,
      ALLOW_UNKNOWN_PROTOCOLS: true,
      ALLOWED_TAGS: [
        "#comment",
        "#cdata-section",
        "body"
      ],
      ALLOWED_ATTR: []
    };
    const filteredUrlAttrs = Tools.makeMap("src,href,data,background,action,formaction,poster,xlink:href");
    const internalElementAttr = "data-mce-type";
    const getPurifyConfig = (settings, mimeType) => {
      const config = { ...basePurifyConfig };
      config.PARSER_MEDIA_TYPE = mimeType;
      if (settings.allow_script_urls) {
        config.ALLOWED_URI_REGEXP = /.*/;
      } else if (settings.allow_html_data_urls) {
        config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
      }
      return config;
    };
    const setupPurify = (settings, schema) => {
      const purify$1 = purify();
      const validate2 = settings.validate;
      let uid = 0;
      purify$1.addHook("uponSanitizeElement", (ele, evt) => {
        var _a, _b;
        if (ele.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test(ele.nodeValue)) {
          ele.nodeValue = " " + ele.nodeValue;
        }
        const tagName = evt.tagName;
        if (ele.nodeType !== ELEMENT || tagName === "body") {
          return;
        }
        const element = SugarElement.fromDom(ele);
        const isInternalElement = has$1(element, internalElementAttr);
        const bogus = get$9(element, "data-mce-bogus");
        if (!isInternalElement && isString(bogus)) {
          if (bogus === "all") {
            remove$6(element);
          } else {
            unwrap(element);
          }
          return;
        }
        const rule = schema.getElementRule(tagName.toLowerCase());
        if (validate2 && !rule) {
          unwrap(element);
          return;
        } else {
          evt.allowedTags[tagName] = true;
        }
        if (validate2 && !isInternalElement) {
          each$f((_a = rule.attributesForced) !== null && _a !== void 0 ? _a : [], (attr) => {
            set$2(element, attr.name, attr.value === "{$uid}" ? `mce_${uid++}` : attr.value);
          });
          each$f((_b = rule.attributesDefault) !== null && _b !== void 0 ? _b : [], (attr) => {
            if (!has$1(element, attr.name)) {
              set$2(element, attr.name, attr.value === "{$uid}" ? `mce_${uid++}` : attr.value);
            }
          });
          if (rule.attributesRequired && !exists(rule.attributesRequired, (attr) => has$1(element, attr))) {
            unwrap(element);
            return;
          }
          if (rule.removeEmptyAttrs && hasNone(element)) {
            unwrap(element);
            return;
          }
          if (rule.outputName && rule.outputName !== tagName.toLowerCase()) {
            mutate(element, rule.outputName);
          }
        }
      });
      purify$1.addHook("uponSanitizeAttribute", (ele, evt) => {
        const tagName = ele.tagName.toLowerCase();
        const { attrName, attrValue } = evt;
        evt.keepAttr = !validate2 || schema.isValid(tagName, attrName) || startsWith(attrName, "data-") || startsWith(attrName, "aria-");
        if (attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) {
          evt.keepAttr = false;
        }
        if (evt.keepAttr) {
          evt.allowedAttributes[attrName] = true;
          if (attrName in schema.getBoolAttrs()) {
            evt.attrValue = attrName;
          }
          if (settings.allow_svg_data_urls && startsWith(attrValue, "data:image/svg+xml")) {
            evt.forceKeepAttr = true;
          }
        } else if (ele.hasAttribute(internalElementAttr) && (attrName === "id" || attrName === "class" || attrName === "style")) {
          evt.forceKeepAttr = true;
        }
      });
      return purify$1;
    };
    const transferChildren = (parent2, nativeParent, specialElements) => {
      const parentName = parent2.name;
      const isSpecial = parentName in specialElements && parentName !== "title" && parentName !== "textarea";
      const childNodes = nativeParent.childNodes;
      for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
        const nativeChild = childNodes[ni];
        const child2 = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
        if (isElement$6(nativeChild)) {
          const attributes = nativeChild.attributes;
          for (let ai = 0, al = attributes.length; ai < al; ai++) {
            const attr = attributes[ai];
            child2.attr(attr.name, attr.value);
          }
        } else if (isText$9(nativeChild)) {
          child2.value = nativeChild.data;
          if (isSpecial) {
            child2.raw = true;
          }
        } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
          child2.value = nativeChild.data;
        }
        transferChildren(child2, nativeChild, specialElements);
        parent2.append(child2);
      }
    };
    const walkTree = (root, preprocessors, postprocessors) => {
      const traverseOrder = [];
      for (let node = root, lastNode = node; isNonNullable(node); lastNode = node, node = node.walk()) {
        each$f(preprocessors, (preprocess2) => preprocess2(node));
        if (isNullable(node.parent) && node !== root) {
          node = lastNode;
        } else {
          traverseOrder.push(node);
        }
      }
      for (let i = traverseOrder.length - 1; i >= 0; i--) {
        const node = traverseOrder[i];
        each$f(postprocessors, (postprocess) => postprocess(node));
      }
    };
    const whitespaceCleaner = (root, schema, settings, args) => {
      const validate2 = settings.validate;
      const nonEmptyElements = schema.getNonEmptyElements();
      const whitespaceElements = schema.getWhitespaceElements();
      const blockElements = extend$1(makeMap("script,style,head,html,body,title,meta,param"), schema.getBlockElements());
      const textRootBlockElements = getTextRootBlockElements(schema);
      const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
      const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
      const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
      const hasWhitespaceParent = (node) => {
        node = node.parent;
        while (isNonNullable(node)) {
          if (node.name in whitespaceElements) {
            return true;
          } else {
            node = node.parent;
          }
        }
        return false;
      };
      const isTextRootBlockEmpty = (node) => {
        let tempNode = node;
        while (isNonNullable(tempNode)) {
          if (tempNode.name in textRootBlockElements) {
            return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
          } else {
            tempNode = tempNode.parent;
          }
        }
        return false;
      };
      const isAtEdgeOfBlock = (node, start2) => {
        const neighbour = start2 ? node.prev : node.next;
        if (isNonNullable(neighbour)) {
          return false;
        }
        return node.parent.name in blockElements && (node.parent !== root || args.isRootContent);
      };
      const preprocess2 = (node) => {
        if (node.type === 3) {
          if (!hasWhitespaceParent(node)) {
            let text2 = node.value;
            text2 = text2.replace(allWhiteSpaceRegExp, " ");
            if (isLineBreakNode(node.prev, blockElements) || isAtEdgeOfBlock(node, true)) {
              text2 = text2.replace(startWhiteSpaceRegExp, "");
            }
            if (text2.length === 0) {
              node.remove();
            } else {
              node.value = text2;
            }
          }
        }
      };
      const postprocess = (node) => {
        var _a;
        if (node.type === 1) {
          const elementRule = schema.getElementRule(node.name);
          if (validate2 && elementRule) {
            const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
            if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
              paddEmptyNode(settings, args, blockElements, node);
            } else if (elementRule.removeEmpty && isNodeEmpty) {
              if (blockElements[node.name]) {
                node.remove();
              } else {
                node.unwrap();
              }
            } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
              paddEmptyNode(settings, args, blockElements, node);
            }
          }
        } else if (node.type === 3) {
          if (!hasWhitespaceParent(node)) {
            let text2 = node.value;
            if (blockElements[(_a = node.next) === null || _a === void 0 ? void 0 : _a.name] || isAtEdgeOfBlock(node, false)) {
              text2 = text2.replace(endWhiteSpaceRegExp, "");
            }
            if (text2.length === 0) {
              node.remove();
            } else {
              node.value = text2;
            }
          }
        }
      };
      return [
        preprocess2,
        postprocess
      ];
    };
    const getRootBlockName = (settings, args) => {
      var _a;
      const name2 = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
      if (name2 === false) {
        return "";
      } else if (name2 === true) {
        return "p";
      } else {
        return name2;
      }
    };
    const DomParser = (settings = {}, schema = Schema()) => {
      const nodeFilterRegistry = create$7();
      const attributeFilterRegistry = create$7();
      const defaultedSettings = {
        validate: true,
        root_name: "body",
        ...settings
      };
      const parser = new DOMParser();
      const purify2 = setupPurify(defaultedSettings, schema);
      const parseAndSanitizeWithContext = (html2, rootName, format = "html") => {
        const mimeType = format === "xhtml" ? "application/xhtml+xml" : "text/html";
        const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
        const content = isSpecialRoot ? `<${rootName}>${html2}</${rootName}>` : html2;
        const wrappedHtml = format === "xhtml" ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${content}</body></html>` : `<body>${content}</body>`;
        const body = parser.parseFromString(wrappedHtml, mimeType).body;
        purify2.sanitize(body, getPurifyConfig(defaultedSettings, mimeType));
        purify2.removed = [];
        return isSpecialRoot ? body.firstChild : body;
      };
      const addNodeFilter = nodeFilterRegistry.addFilter;
      const getNodeFilters = nodeFilterRegistry.getFilters;
      const removeNodeFilter = nodeFilterRegistry.removeFilter;
      const addAttributeFilter = attributeFilterRegistry.addFilter;
      const getAttributeFilters = attributeFilterRegistry.getFilters;
      const removeAttributeFilter = attributeFilterRegistry.removeFilter;
      const findInvalidChildren = (node, invalidChildren) => {
        const parent2 = node.parent;
        if (parent2 && schema.children[node.name] && !schema.isValidChild(parent2.name, node.name)) {
          invalidChildren.push(node);
        }
      };
      const addRootBlocks2 = (rootNode, rootBlockName) => {
        const blockElements = extend$1(makeMap("script,style,head,html,body,title,meta,param"), schema.getBlockElements());
        const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
        const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
        let node = rootNode.firstChild, rootBlockNode = null;
        const trim2 = (rootBlock) => {
          if (rootBlock) {
            node = rootBlock.firstChild;
            if (node && node.type === 3) {
              node.value = node.value.replace(startWhiteSpaceRegExp, "");
            }
            node = rootBlock.lastChild;
            if (node && node.type === 3) {
              node.value = node.value.replace(endWhiteSpaceRegExp, "");
            }
          }
        };
        if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
          return;
        }
        while (node) {
          const next2 = node.next;
          if (node.type === 3 || node.type === 1 && node.name !== "p" && !blockElements[node.name] && !node.attr(internalElementAttr)) {
            if (!rootBlockNode) {
              rootBlockNode = new AstNode(rootBlockName, 1);
              rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
              rootNode.insert(rootBlockNode, node);
              rootBlockNode.append(node);
            } else {
              rootBlockNode.append(node);
            }
          } else {
            trim2(rootBlockNode);
            rootBlockNode = null;
          }
          node = next2;
        }
        trim2(rootBlockNode);
      };
      const parse = (html2, args = {}) => {
        var _a;
        const validate2 = defaultedSettings.validate;
        const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
        const element = parseAndSanitizeWithContext(html2, rootName, args.format);
        const rootNode = new AstNode(rootName, 11);
        transferChildren(rootNode, element, schema.getSpecialElements());
        const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
        const invalidChildren = [];
        const invalidFinder = validate2 ? (node) => findInvalidChildren(node, invalidChildren) : noop;
        const matches = {
          nodes: {},
          attributes: {}
        };
        const matchFinder = (node) => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
        walkTree(rootNode, [
          whitespacePre,
          matchFinder
        ], [
          whitespacePost,
          invalidFinder
        ]);
        invalidChildren.reverse();
        if (validate2 && invalidChildren.length > 0) {
          if (args.context) {
            const {
              pass: topLevelChildren,
              fail: otherChildren
            } = partition$2(invalidChildren, (child2) => child2.parent === rootNode);
            cleanInvalidNodes(otherChildren, schema, matchFinder);
            args.invalid = topLevelChildren.length > 0;
          } else {
            cleanInvalidNodes(invalidChildren, schema, matchFinder);
          }
        }
        const rootBlockName = getRootBlockName(defaultedSettings, args);
        if (rootBlockName && (rootNode.name === "body" || args.isRootContent)) {
          addRootBlocks2(rootNode, rootBlockName);
        }
        if (!args.invalid) {
          runFilters(matches, args);
        }
        return rootNode;
      };
      const exports = {
        schema,
        addAttributeFilter,
        getAttributeFilters,
        removeAttributeFilter,
        addNodeFilter,
        getNodeFilters,
        removeNodeFilter,
        parse
      };
      register$4(exports, defaultedSettings);
      register$5(exports, defaultedSettings, schema);
      return exports;
    };
    const serializeContent = (content) => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
    const withSerializedContent = (content, fireEvent2) => {
      const serializedContent = serializeContent(content);
      const eventArgs = fireEvent2(serializedContent);
      if (eventArgs.isDefaultPrevented()) {
        return eventArgs;
      } else if (isTreeNode(content)) {
        if (eventArgs.content !== serializedContent) {
          const rootNode = DomParser({
            validate: false,
            forced_root_block: false
          }).parse(eventArgs.content, { context: content.name });
          return {
            ...eventArgs,
            content: rootNode
          };
        } else {
          return {
            ...eventArgs,
            content
          };
        }
      } else {
        return eventArgs;
      }
    };
    const preProcessGetContent = (editor, args) => {
      if (args.no_events) {
        return Result.value(args);
      } else {
        const eventArgs = fireBeforeGetContent(editor, args);
        if (eventArgs.isDefaultPrevented()) {
          return Result.error(fireGetContent(editor, {
            content: "",
            ...eventArgs
          }).content);
        } else {
          return Result.value(eventArgs);
        }
      }
    };
    const postProcessGetContent = (editor, content, args) => {
      if (args.no_events) {
        return content;
      } else {
        const processedEventArgs = withSerializedContent(content, (c) => fireGetContent(editor, {
          ...args,
          content: c
        }));
        return processedEventArgs.content;
      }
    };
    const preProcessSetContent = (editor, args) => {
      if (args.no_events) {
        return Result.value(args);
      } else {
        const processedEventArgs = withSerializedContent(args.content, (content) => fireBeforeSetContent(editor, {
          ...args,
          content
        }));
        if (processedEventArgs.isDefaultPrevented()) {
          fireSetContent(editor, processedEventArgs);
          return Result.error(void 0);
        } else {
          return Result.value(processedEventArgs);
        }
      }
    };
    const postProcessSetContent = (editor, content, args) => {
      if (!args.no_events) {
        fireSetContent(editor, {
          ...args,
          content
        });
      }
    };
    const tableModel = (element, width, rows) => ({
      element,
      width,
      rows
    });
    const tableRow = (element, cells2) => ({
      element,
      cells: cells2
    });
    const cellPosition = (x, y) => ({
      x,
      y
    });
    const getSpan = (td, key) => {
      const value2 = parseInt(get$9(td, key), 10);
      return isNaN(value2) ? 1 : value2;
    };
    const fillout = (table2, x, y, tr, td) => {
      const rowspan = getSpan(td, "rowspan");
      const colspan = getSpan(td, "colspan");
      const rows = table2.rows;
      for (let y2 = y; y2 < y + rowspan; y2++) {
        if (!rows[y2]) {
          rows[y2] = tableRow(deep$1(tr), []);
        }
        for (let x2 = x; x2 < x + colspan; x2++) {
          const cells2 = rows[y2].cells;
          cells2[x2] = y2 === y && x2 === x ? td : shallow$1(td);
        }
      }
    };
    const cellExists = (table2, x, y) => {
      const rows = table2.rows;
      const cells2 = rows[y] ? rows[y].cells : [];
      return !!cells2[x];
    };
    const skipCellsX = (table2, x, y) => {
      while (cellExists(table2, x, y)) {
        x++;
      }
      return x;
    };
    const getWidth = (rows) => {
      return foldl(rows, (acc, row) => {
        return row.cells.length > acc ? row.cells.length : acc;
      }, 0);
    };
    const findElementPos = (table2, element) => {
      const rows = table2.rows;
      for (let y = 0; y < rows.length; y++) {
        const cells2 = rows[y].cells;
        for (let x = 0; x < cells2.length; x++) {
          if (eq(cells2[x], element)) {
            return Optional.some(cellPosition(x, y));
          }
        }
      }
      return Optional.none();
    };
    const extractRows = (table2, sx, sy, ex, ey) => {
      const newRows = [];
      const rows = table2.rows;
      for (let y = sy; y <= ey; y++) {
        const cells2 = rows[y].cells;
        const slice = sx < ex ? cells2.slice(sx, ex + 1) : cells2.slice(ex, sx + 1);
        newRows.push(tableRow(rows[y].element, slice));
      }
      return newRows;
    };
    const subTable = (table2, startPos, endPos) => {
      const sx = startPos.x, sy = startPos.y;
      const ex = endPos.x, ey = endPos.y;
      const newRows = sy < ey ? extractRows(table2, sx, sy, ex, ey) : extractRows(table2, sx, ey, ex, sy);
      return tableModel(table2.element, getWidth(newRows), newRows);
    };
    const createDomTable = (table2, rows) => {
      const tableElement = shallow$1(table2.element);
      const tableBody = SugarElement.fromTag("tbody");
      append(tableBody, rows);
      append$1(tableElement, tableBody);
      return tableElement;
    };
    const modelRowsToDomRows = (table2) => {
      return map$3(table2.rows, (row) => {
        const cells2 = map$3(row.cells, (cell2) => {
          const td = deep$1(cell2);
          remove$b(td, "colspan");
          remove$b(td, "rowspan");
          return td;
        });
        const tr = shallow$1(row.element);
        append(tr, cells2);
        return tr;
      });
    };
    const fromDom = (tableElm) => {
      const table2 = tableModel(shallow$1(tableElm), 0, []);
      each$f(descendants(tableElm, "tr"), (tr, y) => {
        each$f(descendants(tr, "td,th"), (td, x) => {
          fillout(table2, skipCellsX(table2, x, y), y, tr, td);
        });
      });
      return tableModel(table2.element, getWidth(table2.rows), table2.rows);
    };
    const toDom = (table2) => {
      return createDomTable(table2, modelRowsToDomRows(table2));
    };
    const subsection = (table2, startElement, endElement) => {
      return findElementPos(table2, startElement).bind((startPos) => {
        return findElementPos(table2, endElement).map((endPos) => {
          return subTable(table2, startPos, endPos);
        });
      });
    };
    const findParentListContainer = (parents2) => find$2(parents2, (elm) => name(elm) === "ul" || name(elm) === "ol");
    const getFullySelectedListWrappers = (parents2, rng) => find$2(parents2, (elm) => name(elm) === "li" && hasAllContentsSelected(elm, rng)).fold(constant([]), (_li) => findParentListContainer(parents2).map((listCont) => {
      const listElm = SugarElement.fromTag(name(listCont));
      const listStyles = filter$5(getAllRaw(listCont), (_style, name2) => startsWith(name2, "list-style"));
      setAll(listElm, listStyles);
      return [
        SugarElement.fromTag("li"),
        listElm
      ];
    }).getOr([]));
    const wrap = (innerElm, elms) => {
      const wrapped = foldl(elms, (acc, elm) => {
        append$1(elm, acc);
        return elm;
      }, innerElm);
      return elms.length > 0 ? fromElements([wrapped]) : wrapped;
    };
    const directListWrappers = (commonAnchorContainer) => {
      if (isListItem(commonAnchorContainer)) {
        return parent(commonAnchorContainer).filter(isList).fold(constant([]), (listElm) => [
          commonAnchorContainer,
          listElm
        ]);
      } else {
        return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
      }
    };
    const getWrapElements = (rootNode, rng) => {
      const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
      const parents2 = parentsAndSelf(commonAnchorContainer, rootNode);
      const wrapElements = filter$6(parents2, isWrapElement);
      const listWrappers = getFullySelectedListWrappers(parents2, rng);
      const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
      return map$3(allWrappers, shallow$1);
    };
    const emptyFragment = () => fromElements([]);
    const getFragmentFromRange = (rootNode, rng) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
    const getParentTable = (rootElm, cell2) => ancestor$2(cell2, "table", curry(eq, rootElm));
    const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind((tableElm) => {
      const firstCell = selectedTableCells[0];
      const lastCell = selectedTableCells[selectedTableCells.length - 1];
      const fullTableModel = fromDom(tableElm);
      return subsection(fullTableModel, firstCell, lastCell).map((sectionedTableModel) => fromElements([toDom(sectionedTableModel)]));
    }).getOrThunk(emptyFragment);
    const getSelectionFragment = (rootNode, ranges) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0]);
    const read$3 = (rootNode, ranges) => {
      const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
      return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges);
    };
    const isCollapsibleWhitespace = (text2, index2) => index2 >= 0 && index2 < text2.length && isWhiteSpace(text2.charAt(index2));
    const getInnerText = (bin) => {
      return trim$1(bin.innerText);
    };
    const getContextNodeName = (parentBlockOpt) => parentBlockOpt.map((block) => block.nodeName).getOr("div").toLowerCase();
    const getTextContent = (editor) => Optional.from(editor.selection.getRng()).map((rng) => {
      const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
      const body = editor.getBody();
      const contextNodeName = getContextNodeName(parentBlockOpt);
      const bin = editor.dom.add(body, contextNodeName, {
        "data-mce-bogus": "all",
        "style": "overflow: hidden; opacity: 0;"
      }, rng.cloneContents());
      const text2 = getInnerText(bin);
      const nonRenderedText = trim$1(bin.textContent);
      editor.dom.remove(bin);
      if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
        const parentBlock = parentBlockOpt.getOr(body);
        const parentBlockText = getInnerText(parentBlock);
        const textIndex = parentBlockText.indexOf(text2);
        if (textIndex === -1) {
          return text2;
        } else {
          const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
          const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text2.length);
          return (hasProceedingSpace ? " " : "") + text2 + (hasTrailingSpace ? " " : "");
        }
      } else {
        return text2;
      }
    }).getOr("");
    const getSerializedContent = (editor, args) => {
      const rng = editor.selection.getRng(), tmpElm = editor.dom.create("body");
      const sel = editor.selection.getSel();
      const ranges = processRanges(editor, getRanges$1(sel));
      const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges).dom : rng.cloneContents();
      if (fragment) {
        tmpElm.appendChild(fragment);
      }
      return editor.selection.serializer.serialize(tmpElm, args);
    };
    const extractSelectedContent = (editor, args) => {
      if (args.format === "text") {
        return getTextContent(editor);
      } else {
        const content = getSerializedContent(editor, args);
        if (args.format === "tree") {
          return content;
        } else {
          return editor.selection.isCollapsed() ? "" : content;
        }
      }
    };
    const setupArgs$3 = (args, format) => ({
      ...args,
      format,
      get: true,
      selection: true,
      getInner: true
    });
    const getSelectedContentInternal = (editor, format, args = {}) => {
      const defaultedArgs = setupArgs$3(args, format);
      return preProcessGetContent(editor, defaultedArgs).fold(identity, (updatedArgs) => {
        const content = extractSelectedContent(editor, updatedArgs);
        return postProcessGetContent(editor, content, updatedArgs);
      });
    };
    const KEEP = 0, INSERT = 1, DELETE = 2;
    const diff = (left, right) => {
      const size = left.length + right.length + 2;
      const vDown = new Array(size);
      const vUp = new Array(size);
      const snake = (start2, end2, diag) => {
        return {
          start: start2,
          end: end2,
          diag
        };
      };
      const buildScript = (start1, end1, start2, end2, script2) => {
        const middle = getMiddleSnake(start1, end1, start2, end2);
        if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
          let i = start1;
          let j = start2;
          while (i < end1 || j < end2) {
            if (i < end1 && j < end2 && left[i] === right[j]) {
              script2.push([
                KEEP,
                left[i]
              ]);
              ++i;
              ++j;
            } else {
              if (end1 - start1 > end2 - start2) {
                script2.push([
                  DELETE,
                  left[i]
                ]);
                ++i;
              } else {
                script2.push([
                  INSERT,
                  right[j]
                ]);
                ++j;
              }
            }
          }
        } else {
          buildScript(start1, middle.start, start2, middle.start - middle.diag, script2);
          for (let i2 = middle.start; i2 < middle.end; ++i2) {
            script2.push([
              KEEP,
              left[i2]
            ]);
          }
          buildScript(middle.end, end1, middle.end - middle.diag, end2, script2);
        }
      };
      const buildSnake = (start2, diag, end1, end2) => {
        let end3 = start2;
        while (end3 - diag < end2 && end3 < end1 && left[end3] === right[end3 - diag]) {
          ++end3;
        }
        return snake(start2, end3, diag);
      };
      const getMiddleSnake = (start1, end1, start2, end2) => {
        const m = end1 - start1;
        const n = end2 - start2;
        if (m === 0 || n === 0) {
          return null;
        }
        const delta = m - n;
        const sum = n + m;
        const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
        vDown[1 + offset] = start1;
        vUp[1 + offset] = end1 + 1;
        let d, k, i, x, y;
        for (d = 0; d <= offset; ++d) {
          for (k = -d; k <= d; k += 2) {
            i = k + offset;
            if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
              vDown[i] = vDown[i + 1];
            } else {
              vDown[i] = vDown[i - 1] + 1;
            }
            x = vDown[i];
            y = x - start1 + start2 - k;
            while (x < end1 && y < end2 && left[x] === right[y]) {
              vDown[i] = ++x;
              ++y;
            }
            if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
              if (vUp[i - delta] <= vDown[i]) {
                return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
              }
            }
          }
          for (k = delta - d; k <= delta + d; k += 2) {
            i = k + offset - delta;
            if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
              vUp[i] = vUp[i + 1] - 1;
            } else {
              vUp[i] = vUp[i - 1];
            }
            x = vUp[i] - 1;
            y = x - start1 + start2 - k;
            while (x >= start1 && y >= start2 && left[x] === right[y]) {
              vUp[i] = x--;
              y--;
            }
            if (delta % 2 === 0 && -d <= k && k <= d) {
              if (vUp[i] <= vDown[i + delta]) {
                return buildSnake(vUp[i], k + start1 - start2, end1, end2);
              }
            }
          }
        }
      };
      const script = [];
      buildScript(0, left.length, 0, right.length, script);
      return script;
    };
    const getOuterHtml = (elm) => {
      if (isElement$6(elm)) {
        return elm.outerHTML;
      } else if (isText$9(elm)) {
        return Entities.encodeRaw(elm.data, false);
      } else if (isComment(elm)) {
        return "<!--" + elm.data + "-->";
      }
      return "";
    };
    const createFragment = (html2) => {
      let node;
      const container = document.createElement("div");
      const frag = document.createDocumentFragment();
      if (html2) {
        container.innerHTML = html2;
      }
      while (node = container.firstChild) {
        frag.appendChild(node);
      }
      return frag;
    };
    const insertAt = (elm, html2, index2) => {
      const fragment = createFragment(html2);
      if (elm.hasChildNodes() && index2 < elm.childNodes.length) {
        const target = elm.childNodes[index2];
        target.parentNode.insertBefore(fragment, target);
      } else {
        elm.appendChild(fragment);
      }
    };
    const removeAt = (elm, index2) => {
      if (elm.hasChildNodes() && index2 < elm.childNodes.length) {
        const target = elm.childNodes[index2];
        target.parentNode.removeChild(target);
      }
    };
    const applyDiff = (diff2, elm) => {
      let index2 = 0;
      each$f(diff2, (action2) => {
        if (action2[0] === KEEP) {
          index2++;
        } else if (action2[0] === INSERT) {
          insertAt(elm, action2[1], index2);
          index2++;
        } else if (action2[0] === DELETE) {
          removeAt(elm, index2);
        }
      });
    };
    const read$2 = (elm) => {
      return filter$6(map$3(from(elm.childNodes), getOuterHtml), (item) => {
        return item.length > 0;
      });
    };
    const write = (fragments, elm) => {
      const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
      applyDiff(diff(currentFragments, fragments), elm);
      return elm;
    };
    const lazyTempDocument = cached(() => document.implementation.createHTMLDocument("undo"));
    const hasIframes = (html2) => {
      return html2.indexOf("</iframe>") !== -1;
    };
    const createFragmentedLevel = (fragments) => {
      return {
        type: "fragmented",
        fragments,
        content: "",
        bookmark: null,
        beforeBookmark: null
      };
    };
    const createCompleteLevel = (content) => {
      return {
        type: "complete",
        fragments: null,
        content,
        bookmark: null,
        beforeBookmark: null
      };
    };
    const createFromEditor = (editor) => {
      const fragments = read$2(editor.getBody());
      const trimmedFragments = bind$3(fragments, (html2) => {
        const trimmed = trimInternal(editor.serializer, html2);
        return trimmed.length > 0 ? [trimmed] : [];
      });
      const content = trimmedFragments.join("");
      return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
    };
    const applyToEditor = (editor, level, before2) => {
      const bookmark = before2 ? level.beforeBookmark : level.bookmark;
      if (level.type === "fragmented") {
        write(level.fragments, editor.getBody());
      } else {
        editor.setContent(level.content, {
          format: "raw",
          no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
        });
      }
      editor.selection.moveToBookmark(bookmark);
    };
    const getLevelContent = (level) => {
      return level.type === "fragmented" ? level.fragments.join("") : level.content;
    };
    const getCleanLevelContent = (level) => {
      const elm = SugarElement.fromTag("body", lazyTempDocument());
      set(elm, getLevelContent(level));
      each$f(descendants(elm, "*[data-mce-bogus]"), unwrap);
      return get$6(elm);
    };
    const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
    const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
    const isEq$1 = (level1, level2) => {
      if (!level1 || !level2) {
        return false;
      } else if (hasEqualContent(level1, level2)) {
        return true;
      } else {
        return hasEqualCleanedContent(level1, level2);
      }
    };
    const isUnlocked = (locks) => locks.get() === 0;
    const setTyping = (undoManager, typing, locks) => {
      if (isUnlocked(locks)) {
        undoManager.typing = typing;
      }
    };
    const endTyping = (undoManager, locks) => {
      if (undoManager.typing) {
        setTyping(undoManager, false, locks);
        undoManager.add();
      }
    };
    const endTypingLevelIgnoreLocks = (undoManager) => {
      if (undoManager.typing) {
        undoManager.typing = false;
        undoManager.add();
      }
    };
    const beforeChange$1 = (editor, locks, beforeBookmark) => {
      if (isUnlocked(locks)) {
        beforeBookmark.set(getUndoBookmark(editor.selection));
      }
    };
    const addUndoLevel$1 = (editor, undoManager, index2, locks, beforeBookmark, level, event) => {
      const currentLevel = createFromEditor(editor);
      level = level || {};
      level = Tools.extend(level, currentLevel);
      if (isUnlocked(locks) === false || editor.removed) {
        return null;
      }
      const lastLevel = undoManager.data[index2.get()];
      if (editor.dispatch("BeforeAddUndo", {
        level,
        lastLevel,
        originalEvent: event
      }).isDefaultPrevented()) {
        return null;
      }
      if (lastLevel && isEq$1(lastLevel, level)) {
        return null;
      }
      if (undoManager.data[index2.get()]) {
        beforeBookmark.get().each((bm) => {
          undoManager.data[index2.get()].beforeBookmark = bm;
        });
      }
      const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
      if (customUndoRedoLevels) {
        if (undoManager.data.length > customUndoRedoLevels) {
          for (let i = 0; i < undoManager.data.length - 1; i++) {
            undoManager.data[i] = undoManager.data[i + 1];
          }
          undoManager.data.length--;
          index2.set(undoManager.data.length);
        }
      }
      level.bookmark = getUndoBookmark(editor.selection);
      if (index2.get() < undoManager.data.length - 1) {
        undoManager.data.length = index2.get() + 1;
      }
      undoManager.data.push(level);
      index2.set(undoManager.data.length - 1);
      const args = {
        level,
        lastLevel,
        originalEvent: event
      };
      if (index2.get() > 0) {
        editor.setDirty(true);
        editor.dispatch("AddUndo", args);
        editor.dispatch("change", args);
      } else {
        editor.dispatch("AddUndo", args);
      }
      return level;
    };
    const clear$1 = (editor, undoManager, index2) => {
      undoManager.data = [];
      index2.set(0);
      undoManager.typing = false;
      editor.dispatch("ClearUndos");
    };
    const extra$1 = (editor, undoManager, index2, callback1, callback2) => {
      if (undoManager.transact(callback1)) {
        const bookmark = undoManager.data[index2.get()].bookmark;
        const lastLevel = undoManager.data[index2.get() - 1];
        applyToEditor(editor, lastLevel, true);
        if (undoManager.transact(callback2)) {
          undoManager.data[index2.get() - 1].beforeBookmark = bookmark;
        }
      }
    };
    const redo$1 = (editor, index2, data2) => {
      let level;
      if (index2.get() < data2.length - 1) {
        index2.set(index2.get() + 1);
        level = data2[index2.get()];
        applyToEditor(editor, level, false);
        editor.setDirty(true);
        editor.dispatch("Redo", { level });
      }
      return level;
    };
    const undo$1 = (editor, undoManager, locks, index2) => {
      let level;
      if (undoManager.typing) {
        undoManager.add();
        undoManager.typing = false;
        setTyping(undoManager, false, locks);
      }
      if (index2.get() > 0) {
        index2.set(index2.get() - 1);
        level = undoManager.data[index2.get()];
        applyToEditor(editor, level, true);
        editor.setDirty(true);
        editor.dispatch("Undo", { level });
      }
      return level;
    };
    const reset$1 = (undoManager) => {
      undoManager.clear();
      undoManager.add();
    };
    const hasUndo$1 = (editor, undoManager, index2) => index2.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
    const hasRedo$1 = (undoManager, index2) => index2.get() < undoManager.data.length - 1 && !undoManager.typing;
    const transact$1 = (undoManager, locks, callback) => {
      endTyping(undoManager, locks);
      undoManager.beforeChange();
      undoManager.ignore(callback);
      return undoManager.add();
    };
    const ignore$1 = (locks, callback) => {
      try {
        locks.set(locks.get() + 1);
        callback();
      } finally {
        locks.set(locks.get() - 1);
      }
    };
    const addVisualInternal = (editor, elm) => {
      const dom2 = editor.dom;
      const scope = isNonNullable(elm) ? elm : editor.getBody();
      if (isUndefined(editor.hasVisual)) {
        editor.hasVisual = isVisualAidsEnabled(editor);
      }
      each$f(dom2.select("table,a", scope), (matchedElm) => {
        switch (matchedElm.nodeName) {
          case "TABLE":
            const cls = getVisualAidsTableClass(editor);
            const value2 = dom2.getAttrib(matchedElm, "border");
            if ((!value2 || value2 === "0") && editor.hasVisual) {
              dom2.addClass(matchedElm, cls);
            } else {
              dom2.removeClass(matchedElm, cls);
            }
            break;
          case "A":
            if (!dom2.getAttrib(matchedElm, "href")) {
              const value3 = dom2.getAttrib(matchedElm, "name") || matchedElm.id;
              const cls2 = getVisualAidsAnchorClass(editor);
              if (value3 && editor.hasVisual) {
                dom2.addClass(matchedElm, cls2);
              } else {
                dom2.removeClass(matchedElm, cls2);
              }
            }
            break;
        }
      });
      editor.dispatch("VisualAid", {
        element: elm,
        hasVisual: editor.hasVisual
      });
    };
    const makePlainAdaptor = (editor) => ({
      init: { bindEvents: noop },
      undoManager: {
        beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
        add: (undoManager, index2, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index2, locks, beforeBookmark, level, event),
        undo: (undoManager, locks, index2) => undo$1(editor, undoManager, locks, index2),
        redo: (index2, data2) => redo$1(editor, index2, data2),
        clear: (undoManager, index2) => clear$1(editor, undoManager, index2),
        reset: (undoManager) => reset$1(undoManager),
        hasUndo: (undoManager, index2) => hasUndo$1(editor, undoManager, index2),
        hasRedo: (undoManager, index2) => hasRedo$1(undoManager, index2),
        transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
        ignore: (locks, callback) => ignore$1(locks, callback),
        extra: (undoManager, index2, callback1, callback2) => extra$1(editor, undoManager, index2, callback1, callback2)
      },
      formatter: {
        match: (name2, vars, node, similar) => match$2(editor, name2, vars, node, similar),
        matchAll: (names, vars) => matchAll(editor, names, vars),
        matchNode: (node, name2, vars, similar) => matchNode(editor, node, name2, vars, similar),
        canApply: (name2) => canApply(editor, name2),
        closest: (names) => closest$1(editor, names),
        apply: (name2, vars, node) => applyFormat$1(editor, name2, vars, node),
        remove: (name2, vars, node, similar) => remove$2(editor, name2, vars, node, similar),
        toggle: (name2, vars, node) => toggle(editor, name2, vars, node),
        formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
      },
      editor: {
        getContent: (args) => getContentInternal(editor, args),
        setContent: (content, args) => setContentInternal(editor, content, args),
        insertContent: (value2, details) => insertHtmlAtCaret(editor, value2, details),
        addVisual: (elm) => addVisualInternal(editor, elm)
      },
      selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
      autocompleter: {
        addDecoration: (range2) => create$9(editor, range2),
        removeDecoration: () => remove$3(editor, SugarElement.fromDom(editor.getBody()))
      },
      raw: { getModel: () => Optional.none() }
    });
    const makeRtcAdaptor = (rtcEditor) => {
      const defaultVars = (vars) => isObject(vars) ? vars : {};
      const { init: init2, undoManager, formatter, editor, selection, autocompleter, raw } = rtcEditor;
      return {
        init: { bindEvents: init2.bindEvents },
        undoManager: {
          beforeChange: undoManager.beforeChange,
          add: undoManager.add,
          undo: undoManager.undo,
          redo: undoManager.redo,
          clear: undoManager.clear,
          reset: undoManager.reset,
          hasUndo: undoManager.hasUndo,
          hasRedo: undoManager.hasRedo,
          transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
          ignore: (_locks, callback) => undoManager.ignore(callback),
          extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
        },
        formatter: {
          match: (name2, vars, _node, similar) => formatter.match(name2, defaultVars(vars), similar),
          matchAll: formatter.matchAll,
          matchNode: formatter.matchNode,
          canApply: (name2) => formatter.canApply(name2),
          closest: (names) => formatter.closest(names),
          apply: (name2, vars, _node) => formatter.apply(name2, defaultVars(vars)),
          remove: (name2, vars, _node, _similar) => formatter.remove(name2, defaultVars(vars)),
          toggle: (name2, vars, _node) => formatter.toggle(name2, defaultVars(vars)),
          formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
        },
        editor: {
          getContent: (args) => editor.getContent(args),
          setContent: (content, args) => {
            return {
              content: editor.setContent(content, args),
              html: ""
            };
          },
          insertContent: (content, _details) => {
            editor.insertContent(content);
            return "";
          },
          addVisual: editor.addVisual
        },
        selection: { getContent: (_format, args) => selection.getContent(args) },
        autocompleter: {
          addDecoration: autocompleter.addDecoration,
          removeDecoration: autocompleter.removeDecoration
        },
        raw: { getModel: () => Optional.some(raw.getRawModel()) }
      };
    };
    const makeNoopAdaptor = () => {
      const nul = constant(null);
      const empty2 = constant("");
      return {
        init: { bindEvents: noop },
        undoManager: {
          beforeChange: noop,
          add: nul,
          undo: nul,
          redo: nul,
          clear: noop,
          reset: noop,
          hasUndo: never,
          hasRedo: never,
          transact: nul,
          ignore: noop,
          extra: noop
        },
        formatter: {
          match: never,
          matchAll: constant([]),
          matchNode: constant(void 0),
          canApply: never,
          closest: empty2,
          apply: noop,
          remove: noop,
          toggle: noop,
          formatChanged: constant({ unbind: noop })
        },
        editor: {
          getContent: empty2,
          setContent: constant({
            content: "",
            html: ""
          }),
          insertContent: constant(""),
          addVisual: noop
        },
        selection: { getContent: empty2 },
        autocompleter: {
          addDecoration: noop,
          removeDecoration: noop
        },
        raw: { getModel: constant(Optional.none()) }
      };
    };
    const isRtc = (editor) => has$2(editor.plugins, "rtc");
    const getRtcSetup = (editor) => get$a(editor.plugins, "rtc").bind((rtcPlugin) => Optional.from(rtcPlugin.setup));
    const setup$s = (editor) => {
      const editorCast = editor;
      return getRtcSetup(editor).fold(() => {
        editorCast.rtcInstance = makePlainAdaptor(editor);
        return Optional.none();
      }, (setup2) => {
        editorCast.rtcInstance = makeNoopAdaptor();
        return Optional.some(() => setup2().then((rtcEditor) => {
          editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
          return rtcEditor.rtc.isRemote;
        }));
      });
    };
    const getRtcInstanceWithFallback = (editor) => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
    const getRtcInstanceWithError = (editor) => {
      const rtcInstance = editor.rtcInstance;
      if (!rtcInstance) {
        throw new Error("Failed to get RTC instance not yet initialized.");
      } else {
        return rtcInstance;
      }
    };
    const beforeChange = (editor, locks, beforeBookmark) => {
      getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
    };
    const addUndoLevel = (editor, undoManager, index2, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index2, locks, beforeBookmark, level, event);
    const undo = (editor, undoManager, locks, index2) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index2);
    const redo = (editor, index2, data2) => getRtcInstanceWithError(editor).undoManager.redo(index2, data2);
    const clear = (editor, undoManager, index2) => {
      getRtcInstanceWithError(editor).undoManager.clear(undoManager, index2);
    };
    const reset = (editor, undoManager) => {
      getRtcInstanceWithError(editor).undoManager.reset(undoManager);
    };
    const hasUndo = (editor, undoManager, index2) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index2);
    const hasRedo = (editor, undoManager, index2) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index2);
    const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
    const ignore = (editor, locks, callback) => {
      getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
    };
    const extra = (editor, undoManager, index2, callback1, callback2) => {
      getRtcInstanceWithError(editor).undoManager.extra(undoManager, index2, callback1, callback2);
    };
    const matchFormat = (editor, name2, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name2, vars, node, similar);
    const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
    const matchNodeFormat = (editor, node, name2, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name2, vars, similar);
    const canApplyFormat = (editor, name2) => getRtcInstanceWithError(editor).formatter.canApply(name2);
    const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
    const applyFormat = (editor, name2, vars, node) => {
      getRtcInstanceWithError(editor).formatter.apply(name2, vars, node);
    };
    const removeFormat = (editor, name2, vars, node, similar) => {
      getRtcInstanceWithError(editor).formatter.remove(name2, vars, node, similar);
    };
    const toggleFormat = (editor, name2, vars, node) => {
      getRtcInstanceWithError(editor).formatter.toggle(name2, vars, node);
    };
    const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
    const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
    const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
    const insertContent$1 = (editor, value2, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value2, details);
    const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
    const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
    const bindEvents = (editor) => getRtcInstanceWithError(editor).init.bindEvents();
    const addAutocompleterDecoration = (editor, range2) => getRtcInstanceWithError(editor).autocompleter.addDecoration(range2);
    const removeAutocompleterDecoration = (editor) => getRtcInstanceWithError(editor).autocompleter.removeDecoration();
    const getContent$1 = (editor, args = {}) => {
      const format = args.format ? args.format : "html";
      return getSelectedContent(editor, format, args);
    };
    const removeEmpty = (text2) => {
      if (text2.dom.length === 0) {
        remove$6(text2);
        return Optional.none();
      } else {
        return Optional.some(text2);
      }
    };
    const walkPastBookmark = (node, start2) => node.filter((elm) => BookmarkManager.isBookmarkNode(elm.dom)).bind(start2 ? nextSibling : prevSibling);
    const merge$1 = (outer, inner, rng, start2) => {
      const outerElm = outer.dom;
      const innerElm = inner.dom;
      const oldLength = start2 ? outerElm.length : innerElm.length;
      if (start2) {
        mergeTextNodes(outerElm, innerElm, false, !start2);
        rng.setStart(innerElm, oldLength);
      } else {
        mergeTextNodes(innerElm, outerElm, false, !start2);
        rng.setEnd(innerElm, oldLength);
      }
    };
    const normalizeTextIfRequired = (inner, start2) => {
      parent(inner).each((root) => {
        const text2 = inner.dom;
        if (start2 && needsToBeNbspLeft(root, CaretPosition(text2, 0))) {
          normalizeWhitespaceAfter(text2, 0);
        } else if (!start2 && needsToBeNbspRight(root, CaretPosition(text2, text2.length))) {
          normalizeWhitespaceBefore(text2, text2.length);
        }
      });
    };
    const mergeAndNormalizeText = (outerNode, innerNode, rng, start2) => {
      outerNode.bind((outer) => {
        const normalizer = start2 ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
        normalizer(outer.dom, start2 ? outer.dom.length : 0);
        return innerNode.filter(isText$a).map((inner) => merge$1(outer, inner, rng, start2));
      }).orThunk(() => {
        const innerTextNode = walkPastBookmark(innerNode, start2).or(innerNode).filter(isText$a);
        return innerTextNode.map((inner) => normalizeTextIfRequired(inner, start2));
      });
    };
    const rngSetContent = (rng, fragment) => {
      const firstChild2 = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
      const lastChild2 = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
      rng.deleteContents();
      rng.insertNode(fragment);
      const prevText = firstChild2.bind(prevSibling).filter(isText$a).bind(removeEmpty);
      const nextText = lastChild2.bind(nextSibling).filter(isText$a).bind(removeEmpty);
      mergeAndNormalizeText(prevText, firstChild2, rng, true);
      mergeAndNormalizeText(nextText, lastChild2, rng, false);
      rng.collapse(false);
    };
    const setupArgs$2 = (args, content) => ({
      format: "html",
      ...args,
      set: true,
      selection: true,
      content
    });
    const cleanContent = (editor, args) => {
      if (args.format !== "raw") {
        const rng = editor.selection.getRng();
        const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
        const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
        const node = editor.parser.parse(args.content, {
          forced_root_block: false,
          ...contextArgs,
          ...args
        });
        return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
      } else {
        return args.content;
      }
    };
    const setContent$1 = (editor, content, args = {}) => {
      const defaultedArgs = setupArgs$2(args, content);
      preProcessSetContent(editor, defaultedArgs).each((updatedArgs) => {
        const cleanedContent = cleanContent(editor, updatedArgs);
        const rng = editor.selection.getRng();
        rngSetContent(rng, rng.createContextualFragment(cleanedContent));
        editor.selection.setRng(rng);
        scrollRangeIntoView(editor, rng);
        postProcessSetContent(editor, cleanedContent, updatedArgs);
      });
    };
    const deleteFromCallbackMap = (callbackMap, selector, callback) => {
      if (callbackMap && has$2(callbackMap, selector)) {
        const newCallbacks = filter$6(callbackMap[selector], (cb) => cb !== callback);
        if (newCallbacks.length === 0) {
          delete callbackMap[selector];
        } else {
          callbackMap[selector] = newCallbacks;
        }
      }
    };
    var SelectorChanged = (dom2, editor) => {
      let selectorChangedData;
      let currentSelectors;
      const findMatchingNode = (selector, nodes) => find$2(nodes, (node) => dom2.is(node, selector));
      const getParents2 = (elem) => dom2.getParents(elem, null, dom2.getRoot());
      return {
        selectorChangedWithUnbind: (selector, callback) => {
          if (!selectorChangedData) {
            selectorChangedData = {};
            currentSelectors = {};
            editor.on("NodeChange", (e) => {
              const node = e.element;
              const parents2 = getParents2(node);
              const matchedSelectors = {};
              Tools.each(selectorChangedData, (callbacks, selector2) => {
                findMatchingNode(selector2, parents2).each((node2) => {
                  if (!currentSelectors[selector2]) {
                    each$f(callbacks, (callback2) => {
                      callback2(true, {
                        node: node2,
                        selector: selector2,
                        parents: parents2
                      });
                    });
                    currentSelectors[selector2] = callbacks;
                  }
                  matchedSelectors[selector2] = callbacks;
                });
              });
              Tools.each(currentSelectors, (callbacks, selector2) => {
                if (!matchedSelectors[selector2]) {
                  delete currentSelectors[selector2];
                  Tools.each(callbacks, (callback2) => {
                    callback2(false, {
                      node,
                      selector: selector2,
                      parents: parents2
                    });
                  });
                }
              });
            });
          }
          if (!selectorChangedData[selector]) {
            selectorChangedData[selector] = [];
          }
          selectorChangedData[selector].push(callback);
          findMatchingNode(selector, getParents2(editor.selection.getStart())).each(() => {
            currentSelectors[selector] = selectorChangedData[selector];
          });
          return {
            unbind: () => {
              deleteFromCallbackMap(selectorChangedData, selector, callback);
              deleteFromCallbackMap(currentSelectors, selector, callback);
            }
          };
        }
      };
    };
    const isAttachedToDom = (node) => {
      return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
    };
    const isValidRange = (rng) => {
      if (!rng) {
        return false;
      } else {
        return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
      }
    };
    const EditorSelection = (dom2, win, serializer, editor) => {
      let selectedRange;
      let explicitRange;
      const { selectorChangedWithUnbind } = SelectorChanged(dom2, editor);
      const setCursorLocation = (node, offset) => {
        const rng = dom2.createRng();
        if (isNonNullable(node) && isNonNullable(offset)) {
          rng.setStart(node, offset);
          rng.setEnd(node, offset);
          setRng(rng);
          collapse2(false);
        } else {
          moveEndPoint(dom2, rng, editor.getBody(), true);
          setRng(rng);
        }
      };
      const getContent2 = (args) => getContent$1(editor, args);
      const setContent2 = (content, args) => setContent$1(editor, content, args);
      const getStart$12 = (real) => getStart(editor.getBody(), getRng$1(), real);
      const getEnd2 = (real) => getEnd$1(editor.getBody(), getRng$1(), real);
      const getBookmark2 = (type2, normalized) => bookmarkManager.getBookmark(type2, normalized);
      const moveToBookmark2 = (bookmark) => bookmarkManager.moveToBookmark(bookmark);
      const select$1 = (node, content) => {
        select(dom2, node, content).each(setRng);
        return node;
      };
      const isCollapsed = () => {
        const rng = getRng$1(), sel = getSel();
        if (!rng || rng.item) {
          return false;
        }
        if (rng.compareEndPoints) {
          return rng.compareEndPoints("StartToEnd", rng) === 0;
        }
        return !sel || rng.collapsed;
      };
      const collapse2 = (toStart) => {
        const rng = getRng$1();
        rng.collapse(!!toStart);
        setRng(rng);
      };
      const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
      const getRng$1 = () => {
        let selection, rng, elm;
        const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
          try {
            return sourceRange.compareBoundaryPoints(how, destinationRange);
          } catch (ex) {
            return -1;
          }
        };
        const doc = win.document;
        if (editor.bookmark !== void 0 && hasFocus(editor) === false) {
          const bookmark = getRng(editor);
          if (bookmark.isSome()) {
            return bookmark.map((r2) => processRanges(editor, [r2])[0]).getOr(doc.createRange());
          }
        }
        try {
          if ((selection = getSel()) && !isRestrictedNode(selection.anchorNode)) {
            if (selection.rangeCount > 0) {
              rng = selection.getRangeAt(0);
            } else {
              rng = selection.createRange ? selection.createRange() : doc.createRange();
            }
            rng = processRanges(editor, [rng])[0];
          }
        } catch (ex) {
        }
        if (!rng) {
          rng = doc.createRange();
        }
        if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
          elm = dom2.getRoot();
          rng.setStart(elm, 0);
          rng.setEnd(elm, 0);
        }
        if (selectedRange && explicitRange) {
          if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
            rng = explicitRange;
          } else {
            selectedRange = null;
            explicitRange = null;
          }
        }
        return rng;
      };
      const setRng = (rng, forward) => {
        let node;
        if (!isValidRange(rng)) {
          return;
        }
        const sel = getSel();
        const evt = editor.dispatch("SetSelectionRange", {
          range: rng,
          forward
        });
        rng = evt.range;
        if (sel) {
          explicitRange = rng;
          try {
            sel.removeAllRanges();
            sel.addRange(rng);
          } catch (ex) {
          }
          if (forward === false && sel.extend) {
            sel.collapse(rng.endContainer, rng.endOffset);
            sel.extend(rng.startContainer, rng.startOffset);
          }
          selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
        }
        if (!rng.collapsed && rng.startContainer === rng.endContainer && sel.setBaseAndExtent) {
          if (rng.endOffset - rng.startOffset < 2) {
            if (rng.startContainer.hasChildNodes()) {
              node = rng.startContainer.childNodes[rng.startOffset];
              if (node && node.tagName === "IMG") {
                sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
                if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
                  sel.setBaseAndExtent(node, 0, node, 1);
                }
              }
            }
          }
        }
        editor.dispatch("AfterSetSelectionRange", {
          range: rng,
          forward
        });
      };
      const setNode = (elm) => {
        setContent2(dom2.getOuterHTML(elm));
        return elm;
      };
      const getNode$12 = () => getNode(editor.getBody(), getRng$1());
      const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom2, getRng$1(), startElm, endElm);
      const isForward = () => {
        const sel = getSel();
        const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
        const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
        if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
          return true;
        }
        const anchorRange = dom2.createRng();
        const focusRange = dom2.createRng();
        try {
          anchorRange.setStart(anchorNode, sel.anchorOffset);
          anchorRange.collapse(true);
          focusRange.setStart(focusNode, sel.focusOffset);
          focusRange.collapse(true);
        } catch (e) {
          return true;
        }
        return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
      };
      const normalize2 = () => {
        const rng = getRng$1();
        const sel = getSel();
        if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
          const normRng = normalize$2(dom2, rng);
          normRng.each((normRng2) => {
            setRng(normRng2, isForward());
          });
          return normRng.getOr(rng);
        }
        return rng;
      };
      const selectorChanged = (selector, callback) => {
        selectorChangedWithUnbind(selector, callback);
        return exports;
      };
      const getScrollContainer = () => {
        let scrollContainer;
        let node = dom2.getRoot();
        while (node && node.nodeName !== "BODY") {
          if (node.scrollHeight > node.clientHeight) {
            scrollContainer = node;
            break;
          }
          node = node.parentNode;
        }
        return scrollContainer;
      };
      const scrollIntoView = (elm, alignToTop) => {
        if (isNonNullable(elm)) {
          scrollElementIntoView(editor, elm, alignToTop);
        } else {
          scrollRangeIntoView(editor, getRng$1(), alignToTop);
        }
      };
      const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
      const getBoundingClientRect2 = () => {
        const rng = getRng$1();
        return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
      };
      const destroy2 = () => {
        win = selectedRange = explicitRange = null;
        controlSelection.destroy();
      };
      const exports = {
        bookmarkManager: null,
        controlSelection: null,
        dom: dom2,
        win,
        serializer,
        editor,
        collapse: collapse2,
        setCursorLocation,
        getContent: getContent2,
        setContent: setContent2,
        getBookmark: getBookmark2,
        moveToBookmark: moveToBookmark2,
        select: select$1,
        isCollapsed,
        isForward,
        setNode,
        getNode: getNode$12,
        getSel,
        setRng,
        getRng: getRng$1,
        getStart: getStart$12,
        getEnd: getEnd2,
        getSelectedBlocks: getSelectedBlocks$1,
        normalize: normalize2,
        selectorChanged,
        selectorChangedWithUnbind,
        getScrollContainer,
        scrollIntoView,
        placeCaretAt,
        getBoundingClientRect: getBoundingClientRect2,
        destroy: destroy2
      };
      const bookmarkManager = BookmarkManager(exports);
      const controlSelection = ControlSelection(exports, editor);
      exports.bookmarkManager = bookmarkManager;
      exports.controlSelection = controlSelection;
      return exports;
    };
    const register$3 = (htmlParser, settings, dom2) => {
      htmlParser.addAttributeFilter("data-mce-tabindex", (nodes, name2) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          node.attr("tabindex", node.attr("data-mce-tabindex"));
          node.attr(name2, null);
        }
      });
      htmlParser.addAttributeFilter("src,href,style", (nodes, name2) => {
        const internalName = "data-mce-" + name2;
        const urlConverter = settings.url_converter;
        const urlConverterScope = settings.url_converter_scope;
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          let value2 = node.attr(internalName);
          if (value2 !== void 0) {
            node.attr(name2, value2.length > 0 ? value2 : null);
            node.attr(internalName, null);
          } else {
            value2 = node.attr(name2);
            if (name2 === "style") {
              value2 = dom2.serializeStyle(dom2.parseStyle(value2), node.name);
            } else if (urlConverter) {
              value2 = urlConverter.call(urlConverterScope, value2, name2, node.name);
            }
            node.attr(name2, value2.length > 0 ? value2 : null);
          }
        }
      });
      htmlParser.addAttributeFilter("class", (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          let value2 = node.attr("class");
          if (value2) {
            value2 = node.attr("class").replace(/(?:^|\s)mce-item-\w+(?!\S)/g, "");
            node.attr("class", value2.length > 0 ? value2 : null);
          }
        }
      });
      htmlParser.addAttributeFilter("data-mce-type", (nodes, name2, args) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (node.attr("data-mce-type") === "bookmark" && !args.cleanup) {
            const hasChildren = Optional.from(node.firstChild).exists((firstChild2) => !isZwsp(firstChild2.value));
            if (hasChildren) {
              node.unwrap();
            } else {
              node.remove();
            }
          }
        }
      });
      htmlParser.addNodeFilter("noscript", (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i].firstChild;
          if (node) {
            node.value = Entities.decode(node.value);
          }
        }
      });
      htmlParser.addNodeFilter("script,style", (nodes, name2) => {
        const trim2 = (value2) => {
          return value2.replace(/(<!--\[CDATA\[|\]\]-->)/g, "\n").replace(/^[\r\n]*|[\r\n]*$/g, "").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, "").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, "");
        };
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          const value2 = node.firstChild ? node.firstChild.value : "";
          if (name2 === "script") {
            const type2 = node.attr("type");
            if (type2) {
              node.attr("type", type2 === "mce-no/type" ? null : type2.replace(/^mce\-/, ""));
            }
            if (settings.element_format === "xhtml" && value2.length > 0) {
              node.firstChild.value = "// <![CDATA[\n" + trim2(value2) + "\n// ]]>";
            }
          } else {
            if (settings.element_format === "xhtml" && value2.length > 0) {
              node.firstChild.value = "<!--\n" + trim2(value2) + "\n-->";
            }
          }
        }
      });
      htmlParser.addNodeFilter("#comment", (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (settings.preserve_cdata && node.value.indexOf("[CDATA[") === 0) {
            node.name = "#cdata";
            node.type = 4;
            node.value = dom2.decode(node.value.replace(/^\[CDATA\[|\]\]$/g, ""));
          } else if (node.value.indexOf("mce:protected ") === 0) {
            node.name = "#text";
            node.type = 3;
            node.raw = true;
            node.value = unescape(node.value).substr(14);
          }
        }
      });
      htmlParser.addNodeFilter("xml:namespace,input", (nodes, name2) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (node.type === 7) {
            node.remove();
          } else if (node.type === 1) {
            if (name2 === "input" && !node.attr("type")) {
              node.attr("type", "text");
            }
          }
        }
      });
      htmlParser.addAttributeFilter("data-mce-type", (nodes) => {
        each$f(nodes, (node) => {
          if (node.attr("data-mce-type") === "format-caret") {
            if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
              node.remove();
            } else {
              node.unwrap();
            }
          }
        });
      });
      htmlParser.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style,data-mce-selected,data-mce-expando,data-mce-type,data-mce-resize,data-mce-placeholder", (nodes, name2) => {
        let i = nodes.length;
        while (i--) {
          nodes[i].attr(name2, null);
        }
      });
    };
    const trimTrailingBr = (rootNode) => {
      const isBr2 = (node) => {
        return node && node.name === "br";
      };
      const brNode1 = rootNode.lastChild;
      if (isBr2(brNode1)) {
        const brNode2 = brNode1.prev;
        if (isBr2(brNode2)) {
          brNode1.remove();
          brNode2.remove();
        }
      }
    };
    const preProcess$1 = (editor, node, args) => {
      let oldDoc;
      const dom2 = editor.dom;
      let clonedNode = node.cloneNode(true);
      const impl = document.implementation;
      if (impl.createHTMLDocument) {
        const doc = impl.createHTMLDocument("");
        Tools.each(clonedNode.nodeName === "BODY" ? clonedNode.childNodes : [clonedNode], (node2) => {
          doc.body.appendChild(doc.importNode(node2, true));
        });
        if (clonedNode.nodeName !== "BODY") {
          clonedNode = doc.body.firstChild;
        } else {
          clonedNode = doc.body;
        }
        oldDoc = dom2.doc;
        dom2.doc = doc;
      }
      firePreProcess(editor, {
        ...args,
        node: clonedNode
      });
      if (oldDoc) {
        dom2.doc = oldDoc;
      }
      return clonedNode;
    };
    const shouldFireEvent = (editor, args) => {
      return editor && editor.hasEventListeners("PreProcess") && !args.no_events;
    };
    const process$1 = (editor, node, args) => {
      return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
    };
    const addTempAttr = (htmlParser, tempAttrs, name2) => {
      if (Tools.inArray(tempAttrs, name2) === -1) {
        htmlParser.addAttributeFilter(name2, (nodes, name3) => {
          let i = nodes.length;
          while (i--) {
            nodes[i].attr(name3, null);
          }
        });
        tempAttrs.push(name2);
      }
    };
    const postProcess = (editor, args, content) => {
      if (!args.no_events && editor) {
        const outArgs = firePostProcess(editor, {
          ...args,
          content
        });
        return outArgs.content;
      } else {
        return content;
      }
    };
    const getHtmlFromNode = (dom2, node, args) => {
      const html2 = trim$1(args.getInner ? node.innerHTML : dom2.getOuterHTML(node));
      return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html2 : Tools.trim(html2);
    };
    const parseHtml = (htmlParser, html2, args) => {
      const parserArgs = args.selection ? {
        forced_root_block: false,
        ...args
      } : args;
      const rootNode = htmlParser.parse(html2, parserArgs);
      trimTrailingBr(rootNode);
      return rootNode;
    };
    const serializeNode = (settings, schema, node) => {
      const htmlSerializer = HtmlSerializer(settings, schema);
      return htmlSerializer.serialize(node);
    };
    const toHtml = (editor, settings, schema, rootNode, args) => {
      const content = serializeNode(settings, schema, rootNode);
      return postProcess(editor, args, content);
    };
    const DomSerializerImpl = (settings, editor) => {
      const tempAttrs = ["data-mce-selected"];
      const dom2 = editor && editor.dom ? editor.dom : DOMUtils.DOM;
      const schema = editor && editor.schema ? editor.schema : Schema(settings);
      settings.entity_encoding = settings.entity_encoding || "named";
      settings.remove_trailing_brs = "remove_trailing_brs" in settings ? settings.remove_trailing_brs : true;
      const htmlParser = DomParser(settings, schema);
      register$3(htmlParser, settings, dom2);
      const serialize = (node, parserArgs = {}) => {
        const args = {
          format: "html",
          ...parserArgs
        };
        const targetNode = process$1(editor, node, args);
        const html2 = getHtmlFromNode(dom2, targetNode, args);
        const rootNode = parseHtml(htmlParser, html2, args);
        return args.format === "tree" ? rootNode : toHtml(editor, settings, schema, rootNode, args);
      };
      return {
        schema,
        addNodeFilter: htmlParser.addNodeFilter,
        addAttributeFilter: htmlParser.addAttributeFilter,
        serialize,
        addRules: schema.addValidElements,
        setRules: schema.setValidElements,
        addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
        getTempAttrs: constant(tempAttrs),
        getNodeFilters: htmlParser.getNodeFilters,
        getAttributeFilters: htmlParser.getAttributeFilters,
        removeNodeFilter: htmlParser.removeNodeFilter,
        removeAttributeFilter: htmlParser.removeAttributeFilter
      };
    };
    const DomSerializer = (settings, editor) => {
      const domSerializer = DomSerializerImpl(settings, editor);
      return {
        schema: domSerializer.schema,
        addNodeFilter: domSerializer.addNodeFilter,
        addAttributeFilter: domSerializer.addAttributeFilter,
        serialize: domSerializer.serialize,
        addRules: domSerializer.addRules,
        setRules: domSerializer.setRules,
        addTempAttr: domSerializer.addTempAttr,
        getTempAttrs: domSerializer.getTempAttrs,
        getNodeFilters: domSerializer.getNodeFilters,
        getAttributeFilters: domSerializer.getAttributeFilters,
        removeNodeFilter: domSerializer.removeNodeFilter,
        removeAttributeFilter: domSerializer.removeAttributeFilter
      };
    };
    const defaultFormat$1 = "html";
    const setupArgs$1 = (args, format) => ({
      ...args,
      format,
      get: true,
      getInner: true
    });
    const getContent = (editor, args = {}) => {
      const format = args.format ? args.format : defaultFormat$1;
      const defaultedArgs = setupArgs$1(args, format);
      return preProcessGetContent(editor, defaultedArgs).fold(identity, (updatedArgs) => {
        const content = getContent$2(editor, updatedArgs);
        return postProcessGetContent(editor, content, updatedArgs);
      });
    };
    const defaultFormat = "html";
    const setupArgs = (args, content) => ({
      format: defaultFormat,
      ...args,
      set: true,
      content
    });
    const setContent = (editor, content, args = {}) => {
      const defaultedArgs = setupArgs(args, content);
      return preProcessSetContent(editor, defaultedArgs).map((updatedArgs) => {
        const result = setContent$2(editor, updatedArgs.content, updatedArgs);
        postProcessSetContent(editor, result.html, updatedArgs);
        return result.content;
      }).getOr(content);
    };
    const removedOptions = "autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists".split(",");
    const removedPlugins = "bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,textcolor".split(",");
    const getRemovedOptions = (options) => {
      const settingNames = filter$6(removedOptions, (setting) => has$2(options, setting));
      const forcedRootBlock = options.forced_root_block;
      if (forcedRootBlock === false || forcedRootBlock === "") {
        settingNames.push("forced_root_block (false only)");
      }
      return sort(settingNames);
    };
    const getRemovedPlugins = (options) => {
      const plugins = Tools.makeMap(options.plugins, " ");
      const hasPlugin = (plugin) => has$2(plugins, plugin);
      const pluginNames = filter$6(removedPlugins, hasPlugin);
      return sort(pluginNames);
    };
    const logRemovedWarnings = (rawOptions, normalizedOptions) => {
      const removedOptions2 = getRemovedOptions(rawOptions);
      const removedPlugins2 = getRemovedPlugins(normalizedOptions);
      const hasRemovedPlugins = removedPlugins2.length > 0;
      const hasRemovedOptions = removedOptions2.length > 0;
      const isLegacyMobileTheme = normalizedOptions.theme === "mobile";
      if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
        const listJoiner = "\n- ";
        const themesMessage = isLegacyMobileTheme ? `

Themes:${listJoiner}mobile` : "";
        const pluginsMessage = hasRemovedPlugins ? `

Plugins:${listJoiner}${removedPlugins2.join(listJoiner)}` : "";
        const optionsMessage = hasRemovedOptions ? `

Options:${listJoiner}${removedOptions2.join(listJoiner)}` : "";
        console.warn("The following deprecated features are currently enabled and have been removed in TinyMCE 6.0. These features will no longer work and should be removed from the TinyMCE configuration. See https://www.tiny.cloud/docs/tinymce/6/migration-from-5x/ for more information." + themesMessage + pluginsMessage + optionsMessage);
      }
    };
    const logWarnings = (rawOptions, normalizedOptions) => {
      logRemovedWarnings(rawOptions, normalizedOptions);
    };
    const DOM$8 = DOMUtils.DOM;
    const restoreOriginalStyles = (editor) => {
      DOM$8.setStyle(editor.id, "display", editor.orgDisplay);
    };
    const safeDestroy = (x) => Optional.from(x).each((x2) => x2.destroy());
    const clearDomReferences = (editor) => {
      editor.contentAreaContainer = editor.formElement = editor.container = editor.editorContainer = null;
      editor.bodyElement = editor.contentDocument = editor.contentWindow = null;
      editor.iframeElement = editor.targetElm = null;
      if (editor.selection) {
        editor.selection = editor.selection.win = editor.selection.dom = editor.selection.dom.doc = null;
      }
    };
    const restoreForm = (editor) => {
      const form = editor.formElement;
      if (form) {
        if (form._mceOldSubmit) {
          form.submit = form._mceOldSubmit;
          form._mceOldSubmit = null;
        }
        DOM$8.unbind(form, "submit reset", editor.formEventDelegate);
      }
    };
    const remove$1 = (editor) => {
      if (!editor.removed) {
        const { _selectionOverrides, editorUpload } = editor;
        const body = editor.getBody();
        const element = editor.getElement();
        if (body) {
          editor.save({ is_removing: true });
        }
        editor.removed = true;
        editor.unbindAllNativeEvents();
        if (editor.hasHiddenInput && element) {
          DOM$8.remove(element.nextSibling);
        }
        fireRemove(editor);
        editor.editorManager.remove(editor);
        if (!editor.inline && body) {
          restoreOriginalStyles(editor);
        }
        fireDetach(editor);
        DOM$8.remove(editor.getContainer());
        safeDestroy(_selectionOverrides);
        safeDestroy(editorUpload);
        editor.destroy();
      }
    };
    const destroy = (editor, automatic) => {
      const { selection, dom: dom2 } = editor;
      if (editor.destroyed) {
        return;
      }
      if (!automatic && !editor.removed) {
        editor.remove();
        return;
      }
      if (!automatic) {
        editor.editorManager.off("beforeunload", editor._beforeUnload);
        if (editor.theme && editor.theme.destroy) {
          editor.theme.destroy();
        }
        safeDestroy(selection);
        safeDestroy(dom2);
      }
      restoreForm(editor);
      clearDomReferences(editor);
      editor.destroyed = true;
    };
    const CreateIconManager = () => {
      const lookup2 = {};
      const add2 = (id, iconPack) => {
        lookup2[id] = iconPack;
      };
      const get2 = (id) => {
        if (lookup2[id]) {
          return lookup2[id];
        }
        return { icons: {} };
      };
      const has2 = (id) => has$2(lookup2, id);
      return {
        add: add2,
        get: get2,
        has: has2
      };
    };
    const IconManager = CreateIconManager();
    const ModelManager = AddOnManager.ModelManager;
    const getProp = (propName, elm) => {
      const rawElm = elm.dom;
      return rawElm[propName];
    };
    const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
    const getClientWidth = curry(getProp, "clientWidth");
    const getClientHeight = curry(getProp, "clientHeight");
    const getMarginTop = curry(getComputedSizeProp, "margin-top");
    const getMarginLeft = curry(getComputedSizeProp, "margin-left");
    const getBoundingClientRect = (elm) => elm.dom.getBoundingClientRect();
    const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
      const clientWidth = getClientWidth(bodyElm);
      const clientHeight = getClientHeight(bodyElm);
      return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
    };
    const transpose = (inline, elm, clientX, clientY) => {
      const clientRect = getBoundingClientRect(elm);
      const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
      const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
      const x = clientX - deltaX;
      const y = clientY - deltaY;
      return {
        x,
        y
      };
    };
    const isXYInContentArea = (editor, clientX, clientY) => {
      const bodyElm = SugarElement.fromDom(editor.getBody());
      const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
      const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
      return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
    };
    const fromDomSafe = (node) => Optional.from(node).map(SugarElement.fromDom);
    const isEditorAttachedToDom = (editor) => {
      const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
      return fromDomSafe(rawContainer).map(inBody).getOr(false);
    };
    const NotificationManagerImpl = () => {
      const unimplemented = () => {
        throw new Error("Theme did not provide a NotificationManager implementation.");
      };
      return {
        open: unimplemented,
        close: unimplemented,
        getArgs: unimplemented
      };
    };
    const NotificationManager = (editor) => {
      const notifications = [];
      const getImplementation = () => {
        const theme = editor.theme;
        return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
      };
      const getTopNotification = () => {
        return Optional.from(notifications[0]);
      };
      const isEqual2 = (a, b) => {
        return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
      };
      const reposition2 = () => {
        each$f(notifications, (notification) => {
          notification.reposition();
        });
      };
      const addNotification = (notification) => {
        notifications.push(notification);
      };
      const closeNotification = (notification) => {
        findIndex$2(notifications, (otherNotification) => {
          return otherNotification === notification;
        }).each((index2) => {
          notifications.splice(index2, 1);
        });
      };
      const open = (spec, fireEvent2 = true) => {
        if (editor.removed || !isEditorAttachedToDom(editor)) {
          return;
        }
        if (fireEvent2) {
          editor.dispatch("BeforeOpenNotification", { notification: spec });
        }
        return find$2(notifications, (notification) => {
          return isEqual2(getImplementation().getArgs(notification), spec);
        }).getOrThunk(() => {
          editor.editorManager.setActive(editor);
          const notification = getImplementation().open(spec, () => {
            closeNotification(notification);
            reposition2();
            getTopNotification().fold(() => editor.focus(), (top) => focus$1(SugarElement.fromDom(top.getEl())));
          });
          addNotification(notification);
          reposition2();
          editor.dispatch("OpenNotification", { notification: { ...notification } });
          return notification;
        });
      };
      const close = () => {
        getTopNotification().each((notification) => {
          getImplementation().close(notification);
          closeNotification(notification);
          reposition2();
        });
      };
      const getNotifications = constant(notifications);
      const registerEvents2 = (editor2) => {
        editor2.on("SkinLoaded", () => {
          const serviceMessage = getServiceMessage(editor2);
          if (serviceMessage) {
            open({
              text: serviceMessage,
              type: "warning",
              timeout: 0
            }, false);
          }
          reposition2();
        });
        editor2.on("show ResizeEditor ResizeWindow NodeChange", () => {
          requestAnimationFrame(reposition2);
        });
        editor2.on("remove", () => {
          each$f(notifications.slice(), (notification) => {
            getImplementation().close(notification);
          });
        });
      };
      registerEvents2(editor);
      return {
        open,
        close,
        getNotifications
      };
    };
    const PluginManager = AddOnManager.PluginManager;
    const ThemeManager = AddOnManager.ThemeManager;
    var WindowManagerImpl = () => {
      const unimplemented = () => {
        throw new Error("Theme did not provide a WindowManager implementation.");
      };
      return {
        open: unimplemented,
        openUrl: unimplemented,
        alert: unimplemented,
        confirm: unimplemented,
        close: unimplemented,
        getParams: unimplemented,
        setParams: unimplemented
      };
    };
    const WindowManager = (editor) => {
      let dialogs = [];
      const getImplementation = () => {
        const theme = editor.theme;
        return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
      };
      const funcBind = (scope, f) => {
        return (...args) => {
          return f ? f.apply(scope, args) : void 0;
        };
      };
      const fireOpenEvent = (dialog) => {
        editor.dispatch("OpenWindow", { dialog });
      };
      const fireCloseEvent = (dialog) => {
        editor.dispatch("CloseWindow", { dialog });
      };
      const addDialog = (dialog) => {
        dialogs.push(dialog);
        fireOpenEvent(dialog);
      };
      const closeDialog = (dialog) => {
        fireCloseEvent(dialog);
        dialogs = filter$6(dialogs, (otherDialog) => {
          return otherDialog !== dialog;
        });
        if (dialogs.length === 0) {
          editor.focus();
        }
      };
      const getTopDialog = () => {
        return Optional.from(dialogs[dialogs.length - 1]);
      };
      const storeSelectionAndOpenDialog = (openDialog) => {
        editor.editorManager.setActive(editor);
        store(editor);
        editor.ui.show();
        const dialog = openDialog();
        addDialog(dialog);
        return dialog;
      };
      const open = (args, params) => {
        return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
      };
      const openUrl = (args) => {
        return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
      };
      const alert = (message, callback, scope) => {
        const windowManagerImpl = getImplementation();
        windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
      };
      const confirm = (message, callback, scope) => {
        const windowManagerImpl = getImplementation();
        windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
      };
      const close = () => {
        getTopDialog().each((dialog) => {
          getImplementation().close(dialog);
          closeDialog(dialog);
        });
      };
      editor.on("remove", () => {
        each$f(dialogs, (dialog) => {
          getImplementation().close(dialog);
        });
      });
      return {
        open,
        openUrl,
        alert,
        confirm,
        close
      };
    };
    const displayNotification = (editor, message) => {
      editor.notificationManager.open({
        type: "error",
        text: message
      });
    };
    const displayError = (editor, message) => {
      if (editor._skinLoaded) {
        displayNotification(editor, message);
      } else {
        editor.on("SkinLoaded", () => {
          displayNotification(editor, message);
        });
      }
    };
    const uploadError = (editor, message) => {
      displayError(editor, I18n.translate([
        "Failed to upload image: {0}",
        message
      ]));
    };
    const logError = (editor, errorType, msg) => {
      fireError(editor, errorType, { message: msg });
      console.error(msg);
    };
    const createLoadError = (type2, url, name2) => name2 ? `Failed to load ${type2}: ${name2} from url ${url}` : `Failed to load ${type2} url: ${url}`;
    const pluginLoadError = (editor, url, name2) => {
      logError(editor, "PluginLoadError", createLoadError("plugin", url, name2));
    };
    const iconsLoadError = (editor, url, name2) => {
      logError(editor, "IconsLoadError", createLoadError("icons", url, name2));
    };
    const languageLoadError = (editor, url, name2) => {
      logError(editor, "LanguageLoadError", createLoadError("language", url, name2));
    };
    const themeLoadError = (editor, url, name2) => {
      logError(editor, "ThemeLoadError", createLoadError("theme", url, name2));
    };
    const modelLoadError = (editor, url, name2) => {
      logError(editor, "ModelLoadError", createLoadError("model", url, name2));
    };
    const pluginInitError = (editor, name2, err) => {
      const message = I18n.translate([
        "Failed to initialize plugin: {0}",
        name2
      ]);
      fireError(editor, "PluginLoadError", { message });
      initError(message, err);
      displayError(editor, message);
    };
    const initError = (message, ...x) => {
      const console2 = window.console;
      if (console2) {
        if (console2.error) {
          console2.error(message, ...x);
        } else {
          console2.log(message, ...x);
        }
      }
    };
    const isContentCssSkinName = (url) => /^[a-z0-9\-]+$/i.test(url);
    const getContentCssUrls = (editor) => {
      return transformToUrls(editor, getContentCss(editor));
    };
    const getFontCssUrls = (editor) => {
      return transformToUrls(editor, getFontCss(editor));
    };
    const transformToUrls = (editor, cssLinks) => {
      const skinUrl = editor.editorManager.baseURL + "/skins/content";
      const suffix = editor.editorManager.suffix;
      const contentCssFile = `content${suffix}.css`;
      const inline = editor.inline === true;
      return map$3(cssLinks, (url) => {
        if (isContentCssSkinName(url) && !inline) {
          return `${skinUrl}/${url}/${contentCssFile}`;
        } else {
          return editor.documentBaseURI.toAbsolute(url);
        }
      });
    };
    const appendContentCssFromSettings = (editor) => {
      editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
    };
    const filter$1 = always;
    const bind$1 = (element, event, handler) => bind$2(element, event, filter$1, handler);
    const getAllImages = (elm) => {
      return elm ? from(elm.getElementsByTagName("img")) : [];
    };
    const ImageScanner = (uploadStatus, blobCache) => {
      const cachedPromises = {};
      const findAll2 = (elm, predicate = always) => {
        const images = filter$6(getAllImages(elm), (img) => {
          const src = img.src;
          if (img.hasAttribute("data-mce-bogus")) {
            return false;
          }
          if (img.hasAttribute("data-mce-placeholder")) {
            return false;
          }
          if (!src || src === Env.transparentSrc) {
            return false;
          }
          if (startsWith(src, "blob:")) {
            return !uploadStatus.isUploaded(src) && predicate(img);
          }
          if (startsWith(src, "data:")) {
            return predicate(img);
          }
          return false;
        });
        const promises = map$3(images, (img) => {
          const imageSrc = img.src;
          if (has$2(cachedPromises, imageSrc)) {
            return cachedPromises[imageSrc].then((imageInfo) => {
              if (isString(imageInfo)) {
                return imageInfo;
              } else {
                return {
                  image: img,
                  blobInfo: imageInfo.blobInfo
                };
              }
            });
          } else {
            const newPromise = imageToBlobInfo(blobCache, imageSrc).then((blobInfo) => {
              delete cachedPromises[imageSrc];
              return {
                image: img,
                blobInfo
              };
            }).catch((error2) => {
              delete cachedPromises[imageSrc];
              return error2;
            });
            cachedPromises[imageSrc] = newPromise;
            return newPromise;
          }
        });
        return Promise.all(promises);
      };
      return { findAll: findAll2 };
    };
    const UploadStatus = () => {
      const PENDING = 1, UPLOADED = 2;
      let blobUriStatuses = {};
      const createStatus = (status, resultUri) => {
        return {
          status,
          resultUri
        };
      };
      const hasBlobUri = (blobUri) => {
        return blobUri in blobUriStatuses;
      };
      const getResultUri = (blobUri) => {
        const result = blobUriStatuses[blobUri];
        return result ? result.resultUri : null;
      };
      const isPending = (blobUri) => {
        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
      };
      const isUploaded = (blobUri) => {
        return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
      };
      const markPending = (blobUri) => {
        blobUriStatuses[blobUri] = createStatus(PENDING, null);
      };
      const markUploaded = (blobUri, resultUri) => {
        blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
      };
      const removeFailed = (blobUri) => {
        delete blobUriStatuses[blobUri];
      };
      const destroy2 = () => {
        blobUriStatuses = {};
      };
      return {
        hasBlobUri,
        getResultUri,
        isPending,
        isUploaded,
        markPending,
        markUploaded,
        removeFailed,
        destroy: destroy2
      };
    };
    let count = 0;
    const seed = () => {
      const rnd = () => {
        return Math.round(Math.random() * 4294967295).toString(36);
      };
      const now = new Date().getTime();
      return "s" + now.toString(36) + rnd() + rnd() + rnd();
    };
    const uuid2 = (prefix) => {
      return prefix + count++ + seed();
    };
    const BlobCache = () => {
      let cache = [];
      const mimeToExt = (mime) => {
        const mimes = {
          "image/jpeg": "jpg",
          "image/jpg": "jpg",
          "image/gif": "gif",
          "image/png": "png",
          "image/apng": "apng",
          "image/avif": "avif",
          "image/svg+xml": "svg",
          "image/webp": "webp",
          "image/bmp": "bmp",
          "image/tiff": "tiff"
        };
        return mimes[mime.toLowerCase()] || "dat";
      };
      const create2 = (o, blob, base64, name2, filename) => {
        if (isString(o)) {
          const id = o;
          return toBlobInfo({
            id,
            name: name2,
            filename,
            blob,
            base64
          });
        } else if (isObject(o)) {
          return toBlobInfo(o);
        } else {
          throw new Error("Unknown input type");
        }
      };
      const toBlobInfo = (o) => {
        if (!o.blob || !o.base64) {
          throw new Error("blob and base64 representations of the image are required for BlobInfo to be created");
        }
        const id = o.id || uuid2("blobid");
        const name2 = o.name || id;
        const blob = o.blob;
        return {
          id: constant(id),
          name: constant(name2),
          filename: constant(o.filename || name2 + "." + mimeToExt(blob.type)),
          blob: constant(blob),
          base64: constant(o.base64),
          blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
          uri: constant(o.uri)
        };
      };
      const add2 = (blobInfo) => {
        if (!get2(blobInfo.id())) {
          cache.push(blobInfo);
        }
      };
      const findFirst = (predicate) => find$2(cache, predicate).getOrUndefined();
      const get2 = (id) => findFirst((cachedBlobInfo) => cachedBlobInfo.id() === id);
      const getByUri = (blobUri) => findFirst((blobInfo) => blobInfo.blobUri() === blobUri);
      const getByData = (base64, type2) => findFirst((blobInfo) => blobInfo.base64() === base64 && blobInfo.blob().type === type2);
      const removeByUri = (blobUri) => {
        cache = filter$6(cache, (blobInfo) => {
          if (blobInfo.blobUri() === blobUri) {
            URL.revokeObjectURL(blobInfo.blobUri());
            return false;
          }
          return true;
        });
      };
      const destroy2 = () => {
        each$f(cache, (cachedBlobInfo) => {
          URL.revokeObjectURL(cachedBlobInfo.blobUri());
        });
        cache = [];
      };
      return {
        create: create2,
        add: add2,
        get: get2,
        getByUri,
        getByData,
        findFirst,
        removeByUri,
        destroy: destroy2
      };
    };
    const Uploader = (uploadStatus, settings) => {
      const pendingPromises = {};
      const pathJoin = (path1, path2) => {
        if (path1) {
          return path1.replace(/\/$/, "") + "/" + path2.replace(/^\//, "");
        }
        return path2;
      };
      const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
        const xhr = new XMLHttpRequest();
        xhr.open("POST", settings.url);
        xhr.withCredentials = settings.credentials;
        xhr.upload.onprogress = (e) => {
          progress(e.loaded / e.total * 100);
        };
        xhr.onerror = () => {
          failure("Image upload failed due to a XHR Transport error. Code: " + xhr.status);
        };
        xhr.onload = () => {
          if (xhr.status < 200 || xhr.status >= 300) {
            failure("HTTP Error: " + xhr.status);
            return;
          }
          const json = JSON.parse(xhr.responseText);
          if (!json || !isString(json.location)) {
            failure("Invalid JSON: " + xhr.responseText);
            return;
          }
          success(pathJoin(settings.basePath, json.location));
        };
        const formData = new FormData();
        formData.append("file", blobInfo.blob(), blobInfo.filename());
        xhr.send(formData);
      });
      const noUpload = () => new Promise((resolve2) => {
        resolve2([]);
      });
      const handlerSuccess = (blobInfo, url) => ({
        url,
        blobInfo,
        status: true
      });
      const handlerFailure = (blobInfo, error2) => ({
        url: "",
        blobInfo,
        status: false,
        error: error2
      });
      const resolvePending = (blobUri, result) => {
        Tools.each(pendingPromises[blobUri], (resolve2) => {
          resolve2(result);
        });
        delete pendingPromises[blobUri];
      };
      const uploadBlobInfo = (blobInfo, handler, openNotification2) => {
        uploadStatus.markPending(blobInfo.blobUri());
        return new Promise((resolve2) => {
          let notification;
          let progress;
          try {
            const closeNotification = () => {
              if (notification) {
                notification.close();
                progress = noop;
              }
            };
            const success = (url) => {
              closeNotification();
              uploadStatus.markUploaded(blobInfo.blobUri(), url);
              resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
              resolve2(handlerSuccess(blobInfo, url));
            };
            const failure = (error2) => {
              closeNotification();
              uploadStatus.removeFailed(blobInfo.blobUri());
              resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error2));
              resolve2(handlerFailure(blobInfo, error2));
            };
            progress = (percent) => {
              if (percent < 0 || percent > 100) {
                return;
              }
              Optional.from(notification).orThunk(() => Optional.from(openNotification2).map(apply$1)).each((n) => {
                notification = n;
                n.progressBar.value(percent);
              });
            };
            handler(blobInfo, progress).then(success, (err) => {
              failure(isString(err) ? { message: err } : err);
            });
          } catch (ex) {
            resolve2(handlerFailure(blobInfo, ex));
          }
        });
      };
      const isDefaultHandler = (handler) => handler === defaultHandler;
      const pendingUploadBlobInfo = (blobInfo) => {
        const blobUri = blobInfo.blobUri();
        return new Promise((resolve2) => {
          pendingPromises[blobUri] = pendingPromises[blobUri] || [];
          pendingPromises[blobUri].push(resolve2);
        });
      };
      const uploadBlobs = (blobInfos, openNotification2) => {
        blobInfos = Tools.grep(blobInfos, (blobInfo) => !uploadStatus.isUploaded(blobInfo.blobUri()));
        return Promise.all(Tools.map(blobInfos, (blobInfo) => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, settings.handler, openNotification2)));
      };
      const upload = (blobInfos, openNotification2) => !settings.url && isDefaultHandler(settings.handler) ? noUpload() : uploadBlobs(blobInfos, openNotification2);
      if (isFunction(settings.handler) === false) {
        settings.handler = defaultHandler;
      }
      return { upload };
    };
    const openNotification = (editor) => () => editor.notificationManager.open({
      text: editor.translate("Image uploading..."),
      type: "info",
      timeout: -1,
      progressBar: true
    });
    const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
      url: getImageUploadUrl(editor),
      basePath: getImageUploadBasePath(editor),
      credentials: getImagesUploadCredentials(editor),
      handler: getImagesUploadHandler(editor)
    });
    const ImageUploader = (editor) => {
      const uploadStatus = UploadStatus();
      const uploader = createUploader(editor, uploadStatus);
      return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : void 0) };
    };
    const EditorUpload = (editor) => {
      const blobCache = BlobCache();
      let uploader, imageScanner;
      const uploadStatus = UploadStatus();
      const urlFilters = [];
      const aliveGuard = (callback) => {
        return (result) => {
          if (editor.selection) {
            return callback(result);
          }
          return [];
        };
      };
      const cacheInvalidator = (url) => url + (url.indexOf("?") === -1 ? "?" : "&") + new Date().getTime();
      const replaceString = (content, search2, replace) => {
        let index2 = 0;
        do {
          index2 = content.indexOf(search2, index2);
          if (index2 !== -1) {
            content = content.substring(0, index2) + replace + content.substr(index2 + search2.length);
            index2 += replace.length - search2.length + 1;
          }
        } while (index2 !== -1);
        return content;
      };
      const replaceImageUrl = (content, targetUrl, replacementUrl) => {
        const replacementString = `src="${replacementUrl}"${replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : ""}`;
        content = replaceString(content, `src="${targetUrl}"`, replacementString);
        content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
        return content;
      };
      const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
        each$f(editor.undoManager.data, (level) => {
          if (level.type === "fragmented") {
            level.fragments = map$3(level.fragments, (fragment) => replaceImageUrl(fragment, targetUrl, replacementUrl));
          } else {
            level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
          }
        });
      };
      const replaceImageUriInView = (image, resultUri) => {
        const src = editor.convertURL(resultUri, "src");
        replaceUrlInUndoStack(image.src, resultUri);
        setAll$1(SugarElement.fromDom(image), {
          "src": shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
          "data-mce-src": src
        });
      };
      const uploadImages = () => {
        if (!uploader) {
          uploader = createUploader(editor, uploadStatus);
        }
        return scanForImages().then(aliveGuard((imageInfos) => {
          const blobInfos = map$3(imageInfos, (imageInfo) => imageInfo.blobInfo);
          return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard((result) => {
            const imagesToRemove = [];
            let shouldDispatchChange = false;
            const filteredResult = map$3(result, (uploadInfo, index2) => {
              const blobInfo = imageInfos[index2].blobInfo;
              const image = imageInfos[index2].image;
              let removed = false;
              if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
                if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
                  shouldDispatchChange = true;
                }
                blobCache.removeByUri(image.src);
                if (isRtc(editor))
                  ;
                else {
                  replaceImageUriInView(image, uploadInfo.url);
                }
              } else if (uploadInfo.error) {
                if (uploadInfo.error.remove) {
                  replaceUrlInUndoStack(image.getAttribute("src"), Env.transparentSrc);
                  imagesToRemove.push(image);
                  removed = true;
                }
                uploadError(editor, uploadInfo.error.message);
              }
              return {
                element: image,
                status: uploadInfo.status,
                uploadUri: uploadInfo.url,
                blobInfo,
                removed
              };
            });
            if (imagesToRemove.length > 0 && !isRtc(editor)) {
              editor.undoManager.transact(() => {
                each$f(imagesToRemove, (element) => {
                  editor.dom.remove(element);
                  blobCache.removeByUri(element.src);
                });
              });
            } else if (shouldDispatchChange) {
              editor.undoManager.dispatchChange();
            }
            return filteredResult;
          }));
        }));
      };
      const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
      const isValidDataUriImage = (imgElm) => forall(urlFilters, (filter2) => filter2(imgElm));
      const addFilter = (filter2) => {
        urlFilters.push(filter2);
      };
      const scanForImages = () => {
        if (!imageScanner) {
          imageScanner = ImageScanner(uploadStatus, blobCache);
        }
        return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard((result) => {
          const filteredResult = filter$6(result, (resultItem) => {
            if (isString(resultItem)) {
              displayError(editor, resultItem);
              return false;
            } else {
              return true;
            }
          });
          if (isRtc(editor))
            ;
          else {
            each$f(filteredResult, (resultItem) => {
              replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
              resultItem.image.src = resultItem.blobInfo.blobUri();
              resultItem.image.removeAttribute("data-mce-src");
            });
          }
          return filteredResult;
        }));
      };
      const destroy2 = () => {
        blobCache.destroy();
        uploadStatus.destroy();
        imageScanner = uploader = null;
      };
      const replaceBlobUris = (content) => {
        return content.replace(/src="(blob:[^"]+)"/g, (match2, blobUri) => {
          const resultUri = uploadStatus.getResultUri(blobUri);
          if (resultUri) {
            return 'src="' + resultUri + '"';
          }
          let blobInfo = blobCache.getByUri(blobUri);
          if (!blobInfo) {
            blobInfo = foldl(editor.editorManager.get(), (result, editor2) => {
              return result || editor2.editorUpload && editor2.editorUpload.blobCache.getByUri(blobUri);
            }, null);
          }
          if (blobInfo) {
            const blob = blobInfo.blob();
            return 'src="data:' + blob.type + ";base64," + blobInfo.base64() + '"';
          }
          return match2;
        });
      };
      editor.on("SetContent", () => {
        if (isAutomaticUploadsEnabled(editor)) {
          uploadImagesAuto();
        } else {
          scanForImages();
        }
      });
      editor.on("RawSaveContent", (e) => {
        e.content = replaceBlobUris(e.content);
      });
      editor.on("GetContent", (e) => {
        if (e.source_view || e.format === "raw" || e.format === "tree") {
          return;
        }
        e.content = replaceBlobUris(e.content);
      });
      editor.on("PostRender", () => {
        editor.parser.addNodeFilter("img", (images) => {
          each$f(images, (img) => {
            const src = img.attr("src");
            if (blobCache.getByUri(src)) {
              return;
            }
            const resultUri = uploadStatus.getResultUri(src);
            if (resultUri) {
              img.attr("src", resultUri);
            }
          });
        });
      });
      return {
        blobCache,
        addFilter,
        uploadImages,
        uploadImagesAuto,
        scanForImages,
        destroy: destroy2
      };
    };
    const get$1 = (editor) => {
      const dom2 = editor.dom;
      const schemaType = editor.schema.type;
      const formats = {
        valigntop: [{
          selector: "td,th",
          styles: { verticalAlign: "top" }
        }],
        valignmiddle: [{
          selector: "td,th",
          styles: { verticalAlign: "middle" }
        }],
        valignbottom: [{
          selector: "td,th",
          styles: { verticalAlign: "bottom" }
        }],
        alignleft: [
          {
            selector: "figure.image",
            collapsed: false,
            classes: "align-left",
            ceFalseOverride: true,
            preview: "font-family font-size"
          },
          {
            selector: "figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",
            styles: { textAlign: "left" },
            inherit: false,
            preview: false
          },
          {
            selector: "img,audio,video",
            collapsed: false,
            styles: { float: "left" },
            preview: "font-family font-size"
          },
          {
            selector: "table",
            collapsed: false,
            styles: {
              marginLeft: "0px",
              marginRight: "auto"
            },
            onformat: (table2) => {
              dom2.setStyle(table2, "float", null);
            },
            preview: "font-family font-size"
          }
        ],
        aligncenter: [
          {
            selector: "figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",
            styles: { textAlign: "center" },
            inherit: false,
            preview: "font-family font-size"
          },
          {
            selector: "figure.image",
            collapsed: false,
            classes: "align-center",
            ceFalseOverride: true,
            preview: "font-family font-size"
          },
          {
            selector: "img,audio,video",
            collapsed: false,
            styles: {
              display: "block",
              marginLeft: "auto",
              marginRight: "auto"
            },
            preview: false
          },
          {
            selector: "table",
            collapsed: false,
            styles: {
              marginLeft: "auto",
              marginRight: "auto"
            },
            preview: "font-family font-size"
          }
        ],
        alignright: [
          {
            selector: "figure.image",
            collapsed: false,
            classes: "align-right",
            ceFalseOverride: true,
            preview: "font-family font-size"
          },
          {
            selector: "figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",
            styles: { textAlign: "right" },
            inherit: false,
            preview: "font-family font-size"
          },
          {
            selector: "img,audio,video",
            collapsed: false,
            styles: { float: "right" },
            preview: "font-family font-size"
          },
          {
            selector: "table",
            collapsed: false,
            styles: {
              marginRight: "0px",
              marginLeft: "auto"
            },
            onformat: (table2) => {
              dom2.setStyle(table2, "float", null);
            },
            preview: "font-family font-size"
          }
        ],
        alignjustify: [{
          selector: "figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre",
          styles: { textAlign: "justify" },
          inherit: false,
          preview: "font-family font-size"
        }],
        bold: [
          {
            inline: "strong",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          },
          {
            inline: "span",
            styles: { fontWeight: "bold" }
          },
          {
            inline: "b",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          }
        ],
        italic: [
          {
            inline: "em",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          },
          {
            inline: "span",
            styles: { fontStyle: "italic" }
          },
          {
            inline: "i",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          }
        ],
        underline: [
          {
            inline: "span",
            styles: { textDecoration: "underline" },
            exact: true
          },
          {
            inline: "u",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          }
        ],
        strikethrough: (() => {
          const span = {
            inline: "span",
            styles: { textDecoration: "line-through" },
            exact: true
          };
          const strike = {
            inline: "strike",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          };
          const s = {
            inline: "s",
            remove: "all",
            preserve_attributes: [
              "class",
              "style"
            ]
          };
          return schemaType !== "html4" ? [
            s,
            span,
            strike
          ] : [
            span,
            s,
            strike
          ];
        })(),
        forecolor: {
          inline: "span",
          styles: { color: "%value" },
          links: true,
          remove_similar: true,
          clear_child_styles: true
        },
        hilitecolor: {
          inline: "span",
          styles: { backgroundColor: "%value" },
          links: true,
          remove_similar: true,
          clear_child_styles: true
        },
        fontname: {
          inline: "span",
          toggle: false,
          styles: { fontFamily: "%value" },
          clear_child_styles: true
        },
        fontsize: {
          inline: "span",
          toggle: false,
          styles: { fontSize: "%value" },
          clear_child_styles: true
        },
        lineheight: {
          selector: "h1,h2,h3,h4,h5,h6,p,li,td,th,div",
          styles: { lineHeight: "%value" }
        },
        fontsize_class: {
          inline: "span",
          attributes: { class: "%value" }
        },
        blockquote: {
          block: "blockquote",
          wrapper: true,
          remove: "all"
        },
        subscript: { inline: "sub" },
        superscript: { inline: "sup" },
        code: { inline: "code" },
        link: {
          inline: "a",
          selector: "a",
          remove: "all",
          split: true,
          deep: true,
          onmatch: (node, _fmt, _itemName) => {
            return isElement$6(node) && node.hasAttribute("href");
          },
          onformat: (elm, _fmt, vars) => {
            Tools.each(vars, (value2, key) => {
              dom2.setAttrib(elm, key, value2);
            });
          }
        },
        lang: {
          inline: "span",
          clear_child_styles: true,
          remove_similar: true,
          attributes: {
            "lang": "%value",
            "data-mce-lang": (vars) => {
              var _a;
              return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
            }
          }
        },
        removeformat: [
          {
            selector: "b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small",
            remove: "all",
            split: true,
            expand: false,
            block_expand: true,
            deep: true
          },
          {
            selector: "span",
            attributes: [
              "style",
              "class"
            ],
            remove: "empty",
            split: true,
            expand: false,
            deep: true
          },
          {
            selector: "*",
            attributes: [
              "style",
              "class"
            ],
            split: false,
            expand: false,
            deep: true
          }
        ]
      };
      Tools.each("p h1 h2 h3 h4 h5 h6 div address pre dt dd samp".split(/\s/), (name2) => {
        formats[name2] = {
          block: name2,
          remove: "all"
        };
      });
      return formats;
    };
    const genericBase = {
      remove_similar: true,
      inherit: false
    };
    const cellBase = {
      selector: "td,th",
      ...genericBase
    };
    const cellFormats = {
      tablecellbackgroundcolor: {
        styles: { backgroundColor: "%value" },
        ...cellBase
      },
      tablecellverticalalign: {
        styles: { "vertical-align": "%value" },
        ...cellBase
      },
      tablecellbordercolor: {
        styles: { borderColor: "%value" },
        ...cellBase
      },
      tablecellclass: {
        classes: ["%value"],
        ...cellBase
      },
      tableclass: {
        selector: "table",
        classes: ["%value"],
        ...genericBase
      },
      tablecellborderstyle: {
        styles: { borderStyle: "%value" },
        ...cellBase
      },
      tablecellborderwidth: {
        styles: { borderWidth: "%value" },
        ...cellBase
      }
    };
    const get = constant(cellFormats);
    const FormatRegistry = (editor) => {
      const formats = {};
      const get$22 = (name2) => isNonNullable(name2) ? formats[name2] : formats;
      const has2 = (name2) => has$2(formats, name2);
      const register2 = (name2, format) => {
        if (name2) {
          if (!isString(name2)) {
            each$e(name2, (format2, name3) => {
              register2(name3, format2);
            });
          } else {
            if (!isArray$1(format)) {
              format = [format];
            }
            each$f(format, (format2) => {
              if (isUndefined(format2.deep)) {
                format2.deep = !isSelectorFormat(format2);
              }
              if (isUndefined(format2.split)) {
                format2.split = !isSelectorFormat(format2) || isInlineFormat(format2);
              }
              if (isUndefined(format2.remove) && isSelectorFormat(format2) && !isInlineFormat(format2)) {
                format2.remove = "none";
              }
              if (isSelectorFormat(format2) && isInlineFormat(format2)) {
                format2.mixed = true;
                format2.block_expand = true;
              }
              if (isString(format2.classes)) {
                format2.classes = format2.classes.split(/\s+/);
              }
            });
            formats[name2] = format;
          }
        }
      };
      const unregister = (name2) => {
        if (name2 && formats[name2]) {
          delete formats[name2];
        }
        return formats;
      };
      register2(get$1(editor));
      register2(get());
      register2(getFormats(editor));
      return {
        get: get$22,
        has: has2,
        register: register2,
        unregister
      };
    };
    const each$3 = Tools.each;
    const dom = DOMUtils.DOM;
    const parsedSelectorToHtml = (ancestry, editor) => {
      let elm, item, fragment;
      const schema = editor && editor.schema || Schema({});
      const decorate = (elm2, item2) => {
        if (item2.classes.length) {
          dom.addClass(elm2, item2.classes.join(" "));
        }
        dom.setAttribs(elm2, item2.attrs);
      };
      const createElement = (sItem) => {
        item = typeof sItem === "string" ? {
          name: sItem,
          classes: [],
          attrs: {}
        } : sItem;
        const elm2 = dom.create(item.name);
        decorate(elm2, item);
        return elm2;
      };
      const getRequiredParent = (elm2, candidate) => {
        const name2 = typeof elm2 !== "string" ? elm2.nodeName.toLowerCase() : elm2;
        const elmRule = schema.getElementRule(name2);
        const parentsRequired = elmRule && elmRule.parentsRequired;
        if (parentsRequired && parentsRequired.length) {
          return candidate && Tools.inArray(parentsRequired, candidate) !== -1 ? candidate : parentsRequired[0];
        } else {
          return false;
        }
      };
      const wrapInHtml = (elm2, ancestry2, siblings2) => {
        let parent2, parentCandidate;
        const ancestor2 = ancestry2.length > 0 && ancestry2[0];
        const ancestorName = ancestor2 && ancestor2.name;
        const parentRequired = getRequiredParent(elm2, ancestorName);
        if (parentRequired) {
          if (ancestorName === parentRequired) {
            parentCandidate = ancestry2[0];
            ancestry2 = ancestry2.slice(1);
          } else {
            parentCandidate = parentRequired;
          }
        } else if (ancestor2) {
          parentCandidate = ancestry2[0];
          ancestry2 = ancestry2.slice(1);
        } else if (!siblings2) {
          return elm2;
        }
        if (parentCandidate) {
          parent2 = createElement(parentCandidate);
          parent2.appendChild(elm2);
        }
        if (siblings2) {
          if (!parent2) {
            parent2 = dom.create("div");
            parent2.appendChild(elm2);
          }
          Tools.each(siblings2, (sibling2) => {
            const siblingElm = createElement(sibling2);
            parent2.insertBefore(siblingElm, elm2);
          });
        }
        return wrapInHtml(parent2, ancestry2, parentCandidate && parentCandidate.siblings);
      };
      if (ancestry && ancestry.length) {
        item = ancestry[0];
        elm = createElement(item);
        fragment = dom.create("div");
        fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), item.siblings));
        return fragment;
      } else {
        return "";
      }
    };
    const parseSelectorItem = (item) => {
      let tagName;
      const obj = {
        classes: [],
        attrs: {}
      };
      item = obj.selector = Tools.trim(item);
      if (item !== "*") {
        tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
          switch ($1) {
            case "#":
              obj.attrs.id = $2;
              break;
            case ".":
              obj.classes.push($2);
              break;
            case ":":
              if (Tools.inArray("checked disabled enabled read-only required".split(" "), $2) !== -1) {
                obj.attrs[$2] = $2;
              }
              break;
          }
          if ($3 === "[") {
            const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
            if (m) {
              obj.attrs[m[1]] = m[2];
            }
          }
          return "";
        });
      }
      obj.name = tagName || "div";
      return obj;
    };
    const parseSelector = (selector) => {
      if (!selector || typeof selector !== "string") {
        return [];
      }
      selector = selector.split(/\s*,\s*/)[0];
      selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, "$1");
      return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), (item) => {
        const siblings2 = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
        const obj = siblings2.pop();
        if (siblings2.length) {
          obj.siblings = siblings2;
        }
        return obj;
      }).reverse();
    };
    const getCssText = (editor, format) => {
      let name2, previewFrag;
      let previewCss = "", parentFontSize;
      let previewStyles = getPreviewStyles(editor);
      if (previewStyles === "") {
        return "";
      }
      const removeVars = (val) => {
        return val.replace(/%(\w+)/g, "");
      };
      if (typeof format === "string") {
        format = editor.formatter.get(format);
        if (!format) {
          return;
        }
        format = format[0];
      }
      if ("preview" in format) {
        const previewOpt = get$a(format, "preview");
        if (is$2(previewOpt, false)) {
          return "";
        } else {
          previewStyles = previewOpt.getOr(previewStyles);
        }
      }
      name2 = format.block || format.inline || "span";
      const items = parseSelector(format.selector);
      if (items.length) {
        if (!items[0].name) {
          items[0].name = name2;
        }
        name2 = format.selector;
        previewFrag = parsedSelectorToHtml(items, editor);
      } else {
        previewFrag = parsedSelectorToHtml([name2], editor);
      }
      const previewElm = dom.select(name2, previewFrag)[0] || previewFrag.firstChild;
      each$3(format.styles, (value2, name3) => {
        const newValue = removeVars(value2);
        if (newValue) {
          dom.setStyle(previewElm, name3, newValue);
        }
      });
      each$3(format.attributes, (value2, name3) => {
        const newValue = removeVars(value2);
        if (newValue) {
          dom.setAttrib(previewElm, name3, newValue);
        }
      });
      each$3(format.classes, (value2) => {
        const newValue = removeVars(value2);
        if (!dom.hasClass(previewElm, newValue)) {
          dom.addClass(previewElm, newValue);
        }
      });
      editor.dispatch("PreviewFormats");
      dom.setStyles(previewFrag, {
        position: "absolute",
        left: -65535
      });
      editor.getBody().appendChild(previewFrag);
      parentFontSize = dom.getStyle(editor.getBody(), "fontSize", true);
      parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
      each$3(previewStyles.split(" "), (name3) => {
        let value2 = dom.getStyle(previewElm, name3, true);
        if (name3 === "background-color" && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value2)) {
          value2 = dom.getStyle(editor.getBody(), name3, true);
          if (rgbaToHexString(value2).toLowerCase() === "#ffffff") {
            return;
          }
        }
        if (name3 === "color") {
          if (rgbaToHexString(value2).toLowerCase() === "#000000") {
            return;
          }
        }
        if (name3 === "font-size") {
          if (/em|%$/.test(value2)) {
            if (parentFontSize === 0) {
              return;
            }
            const numValue = parseFloat(value2) / (/%$/.test(value2) ? 100 : 1);
            value2 = numValue * parentFontSize + "px";
          }
        }
        if (name3 === "border" && value2) {
          previewCss += "padding:0 2px;";
        }
        previewCss += name3 + ":" + value2 + ";";
      });
      editor.dispatch("AfterPreviewFormats");
      dom.remove(previewFrag);
      return previewCss;
    };
    const setup$r = (editor) => {
      editor.addShortcut("meta+b", "", "Bold");
      editor.addShortcut("meta+i", "", "Italic");
      editor.addShortcut("meta+u", "", "Underline");
      for (let i = 1; i <= 6; i++) {
        editor.addShortcut("access+" + i, "", [
          "FormatBlock",
          false,
          "h" + i
        ]);
      }
      editor.addShortcut("access+7", "", [
        "FormatBlock",
        false,
        "p"
      ]);
      editor.addShortcut("access+8", "", [
        "FormatBlock",
        false,
        "div"
      ]);
      editor.addShortcut("access+9", "", [
        "FormatBlock",
        false,
        "address"
      ]);
    };
    const Formatter = (editor) => {
      const formats = FormatRegistry(editor);
      const formatChangeState = Cell(null);
      setup$r(editor);
      setup$u(editor);
      return {
        get: formats.get,
        has: formats.has,
        register: formats.register,
        unregister: formats.unregister,
        apply: (name2, vars, node) => {
          applyFormat(editor, name2, vars, node);
        },
        remove: (name2, vars, node, similar) => {
          removeFormat(editor, name2, vars, node, similar);
        },
        toggle: (name2, vars, node) => {
          toggleFormat(editor, name2, vars, node);
        },
        match: (name2, vars, node, similar) => matchFormat(editor, name2, vars, node, similar),
        closest: (names) => closestFormat(editor, names),
        matchAll: (names, vars) => matchAllFormats(editor, names, vars),
        matchNode: (node, name2, vars, similar) => matchNodeFormat(editor, node, name2, vars, similar),
        canApply: (name2) => canApplyFormat(editor, name2),
        formatChanged: (formats2, callback, similar, vars) => formatChanged(editor, formatChangeState, formats2, callback, similar, vars),
        getCssText: curry(getCssText, editor)
      };
    };
    const shouldIgnoreCommand = (cmd) => {
      switch (cmd.toLowerCase()) {
        case "undo":
        case "redo":
        case "mcefocus":
          return true;
        default:
          return false;
      }
    };
    const registerEvents = (editor, undoManager, locks) => {
      const isFirstTypedCharacter = Cell(false);
      const addNonTypingUndoLevel = (e) => {
        setTyping(undoManager, false, locks);
        undoManager.add({}, e);
      };
      editor.on("init", () => {
        undoManager.add();
      });
      editor.on("BeforeExecCommand", (e) => {
        const cmd = e.command;
        if (!shouldIgnoreCommand(cmd)) {
          endTyping(undoManager, locks);
          undoManager.beforeChange();
        }
      });
      editor.on("ExecCommand", (e) => {
        const cmd = e.command;
        if (!shouldIgnoreCommand(cmd)) {
          addNonTypingUndoLevel(e);
        }
      });
      editor.on("ObjectResizeStart cut", () => {
        undoManager.beforeChange();
      });
      editor.on("SaveContent ObjectResized blur", addNonTypingUndoLevel);
      editor.on("dragend", addNonTypingUndoLevel);
      editor.on("keyup", (e) => {
        const keyCode = e.keyCode;
        if (e.isDefaultPrevented()) {
          return;
        }
        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey) {
          addNonTypingUndoLevel();
          editor.nodeChanged();
        }
        if (keyCode === 46 || keyCode === 8) {
          editor.nodeChanged();
        }
        if (isFirstTypedCharacter.get() && undoManager.typing && isEq$1(createFromEditor(editor), undoManager.data[0]) === false) {
          if (editor.isDirty() === false) {
            editor.setDirty(true);
          }
          editor.dispatch("TypingUndo");
          isFirstTypedCharacter.set(false);
          editor.nodeChanged();
        }
      });
      editor.on("keydown", (e) => {
        const keyCode = e.keyCode;
        if (e.isDefaultPrevented()) {
          return;
        }
        if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
          if (undoManager.typing) {
            addNonTypingUndoLevel(e);
          }
          return;
        }
        const modKey = e.ctrlKey && !e.altKey || e.metaKey;
        if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
          undoManager.beforeChange();
          setTyping(undoManager, true, locks);
          undoManager.add({}, e);
          isFirstTypedCharacter.set(true);
        }
      });
      editor.on("mousedown", (e) => {
        if (undoManager.typing) {
          addNonTypingUndoLevel(e);
        }
      });
      const isInsertReplacementText = (event) => event.inputType === "insertReplacementText";
      const isInsertTextDataNull = (event) => event.inputType === "insertText" && event.data === null;
      const isInsertFromPasteOrDrop = (event) => event.inputType === "insertFromPaste" || event.inputType === "insertFromDrop";
      editor.on("input", (e) => {
        if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
          addNonTypingUndoLevel(e);
        }
      });
      editor.on("AddUndo Undo Redo ClearUndos", (e) => {
        if (!e.isDefaultPrevented()) {
          editor.nodeChanged();
        }
      });
    };
    const addKeyboardShortcuts = (editor) => {
      editor.addShortcut("meta+z", "", "Undo");
      editor.addShortcut("meta+y,meta+shift+z", "", "Redo");
    };
    const UndoManager = (editor) => {
      const beforeBookmark = value$2();
      const locks = Cell(0);
      const index2 = Cell(0);
      const undoManager = {
        data: [],
        typing: false,
        beforeChange: () => {
          beforeChange(editor, locks, beforeBookmark);
        },
        add: (level, event) => {
          return addUndoLevel(editor, undoManager, index2, locks, beforeBookmark, level, event);
        },
        dispatchChange: () => {
          editor.setDirty(true);
          editor.dispatch("change", {
            level: createFromEditor(editor),
            lastLevel: get$b(undoManager.data, index2.get()).getOrUndefined()
          });
        },
        undo: () => {
          return undo(editor, undoManager, locks, index2);
        },
        redo: () => {
          return redo(editor, index2, undoManager.data);
        },
        clear: () => {
          clear(editor, undoManager, index2);
        },
        reset: () => {
          reset(editor, undoManager);
        },
        hasUndo: () => {
          return hasUndo(editor, undoManager, index2);
        },
        hasRedo: () => {
          return hasRedo(editor, undoManager, index2);
        },
        transact: (callback) => {
          return transact(editor, undoManager, locks, callback);
        },
        ignore: (callback) => {
          ignore(editor, locks, callback);
        },
        extra: (callback1, callback2) => {
          extra(editor, undoManager, index2, callback1, callback2);
        }
      };
      if (!isRtc(editor)) {
        registerEvents(editor, undoManager, locks);
      }
      addKeyboardShortcuts(editor);
      return undoManager;
    };
    const nonTypingKeycodes = [
      9,
      27,
      VK.HOME,
      VK.END,
      19,
      20,
      44,
      144,
      145,
      33,
      34,
      45,
      16,
      17,
      18,
      91,
      92,
      93,
      VK.DOWN,
      VK.UP,
      VK.LEFT,
      VK.RIGHT
    ].concat(Env.browser.isFirefox() ? [224] : []);
    const placeholderAttr = "data-mce-placeholder";
    const isKeyboardEvent = (e) => e.type === "keydown" || e.type === "keyup";
    const isDeleteEvent = (e) => {
      const keyCode = e.keyCode;
      return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
    };
    const isNonTypingKeyboardEvent = (e) => {
      if (isKeyboardEvent(e)) {
        const keyCode = e.keyCode;
        return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
      } else {
        return false;
      }
    };
    const isTypingKeyboardEvent = (e) => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === "keyup" && e.keyCode === 229);
    const isVisuallyEmpty = (dom2, rootElm, forcedRootBlock) => {
      if (isEmpty$2(SugarElement.fromDom(rootElm), false)) {
        const firstElement2 = rootElm.firstElementChild;
        if (!firstElement2) {
          return true;
        } else if (dom2.getStyle(rootElm.firstElementChild, "padding-left") || dom2.getStyle(rootElm.firstElementChild, "padding-right")) {
          return false;
        } else {
          return forcedRootBlock === firstElement2.nodeName.toLowerCase();
        }
      } else {
        return false;
      }
    };
    const setup$q = (editor) => {
      const dom2 = editor.dom;
      const rootBlock = getForcedRootBlock(editor);
      const placeholder = getPlaceholder(editor);
      const updatePlaceholder = (e, initial) => {
        if (isNonTypingKeyboardEvent(e)) {
          return;
        }
        const body = editor.getBody();
        const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom2, body, rootBlock);
        const isPlaceholderShown = dom2.getAttrib(body, placeholderAttr) !== "";
        if (isPlaceholderShown !== showPlaceholder || initial) {
          dom2.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
          dom2.setAttrib(body, "aria-placeholder", showPlaceholder ? placeholder : null);
          firePlaceholderToggle(editor, showPlaceholder);
          editor.on(showPlaceholder ? "keydown" : "keyup", updatePlaceholder);
          editor.off(showPlaceholder ? "keyup" : "keydown", updatePlaceholder);
        }
      };
      if (placeholder) {
        editor.on("init", (e) => {
          updatePlaceholder(e, true);
          editor.on("change SetContent ExecCommand", updatePlaceholder);
          editor.on("paste", (e2) => Delay.setEditorTimeout(editor, () => updatePlaceholder(e2)));
        });
      }
    };
    const blockPosition = (block, position) => ({
      block,
      position
    });
    const blockBoundary = (from2, to2) => ({
      from: from2,
      to: to2
    });
    const getBlockPosition = (rootNode, pos) => {
      const rootElm = SugarElement.fromDom(rootNode);
      const containerElm = SugarElement.fromDom(pos.container());
      return getParentBlock$2(rootElm, containerElm).map((block) => blockPosition(block, pos));
    };
    const isDifferentBlocks = (blockBoundary2) => eq(blockBoundary2.from.block, blockBoundary2.to.block) === false;
    const hasSameParent = (blockBoundary2) => parent(blockBoundary2.from.block).bind((parent1) => parent(blockBoundary2.to.block).filter((parent2) => eq(parent1, parent2))).isSome();
    const isEditable$2 = (blockBoundary2) => isContentEditableFalse$b(blockBoundary2.from.block.dom) === false && isContentEditableFalse$b(blockBoundary2.to.block.dom) === false;
    const skipLastBr = (rootNode, forward, blockPosition2) => {
      if (isBr$6(blockPosition2.position.getNode()) && isEmpty$2(blockPosition2.block) === false) {
        return positionIn(false, blockPosition2.block.dom).bind((lastPositionInBlock) => {
          if (lastPositionInBlock.isEqual(blockPosition2.position)) {
            return fromPosition(forward, rootNode, lastPositionInBlock).bind((to2) => getBlockPosition(rootNode, to2));
          } else {
            return Optional.some(blockPosition2);
          }
        }).getOr(blockPosition2);
      } else {
        return blockPosition2;
      }
    };
    const readFromRange = (rootNode, forward, rng) => {
      const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
      const toBlockPos = fromBlockPos.bind((blockPos) => fromPosition(forward, rootNode, blockPos.position).bind((to2) => getBlockPosition(rootNode, to2).map((blockPos2) => skipLastBr(rootNode, forward, blockPos2))));
      return lift2(fromBlockPos, toBlockPos, blockBoundary).filter((blockBoundary2) => isDifferentBlocks(blockBoundary2) && hasSameParent(blockBoundary2) && isEditable$2(blockBoundary2));
    };
    const read$1 = (rootNode, forward, rng) => rng.collapsed ? readFromRange(rootNode, forward, rng) : Optional.none();
    const getChildrenUntilBlockBoundary = (block) => {
      const children$1 = children(block);
      return findIndex$2(children$1, isBlock$2).fold(constant(children$1), (index2) => children$1.slice(0, index2));
    };
    const extractChildren = (block) => {
      const children2 = getChildrenUntilBlockBoundary(block);
      each$f(children2, remove$6);
      return children2;
    };
    const removeEmptyRoot = (rootNode, block) => {
      const parents2 = parentsAndSelf(block, rootNode);
      return find$2(parents2.reverse(), (element) => isEmpty$2(element)).each(remove$6);
    };
    const isEmptyBefore = (el) => filter$6(prevSiblings(el), (el2) => !isEmpty$2(el2)).length === 0;
    const nestedBlockMerge = (rootNode, fromBlock, toBlock, insertionPoint) => {
      if (isEmpty$2(toBlock)) {
        fillWithPaddingBr(toBlock);
        return firstPositionIn(toBlock.dom);
      }
      if (isEmptyBefore(insertionPoint) && isEmpty$2(fromBlock)) {
        before$3(insertionPoint, SugarElement.fromTag("br"));
      }
      const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
      each$f(extractChildren(fromBlock), (child2) => {
        before$3(insertionPoint, child2);
      });
      removeEmptyRoot(rootNode, fromBlock);
      return position;
    };
    const sidelongBlockMerge = (rootNode, fromBlock, toBlock) => {
      if (isEmpty$2(toBlock)) {
        remove$6(toBlock);
        if (isEmpty$2(fromBlock)) {
          fillWithPaddingBr(fromBlock);
        }
        return firstPositionIn(fromBlock.dom);
      }
      const position = lastPositionIn(toBlock.dom);
      each$f(extractChildren(fromBlock), (child2) => {
        append$1(toBlock, child2);
      });
      removeEmptyRoot(rootNode, fromBlock);
      return position;
    };
    const findInsertionPoint = (toBlock, block) => {
      const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
      return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
    };
    const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
    const trimBr = (first2, block) => {
      positionIn(first2, block.dom).map((position) => position.getNode()).map(SugarElement.fromDom).filter(isBr$5).each(remove$6);
    };
    const mergeBlockInto = (rootNode, fromBlock, toBlock) => {
      trimBr(true, fromBlock);
      trimBr(false, toBlock);
      return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock), curry(nestedBlockMerge, rootNode, fromBlock, toBlock));
    };
    const mergeBlocks = (rootNode, forward, block1, block2) => forward ? mergeBlockInto(rootNode, block2, block1) : mergeBlockInto(rootNode, block1, block2);
    const backspaceDelete$8 = (editor, forward) => {
      const rootNode = SugarElement.fromDom(editor.getBody());
      const position = read$1(rootNode.dom, forward, editor.selection.getRng()).map((blockBoundary2) => () => {
        mergeBlocks(rootNode, forward, blockBoundary2.from.block, blockBoundary2.to.block).each((pos) => {
          editor.selection.setRng(pos.toRange());
        });
      });
      return position;
    };
    const deleteRangeMergeBlocks = (rootNode, selection) => {
      const rng = selection.getRng();
      return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
        if (eq(block1, block2) === false) {
          return Optional.some(() => {
            rng.deleteContents();
            mergeBlocks(rootNode, true, block1, block2).each((pos) => {
              selection.setRng(pos.toRange());
            });
          });
        } else {
          return Optional.none();
        }
      }).getOr(Optional.none());
    };
    const isRawNodeInTable = (root, rawNode) => {
      const node = SugarElement.fromDom(rawNode);
      const isRoot2 = curry(eq, root);
      return ancestor$3(node, isTableCell$4, isRoot2).isSome();
    };
    const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
    const isEverythingSelected = (root, rng) => {
      const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
      const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
      return !isSelectionInTable(root, rng) && noPrevious && noNext;
    };
    const emptyEditor = (editor) => {
      return Optional.some(() => {
        editor.setContent("");
        editor.selection.setCursorLocation();
      });
    };
    const deleteRange$1 = (editor) => {
      const rootNode = SugarElement.fromDom(editor.getBody());
      const rng = editor.selection.getRng();
      return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection);
    };
    const backspaceDelete$7 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$1(editor);
    const isContentEditableTrue$2 = isContentEditableTrue$5;
    const isContentEditableFalse$5 = isContentEditableFalse$b;
    const showCaret = (direction, editor, node, before2, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before2, scrollIntoView));
    const getNodeRange = (node) => {
      const rng = node.ownerDocument.createRange();
      rng.selectNode(node);
      return rng;
    };
    const selectNode = (editor, node) => {
      const e = editor.dispatch("BeforeObjectSelected", { target: node });
      if (e.isDefaultPrevented()) {
        return Optional.none();
      }
      return Optional.some(getNodeRange(node));
    };
    const renderCaretAtRange = (editor, range2, scrollIntoView) => {
      const normalizedRange = normalizeRange(1, editor.getBody(), range2);
      const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
      const caretPositionNode = caretPosition.getNode();
      if (isInlineFakeCaretTarget(caretPositionNode)) {
        return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
      }
      const caretPositionBeforeNode = caretPosition.getNode(true);
      if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
        return showCaret(1, editor, caretPositionBeforeNode, false, false);
      }
      const ceRoot = editor.dom.getParent(caretPosition.getNode(), (node) => isContentEditableFalse$5(node) || isContentEditableTrue$2(node));
      if (isInlineFakeCaretTarget(ceRoot)) {
        return showCaret(1, editor, ceRoot, false, scrollIntoView);
      }
      return Optional.none();
    };
    const renderRangeCaret = (editor, range2, scrollIntoView) => range2.collapsed ? renderCaretAtRange(editor, range2, scrollIntoView).getOr(range2) : range2;
    const isBeforeBoundary = (pos) => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
    const isAfterBoundary = (pos) => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
    const trimEmptyTextNode = (dom2, node) => {
      if (isText$9(node) && node.data.length === 0) {
        dom2.remove(node);
      }
    };
    const deleteContentAndShowCaret = (editor, range2, node, direction, forward, peekCaretPosition) => {
      showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each((caretRange) => {
        if (range2.collapsed) {
          const deleteRange2 = range2.cloneRange();
          if (forward) {
            deleteRange2.setEnd(caretRange.startContainer, caretRange.startOffset);
          } else {
            deleteRange2.setStart(caretRange.endContainer, caretRange.endOffset);
          }
          deleteRange2.deleteContents();
        } else {
          range2.deleteContents();
        }
        editor.selection.setRng(caretRange);
      });
      trimEmptyTextNode(editor.dom, node);
    };
    const deleteBoundaryText = (editor, forward) => {
      const range2 = editor.selection.getRng();
      if (!isText$9(range2.commonAncestorContainer)) {
        return Optional.none();
      }
      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
      const caretWalker = CaretWalker(editor.getBody());
      const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
      const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range2);
      const nextCaretPosition = normalizePosition(forward, getNextPosFn(caretPosition));
      if (!nextCaretPosition || !isMoveInsideSameBlock(caretPosition, nextCaretPosition)) {
        return Optional.none();
      } else if (isBeforeFn(nextCaretPosition)) {
        return Optional.some(() => deleteContentAndShowCaret(editor, range2, caretPosition.getNode(), direction, forward, nextCaretPosition));
      }
      const peekCaretPosition = getNextPosFn(nextCaretPosition);
      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
        if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
          return Optional.some(() => deleteContentAndShowCaret(editor, range2, caretPosition.getNode(), direction, forward, peekCaretPosition));
        }
      }
      return Optional.none();
    };
    const backspaceDelete$6 = (editor, forward) => deleteBoundaryText(editor, forward);
    const getEdgeCefPosition = (editor, atStart) => {
      const root = editor.getBody();
      return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
    };
    const isCefAtEdgeSelected = (editor) => {
      const rng = editor.selection.getRng();
      return !rng.collapsed && (getEdgeCefPosition(editor, true).exists((pos) => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists((pos) => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
    };
    const isCompoundElement = (node) => isTableCell$4(SugarElement.fromDom(node)) || isListItem(SugarElement.fromDom(node));
    const DeleteAction = Adt.generate([
      { remove: ["element"] },
      { moveToElement: ["element"] },
      { moveToPosition: ["position"] }
    ]);
    const isAtContentEditableBlockCaret = (forward, from2) => {
      const elm = from2.getNode(forward === false);
      const caretLocation = forward ? "after" : "before";
      return isElement$6(elm) && elm.getAttribute("data-mce-caret") === caretLocation;
    };
    const isDeleteFromCefDifferentBlocks = (root, forward, from2, to2) => {
      const inSameBlock = (elm) => isInline$1(SugarElement.fromDom(elm)) && !isInSameBlock(from2, to2, root);
      return getRelativeCefElm(!forward, from2).fold(() => getRelativeCefElm(forward, to2).fold(never, inSameBlock), inSameBlock);
    };
    const deleteEmptyBlockOrMoveToCef = (root, forward, from2, to2) => {
      const toCefElm = to2.getNode(forward === false);
      return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from2.getNode())).map((blockElm) => isEmpty$2(blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm)));
    };
    const findCefPosition = (root, forward, from2) => fromPosition(forward, root, from2).bind((to2) => {
      if (isCompoundElement(to2.getNode())) {
        return Optional.none();
      } else if (isDeleteFromCefDifferentBlocks(root, forward, from2, to2)) {
        return Optional.none();
      } else if (forward && isContentEditableFalse$b(to2.getNode())) {
        return deleteEmptyBlockOrMoveToCef(root, forward, from2, to2);
      } else if (forward === false && isContentEditableFalse$b(to2.getNode(true))) {
        return deleteEmptyBlockOrMoveToCef(root, forward, from2, to2);
      } else if (forward && isAfterContentEditableFalse(from2)) {
        return Optional.some(DeleteAction.moveToPosition(to2));
      } else if (forward === false && isBeforeContentEditableFalse(from2)) {
        return Optional.some(DeleteAction.moveToPosition(to2));
      } else {
        return Optional.none();
      }
    });
    const getContentEditableBlockAction = (forward, elm) => {
      if (forward && isContentEditableFalse$b(elm.nextSibling)) {
        return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
      } else if (forward === false && isContentEditableFalse$b(elm.previousSibling)) {
        return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
      } else {
        return Optional.none();
      }
    };
    const skipMoveToActionFromInlineCefToContent = (root, from2, deleteAction2) => deleteAction2.fold((elm) => Optional.some(DeleteAction.remove(elm)), (elm) => Optional.some(DeleteAction.moveToElement(elm)), (to2) => {
      if (isInSameBlock(from2, to2, root)) {
        return Optional.none();
      } else {
        return Optional.some(DeleteAction.moveToPosition(to2));
      }
    });
    const getContentEditableAction = (root, forward, from2) => {
      if (isAtContentEditableBlockCaret(forward, from2)) {
        return getContentEditableBlockAction(forward, from2.getNode(forward === false)).fold(() => findCefPosition(root, forward, from2), Optional.some);
      } else {
        return findCefPosition(root, forward, from2).bind((deleteAction2) => skipMoveToActionFromInlineCefToContent(root, from2, deleteAction2));
      }
    };
    const read = (root, forward, rng) => {
      const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
      const from2 = CaretPosition.fromRangeStart(normalizedRange);
      const rootElement = SugarElement.fromDom(root);
      if (forward === false && isAfterContentEditableFalse(from2)) {
        return Optional.some(DeleteAction.remove(from2.getNode(true)));
      } else if (forward && isBeforeContentEditableFalse(from2)) {
        return Optional.some(DeleteAction.remove(from2.getNode()));
      } else if (forward === false && isBeforeContentEditableFalse(from2) && isAfterBr(rootElement, from2)) {
        return findPreviousBr(rootElement, from2).map((br) => DeleteAction.remove(br.getNode()));
      } else if (forward && isAfterContentEditableFalse(from2) && isBeforeBr$1(rootElement, from2)) {
        return findNextBr(rootElement, from2).map((br) => DeleteAction.remove(br.getNode()));
      } else {
        return getContentEditableAction(root, forward, from2);
      }
    };
    const deleteElement$1 = (editor, forward) => (element) => {
      editor._selectionOverrides.hideFakeCaret();
      deleteElement$2(editor, forward, SugarElement.fromDom(element));
      return true;
    };
    const moveToElement = (editor, forward) => (element) => {
      const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
      editor.selection.setRng(pos.toRange());
      return true;
    };
    const moveToPosition = (editor) => (pos) => {
      editor.selection.setRng(pos.toRange());
      return true;
    };
    const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
    const backspaceDeleteCaret = (editor, forward) => {
      const selectedNode = editor.selection.getNode();
      return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$b).fold(() => read(editor.getBody(), forward, editor.selection.getRng()).map((deleteAction2) => () => deleteAction2.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop));
    };
    const deleteOffscreenSelection = (rootElement) => {
      each$f(descendants(rootElement, ".mce-offscreen-selection"), remove$6);
    };
    const backspaceDeleteRange = (editor, forward) => {
      const selectedNode = editor.selection.getNode();
      if (isContentEditableFalse$b(selectedNode) && !isTableCell$5(selectedNode)) {
        const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$b);
        return hasCefAncestor.fold(() => Optional.some(() => {
          deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
          deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
          paddEmptyBody(editor);
        }), () => Optional.some(noop));
      }
      if (isCefAtEdgeSelected(editor)) {
        return Optional.some(() => {
          deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
        });
      }
      return Optional.none();
    };
    const paddEmptyElement = (editor) => {
      const dom2 = editor.dom, selection = editor.selection;
      const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
      if (isContentEditableTrue$5(ceRoot) && dom2.isBlock(ceRoot) && dom2.isEmpty(ceRoot)) {
        const br = dom2.create("br", { "data-mce-bogus": "1" });
        dom2.setHTML(ceRoot, "");
        ceRoot.appendChild(br);
        selection.setRng(CaretPosition.before(br).toRange());
      }
      return true;
    };
    const backspaceDelete$5 = (editor, forward) => {
      if (editor.selection.isCollapsed()) {
        return backspaceDeleteCaret(editor, forward);
      } else {
        return backspaceDeleteRange(editor, forward);
      }
    };
    const deleteCaret$2 = (editor, forward) => {
      const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
      return fromPosition(forward, editor.getBody(), fromPos).filter((pos) => forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos)).bind((pos) => Optional.from(getChildNodeAtRelativeOffset(forward ? 0 : -1, pos))).map((elm) => () => editor.selection.select(elm));
    };
    const backspaceDelete$4 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
    const isText$2 = isText$9;
    const startsWithCaretContainer = (node) => isText$2(node) && node.data[0] === ZWSP$1;
    const endsWithCaretContainer = (node) => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
    const createZwsp = (node) => node.ownerDocument.createTextNode(ZWSP$1);
    const insertBefore = (node) => {
      if (isText$2(node.previousSibling)) {
        if (endsWithCaretContainer(node.previousSibling)) {
          return node.previousSibling;
        } else {
          node.previousSibling.appendData(ZWSP$1);
          return node.previousSibling;
        }
      } else if (isText$2(node)) {
        if (startsWithCaretContainer(node)) {
          return node;
        } else {
          node.insertData(0, ZWSP$1);
          return node;
        }
      } else {
        const newNode = createZwsp(node);
        node.parentNode.insertBefore(newNode, node);
        return newNode;
      }
    };
    const insertAfter = (node) => {
      if (isText$2(node.nextSibling)) {
        if (startsWithCaretContainer(node.nextSibling)) {
          return node.nextSibling;
        } else {
          node.nextSibling.insertData(0, ZWSP$1);
          return node.nextSibling;
        }
      } else if (isText$2(node)) {
        if (endsWithCaretContainer(node)) {
          return node;
        } else {
          node.appendData(ZWSP$1);
          return node;
        }
      } else {
        const newNode = createZwsp(node);
        if (node.nextSibling) {
          node.parentNode.insertBefore(newNode, node.nextSibling);
        } else {
          node.parentNode.appendChild(newNode);
        }
        return newNode;
      }
    };
    const insertInline = (before2, node) => before2 ? insertBefore(node) : insertAfter(node);
    const insertInlineBefore = curry(insertInline, true);
    const insertInlineAfter = curry(insertInline, false);
    const insertInlinePos = (pos, before2) => {
      if (isText$9(pos.container())) {
        return insertInline(before2, pos.container());
      } else {
        return insertInline(before2, pos.getNode());
      }
    };
    const isPosCaretContainer = (pos, caret) => {
      const caretNode = caret.get();
      return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
    };
    const renderCaret = (caret, location) => location.fold((element) => {
      remove$4(caret.get());
      const text2 = insertInlineBefore(element);
      caret.set(text2);
      return Optional.some(CaretPosition(text2, text2.length - 1));
    }, (element) => firstPositionIn(element).map((pos) => {
      if (!isPosCaretContainer(pos, caret)) {
        remove$4(caret.get());
        const text2 = insertInlinePos(pos, true);
        caret.set(text2);
        return CaretPosition(text2, 1);
      } else {
        return CaretPosition(caret.get(), 1);
      }
    }), (element) => lastPositionIn(element).map((pos) => {
      if (!isPosCaretContainer(pos, caret)) {
        remove$4(caret.get());
        const text2 = insertInlinePos(pos, false);
        caret.set(text2);
        return CaretPosition(text2, text2.length - 1);
      } else {
        return CaretPosition(caret.get(), caret.get().length - 1);
      }
    }), (element) => {
      remove$4(caret.get());
      const text2 = insertInlineAfter(element);
      caret.set(text2);
      return Optional.some(CaretPosition(text2, 1));
    });
    const evaluateUntil = (fns, args) => {
      for (let i = 0; i < fns.length; i++) {
        const result = fns[i].apply(null, args);
        if (result.isSome()) {
          return result;
        }
      }
      return Optional.none();
    };
    const Location = Adt.generate([
      { before: ["element"] },
      { start: ["element"] },
      { end: ["element"] },
      { after: ["element"] }
    ]);
    const rescope$1 = (rootNode, node) => {
      const parentBlock = getParentBlock$3(node, rootNode);
      return parentBlock ? parentBlock : rootNode;
    };
    const before = (isInlineTarget2, rootNode, pos) => {
      const nPos = normalizeForwards(pos);
      const scope = rescope$1(rootNode, nPos.container());
      return findRootInline(isInlineTarget2, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget2, scope)).map((inline) => Location.before(inline)), Optional.none);
    };
    const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
    const findInsideRootInline = (isInlineTarget2, rootNode, pos) => findRootInline(isInlineTarget2, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
    const start$1 = (isInlineTarget2, rootNode, pos) => {
      const nPos = normalizeBackwards(pos);
      return findInsideRootInline(isInlineTarget2, rootNode, nPos).bind((inline) => {
        const prevPos = prevPosition(inline, nPos);
        return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
      });
    };
    const end = (isInlineTarget2, rootNode, pos) => {
      const nPos = normalizeForwards(pos);
      return findInsideRootInline(isInlineTarget2, rootNode, nPos).bind((inline) => {
        const nextPos = nextPosition(inline, nPos);
        return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
      });
    };
    const after = (isInlineTarget2, rootNode, pos) => {
      const nPos = normalizeBackwards(pos);
      const scope = rescope$1(rootNode, nPos.container());
      return findRootInline(isInlineTarget2, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget2, scope)).map((inline) => Location.after(inline)), Optional.none);
    };
    const isValidLocation = (location) => isRtl(getElement(location)) === false;
    const readLocation = (isInlineTarget2, rootNode, pos) => {
      const location = evaluateUntil([
        before,
        start$1,
        end,
        after
      ], [
        isInlineTarget2,
        rootNode,
        pos
      ]);
      return location.filter(isValidLocation);
    };
    const getElement = (location) => location.fold(identity, identity, identity, identity);
    const getName = (location) => location.fold(constant("before"), constant("start"), constant("end"), constant("after"));
    const outside = (location) => location.fold(Location.before, Location.before, Location.after, Location.after);
    const inside = (location) => location.fold(Location.start, Location.start, Location.end, Location.end);
    const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
    const betweenInlines = (forward, isInlineTarget2, rootNode, from2, to2, location) => lift2(findRootInline(isInlineTarget2, rootNode, from2), findRootInline(isInlineTarget2, rootNode, to2), (fromInline, toInline) => {
      if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
        return Location.after(forward ? fromInline : toInline);
      } else {
        return location;
      }
    }).getOr(location);
    const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, (fromLocation2) => !isEq(fromLocation2, toLocation));
    const findLocationTraverse = (forward, isInlineTarget2, rootNode, fromLocation, pos) => {
      const from2 = normalizePosition(forward, pos);
      const to2 = fromPosition(forward, rootNode, from2).map(curry(normalizePosition, forward));
      const location = to2.fold(() => fromLocation.map(outside), (to3) => readLocation(isInlineTarget2, rootNode, to3).map(curry(betweenInlines, forward, isInlineTarget2, rootNode, from2, to3)).filter(curry(skipNoMovement, fromLocation)));
      return location.filter(isValidLocation);
    };
    const findLocationSimple = (forward, location) => {
      if (forward) {
        return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
      } else {
        return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
      }
    };
    const findLocation$1 = (forward, isInlineTarget2, rootNode, pos) => {
      const from2 = normalizePosition(forward, pos);
      const fromLocation = readLocation(isInlineTarget2, rootNode, from2);
      return readLocation(isInlineTarget2, rootNode, from2).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget2, rootNode, fromLocation, pos));
    };
    const hasSelectionModifyApi = (editor) => {
      return isFunction(editor.selection.getSel().modify);
    };
    const moveRel = (forward, selection, pos) => {
      const delta = forward ? 1 : -1;
      selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
      selection.getSel().modify("move", forward ? "forward" : "backward", "word");
      return true;
    };
    const moveByWord = (forward, editor) => {
      const rng = editor.selection.getRng();
      const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
      if (!hasSelectionModifyApi(editor)) {
        return false;
      } else if (forward && isBeforeInline(pos)) {
        return moveRel(true, editor.selection, pos);
      } else if (!forward && isAfterInline(pos)) {
        return moveRel(false, editor.selection, pos);
      } else {
        return false;
      }
    };
    var BreakType;
    (function(BreakType2) {
      BreakType2[BreakType2["Br"] = 0] = "Br";
      BreakType2[BreakType2["Block"] = 1] = "Block";
      BreakType2[BreakType2["Wrap"] = 2] = "Wrap";
      BreakType2[BreakType2["Eol"] = 3] = "Eol";
    })(BreakType || (BreakType = {}));
    const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
    const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
    const getBreakType = (scope, direction, currentPos, nextPos) => {
      if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
        return BreakType.Br;
      } else if (isInSameBlock(currentPos, nextPos) === false) {
        return BreakType.Block;
      } else {
        return BreakType.Wrap;
      }
    };
    const getPositionsUntil = (predicate, direction, scope, start2) => {
      const caretWalker = CaretWalker(scope);
      let currentPos = start2;
      const positions = [];
      while (currentPos) {
        const nextPos = walk$1(direction, caretWalker, currentPos);
        if (!nextPos) {
          break;
        }
        if (isBr$6(nextPos.getNode(false))) {
          if (direction === HDirection.Forwards) {
            return {
              positions: flip(direction, positions).concat([nextPos]),
              breakType: BreakType.Br,
              breakAt: Optional.some(nextPos)
            };
          } else {
            return {
              positions: flip(direction, positions),
              breakType: BreakType.Br,
              breakAt: Optional.some(nextPos)
            };
          }
        }
        if (!nextPos.isVisible()) {
          currentPos = nextPos;
          continue;
        }
        if (predicate(currentPos, nextPos)) {
          const breakType = getBreakType(scope, direction, currentPos, nextPos);
          return {
            positions: flip(direction, positions),
            breakType,
            breakAt: Optional.some(nextPos)
          };
        }
        positions.push(nextPos);
        currentPos = nextPos;
      }
      return {
        positions: flip(direction, positions),
        breakType: BreakType.Eol,
        breakAt: Optional.none()
      };
    };
    const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start2) => getPositionsUntilBreak(scope, start2).breakAt.map((pos) => {
      const positions = getPositionsUntilBreak(scope, pos).positions;
      return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
    }).getOr([]);
    const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), (lastPos) => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
      const lastDist = Math.abs(x - lastRect.left);
      const newDist = Math.abs(x - newRect.left);
      return newDist <= lastDist ? newPos : lastPos;
    }).or(acc)), Optional.none());
    const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind((targetRect) => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
    const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
    const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
    const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
    const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
    const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
    const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
    const getFirstLinePositions = (scope) => firstPositionIn(scope).map((pos) => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
    const getLastLinePositions = (scope) => lastPositionIn(scope).map((pos) => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
    const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
    const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
    const isContentEditableFalse$4 = isContentEditableFalse$b;
    const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
    const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
    const isNodeClientRect = (rect) => hasNonNullableKey(rect, "node");
    const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
      const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
      const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
      if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$4(clientRect.node)) {
        return clientRect;
      }
      if (newDistance < oldDistance) {
        return clientRect;
      }
      return oldClientRect;
    });
    const getNodeClientRects = (node) => {
      const toArrayWithNode = (clientRects) => {
        return map$3(clientRects, (rect) => {
          const clientRect = clone$1(rect);
          clientRect.node = node;
          return clientRect;
        });
      };
      if (isElement$6(node)) {
        return toArrayWithNode(node.getClientRects());
      } else if (isText$9(node)) {
        const rng = node.ownerDocument.createRange();
        rng.setStart(node, 0);
        rng.setEnd(node, node.data.length);
        return toArrayWithNode(rng.getClientRects());
      } else {
        return [];
      }
    };
    const getClientRects = (nodes) => bind$3(nodes, getNodeClientRects);
    var VDirection;
    (function(VDirection2) {
      VDirection2[VDirection2["Up"] = -1] = "Up";
      VDirection2[VDirection2["Down"] = 1] = "Down";
    })(VDirection || (VDirection = {}));
    const findUntil = (direction, root, predicateFn, node) => {
      while (node = findNode(node, direction, isEditableCaretCandidate$1, root)) {
        if (predicateFn(node)) {
          return;
        }
      }
    };
    const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
      let line = 0;
      const result = [];
      const add2 = (node2) => {
        let clientRects = getClientRects([node2]);
        if (direction === -1) {
          clientRects = clientRects.reverse();
        }
        for (let i = 0; i < clientRects.length; i++) {
          const clientRect = clientRects[i];
          if (isBeflowFn(clientRect, targetClientRect)) {
            continue;
          }
          if (result.length > 0 && isAboveFn(clientRect, last$2(result))) {
            line++;
          }
          clientRect.line = line;
          if (predicateFn(clientRect)) {
            return true;
          }
          result.push(clientRect);
        }
      };
      const targetClientRect = last$2(caretPosition.getClientRects());
      if (!targetClientRect) {
        return result;
      }
      const node = caretPosition.getNode();
      add2(node);
      findUntil(direction, root, add2, node);
      return result;
    };
    const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
    const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
    const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
    const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
    const positionsUntil = (direction, root, predicateFn, node) => {
      const caretWalker = CaretWalker(root);
      let walkFn;
      let isBelowFn;
      let isAboveFn;
      let caretPosition;
      const result = [];
      let line = 0;
      const getClientRect = (caretPosition2) => {
        if (direction === 1) {
          return last$2(caretPosition2.getClientRects());
        }
        return last$2(caretPosition2.getClientRects());
      };
      if (direction === 1) {
        walkFn = caretWalker.next;
        isBelowFn = isBelow$1;
        isAboveFn = isAbove$1;
        caretPosition = CaretPosition.after(node);
      } else {
        walkFn = caretWalker.prev;
        isBelowFn = isAbove$1;
        isAboveFn = isBelow$1;
        caretPosition = CaretPosition.before(node);
      }
      const targetClientRect = getClientRect(caretPosition);
      do {
        if (!caretPosition.isVisible()) {
          continue;
        }
        const rect = getClientRect(caretPosition);
        if (isAboveFn(rect, targetClientRect)) {
          continue;
        }
        if (result.length > 0 && isBelowFn(rect, last$2(result))) {
          line++;
        }
        const clientRect = clone$1(rect);
        clientRect.position = caretPosition;
        clientRect.line = line;
        if (predicateFn(clientRect)) {
          return result;
        }
        result.push(clientRect);
      } while (caretPosition = walkFn(caretPosition));
      return result;
    };
    const isAboveLine = (lineNumber) => (clientRect) => aboveLineNumber(lineNumber, clientRect);
    const isLine = (lineNumber) => (clientRect) => isLineNumber(lineNumber, clientRect);
    const moveToRange = (editor, rng) => {
      editor.selection.setRng(rng);
      scrollRangeIntoView(editor, editor.selection.getRng());
    };
    const renderRangeCaretOpt = (editor, range2, scrollIntoView) => Optional.some(renderRangeCaret(editor, range2, scrollIntoView));
    const moveHorizontally = (editor, direction, range2, isBefore, isAfter, isElement2) => {
      const forwards = direction === HDirection.Forwards;
      const caretWalker = CaretWalker(editor.getBody());
      const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
      const isBeforeFn = forwards ? isBefore : isAfter;
      if (!range2.collapsed) {
        const node = getSelectedNode(range2);
        if (isElement2(node)) {
          return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
        } else if (isCefAtEdgeSelected(editor)) {
          const newRange = range2.cloneRange();
          newRange.collapse(direction === HDirection.Backwards);
          return Optional.from(newRange);
        }
      }
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range2);
      if (isBeforeFn(caretPosition)) {
        return selectNode(editor, caretPosition.getNode(!forwards));
      }
      const nextCaretPosition = normalizePosition(forwards, getNextPosFn(caretPosition));
      const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range2);
      if (!nextCaretPosition) {
        return rangeIsInContainerBlock ? Optional.some(range2) : Optional.none();
      }
      if (isBeforeFn(nextCaretPosition)) {
        return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
      }
      const peekCaretPosition = getNextPosFn(nextCaretPosition);
      if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
        if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
          return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
        }
      }
      if (rangeIsInContainerBlock) {
        return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
      }
      return Optional.none();
    };
    const moveVertically = (editor, direction, range2, isBefore, isAfter, isElement2) => {
      const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range2);
      const caretClientRect = last$2(caretPosition.getClientRects());
      const forwards = direction === VDirection.Down;
      const root = editor.getBody();
      if (!caretClientRect) {
        return Optional.none();
      }
      if (isCefAtEdgeSelected(editor)) {
        const caretPosition2 = forwards ? CaretPosition.fromRangeEnd(range2) : CaretPosition.fromRangeStart(range2);
        const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
        return getClosestFn(root, caretPosition2).orThunk(() => Optional.from(caretPosition2)).map((pos) => pos.toRange());
      }
      const walkerFn = forwards ? downUntil : upUntil;
      const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
      const nextLinePositions = filter$6(linePositions, isLine(1));
      const clientX = caretClientRect.left;
      const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
      if (nextLineRect && isElement2(nextLineRect.node)) {
        const dist1 = Math.abs(clientX - nextLineRect.left);
        const dist2 = Math.abs(clientX - nextLineRect.right);
        return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
      }
      let currentNode;
      if (isBefore(caretPosition)) {
        currentNode = caretPosition.getNode();
      } else if (isAfter(caretPosition)) {
        currentNode = caretPosition.getNode(true);
      } else {
        currentNode = getSelectedNode(range2);
      }
      if (currentNode) {
        const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
        let closestNextLineRect = findClosestClientRect(filter$6(caretPositions, isLine(1)), clientX);
        if (closestNextLineRect) {
          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
        }
        closestNextLineRect = last$2(filter$6(caretPositions, isLine(0)));
        if (closestNextLineRect) {
          return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
        }
      }
      if (nextLinePositions.length === 0) {
        return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map((pos) => renderRangeCaret(editor, pos.toRange(), false));
      }
      return Optional.none();
    };
    const getLineEndPoint = (editor, forward) => {
      const rng = editor.selection.getRng();
      const from2 = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
      const host = getEditingHost(from2.container(), editor.getBody());
      if (forward) {
        const lineInfo = getPositionsUntilNextLine(host, from2);
        return last$3(lineInfo.positions);
      } else {
        const lineInfo = getPositionsUntilPreviousLine(host, from2);
        return head(lineInfo.positions);
      }
    };
    const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists((pos) => {
      editor.selection.setRng(pos.toRange());
      return true;
    });
    const setCaretPosition = (editor, pos) => {
      const rng = editor.dom.createRng();
      rng.setStart(pos.container(), pos.offset());
      rng.setEnd(pos.container(), pos.offset());
      editor.selection.setRng(rng);
    };
    const setSelected = (state, elm) => {
      if (state) {
        elm.setAttribute("data-mce-selected", "inline-boundary");
      } else {
        elm.removeAttribute("data-mce-selected");
      }
    };
    const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map((pos) => {
      setCaretPosition(editor, pos);
      return location;
    });
    const getPositionFromRange = (range2, root, forward) => {
      const start2 = CaretPosition.fromRangeStart(range2);
      if (range2.collapsed) {
        return start2;
      } else {
        const end2 = CaretPosition.fromRangeEnd(range2);
        return forward ? prevPosition(root, end2).getOr(end2) : nextPosition(root, start2).getOr(start2);
      }
    };
    const findLocation = (editor, caret, forward) => {
      const rootNode = editor.getBody();
      const from2 = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
      const isInlineTarget$1 = curry(isInlineTarget, editor);
      const location = findLocation$1(forward, isInlineTarget$1, rootNode, from2);
      return location.bind((location2) => renderCaretLocation(editor, caret, location2));
    };
    const toggleInlines = (isInlineTarget2, dom2, elms) => {
      const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom2.getRoot()), '*[data-mce-selected="inline-boundary"]'), (e) => e.dom);
      const selectedInlines = filter$6(inlineBoundaries, isInlineTarget2);
      const targetInlines = filter$6(elms, isInlineTarget2);
      each$f(difference(selectedInlines, targetInlines), curry(setSelected, false));
      each$f(difference(targetInlines, selectedInlines), curry(setSelected, true));
    };
    const safeRemoveCaretContainer = (editor, caret) => {
      if (editor.selection.isCollapsed() && editor.composing !== true && caret.get()) {
        const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
        if (CaretPosition.isTextPosition(pos) && isAtZwsp(pos) === false) {
          setCaretPosition(editor, removeAndReposition(caret.get(), pos));
          caret.set(null);
        }
      }
    };
    const renderInsideInlineCaret = (isInlineTarget2, editor, caret, elms) => {
      if (editor.selection.isCollapsed()) {
        const inlines = filter$6(elms, isInlineTarget2);
        each$f(inlines, (_inline) => {
          const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
          readLocation(isInlineTarget2, editor.getBody(), pos).bind((location) => renderCaretLocation(editor, caret, location));
        });
      }
    };
    const move$2 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
    const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
    const setupSelectedState = (editor) => {
      const caret = Cell(null);
      const isInlineTarget$1 = curry(isInlineTarget, editor);
      editor.on("NodeChange", (e) => {
        if (isInlineBoundariesEnabled(editor)) {
          toggleInlines(isInlineTarget$1, editor.dom, e.parents);
          safeRemoveCaretContainer(editor, caret);
          renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
        }
      });
      return caret;
    };
    const moveNextWord = curry(moveWord, true);
    const movePrevWord = curry(moveWord, false);
    const moveToLineEndPoint$2 = (editor, forward, caret) => {
      if (isInlineBoundariesEnabled(editor)) {
        const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
          const rng = editor.selection.getRng();
          return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
        });
        return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists((loc) => {
          const outsideLoc = outside(loc);
          return renderCaret(caret, outsideLoc).exists((pos) => {
            setCaretPosition(editor, pos);
            return true;
          });
        });
      } else {
        return false;
      }
    };
    const rangeFromPositions = (from2, to2) => {
      const range2 = document.createRange();
      range2.setStart(from2.container(), from2.offset());
      range2.setEnd(to2.container(), to2.offset());
      return range2;
    };
    const hasOnlyTwoOrLessPositionsLeft = (elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
      const normalizedFirstPos = normalizePosition(true, firstPos);
      const normalizedLastPos = normalizePosition(false, lastPos);
      return nextPosition(elm, normalizedFirstPos).forall((pos) => pos.isEqual(normalizedLastPos));
    }).getOr(true);
    const setCaretLocation = (editor, caret) => (location) => renderCaret(caret, location).map((pos) => () => setCaretPosition(editor, pos));
    const deleteFromTo = (editor, caret, from2, to2) => {
      const rootNode = editor.getBody();
      const isInlineTarget$1 = curry(isInlineTarget, editor);
      editor.undoManager.ignore(() => {
        editor.selection.setRng(rangeFromPositions(from2, to2));
        execDeleteCommand(editor);
        readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
      });
      editor.nodeChanged();
    };
    const rescope = (rootNode, node) => {
      const parentBlock = getParentBlock$3(node, rootNode);
      return parentBlock ? parentBlock : rootNode;
    };
    const backspaceDeleteCollapsed = (editor, caret, forward, from2) => {
      const rootNode = rescope(editor.getBody(), from2.container());
      const isInlineTarget$1 = curry(isInlineTarget, editor);
      const fromLocation = readLocation(isInlineTarget$1, rootNode, from2);
      const location = fromLocation.bind((location2) => {
        if (forward) {
          return location2.fold(constant(Optional.some(inside(location2))), Optional.none, constant(Optional.some(outside(location2))), Optional.none);
        } else {
          return location2.fold(Optional.none, constant(Optional.some(outside(location2))), Optional.none, constant(Optional.some(inside(location2))));
        }
      });
      return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
        const toPosition = navigate(forward, rootNode, from2);
        const toLocation = toPosition.bind((pos) => readLocation(isInlineTarget$1, rootNode, pos));
        return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from2).bind((elm) => {
          if (hasOnlyTwoOrLessPositionsLeft(elm)) {
            return Optional.some(() => {
              deleteElement$2(editor, forward, SugarElement.fromDom(elm));
            });
          } else {
            return Optional.none();
          }
        })).getOrThunk(() => toLocation.bind(() => toPosition.map((to2) => {
          return () => {
            if (forward) {
              deleteFromTo(editor, caret, from2, to2);
            } else {
              deleteFromTo(editor, caret, to2, from2);
            }
          };
        })));
      });
    };
    const backspaceDelete$3 = (editor, caret, forward) => {
      if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
        const from2 = CaretPosition.fromRangeStart(editor.selection.getRng());
        return backspaceDeleteCollapsed(editor, caret, forward, from2);
      }
      return Optional.none();
    };
    const getParentInlines = (rootElm, startElm) => {
      const parents2 = parentsAndSelf(startElm, rootElm);
      return findIndex$2(parents2, isBlock$2).fold(constant(parents2), (index2) => parents2.slice(0, index2));
    };
    const hasOnlyOneChild = (elm) => childNodesCount(elm) === 1;
    const deleteLastPosition = (forward, editor, target, parentInlines) => {
      const isFormatElement$1 = curry(isFormatElement, editor);
      const formatNodes = map$3(filter$6(parentInlines, isFormatElement$1), (elm) => elm.dom);
      if (formatNodes.length === 0) {
        deleteElement$2(editor, forward, target);
      } else {
        const pos = replaceWithCaretFormat(target.dom, formatNodes);
        editor.selection.setRng(pos.toRange());
      }
    };
    const deleteCaret$1 = (editor, forward) => {
      const rootElm = SugarElement.fromDom(editor.getBody());
      const startElm = SugarElement.fromDom(editor.selection.getStart());
      const parentInlines = filter$6(getParentInlines(rootElm, startElm), hasOnlyOneChild);
      return last$3(parentInlines).bind((target) => {
        const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
        if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
          return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
        } else {
          return Optional.none();
        }
      });
    };
    const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : Optional.none();
    const deleteElement = (editor, forward, element) => {
      return Optional.some(() => {
        editor._selectionOverrides.hideFakeCaret();
        deleteElement$2(editor, forward, SugarElement.fromDom(element));
      });
    };
    const deleteCaret = (editor, forward) => {
      const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
      const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
      if (isNearMedia(fromPos)) {
        return deleteElement(editor, forward, fromPos.getNode(!forward));
      } else {
        return Optional.from(normalizePosition(forward, fromPos)).filter((pos) => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).map((pos) => () => deleteElement(editor, forward, pos.getNode(!forward)));
      }
    };
    const deleteRange = (editor, forward) => {
      const selectedNode = editor.selection.getNode();
      return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
    };
    const backspaceDelete$1 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
    const isEditable$1 = (target) => closest$4(target, (elm) => isContentEditableTrue$5(elm.dom) || isContentEditableFalse$b(elm.dom)).exists((elm) => isContentEditableTrue$5(elm.dom));
    const parseIndentValue = (value2) => {
      const number2 = parseInt(value2, 10);
      return isNaN(number2) ? 0 : number2;
    };
    const getIndentStyleName = (useMargin, element) => {
      const indentStyleName = useMargin || isTable$2(element) ? "margin" : "padding";
      const suffix = get$7(element, "direction") === "rtl" ? "-right" : "-left";
      return indentStyleName + suffix;
    };
    const indentElement = (dom2, command, useMargin, value2, unit, element) => {
      const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
      if (command === "outdent") {
        const styleValue = Math.max(0, parseIndentValue(element.style[indentStyleName]) - value2);
        dom2.setStyle(element, indentStyleName, styleValue ? styleValue + unit : "");
      } else {
        const styleValue = parseIndentValue(element.style[indentStyleName]) + value2 + unit;
        dom2.setStyle(element, indentStyleName, styleValue);
      }
    };
    const validateBlocks = (editor, blocks2) => forall(blocks2, (block) => {
      const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
      const intentValue = getRaw$1(block, indentStyleName).map(parseIndentValue).getOr(0);
      const contentEditable = editor.dom.getContentEditable(block.dom);
      return contentEditable !== "false" && intentValue > 0;
    });
    const canOutdent = (editor) => {
      const blocks2 = getBlocksToIndent(editor);
      return !editor.mode.isReadOnly() && (blocks2.length > 1 || validateBlocks(editor, blocks2));
    };
    const isListComponent = (el) => isList(el) || isListItem(el);
    const parentIsListComponent = (el) => parent(el).exists(isListComponent);
    const getBlocksToIndent = (editor) => filter$6(fromDom$1(editor.selection.getSelectedBlocks()), (el) => !isListComponent(el) && !parentIsListComponent(el) && isEditable$1(el));
    const handle = (editor, command) => {
      const { dom: dom2 } = editor;
      const indentation = getIndentation(editor);
      const indentUnit = /[a-z%]+$/i.exec(indentation)[0];
      const indentValue = parseInt(indentation, 10);
      const useMargin = shouldIndentUseMargin(editor);
      each$f(getBlocksToIndent(editor), (block) => {
        indentElement(dom2, command, useMargin, indentValue, indentUnit, block.dom);
      });
    };
    const indent = (editor) => handle(editor, "indent");
    const outdent = (editor) => handle(editor, "outdent");
    const backspaceDelete = (editor) => {
      if (editor.selection.isCollapsed() && canOutdent(editor)) {
        const dom2 = editor.dom;
        const rng = editor.selection.getRng();
        const pos = CaretPosition.fromRangeStart(rng);
        const block = dom2.getParent(rng.startContainer, dom2.isBlock);
        if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos)) {
          return Optional.some(() => outdent(editor));
        }
      }
      return Optional.none();
    };
    const findAction = (editor, caret, forward) => findMap([
      backspaceDelete,
      backspaceDelete$5,
      backspaceDelete$6,
      (editor2, forward2) => backspaceDelete$3(editor2, caret, forward2),
      backspaceDelete$8,
      backspaceDelete$9,
      backspaceDelete$4,
      backspaceDelete$1,
      backspaceDelete$7,
      backspaceDelete$2
    ], (item) => item(editor, forward));
    const deleteCommand = (editor, caret) => {
      const result = findAction(editor, caret, false);
      result.fold(() => {
        execDeleteCommand(editor);
        paddEmptyBody(editor);
      }, call);
    };
    const forwardDeleteCommand = (editor, caret) => {
      const result = findAction(editor, caret, true);
      result.fold(() => execForwardDeleteCommand(editor), call);
    };
    const setup$p = (editor, caret) => {
      editor.addCommand("delete", () => {
        deleteCommand(editor, caret);
      });
      editor.addCommand("forwardDelete", () => {
        forwardDeleteCommand(editor, caret);
      });
    };
    const SIGNIFICANT_MOVE = 5;
    const LONGPRESS_DELAY = 400;
    const getTouch = (event) => {
      if (event.touches === void 0 || event.touches.length !== 1) {
        return Optional.none();
      }
      return Optional.some(event.touches[0]);
    };
    const isFarEnough = (touch, data2) => {
      const distX = Math.abs(touch.clientX - data2.x);
      const distY = Math.abs(touch.clientY - data2.y);
      return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
    };
    const setup$o = (editor) => {
      const startData = value$2();
      const longpressFired = Cell(false);
      const debounceLongpress = last$1((e) => {
        editor.dispatch("longpress", {
          ...e,
          type: "longpress"
        });
        longpressFired.set(true);
      }, LONGPRESS_DELAY);
      editor.on("touchstart", (e) => {
        getTouch(e).each((touch) => {
          debounceLongpress.cancel();
          const data2 = {
            x: touch.clientX,
            y: touch.clientY,
            target: e.target
          };
          debounceLongpress.throttle(e);
          longpressFired.set(false);
          startData.set(data2);
        });
      }, true);
      editor.on("touchmove", (e) => {
        debounceLongpress.cancel();
        getTouch(e).each((touch) => {
          startData.on((data2) => {
            if (isFarEnough(touch, data2)) {
              startData.clear();
              longpressFired.set(false);
              editor.dispatch("longpresscancel");
            }
          });
        });
      }, true);
      editor.on("touchend touchcancel", (e) => {
        debounceLongpress.cancel();
        if (e.type === "touchcancel") {
          return;
        }
        startData.get().filter((data2) => data2.target.isEqualNode(e.target)).each(() => {
          if (longpressFired.get()) {
            e.preventDefault();
          } else {
            editor.dispatch("tap", {
              ...e,
              type: "tap"
            });
          }
        });
      }, true);
    };
    const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
    const isValidTarget = (blockElements, node) => {
      if (isText$9(node)) {
        return true;
      } else if (isElement$6(node)) {
        return !isBlockElement(blockElements, node) && !isBookmarkNode$1(node);
      } else {
        return false;
      }
    };
    const hasBlockParent = (blockElements, root, node) => {
      return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), (elm) => {
        return isBlockElement(blockElements, elm.dom);
      });
    };
    const shouldRemoveTextNode = (blockElements, node) => {
      if (isText$9(node)) {
        if (node.nodeValue.length === 0) {
          return true;
        } else if (/^\s+$/.test(node.nodeValue) && (!node.nextSibling || isBlockElement(blockElements, node.nextSibling))) {
          return true;
        }
      }
      return false;
    };
    const addRootBlocks = (editor) => {
      const dom2 = editor.dom, selection = editor.selection;
      const schema = editor.schema, blockElements = schema.getBlockElements();
      let node = selection.getStart();
      const rootNode = editor.getBody();
      let rootBlockNode, tempNode, wrapped;
      const forcedRootBlock = getForcedRootBlock(editor);
      if (!node || !isElement$6(node)) {
        return;
      }
      const rootNodeName = rootNode.nodeName.toLowerCase();
      if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, node)) {
        return;
      }
      const rng = selection.getRng();
      const startContainer = rng.startContainer;
      const startOffset = rng.startOffset;
      const endContainer = rng.endContainer;
      const endOffset = rng.endOffset;
      const restoreSelection = hasFocus(editor);
      node = rootNode.firstChild;
      while (node) {
        if (isValidTarget(blockElements, node)) {
          if (shouldRemoveTextNode(blockElements, node)) {
            tempNode = node;
            node = node.nextSibling;
            dom2.remove(tempNode);
            continue;
          }
          if (!rootBlockNode) {
            rootBlockNode = dom2.create(forcedRootBlock, getForcedRootBlockAttrs(editor));
            node.parentNode.insertBefore(rootBlockNode, node);
            wrapped = true;
          }
          tempNode = node;
          node = node.nextSibling;
          rootBlockNode.appendChild(tempNode);
        } else {
          rootBlockNode = null;
          node = node.nextSibling;
        }
      }
      if (wrapped && restoreSelection) {
        rng.setStart(startContainer, startOffset);
        rng.setEnd(endContainer, endOffset);
        selection.setRng(rng);
        editor.nodeChanged();
      }
    };
    const setup$n = (editor) => {
      editor.on("NodeChange", curry(addRootBlocks, editor));
    };
    const hasClass = (checkClassName) => (node) => (" " + node.attr("class") + " ").indexOf(checkClassName) !== -1;
    const replaceMatchWithSpan = (editor, content, cls) => {
      return function(match2) {
        const args = arguments, index2 = args[args.length - 2];
        const prevChar = index2 > 0 ? content.charAt(index2 - 1) : "";
        if (prevChar === '"') {
          return match2;
        }
        if (prevChar === ">") {
          const findStartTagIndex = content.lastIndexOf("<", index2);
          if (findStartTagIndex !== -1) {
            const tagHtml = content.substring(findStartTagIndex, index2);
            if (tagHtml.indexOf('contenteditable="false"') !== -1) {
              return match2;
            }
          }
        }
        return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === "string" ? args[1] : args[0]) + "</span>";
      };
    };
    const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
      let i = nonEditableRegExps.length, content = e.content;
      if (e.format === "raw") {
        return;
      }
      while (i--) {
        content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
      }
      e.content = content;
    };
    const setup$m = (editor) => {
      const contentEditableAttrName = "contenteditable";
      const editClass = " " + Tools.trim(getEditableClass(editor)) + " ";
      const nonEditClass = " " + Tools.trim(getNonEditableClass(editor)) + " ";
      const hasEditClass = hasClass(editClass);
      const hasNonEditClass = hasClass(nonEditClass);
      const nonEditableRegExps = getNonEditableRegExps(editor);
      if (nonEditableRegExps.length > 0) {
        editor.on("BeforeSetContent", (e) => {
          convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
        });
      }
      editor.parser.addAttributeFilter("class", (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (hasEditClass(node)) {
            node.attr(contentEditableAttrName, "true");
          } else if (hasNonEditClass(node)) {
            node.attr(contentEditableAttrName, "false");
          }
        }
      });
      editor.serializer.addAttributeFilter(contentEditableAttrName, (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (!hasEditClass(node) && !hasNonEditClass(node)) {
            continue;
          }
          if (nonEditableRegExps.length > 0 && node.attr("data-mce-content")) {
            node.name = "#text";
            node.type = 3;
            node.raw = true;
            node.value = node.attr("data-mce-content");
          } else {
            node.attr(contentEditableAttrName, null);
          }
        }
      });
    };
    const findBlockCaretContainer = (editor) => descendant(SugarElement.fromDom(editor.getBody()), "*[data-mce-caret]").map((elm) => elm.dom).getOrNull();
    const showBlockCaretContainer = (editor, blockCaretContainer) => {
      if (blockCaretContainer.hasAttribute("data-mce-caret")) {
        showCaretContainerBlock(blockCaretContainer);
        editor.selection.setRng(editor.selection.getRng());
        editor.selection.scrollIntoView(blockCaretContainer);
      }
    };
    const handleBlockContainer = (editor, e) => {
      const blockCaretContainer = findBlockCaretContainer(editor);
      if (!blockCaretContainer) {
        return;
      }
      if (e.type === "compositionstart") {
        e.preventDefault();
        e.stopPropagation();
        showBlockCaretContainer(editor, blockCaretContainer);
        return;
      }
      if (hasContent(blockCaretContainer)) {
        showBlockCaretContainer(editor, blockCaretContainer);
        editor.undoManager.add();
      }
    };
    const setup$l = (editor) => {
      editor.on("keyup compositionstart", curry(handleBlockContainer, editor));
    };
    const isContentEditableFalse$3 = isContentEditableFalse$b;
    const moveToCeFalseHorizontally = (direction, editor, range2) => moveHorizontally(editor, direction, range2, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$3);
    const moveToCeFalseVertically = (direction, editor, range2) => {
      const isBefore = (caretPosition) => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
      const isAfter = (caretPosition) => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
      return moveVertically(editor, direction, range2, isBefore, isAfter, isContentEditableFalse$3);
    };
    const createTextBlock = (editor) => {
      const textBlock = editor.dom.create(getForcedRootBlock(editor));
      textBlock.innerHTML = '<br data-mce-bogus="1">';
      return textBlock;
    };
    const exitPreBlock = (editor, direction, range2) => {
      const caretWalker = CaretWalker(editor.getBody());
      const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
      if (range2.collapsed) {
        const pre = editor.dom.getParent(range2.startContainer, "PRE");
        if (!pre) {
          return;
        }
        const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range2));
        if (!caretPos) {
          const newBlock = SugarElement.fromDom(createTextBlock(editor));
          if (direction === 1) {
            after$4(SugarElement.fromDom(pre), newBlock);
          } else {
            before$3(SugarElement.fromDom(pre), newBlock);
          }
          editor.selection.select(newBlock.dom, true);
          editor.selection.collapse();
        }
      }
    };
    const getHorizontalRange = (editor, forward) => {
      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
      const range2 = editor.selection.getRng();
      return moveToCeFalseHorizontally(direction, editor, range2).orThunk(() => {
        exitPreBlock(editor, direction, range2);
        return Optional.none();
      });
    };
    const getVerticalRange = (editor, down) => {
      const direction = down ? 1 : -1;
      const range2 = editor.selection.getRng();
      return moveToCeFalseVertically(direction, editor, range2).orThunk(() => {
        exitPreBlock(editor, direction, range2);
        return Optional.none();
      });
    };
    const moveH$2 = (editor, forward) => getHorizontalRange(editor, forward).exists((newRange) => {
      moveToRange(editor, newRange);
      return true;
    });
    const moveV$3 = (editor, down) => getVerticalRange(editor, down).exists((newRange) => {
      moveToRange(editor, newRange);
      return true;
    });
    const moveToLineEndPoint$1 = (editor, forward) => {
      const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
      return moveToLineEndPoint$3(editor, forward, isCefPosition);
    };
    const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map((pos) => {
      const rng = pos.toRange();
      const curRng = editor.selection.getRng();
      if (forward) {
        rng.setStart(curRng.startContainer, curRng.startOffset);
      } else {
        rng.setEnd(curRng.endContainer, curRng.endOffset);
      }
      return rng;
    }).exists((rng) => {
      moveToRange(editor, rng);
      return true;
    });
    const isTarget = (node) => contains$2(["figcaption"], name(node));
    const rangeBefore = (target) => {
      const rng = document.createRange();
      rng.setStartBefore(target.dom);
      rng.setEndBefore(target.dom);
      return rng;
    };
    const insertElement = (root, elm, forward) => {
      if (forward) {
        append$1(root, elm);
      } else {
        prepend(root, elm);
      }
    };
    const insertEmptyLine = (root, forward, blockName, attrs) => {
      const block = SugarElement.fromTag(blockName);
      const br = SugarElement.fromTag("br");
      setAll$1(block, attrs);
      append$1(block, br);
      insertElement(root, block, forward);
      return rangeBefore(br);
    };
    const getClosestTargetBlock = (pos, root) => {
      const isRoot2 = curry(eq, root);
      return closest$4(SugarElement.fromDom(pos.container()), isBlock$2, isRoot2).filter(isTarget);
    };
    const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
    const moveCaretToNewEmptyLine = (editor, forward) => {
      const root = SugarElement.fromDom(editor.getBody());
      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
      const rootBlock = getForcedRootBlock(editor);
      const rootBlockAttrs = getForcedRootBlockAttrs(editor);
      return getClosestTargetBlock(pos, root).exists(() => {
        if (isAtFirstOrLastLine(root, forward, pos)) {
          const rng = insertEmptyLine(root, forward, rootBlock, rootBlockAttrs);
          editor.selection.setRng(rng);
          return true;
        } else {
          return false;
        }
      });
    };
    const moveV$2 = (editor, forward) => {
      if (editor.selection.isCollapsed()) {
        return moveCaretToNewEmptyLine(editor, forward);
      } else {
        return false;
      }
    };
    const baseKeyPattern = {
      shiftKey: false,
      altKey: false,
      ctrlKey: false,
      metaKey: false,
      keyCode: 0
    };
    const defaultPatterns = (patterns) => map$3(patterns, (pattern) => ({
      ...baseKeyPattern,
      action: noop,
      ...pattern
    }));
    const defaultDelayedPatterns = (patterns) => map$3(patterns, (pattern) => ({
      ...baseKeyPattern,
      action: () => Optional.none(),
      ...pattern
    }));
    const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
    const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), (pattern) => matchesEvent(pattern, evt) ? [pattern] : []);
    const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), (pattern) => matchesEvent(pattern, evt) ? [pattern] : []);
    const action = (f, ...x) => () => f.apply(null, x);
    const execute = (patterns, evt) => find$2(match$1(patterns, evt), (pattern) => pattern.action());
    const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), (pattern) => pattern.action());
    const moveH$1 = (editor, forward) => {
      const direction = forward ? HDirection.Forwards : HDirection.Backwards;
      const range2 = editor.selection.getRng();
      return moveHorizontally(editor, direction, range2, isBeforeMedia, isAfterMedia, isMedia$2).exists((newRange) => {
        moveToRange(editor, newRange);
        return true;
      });
    };
    const moveV$1 = (editor, down) => {
      const direction = down ? 1 : -1;
      const range2 = editor.selection.getRng();
      return moveVertically(editor, direction, range2, isBeforeMedia, isAfterMedia, isMedia$2).exists((newRange) => {
        moveToRange(editor, newRange);
        return true;
      });
    };
    const moveToLineEndPoint = (editor, forward) => {
      const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
      return moveToLineEndPoint$3(editor, forward, isNearMedia);
    };
    const adt = Adt.generate([
      { none: ["current"] },
      { first: ["current"] },
      {
        middle: [
          "current",
          "target"
        ]
      },
      { last: ["current"] }
    ]);
    const none = (current) => adt.none(current);
    const CellLocation = {
      ...adt,
      none
    };
    const firstLayer = (scope, selector) => {
      return filterFirstLayer(scope, selector, always);
    };
    const filterFirstLayer = (scope, selector, predicate) => {
      return bind$3(children(scope), (x) => {
        if (is$1(x, selector)) {
          return predicate(x) ? [x] : [];
        } else {
          return filterFirstLayer(x, selector, predicate);
        }
      });
    };
    const lookup$1 = (tags, element, isRoot2 = never) => {
      if (isRoot2(element)) {
        return Optional.none();
      }
      if (contains$2(tags, name(element))) {
        return Optional.some(element);
      }
      const isRootOrUpperTable = (elm) => is$1(elm, "table") || isRoot2(elm);
      return ancestor$2(element, tags.join(","), isRootOrUpperTable);
    };
    const cell = (element, isRoot2) => lookup$1([
      "td",
      "th"
    ], element, isRoot2);
    const cells = (ancestor2) => firstLayer(ancestor2, "th,td");
    const table = (element, isRoot2) => closest$3(element, "table", isRoot2);
    const walk = (all2, current, index2, direction, isEligible = always) => {
      const forwards = direction === 1;
      if (!forwards && index2 <= 0) {
        return CellLocation.first(all2[0]);
      } else if (forwards && index2 >= all2.length - 1) {
        return CellLocation.last(all2[all2.length - 1]);
      } else {
        const newIndex = index2 + direction;
        const elem = all2[newIndex];
        return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all2, current, newIndex, direction, isEligible);
      }
    };
    const detect = (current, isRoot2) => {
      return table(current, isRoot2).bind((table2) => {
        const all2 = cells(table2);
        const index2 = findIndex$2(all2, (x) => eq(current, x));
        return index2.map((index3) => ({
          index: index3,
          all: all2
        }));
      });
    };
    const next = (current, isEligible, isRoot2) => {
      const detection = detect(current, isRoot2);
      return detection.fold(() => {
        return CellLocation.none(current);
      }, (info) => {
        return walk(info.all, current, info.index, 1, isEligible);
      });
    };
    const prev = (current, isEligible, isRoot2) => {
      const detection = detect(current, isRoot2);
      return detection.fold(() => {
        return CellLocation.none();
      }, (info) => {
        return walk(info.all, current, info.index, -1, isEligible);
      });
    };
    const closest = (target) => closest$3(target, "[contenteditable]");
    const isEditable = (element, assumeEditable = false) => {
      if (inBody(element)) {
        return element.dom.isContentEditable;
      } else {
        return closest(element).fold(constant(assumeEditable), (editable) => getRaw(editable) === "true");
      }
    };
    const getRaw = (element) => element.dom.contentEditable;
    const deflate = (rect, delta) => ({
      left: rect.left - delta,
      top: rect.top - delta,
      right: rect.right + delta * 2,
      bottom: rect.bottom + delta * 2,
      width: rect.width + delta,
      height: rect.height + delta
    });
    const getCorners = (getYAxisValue, tds) => bind$3(tds, (td) => {
      const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
      return [
        {
          x: rect.left,
          y: getYAxisValue(rect),
          cell: td
        },
        {
          x: rect.right,
          y: getYAxisValue(rect),
          cell: td
        }
      ];
    });
    const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), (oldCorner) => {
      const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
      const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
      return Optional.some(newDist < oldDist ? newCorner : oldCorner);
    }), Optional.none());
    const getClosestCell = (getYAxisValue, isTargetCorner, table2, x, y) => {
      const cells2 = descendants(SugarElement.fromDom(table2), "td,th,caption").map((e) => e.dom);
      const corners = filter$6(getCorners(getYAxisValue, cells2), (corner) => isTargetCorner(corner, y));
      return findClosestCorner(corners, x, y).map((corner) => corner.cell);
    };
    const getBottomValue = (rect) => rect.bottom;
    const getTopValue = (rect) => rect.top;
    const isAbove = (corner, y) => corner.y < y;
    const isBelow = (corner, y) => corner.y > y;
    const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
    const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
    const findClosestPositionInAboveCell = (table2, pos) => head(pos.getClientRects()).bind((rect) => getClosestCellAbove(table2, rect.left, rect.top)).bind((cell2) => findClosestHorizontalPosition(getLastLinePositions(cell2), pos));
    const findClosestPositionInBelowCell = (table2, pos) => last$3(pos.getClientRects()).bind((rect) => getClosestCellBelow(table2, rect.left, rect.top)).bind((cell2) => findClosestHorizontalPosition(getFirstLinePositions(cell2), pos));
    const hasNextBreak = (getPositionsUntil2, scope, lineInfo) => lineInfo.breakAt.exists((breakPos) => getPositionsUntil2(scope, breakPos).breakAt.isSome());
    const startsWithWrapBreak = (lineInfo) => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
    const startsWithBrBreak = (lineInfo) => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
    const isAtTableCellLine = (getPositionsUntil2, scope, pos) => {
      const lineInfo = getPositionsUntil2(scope, pos);
      if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
        return !hasNextBreak(getPositionsUntil2, scope, lineInfo);
      } else {
        return lineInfo.breakAt.isNone();
      }
    };
    const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
    const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
    const isCaretAtStartOrEndOfTable = (forward, rng, table2) => {
      const caretPos = CaretPosition.fromRangeStart(rng);
      return positionIn(!forward, table2).exists((pos) => pos.isEqual(caretPos));
    };
    const navigateHorizontally = (editor, forward, table2, _td) => {
      const rng = editor.selection.getRng();
      const direction = forward ? 1 : -1;
      if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table2)) {
        showCaret(direction, editor, table2, !forward, false).each((newRng) => {
          moveToRange(editor, newRng);
        });
        return true;
      }
      return false;
    };
    const getClosestAbovePosition = (root, table2, start2) => findClosestPositionInAboveCell(table2, start2).orThunk(() => head(start2.getClientRects()).bind((rect) => findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition.before(table2)), rect.left))).getOr(CaretPosition.before(table2));
    const getClosestBelowPosition = (root, table2, start2) => findClosestPositionInBelowCell(table2, start2).orThunk(() => head(start2.getClientRects()).bind((rect) => findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition.after(table2)), rect.left))).getOr(CaretPosition.after(table2));
    const getTable = (previous, pos) => {
      const node = pos.getNode(previous);
      return isElement$6(node) && node.nodeName === "TABLE" ? Optional.some(node) : Optional.none();
    };
    const renderBlock = (down, editor, table2) => {
      const forcedRootBlock = getForcedRootBlock(editor);
      editor.undoManager.transact(() => {
        const element = SugarElement.fromTag(forcedRootBlock);
        setAll$1(element, getForcedRootBlockAttrs(editor));
        append$1(element, SugarElement.fromTag("br"));
        if (down) {
          after$4(SugarElement.fromDom(table2), element);
        } else {
          before$3(SugarElement.fromDom(table2), element);
        }
        const rng = editor.dom.createRng();
        rng.setStart(element.dom, 0);
        rng.setEnd(element.dom, 0);
        moveToRange(editor, rng);
      });
    };
    const moveCaret = (editor, down, pos) => {
      const table2 = down ? getTable(true, pos) : getTable(false, pos);
      const last2 = down === false;
      table2.fold(() => moveToRange(editor, pos.toRange()), (table3) => positionIn(last2, editor.getBody()).filter((lastPos) => lastPos.isEqual(pos)).fold(() => moveToRange(editor, pos.toRange()), (_) => renderBlock(down, editor, table3)));
    };
    const navigateVertically = (editor, down, table2, td) => {
      const rng = editor.selection.getRng();
      const pos = CaretPosition.fromRangeStart(rng);
      const root = editor.getBody();
      if (!down && isAtFirstTableCellLine(td, pos)) {
        const newPos = getClosestAbovePosition(root, table2, pos);
        moveCaret(editor, down, newPos);
        return true;
      } else if (down && isAtLastTableCellLine(td, pos)) {
        const newPos = getClosestBelowPosition(root, table2, pos);
        moveCaret(editor, down, newPos);
        return true;
      } else {
        return false;
      }
    };
    const move$1 = (editor, forward, mover) => Optional.from(editor.dom.getParent(editor.selection.getNode(), "td,th")).bind((td) => Optional.from(editor.dom.getParent(td, "table")).map((table2) => mover(editor, forward, table2, td))).getOr(false);
    const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
    const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
    const getCellFirstCursorPosition = (cell2) => {
      const selection = SimSelection.exact(cell2, 0, cell2, 0);
      return toNative(selection);
    };
    const tabGo = (editor, isRoot2, cell2) => {
      return cell2.fold(Optional.none, Optional.none, (_current, next2) => {
        return first(next2).map((cell3) => {
          return getCellFirstCursorPosition(cell3);
        });
      }, (current) => {
        editor.execCommand("mceTableInsertRowAfter");
        return tabForward(editor, isRoot2, current);
      });
    };
    const tabForward = (editor, isRoot2, cell2) => tabGo(editor, isRoot2, next(cell2, isEditable));
    const tabBackward = (editor, isRoot2, cell2) => tabGo(editor, isRoot2, prev(cell2, isEditable));
    const handleTab = (editor, forward) => {
      const rootElements = [
        "table",
        "li",
        "dl"
      ];
      const body = SugarElement.fromDom(editor.getBody());
      const isRoot2 = (element) => {
        const name$1 = name(element);
        return eq(element, body) || contains$2(rootElements, name$1);
      };
      const rng = editor.selection.getRng();
      const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
      return cell(container, isRoot2).map((cell2) => {
        table(cell2, isRoot2).each((table2) => {
          editor.model.table.clearSelectedCells(table2.dom);
        });
        editor.selection.collapse(!forward);
        const navigation = !forward ? tabBackward : tabForward;
        const rng2 = navigation(editor, isRoot2, cell2);
        rng2.each((range2) => {
          editor.selection.setRng(range2);
        });
        return true;
      }).getOr(false);
    };
    const executeKeydownOverride$4 = (editor, caret, evt) => {
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
      execute([
        {
          keyCode: VK.RIGHT,
          action: action(moveH$2, editor, true)
        },
        {
          keyCode: VK.LEFT,
          action: action(moveH$2, editor, false)
        },
        {
          keyCode: VK.UP,
          action: action(moveV$3, editor, false)
        },
        {
          keyCode: VK.DOWN,
          action: action(moveV$3, editor, true)
        },
        ...isMac ? [
          {
            keyCode: VK.UP,
            action: action(selectToEndPoint, editor, false),
            metaKey: true,
            shiftKey: true
          },
          {
            keyCode: VK.DOWN,
            action: action(selectToEndPoint, editor, true),
            metaKey: true,
            shiftKey: true
          }
        ] : [],
        {
          keyCode: VK.RIGHT,
          action: action(moveH, editor, true)
        },
        {
          keyCode: VK.LEFT,
          action: action(moveH, editor, false)
        },
        {
          keyCode: VK.UP,
          action: action(moveV, editor, false)
        },
        {
          keyCode: VK.DOWN,
          action: action(moveV, editor, true)
        },
        {
          keyCode: VK.RIGHT,
          action: action(moveH$1, editor, true)
        },
        {
          keyCode: VK.LEFT,
          action: action(moveH$1, editor, false)
        },
        {
          keyCode: VK.UP,
          action: action(moveV$1, editor, false)
        },
        {
          keyCode: VK.DOWN,
          action: action(moveV$1, editor, true)
        },
        {
          keyCode: VK.RIGHT,
          action: action(move$2, editor, caret, true)
        },
        {
          keyCode: VK.LEFT,
          action: action(move$2, editor, caret, false)
        },
        {
          keyCode: VK.RIGHT,
          ctrlKey: !isMac,
          altKey: isMac,
          action: action(moveNextWord, editor, caret)
        },
        {
          keyCode: VK.LEFT,
          ctrlKey: !isMac,
          altKey: isMac,
          action: action(movePrevWord, editor, caret)
        },
        {
          keyCode: VK.UP,
          action: action(moveV$2, editor, false)
        },
        {
          keyCode: VK.DOWN,
          action: action(moveV$2, editor, true)
        }
      ], evt).each((_) => {
        evt.preventDefault();
      });
    };
    const setup$k = (editor, caret) => {
      editor.on("keydown", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeydownOverride$4(editor, caret, evt);
        }
      });
    };
    const point = (container, offset) => ({
      container,
      offset
    });
    const DOM$7 = DOMUtils.DOM;
    const alwaysNext = (startNode) => (node) => startNode === node ? -1 : 0;
    const isBoundary = (dom2) => (node) => dom2.isBlock(node) || contains$2([
      "BR",
      "IMG",
      "HR",
      "INPUT"
    ], node.nodeName) || dom2.getContentEditable(node) === "false";
    const textBefore = (node, offset, rootNode) => {
      if (isText$9(node) && offset >= 0) {
        return Optional.some(point(node, offset));
      } else {
        const textSeeker = TextSeeker(DOM$7);
        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map((prev2) => point(prev2.container, prev2.container.data.length));
      }
    };
    const textAfter = (node, offset, rootNode) => {
      if (isText$9(node) && offset >= node.length) {
        return Optional.some(point(node, offset));
      } else {
        const textSeeker = TextSeeker(DOM$7);
        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map((prev2) => point(prev2.container, 0));
      }
    };
    const scanLeft = (node, offset, rootNode) => {
      if (!isText$9(node)) {
        return Optional.none();
      }
      const text2 = node.textContent;
      if (offset >= 0 && offset <= text2.length) {
        return Optional.some(point(node, offset));
      } else {
        const textSeeker = TextSeeker(DOM$7);
        return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind((prev2) => {
          const prevText = prev2.container.data;
          return scanLeft(prev2.container, offset + prevText.length, rootNode);
        });
      }
    };
    const scanRight = (node, offset, rootNode) => {
      if (!isText$9(node)) {
        return Optional.none();
      }
      const text2 = node.textContent;
      if (offset <= text2.length) {
        return Optional.some(point(node, offset));
      } else {
        const textSeeker = TextSeeker(DOM$7);
        return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind((next2) => scanRight(next2.container, offset - text2.length, rootNode));
      }
    };
    const repeatLeft = (dom2, node, offset, process2, rootNode) => {
      const search2 = TextSeeker(dom2, isBoundary(dom2));
      return Optional.from(search2.backwards(node, offset, process2, rootNode));
    };
    const isValidTextRange = (rng) => rng.collapsed && rng.startContainer.nodeType === 3;
    const getText = (rng) => rng.toString().replace(/\u00A0/g, " ").replace(/\uFEFF/g, "");
    const isWhitespace = (chr) => chr !== "" && " \xA0\f\n\r	\v".indexOf(chr) !== -1;
    const stripTriggerChar = (text2, triggerCh) => text2.substring(triggerCh.length);
    const findChar = (text2, index2, ch) => {
      let i;
      for (i = index2 - 1; i >= 0; i--) {
        const char = text2.charAt(i);
        if (isWhitespace(char)) {
          return Optional.none();
        }
        if (char === ch) {
          break;
        }
      }
      return Optional.some(i);
    };
    const findStart = (dom2, initRange, ch, minChars = 0) => {
      if (!isValidTextRange(initRange)) {
        return Optional.none();
      }
      const findTriggerChIndex = (element, offset, text2) => findChar(text2, offset, ch).getOr(offset);
      const root = dom2.getParent(initRange.startContainer, dom2.isBlock) || dom2.getRoot();
      return repeatLeft(dom2, initRange.startContainer, initRange.startOffset, findTriggerChIndex, root).bind((spot) => {
        const range2 = initRange.cloneRange();
        range2.setStart(spot.container, spot.offset);
        range2.setEnd(initRange.endContainer, initRange.endOffset);
        if (range2.collapsed) {
          return Optional.none();
        }
        const text2 = getText(range2);
        const triggerCharIndex = text2.lastIndexOf(ch);
        if (triggerCharIndex !== 0 || stripTriggerChar(text2, ch).length < minChars) {
          return Optional.none();
        } else {
          return Optional.some({
            text: stripTriggerChar(text2, ch),
            range: range2,
            triggerChar: ch
          });
        }
      });
    };
    const getContext = (dom2, initRange, ch, minChars = 0) => detect$1(SugarElement.fromDom(initRange.startContainer)).fold(() => findStart(dom2, initRange, ch, minChars), (elm) => {
      const range2 = dom2.createRng();
      range2.selectNode(elm.dom);
      const text2 = getText(range2);
      return Optional.some({
        range: range2,
        text: stripTriggerChar(text2, ch),
        triggerChar: ch
      });
    });
    const isText$1 = (node) => node.nodeType === TEXT;
    const isElement = (node) => node.nodeType === ELEMENT;
    const toLast = (node) => {
      if (isText$1(node)) {
        return point(node, node.data.length);
      } else {
        const children2 = node.childNodes;
        return children2.length > 0 ? toLast(children2[children2.length - 1]) : point(node, children2.length);
      }
    };
    const toLeaf = (node, offset) => {
      const children2 = node.childNodes;
      if (children2.length > 0 && offset < children2.length) {
        return toLeaf(children2[offset], 0);
      } else if (children2.length > 0 && isElement(node) && children2.length === offset) {
        return toLast(children2[children2.length - 1]);
      } else {
        return point(node, offset);
      }
    };
    const isPreviousCharContent = (dom2, leaf) => {
      const root = dom2.getParent(leaf.container, dom2.isBlock);
      return repeatLeft(dom2, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter((spot) => {
        const char = spot.container.data.charAt(spot.offset - 1);
        return !isWhitespace(char);
      }).isSome();
    };
    const isStartOfWord = (dom2) => (rng) => {
      const leaf = toLeaf(rng.startContainer, rng.startOffset);
      return !isPreviousCharContent(dom2, leaf);
    };
    const getTriggerContext = (dom2, initRange, database) => findMap(database.triggerChars, (ch) => getContext(dom2, initRange, ch));
    const lookup = (editor, getDatabase) => {
      const database = getDatabase();
      const rng = editor.selection.getRng();
      return getTriggerContext(editor.dom, rng, database).bind((context2) => lookupWithContext(editor, getDatabase, context2));
    };
    const lookupWithContext = (editor, getDatabase, context2, fetchOptions = {}) => {
      const database = getDatabase();
      const rng = editor.selection.getRng();
      const startText = rng.startContainer.nodeValue;
      const autocompleters = filter$6(database.lookupByChar(context2.triggerChar), (autocompleter) => context2.text.length >= autocompleter.minChars && autocompleter.matches.getOrThunk(() => isStartOfWord(editor.dom))(context2.range, startText, context2.text));
      if (autocompleters.length === 0) {
        return Optional.none();
      }
      const lookupData = Promise.all(map$3(autocompleters, (ac) => {
        const fetchResult = ac.fetch(context2.text, ac.maxResults, fetchOptions);
        return fetchResult.then((results) => ({
          matchText: context2.text,
          items: results,
          columns: ac.columns,
          onAction: ac.onAction,
          highlightOn: ac.highlightOn
        }));
      }));
      return Optional.some({
        lookupData,
        context: context2
      });
    };
    var SimpleResultType;
    (function(SimpleResultType2) {
      SimpleResultType2[SimpleResultType2["Error"] = 0] = "Error";
      SimpleResultType2[SimpleResultType2["Value"] = 1] = "Value";
    })(SimpleResultType || (SimpleResultType = {}));
    const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
    const partition = (results) => {
      const values2 = [];
      const errors = [];
      each$f(results, (obj) => {
        fold$1(obj, (err) => errors.push(err), (val) => values2.push(val));
      });
      return {
        values: values2,
        errors
      };
    };
    const mapError = (res, f) => {
      if (res.stype === SimpleResultType.Error) {
        return {
          stype: SimpleResultType.Error,
          serror: f(res.serror)
        };
      } else {
        return res;
      }
    };
    const map = (res, f) => {
      if (res.stype === SimpleResultType.Value) {
        return {
          stype: SimpleResultType.Value,
          svalue: f(res.svalue)
        };
      } else {
        return res;
      }
    };
    const bind = (res, f) => {
      if (res.stype === SimpleResultType.Value) {
        return f(res.svalue);
      } else {
        return res;
      }
    };
    const bindError = (res, f) => {
      if (res.stype === SimpleResultType.Error) {
        return f(res.serror);
      } else {
        return res;
      }
    };
    const svalue = (v) => ({
      stype: SimpleResultType.Value,
      svalue: v
    });
    const serror = (e) => ({
      stype: SimpleResultType.Error,
      serror: e
    });
    const toResult = (res) => fold$1(res, Result.error, Result.value);
    const fromResult = (res) => res.fold(serror, svalue);
    const SimpleResult = {
      fromResult,
      toResult,
      svalue,
      partition,
      serror,
      bind,
      bindError,
      map,
      mapError,
      fold: fold$1
    };
    const formatObj = (input) => {
      return isObject(input) && keys(input).length > 100 ? " removed due to size" : JSON.stringify(input, null, 2);
    };
    const formatErrors = (errors) => {
      const es = errors.length > 10 ? errors.slice(0, 10).concat([{
        path: [],
        getErrorInfo: constant("... (only showing first ten failures)")
      }]) : errors;
      return map$3(es, (e) => {
        return "Failed path: (" + e.path.join(" > ") + ")\n" + e.getErrorInfo();
      });
    };
    const nu = (path, getErrorInfo) => {
      return SimpleResult.serror([{
        path,
        getErrorInfo
      }]);
    };
    const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
    const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
    const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
    const custom = (path, err) => nu(path, constant(err));
    const chooseFrom = (path, input, branches, ch) => {
      const fields = get$a(branches, ch);
      return fields.fold(() => missingBranch(path, branches, ch), (vp) => vp.extract(path.concat(["branch: " + ch]), input));
    };
    const choose$1 = (key, branches) => {
      const extract = (path, input) => {
        const choice = get$a(input, key);
        return choice.fold(() => missingKey(path, key), (chosen) => chooseFrom(path, input, branches, chosen));
      };
      const toString = () => "chooseOn(" + key + "). Possible values: " + keys(branches);
      return {
        extract,
        toString
      };
    };
    const shallow = (old, nu2) => {
      return nu2;
    };
    const deep = (old, nu2) => {
      const bothObjects = isPlainObject(old) && isPlainObject(nu2);
      return bothObjects ? deepMerge(old, nu2) : nu2;
    };
    const baseMerge = (merger) => {
      return (...objects) => {
        if (objects.length === 0) {
          throw new Error(`Can't merge zero objects`);
        }
        const ret = {};
        for (let j = 0; j < objects.length; j++) {
          const curObject = objects[j];
          for (const key in curObject) {
            if (has$2(curObject, key)) {
              ret[key] = merger(ret[key], curObject[key]);
            }
          }
        }
        return ret;
      };
    };
    const deepMerge = baseMerge(deep);
    const merge = baseMerge(shallow);
    const required = () => ({
      tag: "required",
      process: {}
    });
    const defaultedThunk = (fallbackThunk) => ({
      tag: "defaultedThunk",
      process: fallbackThunk
    });
    const defaulted$1 = (fallback2) => defaultedThunk(constant(fallback2));
    const asOption = () => ({
      tag: "option",
      process: {}
    });
    const mergeValues = (values2, base) => values2.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(void 0, values2))) : SimpleResult.svalue(base);
    const mergeErrors = (errors) => compose(SimpleResult.serror, flatten)(errors);
    const consolidateObj = (objects, base) => {
      const partition2 = SimpleResult.partition(objects);
      return partition2.errors.length > 0 ? mergeErrors(partition2.errors) : mergeValues(partition2.values, base);
    };
    const consolidateArr = (objects) => {
      const partitions = SimpleResult.partition(objects);
      return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
    };
    const ResultCombine = {
      consolidateObj,
      consolidateArr
    };
    const field$1 = (key, newKey, presence, prop) => ({
      tag: "field",
      key,
      newKey,
      presence,
      prop
    });
    const customField$1 = (newKey, instantiator) => ({
      tag: "custom",
      newKey,
      instantiator
    });
    const fold = (value2, ifField, ifCustom) => {
      switch (value2.tag) {
        case "field":
          return ifField(value2.key, value2.newKey, value2.presence, value2.prop);
        case "custom":
          return ifCustom(value2.newKey, value2.instantiator);
      }
    };
    const value = (validator) => {
      const extract = (path, val) => {
        return SimpleResult.bindError(validator(val), (err) => custom(path, err));
      };
      const toString = constant("val");
      return {
        extract,
        toString
      };
    };
    const anyValue$1 = value(SimpleResult.svalue);
    const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
    const fallbackAccess = (obj, key, fallback2, bundle) => {
      const v = get$a(obj, key).getOrThunk(() => fallback2(obj));
      return bundle(v);
    };
    const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
    const optionDefaultedAccess = (obj, key, fallback2, bundle) => {
      const opt = get$a(obj, key).map((val) => val === true ? fallback2(obj) : val);
      return bundle(opt);
    };
    const extractField = (field2, path, obj, key, prop) => {
      const bundle = (av) => prop.extract(path.concat([key]), av);
      const bundleAsOption = (optValue) => optValue.fold(() => SimpleResult.svalue(Optional.none()), (ov) => {
        const result = prop.extract(path.concat([key]), ov);
        return SimpleResult.map(result, Optional.some);
      });
      switch (field2.tag) {
        case "required":
          return requiredAccess(path, obj, key, bundle);
        case "defaultedThunk":
          return fallbackAccess(obj, key, field2.process, bundle);
        case "option":
          return optionAccess(obj, key, bundleAsOption);
        case "defaultedOptionThunk":
          return optionDefaultedAccess(obj, key, field2.process, bundleAsOption);
        case "mergeWithThunk": {
          return fallbackAccess(obj, key, constant({}), (v) => {
            const result = deepMerge(field2.process(obj), v);
            return bundle(result);
          });
        }
      }
    };
    const extractFields = (path, obj, fields) => {
      const success = {};
      const errors = [];
      for (const field2 of fields) {
        fold(field2, (key, newKey, presence, prop) => {
          const result = extractField(presence, path, obj, key, prop);
          SimpleResult.fold(result, (err) => {
            errors.push(...err);
          }, (res) => {
            success[newKey] = res;
          });
        }, (newKey, instantiator) => {
          success[newKey] = instantiator(obj);
        });
      }
      return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
    };
    const objOf = (values2) => {
      const extract = (path, o) => extractFields(path, o, values2);
      const toString = () => {
        const fieldStrings = map$3(values2, (value2) => fold(value2, (key, _okey, _presence, prop) => key + " -> " + prop.toString(), (newKey, _instantiator) => "state(" + newKey + ")"));
        return "obj{\n" + fieldStrings.join("\n") + "}";
      };
      return {
        extract,
        toString
      };
    };
    const arrOf = (prop) => {
      const extract = (path, array) => {
        const results = map$3(array, (a, i) => prop.extract(path.concat(["[" + i + "]"]), a));
        return ResultCombine.consolidateArr(results);
      };
      const toString = () => "array(" + prop.toString() + ")";
      return {
        extract,
        toString
      };
    };
    const valueOf = (validator) => value((v) => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
    const extractValue = (label, prop, obj) => {
      const res = prop.extract([label], obj);
      return SimpleResult.mapError(res, (errs) => ({
        input: obj,
        errors: errs
      }));
    };
    const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
    const formatError = (errInfo) => {
      return "Errors: \n" + formatErrors(errInfo.errors).join("\n") + "\n\nInput object: " + formatObj(errInfo.input);
    };
    const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
    const anyValue = constant(anyValue$1);
    const typedValue = (validator, expectedType) => value((a) => {
      const actualType = typeof a;
      return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${expectedType} but got: ${actualType}`);
    });
    const number = typedValue(isNumber, "number");
    const string = typedValue(isString, "string");
    const boolean = typedValue(isBoolean, "boolean");
    const functionProcessor = typedValue(isFunction, "function");
    const field = field$1;
    const customField = customField$1;
    const validateEnum = (values2) => valueOf((value2) => contains$2(values2, value2) ? Result.value(value2) : Result.error(`Unsupported value: "${value2}", choose one of "${values2.join(", ")}".`));
    const requiredOf = (key, schema) => field(key, key, required(), schema);
    const requiredString = (key) => requiredOf(key, string);
    const requiredFunction = (key) => requiredOf(key, functionProcessor);
    const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
    const optionOf = (key, schema) => field(key, key, asOption(), schema);
    const optionString = (key) => optionOf(key, string);
    const optionFunction = (key) => optionOf(key, functionProcessor);
    const defaulted = (key, fallback2) => field(key, key, defaulted$1(fallback2), anyValue());
    const defaultedOf = (key, fallback2, schema) => field(key, key, defaulted$1(fallback2), schema);
    const defaultedNumber = (key, fallback2) => defaultedOf(key, fallback2, number);
    const defaultedString = (key, fallback2) => defaultedOf(key, fallback2, string);
    const defaultedStringEnum = (key, fallback2, values2) => defaultedOf(key, fallback2, validateEnum(values2));
    const defaultedBoolean = (key, fallback2) => defaultedOf(key, fallback2, boolean);
    const defaultedFunction = (key, fallback2) => defaultedOf(key, fallback2, functionProcessor);
    const defaultedArrayOf = (key, fallback2, schema) => defaultedOf(key, fallback2, arrOf(schema));
    const type = requiredString("type");
    const fetch$1 = requiredFunction("fetch");
    const onAction = requiredFunction("onAction");
    const onSetup = defaultedFunction("onSetup", () => noop);
    const optionalText = optionString("text");
    const optionalIcon = optionString("icon");
    const optionalTooltip = optionString("tooltip");
    const optionalLabel = optionString("label");
    const active = defaultedBoolean("active", false);
    const enabled = defaultedBoolean("enabled", true);
    const primary = defaultedBoolean("primary", false);
    const defaultedColumns = (num) => defaulted("columns", num);
    const defaultedType = (type2) => defaultedString("type", type2);
    const autocompleterSchema = objOf([
      type,
      requiredString("ch"),
      defaultedNumber("minChars", 1),
      defaultedColumns(1),
      defaultedNumber("maxResults", 10),
      optionFunction("matches"),
      fetch$1,
      onAction,
      defaultedArrayOf("highlightOn", [], string)
    ]);
    const createAutocompleter = (spec) => asRaw("Autocompleter", autocompleterSchema, spec);
    const baseToolbarButtonFields = [
      enabled,
      optionalTooltip,
      optionalIcon,
      optionalText,
      onSetup
    ];
    const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
    const contextBarFields = [
      defaultedFunction("predicate", never),
      defaultedStringEnum("scope", "node", [
        "node",
        "editor"
      ]),
      defaultedStringEnum("position", "selection", [
        "node",
        "selection",
        "line"
      ])
    ];
    const contextButtonFields = baseToolbarButtonFields.concat([
      defaultedType("contextformbutton"),
      primary,
      onAction,
      customField("original", identity)
    ]);
    const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
      defaultedType("contextformbutton"),
      primary,
      onAction,
      customField("original", identity)
    ]);
    const launchButtonFields = baseToolbarButtonFields.concat([defaultedType("contextformbutton")]);
    const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType("contextformtogglebutton")]);
    const toggleOrNormal = choose("type", {
      contextformbutton: contextButtonFields,
      contextformtogglebutton: contextToggleButtonFields
    });
    objOf([
      defaultedType("contextform"),
      defaultedFunction("initValue", constant("")),
      optionalLabel,
      requiredArrayOf("commands", toggleOrNormal),
      optionOf("launch", choose("type", {
        contextformbutton: launchButtonFields,
        contextformtogglebutton: launchToggleButtonFields
      }))
    ].concat(contextBarFields));
    const register$2 = (editor) => {
      const popups = editor.ui.registry.getAll().popups;
      const dataset = map$2(popups, (popup) => createAutocompleter(popup).fold((err) => {
        throw new Error(formatError(err));
      }, identity));
      const triggerChars = stringArray(mapToArray(dataset, (v) => v.ch));
      const datasetValues = values(dataset);
      const lookupByChar = (ch) => filter$6(datasetValues, (dv) => dv.ch === ch);
      return {
        dataset,
        triggerChars,
        lookupByChar
      };
    };
    const setupEditorInput = (editor, api2) => {
      const update = last$1(api2.load, 50);
      editor.on("keypress compositionend", (e) => {
        if (e.which === 27) {
          return;
        }
        update.throttle();
      });
      editor.on("keydown", (e) => {
        const keyCode = e.which;
        if (keyCode === 8) {
          update.throttle();
        } else if (keyCode === 27) {
          api2.cancelIfNecessary();
        }
      });
      editor.on("remove", update.cancel);
    };
    const setup$j = (editor) => {
      const activeAutocompleter = value$2();
      const uiActive = Cell(false);
      const isActive = activeAutocompleter.isSet;
      const cancelIfNecessary = () => {
        if (isActive()) {
          removeAutocompleterDecoration(editor);
          fireAutocompleterEnd(editor);
          uiActive.set(false);
          activeAutocompleter.clear();
        }
      };
      const commenceIfNecessary = (context2) => {
        if (!isActive()) {
          addAutocompleterDecoration(editor, context2.range);
          activeAutocompleter.set({
            triggerChar: context2.triggerChar,
            matchLength: context2.text.length
          });
        }
      };
      const getAutocompleters = cached(() => register$2(editor));
      const doLookup = (fetchOptions) => activeAutocompleter.get().map((ac) => getContext(editor.dom, editor.selection.getRng(), ac.triggerChar).bind((newContext) => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters));
      const load = (fetchOptions) => {
        doLookup(fetchOptions).fold(cancelIfNecessary, (lookupInfo) => {
          commenceIfNecessary(lookupInfo.context);
          lookupInfo.lookupData.then((lookupData) => {
            activeAutocompleter.get().map((ac) => {
              const context2 = lookupInfo.context;
              if (ac.triggerChar === context2.triggerChar) {
                if (context2.text.length - ac.matchLength >= 10) {
                  cancelIfNecessary();
                } else {
                  activeAutocompleter.set({
                    ...ac,
                    matchLength: context2.text.length
                  });
                  if (uiActive.get()) {
                    fireAutocompleterUpdate(editor, { lookupData });
                  } else {
                    uiActive.set(true);
                    fireAutocompleterStart(editor, { lookupData });
                  }
                }
              }
            });
          });
        });
      };
      editor.addCommand("mceAutocompleterReload", (_ui, value2) => {
        const fetchOptions = isObject(value2) ? value2.fetchOptions : {};
        load(fetchOptions);
      });
      editor.addCommand("mceAutocompleterClose", cancelIfNecessary);
      setupEditorInput(editor, {
        cancelIfNecessary,
        load
      });
    };
    const createAndFireInputEvent = (eventType) => (editor, inputType, specifics = {}) => {
      const target = editor.getBody();
      const overrides = {
        bubbles: true,
        composed: true,
        data: null,
        isComposing: false,
        detail: 0,
        view: null,
        target,
        currentTarget: target,
        eventPhase: Event.AT_TARGET,
        originalTarget: target,
        explicitOriginalTarget: target,
        isTrusted: false,
        srcElement: target,
        cancelable: false,
        preventDefault: noop,
        inputType
      };
      const input = clone$3(new InputEvent(eventType));
      return editor.dispatch(eventType, {
        ...input,
        ...overrides,
        ...specifics
      });
    };
    const fireFakeInputEvent = createAndFireInputEvent("input");
    const fireFakeBeforeInputEvent = createAndFireInputEvent("beforeinput");
    const executeKeydownOverride$3 = (editor, caret, evt) => {
      const inputType = evt.keyCode === VK.BACKSPACE ? "deleteContentBackward" : "deleteContentForward";
      executeWithDelayedAction([
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete, editor)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$5, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$5, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$6, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$6, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$3, editor, caret, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$3, editor, caret, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$9, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$9, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$4, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$4, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$1, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$1, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$7, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$7, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$8, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$8, editor, true)
        },
        {
          keyCode: VK.BACKSPACE,
          action: action(backspaceDelete$2, editor, false)
        },
        {
          keyCode: VK.DELETE,
          action: action(backspaceDelete$2, editor, true)
        }
      ], evt).each((applyAction) => {
        evt.preventDefault();
        const beforeInput = fireFakeBeforeInputEvent(editor, inputType);
        if (!beforeInput.isDefaultPrevented()) {
          applyAction();
          fireFakeInputEvent(editor, inputType);
        }
      });
    };
    const executeKeyupOverride = (editor, evt) => {
      execute([
        {
          keyCode: VK.BACKSPACE,
          action: action(paddEmptyElement, editor)
        },
        {
          keyCode: VK.DELETE,
          action: action(paddEmptyElement, editor)
        }
      ], evt);
    };
    const setup$i = (editor, caret) => {
      editor.on("keydown", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeydownOverride$3(editor, caret, evt);
        }
      });
      editor.on("keyup", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeyupOverride(editor, evt);
        }
      });
    };
    const firstNonWhiteSpaceNodeSibling = (node) => {
      while (node) {
        if (node.nodeType === 1 || node.nodeType === 3 && node.data && /[\r\n\s]/.test(node.data)) {
          return node;
        }
        node = node.nextSibling;
      }
    };
    const moveToCaretPosition = (editor, root) => {
      let node, lastNode = root;
      const dom2 = editor.dom;
      const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
      if (!root) {
        return;
      }
      if (/^(LI|DT|DD)$/.test(root.nodeName)) {
        const firstChild2 = firstNonWhiteSpaceNodeSibling(root.firstChild);
        if (firstChild2 && /^(UL|OL|DL)$/.test(firstChild2.nodeName)) {
          root.insertBefore(dom2.doc.createTextNode(nbsp), root.firstChild);
        }
      }
      const rng = dom2.createRng();
      root.normalize();
      if (root.hasChildNodes()) {
        const walker = new DomTreeWalker(root, root);
        while (node = walker.current()) {
          if (isText$9(node)) {
            rng.setStart(node, 0);
            rng.setEnd(node, 0);
            break;
          }
          if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
            rng.setStartBefore(node);
            rng.setEndBefore(node);
            break;
          }
          lastNode = node;
          node = walker.next();
        }
        if (!node) {
          rng.setStart(lastNode, 0);
          rng.setEnd(lastNode, 0);
        }
      } else {
        if (isBr$6(root)) {
          if (root.nextSibling && dom2.isBlock(root.nextSibling)) {
            rng.setStartBefore(root);
            rng.setEndBefore(root);
          } else {
            rng.setStartAfter(root);
            rng.setEndAfter(root);
          }
        } else {
          rng.setStart(root, 0);
          rng.setEnd(root, 0);
        }
      }
      editor.selection.setRng(rng);
      scrollRangeIntoView(editor, rng);
    };
    const getEditableRoot$1 = (dom2, node) => {
      const root = dom2.getRoot();
      let parent2, editableRoot;
      parent2 = node;
      while (parent2 !== root && dom2.getContentEditable(parent2) !== "false") {
        if (dom2.getContentEditable(parent2) === "true") {
          editableRoot = parent2;
        }
        parent2 = parent2.parentNode;
      }
      return parent2 !== root ? editableRoot : root;
    };
    const getParentBlock$1 = (editor) => {
      return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
    };
    const getParentBlockName = (editor) => {
      return getParentBlock$1(editor).fold(constant(""), (parentBlock) => {
        return parentBlock.nodeName.toUpperCase();
      });
    };
    const isListItemParentBlock = (editor) => {
      return getParentBlock$1(editor).filter((elm) => {
        return isListItem(SugarElement.fromDom(elm));
      }).isSome();
    };
    const hasFirstChild = (elm, name2) => {
      return elm.firstChild && elm.firstChild.nodeName === name2;
    };
    const isFirstChild = (elm) => {
      var _a;
      return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
    };
    const hasParent = (elm, parentName) => {
      return elm && elm.parentNode && elm.parentNode.nodeName === parentName;
    };
    const isListBlock = (elm) => {
      return elm && /^(OL|UL|LI)$/.test(elm.nodeName);
    };
    const isNestedList = (elm) => {
      return isListBlock(elm) && isListBlock(elm.parentNode);
    };
    const getContainerBlock = (containerBlock) => {
      const containerBlockParent = containerBlock.parentNode;
      if (/^(LI|DT|DD)$/.test(containerBlockParent.nodeName)) {
        return containerBlockParent;
      }
      return containerBlock;
    };
    const isFirstOrLastLi = (containerBlock, parentBlock, first2) => {
      let node = containerBlock[first2 ? "firstChild" : "lastChild"];
      while (node) {
        if (isElement$6(node)) {
          break;
        }
        node = node[first2 ? "nextSibling" : "previousSibling"];
      }
      return node === parentBlock;
    };
    const insert$3 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
      const dom2 = editor.dom;
      const rng = editor.selection.getRng();
      if (containerBlock === editor.getBody()) {
        return;
      }
      if (isNestedList(containerBlock)) {
        newBlockName = "LI";
      }
      let newBlock = createNewBlock(newBlockName);
      if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
        if (hasParent(containerBlock, "LI")) {
          const containerBlockParent = getContainerBlock(containerBlock);
          dom2.insertAfter(newBlock, containerBlockParent);
          if (isFirstChild(containerBlock)) {
            dom2.remove(containerBlockParent);
          } else {
            dom2.remove(containerBlock);
          }
        } else {
          dom2.replace(newBlock, containerBlock);
        }
      } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
        if (hasParent(containerBlock, "LI")) {
          dom2.insertAfter(newBlock, getContainerBlock(containerBlock));
          newBlock.appendChild(dom2.doc.createTextNode(" "));
          newBlock.appendChild(containerBlock);
        } else {
          containerBlock.parentNode.insertBefore(newBlock, containerBlock);
        }
        dom2.remove(parentBlock);
      } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
        dom2.insertAfter(newBlock, getContainerBlock(containerBlock));
        dom2.remove(parentBlock);
      } else {
        containerBlock = getContainerBlock(containerBlock);
        const tmpRng = rng.cloneRange();
        tmpRng.setStartAfter(parentBlock);
        tmpRng.setEndAfter(containerBlock);
        const fragment = tmpRng.extractContents();
        if (newBlockName === "LI" && hasFirstChild(fragment, "LI")) {
          newBlock = fragment.firstChild;
          dom2.insertAfter(fragment, containerBlock);
        } else {
          dom2.insertAfter(fragment, containerBlock);
          dom2.insertAfter(newBlock, containerBlock);
        }
        dom2.remove(parentBlock);
      }
      moveToCaretPosition(editor, newBlock);
    };
    const trimZwsp = (fragment) => {
      each$f(descendants$1(SugarElement.fromDom(fragment), isText$a), (text2) => {
        const rawNode = text2.dom;
        rawNode.nodeValue = trim$1(rawNode.nodeValue);
      });
    };
    const isEmptyAnchor = (dom2, elm) => {
      return elm && elm.nodeName === "A" && dom2.isEmpty(elm);
    };
    const isTableCell = (node) => {
      return node && /^(TD|TH|CAPTION)$/.test(node.nodeName);
    };
    const emptyBlock = (elm) => {
      elm.innerHTML = '<br data-mce-bogus="1">';
    };
    const containerAndSiblingName = (container, nodeName) => {
      return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
    };
    const canSplitBlock = (dom2, node) => {
      return node && dom2.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom2.getContentEditable(node) !== "true";
    };
    const trimInlineElementsOnLeftSideOfBlock = (dom2, nonEmptyElementsMap, block) => {
      let node = block;
      const firstChilds = [];
      let i;
      if (!node) {
        return;
      }
      while (node = node.firstChild) {
        if (dom2.isBlock(node)) {
          return;
        }
        if (isElement$6(node) && !nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
          firstChilds.push(node);
        }
      }
      i = firstChilds.length;
      while (i--) {
        node = firstChilds[i];
        if (!node.hasChildNodes() || node.firstChild === node.lastChild && node.firstChild.nodeValue === "") {
          dom2.remove(node);
        } else {
          if (isEmptyAnchor(dom2, node)) {
            dom2.remove(node);
          }
        }
      }
    };
    const normalizeZwspOffset = (start2, container, offset) => {
      if (isText$9(container) === false) {
        return offset;
      } else if (start2) {
        return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
      } else {
        return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
      }
    };
    const includeZwspInRange = (rng) => {
      const newRng = rng.cloneRange();
      newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
      newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
      return newRng;
    };
    const trimLeadingLineBreaks = (node) => {
      do {
        if (isText$9(node)) {
          node.nodeValue = node.nodeValue.replace(/^[\r\n]+/, "");
        }
        node = node.firstChild;
      } while (node);
    };
    const getEditableRoot = (dom2, node) => {
      const root = dom2.getRoot();
      let parent2, editableRoot;
      parent2 = node;
      while (parent2 !== root && dom2.getContentEditable(parent2) !== "false") {
        if (dom2.getContentEditable(parent2) === "true") {
          editableRoot = parent2;
        }
        parent2 = parent2.parentNode;
      }
      return parent2 !== root ? editableRoot : root;
    };
    const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
      const dom2 = editor.dom;
      Optional.from(forcedRootBlockAttrs.style).map(dom2.parseStyle).each((attrStyles) => {
        const currentStyles = getAllRaw(SugarElement.fromDom(node));
        const newStyles = {
          ...currentStyles,
          ...attrStyles
        };
        dom2.setStyles(node, newStyles);
      });
      const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map((attrClasses) => attrClasses.split(/\s+/));
      const currentClassesOpt = Optional.from(node.className).map((currentClasses) => filter$6(currentClasses.split(/\s+/), (clazz) => clazz !== ""));
      lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
        const filteredClasses = filter$6(currentClasses, (clazz) => !contains$2(attrClasses, clazz));
        const newClasses = [
          ...attrClasses,
          ...filteredClasses
        ];
        dom2.setAttrib(node, "class", newClasses.join(" "));
      });
      const appliedAttrs = [
        "style",
        "class"
      ];
      const remainingAttrs = filter$5(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
      dom2.setAttribs(node, remainingAttrs);
    };
    const setForcedBlockAttrs = (editor, node) => {
      const forcedRootBlockName = getForcedRootBlock(editor);
      if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
        const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
        applyAttributes(editor, node, forcedRootBlockAttrs);
      }
    };
    const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
      let newBlock, parentBlock, startNode, node, next2, rootBlockName;
      const dom2 = editor.dom, editableRoot = getEditableRoot(dom2, container);
      parentBlock = dom2.getParent(container, dom2.isBlock);
      if (!parentBlock || !canSplitBlock(dom2, parentBlock)) {
        parentBlock = parentBlock || editableRoot;
        if (parentBlock === editor.getBody() || isTableCell(parentBlock)) {
          rootBlockName = parentBlock.nodeName.toLowerCase();
        } else {
          rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
        }
        if (!parentBlock.hasChildNodes()) {
          newBlock = dom2.create(newBlockName);
          setForcedBlockAttrs(editor, newBlock);
          parentBlock.appendChild(newBlock);
          rng.setStart(newBlock, 0);
          rng.setEnd(newBlock, 0);
          return newBlock;
        }
        node = container;
        while (node.parentNode !== parentBlock) {
          node = node.parentNode;
        }
        while (node && !dom2.isBlock(node)) {
          startNode = node;
          node = node.previousSibling;
        }
        if (startNode && editor.schema.isValidChild(rootBlockName, newBlockName.toLowerCase())) {
          newBlock = dom2.create(newBlockName);
          setForcedBlockAttrs(editor, newBlock);
          startNode.parentNode.insertBefore(newBlock, startNode);
          node = startNode;
          while (node && !dom2.isBlock(node)) {
            next2 = node.nextSibling;
            newBlock.appendChild(node);
            node = next2;
          }
          rng.setStart(container, offset);
          rng.setEnd(container, offset);
        }
      }
      return container;
    };
    const addBrToBlockIfNeeded = (dom2, block) => {
      block.normalize();
      const lastChild2 = block.lastChild;
      if (!lastChild2 || /^(left|right)$/gi.test(dom2.getStyle(lastChild2, "float", true))) {
        dom2.add(block, "br");
      }
    };
    const shouldEndContainer = (editor, container) => {
      const optionValue = shouldEndContainerOnEmptyBlock(editor);
      if (isNullable(container)) {
        return false;
      } else if (isString(optionValue)) {
        return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
      } else {
        return optionValue;
      }
    };
    const insert$2 = (editor, evt) => {
      let tmpRng, container, offset, parentBlock;
      let newBlock, fragment, containerBlock, parentBlockName, isAfterLastNodeInContainer;
      const dom2 = editor.dom;
      const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
      const rng = editor.selection.getRng();
      const newBlockName = getForcedRootBlock(editor);
      const createNewBlock = (name2) => {
        let node = container, block, clonedNode, caretNode;
        const textInlineElements = schema.getTextInlineElements();
        if (name2 || parentBlockName === "TABLE" || parentBlockName === "HR") {
          block = dom2.create(name2 || newBlockName);
        } else {
          block = parentBlock.cloneNode(false);
        }
        caretNode = block;
        if (shouldKeepStyles(editor) === false) {
          dom2.setAttrib(block, "style", null);
          dom2.setAttrib(block, "class", null);
        } else {
          do {
            if (textInlineElements[node.nodeName]) {
              if (isCaretNode(node) || isBookmarkNode$1(node)) {
                continue;
              }
              clonedNode = node.cloneNode(false);
              dom2.setAttrib(clonedNode, "id", "");
              if (block.hasChildNodes()) {
                clonedNode.appendChild(block.firstChild);
                block.appendChild(clonedNode);
              } else {
                caretNode = clonedNode;
                block.appendChild(clonedNode);
              }
            }
          } while ((node = node.parentNode) && node !== editableRoot);
        }
        setForcedBlockAttrs(editor, block);
        emptyBlock(caretNode);
        return block;
      };
      const isCaretAtStartOrEndOfBlock = (start2) => {
        let node, name2;
        const normalizedOffset = normalizeZwspOffset(start2, container, offset);
        if (isText$9(container) && (start2 ? normalizedOffset > 0 : normalizedOffset < container.nodeValue.length)) {
          return false;
        }
        if (container.parentNode === parentBlock && isAfterLastNodeInContainer && !start2) {
          return true;
        }
        if (start2 && isElement$6(container) && container === parentBlock.firstChild) {
          return true;
        }
        if (containerAndSiblingName(container, "TABLE") || containerAndSiblingName(container, "HR")) {
          return isAfterLastNodeInContainer && !start2 || !isAfterLastNodeInContainer && start2;
        }
        const walker = new DomTreeWalker(container, parentBlock);
        if (isText$9(container)) {
          if (start2 && normalizedOffset === 0) {
            walker.prev();
          } else if (!start2 && normalizedOffset === container.nodeValue.length) {
            walker.next();
          }
        }
        while (node = walker.current()) {
          if (isElement$6(node)) {
            if (!node.getAttribute("data-mce-bogus")) {
              name2 = node.nodeName.toLowerCase();
              if (nonEmptyElementsMap[name2] && name2 !== "br") {
                return false;
              }
            }
          } else if (isText$9(node) && !isWhitespaceText(node.nodeValue)) {
            return false;
          }
          if (start2) {
            walker.prev();
          } else {
            walker.next();
          }
        }
        return true;
      };
      const insertNewBlockAfter = () => {
        if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== "HGROUP") {
          newBlock = createNewBlock(newBlockName);
        } else {
          newBlock = createNewBlock();
        }
        if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom2, containerBlock) && dom2.isEmpty(parentBlock)) {
          newBlock = dom2.split(containerBlock, parentBlock);
        } else {
          dom2.insertAfter(newBlock, parentBlock);
        }
        moveToCaretPosition(editor, newBlock);
      };
      normalize$2(dom2, rng).each((normRng) => {
        rng.setStart(normRng.startContainer, normRng.startOffset);
        rng.setEnd(normRng.endContainer, normRng.endOffset);
      });
      container = rng.startContainer;
      offset = rng.startOffset;
      const shiftKey = !!(evt && evt.shiftKey);
      const ctrlKey = !!(evt && evt.ctrlKey);
      if (isElement$6(container) && container.hasChildNodes()) {
        isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
        if (isAfterLastNodeInContainer && isText$9(container)) {
          offset = container.nodeValue.length;
        } else {
          offset = 0;
        }
      }
      const editableRoot = getEditableRoot(dom2, container);
      if (!editableRoot) {
        return;
      }
      if (!shiftKey) {
        container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
      }
      parentBlock = dom2.getParent(container, dom2.isBlock);
      containerBlock = parentBlock ? dom2.getParent(parentBlock.parentNode, dom2.isBlock) : null;
      parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : "";
      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : "";
      if (containerBlockName === "LI" && !ctrlKey) {
        parentBlock = containerBlock;
        containerBlock = containerBlock.parentNode;
        parentBlockName = containerBlockName;
      }
      if (/^(LI|DT|DD)$/.test(parentBlockName)) {
        if (dom2.isEmpty(parentBlock)) {
          insert$3(editor, createNewBlock, containerBlock, parentBlock, newBlockName);
          return;
        }
      }
      if (parentBlock === editor.getBody()) {
        return;
      }
      if (isCaretContainerBlock$1(parentBlock)) {
        newBlock = showCaretContainerBlock(parentBlock);
        if (dom2.isEmpty(parentBlock)) {
          emptyBlock(parentBlock);
        }
        setForcedBlockAttrs(editor, newBlock);
        moveToCaretPosition(editor, newBlock);
      } else if (isCaretAtStartOrEndOfBlock()) {
        insertNewBlockAfter();
      } else if (isCaretAtStartOrEndOfBlock(true)) {
        newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
        moveToCaretPosition(editor, containerAndSiblingName(parentBlock, "HR") ? newBlock : parentBlock);
      } else {
        tmpRng = includeZwspInRange(rng).cloneRange();
        tmpRng.setEndAfter(parentBlock);
        fragment = tmpRng.extractContents();
        trimZwsp(fragment);
        trimLeadingLineBreaks(fragment);
        newBlock = fragment.firstChild;
        dom2.insertAfter(fragment, parentBlock);
        trimInlineElementsOnLeftSideOfBlock(dom2, nonEmptyElementsMap, newBlock);
        addBrToBlockIfNeeded(dom2, parentBlock);
        if (dom2.isEmpty(parentBlock)) {
          emptyBlock(parentBlock);
        }
        newBlock.normalize();
        if (dom2.isEmpty(newBlock)) {
          dom2.remove(newBlock);
          insertNewBlockAfter();
        } else {
          setForcedBlockAttrs(editor, newBlock);
          moveToCaretPosition(editor, newBlock);
        }
      }
      dom2.setAttrib(newBlock, "id", "");
      editor.dispatch("NewBlock", { newBlock });
    };
    const fakeEventName$1 = "insertParagraph";
    const blockbreak = {
      insert: insert$2,
      fakeEventName: fakeEventName$1
    };
    const hasRightSideContent = (schema, container, parentBlock) => {
      const walker = new DomTreeWalker(container, parentBlock);
      let node;
      const nonEmptyElementsMap = schema.getNonEmptyElements();
      while (node = walker.next()) {
        if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || node.length > 0) {
          return true;
        }
      }
    };
    const moveSelectionToBr = (editor, brElm, extraBr) => {
      const rng = editor.dom.createRng();
      if (!extraBr) {
        rng.setStartAfter(brElm);
        rng.setEndAfter(brElm);
      } else {
        rng.setStartBefore(brElm);
        rng.setEndBefore(brElm);
      }
      editor.selection.setRng(rng);
      scrollRangeIntoView(editor, rng);
    };
    const insertBrAtCaret = (editor, evt) => {
      const selection = editor.selection;
      const dom2 = editor.dom;
      const rng = selection.getRng();
      let brElm;
      let extraBr;
      normalize$2(dom2, rng).each((normRng) => {
        rng.setStart(normRng.startContainer, normRng.startOffset);
        rng.setEnd(normRng.endContainer, normRng.endOffset);
      });
      let offset = rng.startOffset;
      let container = rng.startContainer;
      if (container.nodeType === 1 && container.hasChildNodes()) {
        const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
        container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
        if (isAfterLastNodeInContainer && container.nodeType === 3) {
          offset = container.nodeValue.length;
        } else {
          offset = 0;
        }
      }
      let parentBlock = dom2.getParent(container, dom2.isBlock);
      const containerBlock = parentBlock ? dom2.getParent(parentBlock.parentNode, dom2.isBlock) : null;
      const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : "";
      const isControlKey = !!(evt && evt.ctrlKey);
      if (containerBlockName === "LI" && !isControlKey) {
        parentBlock = containerBlock;
      }
      if (container && container.nodeType === 3 && offset >= container.nodeValue.length) {
        if (!hasRightSideContent(editor.schema, container, parentBlock)) {
          brElm = dom2.create("br");
          rng.insertNode(brElm);
          rng.setStartAfter(brElm);
          rng.setEndAfter(brElm);
          extraBr = true;
        }
      }
      brElm = dom2.create("br");
      rangeInsertNode(dom2, rng, brElm);
      moveSelectionToBr(editor, brElm, extraBr);
      editor.undoManager.add();
    };
    const insertBrBefore = (editor, inline) => {
      const br = SugarElement.fromTag("br");
      before$3(SugarElement.fromDom(inline), br);
      editor.undoManager.add();
    };
    const insertBrAfter = (editor, inline) => {
      if (!hasBrAfter(editor.getBody(), inline)) {
        after$4(SugarElement.fromDom(inline), SugarElement.fromTag("br"));
      }
      const br = SugarElement.fromTag("br");
      after$4(SugarElement.fromDom(inline), br);
      moveSelectionToBr(editor, br.dom, false);
      editor.undoManager.add();
    };
    const isBeforeBr = (pos) => {
      return isBr$6(pos.getNode());
    };
    const hasBrAfter = (rootNode, startNode) => {
      if (isBeforeBr(CaretPosition.after(startNode))) {
        return true;
      } else {
        return nextPosition(rootNode, CaretPosition.after(startNode)).map((pos) => {
          return isBr$6(pos.getNode());
        }).getOr(false);
      }
    };
    const isAnchorLink = (elm) => {
      return elm && elm.nodeName === "A" && "href" in elm;
    };
    const isInsideAnchor = (location) => {
      return location.fold(never, isAnchorLink, isAnchorLink, never);
    };
    const readInlineAnchorLocation = (editor) => {
      const isInlineTarget$1 = curry(isInlineTarget, editor);
      const position = CaretPosition.fromRangeStart(editor.selection.getRng());
      return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
    };
    const insertBrOutsideAnchor = (editor, location) => {
      location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
    };
    const insert$1 = (editor, evt) => {
      const anchorLocation = readInlineAnchorLocation(editor);
      if (anchorLocation.isSome()) {
        anchorLocation.each(curry(insertBrOutsideAnchor, editor));
      } else {
        insertBrAtCaret(editor, evt);
      }
    };
    const fakeEventName = "insertLineBreak";
    const linebreak = {
      insert: insert$1,
      fakeEventName
    };
    const matchesSelector = (editor, selector) => {
      return getParentBlock$1(editor).filter((parentBlock) => {
        return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
      }).isSome();
    };
    const shouldInsertBr = (editor) => {
      return matchesSelector(editor, getBrNewLineSelector(editor));
    };
    const shouldBlockNewLine$1 = (editor) => {
      return matchesSelector(editor, getNoNewLineSelector(editor));
    };
    const newLineAction = Adt.generate([
      { br: [] },
      { block: [] },
      { none: [] }
    ]);
    const shouldBlockNewLine = (editor, _shiftKey) => {
      return shouldBlockNewLine$1(editor);
    };
    const inListBlock = (requiredState) => {
      return (editor, _shiftKey) => {
        return isListItemParentBlock(editor) === requiredState;
      };
    };
    const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
      const state = getParentBlockName(editor) === blockName.toUpperCase();
      return state === requiredState;
    };
    const inPreBlock = (requiredState) => inBlock("pre", requiredState);
    const inSummaryBlock = () => inBlock("summary", true);
    const shouldPutBrInPre = (requiredState) => {
      return (editor, _shiftKey) => {
        return shouldPutBrInPre$1(editor) === requiredState;
      };
    };
    const inBrContext = (editor, _shiftKey) => {
      return shouldInsertBr(editor);
    };
    const hasShiftKey = (_editor, shiftKey) => {
      return shiftKey;
    };
    const canInsertIntoEditableRoot = (editor) => {
      const forcedRootBlock = getForcedRootBlock(editor);
      const rootEditable = getEditableRoot$1(editor.dom, editor.selection.getStart());
      return rootEditable && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
    };
    const match = (predicates, action2) => {
      return (editor, shiftKey) => {
        const isMatch = foldl(predicates, (res, p) => {
          return res && p(editor, shiftKey);
        }, true);
        return isMatch ? Optional.some(action2) : Optional.none();
      };
    };
    const getAction = (editor, evt) => {
      return evaluateUntil([
        match([shouldBlockNewLine], newLineAction.none()),
        match([inSummaryBlock()], newLineAction.br()),
        match([
          inPreBlock(true),
          shouldPutBrInPre(false),
          hasShiftKey
        ], newLineAction.br()),
        match([
          inPreBlock(true),
          shouldPutBrInPre(false)
        ], newLineAction.block()),
        match([
          inPreBlock(true),
          shouldPutBrInPre(true),
          hasShiftKey
        ], newLineAction.block()),
        match([
          inPreBlock(true),
          shouldPutBrInPre(true)
        ], newLineAction.br()),
        match([
          inListBlock(true),
          hasShiftKey
        ], newLineAction.br()),
        match([inListBlock(true)], newLineAction.block()),
        match([inBrContext], newLineAction.br()),
        match([hasShiftKey], newLineAction.br()),
        match([canInsertIntoEditableRoot], newLineAction.block())
      ], [
        editor,
        !!(evt && evt.shiftKey)
      ]).getOr(newLineAction.none());
    };
    const insertBreak = (breakType, editor, evt) => {
      if (!editor.selection.isCollapsed()) {
        execDeleteCommand(editor);
      }
      if (isNonNullable(evt)) {
        const event = fireFakeBeforeInputEvent(editor, breakType.fakeEventName);
        if (event.isDefaultPrevented()) {
          return;
        }
      }
      breakType.insert(editor, evt);
      if (isNonNullable(evt)) {
        fireFakeInputEvent(editor, breakType.fakeEventName);
      }
    };
    const insert = (editor, evt) => {
      const br = () => insertBreak(linebreak, editor, evt);
      const block = () => insertBreak(blockbreak, editor, evt);
      const logicalAction = getAction(editor, evt);
      switch (getNewlineBehavior(editor)) {
        case "linebreak":
          logicalAction.fold(br, br, noop);
          break;
        case "block":
          logicalAction.fold(block, block, noop);
          break;
        case "invert":
          logicalAction.fold(block, br, noop);
          break;
        default:
          logicalAction.fold(br, block, noop);
          break;
      }
    };
    const handleEnterKeyEvent = (editor, event) => {
      if (event.isDefaultPrevented()) {
        return;
      }
      event.preventDefault();
      endTypingLevelIgnoreLocks(editor.undoManager);
      editor.undoManager.transact(() => {
        insert(editor, event);
      });
    };
    const setup$h = (editor) => {
      editor.on("keydown", (event) => {
        if (event.keyCode === VK.ENTER) {
          handleEnterKeyEvent(editor, event);
        }
      });
    };
    const executeKeydownOverride$2 = (editor, caret, evt) => {
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
      execute([
        {
          keyCode: VK.END,
          action: action(moveToLineEndPoint$1, editor, true)
        },
        {
          keyCode: VK.HOME,
          action: action(moveToLineEndPoint$1, editor, false)
        },
        ...!isMac ? [
          {
            keyCode: VK.HOME,
            action: action(selectToEndPoint, editor, false),
            ctrlKey: true,
            shiftKey: true
          },
          {
            keyCode: VK.END,
            action: action(selectToEndPoint, editor, true),
            ctrlKey: true,
            shiftKey: true
          }
        ] : [],
        {
          keyCode: VK.END,
          action: action(moveToLineEndPoint, editor, true)
        },
        {
          keyCode: VK.HOME,
          action: action(moveToLineEndPoint, editor, false)
        },
        {
          keyCode: VK.END,
          action: action(moveToLineEndPoint$2, editor, true, caret)
        },
        {
          keyCode: VK.HOME,
          action: action(moveToLineEndPoint$2, editor, false, caret)
        }
      ], evt).each((_) => {
        evt.preventDefault();
      });
    };
    const setup$g = (editor, caret) => {
      editor.on("keydown", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeydownOverride$2(editor, caret, evt);
        }
      });
    };
    const setup$f = (editor) => {
      editor.on("input", (e) => {
        if (e.isComposing === false) {
          normalizeNbspsInEditor(editor);
        }
      });
    };
    const platform = detect$2();
    const executeKeyupAction = (editor, caret, evt) => {
      execute([
        {
          keyCode: VK.PAGE_UP,
          action: action(moveToLineEndPoint$2, editor, false, caret)
        },
        {
          keyCode: VK.PAGE_DOWN,
          action: action(moveToLineEndPoint$2, editor, true, caret)
        }
      ], evt);
    };
    const stopImmediatePropagation = (e) => e.stopImmediatePropagation();
    const isPageUpDown = (evt) => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
    const setNodeChangeBlocker = (blocked, editor, block) => {
      if (block && !blocked.get()) {
        editor.on("NodeChange", stopImmediatePropagation, true);
      } else if (!block && blocked.get()) {
        editor.off("NodeChange", stopImmediatePropagation);
      }
      blocked.set(block);
    };
    const setup$e = (editor, caret) => {
      if (platform.os.isMacOS()) {
        return;
      }
      const blocked = Cell(false);
      editor.on("keydown", (evt) => {
        if (isPageUpDown(evt)) {
          setNodeChangeBlocker(blocked, editor, true);
        }
      });
      editor.on("keyup", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeyupAction(editor, caret, evt);
        }
        if (isPageUpDown(evt) && blocked.get()) {
          setNodeChangeBlocker(blocked, editor, false);
          editor.nodeChanged();
        }
      });
    };
    const insertTextAtPosition = (text2, pos) => {
      const container = pos.container();
      const offset = pos.offset();
      if (isText$9(container)) {
        container.insertData(offset, text2);
        return Optional.some(CaretPosition(container, offset + text2.length));
      } else {
        return getElementFromPosition(pos).map((elm) => {
          const textNode = SugarElement.fromText(text2);
          if (pos.isAtEnd()) {
            after$4(elm, textNode);
          } else {
            before$3(elm, textNode);
          }
          return CaretPosition(textNode.dom, text2.length);
        });
      }
    };
    const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
    const insertSpaceAtPosition = curry(insertTextAtPosition, " ");
    const locationToCaretPosition = (root) => (location) => location.fold((element) => prevPosition(root.dom, CaretPosition.before(element)), (element) => firstPositionIn(element), (element) => lastPositionIn(element), (element) => nextPosition(root.dom, CaretPosition.after(element)));
    const insertInlineBoundarySpaceOrNbsp = (root, pos) => (checkPos) => needsToHaveNbsp(root, checkPos) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
    const setSelection = (editor) => (pos) => {
      editor.selection.setRng(pos.toRange());
      editor.nodeChanged();
      return true;
    };
    const insertSpaceOrNbspAtSelection = (editor) => {
      const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
      const root = SugarElement.fromDom(editor.getBody());
      if (editor.selection.isCollapsed()) {
        const isInlineTarget$1 = curry(isInlineTarget, editor);
        const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
        return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map((checkPos) => () => insertInlineBoundarySpaceOrNbsp(root, pos)(checkPos).each(setSelection(editor)));
      } else {
        return Optional.none();
      }
    };
    const executeKeydownOverride$1 = (editor, evt) => {
      executeWithDelayedAction([{
        keyCode: VK.SPACEBAR,
        action: action(insertSpaceOrNbspAtSelection, editor)
      }], evt).each((applyAction) => {
        evt.preventDefault();
        const event = fireFakeBeforeInputEvent(editor, "insertText", { data: " " });
        if (!event.isDefaultPrevented()) {
          applyAction();
          fireFakeInputEvent(editor, "insertText", { data: " " });
        }
      });
    };
    const setup$d = (editor) => {
      editor.on("keydown", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeydownOverride$1(editor, evt);
        }
      });
    };
    const tableTabNavigation = (editor) => {
      if (hasTableTabNavigation(editor)) {
        return [
          {
            keyCode: VK.TAB,
            action: action(handleTab, editor, true)
          },
          {
            keyCode: VK.TAB,
            shiftKey: true,
            action: action(handleTab, editor, false)
          }
        ];
      } else {
        return [];
      }
    };
    const executeKeydownOverride = (editor, evt) => {
      execute([...tableTabNavigation(editor)], evt).each((_) => {
        evt.preventDefault();
      });
    };
    const setup$c = (editor) => {
      editor.on("keydown", (evt) => {
        if (evt.isDefaultPrevented() === false) {
          executeKeydownOverride(editor, evt);
        }
      });
    };
    const setup$b = (editor) => {
      editor.addShortcut("Meta+P", "", "mcePrint");
      setup$j(editor);
      if (isRtc(editor)) {
        return Cell(null);
      } else {
        const caret = setupSelectedState(editor);
        setup$l(editor);
        setup$k(editor, caret);
        setup$i(editor, caret);
        setup$h(editor);
        setup$d(editor);
        setup$f(editor);
        setup$c(editor);
        setup$g(editor, caret);
        setup$e(editor, caret);
        return caret;
      }
    };
    class NodeChange {
      constructor(editor) {
        this.lastPath = [];
        this.editor = editor;
        let lastRng;
        const self = this;
        if (!("onselectionchange" in editor.getDoc())) {
          editor.on("NodeChange click mouseup keyup focus", (e) => {
            const nativeRng = editor.selection.getRng();
            const fakeRng = {
              startContainer: nativeRng.startContainer,
              startOffset: nativeRng.startOffset,
              endContainer: nativeRng.endContainer,
              endOffset: nativeRng.endOffset
            };
            if (e.type === "nodechange" || !isEq$4(fakeRng, lastRng)) {
              editor.dispatch("SelectionChange");
            }
            lastRng = fakeRng;
          });
        }
        editor.on("contextmenu", () => {
          editor.dispatch("SelectionChange");
        });
        editor.on("SelectionChange", () => {
          const startElm = editor.selection.getStart(true);
          if (!startElm) {
            return;
          }
          if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
            editor.nodeChanged({ selectionChange: true });
          }
        });
        editor.on("mouseup", (e) => {
          if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
            if (editor.selection.getNode().nodeName === "IMG") {
              Delay.setEditorTimeout(editor, () => {
                editor.nodeChanged();
              });
            } else {
              editor.nodeChanged();
            }
          }
        });
      }
      nodeChanged(args) {
        const selection = this.editor.selection;
        let node, parents2, root;
        if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
          root = this.editor.getBody();
          node = selection.getStart(true) || root;
          if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
            node = root;
          }
          parents2 = [];
          this.editor.dom.getParent(node, (node2) => {
            if (node2 === root) {
              return true;
            }
            parents2.push(node2);
          });
          args = args || {};
          args.element = node;
          args.parents = parents2;
          this.editor.dispatch("NodeChange", args);
        }
      }
      isSameElementPath(startElm) {
        let i;
        const editor = this.editor;
        const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
        if (currentPath.length === this.lastPath.length) {
          for (i = currentPath.length; i >= 0; i--) {
            if (currentPath[i] !== this.lastPath[i]) {
              break;
            }
          }
          if (i === -1) {
            this.lastPath = currentPath;
            return true;
          }
        }
        this.lastPath = currentPath;
        return false;
      }
    }
    const internalMimeType = "x-tinymce/html";
    const internalHtmlMime = constant(internalMimeType);
    const internalMark = "<!-- " + internalMimeType + " -->";
    const mark = (html2) => internalMark + html2;
    const unmark = (html2) => html2.replace(internalMark, "");
    const isMarked = (html2) => html2.indexOf(internalMark) !== -1;
    const isPlainText = (text2) => {
      return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text2);
    };
    const openContainer = (rootTag, rootAttrs) => {
      let tag = "<" + rootTag;
      const attrs = mapToArray(rootAttrs, (value2, key) => key + '="' + Entities.encodeAllRaw(value2) + '"');
      if (attrs.length) {
        tag += " " + attrs.join(" ");
      }
      return tag + ">";
    };
    const toBlockElements = (text2, rootTag, rootAttrs) => {
      const blocks2 = text2.split(/\n\n/);
      const tagOpen = openContainer(rootTag, rootAttrs);
      const tagClose = "</" + rootTag + ">";
      const paragraphs = map$3(blocks2, (p) => {
        return p.split(/\n/).join("<br />");
      });
      const stitch = (p) => {
        return tagOpen + p + tagClose;
      };
      return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join("");
    };
    const pasteBinDefaultContent = "%MCEPASTEBIN%";
    const create$6 = (editor, lastRngCell) => {
      const { dom: dom2, selection } = editor;
      const body = editor.getBody();
      lastRngCell.set(selection.getRng());
      const pasteBinElm = dom2.add(editor.getBody(), "div", {
        "id": "mcepastebin",
        "class": "mce-pastebin",
        "contentEditable": true,
        "data-mce-bogus": "all",
        "style": "position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0"
      }, pasteBinDefaultContent);
      if (Env.browser.isFirefox()) {
        dom2.setStyle(pasteBinElm, "left", dom2.getStyle(body, "direction", true) === "rtl" ? 65535 : -65535);
      }
      dom2.bind(pasteBinElm, "beforedeactivate focusin focusout", (e) => {
        e.stopPropagation();
      });
      pasteBinElm.focus();
      selection.select(pasteBinElm, true);
    };
    const remove = (editor, lastRngCell) => {
      const dom2 = editor.dom;
      if (getEl(editor)) {
        let pasteBinClone;
        const lastRng = lastRngCell.get();
        while (pasteBinClone = getEl(editor)) {
          dom2.remove(pasteBinClone);
          dom2.unbind(pasteBinClone);
        }
        if (lastRng) {
          editor.selection.setRng(lastRng);
        }
      }
      lastRngCell.set(null);
    };
    const getEl = (editor) => editor.dom.get("mcepastebin");
    const isPasteBin = (elm) => elm && elm.id === "mcepastebin";
    const getHtml = (editor) => {
      const dom2 = editor.dom;
      const copyAndRemove = (toElm, fromElm) => {
        toElm.appendChild(fromElm);
        dom2.remove(fromElm, true);
      };
      const [pasteBinElm, ...pasteBinClones] = filter$6(editor.getBody().childNodes, isPasteBin);
      each$f(pasteBinClones, (pasteBinClone) => {
        copyAndRemove(pasteBinElm, pasteBinClone);
      });
      const dirtyWrappers = dom2.select("div[id=mcepastebin]", pasteBinElm);
      for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
        const cleanWrapper = dom2.create("div");
        pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
        copyAndRemove(cleanWrapper, dirtyWrappers[i]);
      }
      return pasteBinElm ? pasteBinElm.innerHTML : "";
    };
    const isDefaultPasteBinContent = (content) => content === pasteBinDefaultContent;
    const PasteBin = (editor) => {
      const lastRng = Cell(null);
      return {
        create: () => create$6(editor, lastRng),
        remove: () => remove(editor, lastRng),
        getEl: () => getEl(editor),
        getHtml: () => getHtml(editor),
        getLastRng: lastRng.get
      };
    };
    const filter = (content, items) => {
      Tools.each(items, (v) => {
        if (is$4(v, RegExp)) {
          content = content.replace(v, "");
        } else {
          content = content.replace(v[0], v[1]);
        }
      });
      return content;
    };
    const innerText = (html2) => {
      const schema = Schema();
      const domParser = DomParser({}, schema);
      let text2 = "";
      const voidElements = schema.getVoidElements();
      const ignoreElements = Tools.makeMap("script noscript style textarea video audio iframe object", " ");
      const blockElements = schema.getBlockElements();
      const walk2 = (node) => {
        const name2 = node.name, currentNode = node;
        if (name2 === "br") {
          text2 += "\n";
          return;
        }
        if (name2 === "wbr") {
          return;
        }
        if (voidElements[name2]) {
          text2 += " ";
        }
        if (ignoreElements[name2]) {
          text2 += " ";
          return;
        }
        if (node.type === 3) {
          text2 += node.value;
        }
        if (!(node.name in schema.getVoidElements())) {
          if (node = node.firstChild) {
            do {
              walk2(node);
            } while (node = node.next);
          }
        }
        if (blockElements[name2] && currentNode.next) {
          text2 += "\n";
          if (name2 === "p") {
            text2 += "\n";
          }
        }
      };
      html2 = filter(html2, [/<!\[[^\]]+\]>/g]);
      walk2(domParser.parse(html2));
      return text2;
    };
    const trimHtml = (html2) => {
      const trimSpaces = (all2, s1, s2) => {
        if (!s1 && !s2) {
          return " ";
        }
        return nbsp;
      };
      html2 = filter(html2, [
        /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
        /<!--StartFragment-->|<!--EndFragment-->/g,
        [
          /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
          trimSpaces
        ],
        /<br class="Apple-interchange-newline">/g,
        /<br>$/i
      ]);
      return html2;
    };
    const createIdGenerator = (prefix) => {
      let count2 = 0;
      return () => {
        return prefix + count2++;
      };
    };
    const getImageMimeType = (ext) => {
      const lowerExt = ext.toLowerCase();
      const mimeOverrides = {
        jpg: "jpeg",
        jpe: "jpeg",
        jfi: "jpeg",
        jif: "jpeg",
        jfif: "jpeg",
        pjpeg: "jpeg",
        pjp: "jpeg",
        svg: "svg+xml"
      };
      return Tools.hasOwn(mimeOverrides, lowerExt) ? "image/" + mimeOverrides[lowerExt] : "image/" + lowerExt;
    };
    const preProcess = (editor, html2) => {
      const parser = DomParser({}, editor.schema);
      parser.addNodeFilter("meta", (nodes) => {
        Tools.each(nodes, (node) => {
          node.remove();
        });
      });
      const fragment = parser.parse(html2, {
        forced_root_block: false,
        isRootContent: true
      });
      return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
    };
    const processResult = (content, cancelled) => ({
      content,
      cancelled
    });
    const postProcessFilter = (editor, html2, internal) => {
      const tempBody = editor.dom.create("div", { style: "display:none" }, html2);
      const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
      return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
    };
    const filterContent = (editor, content, internal) => {
      const preProcessArgs = firePastePreProcess(editor, content, internal);
      const filteredContent = preProcess(editor, preProcessArgs.content);
      if (editor.hasEventListeners("PastePostProcess") && !preProcessArgs.isDefaultPrevented()) {
        return postProcessFilter(editor, filteredContent, internal);
      } else {
        return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
      }
    };
    const process = (editor, html2, internal) => {
      return filterContent(editor, html2, internal);
    };
    const pasteHtml$1 = (editor, html2) => {
      editor.insertContent(html2, {
        merge: shouldPasteMergeFormats(editor),
        paste: true
      });
      return true;
    };
    const isAbsoluteUrl = (url) => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
    const isImageUrl = (editor, url) => {
      return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), (type2) => endsWith(url.toLowerCase(), `.${type2.toLowerCase()}`));
    };
    const createImage = (editor, url, pasteHtmlFn) => {
      editor.undoManager.extra(() => {
        pasteHtmlFn(editor, url);
      }, () => {
        editor.insertContent('<img src="' + url + '">');
      });
      return true;
    };
    const createLink = (editor, url, pasteHtmlFn) => {
      editor.undoManager.extra(() => {
        pasteHtmlFn(editor, url);
      }, () => {
        editor.execCommand("mceInsertLink", false, url);
      });
      return true;
    };
    const linkSelection = (editor, html2, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html2) ? createLink(editor, html2, pasteHtmlFn) : false;
    const insertImage = (editor, html2, pasteHtmlFn) => isImageUrl(editor, html2) ? createImage(editor, html2, pasteHtmlFn) : false;
    const smartInsertContent = (editor, html2) => {
      Tools.each([
        linkSelection,
        insertImage,
        pasteHtml$1
      ], (action2) => {
        return action2(editor, html2, pasteHtml$1) !== true;
      });
    };
    const insertContent = (editor, html2, pasteAsText) => {
      if (pasteAsText || !isSmartPasteEnabled(editor)) {
        pasteHtml$1(editor, html2);
      } else {
        smartInsertContent(editor, html2);
      }
    };
    const uniqueId = createIdGenerator("mceclip");
    const doPaste = (editor, content, internal, pasteAsText) => {
      const args = process(editor, content, internal);
      if (args.cancelled === false) {
        insertContent(editor, args.content, pasteAsText);
      }
    };
    const pasteHtml = (editor, html2, internalFlag) => {
      const internal = internalFlag ? internalFlag : isMarked(html2);
      doPaste(editor, unmark(html2), internal, false);
    };
    const pasteText = (editor, text2) => {
      const encodedText = editor.dom.encode(text2).replace(/\r\n/g, "\n");
      const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
      const html2 = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
      doPaste(editor, html2, false, true);
    };
    const getDataTransferItems = (dataTransfer) => {
      const items = {};
      if (dataTransfer && dataTransfer.types) {
        for (let i = 0; i < dataTransfer.types.length; i++) {
          const contentType = dataTransfer.types[i];
          try {
            items[contentType] = dataTransfer.getData(contentType);
          } catch (ex) {
            items[contentType] = "";
          }
        }
      }
      return items;
    };
    const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
    const hasHtmlOrText = (content) => hasContentType(content, "text/html") || hasContentType(content, "text/plain");
    const extractFilename = (editor, str) => {
      const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
      return isNonNullable(m) ? editor.dom.encode(m[1]) : null;
    };
    const createBlobInfo = (editor, blobCache, file, base64) => {
      const id = uniqueId();
      const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
      const name2 = useFileName ? extractFilename(editor, file.name) : id;
      const filename = useFileName ? file.name : void 0;
      const blobInfo = blobCache.create(id, file, base64, name2, filename);
      blobCache.add(blobInfo);
      return blobInfo;
    };
    const pasteImage = (editor, imageItem) => {
      parseDataUri(imageItem.uri).each(({ data: data2, type: type2, base64Encoded }) => {
        const base64 = base64Encoded ? data2 : btoa(data2);
        const file = imageItem.file;
        const blobCache = editor.editorUpload.blobCache;
        const existingBlobInfo = blobCache.getByData(base64, type2);
        const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
        pasteHtml(editor, `<img src="${blobInfo.blobUri()}">`, false);
      });
    };
    const isClipboardEvent = (event) => event.type === "paste";
    const readFilesAsDataUris = (items) => Promise.all(map$3(items, (file) => {
      return blobToDataUri(file).then((uri) => ({
        file,
        uri
      }));
    }));
    const isImage = (editor) => {
      const allowedExtensions = getAllowedImageFileTypes(editor);
      return (file) => startsWith(file.type, "image/") && exists(allowedExtensions, (extension) => {
        return getImageMimeType(extension) === file.type;
      });
    };
    const getImagesFromDataTransfer = (editor, dataTransfer) => {
      const items = dataTransfer.items ? bind$3(from(dataTransfer.items), (item) => {
        return item.kind === "file" ? [item.getAsFile()] : [];
      }) : [];
      const files = dataTransfer.files ? from(dataTransfer.files) : [];
      return filter$6(items.length > 0 ? items : files, isImage(editor));
    };
    const pasteImageData = (editor, e, rng) => {
      const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
      if (shouldPasteDataImages(editor) && dataTransfer) {
        const images = getImagesFromDataTransfer(editor, dataTransfer);
        if (images.length > 0) {
          e.preventDefault();
          readFilesAsDataUris(images).then((fileResults) => {
            if (rng) {
              editor.selection.setRng(rng);
            }
            each$f(fileResults, (result) => {
              pasteImage(editor, result);
            });
          });
          return true;
        }
      }
      return false;
    };
    const isBrokenAndroidClipboardEvent = (e) => {
      var _a, _b;
      return Env.os.isAndroid() && ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b.length) === 0;
    };
    const isKeyboardPasteEvent = (e) => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
    const insertClipboardContent = (editor, clipboardContent, html2, plainTextMode) => {
      let content = trimHtml(html2);
      const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html2);
      const isPlainTextHtml = !isInternal && isPlainText(content);
      const isAbsoluteUrl$1 = isAbsoluteUrl(content);
      if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
        plainTextMode = true;
      }
      if (plainTextMode || isAbsoluteUrl$1) {
        if (hasContentType(clipboardContent, "text/plain") && isPlainTextHtml) {
          content = clipboardContent["text/plain"];
        } else {
          content = innerText(content);
        }
      }
      if (isDefaultPasteBinContent(content)) {
        return;
      }
      if (plainTextMode) {
        pasteText(editor, content);
      } else {
        pasteHtml(editor, content, isInternal);
      }
    };
    const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
      let keyboardPastePlainTextState;
      const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
      editor.on("keydown", (e) => {
        if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
          keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
        }
      });
      editor.on("paste", (e) => {
        if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
          return;
        }
        const plainTextMode = pasteFormat.get() === "text" || keyboardPastePlainTextState;
        keyboardPastePlainTextState = false;
        const clipboardContent = getDataTransferItems(e.clipboardData);
        if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
          return;
        }
        if (hasContentType(clipboardContent, "text/html")) {
          e.preventDefault();
          insertClipboardContent(editor, clipboardContent, clipboardContent["text/html"], plainTextMode);
        } else {
          pasteBin.create();
          Delay.setEditorTimeout(editor, () => {
            const html2 = pasteBin.getHtml();
            pasteBin.remove();
            insertClipboardContent(editor, clipboardContent, html2, plainTextMode);
          }, 0);
        }
      });
    };
    const registerDataImageFilter = (editor) => {
      const isWebKitFakeUrl = (src) => startsWith(src, "webkit-fake-url");
      const isDataUri = (src) => startsWith(src, "data:");
      const isPasteInsert = (args) => {
        var _a;
        return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
      };
      editor.parser.addNodeFilter("img", (nodes, name2, args) => {
        if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
          for (const node of nodes) {
            const src = node.attr("src");
            if (isString(src) && !node.attr("data-mce-object") && src !== Env.transparentSrc) {
              if (isWebKitFakeUrl(src)) {
                node.remove();
              } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
                node.remove();
              }
            }
          }
        }
      });
    };
    const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
      registerEventHandlers(editor, pasteBin, pasteFormat);
      registerDataImageFilter(editor);
    };
    const togglePlainTextPaste = (editor, pasteFormat) => {
      if (pasteFormat.get() === "text") {
        pasteFormat.set("html");
        firePastePlainTextToggle(editor, false);
      } else {
        pasteFormat.set("text");
        firePastePlainTextToggle(editor, true);
      }
      editor.focus();
    };
    const register$1 = (editor, pasteFormat) => {
      editor.addCommand("mceTogglePlainTextPaste", () => {
        togglePlainTextPaste(editor, pasteFormat);
      });
      editor.addCommand("mceInsertClipboardContent", (ui, value2) => {
        if (value2.html) {
          pasteHtml(editor, value2.html, value2.internal);
        }
        if (value2.text) {
          pasteText(editor, value2.text);
        }
      });
    };
    const setHtml5Clipboard = (clipboardData, html2, text2) => {
      try {
        clipboardData.clearData();
        clipboardData.setData("text/html", html2);
        clipboardData.setData("text/plain", text2);
        clipboardData.setData(internalHtmlMime(), html2);
        return true;
      } catch (e) {
        return false;
      }
    };
    const setClipboardData = (evt, data2, fallback2, done) => {
      if (setHtml5Clipboard(evt.clipboardData, data2.html, data2.text)) {
        evt.preventDefault();
        done();
      } else {
        fallback2(data2.html, done);
      }
    };
    const fallback = (editor) => (html2, done) => {
      const { dom: dom2, selection } = editor;
      const outer = dom2.create("div", {
        "contenteditable": "false",
        "data-mce-bogus": "all"
      });
      const inner = dom2.create("div", { contenteditable: "true" }, html2);
      dom2.setStyles(outer, {
        position: "fixed",
        top: "0",
        left: "-3000px",
        width: "1000px",
        overflow: "hidden"
      });
      outer.appendChild(inner);
      dom2.add(editor.getBody(), outer);
      const range2 = selection.getRng();
      inner.focus();
      const offscreenRange = dom2.createRng();
      offscreenRange.selectNodeContents(inner);
      selection.setRng(offscreenRange);
      Delay.setEditorTimeout(editor, () => {
        selection.setRng(range2);
        dom2.remove(outer);
        done();
      }, 0);
    };
    const getData = (editor) => ({
      html: mark(editor.selection.getContent({ contextual: true })),
      text: editor.selection.getContent({ format: "text" })
    });
    const isTableSelection = (editor) => !!editor.dom.getParent(editor.selection.getStart(), "td[data-mce-selected],th[data-mce-selected]", editor.getBody());
    const hasSelectedContent = (editor) => !editor.selection.isCollapsed() || isTableSelection(editor);
    const cut = (editor) => (evt) => {
      if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
        setClipboardData(evt, getData(editor), fallback(editor), () => {
          if (Env.browser.isChromium() || Env.browser.isFirefox()) {
            const rng = editor.selection.getRng();
            Delay.setEditorTimeout(editor, () => {
              editor.selection.setRng(rng);
              editor.execCommand("Delete");
            }, 0);
          } else {
            editor.execCommand("Delete");
          }
        });
      }
    };
    const copy = (editor) => (evt) => {
      if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
        setClipboardData(evt, getData(editor), fallback(editor), noop);
      }
    };
    const register = (editor) => {
      editor.on("cut", cut(editor));
      editor.on("copy", copy(editor));
    };
    const getCaretRangeFromEvent = (editor, e) => {
      var _a, _b;
      return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
    };
    const isPlainTextFileUrl = (content) => {
      const plainTextContent = content["text/plain"];
      return plainTextContent ? plainTextContent.indexOf("file://") === 0 : false;
    };
    const setFocusedRange = (editor, rng) => {
      editor.focus();
      if (rng) {
        editor.selection.setRng(rng);
      }
    };
    const hasImage = (dataTransfer) => exists(dataTransfer.files, (file) => /^image\//.test(file.type));
    const setup$a = (editor, draggingInternallyState) => {
      if (shouldPasteBlockDrop(editor)) {
        editor.on("dragend dragover draggesture dragdrop drop drag", (e) => {
          e.preventDefault();
          e.stopPropagation();
        });
      }
      if (!shouldPasteDataImages(editor)) {
        editor.on("drop", (e) => {
          const dataTransfer = e.dataTransfer;
          if (dataTransfer && hasImage(dataTransfer)) {
            e.preventDefault();
          }
        });
      }
      editor.on("drop", (e) => {
        if (e.isDefaultPrevented() || draggingInternallyState.get()) {
          return;
        }
        const rng = getCaretRangeFromEvent(editor, e);
        if (isNullable(rng)) {
          return;
        }
        const dropContent = getDataTransferItems(e.dataTransfer);
        const internal = hasContentType(dropContent, internalHtmlMime());
        if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
          return;
        }
        const internalContent = dropContent[internalHtmlMime()];
        const content = internalContent || dropContent["text/html"] || dropContent["text/plain"];
        if (content) {
          e.preventDefault();
          Delay.setEditorTimeout(editor, () => {
            editor.undoManager.transact(() => {
              if (internalContent) {
                editor.execCommand("Delete");
              }
              setFocusedRange(editor, rng);
              const trimmedContent = trimHtml(content);
              if (dropContent["text/html"]) {
                pasteHtml(editor, trimmedContent, internal);
              } else {
                pasteText(editor, trimmedContent);
              }
            });
          });
        }
      });
      editor.on("dragstart", (_e) => {
        draggingInternallyState.set(true);
      });
      editor.on("dragover dragend", (e) => {
        if (shouldPasteDataImages(editor) && draggingInternallyState.get() === false) {
          e.preventDefault();
          setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
        }
        if (e.type === "dragend") {
          draggingInternallyState.set(false);
        }
      });
    };
    const setup$9 = (editor) => {
      const processEvent = (f) => (e) => {
        f(editor, e);
      };
      const preProcess2 = getPastePreProcess(editor);
      if (isFunction(preProcess2)) {
        editor.on("PastePreProcess", processEvent(preProcess2));
      }
      const postProcess2 = getPastePostProcess(editor);
      if (isFunction(postProcess2)) {
        editor.on("PastePostProcess", processEvent(postProcess2));
      }
    };
    const addPreProcessFilter = (editor, filterFunc) => {
      editor.on("PastePreProcess", (e) => {
        e.content = filterFunc(editor, e.content, e.internal);
      });
    };
    const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
    const rgbToHex = (value2) => Tools.trim(value2).replace(rgbRegExp, rgbaToHexString).toLowerCase();
    const removeWebKitStyles = (editor, content, internal) => {
      const webKitStylesOption = getPasteWebkitStyles(editor);
      if (internal || webKitStylesOption === "all" || !shouldPasteRemoveWebKitStyles(editor)) {
        return content;
      }
      const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
      if (webKitStyles && webKitStylesOption !== "none") {
        const dom2 = editor.dom, node = editor.selection.getNode();
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all2, before2, value2, after2) => {
          const inputStyles = dom2.parseStyle(dom2.decode(value2));
          const outputStyles = {};
          for (let i = 0; i < webKitStyles.length; i++) {
            const inputValue = inputStyles[webKitStyles[i]];
            let compareInput = inputValue;
            let currentValue = dom2.getStyle(node, webKitStyles[i], true);
            if (/color/.test(webKitStyles[i])) {
              compareInput = rgbToHex(compareInput);
              currentValue = rgbToHex(currentValue);
            }
            if (currentValue !== compareInput) {
              outputStyles[webKitStyles[i]] = inputValue;
            }
          }
          const outputStyle = dom2.serializeStyle(outputStyles, "span");
          if (outputStyle) {
            return before2 + ' style="' + outputStyle + '"' + after2;
          }
          return before2 + after2;
        });
      } else {
        content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, "$1$3");
      }
      content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all2, before2, value2, after2) => {
        return before2 + ' style="' + value2 + '"' + after2;
      });
      return content;
    };
    const setup$8 = (editor) => {
      if (Env.browser.isChromium() || Env.browser.isSafari()) {
        addPreProcessFilter(editor, removeWebKitStyles);
      }
    };
    const setup$7 = (editor) => {
      const draggingInternallyState = Cell(false);
      const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? "text" : "html");
      const pasteBin = PasteBin(editor);
      setup$8(editor);
      register$1(editor, pasteFormat);
      setup$9(editor);
      editor.on("PreInit", () => {
        register(editor);
        setup$a(editor, draggingInternallyState);
        registerEventsAndFilters(editor, pasteBin, pasteFormat);
      });
    };
    const preventSummaryToggle = (editor) => {
      editor.on("click", (e) => {
        if (editor.dom.getParent(e.target, "details")) {
          e.preventDefault();
        }
      });
    };
    const filterDetails = (editor) => {
      editor.parser.addNodeFilter("details", (elms) => {
        each$f(elms, (details) => {
          details.attr("data-mce-open", details.attr("open"));
          details.attr("open", "open");
        });
      });
      editor.serializer.addNodeFilter("details", (elms) => {
        each$f(elms, (details) => {
          const open = details.attr("data-mce-open");
          details.attr("open", isString(open) ? open : null);
          details.attr("data-mce-open", null);
        });
      });
    };
    const setup$6 = (editor) => {
      preventSummaryToggle(editor);
      filterDetails(editor);
    };
    const isBr = isBr$6;
    const isText = isText$9;
    const isContentEditableFalse$2 = (elm) => isContentEditableFalse$b(elm.dom);
    const isContentEditableTrue$1 = (elm) => isContentEditableTrue$5(elm.dom);
    const isRoot = (rootNode) => (elm) => eq(SugarElement.fromDom(rootNode), elm);
    const getClosestScope = (node, rootNode) => closest$4(SugarElement.fromDom(node), (elm) => isContentEditableTrue$1(elm) || isBlock$2(elm), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
    const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
    const findEdgeCaretCandidate = (startNode, scope, forward) => {
      const walker = new DomTreeWalker(startNode, scope);
      const next2 = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
      let result = startNode;
      for (let current = forward ? startNode : next2(); current && !isBr(current); current = next2()) {
        if (isCaretCandidate$3(current)) {
          result = current;
        }
      }
      return result;
    };
    const findClosestBlockRange = (startRng, rootNode) => {
      const startPos = CaretPosition.fromRangeStart(startRng);
      const clickNode = startPos.getNode();
      const scope = getClosestScope(clickNode, rootNode);
      const startNode = findEdgeCaretCandidate(clickNode, scope, false);
      const endNode = findEdgeCaretCandidate(clickNode, scope, true);
      const rng = document.createRange();
      getClosestCef(startNode, scope).fold(() => {
        if (isText(startNode)) {
          rng.setStart(startNode, 0);
        } else {
          rng.setStartBefore(startNode);
        }
      }, (cef) => rng.setStartBefore(cef.dom));
      getClosestCef(endNode, scope).fold(() => {
        if (isText(endNode)) {
          rng.setEnd(endNode, endNode.data.length);
        } else {
          rng.setEndAfter(endNode);
        }
      }, (cef) => rng.setEndAfter(cef.dom));
      return rng;
    };
    const onTripleClickSelect = (editor) => {
      const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody());
      editor.selection.setRng(normalize(rng));
    };
    const setup$5 = (editor) => {
      editor.on("mousedown", (e) => {
        if (e.detail >= 3) {
          e.preventDefault();
          onTripleClickSelect(editor);
        }
      });
    };
    var FakeCaretPosition;
    (function(FakeCaretPosition2) {
      FakeCaretPosition2["Before"] = "before";
      FakeCaretPosition2["After"] = "after";
    })(FakeCaretPosition || (FakeCaretPosition = {}));
    const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
    const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
    const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
    const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
    const isOverlapping = (r1, r2) => {
      const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
      return collidesY(r1, r2) && overlap > 0.5;
    };
    const splitRectsPerAxis = (rects, y) => {
      const intersectingRects = filter$6(rects, (rect) => isInsideY(y, rect));
      return boundingClientRectFromRects(intersectingRects).fold(() => [
        [],
        rects
      ], (boundingRect) => {
        const {
          pass: horizontal,
          fail: vertical
        } = partition$2(rects, (rect) => isOverlapping(rect, boundingRect));
        return [
          horizontal,
          vertical
        ];
      });
    };
    const clientInfo = (rect, clientX) => {
      return {
        node: rect.node,
        position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
      };
    };
    const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
    const closestChildCaretCandidateNodeRect = (children2, clientX, clientY) => {
      const caretCandidateRect = (rect) => {
        if (isCaretCandidate$3(rect.node)) {
          return Optional.some(rect);
        } else if (isElement$6(rect.node)) {
          return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY);
        } else {
          return Optional.none();
        }
      };
      const getClosestTextNode = (rects, distance) => {
        if (rects.length >= 2) {
          const r1 = caretCandidateRect(rects[0]).getOr(rects[0]);
          const r2 = caretCandidateRect(rects[1]).getOr(rects[1]);
          const deltaDistance = Math.abs(distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
          if (deltaDistance < 2) {
            if (isText$9(r1.node)) {
              return Optional.some(r1);
            } else if (isText$9(r2.node)) {
              return Optional.some(r2);
            }
          }
        }
        return Optional.none();
      };
      const findClosestCaretCandidateNodeRect = (rects, distance) => {
        const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
        return getClosestTextNode(sortedRects, distance).orThunk(() => findMap(sortedRects, caretCandidateRect));
      };
      const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children2), clientY);
      const {
        pass: above,
        fail: below
      } = partition$2(verticalRects, (rect) => rect.top < clientY);
      return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
    };
    const traverseUp = (rootElm, scope, clientX, clientY) => {
      const helper = (scope2, prevScope) => {
        return prevScope.fold(() => closestChildCaretCandidateNodeRect(from(scope2.dom.childNodes), clientX, clientY), (prevScope2) => {
          const uncheckedChildren = filter$6(from(scope2.dom.childNodes), (node) => node !== prevScope2.dom);
          return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY);
        }).orThunk(() => {
          const parent2 = eq(scope2, rootElm) ? Optional.none() : parentElement(scope2);
          return parent2.bind((newScope) => helper(newScope, Optional.some(scope2)));
        });
      };
      return helper(scope, Optional.none());
    };
    const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
      const rootElm = SugarElement.fromDom(root);
      const ownerDoc = documentOrOwner(rootElm);
      const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter((elm) => contains(rootElm, elm));
      const element = elementAtPoint.getOr(rootElm);
      return traverseUp(rootElm, element, clientX, clientY);
    };
    const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter((rect) => isFakeCaretTarget(rect.node)).map((rect) => clientInfo(rect, clientX));
    const getAbsolutePosition = (elm) => {
      const clientRect = elm.getBoundingClientRect();
      const doc = elm.ownerDocument;
      const docElem = doc.documentElement;
      const win = doc.defaultView;
      return {
        top: clientRect.top + win.pageYOffset - docElem.clientTop,
        left: clientRect.left + win.pageXOffset - docElem.clientLeft
      };
    };
    const getBodyPosition = (editor) => editor.inline ? getAbsolutePosition(editor.getBody()) : {
      left: 0,
      top: 0
    };
    const getScrollPosition = (editor) => {
      const body = editor.getBody();
      return editor.inline ? {
        left: body.scrollLeft,
        top: body.scrollTop
      } : {
        left: 0,
        top: 0
      };
    };
    const getBodyScroll = (editor) => {
      const body = editor.getBody(), docElm = editor.getDoc().documentElement;
      const inlineScroll = {
        left: body.scrollLeft,
        top: body.scrollTop
      };
      const iframeScroll = {
        left: body.scrollLeft || docElm.scrollLeft,
        top: body.scrollTop || docElm.scrollTop
      };
      return editor.inline ? inlineScroll : iframeScroll;
    };
    const getMousePosition = (editor, event) => {
      if (event.target.ownerDocument !== editor.getDoc()) {
        const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
        const scrollPosition = getBodyScroll(editor);
        return {
          left: event.pageX - iframePosition.left + scrollPosition.left,
          top: event.pageY - iframePosition.top + scrollPosition.top
        };
      }
      return {
        left: event.pageX,
        top: event.pageY
      };
    };
    const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
      pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
      pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
    });
    const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
    const isContentEditableFalse$1 = isContentEditableFalse$b, isContentEditableTrue = isContentEditableTrue$5;
    const isDraggable = (rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm;
    const isValidDropTarget = (editor, targetElement, dragElement) => {
      if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
        return false;
      }
      return !isContentEditableFalse$1(targetElement);
    };
    const cloneElement = (elm) => {
      const cloneElm = elm.cloneNode(true);
      cloneElm.removeAttribute("data-mce-selected");
      return cloneElm;
    };
    const createGhost = (editor, elm, width, height) => {
      const dom2 = editor.dom;
      const clonedElm = elm.cloneNode(true);
      dom2.setStyles(clonedElm, {
        width,
        height
      });
      dom2.setAttrib(clonedElm, "data-mce-selected", null);
      const ghostElm = dom2.create("div", {
        "class": "mce-drag-container",
        "data-mce-bogus": "all",
        "unselectable": "on",
        "contenteditable": "false"
      });
      dom2.setStyles(ghostElm, {
        position: "absolute",
        opacity: 0.5,
        overflow: "hidden",
        border: 0,
        padding: 0,
        margin: 0,
        width,
        height
      });
      dom2.setStyles(clonedElm, {
        margin: 0,
        boxSizing: "border-box"
      });
      ghostElm.appendChild(clonedElm);
      return ghostElm;
    };
    const appendGhostToBody = (ghostElm, bodyElm) => {
      if (ghostElm.parentNode !== bodyElm) {
        bodyElm.appendChild(ghostElm);
      }
    };
    const moveGhost = (ghostElm, position, width, height, maxX, maxY) => {
      let overflowX = 0, overflowY = 0;
      ghostElm.style.left = position.pageX + "px";
      ghostElm.style.top = position.pageY + "px";
      if (position.pageX + width > maxX) {
        overflowX = position.pageX + width - maxX;
      }
      if (position.pageY + height > maxY) {
        overflowY = position.pageY + height - maxY;
      }
      ghostElm.style.width = width - overflowX + "px";
      ghostElm.style.height = height - overflowY + "px";
    };
    const removeElement = (elm) => {
      if (elm && elm.parentNode) {
        elm.parentNode.removeChild(elm);
      }
    };
    const isLeftMouseButtonPressed = (e) => e.button === 0;
    const applyRelPos = (state, position) => ({
      pageX: position.pageX - state.relX,
      pageY: position.pageY + 5
    });
    const start = (state, editor) => (e) => {
      if (isLeftMouseButtonPressed(e)) {
        const ceElm = find$2(editor.dom.getParents(e.target), or(isContentEditableFalse$1, isContentEditableTrue)).getOr(null);
        if (isDraggable(editor.getBody(), ceElm)) {
          const elmPos = editor.dom.getPos(ceElm);
          const bodyElm = editor.getBody();
          const docElm = editor.getDoc().documentElement;
          state.set({
            element: ceElm,
            dragging: false,
            screenX: e.screenX,
            screenY: e.screenY,
            maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
            maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
            relX: e.pageX - elmPos.x,
            relY: e.pageY - elmPos.y,
            width: ceElm.offsetWidth,
            height: ceElm.offsetHeight,
            ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight)
          });
        }
      }
    };
    const move = (state, editor) => {
      const throttledPlaceCaretAt = first$1((clientX, clientY) => {
        editor._selectionOverrides.hideFakeCaret();
        editor.selection.placeCaretAt(clientX, clientY);
      }, 0);
      editor.on("remove", throttledPlaceCaretAt.cancel);
      return (e) => state.on((state2) => {
        const movement = Math.max(Math.abs(e.screenX - state2.screenX), Math.abs(e.screenY - state2.screenY));
        if (!state2.dragging && movement > 10) {
          const args = editor.dispatch("dragstart", { target: state2.element });
          if (args.isDefaultPrevented()) {
            return;
          }
          state2.dragging = true;
          editor.focus();
        }
        if (state2.dragging) {
          const targetPos = applyRelPos(state2, calc(editor, e));
          appendGhostToBody(state2.ghost, editor.getBody());
          moveGhost(state2.ghost, targetPos, state2.width, state2.height, state2.maxX, state2.maxY);
          throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
        }
      });
    };
    const getRawTarget = (selection) => {
      const rng = selection.getSel().getRangeAt(0);
      const startContainer = rng.startContainer;
      return startContainer.nodeType === 3 ? startContainer.parentNode : startContainer;
    };
    const drop = (state, editor) => (e) => {
      state.on((state2) => {
        if (state2.dragging) {
          if (isValidDropTarget(editor, getRawTarget(editor.selection), state2.element)) {
            const targetClone = cloneElement(state2.element);
            const args = editor.dispatch("drop", {
              clientX: e.clientX,
              clientY: e.clientY
            });
            if (!args.isDefaultPrevented()) {
              editor.undoManager.transact(() => {
                removeElement(state2.element);
                editor.insertContent(editor.dom.getOuterHTML(targetClone));
                editor._selectionOverrides.hideFakeCaret();
              });
            }
          }
          editor.dispatch("dragend");
        }
      });
      removeDragState(state);
    };
    const stop = (state, editor) => () => {
      state.on((state2) => {
        if (state2.dragging) {
          editor.dispatch("dragend");
        }
      });
      removeDragState(state);
    };
    const removeDragState = (state) => {
      state.on((state2) => {
        removeElement(state2.ghost);
      });
      state.clear();
    };
    const bindFakeDragEvents = (editor) => {
      const state = value$2();
      const pageDom = DOMUtils.DOM;
      const rootDocument = document;
      const dragStartHandler = start(state, editor);
      const dragHandler = move(state, editor);
      const dropHandler = drop(state, editor);
      const dragEndHandler = stop(state, editor);
      editor.on("mousedown", dragStartHandler);
      editor.on("mousemove", dragHandler);
      editor.on("mouseup", dropHandler);
      pageDom.bind(rootDocument, "mousemove", dragHandler);
      pageDom.bind(rootDocument, "mouseup", dragEndHandler);
      editor.on("remove", () => {
        pageDom.unbind(rootDocument, "mousemove", dragHandler);
        pageDom.unbind(rootDocument, "mouseup", dragEndHandler);
      });
      editor.on("keydown", (e) => {
        if (e.keyCode === VK.ESC) {
          dragEndHandler();
        }
      });
    };
    const blockUnsupportedFileDrop = (editor) => {
      const preventFileDrop = (e) => {
        if (!e.isDefaultPrevented()) {
          const dataTransfer = e.dataTransfer;
          if (dataTransfer && (contains$2(dataTransfer.types, "Files") || dataTransfer.files.length > 0)) {
            e.preventDefault();
            if (e.type === "drop") {
              displayError(editor, "Dropped file type is not supported");
            }
          }
        }
      };
      const preventFileDropIfUIElement = (e) => {
        if (isUIElement(editor, e.target)) {
          preventFileDrop(e);
        }
      };
      const setup2 = () => {
        const pageDom = DOMUtils.DOM;
        const dom2 = editor.dom;
        const doc = document;
        const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
        const eventNames = [
          "drop",
          "dragover"
        ];
        each$f(eventNames, (name2) => {
          pageDom.bind(doc, name2, preventFileDropIfUIElement);
          dom2.bind(editorRoot, name2, preventFileDrop);
        });
        editor.on("remove", () => {
          each$f(eventNames, (name2) => {
            pageDom.unbind(doc, name2, preventFileDropIfUIElement);
            dom2.unbind(editorRoot, name2, preventFileDrop);
          });
        });
      };
      editor.on("init", () => {
        Delay.setEditorTimeout(editor, setup2, 0);
      });
    };
    const init$2 = (editor) => {
      bindFakeDragEvents(editor);
      if (shouldBlockUnsupportedDrop(editor)) {
        blockUnsupportedFileDrop(editor);
      }
    };
    const setup$4 = (editor) => {
      const renderFocusCaret = first$1(() => {
        if (!editor.removed && editor.getBody().contains(document.activeElement)) {
          const rng = editor.selection.getRng();
          if (rng.collapsed) {
            const caretRange = renderRangeCaret(editor, rng, false);
            editor.selection.setRng(caretRange);
          }
        }
      }, 0);
      editor.on("focus", () => {
        renderFocusCaret.throttle();
      });
      editor.on("blur", () => {
        renderFocusCaret.cancel();
      });
    };
    const setup$3 = (editor) => {
      editor.on("init", () => {
        editor.on("focusin", (e) => {
          const target = e.target;
          if (isMedia$2(target)) {
            const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
            const node = isContentEditableFalse$b(ceRoot) ? ceRoot : target;
            if (editor.selection.getNode() !== node) {
              selectNode(editor, node).each((rng) => editor.selection.setRng(rng));
            }
          }
        });
      });
    };
    const isContentEditableFalse = isContentEditableFalse$b;
    const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
    const SelectionOverrides = (editor) => {
      const selection = editor.selection, dom2 = editor.dom;
      const isBlock2 = dom2.isBlock;
      const rootNode = editor.getBody();
      const fakeCaret = FakeCaret(editor, rootNode, isBlock2, () => hasFocus(editor));
      const realSelectionId = "sel-" + dom2.uniqueId();
      const elementSelectionAttr2 = "data-mce-selected";
      let selectedElement;
      const isFakeSelectionElement = (node) => dom2.hasClass(node, "mce-offscreen-selection");
      const isFakeSelectionTargetElement = (node) => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom2.isChildOf(node, rootNode);
      const setRange = (range2) => {
        if (range2) {
          selection.setRng(range2);
        }
      };
      const showCaret2 = (direction, node, before2, scrollIntoView = true) => {
        const e = editor.dispatch("ShowCaret", {
          target: node,
          direction,
          before: before2
        });
        if (e.isDefaultPrevented()) {
          return null;
        }
        if (scrollIntoView) {
          selection.scrollIntoView(node, direction === -1);
        }
        return fakeCaret.show(before2, node);
      };
      const showBlockCaretContainer2 = (blockCaretContainer) => {
        if (blockCaretContainer.hasAttribute("data-mce-caret")) {
          showCaretContainerBlock(blockCaretContainer);
          selection.scrollIntoView(blockCaretContainer);
        }
      };
      const registerEvents2 = () => {
        editor.on("click", (e) => {
          const contentEditableRoot = getContentEditableRoot(editor, e.target);
          if (contentEditableRoot) {
            if (isContentEditableFalse(contentEditableRoot)) {
              e.preventDefault();
              editor.focus();
            }
          }
        });
        editor.on("blur NewBlock", removeElementSelection);
        editor.on("ResizeWindow FullscreenStateChanged", fakeCaret.reposition);
        editor.on("tap", (e) => {
          const targetElm = e.target;
          const contentEditableRoot = getContentEditableRoot(editor, targetElm);
          if (isContentEditableFalse(contentEditableRoot)) {
            e.preventDefault();
            selectNode(editor, contentEditableRoot).each(setElementSelection);
          } else if (isFakeSelectionTargetElement(targetElm)) {
            selectNode(editor, targetElm).each(setElementSelection);
          }
        }, true);
        editor.on("mousedown", (e) => {
          const targetElm = e.target;
          if (targetElm !== rootNode && targetElm.nodeName !== "HTML" && !dom2.isChildOf(targetElm, rootNode)) {
            return;
          }
          if (isXYInContentArea(editor, e.clientX, e.clientY) === false) {
            return;
          }
          removeElementSelection();
          hideFakeCaret();
          const closestContentEditable = getContentEditableRoot(editor, targetElm);
          if (isContentEditableFalse(closestContentEditable)) {
            e.preventDefault();
            selectNode(editor, closestContentEditable).each(setElementSelection);
          } else {
            closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each((caretInfo) => {
              e.preventDefault();
              const range2 = showCaret2(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
              setRange(range2);
              if (isElement$6(closestContentEditable)) {
                closestContentEditable.focus();
              } else {
                editor.getBody().focus();
              }
            });
          }
        });
        editor.on("keypress", (e) => {
          if (VK.modifierPressed(e)) {
            return;
          }
          if (isContentEditableFalse(selection.getNode())) {
            e.preventDefault();
          }
        });
        editor.on("GetSelectionRange", (e) => {
          let rng = e.range;
          if (selectedElement) {
            if (!selectedElement.parentNode) {
              selectedElement = null;
              return;
            }
            rng = rng.cloneRange();
            rng.selectNode(selectedElement);
            e.range = rng;
          }
        });
        editor.on("SetSelectionRange", (e) => {
          e.range = normalizeVoidElementSelection(e.range);
          const rng = setElementSelection(e.range, e.forward);
          if (rng) {
            e.range = rng;
          }
        });
        const isPasteBin2 = (node) => node.id === "mcepastebin";
        editor.on("AfterSetSelectionRange", (e) => {
          const rng = e.range;
          const parentNode = rng.startContainer.parentNode;
          if (!isRangeInCaretContainer(rng) && !isPasteBin2(parentNode)) {
            hideFakeCaret();
          }
          if (!isFakeSelectionElement(parentNode)) {
            removeElementSelection();
          }
        });
        init$2(editor);
        setup$4(editor);
        setup$3(editor);
      };
      const isWithinCaretContainer = (node) => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
      const isRangeInCaretContainer = (rng) => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
      const normalizeVoidElementSelection = (rng) => {
        const voidElements = editor.schema.getVoidElements();
        const newRng = dom2.createRng();
        const startContainer = rng.startContainer;
        const startOffset = rng.startOffset;
        const endContainer = rng.endContainer;
        const endOffset = rng.endOffset;
        if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
          if (startOffset === 0) {
            newRng.setStartBefore(startContainer);
          } else {
            newRng.setStartAfter(startContainer);
          }
        } else {
          newRng.setStart(startContainer, startOffset);
        }
        if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
          if (endOffset === 0) {
            newRng.setEndBefore(endContainer);
          } else {
            newRng.setEndAfter(endContainer);
          }
        } else {
          newRng.setEnd(endContainer, endOffset);
        }
        return newRng;
      };
      const setupOffscreenSelection = (node, targetClone) => {
        const body = SugarElement.fromDom(editor.getBody());
        const doc = editor.getDoc();
        const realSelectionContainer = descendant(body, "#" + realSelectionId).getOrThunk(() => {
          const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
          set$2(newContainer, "id", realSelectionId);
          append$1(body, newContainer);
          return newContainer;
        });
        const newRange = dom2.createRng();
        empty(realSelectionContainer);
        append(realSelectionContainer, [
          SugarElement.fromText(nbsp, doc),
          SugarElement.fromDom(targetClone),
          SugarElement.fromText(nbsp, doc)
        ]);
        newRange.setStart(realSelectionContainer.dom.firstChild, 1);
        newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
        setAll(realSelectionContainer, { top: dom2.getPos(node, editor.getBody()).y + "px" });
        focus$1(realSelectionContainer);
        const sel = selection.getSel();
        sel.removeAllRanges();
        sel.addRange(newRange);
        return newRange;
      };
      const selectElement = (elm) => {
        const targetClone = elm.cloneNode(true);
        const e = editor.dispatch("ObjectSelected", {
          target: elm,
          targetClone
        });
        if (e.isDefaultPrevented()) {
          return null;
        }
        const range2 = setupOffscreenSelection(elm, e.targetClone);
        const nodeElm = SugarElement.fromDom(elm);
        each$f(descendants(SugarElement.fromDom(editor.getBody()), `*[${elementSelectionAttr2}]`), (elm2) => {
          if (!eq(nodeElm, elm2)) {
            remove$b(elm2, elementSelectionAttr2);
          }
        });
        if (!dom2.getAttrib(elm, elementSelectionAttr2)) {
          elm.setAttribute(elementSelectionAttr2, "1");
        }
        selectedElement = elm;
        hideFakeCaret();
        return range2;
      };
      const setElementSelection = (range2, forward) => {
        if (!range2) {
          return null;
        }
        if (range2.collapsed) {
          if (!isRangeInCaretContainer(range2)) {
            const dir = forward ? 1 : -1;
            const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range2);
            const beforeNode = caretPosition.getNode(!forward);
            if (isFakeCaretTarget(beforeNode)) {
              return showCaret2(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
            }
            const afterNode = caretPosition.getNode(forward);
            if (isFakeCaretTarget(afterNode)) {
              return showCaret2(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
            }
          }
          return null;
        }
        let startContainer = range2.startContainer;
        let startOffset = range2.startOffset;
        const endOffset = range2.endOffset;
        if (startContainer.nodeType === 3 && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
          startContainer = startContainer.parentNode;
          startOffset = dom2.nodeIndex(startContainer);
          startContainer = startContainer.parentNode;
        }
        if (startContainer.nodeType !== 1) {
          return null;
        }
        if (endOffset === startOffset + 1 && startContainer === range2.endContainer) {
          const node = startContainer.childNodes[startOffset];
          if (isFakeSelectionTargetElement(node)) {
            return selectElement(node);
          }
        }
        return null;
      };
      const removeElementSelection = () => {
        if (selectedElement) {
          selectedElement.removeAttribute(elementSelectionAttr2);
        }
        descendant(SugarElement.fromDom(editor.getBody()), "#" + realSelectionId).each(remove$6);
        selectedElement = null;
      };
      const destroy2 = () => {
        fakeCaret.destroy();
        selectedElement = null;
      };
      const hideFakeCaret = () => {
        fakeCaret.hide();
      };
      if (!isRtc(editor)) {
        registerEvents2();
      }
      return {
        showCaret: showCaret2,
        showBlockCaretContainer: showBlockCaretContainer2,
        hideFakeCaret,
        destroy: destroy2
      };
    };
    const generatePath = (root, node, offset) => {
      if (isText$9(node) && (offset < 0 || offset > node.data.length)) {
        return [];
      }
      const p = [offset];
      let current = node;
      while (current !== root && current.parentNode) {
        const parent2 = current.parentNode;
        for (let i = 0; i < parent2.childNodes.length; i++) {
          if (parent2.childNodes[i] === current) {
            p.push(i);
            break;
          }
        }
        current = parent2;
      }
      return current === root ? p.reverse() : [];
    };
    const generatePathRange = (root, startNode, startOffset, endNode, endOffset) => {
      const start2 = generatePath(root, startNode, startOffset);
      const end2 = generatePath(root, endNode, endOffset);
      return {
        start: start2,
        end: end2
      };
    };
    const resolvePath = (root, path) => {
      const nodePath = path.slice();
      const offset = nodePath.pop();
      const resolvedNode = foldl(nodePath, (optNode, index2) => optNode.bind((node) => Optional.from(node.childNodes[index2])), Optional.some(root));
      return resolvedNode.bind((node) => {
        if (isText$9(node) && (offset < 0 || offset > node.data.length)) {
          return Optional.none();
        } else {
          return Optional.some({
            node,
            offset
          });
        }
      });
    };
    const resolvePathRange = (root, range2) => resolvePath(root, range2.start).bind(({
      node: startNode,
      offset: startOffset
    }) => resolvePath(root, range2.end).map(({
      node: endNode,
      offset: endOffset
    }) => {
      const rng = document.createRange();
      rng.setStart(startNode, startOffset);
      rng.setEnd(endNode, endOffset);
      return rng;
    }));
    const generatePathRangeFromRange = (root, range2) => generatePathRange(root, range2.startContainer, range2.startOffset, range2.endContainer, range2.endOffset);
    const cleanEmptyNodes = (dom2, node, isRoot2) => {
      if (node && dom2.isEmpty(node) && !isRoot2(node)) {
        const parent2 = node.parentNode;
        dom2.remove(node);
        cleanEmptyNodes(dom2, parent2, isRoot2);
      }
    };
    const deleteRng = (dom2, rng, isRoot2, clean = true) => {
      const startParent = rng.startContainer.parentNode;
      const endParent = rng.endContainer.parentNode;
      rng.deleteContents();
      if (clean && !isRoot2(rng.startContainer)) {
        if (isText$9(rng.startContainer) && rng.startContainer.data.length === 0) {
          dom2.remove(rng.startContainer);
        }
        if (isText$9(rng.endContainer) && rng.endContainer.data.length === 0) {
          dom2.remove(rng.endContainer);
        }
        cleanEmptyNodes(dom2, startParent, isRoot2);
        if (startParent !== endParent) {
          cleanEmptyNodes(dom2, endParent, isRoot2);
        }
      }
    };
    const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
    const stripPattern = (dom2, block, pattern) => {
      const firstTextNode = textAfter(block, 0, block);
      firstTextNode.each((spot) => {
        const node = spot.container;
        scanRight(node, pattern.start.length, block).each((end2) => {
          const rng = dom2.createRng();
          rng.setStart(node, 0);
          rng.setEnd(end2.container, end2.offset);
          deleteRng(dom2, rng, (e) => e === block);
        });
      });
    };
    const applyPattern$1 = (editor, match2) => {
      const dom2 = editor.dom;
      const pattern = match2.pattern;
      const rng = resolvePathRange(dom2.getRoot(), match2.range).getOrDie("Unable to resolve path range");
      const isBlockFormatName = (name2, formatter) => {
        const formatSet = formatter.get(name2);
        return isArray$1(formatSet) && head(formatSet).exists((format) => has$2(format, "block"));
      };
      getParentBlock(editor, rng).each((block) => {
        if (pattern.type === "block-format") {
          if (isBlockFormatName(pattern.format, editor.formatter)) {
            editor.undoManager.transact(() => {
              stripPattern(editor.dom, block, pattern);
              editor.formatter.apply(pattern.format);
            });
          }
        } else if (pattern.type === "block-command") {
          editor.undoManager.transact(() => {
            stripPattern(editor.dom, block, pattern);
            editor.execCommand(pattern.cmd, false, pattern.value);
          });
        }
      });
      return true;
    };
    const findPattern$1 = (patterns, text2) => {
      const nuText = text2.replace(nbsp, " ");
      return find$2(patterns, (pattern) => text2.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
    };
    const findPatterns$1 = (editor, patterns) => {
      const dom2 = editor.dom;
      const rng = editor.selection.getRng();
      return getParentBlock(editor, rng).filter((block) => {
        const forcedRootBlock = getForcedRootBlock(editor);
        const matchesForcedRootBlock = dom2.is(block, forcedRootBlock);
        return block !== null && matchesForcedRootBlock;
      }).bind((block) => {
        const blockText = block.textContent;
        const matchedPattern = findPattern$1(patterns, blockText);
        return matchedPattern.map((pattern) => {
          if (Tools.trim(blockText).length === pattern.start.length) {
            return [];
          }
          return [{
            pattern,
            range: generatePathRange(dom2.getRoot(), block, 0, block, 0)
          }];
        });
      }).getOr([]);
    };
    const applyMatches$1 = (editor, matches) => {
      if (matches.length === 0) {
        return;
      }
      const bookmark = editor.selection.getBookmark();
      each$f(matches, (match2) => applyPattern$1(editor, match2));
      editor.selection.moveToBookmark(bookmark);
    };
    const newMarker = (dom2, id) => dom2.create("span", {
      "data-mce-type": "bookmark",
      id
    });
    const rangeFromMarker = (dom2, marker) => {
      const rng = dom2.createRng();
      rng.setStartAfter(marker.start);
      rng.setEndBefore(marker.end);
      return rng;
    };
    const createMarker = (dom2, markerPrefix, pathRange) => {
      const rng = resolvePathRange(dom2.getRoot(), pathRange).getOrDie("Unable to resolve path range");
      const startNode = rng.startContainer;
      const endNode = rng.endContainer;
      const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
      const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
      return {
        prefix: markerPrefix,
        end: textEnd.parentNode.insertBefore(newMarker(dom2, markerPrefix + "-end"), textEnd),
        start: textStart.parentNode.insertBefore(newMarker(dom2, markerPrefix + "-start"), textStart)
      };
    };
    const removeMarker = (dom2, marker, isRoot2) => {
      cleanEmptyNodes(dom2, dom2.get(marker.prefix + "-end"), isRoot2);
      cleanEmptyNodes(dom2, dom2.get(marker.prefix + "-start"), isRoot2);
    };
    const isReplacementPattern = (pattern) => pattern.start.length === 0;
    const matchesPattern = (patternContent) => (element, offset) => {
      const text2 = element.data;
      const searchText = text2.substring(0, offset);
      const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
      const startIndex = searchText.lastIndexOf(patternContent);
      if (startIndex !== -1) {
        return startIndex + patternContent.length;
      } else if (startEndIndex !== -1) {
        return startEndIndex + 1;
      } else {
        return -1;
      }
    };
    const findPatternStartFromSpot = (dom2, pattern, block, spot) => {
      const startPattern = pattern.start;
      const startSpot = repeatLeft(dom2, spot.container, spot.offset, matchesPattern(startPattern), block);
      return startSpot.bind((spot2) => {
        if (spot2.offset >= startPattern.length) {
          const rng = dom2.createRng();
          rng.setStart(spot2.container, spot2.offset - startPattern.length);
          rng.setEnd(spot2.container, spot2.offset);
          return Optional.some(rng);
        } else {
          const offset = spot2.offset - startPattern.length;
          return scanLeft(spot2.container, offset, block).map((nextSpot) => {
            const rng = dom2.createRng();
            rng.setStart(nextSpot.container, nextSpot.offset);
            rng.setEnd(spot2.container, spot2.offset);
            return rng;
          }).filter((rng) => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom2, pattern, block, point(spot2.container, 0)));
        }
      });
    };
    const findPatternStart = (dom2, pattern, node, offset, block, requireGap = false) => {
      if (pattern.start.length === 0 && !requireGap) {
        const rng = dom2.createRng();
        rng.setStart(node, offset);
        rng.setEnd(node, offset);
        return Optional.some(rng);
      }
      return textBefore(node, offset, block).bind((spot) => {
        const start2 = findPatternStartFromSpot(dom2, pattern, block, spot);
        return start2.bind((startRange) => {
          if (requireGap) {
            if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
              return Optional.none();
            } else if (spot.offset === 0 && startRange.endContainer.textContent.length === startRange.endOffset) {
              return Optional.none();
            }
          }
          return Optional.some(startRange);
        });
      });
    };
    const findPattern = (editor, block, details) => {
      const dom2 = editor.dom;
      const root = dom2.getRoot();
      const pattern = details.pattern;
      const endNode = details.position.container;
      const endOffset = details.position.offset;
      return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind((spot) => {
        const endPathRng = generatePathRange(root, spot.container, spot.offset, endNode, endOffset);
        if (isReplacementPattern(pattern)) {
          return Optional.some({
            matches: [{
              pattern,
              startRng: endPathRng,
              endRng: endPathRng
            }],
            position: spot
          });
        } else {
          const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block);
          const results = resultsOpt.getOr({
            matches: [],
            position: spot
          });
          const pos = results.position;
          const start2 = findPatternStart(dom2, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
          return start2.map((startRng) => {
            const startPathRng = generatePathRangeFromRange(root, startRng);
            return {
              matches: results.matches.concat([{
                pattern,
                startRng: startPathRng,
                endRng: endPathRng
              }]),
              position: point(startRng.startContainer, startRng.startOffset)
            };
          });
        }
      });
    };
    const findPatternsRec = (editor, patterns, node, offset, block) => {
      const dom2 = editor.dom;
      return textBefore(node, offset, dom2.getRoot()).bind((endSpot) => {
        const rng = dom2.createRng();
        rng.setStart(block, 0);
        rng.setEnd(node, offset);
        const text2 = rng.toString();
        for (let i = 0; i < patterns.length; i++) {
          const pattern = patterns[i];
          if (!endsWith(text2, pattern.end)) {
            continue;
          }
          const patternsWithoutCurrent = patterns.slice();
          patternsWithoutCurrent.splice(i, 1);
          const result = findPattern(editor, block, {
            pattern,
            remainingPatterns: patternsWithoutCurrent,
            position: endSpot
          });
          if (result.isSome()) {
            return result;
          }
        }
        return Optional.none();
      });
    };
    const applyPattern = (editor, pattern, patternRange) => {
      editor.selection.setRng(patternRange);
      if (pattern.type === "inline-format") {
        each$f(pattern.format, (format) => {
          editor.formatter.apply(format);
        });
      } else {
        editor.execCommand(pattern.cmd, false, pattern.value);
      }
    };
    const applyReplacementPattern = (editor, pattern, marker, isRoot2) => {
      const markerRange = rangeFromMarker(editor.dom, marker);
      deleteRng(editor.dom, markerRange, isRoot2);
      applyPattern(editor, pattern, markerRange);
    };
    const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot2) => {
      const dom2 = editor.dom;
      const markerEndRange = rangeFromMarker(dom2, endMarker);
      const markerStartRange = rangeFromMarker(dom2, startMarker);
      deleteRng(dom2, markerStartRange, isRoot2);
      deleteRng(dom2, markerEndRange, isRoot2);
      const patternMarker = {
        prefix: startMarker.prefix,
        start: startMarker.end,
        end: endMarker.start
      };
      const patternRange = rangeFromMarker(dom2, patternMarker);
      applyPattern(editor, pattern, patternRange);
    };
    const addMarkers = (dom2, matches) => {
      const markerPrefix = generate$1("mce_textpattern");
      const matchesWithEnds = foldr(matches, (acc, match2) => {
        const endMarker = createMarker(dom2, markerPrefix + `_end${acc.length}`, match2.endRng);
        return acc.concat([{
          ...match2,
          endMarker
        }]);
      }, []);
      return foldr(matchesWithEnds, (acc, match2) => {
        const idx = matchesWithEnds.length - acc.length - 1;
        const startMarker = isReplacementPattern(match2.pattern) ? match2.endMarker : createMarker(dom2, markerPrefix + `_start${idx}`, match2.startRng);
        return acc.concat([{
          ...match2,
          startMarker
        }]);
      }, []);
    };
    const findPatterns = (editor, patterns, space) => {
      const rng = editor.selection.getRng();
      if (rng.collapsed === false) {
        return [];
      }
      return getParentBlock(editor, rng).bind((block) => {
        const offset = Math.max(0, rng.startOffset - (space ? 1 : 0));
        return findPatternsRec(editor, patterns, rng.startContainer, offset, block);
      }).fold(() => [], (result) => result.matches);
    };
    const applyMatches = (editor, matches) => {
      if (matches.length === 0) {
        return;
      }
      const dom2 = editor.dom;
      const bookmark = editor.selection.getBookmark();
      const matchesWithMarkers = addMarkers(dom2, matches);
      each$f(matchesWithMarkers, (match2) => {
        const block = dom2.getParent(match2.startMarker.start, dom2.isBlock);
        const isRoot2 = (node) => node === block;
        if (isReplacementPattern(match2.pattern)) {
          applyReplacementPattern(editor, match2.pattern, match2.endMarker, isRoot2);
        } else {
          applyPatternWithContent(editor, match2.pattern, match2.startMarker, match2.endMarker, isRoot2);
        }
        removeMarker(dom2, match2.endMarker, isRoot2);
        removeMarker(dom2, match2.startMarker, isRoot2);
      });
      editor.selection.moveToBookmark(bookmark);
    };
    const hasPatterns = (patternSet) => patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0;
    const handleEnter = (editor, patternSet) => {
      if (!editor.selection.isCollapsed() || !hasPatterns(patternSet)) {
        return false;
      }
      const inlineMatches = findPatterns(editor, patternSet.inlinePatterns, false);
      const blockMatches = findPatterns$1(editor, patternSet.blockPatterns);
      if (blockMatches.length > 0 || inlineMatches.length > 0) {
        editor.undoManager.add();
        editor.undoManager.extra(() => {
          editor.execCommand("mceInsertNewLine");
        }, () => {
          editor.insertContent(zeroWidth);
          applyMatches(editor, inlineMatches);
          applyMatches$1(editor, blockMatches);
          const range2 = editor.selection.getRng();
          const spot = textBefore(range2.startContainer, range2.startOffset, editor.dom.getRoot());
          editor.execCommand("mceInsertNewLine");
          spot.each((s) => {
            const node = s.container;
            if (node.data.charAt(s.offset - 1) === zeroWidth) {
              node.deleteData(s.offset - 1, 1);
              cleanEmptyNodes(editor.dom, node.parentNode, (e) => e === editor.dom.getRoot());
            }
          });
        });
        return true;
      }
      return false;
    };
    const handleInlineKey = (editor, inlinePatterns) => {
      if (inlinePatterns.length > 0) {
        const inlineMatches = findPatterns(editor, inlinePatterns, true);
        if (inlineMatches.length > 0) {
          editor.undoManager.transact(() => {
            applyMatches(editor, inlineMatches);
          });
        }
      }
    };
    const checkKeyEvent = (codes, event, predicate) => {
      for (let i = 0; i < codes.length; i++) {
        if (predicate(codes[i], event)) {
          return true;
        }
      }
      return false;
    };
    const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event2) => {
      return code === event2.keyCode && VK.modifierPressed(event2) === false;
    });
    const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event2) => {
      return chr.charCodeAt(0) === event2.charCode;
    });
    const setup$2 = (editor) => {
      const charCodes = [
        ",",
        ".",
        ";",
        ":",
        "!",
        "?"
      ];
      const keyCodes = [32];
      const getPatternSet = () => createPatternSet(getTextPatterns(editor));
      const getInlinePatterns$1 = () => getInlinePatterns(getTextPatterns(editor));
      editor.on("keydown", (e) => {
        if (e.keyCode === 13 && !VK.modifierPressed(e)) {
          if (handleEnter(editor, getPatternSet())) {
            e.preventDefault();
          }
        }
      }, true);
      editor.on("keyup", (e) => {
        if (checkKeyCode(keyCodes, e)) {
          handleInlineKey(editor, getInlinePatterns$1());
        }
      });
      editor.on("keypress", (e) => {
        if (checkCharCode(charCodes, e)) {
          Delay.setEditorTimeout(editor, () => {
            handleInlineKey(editor, getInlinePatterns$1());
          });
        }
      });
    };
    const setup$1 = (editor) => {
      setup$2(editor);
    };
    const Quirks = (editor) => {
      const each2 = Tools.each;
      const BACKSPACE = VK.BACKSPACE, DELETE2 = VK.DELETE, dom2 = editor.dom, selection = editor.selection, parser = editor.parser;
      const browser2 = Env.browser;
      const isGecko = browser2.isFirefox();
      const isWebKit = browser2.isChromium() || browser2.isSafari();
      const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
      const setEditorCommandState2 = (cmd, state) => {
        try {
          editor.getDoc().execCommand(cmd, false, state);
        } catch (ex) {
        }
      };
      const isDefaultPrevented = (e) => {
        return e.isDefaultPrevented();
      };
      const emptyEditorWhenDeleting = () => {
        const serializeRng = (rng) => {
          const body = dom2.create("body");
          const contents = rng.cloneContents();
          body.appendChild(contents);
          return selection.serializer.serialize(body, { format: "html" });
        };
        const allContentsSelected = (rng) => {
          const selection2 = serializeRng(rng);
          const allRng = dom2.createRng();
          allRng.selectNode(editor.getBody());
          const allSelection = serializeRng(allRng);
          return selection2 === allSelection;
        };
        editor.on("keydown", (e) => {
          const keyCode = e.keyCode;
          let isCollapsed, body;
          if (!isDefaultPrevented(e) && (keyCode === DELETE2 || keyCode === BACKSPACE)) {
            isCollapsed = editor.selection.isCollapsed();
            body = editor.getBody();
            if (isCollapsed && !dom2.isEmpty(body)) {
              return;
            }
            if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
              return;
            }
            e.preventDefault();
            editor.setContent("");
            if (body.firstChild && dom2.isBlock(body.firstChild)) {
              editor.selection.setCursorLocation(body.firstChild, 0);
            } else {
              editor.selection.setCursorLocation(body, 0);
            }
            editor.nodeChanged();
          }
        });
      };
      const selectAll = () => {
        editor.shortcuts.add("meta+a", null, "SelectAll");
      };
      const documentElementEditingFocus = () => {
        if (!editor.inline) {
          dom2.bind(editor.getDoc(), "mousedown mouseup", (e) => {
            let rng;
            if (e.target === editor.getDoc().documentElement) {
              rng = selection.getRng();
              editor.getBody().focus();
              if (e.type === "mousedown") {
                if (isCaretContainer$2(rng.startContainer)) {
                  return;
                }
                selection.placeCaretAt(e.clientX, e.clientY);
              } else {
                selection.setRng(rng);
              }
            }
          });
        }
      };
      const removeHrOnBackspace = () => {
        editor.on("keydown", (e) => {
          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
            if (!editor.getBody().getElementsByTagName("hr").length) {
              return;
            }
            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
              const node = selection.getNode();
              const previousSibling = node.previousSibling;
              if (node.nodeName === "HR") {
                dom2.remove(node);
                e.preventDefault();
                return;
              }
              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") {
                dom2.remove(previousSibling);
                e.preventDefault();
              }
            }
          }
        });
      };
      const focusBody2 = () => {
        if (!Range.prototype.getClientRects) {
          editor.on("mousedown", (e) => {
            if (!isDefaultPrevented(e) && e.target.nodeName === "HTML") {
              const body = editor.getBody();
              body.blur();
              Delay.setEditorTimeout(editor, () => {
                body.focus();
              });
            }
          });
        }
      };
      const selectControlElements = () => {
        const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
        editor.on("click", (e) => {
          const target = e.target;
          if (/^(IMG|HR)$/.test(target.nodeName) && dom2.getContentEditableParent(target) !== "false") {
            e.preventDefault();
            editor.selection.select(target);
            editor.nodeChanged();
          }
          if (target.nodeName === "A" && dom2.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0) {
            e.preventDefault();
            selection.select(target);
          }
        });
      };
      const removeStylesWhenDeletingAcrossBlockElements = () => {
        const getAttributeApplyFunction = () => {
          const template = dom2.getAttribs(selection.getStart().cloneNode(false));
          return () => {
            const target = selection.getStart();
            if (target !== editor.getBody()) {
              dom2.setAttrib(target, "style", null);
              each2(template, (attr) => {
                target.setAttributeNode(attr.cloneNode(true));
              });
            }
          };
        };
        const isSelectionAcrossElements = () => {
          return !selection.isCollapsed() && dom2.getParent(selection.getStart(), dom2.isBlock) !== dom2.getParent(selection.getEnd(), dom2.isBlock);
        };
        editor.on("keypress", (e) => {
          let applyAttributes2;
          if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
            applyAttributes2 = getAttributeApplyFunction();
            editor.getDoc().execCommand("delete", false, null);
            applyAttributes2();
            e.preventDefault();
            return false;
          }
        });
        dom2.bind(editor.getDoc(), "cut", (e) => {
          let applyAttributes2;
          if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
            applyAttributes2 = getAttributeApplyFunction();
            Delay.setEditorTimeout(editor, () => {
              applyAttributes2();
            });
          }
        });
      };
      const disableBackspaceIntoATable = () => {
        editor.on("keydown", (e) => {
          if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
            if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
              const previousSibling = selection.getNode().previousSibling;
              if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
                e.preventDefault();
                return false;
              }
            }
          }
        });
      };
      const removeBlockQuoteOnBackSpace = () => {
        editor.on("keydown", (e) => {
          let rng, parent2;
          if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
            return;
          }
          rng = selection.getRng();
          const container = rng.startContainer;
          const offset = rng.startOffset;
          const root = dom2.getRoot();
          parent2 = container;
          if (!rng.collapsed || offset !== 0) {
            return;
          }
          while (parent2 && parent2.parentNode && parent2.parentNode.firstChild === parent2 && parent2.parentNode !== root) {
            parent2 = parent2.parentNode;
          }
          if (parent2.tagName === "BLOCKQUOTE") {
            editor.formatter.toggle("blockquote", null, parent2);
            rng = dom2.createRng();
            rng.setStart(container, 0);
            rng.setEnd(container, 0);
            selection.setRng(rng);
          }
        });
      };
      const setGeckoEditingOptions = () => {
        const setOpts = () => {
          setEditorCommandState2("StyleWithCSS", false);
          setEditorCommandState2("enableInlineTableEditing", false);
          if (!getObjectResizing(editor)) {
            setEditorCommandState2("enableObjectResizing", false);
          }
        };
        if (!isReadOnly$1(editor)) {
          editor.on("BeforeExecCommand mousedown", setOpts);
        }
      };
      const addBrAfterLastLinks = () => {
        const fixLinks = () => {
          each2(dom2.select("a"), (node) => {
            let parentNode = node.parentNode;
            const root = dom2.getRoot();
            if (parentNode.lastChild === node) {
              while (parentNode && !dom2.isBlock(parentNode)) {
                if (parentNode.parentNode.lastChild !== parentNode || parentNode === root) {
                  return;
                }
                parentNode = parentNode.parentNode;
              }
              dom2.add(parentNode, "br", { "data-mce-bogus": 1 });
            }
          });
        };
        editor.on("SetContent ExecCommand", (e) => {
          if (e.type === "setcontent" || e.command === "mceInsertLink") {
            fixLinks();
          }
        });
      };
      const setDefaultBlockType = () => {
        editor.on("init", () => {
          setEditorCommandState2("DefaultParagraphSeparator", getForcedRootBlock(editor));
        });
      };
      const isAllContentSelected = (editor2) => {
        const body = editor2.getBody();
        const rng = editor2.selection.getRng();
        return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
      };
      const normalizeSelection2 = () => {
        editor.on("keyup focusin mouseup", (e) => {
          if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
            selection.normalize();
          }
        }, true);
      };
      const showBrokenImageIcon = () => {
        editor.contentStyles.push("img:-moz-broken {-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}");
      };
      const restoreFocusOnKeyDown = () => {
        if (!editor.inline) {
          editor.on("keydown", () => {
            if (document.activeElement === document.body) {
              editor.getWin().focus();
            }
          });
        }
      };
      const bodyHeight = () => {
        if (!editor.inline) {
          editor.contentStyles.push("body {min-height: 150px}");
          editor.on("click", (e) => {
            let rng;
            if (e.target.nodeName === "HTML") {
              rng = editor.selection.getRng();
              editor.getBody().focus();
              editor.selection.setRng(rng);
              editor.selection.normalize();
              editor.nodeChanged();
            }
          });
        }
      };
      const blockCmdArrowNavigation = () => {
        if (isMac) {
          editor.on("keydown", (e) => {
            if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
              e.preventDefault();
              const selection2 = editor.selection.getSel();
              selection2.modify("move", e.keyCode === 37 ? "backward" : "forward", "lineboundary");
            }
          });
        }
      };
      const tapLinksAndImages = () => {
        editor.on("click", (e) => {
          let elm = e.target;
          do {
            if (elm.tagName === "A") {
              e.preventDefault();
              return;
            }
          } while (elm = elm.parentNode);
        });
        editor.contentStyles.push(".mce-content-body {-webkit-touch-callout: none}");
      };
      const blockFormSubmitInsideEditor = () => {
        editor.on("init", () => {
          editor.dom.bind(editor.getBody(), "submit", (e) => {
            e.preventDefault();
          });
        });
      };
      const removeAppleInterchangeBrs = () => {
        parser.addNodeFilter("br", (nodes) => {
          let i = nodes.length;
          while (i--) {
            if (nodes[i].attr("class") === "Apple-interchange-newline") {
              nodes[i].remove();
            }
          }
        });
      };
      const refreshContentEditable = noop;
      const isHidden = () => {
        if (!isGecko || editor.removed) {
          return false;
        }
        const sel = editor.selection.getSel();
        return !sel || !sel.rangeCount || sel.rangeCount === 0;
      };
      const setupRtc = () => {
        if (isWebKit) {
          documentElementEditingFocus();
          selectControlElements();
          blockFormSubmitInsideEditor();
          selectAll();
          if (isiOS) {
            restoreFocusOnKeyDown();
            bodyHeight();
            tapLinksAndImages();
          }
        }
        if (isGecko) {
          focusBody2();
          setGeckoEditingOptions();
          showBrokenImageIcon();
          blockCmdArrowNavigation();
        }
      };
      const setup2 = () => {
        removeBlockQuoteOnBackSpace();
        emptyEditorWhenDeleting();
        if (!Env.windowsPhone) {
          normalizeSelection2();
        }
        if (isWebKit) {
          documentElementEditingFocus();
          selectControlElements();
          setDefaultBlockType();
          blockFormSubmitInsideEditor();
          disableBackspaceIntoATable();
          removeAppleInterchangeBrs();
          if (isiOS) {
            restoreFocusOnKeyDown();
            bodyHeight();
            tapLinksAndImages();
          } else {
            selectAll();
          }
        }
        if (isGecko) {
          removeHrOnBackspace();
          focusBody2();
          removeStylesWhenDeletingAcrossBlockElements();
          setGeckoEditingOptions();
          addBrAfterLastLinks();
          showBrokenImageIcon();
          blockCmdArrowNavigation();
          disableBackspaceIntoATable();
        }
      };
      if (isRtc(editor)) {
        setupRtc();
      } else {
        setup2();
      }
      return {
        refreshContentEditable,
        isHidden
      };
    };
    const DOM$6 = DOMUtils.DOM;
    const appendStyle = (editor, text2) => {
      const body = SugarElement.fromDom(editor.getBody());
      const container = getStyleContainer(getRootNode(body));
      const style = SugarElement.fromTag("style");
      set$2(style, "type", "text/css");
      append$1(style, SugarElement.fromText(text2));
      append$1(container, style);
      editor.on("remove", () => {
        remove$6(style);
      });
    };
    const getRootName = (editor) => editor.inline ? editor.getElement().nodeName.toLowerCase() : void 0;
    const removeUndefined = (obj) => filter$5(obj, (v) => isUndefined(v) === false);
    const mkParserSettings = (editor) => {
      const getOption2 = editor.options.get;
      const blobCache = editor.editorUpload.blobCache;
      return removeUndefined({
        allow_conditional_comments: getOption2("allow_conditional_comments"),
        allow_html_data_urls: getOption2("allow_html_data_urls"),
        allow_svg_data_urls: getOption2("allow_svg_data_urls"),
        allow_html_in_named_anchor: getOption2("allow_html_in_named_anchor"),
        allow_script_urls: getOption2("allow_script_urls"),
        allow_unsafe_link_target: getOption2("allow_unsafe_link_target"),
        convert_fonts_to_spans: getOption2("convert_fonts_to_spans"),
        fix_list_elements: getOption2("fix_list_elements"),
        font_size_legacy_values: getOption2("font_size_legacy_values"),
        forced_root_block: getOption2("forced_root_block"),
        forced_root_block_attrs: getOption2("forced_root_block_attrs"),
        preserve_cdata: getOption2("preserve_cdata"),
        remove_trailing_brs: getOption2("remove_trailing_brs"),
        inline_styles: getOption2("inline_styles"),
        root_name: getRootName(editor),
        validate: true,
        blob_cache: blobCache,
        document: editor.getDoc()
      });
    };
    const mkSchemaSettings = (editor) => {
      const getOption2 = editor.options.get;
      return removeUndefined({
        custom_elements: getOption2("custom_elements"),
        extended_valid_elements: getOption2("extended_valid_elements"),
        invalid_elements: getOption2("invalid_elements"),
        invalid_styles: getOption2("invalid_styles"),
        schema: getOption2("schema"),
        valid_children: getOption2("valid_children"),
        valid_classes: getOption2("valid_classes"),
        valid_elements: getOption2("valid_elements"),
        valid_styles: getOption2("valid_styles"),
        verify_html: getOption2("verify_html"),
        padd_empty_block_inline_children: getOption2("format_empty_lines")
      });
    };
    const mkSerializerSettings = (editor) => {
      const getOption2 = editor.options.get;
      return {
        ...mkParserSettings(editor),
        ...mkSchemaSettings(editor),
        ...removeUndefined({
          url_converter: getOption2("url_converter"),
          url_converter_scope: getOption2("url_converter_scope"),
          element_format: getOption2("element_format"),
          entities: getOption2("entities"),
          entity_encoding: getOption2("entity_encoding"),
          indent: getOption2("indent"),
          indent_after: getOption2("indent_after"),
          indent_before: getOption2("indent_before")
        })
      };
    };
    const createParser = (editor) => {
      const parser = DomParser(mkParserSettings(editor), editor.schema);
      parser.addAttributeFilter("src,href,style,tabindex", (nodes, name2) => {
        let i = nodes.length, node, value2;
        const dom2 = editor.dom;
        const internalName = "data-mce-" + name2;
        while (i--) {
          node = nodes[i];
          value2 = node.attr(name2);
          if (value2 && !node.attr(internalName)) {
            if (value2.indexOf("data:") === 0 || value2.indexOf("blob:") === 0) {
              continue;
            }
            if (name2 === "style") {
              value2 = dom2.serializeStyle(dom2.parseStyle(value2), node.name);
              if (!value2.length) {
                value2 = null;
              }
              node.attr(internalName, value2);
              node.attr(name2, value2);
            } else if (name2 === "tabindex") {
              node.attr(internalName, value2);
              node.attr(name2, null);
            } else {
              node.attr(internalName, editor.convertURL(value2, name2, node.name));
            }
          }
        }
      });
      parser.addNodeFilter("script", (nodes) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          const type2 = node.attr("type") || "no/type";
          if (type2.indexOf("mce-") !== 0) {
            node.attr("type", "mce-" + type2);
          }
        }
      });
      if (editor.options.get("preserve_cdata")) {
        parser.addNodeFilter("#cdata", (nodes) => {
          let i = nodes.length;
          while (i--) {
            const node = nodes[i];
            node.type = 8;
            node.name = "#comment";
            node.value = "[CDATA[" + editor.dom.encode(node.value) + "]]";
          }
        });
      }
      parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div", (nodes) => {
        let i = nodes.length;
        const nonEmptyElements = editor.schema.getNonEmptyElements();
        while (i--) {
          const node = nodes[i];
          if (node.isEmpty(nonEmptyElements) && node.getAll("br").length === 0) {
            node.append(new AstNode("br", 1));
          }
        }
      });
      return parser;
    };
    const autoFocus = (editor) => {
      const autoFocus2 = getAutoFocus(editor);
      if (autoFocus2) {
        Delay.setEditorTimeout(editor, () => {
          let focusEditor2;
          if (autoFocus2 === true) {
            focusEditor2 = editor;
          } else {
            focusEditor2 = editor.editorManager.get(autoFocus2);
          }
          if (!focusEditor2.destroyed) {
            focusEditor2.focus();
          }
        }, 100);
      }
    };
    const moveSelectionToFirstCaretPosition = (editor) => {
      const root = editor.dom.getRoot();
      if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
        firstPositionIn(root).each((pos) => {
          const node = pos.getNode();
          const caretPos = isTable$3(node) ? firstPositionIn(node).getOr(pos) : pos;
          editor.selection.setRng(caretPos.toRange());
        });
      }
    };
    const initEditor2 = (editor) => {
      editor.bindPendingEventDelegates();
      editor.initialized = true;
      fireInit(editor);
      editor.focus(true);
      moveSelectionToFirstCaretPosition(editor);
      editor.nodeChanged({ initial: true });
      const initInstanceCallback = getInitInstanceCallback(editor);
      if (isFunction(initInstanceCallback)) {
        initInstanceCallback.call(editor, editor);
      }
      autoFocus(editor);
    };
    const getStyleSheetLoader$1 = (editor) => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
    const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
      const promises = [getStyleSheetLoader$1(editor).loadAll(css)];
      if (editor.inline) {
        return promises;
      } else {
        return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
      }
    };
    const loadContentCss = (editor) => {
      const styleSheetLoader = getStyleSheetLoader$1(editor);
      const fontCss = getFontCss(editor);
      const css = editor.contentCSS;
      const removeCss = () => {
        styleSheetLoader.unloadAll(css);
        if (!editor.inline) {
          editor.ui.styleSheetLoader.unloadAll(fontCss);
        }
      };
      const loaded = () => {
        if (editor.removed) {
          removeCss();
        } else {
          editor.on("remove", removeCss);
        }
      };
      if (editor.contentStyles.length > 0) {
        let contentCssText = "";
        Tools.each(editor.contentStyles, (style) => {
          contentCssText += style + "\r\n";
        });
        editor.dom.addStyle(contentCssText);
      }
      const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
      const contentStyle = getContentStyle(editor);
      if (contentStyle) {
        appendStyle(editor, contentStyle);
      }
      return allStylesheets;
    };
    const preInit = (editor) => {
      const doc = editor.getDoc(), body = editor.getBody();
      firePreInit(editor);
      if (!shouldBrowserSpellcheck(editor)) {
        doc.body.spellcheck = false;
        DOM$6.setAttrib(body, "spellcheck", "false");
      }
      editor.quirks = Quirks(editor);
      firePostRender(editor);
      const directionality = getDirectionality(editor);
      if (directionality !== void 0) {
        body.dir = directionality;
      }
      const protect = getProtect(editor);
      if (protect) {
        editor.on("BeforeSetContent", (e) => {
          Tools.each(protect, (pattern) => {
            e.content = e.content.replace(pattern, (str) => {
              return "<!--mce:protected " + escape(str) + "-->";
            });
          });
        });
      }
      editor.on("SetContent", () => {
        editor.addVisual(editor.getBody());
      });
      editor.on("compositionstart compositionend", (e) => {
        editor.composing = e.type === "compositionstart";
      });
    };
    const loadInitialContent = (editor) => {
      if (!isRtc(editor)) {
        editor.load({
          initial: true,
          format: "html"
        });
      }
      editor.startContent = editor.getContent({ format: "raw" });
    };
    const initEditorWithInitialContent = (editor) => {
      if (editor.removed !== true) {
        loadInitialContent(editor);
        initEditor2(editor);
      }
    };
    const contentBodyLoaded = (editor) => {
      const targetElm = editor.getElement();
      let doc = editor.getDoc();
      if (editor.inline) {
        DOM$6.addClass(targetElm, "mce-content-body");
        editor.contentDocument = doc = document;
        editor.contentWindow = window;
        editor.bodyElement = targetElm;
        editor.contentAreaContainer = targetElm;
      }
      const body = editor.getBody();
      body.disabled = true;
      editor.readonly = isReadOnly$1(editor);
      if (!editor.readonly) {
        if (editor.inline && DOM$6.getStyle(body, "position", true) === "static") {
          body.style.position = "relative";
        }
        body.contentEditable = "true";
      }
      body.disabled = false;
      editor.editorUpload = EditorUpload(editor);
      editor.schema = Schema(mkSchemaSettings(editor));
      editor.dom = DOMUtils(doc, {
        keep_values: true,
        url_converter: editor.convertURL,
        url_converter_scope: editor,
        update_styles: true,
        root_element: editor.inline ? editor.getBody() : null,
        collect: () => editor.inline,
        schema: editor.schema,
        contentCssCors: shouldUseContentCssCors(editor),
        referrerPolicy: getReferrerPolicy(editor),
        onSetAttrib: (e) => {
          editor.dispatch("SetAttrib", e);
        }
      });
      editor.parser = createParser(editor);
      editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
      editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
      editor.annotator = Annotator(editor);
      editor.formatter = Formatter(editor);
      editor.undoManager = UndoManager(editor);
      editor._nodeChangeDispatcher = new NodeChange(editor);
      editor._selectionOverrides = SelectionOverrides(editor);
      setup$o(editor);
      setup$6(editor);
      setup$m(editor);
      if (!isRtc(editor)) {
        setup$5(editor);
        setup$1(editor);
      }
      const caret = setup$b(editor);
      setup$p(editor, caret);
      setup$n(editor);
      setup$q(editor);
      setup$7(editor);
      const setupRtcThunk = setup$s(editor);
      preInit(editor);
      setupRtcThunk.fold(() => {
        loadContentCss(editor).then(() => initEditorWithInitialContent(editor));
      }, (setupRtc) => {
        editor.setProgressState(true);
        loadContentCss(editor).then(() => {
          setupRtc().then((_rtcMode) => {
            editor.setProgressState(false);
            initEditorWithInitialContent(editor);
            bindEvents(editor);
          }, (err) => {
            editor.notificationManager.open({
              type: "error",
              text: String(err)
            });
            initEditorWithInitialContent(editor);
            bindEvents(editor);
          });
        });
      });
    };
    const initContentBody = (editor, skipWrite) => {
      if (!editor.inline) {
        editor.getElement().style.visibility = editor.orgVisibility;
      }
      if (!skipWrite && !editor.inline) {
        const iframe = editor.iframeElement;
        const binder2 = bind$1(SugarElement.fromDom(iframe), "load", () => {
          binder2.unbind();
          editor.contentDocument = iframe.contentDocument;
          contentBodyLoaded(editor);
        });
        iframe.srcdoc = editor.iframeHTML;
      } else {
        contentBodyLoaded(editor);
      }
    };
    const DOM$5 = DOMUtils.DOM;
    const createIframeElement = (id, title, customAttrs, tabindex) => {
      const iframe = SugarElement.fromTag("iframe");
      tabindex.each((t) => set$2(iframe, "tabindex", t));
      setAll$1(iframe, customAttrs);
      setAll$1(iframe, {
        id: id + "_ifr",
        frameBorder: "0",
        allowTransparency: "true",
        title
      });
      add$2(iframe, "tox-edit-area__iframe");
      return iframe;
    };
    const getIframeHtml = (editor) => {
      let iframeHTML = getDocType(editor) + "<html><head>";
      if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
        iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
      }
      iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
      const bodyId = getBodyId(editor);
      const bodyClass = getBodyClass(editor);
      const translatedAriaText = editor.translate(getIframeAriaText(editor));
      if (getContentSecurityPolicy(editor)) {
        iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
      }
      iframeHTML += `</head><body id="${bodyId}" class="mce-content-body ${bodyClass}" data-id="${editor.id}" aria-label="${translatedAriaText}"><br></body></html>`;
      return iframeHTML;
    };
    const createIframe = (editor, boxInfo) => {
      const iframeTitle = editor.translate("Rich Text Area");
      const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), "tabindex").bind(toInt);
      const ifr = createIframeElement(editor.id, iframeTitle, getIframeAttrs(editor), tabindex).dom;
      ifr.onload = () => {
        ifr.onload = null;
        editor.dispatch("load");
      };
      editor.contentAreaContainer = boxInfo.iframeContainer;
      editor.iframeElement = ifr;
      editor.iframeHTML = getIframeHtml(editor);
      DOM$5.add(boxInfo.iframeContainer, ifr);
    };
    const init$1 = (editor, boxInfo) => {
      createIframe(editor, boxInfo);
      if (boxInfo.editorContainer) {
        DOM$5.get(boxInfo.editorContainer).style.display = editor.orgDisplay;
        editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
      }
      editor.getElement().style.display = "none";
      DOM$5.setAttrib(editor.id, "aria-hidden", "true");
      initContentBody(editor);
    };
    const DOM$4 = DOMUtils.DOM;
    const initPlugin = (editor, initializedPlugins, plugin) => {
      const Plugin = PluginManager.get(plugin);
      const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, "");
      plugin = Tools.trim(plugin);
      if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
        if (editor.plugins[plugin]) {
          return;
        }
        try {
          const pluginInstance = Plugin(editor, pluginUrl) || {};
          editor.plugins[plugin] = pluginInstance;
          if (isFunction(pluginInstance.init)) {
            pluginInstance.init(editor, pluginUrl);
            initializedPlugins.push(plugin);
          }
        } catch (e) {
          pluginInitError(editor, plugin, e);
        }
      }
    };
    const trimLegacyPrefix = (name2) => {
      return name2.replace(/^\-/, "");
    };
    const initPlugins = (editor) => {
      const initializedPlugins = [];
      each$f(getPlugins(editor), (name2) => {
        initPlugin(editor, initializedPlugins, trimLegacyPrefix(name2));
      });
    };
    const initIcons = (editor) => {
      const iconPackName = Tools.trim(getIconPackName(editor));
      const currentIcons = editor.ui.registry.getAll().icons;
      const loadIcons2 = {
        ...IconManager.get("default").icons,
        ...IconManager.get(iconPackName).icons
      };
      each$e(loadIcons2, (svgData, icon) => {
        if (!has$2(currentIcons, icon)) {
          editor.ui.registry.addIcon(icon, svgData);
        }
      });
    };
    const initTheme = (editor) => {
      const theme = getTheme(editor);
      if (isString(theme)) {
        const Theme = ThemeManager.get(theme);
        editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
        if (isFunction(editor.theme.init)) {
          editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ""));
        }
      } else {
        editor.theme = {};
      }
    };
    const initModel = (editor) => {
      const model = getModel(editor);
      const Model = ModelManager.get(model);
      editor.model = Model(editor, ModelManager.urls[model]);
    };
    const renderFromLoadedTheme = (editor) => {
      return editor.theme.renderUI();
    };
    const renderFromThemeFunc = (editor) => {
      const elm = editor.getElement();
      const theme = getTheme(editor);
      const info = theme(editor, elm);
      if (info.editorContainer.nodeType) {
        info.editorContainer.id = info.editorContainer.id || editor.id + "_parent";
      }
      if (info.iframeContainer && info.iframeContainer.nodeType) {
        info.iframeContainer.id = info.iframeContainer.id || editor.id + "_iframecontainer";
      }
      info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
      return info;
    };
    const createThemeFalseResult = (element) => {
      return {
        editorContainer: element,
        iframeContainer: element,
        api: {}
      };
    };
    const renderThemeFalseIframe = (targetElement) => {
      const iframeContainer = DOM$4.create("div");
      DOM$4.insertAfter(iframeContainer, targetElement);
      return createThemeFalseResult(iframeContainer);
    };
    const renderThemeFalse = (editor) => {
      const targetElement = editor.getElement();
      return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
    };
    const renderThemeUi = (editor) => {
      const elm = editor.getElement();
      editor.orgDisplay = elm.style.display;
      if (isString(getTheme(editor))) {
        return renderFromLoadedTheme(editor);
      } else if (isFunction(getTheme(editor))) {
        return renderFromThemeFunc(editor);
      } else {
        return renderThemeFalse(editor);
      }
    };
    const augmentEditorUiApi = (editor, api2) => {
      const uiApiFacade = {
        show: Optional.from(api2.show).getOr(noop),
        hide: Optional.from(api2.hide).getOr(noop),
        isEnabled: Optional.from(api2.isEnabled).getOr(always),
        setEnabled: (state) => {
          if (!editor.mode.isReadOnly()) {
            Optional.from(api2.setEnabled).each((f) => f(state));
          }
        }
      };
      editor.ui = {
        ...editor.ui,
        ...uiApiFacade
      };
    };
    const init = (editor) => {
      editor.dispatch("ScriptsLoaded");
      initIcons(editor);
      initTheme(editor);
      initModel(editor);
      initPlugins(editor);
      const renderInfo = renderThemeUi(editor);
      augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
      const boxInfo = {
        editorContainer: renderInfo.editorContainer,
        iframeContainer: renderInfo.iframeContainer
      };
      editor.editorContainer = boxInfo.editorContainer ? boxInfo.editorContainer : null;
      appendContentCssFromSettings(editor);
      if (editor.inline) {
        return initContentBody(editor);
      } else {
        return init$1(editor, boxInfo);
      }
    };
    const DOM$3 = DOMUtils.DOM;
    const hasSkipLoadPrefix = (name2) => name2.charAt(0) === "-";
    const loadLanguage = (scriptLoader, editor) => {
      const languageCode = getLanguageCode(editor);
      const languageUrl = getLanguageUrl(editor);
      if (I18n.hasCode(languageCode) === false && languageCode !== "en") {
        const url = isNotEmpty(languageUrl) ? languageUrl : `${editor.editorManager.baseURL}/langs/${languageCode}.js`;
        scriptLoader.add(url).catch(() => {
          languageLoadError(editor, url, languageCode);
        });
      }
    };
    const loadTheme = (editor, suffix) => {
      const theme = getTheme(editor);
      if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
        const themeUrl = getThemeUrl(editor);
        const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${theme}/theme${suffix}.js`;
        ThemeManager.load(theme, url).catch(() => {
          themeLoadError(editor, url, theme);
        });
      }
    };
    const loadModel = (editor, suffix) => {
      const model = getModel(editor);
      if (model !== "plugin" && !has$2(ModelManager.urls, model)) {
        const modelUrl = getModelUrl(editor);
        const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${model}/model${suffix}.js`;
        ModelManager.load(model, url).catch(() => {
          modelLoadError(editor, url, model);
        });
      }
    };
    const getIconsUrlMetaFromUrl = (editor) => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map((url) => ({
      url,
      name: Optional.none()
    }));
    const getIconsUrlMetaFromName = (editor, name2, suffix) => Optional.from(name2).filter((name3) => isNotEmpty(name3) && !IconManager.has(name3)).map((name3) => ({
      url: `${editor.editorManager.baseURL}/icons/${name3}/icons${suffix}.js`,
      name: Optional.some(name3)
    }));
    const loadIcons = (scriptLoader, editor, suffix) => {
      const defaultIconsUrl = getIconsUrlMetaFromName(editor, "default", suffix);
      const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ""));
      each$f(cat([
        defaultIconsUrl,
        customIconsUrl
      ]), (urlMeta) => {
        scriptLoader.add(urlMeta.url).catch(() => {
          iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
        });
      });
    };
    const loadPlugins = (editor, suffix) => {
      const loadPlugin = (name2, url) => {
        PluginManager.load(name2, url).catch(() => {
          pluginLoadError(editor, url, name2);
        });
      };
      each$e(getExternalPlugins$1(editor), (url, name2) => {
        loadPlugin(name2, url);
        editor.options.set("plugins", getPlugins(editor).concat(name2));
      });
      each$f(getPlugins(editor), (plugin) => {
        plugin = Tools.trim(plugin);
        if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
          loadPlugin(plugin, `plugins/${plugin}/plugin${suffix}.js`);
        }
      });
    };
    const isThemeLoaded = (editor) => {
      const theme = getTheme(editor);
      return !isString(theme) || isNonNullable(ThemeManager.get(theme));
    };
    const isModelLoaded = (editor) => {
      const model = getModel(editor);
      return isNonNullable(ModelManager.get(model));
    };
    const loadScripts = (editor, suffix) => {
      const scriptLoader = ScriptLoader2.ScriptLoader;
      const initEditor3 = () => {
        if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
          init(editor);
        }
      };
      loadTheme(editor, suffix);
      loadModel(editor, suffix);
      loadLanguage(scriptLoader, editor);
      loadIcons(scriptLoader, editor, suffix);
      loadPlugins(editor, suffix);
      scriptLoader.loadQueue().then(initEditor3, initEditor3);
    };
    const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
      contentCssCors: hasContentCssCors(editor),
      referrerPolicy: getReferrerPolicy(editor)
    });
    const render = (editor) => {
      const id = editor.id;
      I18n.setCode(getLanguageCode(editor));
      const readyHandler = () => {
        DOM$3.unbind(window, "ready", readyHandler);
        editor.render();
      };
      if (!EventUtils.Event.domLoaded) {
        DOM$3.bind(window, "ready", readyHandler);
        return;
      }
      if (!editor.getElement()) {
        return;
      }
      const element = SugarElement.fromDom(editor.getElement());
      const snapshot = clone$4(element);
      editor.on("remove", () => {
        eachr(element.dom.attributes, (attr) => remove$b(element, attr.name));
        setAll$1(element, snapshot);
      });
      editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
      if (!isInline(editor)) {
        editor.orgVisibility = editor.getElement().style.visibility;
        editor.getElement().style.visibility = "hidden";
      } else {
        editor.inline = true;
      }
      const form = editor.getElement().form || DOM$3.getParent(id, "form");
      if (form) {
        editor.formElement = form;
        if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
          DOM$3.insertAfter(DOM$3.create("input", {
            type: "hidden",
            name: id
          }), id);
          editor.hasHiddenInput = true;
        }
        editor.formEventDelegate = (e) => {
          editor.dispatch(e.type, e);
        };
        DOM$3.bind(form, "submit reset", editor.formEventDelegate);
        editor.on("reset", () => {
          editor.resetContent();
        });
        if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
          form._mceOldSubmit = form.submit;
          form.submit = () => {
            editor.editorManager.triggerSave();
            editor.setDirty(false);
            return form._mceOldSubmit(form);
          };
        }
      }
      editor.windowManager = WindowManager(editor);
      editor.notificationManager = NotificationManager(editor);
      if (isEncodingXml(editor)) {
        editor.on("GetContent", (e) => {
          if (e.save) {
            e.content = DOM$3.encode(e.content);
          }
        });
      }
      if (shouldAddFormSubmitTrigger(editor)) {
        editor.on("submit", () => {
          if (editor.initialized) {
            editor.save();
          }
        });
      }
      if (shouldAddUnloadTrigger(editor)) {
        editor._beforeUnload = () => {
          if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
            editor.save({
              format: "raw",
              no_events: true,
              set_dirty: false
            });
          }
        };
        editor.editorManager.on("BeforeUnload", editor._beforeUnload);
      }
      editor.editorManager.add(editor);
      loadScripts(editor, editor.suffix);
    };
    const sectionResult = (sections, settings) => ({
      sections: constant(sections),
      options: constant(settings)
    });
    const deviceDetection = detect$2().deviceType;
    const isPhone = deviceDetection.isPhone();
    const isTablet = deviceDetection.isTablet();
    const normalizePlugins = (plugins) => {
      if (isNullable(plugins)) {
        return [];
      } else {
        const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
        const trimmedPlugins = map$3(pluginNames, trim$3);
        return filter$6(trimmedPlugins, isNotEmpty);
      }
    };
    const extractSections = (keys2, options) => {
      const result = bifilter(options, (value2, key) => {
        return contains$2(keys2, key);
      });
      return sectionResult(result.t, result.f);
    };
    const getSection = (sectionResult2, name2, defaults = {}) => {
      const sections = sectionResult2.sections();
      const sectionOptions = get$a(sections, name2).getOr({});
      return Tools.extend({}, defaults, sectionOptions);
    };
    const hasSection = (sectionResult2, name2) => {
      return has$2(sectionResult2.sections(), name2);
    };
    const getSectionConfig = (sectionResult2, name2) => {
      return hasSection(sectionResult2, name2) ? sectionResult2.sections()[name2] : {};
    };
    const getMobileOverrideOptions = (mobileOptions, isPhone2) => {
      const defaultMobileOptions = {
        table_grid: false,
        object_resizing: false,
        resize: false,
        toolbar_mode: get$a(mobileOptions, "toolbar_mode").getOr("scrolling"),
        toolbar_sticky: false
      };
      const defaultPhoneOptions = { menubar: false };
      return {
        ...defaultMobileOptions,
        ...isPhone2 ? defaultPhoneOptions : {}
      };
    };
    const getExternalPlugins = (overrideOptions, options) => {
      var _a;
      const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
      if (overrideOptions && overrideOptions.external_plugins) {
        return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
      } else {
        return userDefinedExternalPlugins;
      }
    };
    const combinePlugins = (forcedPlugins, plugins) => {
      return [].concat(normalizePlugins(forcedPlugins)).concat(normalizePlugins(plugins));
    };
    const getPlatformPlugins = (isMobileDevice, sectionResult2, desktopPlugins, mobilePlugins) => {
      if (isMobileDevice && hasSection(sectionResult2, "mobile")) {
        return mobilePlugins;
      } else {
        return desktopPlugins;
      }
    };
    const processPlugins = (isMobileDevice, sectionResult2, defaultOverrideOptions, options) => {
      const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
      const desktopPlugins = normalizePlugins(options.plugins);
      const mobileConfig = getSectionConfig(sectionResult2, "mobile");
      const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
      const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult2, desktopPlugins, mobilePlugins);
      const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
      return Tools.extend(options, {
        forced_plugins: forcedPlugins,
        plugins: combinedPlugins
      });
    };
    const isOnMobile = (isMobileDevice, sectionResult2) => {
      return isMobileDevice && hasSection(sectionResult2, "mobile");
    };
    const combineOptions = (isMobileDevice, isPhone2, defaultOptions, defaultOverrideOptions, options) => {
      var _a;
      const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone2) } : {};
      const sectionResult2 = extractSections(["mobile"], deepMerge(deviceOverrideOptions, options));
      const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult2.options(), isOnMobile(isMobileDevice, sectionResult2) ? getSection(sectionResult2, "mobile") : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult2.options()) });
      return processPlugins(isMobileDevice, sectionResult2, defaultOverrideOptions, extendedOptions);
    };
    const normalizeOptions = (defaultOverrideOptions, options) => combineOptions(isPhone || isTablet, isPhone, options, defaultOverrideOptions, options);
    const addVisual = (editor, elm) => addVisual$1(editor, elm);
    const registerExecCommands$3 = (editor) => {
      const toggleFormat2 = (name2, value2) => {
        editor.formatter.toggle(name2, value2);
        editor.nodeChanged();
      };
      const toggleAlign = (align) => () => {
        each$f("left,center,right,justify".split(","), (name2) => {
          if (align !== name2) {
            editor.formatter.remove("align" + name2);
          }
        });
        if (align !== "none") {
          toggleFormat2("align" + align);
        }
      };
      editor.editorCommands.addCommands({
        JustifyLeft: toggleAlign("left"),
        JustifyCenter: toggleAlign("center"),
        JustifyRight: toggleAlign("right"),
        JustifyFull: toggleAlign("justify"),
        JustifyNone: toggleAlign("none")
      });
    };
    const registerQueryStateCommands$1 = (editor) => {
      const alignStates = (name2) => () => {
        const selection = editor.selection;
        const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
        return exists(nodes, (node) => isNonNullable(editor.formatter.matchNode(node, name2)));
      };
      editor.editorCommands.addCommands({
        JustifyLeft: alignStates("alignleft"),
        JustifyCenter: alignStates("aligncenter"),
        JustifyRight: alignStates("alignright"),
        JustifyFull: alignStates("alignjustify")
      }, "state");
    };
    const registerCommands$a = (editor) => {
      registerExecCommands$3(editor);
      registerQueryStateCommands$1(editor);
    };
    const registerCommands$9 = (editor) => {
      editor.editorCommands.addCommands({
        "Cut,Copy,Paste": (command) => {
          const doc = editor.getDoc();
          let failed;
          try {
            doc.execCommand(command);
          } catch (ex) {
            failed = true;
          }
          if (command === "paste" && !doc.queryCommandEnabled(command)) {
            failed = true;
          }
          if (failed || !doc.queryCommandSupported(command)) {
            let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.`);
            if (Env.os.isMacOS() || Env.os.isiOS()) {
              msg = msg.replace(/Ctrl\+/g, "\u2318+");
            }
            editor.notificationManager.open({
              text: msg,
              type: "error"
            });
          }
        }
      });
    };
    const trimOrPadLeftRight = (dom2, rng, html2) => {
      const root = SugarElement.fromDom(dom2.getRoot());
      if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng))) {
        html2 = html2.replace(/^ /, "&nbsp;");
      } else {
        html2 = html2.replace(/^&nbsp;/, " ");
      }
      if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng))) {
        html2 = html2.replace(/(&nbsp;| )(<br( \/)>)?$/, "&nbsp;");
      } else {
        html2 = html2.replace(/&nbsp;(<br( \/)?>)?$/, " ");
      }
      return html2;
    };
    const processValue$1 = (value2) => {
      if (typeof value2 !== "string") {
        const details = Tools.extend({
          paste: value2.paste,
          data: { paste: value2.paste }
        }, value2);
        return {
          content: value2.content,
          details
        };
      }
      return {
        content: value2,
        details: {}
      };
    };
    const trimOrPad = (editor, value2) => {
      const selection = editor.selection;
      const dom2 = editor.dom;
      if (/^ | $/.test(value2)) {
        return trimOrPadLeftRight(dom2, selection.getRng(), value2);
      } else {
        return value2;
      }
    };
    const insertAtCaret = (editor, value2) => {
      const { content, details } = processValue$1(value2);
      preProcessSetContent(editor, {
        content: trimOrPad(editor, content),
        format: "html",
        set: false,
        selection: true,
        paste: details.paste
      }).each((args) => {
        const insertedContent = insertContent$1(editor, args.content, details);
        postProcessSetContent(editor, insertedContent, args);
        editor.addVisual();
      });
    };
    const registerCommands$8 = (editor) => {
      editor.editorCommands.addCommands({
        mceCleanup: () => {
          const bm = editor.selection.getBookmark();
          editor.setContent(editor.getContent());
          editor.selection.moveToBookmark(bm);
        },
        insertImage: (_command, _ui, value2) => {
          insertAtCaret(editor, editor.dom.createHTML("img", { src: value2 }));
        },
        insertHorizontalRule: () => {
          editor.execCommand("mceInsertContent", false, "<hr>");
        },
        insertText: (_command, _ui, value2) => {
          insertAtCaret(editor, editor.dom.encode(value2));
        },
        insertHTML: (_command, _ui, value2) => {
          insertAtCaret(editor, value2);
        },
        mceInsertContent: (_command, _ui, value2) => {
          insertAtCaret(editor, value2);
        },
        mceSetContent: (_command, _ui, value2) => {
          editor.setContent(value2);
        },
        mceReplaceContent: (_command, _ui, value2) => {
          editor.execCommand("mceInsertContent", false, value2.replace(/\{\$selection\}/g, editor.selection.getContent({ format: "text" })));
        },
        mceNewDocument: () => {
          editor.setContent("");
        }
      });
    };
    const legacyPropNames = {
      "font-size": "size",
      "font-family": "face"
    };
    const getSpecifiedFontProp = (propName, rootElm, elm) => {
      const getProperty = (elm2) => getRaw$1(elm2, propName).orThunk(() => {
        if (name(elm2) === "font") {
          return get$a(legacyPropNames, propName).bind((legacyPropName) => getOpt(elm2, legacyPropName));
        } else {
          return Optional.none();
        }
      });
      const isRoot2 = (elm2) => eq(SugarElement.fromDom(rootElm), elm2);
      return closest$2(SugarElement.fromDom(elm), (elm2) => getProperty(elm2), isRoot2);
    };
    const normalizeFontFamily = (fontFamily) => fontFamily.replace(/[\'\"\\]/g, "").replace(/,\s+/g, ",");
    const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
    const getFontProp = (propName) => (rootElm, elm) => Optional.from(elm).map(SugarElement.fromDom).filter(isElement$7).bind((element) => getSpecifiedFontProp(propName, rootElm, element.dom).or(getComputedFontProp(propName, element.dom))).getOr("");
    const getFontSize = getFontProp("font-size");
    const getFontFamily = compose(normalizeFontFamily, getFontProp("font-family"));
    const findFirstCaretElement = (editor) => firstPositionIn(editor.getBody()).map((caret) => {
      const container = caret.container();
      return isText$9(container) ? container.parentNode : container;
    });
    const getCaretElement = (editor) => Optional.from(editor.selection.getRng()).bind((rng) => {
      const root = editor.getBody();
      const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
      return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
    });
    const bindRange = (editor, binder2) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder2);
    const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
    const fromFontSizeNumber = (editor, value2) => {
      if (/^[0-9.]+$/.test(value2)) {
        const fontSizeNumber = parseInt(value2, 10);
        if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
          const fontSizes = getFontStyleValues(editor);
          const fontClasses = getFontSizeClasses(editor);
          if (fontClasses) {
            return fontClasses[fontSizeNumber - 1] || value2;
          } else {
            return fontSizes[fontSizeNumber - 1] || value2;
          }
        } else {
          return value2;
        }
      } else {
        return value2;
      }
    };
    const normalizeFontNames = (font) => {
      const fonts = font.split(/\s*,\s*/);
      return map$3(fonts, (font2) => {
        if (font2.indexOf(" ") !== -1 && !(startsWith(font2, '"') || startsWith(font2, `'`))) {
          return `'${font2}'`;
        } else {
          return font2;
        }
      }).join(",");
    };
    const fontNameAction = (editor, value2) => {
      const font = fromFontSizeNumber(editor, value2);
      editor.formatter.toggle("fontname", { value: normalizeFontNames(font) });
      editor.nodeChanged();
    };
    const fontNameQuery = (editor) => mapRange(editor, (elm) => getFontFamily(editor.getBody(), elm.dom)).getOr("");
    const fontSizeAction = (editor, value2) => {
      editor.formatter.toggle("fontsize", { value: fromFontSizeNumber(editor, value2) });
      editor.nodeChanged();
    };
    const fontSizeQuery = (editor) => mapRange(editor, (elm) => getFontSize(editor.getBody(), elm.dom)).getOr("");
    const lineHeightQuery = (editor) => mapRange(editor, (elm) => {
      const root = SugarElement.fromDom(editor.getBody());
      const specifiedStyle = closest$2(elm, (elm2) => getRaw$1(elm2, "line-height"), curry(eq, root));
      const computedStyle = () => {
        const lineHeight = parseFloat(get$7(elm, "line-height"));
        const fontSize = parseFloat(get$7(elm, "font-size"));
        return String(lineHeight / fontSize);
      };
      return specifiedStyle.getOrThunk(computedStyle);
    }).getOr("");
    const lineHeightAction = (editor, lineHeight) => {
      editor.formatter.toggle("lineheight", { value: String(lineHeight) });
      editor.nodeChanged();
    };
    const registerExecCommands$2 = (editor) => {
      const toggleFormat2 = (name2, value2) => {
        editor.formatter.toggle(name2, value2);
        editor.nodeChanged();
      };
      editor.editorCommands.addCommands({
        "Bold,Italic,Underline,Strikethrough,Superscript,Subscript": (command) => {
          toggleFormat2(command);
        },
        "ForeColor,HiliteColor": (command, _ui, value2) => {
          toggleFormat2(command, { value: value2 });
        },
        "BackColor": (_command, _ui, value2) => {
          toggleFormat2("hilitecolor", { value: value2 });
        },
        "FontName": (_command, _ui, value2) => {
          fontNameAction(editor, value2);
        },
        "FontSize": (_command, _ui, value2) => {
          fontSizeAction(editor, value2);
        },
        "LineHeight": (_command, _ui, value2) => {
          lineHeightAction(editor, value2);
        },
        "Lang": (command, _ui, lang) => {
          toggleFormat2(command, {
            value: lang.code,
            customValue: lang.customCode
          });
        },
        "RemoveFormat": (command) => {
          editor.formatter.remove(command);
        },
        "mceBlockQuote": () => {
          toggleFormat2("blockquote");
        },
        "FormatBlock": (_command, _ui, value2) => {
          toggleFormat2(isString(value2) ? value2 : "p");
        },
        "mceToggleFormat": (_command, _ui, value2) => {
          toggleFormat2(value2);
        }
      });
    };
    const registerQueryValueCommands = (editor) => {
      const isFormatMatch = (name2) => editor.formatter.match(name2);
      editor.editorCommands.addCommands({
        "Bold,Italic,Underline,Strikethrough,Superscript,Subscript": (command) => isFormatMatch(command),
        "mceBlockQuote": () => isFormatMatch("blockquote")
      }, "state");
      editor.editorCommands.addQueryValueHandler("FontName", () => fontNameQuery(editor));
      editor.editorCommands.addQueryValueHandler("FontSize", () => fontSizeQuery(editor));
      editor.editorCommands.addQueryValueHandler("LineHeight", () => lineHeightQuery(editor));
    };
    const registerCommands$7 = (editor) => {
      registerExecCommands$2(editor);
      registerQueryValueCommands(editor);
    };
    const registerCommands$6 = (editor) => {
      editor.editorCommands.addCommands({
        mceAddUndoLevel: () => {
          editor.undoManager.add();
        },
        mceEndUndoLevel: () => {
          editor.undoManager.add();
        },
        Undo: () => {
          editor.undoManager.undo();
        },
        Redo: () => {
          editor.undoManager.redo();
        }
      });
    };
    const registerCommands$5 = (editor) => {
      editor.editorCommands.addCommands({
        Indent: () => {
          indent(editor);
        },
        Outdent: () => {
          outdent(editor);
        }
      });
      editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, "state");
    };
    const registerCommands$4 = (editor) => {
      const applyLinkToSelection = (_command, _ui, value2) => {
        const linkDetails = isString(value2) ? { href: value2 } : value2;
        const anchor = editor.dom.getParent(editor.selection.getNode(), "a");
        if (isObject(linkDetails) && isString(linkDetails.href)) {
          linkDetails.href = linkDetails.href.replace(/ /g, "%20");
          if (!anchor || !linkDetails.href) {
            editor.formatter.remove("link");
          }
          if (linkDetails.href) {
            editor.formatter.apply("link", linkDetails, anchor);
          }
        }
      };
      editor.editorCommands.addCommands({
        unlink: () => {
          if (editor.selection.isCollapsed()) {
            const elm = editor.dom.getParent(editor.selection.getStart(), "a");
            if (elm) {
              editor.dom.remove(elm, true);
            }
            return;
          }
          editor.formatter.remove("link");
        },
        mceInsertLink: applyLinkToSelection,
        createLink: applyLinkToSelection
      });
    };
    const registerExecCommands$1 = (editor) => {
      editor.editorCommands.addCommands({
        "InsertUnorderedList,InsertOrderedList": (command) => {
          editor.getDoc().execCommand(command);
          const listElm = editor.dom.getParent(editor.selection.getNode(), "ol,ul");
          if (listElm) {
            const listParent = listElm.parentNode;
            if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
              const bm = editor.selection.getBookmark();
              editor.dom.split(listParent, listElm);
              editor.selection.moveToBookmark(bm);
            }
          }
        }
      });
    };
    const registerQueryStateCommands = (editor) => {
      editor.editorCommands.addCommands({
        "InsertUnorderedList,InsertOrderedList": (command) => {
          const list = editor.dom.getParent(editor.selection.getNode(), "ul,ol");
          return list && (command === "insertunorderedlist" && list.tagName === "UL" || command === "insertorderedlist" && list.tagName === "OL");
        }
      }, "state");
    };
    const registerCommands$3 = (editor) => {
      registerExecCommands$1(editor);
      registerQueryStateCommands(editor);
    };
    const registerCommands$2 = (editor) => {
      editor.editorCommands.addCommands({
        insertParagraph: () => {
          insertBreak(blockbreak, editor);
        },
        mceInsertNewLine: (_command, _ui, value2) => {
          insert(editor, value2);
        },
        InsertLineBreak: (_command, _ui, _value) => {
          insertBreak(linebreak, editor);
        }
      });
    };
    const registerCommands$1 = (editor) => {
      editor.editorCommands.addCommands({
        mceSelectNodeDepth: (_command, _ui, value2) => {
          let counter = 0;
          editor.dom.getParent(editor.selection.getNode(), (node) => {
            if (node.nodeType === 1 && counter++ === value2) {
              editor.selection.select(node);
              return false;
            }
          }, editor.getBody());
        },
        mceSelectNode: (_command, _ui, value2) => {
          editor.selection.select(value2);
        },
        selectAll: () => {
          const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$5);
          if (editingHost) {
            const rng = editor.dom.createRng();
            rng.selectNodeContents(editingHost);
            editor.selection.setRng(rng);
          }
        }
      });
    };
    const registerExecCommands = (editor) => {
      editor.editorCommands.addCommands({
        mceRemoveNode: (_command, _ui, value2) => {
          const node = value2 !== null && value2 !== void 0 ? value2 : editor.selection.getNode();
          if (node !== editor.getBody()) {
            const bm = editor.selection.getBookmark();
            editor.dom.remove(node, true);
            editor.selection.moveToBookmark(bm);
          }
        },
        mcePrint: () => {
          editor.getWin().print();
        },
        mceFocus: (_command, _ui, value2) => {
          focus(editor, value2);
        },
        mceToggleVisualAid: () => {
          editor.hasVisual = !editor.hasVisual;
          editor.addVisual();
        }
      });
    };
    const registerCommands = (editor) => {
      registerCommands$a(editor);
      registerCommands$9(editor);
      registerCommands$6(editor);
      registerCommands$1(editor);
      registerCommands$8(editor);
      registerCommands$4(editor);
      registerCommands$5(editor);
      registerCommands$2(editor);
      registerCommands$3(editor);
      registerCommands$7(editor);
      registerExecCommands(editor);
    };
    class EditorCommands {
      constructor(editor) {
        this.commands = {
          state: {},
          exec: {},
          value: {}
        };
        this.editor = editor;
      }
      execCommand(command, ui, value2, args) {
        const editor = this.editor;
        const lowerCaseCommand = command.toLowerCase();
        const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
        if (editor.removed) {
          return false;
        }
        if (lowerCaseCommand !== "mcefocus") {
          if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
            editor.focus();
          } else {
            restore(editor);
          }
        }
        const eventArgs = editor.dispatch("BeforeExecCommand", {
          command,
          ui,
          value: value2
        });
        if (eventArgs.isDefaultPrevented()) {
          return false;
        }
        const func = this.commands.exec[lowerCaseCommand];
        if (isFunction(func)) {
          func(lowerCaseCommand, ui, value2);
          editor.dispatch("ExecCommand", {
            command,
            ui,
            value: value2
          });
          return true;
        }
        return false;
      }
      queryCommandState(command) {
        if (this.editor.quirks.isHidden() || this.editor.removed) {
          return false;
        }
        const lowerCaseCommand = command.toLowerCase();
        const func = this.commands.state[lowerCaseCommand];
        if (isFunction(func)) {
          return func(lowerCaseCommand);
        }
        return false;
      }
      queryCommandValue(command) {
        if (this.editor.quirks.isHidden() || this.editor.removed) {
          return "";
        }
        const lowerCaseCommand = command.toLowerCase();
        const func = this.commands.value[lowerCaseCommand];
        if (isFunction(func)) {
          return func(lowerCaseCommand);
        }
        return "";
      }
      addCommands(commandList, type2 = "exec") {
        const commands = this.commands;
        each$e(commandList, (callback, command) => {
          each$f(command.toLowerCase().split(","), (command2) => {
            commands[type2][command2] = callback;
          });
        });
      }
      addCommand(command, callback, scope) {
        const lowerCaseCommand = command.toLowerCase();
        this.commands.exec[lowerCaseCommand] = (_command, ui, value2) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value2);
      }
      queryCommandSupported(command) {
        const lowerCaseCommand = command.toLowerCase();
        if (this.commands.exec[lowerCaseCommand]) {
          return true;
        }
        return false;
      }
      addQueryStateHandler(command, callback, scope) {
        this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
      }
      addQueryValueHandler(command, callback, scope) {
        this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
      }
    }
    const internalContentEditableAttr = "data-mce-contenteditable";
    const toggleClass = (elm, cls, state) => {
      if (has(elm, cls) && state === false) {
        remove$8(elm, cls);
      } else if (state) {
        add$2(elm, cls);
      }
    };
    const setEditorCommandState = (editor, cmd, state) => {
      try {
        editor.getDoc().execCommand(cmd, false, String(state));
      } catch (ex) {
      }
    };
    const setContentEditable = (elm, state) => {
      elm.dom.contentEditable = state ? "true" : "false";
    };
    const switchOffContentEditableTrue = (elm) => {
      each$f(descendants(elm, '*[contenteditable="true"]'), (elm2) => {
        set$2(elm2, internalContentEditableAttr, "true");
        setContentEditable(elm2, false);
      });
    };
    const switchOnContentEditableTrue = (elm) => {
      each$f(descendants(elm, `*[${internalContentEditableAttr}="true"]`), (elm2) => {
        remove$b(elm2, internalContentEditableAttr);
        setContentEditable(elm2, true);
      });
    };
    const removeFakeSelection = (editor) => {
      Optional.from(editor.selection.getNode()).each((elm) => {
        elm.removeAttribute("data-mce-selected");
      });
    };
    const restoreFakeSelection = (editor) => {
      editor.selection.setRng(editor.selection.getRng());
    };
    const toggleReadOnly = (editor, state) => {
      const body = SugarElement.fromDom(editor.getBody());
      toggleClass(body, "mce-content-readonly", state);
      if (state) {
        editor.selection.controlSelection.hideResizeRect();
        editor._selectionOverrides.hideFakeCaret();
        removeFakeSelection(editor);
        editor.readonly = true;
        setContentEditable(body, false);
        switchOffContentEditableTrue(body);
      } else {
        editor.readonly = false;
        setContentEditable(body, true);
        switchOnContentEditableTrue(body);
        setEditorCommandState(editor, "StyleWithCSS", false);
        setEditorCommandState(editor, "enableInlineTableEditing", false);
        setEditorCommandState(editor, "enableObjectResizing", false);
        if (hasEditorOrUiFocus(editor)) {
          editor.focus();
        }
        restoreFakeSelection(editor);
        editor.nodeChanged();
      }
    };
    const isReadOnly = (editor) => editor.readonly;
    const registerFilters = (editor) => {
      editor.parser.addAttributeFilter("contenteditable", (nodes) => {
        if (isReadOnly(editor)) {
          each$f(nodes, (node) => {
            node.attr(internalContentEditableAttr, node.attr("contenteditable"));
            node.attr("contenteditable", "false");
          });
        }
      });
      editor.serializer.addAttributeFilter(internalContentEditableAttr, (nodes) => {
        if (isReadOnly(editor)) {
          each$f(nodes, (node) => {
            node.attr("contenteditable", node.attr(internalContentEditableAttr));
          });
        }
      });
      editor.serializer.addTempAttr(internalContentEditableAttr);
    };
    const registerReadOnlyContentFilters = (editor) => {
      if (editor.serializer) {
        registerFilters(editor);
      } else {
        editor.on("PreInit", () => {
          registerFilters(editor);
        });
      }
    };
    const isClickEvent = (e) => e.type === "click";
    const allowedEvents = ["copy"];
    const isReadOnlyAllowedEvent = (e) => contains$2(allowedEvents, e.type);
    const getAnchorHrefOpt = (editor, elm) => {
      const isRoot2 = (elm2) => eq(elm2, SugarElement.fromDom(editor.getBody()));
      return closest$3(elm, "a", isRoot2).bind((a) => getOpt(a, "href"));
    };
    const processReadonlyEvents = (editor, e) => {
      if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
        const elm = SugarElement.fromDom(e.target);
        getAnchorHrefOpt(editor, elm).each((href) => {
          e.preventDefault();
          if (/^#/.test(href)) {
            const targetEl = editor.dom.select(`${href},[name="${removeLeading(href, "#")}"]`);
            if (targetEl.length) {
              editor.selection.scrollIntoView(targetEl[0], true);
            }
          } else {
            window.open(href, "_blank", "rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes");
          }
        });
      } else if (isReadOnlyAllowedEvent(e)) {
        editor.dispatch(e.type, e);
      }
    };
    const registerReadOnlySelectionBlockers = (editor) => {
      editor.on("ShowCaret", (e) => {
        if (isReadOnly(editor)) {
          e.preventDefault();
        }
      });
      editor.on("ObjectSelected", (e) => {
        if (isReadOnly(editor)) {
          e.preventDefault();
        }
      });
    };
    const nativeEvents = Tools.makeMap("focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover draggesture dragdrop drop drag submit compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel", " ");
    class EventDispatcher {
      constructor(settings) {
        this.bindings = {};
        this.settings = settings || {};
        this.scope = this.settings.scope || this;
        this.toggleEvent = this.settings.toggleEvent || never;
      }
      static isNative(name2) {
        return !!nativeEvents[name2.toLowerCase()];
      }
      fire(name2, args) {
        return this.dispatch(name2, args);
      }
      dispatch(name2, args) {
        const lcName = name2.toLowerCase();
        const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
        if (this.settings.beforeFire) {
          this.settings.beforeFire(event);
        }
        const handlers = this.bindings[lcName];
        if (handlers) {
          for (let i = 0, l = handlers.length; i < l; i++) {
            const callback = handlers[i];
            if (callback.removed) {
              continue;
            }
            if (callback.once) {
              this.off(lcName, callback.func);
            }
            if (event.isImmediatePropagationStopped()) {
              return event;
            }
            if (callback.func.call(this.scope, event) === false) {
              event.preventDefault();
              return event;
            }
          }
        }
        return event;
      }
      on(name2, callback, prepend2, extra2) {
        if (callback === false) {
          callback = never;
        }
        if (callback) {
          const wrappedCallback = {
            func: callback,
            removed: false
          };
          if (extra2) {
            Tools.extend(wrappedCallback, extra2);
          }
          const names = name2.toLowerCase().split(" ");
          let i = names.length;
          while (i--) {
            const currentName = names[i];
            let handlers = this.bindings[currentName];
            if (!handlers) {
              handlers = [];
              this.toggleEvent(currentName, true);
            }
            if (prepend2) {
              handlers = [
                wrappedCallback,
                ...handlers
              ];
            } else {
              handlers = [
                ...handlers,
                wrappedCallback
              ];
            }
            this.bindings[currentName] = handlers;
          }
        }
        return this;
      }
      off(name2, callback) {
        if (name2) {
          const names = name2.toLowerCase().split(" ");
          let i = names.length;
          while (i--) {
            const currentName = names[i];
            let handlers = this.bindings[currentName];
            if (!currentName) {
              each$e(this.bindings, (_value, bindingName) => {
                this.toggleEvent(bindingName, false);
                delete this.bindings[bindingName];
              });
              return this;
            }
            if (handlers) {
              if (!callback) {
                handlers.length = 0;
              } else {
                const filteredHandlers = partition$2(handlers, (handler) => handler.func === callback);
                handlers = filteredHandlers.fail;
                this.bindings[currentName] = handlers;
                each$f(filteredHandlers.pass, (handler) => {
                  handler.removed = true;
                });
              }
              if (!handlers.length) {
                this.toggleEvent(name2, false);
                delete this.bindings[currentName];
              }
            }
          }
        } else {
          each$e(this.bindings, (_value, name3) => {
            this.toggleEvent(name3, false);
          });
          this.bindings = {};
        }
        return this;
      }
      once(name2, callback, prepend2) {
        return this.on(name2, callback, prepend2, { once: true });
      }
      has(name2) {
        name2 = name2.toLowerCase();
        return !(!this.bindings[name2] || this.bindings[name2].length === 0);
      }
    }
    const getEventDispatcher = (obj) => {
      if (!obj._eventDispatcher) {
        obj._eventDispatcher = new EventDispatcher({
          scope: obj,
          toggleEvent: (name2, state) => {
            if (EventDispatcher.isNative(name2) && obj.toggleNativeEvent) {
              obj.toggleNativeEvent(name2, state);
            }
          }
        });
      }
      return obj._eventDispatcher;
    };
    const Observable = {
      fire(name2, args, bubble) {
        return this.dispatch(name2, args, bubble);
      },
      dispatch(name2, args, bubble) {
        const self = this;
        if (self.removed && name2 !== "remove" && name2 !== "detach") {
          return normalize$3(name2.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
        }
        const dispatcherArgs = getEventDispatcher(self).dispatch(name2, args);
        if (bubble !== false && self.parent) {
          let parent2 = self.parent();
          while (parent2 && !dispatcherArgs.isPropagationStopped()) {
            parent2.dispatch(name2, dispatcherArgs, false);
            parent2 = parent2.parent();
          }
        }
        return dispatcherArgs;
      },
      on(name2, callback, prepend2) {
        return getEventDispatcher(this).on(name2, callback, prepend2);
      },
      off(name2, callback) {
        return getEventDispatcher(this).off(name2, callback);
      },
      once(name2, callback) {
        return getEventDispatcher(this).once(name2, callback);
      },
      hasEventListeners(name2) {
        return getEventDispatcher(this).has(name2);
      }
    };
    const DOM$2 = DOMUtils.DOM;
    let customEventRootDelegates;
    const getEventTarget = (editor, eventName) => {
      if (eventName === "selectionchange") {
        return editor.getDoc();
      }
      if (!editor.inline && /^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(eventName)) {
        return editor.getDoc().documentElement;
      }
      const eventRoot = getEventRoot(editor);
      if (eventRoot) {
        if (!editor.eventRoot) {
          editor.eventRoot = DOM$2.select(eventRoot)[0];
        }
        return editor.eventRoot;
      }
      return editor.getBody();
    };
    const isListening = (editor) => !editor.hidden && !isReadOnly(editor);
    const fireEvent = (editor, eventName, e) => {
      if (isListening(editor)) {
        editor.dispatch(eventName, e);
      } else if (isReadOnly(editor)) {
        processReadonlyEvents(editor, e);
      }
    };
    const bindEventDelegate = (editor, eventName) => {
      let delegate;
      if (!editor.delegates) {
        editor.delegates = {};
      }
      if (editor.delegates[eventName] || editor.removed) {
        return;
      }
      const eventRootElm = getEventTarget(editor, eventName);
      if (getEventRoot(editor)) {
        if (!customEventRootDelegates) {
          customEventRootDelegates = {};
          editor.editorManager.on("removeEditor", () => {
            if (!editor.editorManager.activeEditor) {
              if (customEventRootDelegates) {
                each$e(customEventRootDelegates, (_value, name2) => {
                  editor.dom.unbind(getEventTarget(editor, name2));
                });
                customEventRootDelegates = null;
              }
            }
          });
        }
        if (customEventRootDelegates[eventName]) {
          return;
        }
        delegate = (e) => {
          const target = e.target;
          const editors2 = editor.editorManager.get();
          let i = editors2.length;
          while (i--) {
            const body = editors2[i].getBody();
            if (body === target || DOM$2.isChildOf(target, body)) {
              fireEvent(editors2[i], eventName, e);
            }
          }
        };
        customEventRootDelegates[eventName] = delegate;
        DOM$2.bind(eventRootElm, eventName, delegate);
      } else {
        delegate = (e) => {
          fireEvent(editor, eventName, e);
        };
        DOM$2.bind(eventRootElm, eventName, delegate);
        editor.delegates[eventName] = delegate;
      }
    };
    const EditorObservable = {
      ...Observable,
      bindPendingEventDelegates() {
        const self = this;
        Tools.each(self._pendingNativeEvents, (name2) => {
          bindEventDelegate(self, name2);
        });
      },
      toggleNativeEvent(name2, state) {
        const self = this;
        if (name2 === "focus" || name2 === "blur") {
          return;
        }
        if (self.removed) {
          return;
        }
        if (state) {
          if (self.initialized) {
            bindEventDelegate(self, name2);
          } else {
            if (!self._pendingNativeEvents) {
              self._pendingNativeEvents = [name2];
            } else {
              self._pendingNativeEvents.push(name2);
            }
          }
        } else if (self.initialized) {
          self.dom.unbind(getEventTarget(self, name2), name2, self.delegates[name2]);
          delete self.delegates[name2];
        }
      },
      unbindAllNativeEvents() {
        const self = this;
        const body = self.getBody();
        const dom2 = self.dom;
        if (self.delegates) {
          each$e(self.delegates, (value2, name2) => {
            self.dom.unbind(getEventTarget(self, name2), name2, value2);
          });
          delete self.delegates;
        }
        if (!self.inline && body && dom2) {
          body.onload = null;
          dom2.unbind(self.getWin());
          dom2.unbind(self.getDoc());
        }
        if (dom2) {
          dom2.unbind(body);
          dom2.unbind(self.getContainer());
        }
      }
    };
    const stringListProcessor = (value2) => {
      if (isString(value2)) {
        return {
          value: value2.split(/[ ,]/),
          valid: true
        };
      } else if (isArrayOf(value2, isString)) {
        return {
          value: value2,
          valid: true
        };
      } else {
        return {
          valid: false,
          message: `The value must be a string[] or a comma/space separated string.`
        };
      }
    };
    const getBuiltInProcessor = (type2) => {
      const validator = (() => {
        switch (type2) {
          case "array":
            return isArray$1;
          case "boolean":
            return isBoolean;
          case "function":
            return isFunction;
          case "number":
            return isNumber;
          case "object":
            return isObject;
          case "string":
            return isString;
          case "string[]":
            return stringListProcessor;
          case "object[]":
            return (val) => isArrayOf(val, isObject);
          case "regexp":
            return (val) => is$4(val, RegExp);
        }
      })();
      return (value2) => processValue(value2, validator, `The value must be a ${type2}.`);
    };
    const isBuiltInSpec = (spec) => isString(spec.processor);
    const getErrorMessage = (message, result) => {
      const additionalText = isEmpty$3(result.message) ? "" : `. ${result.message}`;
      return message + additionalText;
    };
    const isValidResult = (result) => result.valid;
    const processValue = (value2, processor, message = "") => {
      const result = processor(value2);
      if (isBoolean(result)) {
        return result ? {
          value: value2,
          valid: true
        } : {
          valid: false,
          message
        };
      } else {
        return result;
      }
    };
    const processDefaultValue = (name2, defaultValue, processor) => {
      if (!isUndefined(defaultValue)) {
        const result = processValue(defaultValue, processor);
        if (isValidResult(result)) {
          return result.value;
        } else {
          console.error(getErrorMessage(`Invalid default value passed for the "${name2}" option`, result));
        }
      }
      return void 0;
    };
    const create$5 = (editor, initialOptions) => {
      const registry2 = {};
      const values2 = {};
      const setValue = (name2, value2, processor) => {
        const result = processValue(value2, processor);
        if (isValidResult(result)) {
          values2[name2] = result.value;
          return true;
        } else {
          console.warn(getErrorMessage(`Invalid value passed for the ${name2} option`, result));
          return false;
        }
      };
      const register2 = (name2, spec) => {
        const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
        const defaultValue = processDefaultValue(name2, spec.default, processor);
        registry2[name2] = {
          ...spec,
          default: defaultValue,
          processor
        };
        const initValue = get$a(values2, name2).orThunk(() => get$a(initialOptions, name2));
        initValue.each((value2) => setValue(name2, value2, processor));
      };
      const isRegistered = (name2) => has$2(registry2, name2);
      const get2 = (name2) => get$a(values2, name2).orThunk(() => get$a(registry2, name2).map((spec) => spec.default)).getOrUndefined();
      const set2 = (name2, value2) => {
        if (!isRegistered(name2)) {
          console.warn(`"${name2}" is not a registered option. Ensure the option has been registered before setting a value.`);
          return false;
        } else {
          const spec = registry2[name2];
          if (spec.immutable) {
            console.error(`"${name2}" is an immutable option and cannot be updated`);
            return false;
          } else {
            return setValue(name2, value2, spec.processor);
          }
        }
      };
      const unset = (name2) => {
        const registered = isRegistered(name2);
        if (registered) {
          delete values2[name2];
        }
        return registered;
      };
      const isSet = (name2) => has$2(values2, name2);
      return {
        register: register2,
        isRegistered,
        get: get2,
        set: set2,
        unset,
        isSet
      };
    };
    const defaultModes = [
      "design",
      "readonly"
    ];
    const switchToMode = (editor, activeMode, availableModes, mode) => {
      const oldMode = availableModes[activeMode.get()];
      const newMode = availableModes[mode];
      try {
        newMode.activate();
      } catch (e) {
        console.error(`problem while activating editor mode ${mode}:`, e);
        return;
      }
      oldMode.deactivate();
      if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
        toggleReadOnly(editor, newMode.editorReadOnly);
      }
      activeMode.set(mode);
      fireSwitchMode(editor, mode);
    };
    const setMode = (editor, availableModes, activeMode, mode) => {
      if (mode === activeMode.get()) {
        return;
      } else if (!has$2(availableModes, mode)) {
        throw new Error(`Editor mode '${mode}' is invalid`);
      }
      if (editor.initialized) {
        switchToMode(editor, activeMode, availableModes, mode);
      } else {
        editor.on("init", () => switchToMode(editor, activeMode, availableModes, mode));
      }
    };
    const registerMode = (availableModes, mode, api2) => {
      if (contains$2(defaultModes, mode)) {
        throw new Error(`Cannot override default mode ${mode}`);
      }
      return {
        ...availableModes,
        [mode]: {
          ...api2,
          deactivate: () => {
            try {
              api2.deactivate();
            } catch (e) {
              console.error(`problem while deactivating editor mode ${mode}:`, e);
            }
          }
        }
      };
    };
    const create$4 = (editor) => {
      const activeMode = Cell("design");
      const availableModes = Cell({
        design: {
          activate: noop,
          deactivate: noop,
          editorReadOnly: false
        },
        readonly: {
          activate: noop,
          deactivate: noop,
          editorReadOnly: true
        }
      });
      registerReadOnlyContentFilters(editor);
      registerReadOnlySelectionBlockers(editor);
      return {
        isReadOnly: () => isReadOnly(editor),
        set: (mode) => setMode(editor, availableModes.get(), activeMode, mode),
        get: () => activeMode.get(),
        register: (mode, api2) => {
          availableModes.set(registerMode(availableModes.get(), mode, api2));
        }
      };
    };
    const each$2 = Tools.each, explode = Tools.explode;
    const keyCodeLookup = {
      f1: 112,
      f2: 113,
      f3: 114,
      f4: 115,
      f5: 116,
      f6: 117,
      f7: 118,
      f8: 119,
      f9: 120,
      f10: 121,
      f11: 122,
      f12: 123
    };
    const modifierNames = Tools.makeMap("alt,ctrl,shift,meta,access");
    const parseShortcut = (pattern) => {
      let key;
      const shortcut = {};
      const isMac = Env.os.isMacOS() || Env.os.isiOS();
      each$2(explode(pattern.toLowerCase(), "+"), (value2) => {
        if (value2 in modifierNames) {
          shortcut[value2] = true;
        } else {
          if (/^[0-9]{2,}$/.test(value2)) {
            shortcut.keyCode = parseInt(value2, 10);
          } else {
            shortcut.charCode = value2.charCodeAt(0);
            shortcut.keyCode = keyCodeLookup[value2] || value2.toUpperCase().charCodeAt(0);
          }
        }
      });
      const id = [shortcut.keyCode];
      for (key in modifierNames) {
        if (shortcut[key]) {
          id.push(key);
        } else {
          shortcut[key] = false;
        }
      }
      shortcut.id = id.join(",");
      if (shortcut.access) {
        shortcut.alt = true;
        if (isMac) {
          shortcut.ctrl = true;
        } else {
          shortcut.shift = true;
        }
      }
      if (shortcut.meta) {
        if (isMac) {
          shortcut.meta = true;
        } else {
          shortcut.ctrl = true;
          shortcut.meta = false;
        }
      }
      return shortcut;
    };
    class Shortcuts {
      constructor(editor) {
        this.shortcuts = {};
        this.pendingPatterns = [];
        this.editor = editor;
        const self = this;
        editor.on("keyup keypress keydown", (e) => {
          if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
            each$2(self.shortcuts, (shortcut) => {
              if (self.matchShortcut(e, shortcut)) {
                self.pendingPatterns = shortcut.subpatterns.slice(0);
                if (e.type === "keydown") {
                  self.executeShortcutAction(shortcut);
                }
                return true;
              }
            });
            if (self.matchShortcut(e, self.pendingPatterns[0])) {
              if (self.pendingPatterns.length === 1) {
                if (e.type === "keydown") {
                  self.executeShortcutAction(self.pendingPatterns[0]);
                }
              }
              self.pendingPatterns.shift();
            }
          }
        });
      }
      add(pattern, desc, cmdFunc, scope) {
        const self = this;
        const func = self.normalizeCommandFunc(cmdFunc);
        each$2(explode(Tools.trim(pattern)), (pattern2) => {
          const shortcut = self.createShortcut(pattern2, desc, func, scope);
          self.shortcuts[shortcut.id] = shortcut;
        });
        return true;
      }
      remove(pattern) {
        const shortcut = this.createShortcut(pattern);
        if (this.shortcuts[shortcut.id]) {
          delete this.shortcuts[shortcut.id];
          return true;
        }
        return false;
      }
      normalizeCommandFunc(cmdFunc) {
        const self = this;
        const cmd = cmdFunc;
        if (typeof cmd === "string") {
          return () => {
            self.editor.execCommand(cmd, false, null);
          };
        } else if (Tools.isArray(cmd)) {
          return () => {
            self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
          };
        } else {
          return cmd;
        }
      }
      createShortcut(pattern, desc, cmdFunc, scope) {
        const shortcuts = Tools.map(explode(pattern, ">"), parseShortcut);
        shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
          func: cmdFunc,
          scope: scope || this.editor
        });
        return Tools.extend(shortcuts[0], {
          desc: this.editor.translate(desc),
          subpatterns: shortcuts.slice(1)
        });
      }
      hasModifier(e) {
        return e.altKey || e.ctrlKey || e.metaKey;
      }
      isFunctionKey(e) {
        return e.type === "keydown" && e.keyCode >= 112 && e.keyCode <= 123;
      }
      matchShortcut(e, shortcut) {
        if (!shortcut) {
          return false;
        }
        if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
          return false;
        }
        if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
          return false;
        }
        if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
          e.preventDefault();
          return true;
        }
        return false;
      }
      executeShortcutAction(shortcut) {
        return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
      }
    }
    const create$3 = () => {
      const buttons = {};
      const menuItems = {};
      const popups = {};
      const icons = {};
      const contextMenus = {};
      const contextToolbars = {};
      const sidebars = {};
      const add2 = (collection, type2) => (name2, spec) => collection[name2.toLowerCase()] = {
        ...spec,
        type: type2
      };
      const addIcon = (name2, svgData) => icons[name2.toLowerCase()] = svgData;
      return {
        addButton: add2(buttons, "button"),
        addGroupToolbarButton: add2(buttons, "grouptoolbarbutton"),
        addToggleButton: add2(buttons, "togglebutton"),
        addMenuButton: add2(buttons, "menubutton"),
        addSplitButton: add2(buttons, "splitbutton"),
        addMenuItem: add2(menuItems, "menuitem"),
        addNestedMenuItem: add2(menuItems, "nestedmenuitem"),
        addToggleMenuItem: add2(menuItems, "togglemenuitem"),
        addAutocompleter: add2(popups, "autocompleter"),
        addContextMenu: add2(contextMenus, "contextmenu"),
        addContextToolbar: add2(contextToolbars, "contexttoolbar"),
        addContextForm: add2(contextToolbars, "contextform"),
        addSidebar: add2(sidebars, "sidebar"),
        addIcon,
        getAll: () => ({
          buttons,
          menuItems,
          icons,
          popups,
          contextMenus,
          contextToolbars,
          sidebars
        })
      };
    };
    const registry = () => {
      const bridge = create$3();
      return {
        addAutocompleter: bridge.addAutocompleter,
        addButton: bridge.addButton,
        addContextForm: bridge.addContextForm,
        addContextMenu: bridge.addContextMenu,
        addContextToolbar: bridge.addContextToolbar,
        addIcon: bridge.addIcon,
        addMenuButton: bridge.addMenuButton,
        addMenuItem: bridge.addMenuItem,
        addNestedMenuItem: bridge.addNestedMenuItem,
        addSidebar: bridge.addSidebar,
        addSplitButton: bridge.addSplitButton,
        addToggleButton: bridge.addToggleButton,
        addGroupToolbarButton: bridge.addGroupToolbarButton,
        addToggleMenuItem: bridge.addToggleMenuItem,
        getAll: bridge.getAll
      };
    };
    const DOM$1 = DOMUtils.DOM;
    const extend = Tools.extend, each$1 = Tools.each;
    class Editor2 {
      constructor(id, options, editorManager) {
        this.plugins = {};
        this.contentCSS = [];
        this.contentStyles = [];
        this.loadedCSS = {};
        this.isNotDirty = false;
        this.editorManager = editorManager;
        this.documentBaseUrl = editorManager.documentBaseURL;
        extend(this, EditorObservable);
        const self = this;
        this.id = id;
        this.hidden = false;
        const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
        this.options = create$5(self, normalizedOptions);
        register$7(self);
        const getOption2 = this.options.get;
        if (getOption2("deprecation_warnings")) {
          logWarnings(options, normalizedOptions);
        }
        const suffix = getOption2("suffix");
        if (suffix) {
          editorManager.suffix = suffix;
        }
        this.suffix = editorManager.suffix;
        const baseUrl = getOption2("base_url");
        if (baseUrl) {
          editorManager._setBaseUrl(baseUrl);
        }
        this.baseUri = editorManager.baseURI;
        const referrerPolicy = getReferrerPolicy(self);
        if (referrerPolicy) {
          ScriptLoader2.ScriptLoader._setReferrerPolicy(referrerPolicy);
          DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
        }
        AddOnManager.languageLoad = getOption2("language_load");
        AddOnManager.baseURL = editorManager.baseURL;
        this.setDirty(false);
        this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
        this.baseURI = this.baseUri;
        this.inline = isInline(self);
        this.shortcuts = new Shortcuts(this);
        this.editorCommands = new EditorCommands(this);
        registerCommands(this);
        const cacheSuffix = getOption2("cache_suffix");
        if (cacheSuffix) {
          Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, "");
        }
        this.ui = {
          registry: registry(),
          styleSheetLoader: void 0,
          show: noop,
          hide: noop,
          setEnabled: noop,
          isEnabled: always
        };
        this.mode = create$4(self);
        editorManager.dispatch("SetupEditor", { editor: this });
        const setupCallback = getSetupCallback(self);
        if (isFunction(setupCallback)) {
          setupCallback.call(self, self);
        }
      }
      render() {
        render(this);
      }
      focus(skipFocus) {
        this.execCommand("mceFocus", false, skipFocus);
      }
      hasFocus() {
        return hasFocus(this);
      }
      translate(text2) {
        return I18n.translate(text2);
      }
      getParam(name2, defaultVal, type2) {
        const options = this.options;
        if (!options.isRegistered(name2)) {
          if (isNonNullable(type2)) {
            options.register(name2, {
              processor: type2,
              default: defaultVal
            });
          } else {
            options.register(name2, {
              processor: always,
              default: defaultVal
            });
          }
        }
        return !options.isSet(name2) && !isUndefined(defaultVal) ? defaultVal : options.get(name2);
      }
      hasPlugin(name2, loaded) {
        const hasPlugin = contains$2(getPlugins(this), name2);
        if (hasPlugin) {
          return loaded ? PluginManager.get(name2) !== void 0 : true;
        } else {
          return false;
        }
      }
      nodeChanged(args) {
        this._nodeChangeDispatcher.nodeChanged(args);
      }
      addCommand(name2, callback, scope) {
        this.editorCommands.addCommand(name2, callback, scope);
      }
      addQueryStateHandler(name2, callback, scope) {
        this.editorCommands.addQueryStateHandler(name2, callback, scope);
      }
      addQueryValueHandler(name2, callback, scope) {
        this.editorCommands.addQueryValueHandler(name2, callback, scope);
      }
      addShortcut(pattern, desc, cmdFunc, scope) {
        this.shortcuts.add(pattern, desc, cmdFunc, scope);
      }
      execCommand(cmd, ui, value2, args) {
        return this.editorCommands.execCommand(cmd, ui, value2, args);
      }
      queryCommandState(cmd) {
        return this.editorCommands.queryCommandState(cmd);
      }
      queryCommandValue(cmd) {
        return this.editorCommands.queryCommandValue(cmd);
      }
      queryCommandSupported(cmd) {
        return this.editorCommands.queryCommandSupported(cmd);
      }
      show() {
        const self = this;
        if (self.hidden) {
          self.hidden = false;
          if (self.inline) {
            self.getBody().contentEditable = "true";
          } else {
            DOM$1.show(self.getContainer());
            DOM$1.hide(self.id);
          }
          self.load();
          self.dispatch("show");
        }
      }
      hide() {
        const self = this;
        if (!self.hidden) {
          self.save();
          if (self.inline) {
            self.getBody().contentEditable = "false";
            if (self === self.editorManager.focusedEditor) {
              self.editorManager.focusedEditor = null;
            }
          } else {
            DOM$1.hide(self.getContainer());
            DOM$1.setStyle(self.id, "display", self.orgDisplay);
          }
          self.hidden = true;
          self.dispatch("hide");
        }
      }
      isHidden() {
        return this.hidden;
      }
      setProgressState(state, time) {
        this.dispatch("ProgressState", {
          state,
          time
        });
      }
      load(args) {
        const self = this;
        let elm = self.getElement(), html2;
        if (self.removed) {
          return "";
        }
        if (elm) {
          args = args || {};
          args.load = true;
          const value2 = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
          html2 = self.setContent(value2, args);
          args.element = elm;
          if (!args.no_events) {
            self.dispatch("LoadContent", args);
          }
          args.element = elm = null;
          return html2;
        }
      }
      save(args) {
        const self = this;
        let elm = self.getElement(), html2, form;
        if (!elm || !self.initialized || self.removed) {
          return;
        }
        args = args || {};
        args.save = true;
        args.element = elm;
        html2 = args.content = self.getContent(args);
        if (!args.no_events) {
          self.dispatch("SaveContent", args);
        }
        if (args.format === "raw") {
          self.dispatch("RawSaveContent", args);
        }
        html2 = args.content;
        if (!isTextareaOrInput(elm)) {
          if (args.is_removing || !self.inline) {
            elm.innerHTML = html2;
          }
          if (form = DOM$1.getParent(self.id, "form")) {
            each$1(form.elements, (elm2) => {
              if (elm2.name === self.id) {
                elm2.value = html2;
                return false;
              }
            });
          }
        } else {
          elm.value = html2;
        }
        args.element = elm = null;
        if (args.set_dirty !== false) {
          self.setDirty(false);
        }
        return html2;
      }
      setContent(content, args) {
        return setContent(this, content, args);
      }
      getContent(args) {
        return getContent(this, args);
      }
      insertContent(content, args) {
        if (args) {
          content = extend({ content }, args);
        }
        this.execCommand("mceInsertContent", false, content);
      }
      resetContent(initialContent) {
        if (initialContent === void 0) {
          setContent(this, this.startContent, { format: "raw" });
        } else {
          setContent(this, initialContent);
        }
        this.undoManager.reset();
        this.setDirty(false);
        this.nodeChanged();
      }
      isDirty() {
        return !this.isNotDirty;
      }
      setDirty(state) {
        const oldState = !this.isNotDirty;
        this.isNotDirty = !state;
        if (state && state !== oldState) {
          this.dispatch("dirty");
        }
      }
      getContainer() {
        const self = this;
        if (!self.container) {
          self.container = DOM$1.get(self.editorContainer || self.id + "_parent");
        }
        return self.container;
      }
      getContentAreaContainer() {
        return this.contentAreaContainer;
      }
      getElement() {
        if (!this.targetElm) {
          this.targetElm = DOM$1.get(this.id);
        }
        return this.targetElm;
      }
      getWin() {
        const self = this;
        let elm;
        if (!self.contentWindow) {
          elm = self.iframeElement;
          if (elm) {
            self.contentWindow = elm.contentWindow;
          }
        }
        return self.contentWindow;
      }
      getDoc() {
        const self = this;
        let win;
        if (!self.contentDocument) {
          win = self.getWin();
          if (win) {
            self.contentDocument = win.document;
          }
        }
        return self.contentDocument;
      }
      getBody() {
        const doc = this.getDoc();
        return this.bodyElement || (doc ? doc.body : null);
      }
      convertURL(url, name2, elm) {
        const self = this, getOption2 = self.options.get;
        const urlConverterCallback = getUrlConverterCallback(self);
        if (isFunction(urlConverterCallback)) {
          return urlConverterCallback.call(self, url, elm, true, name2);
        }
        if (!getOption2("convert_urls") || elm && elm.nodeName === "LINK" || url.indexOf("file:") === 0 || url.length === 0) {
          return url;
        }
        if (getOption2("relative_urls")) {
          return self.documentBaseURI.toRelative(url);
        }
        url = self.documentBaseURI.toAbsolute(url, getOption2("remove_script_host"));
        return url;
      }
      addVisual(elm) {
        addVisual(this, elm);
      }
      remove() {
        remove$1(this);
      }
      destroy(automatic) {
        destroy(this, automatic);
      }
      uploadImages() {
        return this.editorUpload.uploadImages();
      }
      _scanForImages() {
        return this.editorUpload.scanForImages();
      }
    }
    const DOM = DOMUtils.DOM;
    const each = Tools.each;
    let boundGlobalEvents = false;
    let beforeUnloadDelegate;
    let editors = [];
    const globalEventDelegate = (e) => {
      const type2 = e.type;
      each(EditorManager.get(), (editor) => {
        switch (type2) {
          case "scroll":
            editor.dispatch("ScrollWindow", e);
            break;
          case "resize":
            editor.dispatch("ResizeWindow", e);
            break;
        }
      });
    };
    const toggleGlobalEvents = (state) => {
      if (state !== boundGlobalEvents) {
        const DOM2 = DOMUtils.DOM;
        if (state) {
          DOM2.bind(window, "resize", globalEventDelegate);
          DOM2.bind(window, "scroll", globalEventDelegate);
        } else {
          DOM2.unbind(window, "resize", globalEventDelegate);
          DOM2.unbind(window, "scroll", globalEventDelegate);
        }
        boundGlobalEvents = state;
      }
    };
    const removeEditorFromList = (targetEditor) => {
      const oldEditors = editors;
      editors = filter$6(editors, (editor) => {
        return targetEditor !== editor;
      });
      if (EditorManager.activeEditor === targetEditor) {
        EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
      }
      if (EditorManager.focusedEditor === targetEditor) {
        EditorManager.focusedEditor = null;
      }
      return oldEditors.length !== editors.length;
    };
    const purgeDestroyedEditor = (editor) => {
      if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
        removeEditorFromList(editor);
        editor.unbindAllNativeEvents();
        editor.destroy(true);
        editor.removed = true;
        editor = null;
      }
      return editor;
    };
    const isQuirksMode = document.compatMode !== "CSS1Compat";
    const EditorManager = {
      ...Observable,
      baseURI: null,
      baseURL: null,
      defaultOptions: {},
      documentBaseURL: null,
      suffix: null,
      majorVersion: "6",
      minorVersion: "1.0",
      releaseDate: "2022-06-29",
      i18n: I18n,
      activeEditor: null,
      focusedEditor: null,
      setup() {
        const self = this;
        let baseURL, documentBaseURL, suffix = "";
        documentBaseURL = URI.getDocumentBaseUrl(document.location);
        if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
          documentBaseURL = documentBaseURL.replace(/[\?#].*$/, "").replace(/[\/\\][^\/]+$/, "");
          if (!/[\/\\]$/.test(documentBaseURL)) {
            documentBaseURL += "/";
          }
        }
        const preInit2 = window.tinymce || window.tinyMCEPreInit;
        if (preInit2) {
          baseURL = preInit2.base || preInit2.baseURL;
          suffix = preInit2.suffix;
        } else {
          const scripts = document.getElementsByTagName("script");
          for (let i = 0; i < scripts.length; i++) {
            const src = scripts[i].src || "";
            if (src === "") {
              continue;
            }
            const srcScript = src.substring(src.lastIndexOf("/"));
            if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
              if (srcScript.indexOf(".min") !== -1) {
                suffix = ".min";
              }
              baseURL = src.substring(0, src.lastIndexOf("/"));
              break;
            }
          }
          if (!baseURL && document.currentScript) {
            const src = document.currentScript.src;
            if (src.indexOf(".min") !== -1) {
              suffix = ".min";
            }
            baseURL = src.substring(0, src.lastIndexOf("/"));
          }
        }
        self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
        self.documentBaseURL = documentBaseURL;
        self.baseURI = new URI(self.baseURL);
        self.suffix = suffix;
        setup$v(self);
      },
      overrideDefaults(defaultOptions) {
        const baseUrl = defaultOptions.base_url;
        if (baseUrl) {
          this._setBaseUrl(baseUrl);
        }
        const suffix = defaultOptions.suffix;
        if (defaultOptions.suffix) {
          this.suffix = suffix;
        }
        this.defaultOptions = defaultOptions;
        const pluginBaseUrls = defaultOptions.plugin_base_urls;
        if (pluginBaseUrls !== void 0) {
          each$e(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
            AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
          });
        }
      },
      init(options) {
        const self = this;
        let result;
        const invalidInlineTargets = Tools.makeMap("area base basefont br col frame hr img input isindex link meta param embed source wbr track colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu", " ");
        const isInvalidInlineTarget = (options2, elm) => options2.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
        const createId = (elm) => {
          let id = elm.id;
          if (!id) {
            id = get$a(elm, "name").filter((name2) => !DOM.get(name2)).getOrThunk(DOM.uniqueId);
            elm.setAttribute("id", id);
          }
          return id;
        };
        const execCallback = (name2) => {
          const callback = options[name2];
          if (!callback) {
            return;
          }
          return callback.apply(self, []);
        };
        const findTargets = (options2) => {
          if (Env.browser.isIE() || Env.browser.isEdge()) {
            initError("TinyMCE does not support the browser you are using. For a list of supported browsers please see: https://www.tiny.cloud/docs/tinymce/6/support/#supportedwebbrowsers");
            return [];
          } else if (isQuirksMode) {
            initError("Failed to initialize the editor as the document is not in standards mode. TinyMCE requires standards mode.");
            return [];
          } else if (isString(options2.selector)) {
            return DOM.select(options2.selector);
          } else if (isNonNullable(options2.target)) {
            return [options2.target];
          } else {
            return [];
          }
        };
        let provideResults = (editors2) => {
          result = editors2;
        };
        const initEditors = () => {
          let initCount = 0;
          const editors2 = [];
          let targets;
          const createEditor = (id, options2, targetElm) => {
            const editor = new Editor2(id, options2, self);
            editors2.push(editor);
            editor.on("init", () => {
              if (++initCount === targets.length) {
                provideResults(editors2);
              }
            });
            editor.targetElm = editor.targetElm || targetElm;
            editor.render();
          };
          DOM.unbind(window, "ready", initEditors);
          execCallback("onpageload");
          targets = unique$1(findTargets(options));
          Tools.each(targets, (elm) => {
            purgeDestroyedEditor(self.get(elm.id));
          });
          targets = Tools.grep(targets, (elm) => {
            return !self.get(elm.id);
          });
          if (targets.length === 0) {
            provideResults([]);
          } else {
            each(targets, (elm) => {
              if (isInvalidInlineTarget(options, elm)) {
                initError("Could not initialize inline editor on invalid inline target element", elm);
              } else {
                createEditor(createId(elm), options, elm);
              }
            });
          }
        };
        DOM.bind(window, "ready", initEditors);
        return new Promise((resolve2) => {
          if (result) {
            resolve2(result);
          } else {
            provideResults = (editors2) => {
              resolve2(editors2);
            };
          }
        });
      },
      get(id) {
        if (arguments.length === 0) {
          return editors.slice(0);
        } else if (isString(id)) {
          return find$2(editors, (editor) => {
            return editor.id === id;
          }).getOr(null);
        } else if (isNumber(id)) {
          return editors[id] ? editors[id] : null;
        } else {
          return null;
        }
      },
      add(editor) {
        const self = this;
        const existingEditor = self.get(editor.id);
        if (existingEditor === editor) {
          return editor;
        }
        if (existingEditor === null) {
          editors.push(editor);
        }
        toggleGlobalEvents(true);
        self.activeEditor = editor;
        self.dispatch("AddEditor", { editor });
        if (!beforeUnloadDelegate) {
          beforeUnloadDelegate = (e) => {
            const event = self.dispatch("BeforeUnload");
            if (event.returnValue) {
              e.preventDefault();
              e.returnValue = event.returnValue;
              return event.returnValue;
            }
          };
          window.addEventListener("beforeunload", beforeUnloadDelegate);
        }
        return editor;
      },
      createEditor(id, options) {
        return this.add(new Editor2(id, options, this));
      },
      remove(selector) {
        const self = this;
        let i, editor;
        if (!selector) {
          for (i = editors.length - 1; i >= 0; i--) {
            self.remove(editors[i]);
          }
          return;
        }
        if (isString(selector)) {
          each(DOM.select(selector), (elm) => {
            editor = self.get(elm.id);
            if (editor) {
              self.remove(editor);
            }
          });
          return;
        }
        editor = selector;
        if (isNull(self.get(editor.id))) {
          return null;
        }
        if (removeEditorFromList(editor)) {
          self.dispatch("RemoveEditor", { editor });
        }
        if (editors.length === 0) {
          window.removeEventListener("beforeunload", beforeUnloadDelegate);
        }
        editor.remove();
        toggleGlobalEvents(editors.length > 0);
        return editor;
      },
      execCommand(cmd, ui, value2) {
        var _a;
        const self = this;
        const editorId = isObject(value2) ? (_a = value2.id) !== null && _a !== void 0 ? _a : value2.index : value2;
        switch (cmd) {
          case "mceAddEditor": {
            if (!self.get(editorId)) {
              const editorOptions = value2.options;
              new Editor2(editorId, editorOptions, self).render();
            }
            return true;
          }
          case "mceRemoveEditor": {
            const editor = self.get(editorId);
            if (editor) {
              editor.remove();
            }
            return true;
          }
          case "mceToggleEditor": {
            const editor = self.get(editorId);
            if (!editor) {
              self.execCommand("mceAddEditor", false, value2);
              return true;
            }
            if (editor.isHidden()) {
              editor.show();
            } else {
              editor.hide();
            }
            return true;
          }
        }
        if (self.activeEditor) {
          return self.activeEditor.execCommand(cmd, ui, value2);
        }
        return false;
      },
      triggerSave: () => {
        each(editors, (editor) => {
          editor.save();
        });
      },
      addI18n: (code, items) => {
        I18n.add(code, items);
      },
      translate: (text2) => {
        return I18n.translate(text2);
      },
      setActive(editor) {
        const activeEditor = this.activeEditor;
        if (this.activeEditor !== editor) {
          if (activeEditor) {
            activeEditor.dispatch("deactivate", { relatedTarget: editor });
          }
          editor.dispatch("activate", { relatedTarget: activeEditor });
        }
        this.activeEditor = editor;
      },
      _setBaseUrl(baseUrl) {
        this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ""));
        this.baseURI = new URI(this.baseURL);
      }
    };
    EditorManager.setup();
    const setup = () => {
      const dataValue = value$2();
      const FakeClipboardItem = (items) => ({
        items,
        types: keys(items),
        getType: (type2) => get$a(items, type2).getOrUndefined()
      });
      const write2 = (data2) => {
        dataValue.set(data2);
      };
      const read2 = () => dataValue.get().getOrUndefined();
      const clear2 = dataValue.clear;
      return {
        FakeClipboardItem,
        write: write2,
        read: read2,
        clear: clear2
      };
    };
    const FakeClipboard = setup();
    const min = Math.min, max = Math.max, round = Math.round;
    const relativePosition = (rect, targetRect, rel) => {
      let x = targetRect.x;
      let y = targetRect.y;
      const w = rect.w;
      const h2 = rect.h;
      const targetW = targetRect.w;
      const targetH = targetRect.h;
      const relChars = (rel || "").split("");
      if (relChars[0] === "b") {
        y += targetH;
      }
      if (relChars[1] === "r") {
        x += targetW;
      }
      if (relChars[0] === "c") {
        y += round(targetH / 2);
      }
      if (relChars[1] === "c") {
        x += round(targetW / 2);
      }
      if (relChars[3] === "b") {
        y -= h2;
      }
      if (relChars[4] === "r") {
        x -= w;
      }
      if (relChars[3] === "c") {
        y -= round(h2 / 2);
      }
      if (relChars[4] === "c") {
        x -= round(w / 2);
      }
      return create$2(x, y, w, h2);
    };
    const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
      let pos, i;
      for (i = 0; i < rels.length; i++) {
        pos = relativePosition(rect, targetRect, rels[i]);
        if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
          return rels[i];
        }
      }
      return null;
    };
    const inflate = (rect, w, h2) => {
      return create$2(rect.x - w, rect.y - h2, rect.w + w * 2, rect.h + h2 * 2);
    };
    const intersect = (rect, cropRect) => {
      const x1 = max(rect.x, cropRect.x);
      const y1 = max(rect.y, cropRect.y);
      const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
      const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
      if (x2 - x1 < 0 || y2 - y1 < 0) {
        return null;
      }
      return create$2(x1, y1, x2 - x1, y2 - y1);
    };
    const clamp = (rect, clampRect, fixedSize) => {
      let x1 = rect.x;
      let y1 = rect.y;
      let x2 = rect.x + rect.w;
      let y2 = rect.y + rect.h;
      const cx2 = clampRect.x + clampRect.w;
      const cy2 = clampRect.y + clampRect.h;
      const underflowX1 = max(0, clampRect.x - x1);
      const underflowY1 = max(0, clampRect.y - y1);
      const overflowX2 = max(0, x2 - cx2);
      const overflowY2 = max(0, y2 - cy2);
      x1 += underflowX1;
      y1 += underflowY1;
      if (fixedSize) {
        x2 += underflowX1;
        y2 += underflowY1;
        x1 -= overflowX2;
        y1 -= overflowY2;
      }
      x2 -= overflowX2;
      y2 -= overflowY2;
      return create$2(x1, y1, x2 - x1, y2 - y1);
    };
    const create$2 = (x, y, w, h2) => {
      return {
        x,
        y,
        w,
        h: h2
      };
    };
    const fromClientRect = (clientRect) => {
      return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
    };
    const Rect = {
      inflate,
      relativePosition,
      findBestRelativePosition,
      intersect,
      clamp,
      create: create$2,
      fromClientRect
    };
    const awaiter = (resolveCb, rejectCb, timeout = 1e3) => {
      let done = false;
      let timer = null;
      const complete = (completer) => (...args) => {
        if (!done) {
          done = true;
          if (timer !== null) {
            clearTimeout(timer);
            timer = null;
          }
          completer.apply(null, args);
        }
      };
      const resolve2 = complete(resolveCb);
      const reject = complete(rejectCb);
      const start2 = (...args) => {
        if (!done && timer === null) {
          timer = setTimeout(() => reject.apply(null, args), timeout);
        }
      };
      return {
        start: start2,
        resolve: resolve2,
        reject
      };
    };
    const create$1 = () => {
      const tasks = {};
      const resultFns = {};
      const load = (id, url) => {
        const loadErrMsg = `Script at URL "${url}" failed to load`;
        const runErrMsg = `Script at URL "${url}" did not call \`tinymce.Resource.add('${id}', data)\` within 1 second`;
        if (tasks[id] !== void 0) {
          return tasks[id];
        } else {
          const task = new Promise((resolve2, reject) => {
            const waiter = awaiter(resolve2, reject);
            resultFns[id] = waiter.resolve;
            ScriptLoader2.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
          });
          tasks[id] = task;
          return task;
        }
      };
      const add2 = (id, data2) => {
        if (resultFns[id] !== void 0) {
          resultFns[id](data2);
          delete resultFns[id];
        }
        tasks[id] = Promise.resolve(data2);
      };
      const unload = (id) => {
        delete tasks[id];
      };
      return {
        load,
        add: add2,
        unload
      };
    };
    const Resource = create$1();
    const create = () => (() => {
      let data2 = {};
      let keys2 = [];
      const storage = {
        getItem: (key) => {
          const item = data2[key];
          return item ? item : null;
        },
        setItem: (key, value2) => {
          keys2.push(key);
          data2[key] = String(value2);
        },
        key: (index2) => {
          return keys2[index2];
        },
        removeItem: (key) => {
          keys2 = keys2.filter((k) => k === key);
          delete data2[key];
        },
        clear: () => {
          keys2 = [];
          data2 = {};
        },
        length: 0
      };
      Object.defineProperty(storage, "length", {
        get: () => keys2.length,
        configurable: false,
        enumerable: false
      });
      return storage;
    })();
    let localStorage;
    try {
      const test = "__storage_test__";
      localStorage = window.localStorage;
      localStorage.setItem(test, test);
      localStorage.removeItem(test);
    } catch (e) {
      localStorage = create();
    }
    var LocalStorage = localStorage;
    const publicApi = {
      geom: { Rect },
      util: {
        Delay,
        Tools,
        VK,
        URI,
        EventDispatcher,
        Observable,
        I18n,
        LocalStorage,
        ImageUploader
      },
      dom: {
        EventUtils,
        TreeWalker: DomTreeWalker,
        TextSeeker,
        DOMUtils,
        ScriptLoader: ScriptLoader2,
        RangeUtils,
        Serializer: DomSerializer,
        StyleSheetLoader,
        ControlSelection,
        BookmarkManager,
        Selection: EditorSelection,
        Event: EventUtils.Event
      },
      html: {
        Styles,
        Entities,
        Node: AstNode,
        Schema,
        DomParser,
        Writer,
        Serializer: HtmlSerializer
      },
      Env,
      AddOnManager,
      Annotator,
      Formatter,
      UndoManager,
      EditorCommands,
      WindowManager,
      NotificationManager,
      EditorObservable,
      Shortcuts,
      Editor: Editor2,
      FocusManager,
      EditorManager,
      DOM: DOMUtils.DOM,
      ScriptLoader: ScriptLoader2.ScriptLoader,
      PluginManager,
      ThemeManager,
      ModelManager,
      IconManager,
      Resource,
      FakeClipboard,
      trim: Tools.trim,
      isArray: Tools.isArray,
      is: Tools.is,
      toArray: Tools.toArray,
      makeMap: Tools.makeMap,
      each: Tools.each,
      map: Tools.map,
      grep: Tools.grep,
      inArray: Tools.inArray,
      extend: Tools.extend,
      walk: Tools.walk,
      resolve: Tools.resolve,
      explode: Tools.explode,
      _addCacheSuffix: Tools._addCacheSuffix
    };
    const tinymce2 = Tools.extend(EditorManager, publicApi);
    const exportToModuleLoaders = (tinymce3) => {
      {
        try {
          module.exports = tinymce3;
        } catch (_) {
        }
      }
    };
    const exportToWindowGlobal = (tinymce3) => {
      window.tinymce = tinymce3;
      window.tinyMCE = tinymce3;
    };
    exportToWindowGlobal(tinymce2);
    exportToModuleLoaders(tinymce2);
  })();
})(tinymce$2);
var tinymce$1 = tinymce$2.exports;
var validEvents = [
  "onActivate",
  "onAddUndo",
  "onBeforeAddUndo",
  "onBeforeExecCommand",
  "onBeforeGetContent",
  "onBeforeRenderUI",
  "onBeforeSetContent",
  "onBeforePaste",
  "onBlur",
  "onChange",
  "onClearUndos",
  "onClick",
  "onContextMenu",
  "onCopy",
  "onCut",
  "onDblclick",
  "onDeactivate",
  "onDirty",
  "onDrag",
  "onDragDrop",
  "onDragEnd",
  "onDragGesture",
  "onDragOver",
  "onDrop",
  "onExecCommand",
  "onFocus",
  "onFocusIn",
  "onFocusOut",
  "onGetContent",
  "onHide",
  "onInit",
  "onKeyDown",
  "onKeyPress",
  "onKeyUp",
  "onLoadContent",
  "onMouseDown",
  "onMouseEnter",
  "onMouseLeave",
  "onMouseMove",
  "onMouseOut",
  "onMouseOver",
  "onMouseUp",
  "onNodeChange",
  "onObjectResizeStart",
  "onObjectResized",
  "onObjectSelected",
  "onPaste",
  "onPostProcess",
  "onPostRender",
  "onPreProcess",
  "onProgressState",
  "onRedo",
  "onRemove",
  "onReset",
  "onSaveContent",
  "onSelectionChange",
  "onSetAttrib",
  "onSetContent",
  "onShow",
  "onSubmit",
  "onUndo",
  "onVisualAid"
];
var isValidKey = function(key) {
  return validEvents.map(function(event) {
    return event.toLowerCase();
  }).indexOf(key.toLowerCase()) !== -1;
};
var bindHandlers = function(initEvent, listeners, editor) {
  Object.keys(listeners).filter(isValidKey).forEach(function(key) {
    var handler = listeners[key];
    if (typeof handler === "function") {
      if (key === "onInit") {
        handler(initEvent, editor);
      } else {
        editor.on(key.substring(2), function(e) {
          return handler(e, editor);
        });
      }
    }
  });
};
var bindModelHandlers = function(props, ctx, editor, modelValue) {
  var modelEvents = props.modelEvents ? props.modelEvents : null;
  var normalizedEvents = Array.isArray(modelEvents) ? modelEvents.join(" ") : modelEvents;
  watch(modelValue, function(val, prevVal) {
    if (editor && typeof val === "string" && val !== prevVal && val !== editor.getContent({ format: props.outputFormat })) {
      editor.setContent(val);
    }
  });
  editor.on(normalizedEvents ? normalizedEvents : "change input undo redo", function() {
    ctx.emit("update:modelValue", editor.getContent({ format: props.outputFormat }));
  });
};
var initEditor = function(initEvent, props, ctx, editor, modelValue, content) {
  editor.setContent(content());
  if (ctx.attrs["onUpdate:modelValue"]) {
    bindModelHandlers(props, ctx, editor, modelValue);
  }
  bindHandlers(initEvent, ctx.attrs, editor);
};
var unique = 0;
var uuid = function(prefix) {
  var time = Date.now();
  var random = Math.floor(Math.random() * 1e9);
  unique++;
  return prefix + "_" + random + unique + String(time);
};
var isTextarea = function(element) {
  return element !== null && element.tagName.toLowerCase() === "textarea";
};
var normalizePluginArray = function(plugins) {
  if (typeof plugins === "undefined" || plugins === "") {
    return [];
  }
  return Array.isArray(plugins) ? plugins : plugins.split(" ");
};
var mergePlugins = function(initPlugins, inputPlugins) {
  return normalizePluginArray(initPlugins).concat(normalizePluginArray(inputPlugins));
};
var isNullOrUndefined = function(value) {
  return value === null || value === void 0;
};
var createState = function() {
  return {
    listeners: [],
    scriptId: uuid("tiny-script"),
    scriptLoaded: false
  };
};
var CreateScriptLoader = function() {
  var state = createState();
  var injectScriptTag = function(scriptId, doc, url, callback) {
    var scriptTag = doc.createElement("script");
    scriptTag.referrerPolicy = "origin";
    scriptTag.type = "application/javascript";
    scriptTag.id = scriptId;
    scriptTag.src = url;
    var handler = function() {
      scriptTag.removeEventListener("load", handler);
      callback();
    };
    scriptTag.addEventListener("load", handler);
    if (doc.head) {
      doc.head.appendChild(scriptTag);
    }
  };
  var load = function(doc, url, callback) {
    if (state.scriptLoaded) {
      callback();
    } else {
      state.listeners.push(callback);
      if (!doc.getElementById(state.scriptId)) {
        injectScriptTag(state.scriptId, doc, url, function() {
          state.listeners.forEach(function(fn) {
            return fn();
          });
          state.scriptLoaded = true;
        });
      }
    }
  };
  var reinitialize = function() {
    state = createState();
  };
  return {
    load,
    reinitialize
  };
};
var ScriptLoader = CreateScriptLoader();
var getGlobal = function() {
  return typeof window !== "undefined" ? window : global;
};
var getTinymce = function() {
  var global2 = getGlobal();
  return global2 && global2.tinymce ? global2.tinymce : null;
};
var editorProps = {
  apiKey: String,
  cloudChannel: String,
  id: String,
  init: Object,
  initialValue: String,
  inline: Boolean,
  modelEvents: [String, Array],
  plugins: [String, Array],
  tagName: String,
  toolbar: [String, Array],
  modelValue: String,
  disabled: Boolean,
  tinymceScriptSrc: String,
  outputFormat: {
    type: String,
    validator: function(prop) {
      return prop === "html" || prop === "text";
    }
  }
};
var __assign = globalThis && globalThis.__assign || function() {
  __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p in s)
        if (Object.prototype.hasOwnProperty.call(s, p))
          t[p] = s[p];
    }
    return t;
  };
  return __assign.apply(this, arguments);
};
var renderInline = function(ce, id, elementRef, tagName) {
  return ce(tagName ? tagName : "div", {
    id,
    ref: elementRef
  });
};
var renderIframe = function(ce, id, elementRef) {
  return ce("textarea", {
    id,
    visibility: "hidden",
    ref: elementRef
  });
};
var Editor = defineComponent({
  props: editorProps,
  setup: function(props, ctx) {
    var conf = props.init ? __assign({}, props.init) : {};
    var _a = toRefs(props), disabled = _a.disabled, modelValue = _a.modelValue, tagName = _a.tagName;
    var element = ref(null);
    var vueEditor = null;
    var elementId = props.id || uuid("tiny-vue");
    var inlineEditor = props.init && props.init.inline || props.inline;
    var modelBind = !!ctx.attrs["onUpdate:modelValue"];
    var mounting = true;
    var initialValue = props.initialValue ? props.initialValue : "";
    var cache = "";
    var getContent = function(isMounting) {
      return modelBind ? function() {
        return (modelValue === null || modelValue === void 0 ? void 0 : modelValue.value) ? modelValue.value : "";
      } : function() {
        return isMounting ? initialValue : cache;
      };
    };
    var initWrapper = function() {
      var content = getContent(mounting);
      var finalInit = __assign(__assign({}, conf), { readonly: props.disabled, selector: "#" + elementId, plugins: mergePlugins(conf.plugins, props.plugins), toolbar: props.toolbar || conf.toolbar, inline: inlineEditor, setup: function(editor) {
        vueEditor = editor;
        editor.on("init", function(e) {
          return initEditor(e, props, ctx, editor, modelValue, content);
        });
        if (typeof conf.setup === "function") {
          conf.setup(editor);
        }
      } });
      if (isTextarea(element.value)) {
        element.value.style.visibility = "";
      }
      getTinymce().init(finalInit);
      mounting = false;
    };
    watch(disabled, function(disable) {
      var _a2;
      if (vueEditor !== null) {
        if (typeof ((_a2 = vueEditor.mode) === null || _a2 === void 0 ? void 0 : _a2.set) === "function") {
          vueEditor.mode.set(disable ? "readonly" : "design");
        } else {
          vueEditor.setMode(disable ? "readonly" : "design");
        }
      }
    });
    watch(tagName, function(_) {
      var _a2;
      if (!modelBind) {
        cache = vueEditor.getContent();
      }
      (_a2 = getTinymce()) === null || _a2 === void 0 ? void 0 : _a2.remove(vueEditor);
      nextTick(function() {
        return initWrapper();
      });
    });
    onMounted(function() {
      if (getTinymce() !== null) {
        initWrapper();
      } else if (element.value && element.value.ownerDocument) {
        var channel = props.cloudChannel ? props.cloudChannel : "6";
        var apiKey = props.apiKey ? props.apiKey : "no-api-key";
        var scriptSrc = isNullOrUndefined(props.tinymceScriptSrc) ? "https://cdn.tiny.cloud/1/" + apiKey + "/tinymce/" + channel + "/tinymce.min.js" : props.tinymceScriptSrc;
        ScriptLoader.load(element.value.ownerDocument, scriptSrc, initWrapper);
      }
    });
    onBeforeUnmount(function() {
      if (getTinymce() !== null) {
        getTinymce().remove(vueEditor);
      }
    });
    if (!inlineEditor) {
      onActivated(function() {
        if (!mounting) {
          initWrapper();
        }
      });
      onDeactivated(function() {
        var _a2;
        if (!modelBind) {
          cache = vueEditor.getContent();
        }
        (_a2 = getTinymce()) === null || _a2 === void 0 ? void 0 : _a2.remove(vueEditor);
      });
    }
    var rerender = function(init) {
      var _a2;
      cache = vueEditor.getContent();
      (_a2 = getTinymce()) === null || _a2 === void 0 ? void 0 : _a2.remove(vueEditor);
      conf = __assign(__assign({}, conf), init);
      nextTick(function() {
        return initWrapper();
      });
    };
    ctx.expose({
      rerender
    });
    return function() {
      return inlineEditor ? renderInline(h, elementId, element, props.tagName) : renderIframe(h, elementId, element);
    };
  }
});
(function() {
  const getPrototypeOf = Object.getPrototypeOf;
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t2 = typeof x;
    if (x === null) {
      return "null";
    } else if (t2 === "object" && Array.isArray(x)) {
      return "array";
    } else if (t2 === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t2;
    }
  };
  const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
  const isSimpleType = (type2) => (value2) => typeof value2 === type2;
  const eq$1 = (t2) => (a) => t2 === a;
  const is$2 = (value2, constructor) => isObject(value2) && hasProto(value2, constructor, (o, proto) => getPrototypeOf(o) === proto);
  const isString = isType$1("string");
  const isObject = isType$1("object");
  const isPlainObject = (value2) => is$2(value2, Object);
  const isArray = isType$1("array");
  const isNull = eq$1(null);
  const isBoolean = isSimpleType("boolean");
  const isUndefined = eq$1(void 0);
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const isArrayOf = (value2, pred) => {
    if (isArray(value2)) {
      for (let i = 0, len = value2.length; i < len; ++i) {
        if (!pred(value2[i])) {
          return false;
        }
      }
      return true;
    }
    return false;
  };
  const noop = () => {
  };
  const noarg = (f) => () => f();
  const compose = (fa, fb) => {
    return (...args) => {
      return fa(fb.apply(null, args));
    };
  };
  const compose1 = (fbc, fab) => (a) => fbc(fab(a));
  const constant$1 = (value2) => {
    return () => {
      return value2;
    };
  };
  const identity = (x) => {
    return x;
  };
  const tripleEquals = (a, b2) => {
    return a === b2;
  };
  function curry(fn, ...initialArgs) {
    return (...restArgs) => {
      const all2 = initialArgs.concat(restArgs);
      return fn.apply(null, all2);
    };
  }
  const not = (f) => (t2) => !f(t2);
  const die = (msg) => {
    return () => {
      throw new Error(msg);
    };
  };
  const apply = (f) => {
    return f();
  };
  const never = constant$1(false);
  const always = constant$1(true);
  var global$a = tinymce.util.Tools.resolve("tinymce.ThemeManager");
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder2) {
      if (this.tag) {
        return binder2(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk2) {
      return this.tag ? this.value : thunk2();
    }
    orThunk(thunk2) {
      return this.tag ? this : thunk2();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativeSlice = Array.prototype.slice;
  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t2) => nativeIndexOf.call(ts, t2);
  const indexOf = (xs, x) => {
    const r2 = rawIndexOf(xs, x);
    return r2 === -1 ? Optional.none() : Optional.some(r2);
  };
  const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
  const exists = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return true;
      }
    }
    return false;
  };
  const range$2 = (num, f) => {
    const r2 = [];
    for (let i = 0; i < num; i++) {
      r2.push(f(i));
    }
    return r2;
  };
  const chunk$1 = (array, size) => {
    const r2 = [];
    for (let i = 0; i < array.length; i += size) {
      const s = nativeSlice.call(array, i, i + size);
      r2.push(s);
    }
    return r2;
  };
  const map$2 = (xs, f) => {
    const len = xs.length;
    const r2 = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r2[i] = f(x, i);
    }
    return r2;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const eachr = (xs, f) => {
    for (let i = xs.length - 1; i >= 0; i--) {
      const x = xs[i];
      f(x, i);
    }
  };
  const partition$3 = (xs, pred) => {
    const pass = [];
    const fail = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      const arr = pred(x, i) ? pass : fail;
      arr.push(x);
    }
    return {
      pass,
      fail
    };
  };
  const filter$2 = (xs, pred) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r2.push(x);
      }
    }
    return r2;
  };
  const foldr = (xs, f, acc) => {
    eachr(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const foldl = (xs, f, acc) => {
    each$1(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find$5 = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const findIndex$1 = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(i);
      }
    }
    return Optional.none();
  };
  const flatten = (xs) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r2, xs[i]);
    }
    return r2;
  };
  const bind$3 = (xs, f) => flatten(map$2(xs, f));
  const forall = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; ++i) {
      const x = xs[i];
      if (pred(x, i) !== true) {
        return false;
      }
    }
    return true;
  };
  const reverse = (xs) => {
    const r2 = nativeSlice.call(xs, 0);
    r2.reverse();
    return r2;
  };
  const difference = (a1, a2) => filter$2(a1, (x) => !contains$2(a2, x));
  const mapToObject = (xs, f) => {
    const r2 = {};
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      r2[String(x)] = f(x, i);
    }
    return r2;
  };
  const pure$2 = (x) => [x];
  const sort = (xs, comparator) => {
    const copy = nativeSlice.call(xs, 0);
    copy.sort(comparator);
    return copy;
  };
  const get$h = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get$h(xs, 0);
  const last$1 = (xs) => get$h(xs, xs.length - 1);
  const from = isFunction(Array.from) ? Array.from : (x) => nativeSlice.call(x);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r2 = f(arr[i], i);
      if (r2.isSome()) {
        return r2;
      }
    }
    return Optional.none();
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const map$1 = (obj, f) => {
    return tupleMap(obj, (x, i) => ({
      k: i,
      v: f(x, i)
    }));
  };
  const tupleMap = (obj, f) => {
    const r2 = {};
    each(obj, (x, i) => {
      const tuple = f(x, i);
      r2[tuple.k] = tuple.v;
    });
    return r2;
  };
  const objAcc = (r2) => (x, i) => {
    r2[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r2 = {};
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r2;
  };
  const bifilter = (obj, pred) => {
    const t2 = {};
    const f = {};
    internalFilter(obj, pred, objAcc(t2), objAcc(f));
    return {
      t: t2,
      f
    };
  };
  const filter$1 = (obj, pred) => {
    const t2 = {};
    internalFilter(obj, pred, objAcc(t2), noop);
    return t2;
  };
  const mapToArray = (obj, f) => {
    const r2 = [];
    each(obj, (value2, name2) => {
      r2.push(f(value2, name2));
    });
    return r2;
  };
  const find$4 = (obj, pred) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      if (pred(x, i, obj)) {
        return Optional.some(x);
      }
    }
    return Optional.none();
  };
  const values = (obj) => {
    return mapToArray(obj, identity);
  };
  const get$g = (obj, key) => {
    return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
  };
  const has$2 = (obj, key) => hasOwnProperty.call(obj, key);
  const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== void 0 && obj[key] !== null;
  const is$1 = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left2) => comparator(left2, rhs));
  const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
  const cat = (arr) => {
    const r2 = [];
    const push = (x) => {
      r2.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r2;
  };
  const sequence = (arr) => {
    const r2 = [];
    for (let i = 0; i < arr.length; i++) {
      const x = arr[i];
      if (x.isSome()) {
        r2.push(x.getOrDie());
      } else {
        return Optional.none();
      }
    }
    return Optional.some(r2);
  };
  const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
  const mapFrom = (a, f) => a !== void 0 && a !== null ? Optional.some(f(a)) : Optional.none();
  const someIf = (b2, a) => b2 ? Optional.some(a) : Optional.none();
  const addToEnd = (str, suffix2) => {
    return str + suffix2;
  };
  const removeFromStart = (str, numChars) => {
    return str.substring(numChars);
  };
  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const removeLeading = (str, prefix2) => {
    return startsWith(str, prefix2) ? removeFromStart(str, prefix2.length) : str;
  };
  const ensureTrailing = (str, suffix2) => {
    return endsWith(str, suffix2) ? str : addToEnd(str, suffix2);
  };
  const contains$1 = (str, substr) => {
    return str.indexOf(substr) !== -1;
  };
  const startsWith = (str, prefix2) => {
    return checkRange(str, prefix2, 0);
  };
  const endsWith = (str, suffix2) => {
    return checkRange(str, suffix2, str.length - suffix2.length);
  };
  const blank = (r2) => (s) => s.replace(r2, "");
  const trim$1 = blank(/^\s+|\s+$/g);
  const isNotEmpty = (s) => s.length > 0;
  const isEmpty = (s) => !isNotEmpty(s);
  const isSupported$1 = (dom2) => dom2.style !== void 0 && isFunction(dom2.style.getPropertyValue);
  const fromHtml$2 = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text2, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text2);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml: fromHtml$2,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const DOCUMENT = 9;
  const DOCUMENT_FRAGMENT = 11;
  const ELEMENT = 1;
  const TEXT = 3;
  const name$3 = (element2) => {
    const r2 = element2.dom.nodeName;
    return r2.toLowerCase();
  };
  const type$1 = (element2) => element2.dom.nodeType;
  const isType = (t2) => (element2) => type$1(element2) === t2;
  const isElement$1 = isType(ELEMENT);
  const isText = isType(TEXT);
  const isDocument = isType(DOCUMENT);
  const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  const isTag = (tag) => (e) => isElement$1(e) && name$3(e) === tag;
  const is = (element2, selector) => {
    const dom2 = element2.dom;
    if (dom2.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom2;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  const bypassSelector = (dom2) => dom2.nodeType !== ELEMENT && dom2.nodeType !== DOCUMENT && dom2.nodeType !== DOCUMENT_FRAGMENT || dom2.childElementCount === 0;
  const all$3 = (selector, scope) => {
    const base2 = scope === void 0 ? document : scope.dom;
    return bypassSelector(base2) ? [] : map$2(base2.querySelectorAll(selector), SugarElement.fromDom);
  };
  const one = (selector, scope) => {
    const base2 = scope === void 0 ? document : scope.dom;
    return bypassSelector(base2) ? Optional.none() : Optional.from(base2.querySelector(selector)).map(SugarElement.fromDom);
  };
  const eq = (e1, e2) => e1.dom === e2.dom;
  const contains = (e1, e2) => {
    const d1 = e1.dom;
    const d2 = e2.dom;
    return d1 === d2 ? false : d1.contains(d2);
  };
  const owner$4 = (element2) => SugarElement.fromDom(element2.dom.ownerDocument);
  const documentOrOwner = (dos) => isDocument(dos) ? dos : owner$4(dos);
  const documentElement = (element2) => SugarElement.fromDom(documentOrOwner(element2).dom.documentElement);
  const defaultView = (element2) => SugarElement.fromDom(documentOrOwner(element2).dom.defaultView);
  const parent = (element2) => Optional.from(element2.dom.parentNode).map(SugarElement.fromDom);
  const parentElement = (element2) => Optional.from(element2.dom.parentElement).map(SugarElement.fromDom);
  const offsetParent = (element2) => Optional.from(element2.dom.offsetParent).map(SugarElement.fromDom);
  const nextSibling = (element2) => Optional.from(element2.dom.nextSibling).map(SugarElement.fromDom);
  const children = (element2) => map$2(element2.dom.childNodes, SugarElement.fromDom);
  const child$2 = (element2, index2) => {
    const cs = element2.dom.childNodes;
    return Optional.from(cs[index2]).map(SugarElement.fromDom);
  };
  const firstChild = (element2) => child$2(element2, 0);
  const spot = (element2, offset2) => ({
    element: element2,
    offset: offset2
  });
  const leaf = (element2, offset2) => {
    const cs = children(element2);
    return cs.length > 0 && offset2 < cs.length ? spot(cs[offset2], 0) : spot(element2, offset2);
  };
  const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  const isSupported = constant$1(supported);
  const getRootNode = supported ? (e) => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  const getContentContainer = (dos) => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
  const isInShadowRoot = (e) => getShadowRoot(e).isSome();
  const getShadowRoot = (e) => {
    const r2 = getRootNode(e);
    return isShadowRoot(r2) ? Optional.some(r2) : Optional.none();
  };
  const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
  const getOriginalEventTarget = (event) => {
    if (isSupported() && isNonNullable(event.target)) {
      const el = SugarElement.fromDom(event.target);
      if (isElement$1(el) && isOpenShadowHost(el)) {
        if (event.composed && event.composedPath) {
          const composedPath = event.composedPath();
          if (composedPath) {
            return head(composedPath);
          }
        }
      }
    }
    return Optional.from(event.target);
  };
  const isOpenShadowHost = (element2) => isNonNullable(element2.dom.shadowRoot);
  const inBody = (element2) => {
    const dom2 = isText(element2) ? element2.dom.parentNode : element2.dom;
    if (dom2 === void 0 || dom2 === null || dom2.ownerDocument === null) {
      return false;
    }
    const doc = dom2.ownerDocument;
    return getShadowRoot(SugarElement.fromDom(dom2)).fold(() => doc.body.contains(dom2), compose1(inBody, getShadowHost));
  };
  const body = () => getBody(SugarElement.fromDom(document));
  const getBody = (doc) => {
    const b2 = doc.dom.body;
    if (b2 === null || b2 === void 0) {
      throw new Error("Body is not available yet");
    }
    return SugarElement.fromDom(b2);
  };
  const rawSet = (dom2, key, value2) => {
    if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
      dom2.setAttribute(key, value2 + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value2, ":: Element ", dom2);
      throw new Error("Attribute value was not simple");
    }
  };
  const set$9 = (element2, key, value2) => {
    rawSet(element2.dom, key, value2);
  };
  const setAll$1 = (element2, attrs) => {
    const dom2 = element2.dom;
    each(attrs, (v, k) => {
      rawSet(dom2, k, v);
    });
  };
  const get$f = (element2, key) => {
    const v = element2.dom.getAttribute(key);
    return v === null ? void 0 : v;
  };
  const getOpt = (element2, key) => Optional.from(get$f(element2, key));
  const has$1 = (element2, key) => {
    const dom2 = element2.dom;
    return dom2 && dom2.hasAttribute ? dom2.hasAttribute(key) : false;
  };
  const remove$7 = (element2, key) => {
    element2.dom.removeAttribute(key);
  };
  const clone$1 = (element2) => foldl(element2.dom.attributes, (acc, attr) => {
    acc[attr.name] = attr.value;
    return acc;
  }, {});
  const internalSet = (dom2, property, value2) => {
    if (!isString(value2)) {
      console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value2, ":: Element ", dom2);
      throw new Error("CSS value must be a string: " + value2);
    }
    if (isSupported$1(dom2)) {
      dom2.style.setProperty(property, value2);
    }
  };
  const internalRemove = (dom2, property) => {
    if (isSupported$1(dom2)) {
      dom2.style.removeProperty(property);
    }
  };
  const set$8 = (element2, property, value2) => {
    const dom2 = element2.dom;
    internalSet(dom2, property, value2);
  };
  const setAll = (element2, css) => {
    const dom2 = element2.dom;
    each(css, (v, k) => {
      internalSet(dom2, k, v);
    });
  };
  const setOptions = (element2, css) => {
    const dom2 = element2.dom;
    each(css, (v, k) => {
      v.fold(() => {
        internalRemove(dom2, k);
      }, (value2) => {
        internalSet(dom2, k, value2);
      });
    });
  };
  const get$e = (element2, property) => {
    const dom2 = element2.dom;
    const styles = window.getComputedStyle(dom2);
    const r2 = styles.getPropertyValue(property);
    return r2 === "" && !inBody(element2) ? getUnsafeProperty(dom2, property) : r2;
  };
  const getUnsafeProperty = (dom2, property) => isSupported$1(dom2) ? dom2.style.getPropertyValue(property) : "";
  const getRaw = (element2, property) => {
    const dom2 = element2.dom;
    const raw = getUnsafeProperty(dom2, property);
    return Optional.from(raw).filter((r2) => r2.length > 0);
  };
  const getAllRaw = (element2) => {
    const css = {};
    const dom2 = element2.dom;
    if (isSupported$1(dom2)) {
      for (let i = 0; i < dom2.style.length; i++) {
        const ruleName = dom2.style.item(i);
        css[ruleName] = dom2.style[ruleName];
      }
    }
    return css;
  };
  const isValidValue = (tag, property, value2) => {
    const element2 = SugarElement.fromTag(tag);
    set$8(element2, property, value2);
    const style = getRaw(element2, property);
    return style.isSome();
  };
  const remove$6 = (element2, property) => {
    const dom2 = element2.dom;
    internalRemove(dom2, property);
    if (is$1(getOpt(element2, "style").map(trim$1), "")) {
      remove$7(element2, "style");
    }
  };
  const reflow = (e) => e.dom.offsetWidth;
  const Dimension = (name2, getOffset2) => {
    const set2 = (element2, h2) => {
      if (!isNumber(h2) && !h2.match(/^[0-9]+$/)) {
        throw new Error(name2 + ".set accepts only positive integer values. Value was " + h2);
      }
      const dom2 = element2.dom;
      if (isSupported$1(dom2)) {
        dom2.style[name2] = h2 + "px";
      }
    };
    const get2 = (element2) => {
      const r2 = getOffset2(element2);
      if (r2 <= 0 || r2 === null) {
        const css = get$e(element2, name2);
        return parseFloat(css) || 0;
      }
      return r2;
    };
    const getOuter2 = get2;
    const aggregate = (element2, properties2) => foldl(properties2, (acc, property) => {
      const val = get$e(element2, property);
      const value2 = val === void 0 ? 0 : parseInt(val, 10);
      return isNaN(value2) ? acc : acc + value2;
    }, 0);
    const max2 = (element2, value2, properties2) => {
      const cumulativeInclusions = aggregate(element2, properties2);
      const absoluteMax = value2 > cumulativeInclusions ? value2 - cumulativeInclusions : 0;
      return absoluteMax;
    };
    return {
      set: set2,
      get: get2,
      getOuter: getOuter2,
      aggregate,
      max: max2
    };
  };
  const api$2 = Dimension("height", (element2) => {
    const dom2 = element2.dom;
    return inBody(element2) ? dom2.getBoundingClientRect().height : dom2.offsetHeight;
  });
  const get$d = (element2) => api$2.get(element2);
  const getOuter$2 = (element2) => api$2.getOuter(element2);
  const setMax$1 = (element2, value2) => {
    const inclusions = [
      "margin-top",
      "border-top-width",
      "padding-top",
      "padding-bottom",
      "border-bottom-width",
      "margin-bottom"
    ];
    const absMax = api$2.max(element2, value2, inclusions);
    set$8(element2, "max-height", absMax + "px");
  };
  const r$1 = (left2, top2) => {
    const translate2 = (x, y) => r$1(left2 + x, top2 + y);
    return {
      left: left2,
      top: top2,
      translate: translate2
    };
  };
  const SugarPosition = r$1;
  const boxPosition = (dom2) => {
    const box2 = dom2.getBoundingClientRect();
    return SugarPosition(box2.left, box2.top);
  };
  const firstDefinedOrZero = (a, b2) => {
    if (a !== void 0) {
      return a;
    } else {
      return b2 !== void 0 ? b2 : 0;
    }
  };
  const absolute$3 = (element2) => {
    const doc = element2.dom.ownerDocument;
    const body2 = doc.body;
    const win2 = doc.defaultView;
    const html = doc.documentElement;
    if (body2 === element2.dom) {
      return SugarPosition(body2.offsetLeft, body2.offsetTop);
    }
    const scrollTop = firstDefinedOrZero(win2 === null || win2 === void 0 ? void 0 : win2.pageYOffset, html.scrollTop);
    const scrollLeft = firstDefinedOrZero(win2 === null || win2 === void 0 ? void 0 : win2.pageXOffset, html.scrollLeft);
    const clientTop = firstDefinedOrZero(html.clientTop, body2.clientTop);
    const clientLeft = firstDefinedOrZero(html.clientLeft, body2.clientLeft);
    return viewport$1(element2).translate(scrollLeft - clientLeft, scrollTop - clientTop);
  };
  const viewport$1 = (element2) => {
    const dom2 = element2.dom;
    const doc = dom2.ownerDocument;
    const body2 = doc.body;
    if (body2 === dom2) {
      return SugarPosition(body2.offsetLeft, body2.offsetTop);
    }
    if (!inBody(element2)) {
      return SugarPosition(0, 0);
    }
    return boxPosition(dom2);
  };
  const api$1 = Dimension("width", (element2) => element2.dom.offsetWidth);
  const set$7 = (element2, h2) => api$1.set(element2, h2);
  const get$c = (element2) => api$1.get(element2);
  const getOuter$1 = (element2) => api$1.getOuter(element2);
  const setMax = (element2, value2) => {
    const inclusions = [
      "margin-left",
      "border-left-width",
      "padding-left",
      "padding-right",
      "border-right-width",
      "margin-right"
    ];
    const absMax = api$1.max(element2, value2, inclusions);
    set$8(element2, "max-width", absMax + "px");
  };
  const cached = (f) => {
    let called = false;
    let r2;
    return (...args) => {
      if (!called) {
        called = true;
        r2 = f.apply(null, args);
      }
      return r2;
    };
  };
  const DeviceType = (os, browser, userAgent, mediaMatch2) => {
    const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
    const isiPhone = os.isiOS() && !isiPad;
    const isMobile = os.isiOS() || os.isAndroid();
    const isTouch2 = isMobile || mediaMatch2("(pointer:coarse)");
    const isTablet = isiPad || !isiPhone && isMobile && mediaMatch2("(min-device-width:768px)");
    const isPhone = isiPhone || isMobile && !isTablet;
    const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
    const isDesktop = !isPhone && !isTablet && !iOSwebview;
    return {
      isiPad: constant$1(isiPad),
      isiPhone: constant$1(isiPhone),
      isTablet: constant$1(isTablet),
      isPhone: constant$1(isPhone),
      isTouch: constant$1(isTouch2),
      isAndroid: os.isAndroid,
      isiOS: os.isiOS,
      isWebView: constant$1(iOSwebview),
      isDesktop: constant$1(isDesktop)
    };
  };
  const firstMatch = (regexes, s) => {
    for (let i = 0; i < regexes.length; i++) {
      const x = regexes[i];
      if (x.test(s)) {
        return x;
      }
    }
    return void 0;
  };
  const find$3 = (regexes, agent) => {
    const r2 = firstMatch(regexes, agent);
    if (!r2) {
      return {
        major: 0,
        minor: 0
      };
    }
    const group2 = (i) => {
      return Number(agent.replace(r2, "$" + i));
    };
    return nu$d(group2(1), group2(2));
  };
  const detect$4 = (versionRegexes, agent) => {
    const cleanedAgent = String(agent).toLowerCase();
    if (versionRegexes.length === 0) {
      return unknown$3();
    }
    return find$3(versionRegexes, cleanedAgent);
  };
  const unknown$3 = () => {
    return nu$d(0, 0);
  };
  const nu$d = (major, minor) => {
    return {
      major,
      minor
    };
  };
  const Version = {
    nu: nu$d,
    detect: detect$4,
    unknown: unknown$3
  };
  const detectBrowser$1 = (browsers2, userAgentData) => {
    return findMap(userAgentData.brands, (uaBrand) => {
      const lcBrand = uaBrand.brand.toLowerCase();
      return find$5(browsers2, (browser) => {
        var _a;
        return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
      }).map((info) => ({
        current: info.name,
        version: Version.nu(parseInt(uaBrand.version, 10), 0)
      }));
    });
  };
  const detect$3 = (candidates, userAgent) => {
    const agent = String(userAgent).toLowerCase();
    return find$5(candidates, (candidate) => {
      return candidate.search(agent);
    });
  };
  const detectBrowser = (browsers2, userAgent) => {
    return detect$3(browsers2, userAgent).map((browser) => {
      const version = Version.detect(browser.versionRegexes, userAgent);
      return {
        current: browser.name,
        version
      };
    });
  };
  const detectOs = (oses2, userAgent) => {
    return detect$3(oses2, userAgent).map((os) => {
      const version = Version.detect(os.versionRegexes, userAgent);
      return {
        current: os.name,
        version
      };
    });
  };
  const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  const checkContains = (target) => {
    return (uastring) => {
      return contains$1(uastring, target);
    };
  };
  const browsers = [
    {
      name: "Edge",
      versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
      search: (uastring) => {
        return contains$1(uastring, "edge/") && contains$1(uastring, "chrome") && contains$1(uastring, "safari") && contains$1(uastring, "applewebkit");
      }
    },
    {
      name: "Chromium",
      brand: "Chromium",
      versionRegexes: [
        /.*?chrome\/([0-9]+)\.([0-9]+).*/,
        normalVersionRegex
      ],
      search: (uastring) => {
        return contains$1(uastring, "chrome") && !contains$1(uastring, "chromeframe");
      }
    },
    {
      name: "IE",
      versionRegexes: [
        /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
        /.*?rv:([0-9]+)\.([0-9]+).*/
      ],
      search: (uastring) => {
        return contains$1(uastring, "msie") || contains$1(uastring, "trident");
      }
    },
    {
      name: "Opera",
      versionRegexes: [
        normalVersionRegex,
        /.*?opera\/([0-9]+)\.([0-9]+).*/
      ],
      search: checkContains("opera")
    },
    {
      name: "Firefox",
      versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
      search: checkContains("firefox")
    },
    {
      name: "Safari",
      versionRegexes: [
        normalVersionRegex,
        /.*?cpu os ([0-9]+)_([0-9]+).*/
      ],
      search: (uastring) => {
        return (contains$1(uastring, "safari") || contains$1(uastring, "mobile/")) && contains$1(uastring, "applewebkit");
      }
    }
  ];
  const oses = [
    {
      name: "Windows",
      search: checkContains("win"),
      versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "iOS",
      search: (uastring) => {
        return contains$1(uastring, "iphone") || contains$1(uastring, "ipad");
      },
      versionRegexes: [
        /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
        /.*cpu os ([0-9]+)_([0-9]+).*/,
        /.*cpu iphone os ([0-9]+)_([0-9]+).*/
      ]
    },
    {
      name: "Android",
      search: checkContains("android"),
      versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "macOS",
      search: checkContains("mac os x"),
      versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
    },
    {
      name: "Linux",
      search: checkContains("linux"),
      versionRegexes: []
    },
    {
      name: "Solaris",
      search: checkContains("sunos"),
      versionRegexes: []
    },
    {
      name: "FreeBSD",
      search: checkContains("freebsd"),
      versionRegexes: []
    },
    {
      name: "ChromeOS",
      search: checkContains("cros"),
      versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
    }
  ];
  const PlatformInfo = {
    browsers: constant$1(browsers),
    oses: constant$1(oses)
  };
  const edge = "Edge";
  const chromium = "Chromium";
  const ie = "IE";
  const opera = "Opera";
  const firefox = "Firefox";
  const safari = "Safari";
  const unknown$2 = () => {
    return nu$c({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu$c = (info) => {
    const current = info.current;
    const version = info.version;
    const isBrowser = (name2) => () => current === name2;
    return {
      current,
      version,
      isEdge: isBrowser(edge),
      isChromium: isBrowser(chromium),
      isIE: isBrowser(ie),
      isOpera: isBrowser(opera),
      isFirefox: isBrowser(firefox),
      isSafari: isBrowser(safari)
    };
  };
  const Browser = {
    unknown: unknown$2,
    nu: nu$c,
    edge: constant$1(edge),
    chromium: constant$1(chromium),
    ie: constant$1(ie),
    opera: constant$1(opera),
    firefox: constant$1(firefox),
    safari: constant$1(safari)
  };
  const windows = "Windows";
  const ios = "iOS";
  const android = "Android";
  const linux = "Linux";
  const macos = "macOS";
  const solaris = "Solaris";
  const freebsd = "FreeBSD";
  const chromeos = "ChromeOS";
  const unknown$1 = () => {
    return nu$b({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu$b = (info) => {
    const current = info.current;
    const version = info.version;
    const isOS = (name2) => () => current === name2;
    return {
      current,
      version,
      isWindows: isOS(windows),
      isiOS: isOS(ios),
      isAndroid: isOS(android),
      isMacOS: isOS(macos),
      isLinux: isOS(linux),
      isSolaris: isOS(solaris),
      isFreeBSD: isOS(freebsd),
      isChromeOS: isOS(chromeos)
    };
  };
  const OperatingSystem = {
    unknown: unknown$1,
    nu: nu$b,
    windows: constant$1(windows),
    ios: constant$1(ios),
    android: constant$1(android),
    linux: constant$1(linux),
    macos: constant$1(macos),
    solaris: constant$1(solaris),
    freebsd: constant$1(freebsd),
    chromeos: constant$1(chromeos)
  };
  const detect$2 = (userAgent, userAgentDataOpt, mediaMatch2) => {
    const browsers2 = PlatformInfo.browsers();
    const oses2 = PlatformInfo.oses();
    const browser = userAgentDataOpt.bind((userAgentData) => detectBrowser$1(browsers2, userAgentData)).orThunk(() => detectBrowser(browsers2, userAgent)).fold(Browser.unknown, Browser.nu);
    const os = detectOs(oses2, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
    const deviceType = DeviceType(os, browser, userAgent, mediaMatch2);
    return {
      browser,
      os,
      deviceType
    };
  };
  const PlatformDetection = { detect: detect$2 };
  const mediaMatch = (query2) => window.matchMedia(query2).matches;
  let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  const detect$1 = () => platform();
  const mkEvent = (target, x, y, stop2, prevent, kill, raw) => ({
    target,
    x,
    y,
    stop: stop2,
    prevent,
    kill,
    raw
  });
  const fromRawEvent$1 = (rawEvent) => {
    const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
    const stop2 = () => rawEvent.stopPropagation();
    const prevent = () => rawEvent.preventDefault();
    const kill = compose(prevent, stop2);
    return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop2, prevent, kill, rawEvent);
  };
  const handle = (filter2, handler) => (rawEvent) => {
    if (filter2(rawEvent)) {
      handler(fromRawEvent$1(rawEvent));
    }
  };
  const binder = (element2, event, filter2, handler, useCapture) => {
    const wrapped = handle(filter2, handler);
    element2.dom.addEventListener(event, wrapped, useCapture);
    return { unbind: curry(unbind, element2, event, wrapped, useCapture) };
  };
  const bind$2 = (element2, event, filter2, handler) => binder(element2, event, filter2, handler, false);
  const capture$1 = (element2, event, filter2, handler) => binder(element2, event, filter2, handler, true);
  const unbind = (element2, event, handler, useCapture) => {
    element2.dom.removeEventListener(event, handler, useCapture);
  };
  const before$1 = (marker, element2) => {
    const parent$1 = parent(marker);
    parent$1.each((v) => {
      v.dom.insertBefore(element2.dom, marker.dom);
    });
  };
  const after$2 = (marker, element2) => {
    const sibling = nextSibling(marker);
    sibling.fold(() => {
      const parent$1 = parent(marker);
      parent$1.each((v) => {
        append$2(v, element2);
      });
    }, (v) => {
      before$1(v, element2);
    });
  };
  const prepend$1 = (parent2, element2) => {
    const firstChild$1 = firstChild(parent2);
    firstChild$1.fold(() => {
      append$2(parent2, element2);
    }, (v) => {
      parent2.dom.insertBefore(element2.dom, v.dom);
    });
  };
  const append$2 = (parent2, element2) => {
    parent2.dom.appendChild(element2.dom);
  };
  const appendAt = (parent2, element2, index2) => {
    child$2(parent2, index2).fold(() => {
      append$2(parent2, element2);
    }, (v) => {
      before$1(v, element2);
    });
  };
  const append$1 = (parent2, elements) => {
    each$1(elements, (x) => {
      append$2(parent2, x);
    });
  };
  const empty = (element2) => {
    element2.dom.textContent = "";
    each$1(children(element2), (rogue) => {
      remove$5(rogue);
    });
  };
  const remove$5 = (element2) => {
    const dom2 = element2.dom;
    if (dom2.parentNode !== null) {
      dom2.parentNode.removeChild(dom2);
    }
  };
  const get$b = (_DOC) => {
    const doc = _DOC !== void 0 ? _DOC.dom : document;
    const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
    const y = doc.body.scrollTop || doc.documentElement.scrollTop;
    return SugarPosition(x, y);
  };
  const to = (x, y, _DOC) => {
    const doc = _DOC !== void 0 ? _DOC.dom : document;
    const win2 = doc.defaultView;
    if (win2) {
      win2.scrollTo(x, y);
    }
  };
  const get$a = (_win) => {
    const win2 = _win === void 0 ? window : _win;
    if (detect$1().browser.isFirefox()) {
      return Optional.none();
    } else {
      return Optional.from(win2.visualViewport);
    }
  };
  const bounds$1 = (x, y, width2, height2) => ({
    x,
    y,
    width: width2,
    height: height2,
    right: x + width2,
    bottom: y + height2
  });
  const getBounds$3 = (_win) => {
    const win2 = _win === void 0 ? window : _win;
    const doc = win2.document;
    const scroll = get$b(SugarElement.fromDom(doc));
    return get$a(win2).fold(() => {
      const html = win2.document.documentElement;
      const width2 = html.clientWidth;
      const height2 = html.clientHeight;
      return bounds$1(scroll.left, scroll.top, width2, height2);
    }, (visualViewport) => bounds$1(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  };
  const getDocument = () => SugarElement.fromDom(document);
  const walkUp = (navigation, doc) => {
    const frame = navigation.view(doc);
    return frame.fold(constant$1([]), (f) => {
      const parent2 = navigation.owner(f);
      const rest = walkUp(navigation, parent2);
      return [f].concat(rest);
    });
  };
  const pathTo = (element2, navigation) => {
    const d = navigation.owner(element2);
    const paths = walkUp(navigation, d);
    return Optional.some(paths);
  };
  const view = (doc) => {
    var _a;
    const element2 = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
    return element2.map(SugarElement.fromDom);
  };
  const owner$3 = (element2) => owner$4(element2);
  var Navigation = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    view,
    owner: owner$3
  });
  const find$2 = (element2) => {
    const doc = getDocument();
    const scroll = get$b(doc);
    const path2 = pathTo(element2, Navigation);
    return path2.fold(curry(absolute$3, element2), (frames) => {
      const offset2 = viewport$1(element2);
      const r2 = foldr(frames, (b2, a) => {
        const loc = viewport$1(a);
        return {
          left: b2.left + loc.left,
          top: b2.top + loc.top
        };
      }, {
        left: 0,
        top: 0
      });
      return SugarPosition(r2.left + offset2.left + scroll.left, r2.top + offset2.top + scroll.top);
    });
  };
  const pointed = (point2, width2, height2) => ({
    point: point2,
    width: width2,
    height: height2
  });
  const rect = (x, y, width2, height2) => ({
    x,
    y,
    width: width2,
    height: height2
  });
  const bounds = (x, y, width2, height2) => ({
    x,
    y,
    width: width2,
    height: height2,
    right: x + width2,
    bottom: y + height2
  });
  const box$1 = (element2) => {
    const xy = absolute$3(element2);
    const w = getOuter$1(element2);
    const h2 = getOuter$2(element2);
    return bounds(xy.left, xy.top, w, h2);
  };
  const absolute$2 = (element2) => {
    const position2 = find$2(element2);
    const width2 = getOuter$1(element2);
    const height2 = getOuter$2(element2);
    return bounds(position2.left, position2.top, width2, height2);
  };
  const win = () => getBounds$3(window);
  const value$4 = (value2) => {
    const applyHelper = (fn) => fn(value2);
    const constHelper = constant$1(value2);
    const outputHelper = () => output2;
    const output2 = {
      tag: true,
      inner: value2,
      fold: (_onError, onValue) => onValue(value2),
      isValue: always,
      isError: never,
      map: (mapper) => Result.value(mapper(value2)),
      mapError: outputHelper,
      bind: applyHelper,
      exists: applyHelper,
      forall: applyHelper,
      getOr: constHelper,
      or: outputHelper,
      getOrThunk: constHelper,
      orThunk: outputHelper,
      getOrDie: constHelper,
      each: (fn) => {
        fn(value2);
      },
      toOptional: () => Optional.some(value2)
    };
    return output2;
  };
  const error$1 = (error2) => {
    const outputHelper = () => output2;
    const output2 = {
      tag: false,
      inner: error2,
      fold: (onError, _onValue) => onError(error2),
      isValue: never,
      isError: always,
      map: outputHelper,
      mapError: (mapper) => Result.error(mapper(error2)),
      bind: outputHelper,
      exists: never,
      forall: always,
      getOr: identity,
      or: identity,
      getOrThunk: apply,
      orThunk: apply,
      getOrDie: die(String(error2)),
      each: noop,
      toOptional: Optional.none
    };
    return output2;
  };
  const fromOption = (optional2, err) => optional2.fold(() => error$1(err), value$4);
  const Result = {
    value: value$4,
    error: error$1,
    fromOption
  };
  var SimpleResultType;
  (function(SimpleResultType2) {
    SimpleResultType2[SimpleResultType2["Error"] = 0] = "Error";
    SimpleResultType2[SimpleResultType2["Value"] = 1] = "Value";
  })(SimpleResultType || (SimpleResultType = {}));
  const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
  const partition$2 = (results) => {
    const values2 = [];
    const errors = [];
    each$1(results, (obj) => {
      fold$1(obj, (err) => errors.push(err), (val) => values2.push(val));
    });
    return {
      values: values2,
      errors
    };
  };
  const mapError = (res, f) => {
    if (res.stype === SimpleResultType.Error) {
      return {
        stype: SimpleResultType.Error,
        serror: f(res.serror)
      };
    } else {
      return res;
    }
  };
  const map = (res, f) => {
    if (res.stype === SimpleResultType.Value) {
      return {
        stype: SimpleResultType.Value,
        svalue: f(res.svalue)
      };
    } else {
      return res;
    }
  };
  const bind$1 = (res, f) => {
    if (res.stype === SimpleResultType.Value) {
      return f(res.svalue);
    } else {
      return res;
    }
  };
  const bindError = (res, f) => {
    if (res.stype === SimpleResultType.Error) {
      return f(res.serror);
    } else {
      return res;
    }
  };
  const svalue = (v) => ({
    stype: SimpleResultType.Value,
    svalue: v
  });
  const serror = (e) => ({
    stype: SimpleResultType.Error,
    serror: e
  });
  const toResult$1 = (res) => fold$1(res, Result.error, Result.value);
  const fromResult$1 = (res) => res.fold(serror, svalue);
  const SimpleResult = {
    fromResult: fromResult$1,
    toResult: toResult$1,
    svalue,
    partition: partition$2,
    serror,
    bind: bind$1,
    bindError,
    map,
    mapError,
    fold: fold$1
  };
  const field$2 = (key, newKey, presence, prop) => ({
    tag: "field",
    key,
    newKey,
    presence,
    prop
  });
  const customField$1 = (newKey, instantiator) => ({
    tag: "custom",
    newKey,
    instantiator
  });
  const fold = (value2, ifField, ifCustom) => {
    switch (value2.tag) {
      case "field":
        return ifField(value2.key, value2.newKey, value2.presence, value2.prop);
      case "custom":
        return ifCustom(value2.newKey, value2.instantiator);
    }
  };
  const shallow$1 = (old, nu2) => {
    return nu2;
  };
  const deep = (old, nu2) => {
    const bothObjects = isPlainObject(old) && isPlainObject(nu2);
    return bothObjects ? deepMerge(old, nu2) : nu2;
  };
  const baseMerge = (merger) => {
    return (...objects) => {
      if (objects.length === 0) {
        throw new Error(`Can't merge zero objects`);
      }
      const ret = {};
      for (let j = 0; j < objects.length; j++) {
        const curObject = objects[j];
        for (const key in curObject) {
          if (has$2(curObject, key)) {
            ret[key] = merger(ret[key], curObject[key]);
          }
        }
      }
      return ret;
    };
  };
  const deepMerge = baseMerge(deep);
  const merge$1 = baseMerge(shallow$1);
  const required$2 = () => ({
    tag: "required",
    process: {}
  });
  const defaultedThunk = (fallbackThunk) => ({
    tag: "defaultedThunk",
    process: fallbackThunk
  });
  const defaulted$1 = (fallback2) => defaultedThunk(constant$1(fallback2));
  const asOption = () => ({
    tag: "option",
    process: {}
  });
  const mergeWithThunk = (baseThunk) => ({
    tag: "mergeWithThunk",
    process: baseThunk
  });
  const mergeWith = (base2) => mergeWithThunk(constant$1(base2));
  const mergeValues$1 = (values2, base2) => values2.length > 0 ? SimpleResult.svalue(deepMerge(base2, merge$1.apply(void 0, values2))) : SimpleResult.svalue(base2);
  const mergeErrors$1 = (errors) => compose(SimpleResult.serror, flatten)(errors);
  const consolidateObj = (objects, base2) => {
    const partition2 = SimpleResult.partition(objects);
    return partition2.errors.length > 0 ? mergeErrors$1(partition2.errors) : mergeValues$1(partition2.values, base2);
  };
  const consolidateArr = (objects) => {
    const partitions = SimpleResult.partition(objects);
    return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values);
  };
  const ResultCombine = {
    consolidateObj,
    consolidateArr
  };
  const formatObj = (input2) => {
    return isObject(input2) && keys(input2).length > 100 ? " removed due to size" : JSON.stringify(input2, null, 2);
  };
  const formatErrors = (errors) => {
    const es = errors.length > 10 ? errors.slice(0, 10).concat([{
      path: [],
      getErrorInfo: constant$1("... (only showing first ten failures)")
    }]) : errors;
    return map$2(es, (e) => {
      return "Failed path: (" + e.path.join(" > ") + ")\n" + e.getErrorInfo();
    });
  };
  const nu$a = (path2, getErrorInfo) => {
    return SimpleResult.serror([{
      path: path2,
      getErrorInfo
    }]);
  };
  const missingRequired = (path2, key, obj) => nu$a(path2, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
  const missingKey = (path2, key) => nu$a(path2, () => 'Choice schema did not contain choice key: "' + key + '"');
  const missingBranch = (path2, branches, branch) => nu$a(path2, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
  const unsupportedFields = (path2, unsupported) => nu$a(path2, () => "There are unsupported fields: [" + unsupported.join(", ") + "] specified");
  const custom = (path2, err) => nu$a(path2, constant$1(err));
  const value$3 = (validator) => {
    const extract2 = (path2, val) => {
      return SimpleResult.bindError(validator(val), (err) => custom(path2, err));
    };
    const toString2 = constant$1("val");
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const anyValue$1 = value$3(SimpleResult.svalue);
  const requiredAccess = (path2, obj, key, bundle) => get$g(obj, key).fold(() => missingRequired(path2, key, obj), bundle);
  const fallbackAccess = (obj, key, fallback2, bundle) => {
    const v = get$g(obj, key).getOrThunk(() => fallback2(obj));
    return bundle(v);
  };
  const optionAccess = (obj, key, bundle) => bundle(get$g(obj, key));
  const optionDefaultedAccess = (obj, key, fallback2, bundle) => {
    const opt = get$g(obj, key).map((val) => val === true ? fallback2(obj) : val);
    return bundle(opt);
  };
  const extractField = (field2, path2, obj, key, prop) => {
    const bundle = (av) => prop.extract(path2.concat([key]), av);
    const bundleAsOption = (optValue) => optValue.fold(() => SimpleResult.svalue(Optional.none()), (ov) => {
      const result = prop.extract(path2.concat([key]), ov);
      return SimpleResult.map(result, Optional.some);
    });
    switch (field2.tag) {
      case "required":
        return requiredAccess(path2, obj, key, bundle);
      case "defaultedThunk":
        return fallbackAccess(obj, key, field2.process, bundle);
      case "option":
        return optionAccess(obj, key, bundleAsOption);
      case "defaultedOptionThunk":
        return optionDefaultedAccess(obj, key, field2.process, bundleAsOption);
      case "mergeWithThunk": {
        return fallbackAccess(obj, key, constant$1({}), (v) => {
          const result = deepMerge(field2.process(obj), v);
          return bundle(result);
        });
      }
    }
  };
  const extractFields = (path2, obj, fields) => {
    const success = {};
    const errors = [];
    for (const field2 of fields) {
      fold(field2, (key, newKey, presence, prop) => {
        const result = extractField(presence, path2, obj, key, prop);
        SimpleResult.fold(result, (err) => {
          errors.push(...err);
        }, (res) => {
          success[newKey] = res;
        });
      }, (newKey, instantiator) => {
        success[newKey] = instantiator(obj);
      });
    }
    return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
  };
  const valueThunk = (getDelegate) => {
    const extract2 = (path2, val) => getDelegate().extract(path2, val);
    const toString2 = () => getDelegate().toString();
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const getSetKeys = (obj) => keys(filter$1(obj, isNonNullable));
  const objOfOnly = (fields) => {
    const delegate = objOf(fields);
    const fieldNames = foldr(fields, (acc, value2) => {
      return fold(value2, (key) => deepMerge(acc, { [key]: true }), constant$1(acc));
    }, {});
    const extract2 = (path2, o) => {
      const keys2 = isBoolean(o) ? [] : getSetKeys(o);
      const extra = filter$2(keys2, (k) => !hasNonNullableKey(fieldNames, k));
      return extra.length === 0 ? delegate.extract(path2, o) : unsupportedFields(path2, extra);
    };
    return {
      extract: extract2,
      toString: delegate.toString
    };
  };
  const objOf = (values2) => {
    const extract2 = (path2, o) => extractFields(path2, o, values2);
    const toString2 = () => {
      const fieldStrings = map$2(values2, (value2) => fold(value2, (key, _okey, _presence, prop) => key + " -> " + prop.toString(), (newKey, _instantiator) => "state(" + newKey + ")"));
      return "obj{\n" + fieldStrings.join("\n") + "}";
    };
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const arrOf = (prop) => {
    const extract2 = (path2, array) => {
      const results = map$2(array, (a, i) => prop.extract(path2.concat(["[" + i + "]"]), a));
      return ResultCombine.consolidateArr(results);
    };
    const toString2 = () => "array(" + prop.toString() + ")";
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const oneOf = (props) => {
    const extract2 = (path2, val) => {
      const errors = [];
      for (const prop of props) {
        const res = prop.extract(path2, val);
        if (res.stype === SimpleResultType.Value) {
          return res;
        }
        errors.push(res);
      }
      return ResultCombine.consolidateArr(errors);
    };
    const toString2 = () => "oneOf(" + map$2(props, (prop) => prop.toString()).join(", ") + ")";
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const setOf$1 = (validator, prop) => {
    const validateKeys = (path2, keys2) => arrOf(value$3(validator)).extract(path2, keys2);
    const extract2 = (path2, o) => {
      const keys$1 = keys(o);
      const validatedKeys = validateKeys(path2, keys$1);
      return SimpleResult.bind(validatedKeys, (validKeys) => {
        const schema2 = map$2(validKeys, (vk) => {
          return field$2(vk, vk, required$2(), prop);
        });
        return objOf(schema2).extract(path2, o);
      });
    };
    const toString2 = () => "setOf(" + prop.toString() + ")";
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const thunk = (_desc, processor) => {
    const getP = cached(processor);
    const extract2 = (path2, val) => getP().extract(path2, val);
    const toString2 = () => getP().toString();
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const arrOfObj = compose(arrOf, objOf);
  const anyValue = constant$1(anyValue$1);
  const typedValue = (validator, expectedType) => value$3((a) => {
    const actualType = typeof a;
    return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${expectedType} but got: ${actualType}`);
  });
  const number = typedValue(isNumber, "number");
  const string = typedValue(isString, "string");
  const boolean = typedValue(isBoolean, "boolean");
  const functionProcessor = typedValue(isFunction, "function");
  const isPostMessageable = (val) => {
    if (Object(val) !== val) {
      return true;
    }
    switch ({}.toString.call(val).slice(8, -1)) {
      case "Boolean":
      case "Number":
      case "String":
      case "Date":
      case "RegExp":
      case "Blob":
      case "FileList":
      case "ImageData":
      case "ImageBitmap":
      case "ArrayBuffer":
        return true;
      case "Array":
      case "Object":
        return Object.keys(val).every((prop) => isPostMessageable(val[prop]));
      default:
        return false;
    }
  };
  const postMessageable = value$3((a) => {
    if (isPostMessageable(a)) {
      return SimpleResult.svalue(a);
    } else {
      return SimpleResult.serror("Expected value to be acceptable for sending via postMessage");
    }
  });
  const chooseFrom = (path2, input2, branches, ch) => {
    const fields = get$g(branches, ch);
    return fields.fold(() => missingBranch(path2, branches, ch), (vp) => vp.extract(path2.concat(["branch: " + ch]), input2));
  };
  const choose$2 = (key, branches) => {
    const extract2 = (path2, input2) => {
      const choice = get$g(input2, key);
      return choice.fold(() => missingKey(path2, key), (chosen) => chooseFrom(path2, input2, branches, chosen));
    };
    const toString2 = () => "chooseOn(" + key + "). Possible values: " + keys(branches);
    return {
      extract: extract2,
      toString: toString2
    };
  };
  const arrOfVal = () => arrOf(anyValue$1);
  const valueOf = (validator) => value$3((v) => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
  const setOf = (validator, prop) => setOf$1((v) => SimpleResult.fromResult(validator(v)), prop);
  const extractValue = (label2, prop, obj) => {
    const res = prop.extract([label2], obj);
    return SimpleResult.mapError(res, (errs) => ({
      input: obj,
      errors: errs
    }));
  };
  const asRaw = (label2, prop, obj) => SimpleResult.toResult(extractValue(label2, prop, obj));
  const getOrDie = (extraction) => {
    return extraction.fold((errInfo) => {
      throw new Error(formatError(errInfo));
    }, identity);
  };
  const asRawOrDie$1 = (label2, prop, obj) => getOrDie(asRaw(label2, prop, obj));
  const formatError = (errInfo) => {
    return "Errors: \n" + formatErrors(errInfo.errors).join("\n") + "\n\nInput object: " + formatObj(errInfo.input);
  };
  const choose$1 = (key, branches) => choose$2(key, map$1(branches, objOf));
  const thunkOf = (desc, schema2) => thunk(desc, schema2);
  const field$1 = field$2;
  const customField = customField$1;
  const validateEnum = (values2) => valueOf((value2) => contains$2(values2, value2) ? Result.value(value2) : Result.error(`Unsupported value: "${value2}", choose one of "${values2.join(", ")}".`));
  const required$1 = (key) => field$1(key, key, required$2(), anyValue());
  const requiredOf = (key, schema2) => field$1(key, key, required$2(), schema2);
  const requiredNumber = (key) => requiredOf(key, number);
  const requiredString = (key) => requiredOf(key, string);
  const requiredStringEnum = (key, values2) => field$1(key, key, required$2(), validateEnum(values2));
  const requiredBoolean = (key) => requiredOf(key, boolean);
  const requiredFunction = (key) => requiredOf(key, functionProcessor);
  const forbid = (key, message) => field$1(key, key, asOption(), value$3((_v) => SimpleResult.serror("The field: " + key + " is forbidden. " + message)));
  const requiredObjOf = (key, objSchema) => field$1(key, key, required$2(), objOf(objSchema));
  const requiredArrayOfObj = (key, objFields) => field$1(key, key, required$2(), arrOfObj(objFields));
  const requiredArrayOf = (key, schema2) => field$1(key, key, required$2(), arrOf(schema2));
  const option$3 = (key) => field$1(key, key, asOption(), anyValue());
  const optionOf = (key, schema2) => field$1(key, key, asOption(), schema2);
  const optionNumber = (key) => optionOf(key, number);
  const optionString = (key) => optionOf(key, string);
  const optionStringEnum = (key, values2) => optionOf(key, validateEnum(values2));
  const optionFunction = (key) => optionOf(key, functionProcessor);
  const optionArrayOf = (key, schema2) => optionOf(key, arrOf(schema2));
  const optionObjOf = (key, objSchema) => optionOf(key, objOf(objSchema));
  const optionObjOfOnly = (key, objSchema) => optionOf(key, objOfOnly(objSchema));
  const defaulted = (key, fallback2) => field$1(key, key, defaulted$1(fallback2), anyValue());
  const defaultedOf = (key, fallback2, schema2) => field$1(key, key, defaulted$1(fallback2), schema2);
  const defaultedNumber = (key, fallback2) => defaultedOf(key, fallback2, number);
  const defaultedString = (key, fallback2) => defaultedOf(key, fallback2, string);
  const defaultedStringEnum = (key, fallback2, values2) => defaultedOf(key, fallback2, validateEnum(values2));
  const defaultedBoolean = (key, fallback2) => defaultedOf(key, fallback2, boolean);
  const defaultedFunction = (key, fallback2) => defaultedOf(key, fallback2, functionProcessor);
  const defaultedPostMsg = (key, fallback2) => defaultedOf(key, fallback2, postMessageable);
  const defaultedArrayOf = (key, fallback2, schema2) => defaultedOf(key, fallback2, arrOf(schema2));
  const defaultedObjOf = (key, fallback2, objSchema) => defaultedOf(key, fallback2, objOf(objSchema));
  const Cell = (initial) => {
    let value2 = initial;
    const get2 = () => {
      return value2;
    };
    const set2 = (v) => {
      value2 = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  const generate$7 = (cases) => {
    if (!isArray(cases)) {
      throw new Error("cases must be an array");
    }
    if (cases.length === 0) {
      throw new Error("there must be at least one case");
    }
    const constructors = [];
    const adt2 = {};
    each$1(cases, (acase, count) => {
      const keys$1 = keys(acase);
      if (keys$1.length !== 1) {
        throw new Error("one and only one name per case");
      }
      const key = keys$1[0];
      const value2 = acase[key];
      if (adt2[key] !== void 0) {
        throw new Error("duplicate key detected:" + key);
      } else if (key === "cata") {
        throw new Error("cannot have a case named cata (sorry)");
      } else if (!isArray(value2)) {
        throw new Error("case arguments must be an array");
      }
      constructors.push(key);
      adt2[key] = (...args) => {
        const argLength = args.length;
        if (argLength !== value2.length) {
          throw new Error("Wrong number of arguments to case " + key + ". Expected " + value2.length + " (" + value2 + "), got " + argLength);
        }
        const match = (branches) => {
          const branchKeys = keys(branches);
          if (constructors.length !== branchKeys.length) {
            throw new Error("Wrong number of arguments to match. Expected: " + constructors.join(",") + "\nActual: " + branchKeys.join(","));
          }
          const allReqd = forall(constructors, (reqKey) => {
            return contains$2(branchKeys, reqKey);
          });
          if (!allReqd) {
            throw new Error("Not all branches were specified when using match. Specified: " + branchKeys.join(", ") + "\nRequired: " + constructors.join(", "));
          }
          return branches[key].apply(null, args);
        };
        return {
          fold: (...foldArgs) => {
            if (foldArgs.length !== cases.length) {
              throw new Error("Wrong number of arguments to fold. Expected " + cases.length + ", got " + foldArgs.length);
            }
            const target = foldArgs[count];
            return target.apply(null, args);
          },
          match,
          log: (label2) => {
            console.log(label2, {
              constructors,
              constructor: key,
              params: args
            });
          }
        };
      };
    });
    return adt2;
  };
  const Adt = { generate: generate$7 };
  Adt.generate([
    {
      bothErrors: [
        "error1",
        "error2"
      ]
    },
    {
      firstError: [
        "error1",
        "value2"
      ]
    },
    {
      secondError: [
        "value1",
        "error2"
      ]
    },
    {
      bothValues: [
        "value1",
        "value2"
      ]
    }
  ]);
  const partition$1 = (results) => {
    const errors = [];
    const values2 = [];
    each$1(results, (result) => {
      result.fold((err) => {
        errors.push(err);
      }, (value2) => {
        values2.push(value2);
      });
    });
    return {
      errors,
      values: values2
    };
  };
  const exclude$1 = (obj, fields) => {
    const r2 = {};
    each(obj, (v, k) => {
      if (!contains$2(fields, k)) {
        r2[k] = v;
      }
    });
    return r2;
  };
  const wrap$2 = (key, value2) => ({ [key]: value2 });
  const wrapAll$1 = (keyvalues) => {
    const r2 = {};
    each$1(keyvalues, (kv) => {
      r2[kv.key] = kv.value;
    });
    return r2;
  };
  const exclude = (obj, fields) => exclude$1(obj, fields);
  const wrap$1 = (key, value2) => wrap$2(key, value2);
  const wrapAll = (keyvalues) => wrapAll$1(keyvalues);
  const mergeValues = (values2, base2) => {
    return values2.length === 0 ? Result.value(base2) : Result.value(deepMerge(base2, merge$1.apply(void 0, values2)));
  };
  const mergeErrors = (errors) => Result.error(flatten(errors));
  const consolidate = (objs, base2) => {
    const partitions = partition$1(objs);
    return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base2);
  };
  const ensureIsRoot = (isRoot) => isFunction(isRoot) ? isRoot : never;
  const ancestor$2 = (scope, transform2, isRoot) => {
    let element2 = scope.dom;
    const stop2 = ensureIsRoot(isRoot);
    while (element2.parentNode) {
      element2 = element2.parentNode;
      const el = SugarElement.fromDom(element2);
      const transformed = transform2(el);
      if (transformed.isSome()) {
        return transformed;
      } else if (stop2(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const closest$4 = (scope, transform2, isRoot) => {
    const current = transform2(scope);
    const stop2 = ensureIsRoot(isRoot);
    return current.orThunk(() => stop2(scope) ? Optional.none() : ancestor$2(scope, transform2, stop2));
  };
  const isSource = (component, simulatedEvent) => eq(component.element, simulatedEvent.event.target);
  const defaultEventHandler = {
    can: always,
    abort: never,
    run: noop
  };
  const nu$9 = (parts2) => {
    if (!hasNonNullableKey(parts2, "can") && !hasNonNullableKey(parts2, "abort") && !hasNonNullableKey(parts2, "run")) {
      throw new Error("EventHandler defined by: " + JSON.stringify(parts2, null, 2) + " does not have can, abort, or run!");
    }
    return {
      ...defaultEventHandler,
      ...parts2
    };
  };
  const all$2 = (handlers2, f) => (...args) => foldl(handlers2, (acc, handler) => acc && f(handler).apply(void 0, args), true);
  const any = (handlers2, f) => (...args) => foldl(handlers2, (acc, handler) => acc || f(handler).apply(void 0, args), false);
  const read$2 = (handler) => isFunction(handler) ? {
    can: always,
    abort: never,
    run: handler
  } : handler;
  const fuse$1 = (handlers2) => {
    const can2 = all$2(handlers2, (handler) => handler.can);
    const abort2 = any(handlers2, (handler) => handler.abort);
    const run2 = (...args) => {
      each$1(handlers2, (handler) => {
        handler.run.apply(void 0, args);
      });
    };
    return {
      can: can2,
      abort: abort2,
      run: run2
    };
  };
  const constant = constant$1;
  const touchstart = constant("touchstart");
  const touchmove = constant("touchmove");
  const touchend = constant("touchend");
  const touchcancel = constant("touchcancel");
  const mousedown = constant("mousedown");
  const mousemove = constant("mousemove");
  const mouseout = constant("mouseout");
  const mouseup = constant("mouseup");
  const mouseover = constant("mouseover");
  const focusin = constant("focusin");
  const focusout = constant("focusout");
  const keydown = constant("keydown");
  const keyup = constant("keyup");
  const input = constant("input");
  const change = constant("change");
  const click = constant("click");
  const transitioncancel = constant("transitioncancel");
  const transitionend = constant("transitionend");
  const transitionstart = constant("transitionstart");
  const selectstart = constant("selectstart");
  const prefixName = (name2) => constant$1("alloy." + name2);
  const alloy = { tap: prefixName("tap") };
  const focus$4 = prefixName("focus");
  const postBlur = prefixName("blur.post");
  const postPaste = prefixName("paste.post");
  const receive = prefixName("receive");
  const execute$5 = prefixName("execute");
  const focusItem = prefixName("focus.item");
  const tap = alloy.tap;
  const longpress = prefixName("longpress");
  const sandboxClose = prefixName("sandbox.close");
  const typeaheadCancel = prefixName("typeahead.cancel");
  const systemInit = prefixName("system.init");
  const documentTouchmove = prefixName("system.touchmove");
  const documentTouchend = prefixName("system.touchend");
  const windowScroll = prefixName("system.scroll");
  const windowResize = prefixName("system.resize");
  const attachedToDom = prefixName("system.attached");
  const detachedFromDom = prefixName("system.detached");
  const dismissRequested = prefixName("system.dismissRequested");
  const repositionRequested = prefixName("system.repositionRequested");
  const focusShifted = prefixName("focusmanager.shifted");
  const slotVisibility = prefixName("slotcontainer.visibility");
  const changeTab = prefixName("change.tab");
  const dismissTab = prefixName("dismiss.tab");
  const highlight$1 = prefixName("highlight");
  const dehighlight$1 = prefixName("dehighlight");
  const emit = (component, event) => {
    dispatchWith(component, component.element, event, {});
  };
  const emitWith = (component, event, properties2) => {
    dispatchWith(component, component.element, event, properties2);
  };
  const emitExecute = (component) => {
    emit(component, execute$5());
  };
  const dispatch = (component, target, event) => {
    dispatchWith(component, target, event, {});
  };
  const dispatchWith = (component, target, event, properties2) => {
    const data = {
      target,
      ...properties2
    };
    component.getSystem().triggerEvent(event, target, data);
  };
  const dispatchEvent = (component, target, event, simulatedEvent) => {
    component.getSystem().triggerEvent(event, target, simulatedEvent.event);
  };
  const derive$2 = (configs) => wrapAll(configs);
  const abort = (name2, predicate) => {
    return {
      key: name2,
      value: nu$9({ abort: predicate })
    };
  };
  const can = (name2, predicate) => {
    return {
      key: name2,
      value: nu$9({ can: predicate })
    };
  };
  const preventDefault = (name2) => {
    return {
      key: name2,
      value: nu$9({
        run: (component, simulatedEvent) => {
          simulatedEvent.event.prevent();
        }
      })
    };
  };
  const run$1 = (name2, handler) => {
    return {
      key: name2,
      value: nu$9({ run: handler })
    };
  };
  const runActionExtra = (name2, action, extra) => {
    return {
      key: name2,
      value: nu$9({
        run: (component, simulatedEvent) => {
          action.apply(void 0, [
            component,
            simulatedEvent
          ].concat(extra));
        }
      })
    };
  };
  const runOnName = (name2) => {
    return (handler) => run$1(name2, handler);
  };
  const runOnSourceName = (name2) => {
    return (handler) => ({
      key: name2,
      value: nu$9({
        run: (component, simulatedEvent) => {
          if (isSource(component, simulatedEvent)) {
            handler(component, simulatedEvent);
          }
        }
      })
    });
  };
  const redirectToUid = (name2, uid) => {
    return run$1(name2, (component, simulatedEvent) => {
      component.getSystem().getByUid(uid).each((redirectee) => {
        dispatchEvent(redirectee, redirectee.element, name2, simulatedEvent);
      });
    });
  };
  const redirectToPart = (name2, detail, partName) => {
    const uid = detail.partUids[partName];
    return redirectToUid(name2, uid);
  };
  const runWithTarget = (name2, f) => {
    return run$1(name2, (component, simulatedEvent) => {
      const ev = simulatedEvent.event;
      const target = component.getSystem().getByDom(ev.target).getOrThunk(() => {
        const closest2 = closest$4(ev.target, (el) => component.getSystem().getByDom(el).toOptional(), never);
        return closest2.getOr(component);
      });
      f(component, target, simulatedEvent);
    });
  };
  const cutter = (name2) => {
    return run$1(name2, (component, simulatedEvent) => {
      simulatedEvent.cut();
    });
  };
  const stopper = (name2) => {
    return run$1(name2, (component, simulatedEvent) => {
      simulatedEvent.stop();
    });
  };
  const runOnSource = (name2, f) => {
    return runOnSourceName(name2)(f);
  };
  const runOnAttached = runOnSourceName(attachedToDom());
  const runOnDetached = runOnSourceName(detachedFromDom());
  const runOnInit = runOnSourceName(systemInit());
  const runOnExecute$1 = runOnName(execute$5());
  const fromHtml$1 = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    return children(SugarElement.fromDom(div));
  };
  const get$9 = (element2) => element2.dom.innerHTML;
  const set$6 = (element2, content) => {
    const owner2 = owner$4(element2);
    const docDom = owner2.dom;
    const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
    const contentElements = fromHtml$1(content, docDom);
    append$1(fragment, contentElements);
    empty(element2);
    append$2(element2, fragment);
  };
  const getOuter = (element2) => {
    const container = SugarElement.fromTag("div");
    const clone2 = SugarElement.fromDom(element2.dom.cloneNode(true));
    append$2(container, clone2);
    return get$9(container);
  };
  const clone = (original2, isDeep) => SugarElement.fromDom(original2.dom.cloneNode(isDeep));
  const shallow = (original2) => clone(original2, false);
  const getHtml = (element2) => {
    if (isShadowRoot(element2)) {
      return "#shadow-root";
    } else {
      const clone2 = shallow(element2);
      return getOuter(clone2);
    }
  };
  const element = (elem) => getHtml(elem);
  const isRecursive = (component, originator, target) => eq(originator, component.element) && !eq(originator, target);
  const events$i = derive$2([can(focus$4(), (component, simulatedEvent) => {
    const event = simulatedEvent.event;
    const originator = event.originator;
    const target = event.target;
    if (isRecursive(component, originator, target)) {
      console.warn(focus$4() + " did not get interpreted by the desired target. \nOriginator: " + element(originator) + "\nTarget: " + element(target) + "\nCheck the " + focus$4() + " event handlers");
      return false;
    } else {
      return true;
    }
  })]);
  var DefaultEvents = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$i
  });
  let unique2 = 0;
  const generate$6 = (prefix2) => {
    const date = new Date();
    const time = date.getTime();
    const random = Math.floor(Math.random() * 1e9);
    unique2++;
    return prefix2 + "_" + random + unique2 + String(time);
  };
  const prefix$1 = constant$1("alloy-id-");
  const idAttr$1 = constant$1("data-alloy-id");
  const prefix = prefix$1();
  const idAttr = idAttr$1();
  const write = (label2, elem) => {
    const id = generate$6(prefix + label2);
    writeOnly(elem, id);
    return id;
  };
  const writeOnly = (elem, uid) => {
    Object.defineProperty(elem.dom, idAttr, {
      value: uid,
      writable: true
    });
  };
  const read$1 = (elem) => {
    const id = isElement$1(elem) ? elem.dom[idAttr] : null;
    return Optional.from(id);
  };
  const generate$5 = (prefix2) => generate$6(prefix2);
  const make$8 = identity;
  const NoContextApi = (getComp) => {
    const getMessage = (event) => `The component must be in a context to execute: ${event}` + (getComp ? "\n" + element(getComp().element) + " is not in context." : "");
    const fail = (event) => () => {
      throw new Error(getMessage(event));
    };
    const warn = (event) => () => {
      console.warn(getMessage(event));
    };
    return {
      debugInfo: constant$1("fake"),
      triggerEvent: warn("triggerEvent"),
      triggerFocus: warn("triggerFocus"),
      triggerEscape: warn("triggerEscape"),
      broadcast: warn("broadcast"),
      broadcastOn: warn("broadcastOn"),
      broadcastEvent: warn("broadcastEvent"),
      build: fail("build"),
      buildOrPatch: fail("buildOrPatch"),
      addToWorld: fail("addToWorld"),
      removeFromWorld: fail("removeFromWorld"),
      addToGui: fail("addToGui"),
      removeFromGui: fail("removeFromGui"),
      getByUid: fail("getByUid"),
      getByDom: fail("getByDom"),
      isConnected: never
    };
  };
  const singleton$1 = NoContextApi();
  const markAsBehaviourApi = (f, apiName, apiFunction) => {
    const delegate = apiFunction.toString();
    const endIndex = delegate.indexOf(")") + 1;
    const openBracketIndex = delegate.indexOf("(");
    const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
    f.toFunctionAnnotation = () => ({
      name: apiName,
      parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
    });
    return f;
  };
  const cleanParameters = (parameters) => map$2(parameters, (p) => endsWith(p, "/*") ? p.substring(0, p.length - "/*".length) : p);
  const markAsExtraApi = (f, extraName) => {
    const delegate = f.toString();
    const endIndex = delegate.indexOf(")") + 1;
    const openBracketIndex = delegate.indexOf("(");
    const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
    f.toFunctionAnnotation = () => ({
      name: extraName,
      parameters: cleanParameters(parameters)
    });
    return f;
  };
  const markAsSketchApi = (f, apiFunction) => {
    const delegate = apiFunction.toString();
    const endIndex = delegate.indexOf(")") + 1;
    const openBracketIndex = delegate.indexOf("(");
    const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
    f.toFunctionAnnotation = () => ({
      name: "OVERRIDE",
      parameters: cleanParameters(parameters.slice(1))
    });
    return f;
  };
  const premadeTag = generate$6("alloy-premade");
  const premade$1 = (comp) => {
    Object.defineProperty(comp.element.dom, premadeTag, {
      value: comp.uid,
      writable: true
    });
    return wrap$1(premadeTag, comp);
  };
  const isPremade = (element2) => has$2(element2.dom, premadeTag);
  const getPremade = (spec) => get$g(spec, premadeTag);
  const makeApi = (f) => markAsSketchApi((component, ...rest) => f(component.getApis(), component, ...rest), f);
  const NoState = { init: () => nu$8({ readState: constant$1("No State required") }) };
  const nu$8 = (spec) => spec;
  const generateFrom$1 = (spec, all2) => {
    const schema2 = map$2(all2, (a) => optionObjOf(a.name(), [
      required$1("config"),
      defaulted("state", NoState)
    ]));
    const validated = asRaw("component.behaviours", objOf(schema2), spec.behaviours).fold((errInfo) => {
      throw new Error(formatError(errInfo) + "\nComplete spec:\n" + JSON.stringify(spec, null, 2));
    }, identity);
    return {
      list: all2,
      data: map$1(validated, (optBlobThunk) => {
        const output2 = optBlobThunk.map((blob) => ({
          config: blob.config,
          state: blob.state.init(blob.config)
        }));
        return constant$1(output2);
      })
    };
  };
  const getBehaviours$3 = (bData) => bData.list;
  const getData$2 = (bData) => bData.data;
  const byInnerKey = (data, tuple) => {
    const r2 = {};
    each(data, (detail, key) => {
      each(detail, (value2, indexKey) => {
        const chain = get$g(r2, indexKey).getOr([]);
        r2[indexKey] = chain.concat([tuple(key, value2)]);
      });
    });
    return r2;
  };
  const nu$7 = (s) => ({
    classes: isUndefined(s.classes) ? [] : s.classes,
    attributes: isUndefined(s.attributes) ? {} : s.attributes,
    styles: isUndefined(s.styles) ? {} : s.styles
  });
  const merge = (defnA, mod) => ({
    ...defnA,
    attributes: {
      ...defnA.attributes,
      ...mod.attributes
    },
    styles: {
      ...defnA.styles,
      ...mod.styles
    },
    classes: defnA.classes.concat(mod.classes)
  });
  const combine$2 = (info, baseMod, behaviours2, base2) => {
    const modsByBehaviour = { ...baseMod };
    each$1(behaviours2, (behaviour) => {
      modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base2);
    });
    const byAspect = byInnerKey(modsByBehaviour, (name2, modification) => ({
      name: name2,
      modification
    }));
    const combineObjects = (objects) => foldr(objects, (b2, a) => ({
      ...a.modification,
      ...b2
    }), {});
    const combinedClasses = foldr(byAspect.classes, (b2, a) => a.modification.concat(b2), []);
    const combinedAttributes = combineObjects(byAspect.attributes);
    const combinedStyles = combineObjects(byAspect.styles);
    return nu$7({
      classes: combinedClasses,
      attributes: combinedAttributes,
      styles: combinedStyles
    });
  };
  const sortKeys = (label2, keyName, array, order) => {
    try {
      const sorted = sort(array, (a, b2) => {
        const aKey = a[keyName];
        const bKey = b2[keyName];
        const aIndex = order.indexOf(aKey);
        const bIndex = order.indexOf(bKey);
        if (aIndex === -1) {
          throw new Error("The ordering for " + label2 + " does not have an entry for " + aKey + ".\nOrder specified: " + JSON.stringify(order, null, 2));
        }
        if (bIndex === -1) {
          throw new Error("The ordering for " + label2 + " does not have an entry for " + bKey + ".\nOrder specified: " + JSON.stringify(order, null, 2));
        }
        if (aIndex < bIndex) {
          return -1;
        } else if (bIndex < aIndex) {
          return 1;
        } else {
          return 0;
        }
      });
      return Result.value(sorted);
    } catch (err) {
      return Result.error([err]);
    }
  };
  const uncurried = (handler, purpose) => ({
    handler,
    purpose
  });
  const curried = (handler, purpose) => ({
    cHandler: handler,
    purpose
  });
  const curryArgs = (descHandler, extraArgs) => curried(curry.apply(void 0, [descHandler.handler].concat(extraArgs)), descHandler.purpose);
  const getCurried = (descHandler) => descHandler.cHandler;
  const behaviourTuple = (name2, handler) => ({
    name: name2,
    handler
  });
  const nameToHandlers = (behaviours2, info) => {
    const r2 = {};
    each$1(behaviours2, (behaviour) => {
      r2[behaviour.name()] = behaviour.handlers(info);
    });
    return r2;
  };
  const groupByEvents = (info, behaviours2, base2) => {
    const behaviourEvents = {
      ...base2,
      ...nameToHandlers(behaviours2, info)
    };
    return byInnerKey(behaviourEvents, behaviourTuple);
  };
  const combine$1 = (info, eventOrder, behaviours2, base2) => {
    const byEventName = groupByEvents(info, behaviours2, base2);
    return combineGroups(byEventName, eventOrder);
  };
  const assemble = (rawHandler) => {
    const handler = read$2(rawHandler);
    return (component, simulatedEvent, ...rest) => {
      const args = [
        component,
        simulatedEvent
      ].concat(rest);
      if (handler.abort.apply(void 0, args)) {
        simulatedEvent.stop();
      } else if (handler.can.apply(void 0, args)) {
        handler.run.apply(void 0, args);
      }
    };
  };
  const missingOrderError = (eventName, tuples) => Result.error(["The event (" + eventName + ') has more than one behaviour that listens to it.\nWhen this occurs, you must specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that can trigger it are: ' + JSON.stringify(map$2(tuples, (c) => c.name), null, 2)]);
  const fuse = (tuples, eventOrder, eventName) => {
    const order = eventOrder[eventName];
    if (!order) {
      return missingOrderError(eventName, tuples);
    } else {
      return sortKeys("Event: " + eventName, "name", tuples, order).map((sortedTuples) => {
        const handlers2 = map$2(sortedTuples, (tuple) => tuple.handler);
        return fuse$1(handlers2);
      });
    }
  };
  const combineGroups = (byEventName, eventOrder) => {
    const r2 = mapToArray(byEventName, (tuples, eventName) => {
      const combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName);
      return combined.map((handler) => {
        const assembled = assemble(handler);
        const purpose = tuples.length > 1 ? filter$2(eventOrder[eventName], (o) => exists(tuples, (t2) => t2.name === o)).join(" > ") : tuples[0].name;
        return wrap$1(eventName, uncurried(assembled, purpose));
      });
    });
    return consolidate(r2, {});
  };
  const baseBehaviour = "alloy.base.behaviour";
  const schema$z = objOf([
    field$1("dom", "dom", required$2(), objOf([
      required$1("tag"),
      defaulted("styles", {}),
      defaulted("classes", []),
      defaulted("attributes", {}),
      option$3("value"),
      option$3("innerHtml")
    ])),
    required$1("components"),
    required$1("uid"),
    defaulted("events", {}),
    defaulted("apis", {}),
    field$1("eventOrder", "eventOrder", mergeWith({
      [execute$5()]: [
        "disabling",
        baseBehaviour,
        "toggling",
        "typeaheadevents"
      ],
      [focus$4()]: [
        baseBehaviour,
        "focusing",
        "keying"
      ],
      [systemInit()]: [
        baseBehaviour,
        "disabling",
        "toggling",
        "representing"
      ],
      [input()]: [
        baseBehaviour,
        "representing",
        "streaming",
        "invalidating"
      ],
      [detachedFromDom()]: [
        baseBehaviour,
        "representing",
        "item-events",
        "tooltipping"
      ],
      [mousedown()]: [
        "focusing",
        baseBehaviour,
        "item-type-events"
      ],
      [touchstart()]: [
        "focusing",
        baseBehaviour,
        "item-type-events"
      ],
      [mouseover()]: [
        "item-type-events",
        "tooltipping"
      ],
      [receive()]: [
        "receiving",
        "reflecting",
        "tooltipping"
      ]
    }), anyValue()),
    option$3("domModification")
  ]);
  const toInfo = (spec) => asRaw("custom.definition", schema$z, spec);
  const toDefinition = (detail) => ({
    ...detail.dom,
    uid: detail.uid,
    domChildren: map$2(detail.components, (comp) => comp.element)
  });
  const toModification = (detail) => detail.domModification.fold(() => nu$7({}), nu$7);
  const toEvents = (info) => info.events;
  const read = (element2, attr) => {
    const value2 = get$f(element2, attr);
    return value2 === void 0 || value2 === "" ? [] : value2.split(" ");
  };
  const add$4 = (element2, attr, id) => {
    const old = read(element2, attr);
    const nu2 = old.concat([id]);
    set$9(element2, attr, nu2.join(" "));
    return true;
  };
  const remove$4 = (element2, attr, id) => {
    const nu2 = filter$2(read(element2, attr), (v) => v !== id);
    if (nu2.length > 0) {
      set$9(element2, attr, nu2.join(" "));
    } else {
      remove$7(element2, attr);
    }
    return false;
  };
  const supports = (element2) => element2.dom.classList !== void 0;
  const get$8 = (element2) => read(element2, "class");
  const add$3 = (element2, clazz) => add$4(element2, "class", clazz);
  const remove$3 = (element2, clazz) => remove$4(element2, "class", clazz);
  const add$2 = (element2, clazz) => {
    if (supports(element2)) {
      element2.dom.classList.add(clazz);
    } else {
      add$3(element2, clazz);
    }
  };
  const cleanClass = (element2) => {
    const classList = supports(element2) ? element2.dom.classList : get$8(element2);
    if (classList.length === 0) {
      remove$7(element2, "class");
    }
  };
  const remove$2 = (element2, clazz) => {
    if (supports(element2)) {
      const classList = element2.dom.classList;
      classList.remove(clazz);
    } else {
      remove$3(element2, clazz);
    }
    cleanClass(element2);
  };
  const has = (element2, clazz) => supports(element2) && element2.dom.classList.contains(clazz);
  const add$1 = (element2, classes2) => {
    each$1(classes2, (x) => {
      add$2(element2, x);
    });
  };
  const remove$1 = (element2, classes2) => {
    each$1(classes2, (x) => {
      remove$2(element2, x);
    });
  };
  const hasAll = (element2, classes2) => forall(classes2, (clazz) => has(element2, clazz));
  const getNative = (element2) => {
    const classList = element2.dom.classList;
    const r2 = new Array(classList.length);
    for (let i = 0; i < classList.length; i++) {
      const item2 = classList.item(i);
      if (item2 !== null) {
        r2[i] = item2;
      }
    }
    return r2;
  };
  const get$7 = (element2) => supports(element2) ? getNative(element2) : get$8(element2);
  const get$6 = (element2) => element2.dom.value;
  const set$5 = (element2, value2) => {
    if (value2 === void 0) {
      throw new Error("Value.set was undefined");
    }
    element2.dom.value = value2;
  };
  const determineObsoleted = (parent2, index2, oldObsoleted) => {
    const newObsoleted = child$2(parent2, index2);
    return newObsoleted.map((newObs) => {
      const elemChanged = oldObsoleted.exists((o) => !eq(o, newObs));
      if (elemChanged) {
        const oldTag = oldObsoleted.map(name$3).getOr("span");
        const marker = SugarElement.fromTag(oldTag);
        before$1(newObs, marker);
        return marker;
      } else {
        return newObs;
      }
    });
  };
  const ensureInDom = (parent2, child2, obsoleted) => {
    obsoleted.fold(() => append$2(parent2, child2), (obs) => {
      if (!eq(obs, child2)) {
        before$1(obs, child2);
        remove$5(obs);
      }
    });
  };
  const patchChildrenWith = (parent2, nu2, f) => {
    const builtChildren = map$2(nu2, f);
    const currentChildren = children(parent2);
    each$1(currentChildren.slice(builtChildren.length), remove$5);
    return builtChildren;
  };
  const patchSpecChild = (parent2, index2, spec, build2) => {
    const oldObsoleted = child$2(parent2, index2);
    const childComp = build2(spec, oldObsoleted);
    const obsoleted = determineObsoleted(parent2, index2, oldObsoleted);
    ensureInDom(parent2, childComp.element, obsoleted);
    return childComp;
  };
  const patchSpecChildren = (parent2, specs, build2) => patchChildrenWith(parent2, specs, (spec, index2) => patchSpecChild(parent2, index2, spec, build2));
  const patchDomChildren = (parent2, nodes) => patchChildrenWith(parent2, nodes, (node, index2) => {
    const optObsoleted = child$2(parent2, index2);
    ensureInDom(parent2, node, optObsoleted);
    return node;
  });
  const diffKeyValueSet = (newObj, oldObj) => {
    const newKeys = keys(newObj);
    const oldKeys = keys(oldObj);
    const toRemove = difference(oldKeys, newKeys);
    const toSet = bifilter(newObj, (v, k) => {
      return !has$2(oldObj, k) || v !== oldObj[k];
    }).t;
    return {
      toRemove,
      toSet
    };
  };
  const reconcileToDom = (definition, obsoleted) => {
    const {
      class: clazz,
      style,
      ...existingAttributes
    } = clone$1(obsoleted);
    const {
      toSet: attrsToSet,
      toRemove: attrsToRemove
    } = diffKeyValueSet(definition.attributes, existingAttributes);
    const updateAttrs = () => {
      each$1(attrsToRemove, (a) => remove$7(obsoleted, a));
      setAll$1(obsoleted, attrsToSet);
    };
    const existingStyles = getAllRaw(obsoleted);
    const {
      toSet: stylesToSet,
      toRemove: stylesToRemove
    } = diffKeyValueSet(definition.styles, existingStyles);
    const updateStyles = () => {
      each$1(stylesToRemove, (s) => remove$6(obsoleted, s));
      setAll(obsoleted, stylesToSet);
    };
    const existingClasses = get$7(obsoleted);
    const classesToRemove = difference(existingClasses, definition.classes);
    const classesToAdd = difference(definition.classes, existingClasses);
    const updateClasses = () => {
      add$1(obsoleted, classesToAdd);
      remove$1(obsoleted, classesToRemove);
    };
    const updateHtml = (html) => {
      set$6(obsoleted, html);
    };
    const updateChildren = () => {
      const children2 = definition.domChildren;
      patchDomChildren(obsoleted, children2);
    };
    const updateValue = () => {
      const valueElement = obsoleted;
      const value2 = definition.value.getOrUndefined();
      if (value2 !== get$6(valueElement)) {
        set$5(valueElement, value2 !== null && value2 !== void 0 ? value2 : "");
      }
    };
    updateAttrs();
    updateClasses();
    updateStyles();
    definition.innerHtml.fold(updateChildren, updateHtml);
    updateValue();
    return obsoleted;
  };
  const introduceToDom = (definition) => {
    const subject = SugarElement.fromTag(definition.tag);
    setAll$1(subject, definition.attributes);
    add$1(subject, definition.classes);
    setAll(subject, definition.styles);
    definition.innerHtml.each((html) => set$6(subject, html));
    const children2 = definition.domChildren;
    append$1(subject, children2);
    definition.value.each((value2) => {
      set$5(subject, value2);
    });
    return subject;
  };
  const attemptPatch = (definition, obsoleted) => {
    try {
      const e = reconcileToDom(definition, obsoleted);
      return Optional.some(e);
    } catch (err) {
      return Optional.none();
    }
  };
  const hasMixedChildren = (definition) => definition.innerHtml.isSome() && definition.domChildren.length > 0;
  const renderToDom = (definition, optObsoleted) => {
    const canBePatched = (candidate) => name$3(candidate) === definition.tag && !hasMixedChildren(definition) && !isPremade(candidate);
    const elem = optObsoleted.filter(canBePatched).bind((obsoleted) => attemptPatch(definition, obsoleted)).getOrThunk(() => introduceToDom(definition));
    writeOnly(elem, definition.uid);
    return elem;
  };
  const getBehaviours$2 = (spec) => {
    const behaviours2 = get$g(spec, "behaviours").getOr({});
    return bind$3(keys(behaviours2), (name2) => {
      const behaviour = behaviours2[name2];
      return isNonNullable(behaviour) ? [behaviour.me] : [];
    });
  };
  const generateFrom = (spec, all2) => generateFrom$1(spec, all2);
  const generate$4 = (spec) => {
    const all2 = getBehaviours$2(spec);
    return generateFrom(spec, all2);
  };
  const getDomDefinition = (info, bList, bData) => {
    const definition = toDefinition(info);
    const infoModification = toModification(info);
    const baseModification = { "alloy.base.modification": infoModification };
    const modification = bList.length > 0 ? combine$2(bData, baseModification, bList, definition) : infoModification;
    return merge(definition, modification);
  };
  const getEvents = (info, bList, bData) => {
    const baseEvents = { "alloy.base.behaviour": toEvents(info) };
    return combine$1(bData, info.eventOrder, bList, baseEvents).getOrDie();
  };
  const build$2 = (spec, obsoleted) => {
    const getMe = () => me;
    const systemApi = Cell(singleton$1);
    const info = getOrDie(toInfo(spec));
    const bBlob = generate$4(spec);
    const bList = getBehaviours$3(bBlob);
    const bData = getData$2(bBlob);
    const modDefinition = getDomDefinition(info, bList, bData);
    const item2 = renderToDom(modDefinition, obsoleted);
    const events2 = getEvents(info, bList, bData);
    const subcomponents = Cell(info.components);
    const connect = (newApi) => {
      systemApi.set(newApi);
    };
    const disconnect = () => {
      systemApi.set(NoContextApi(getMe));
    };
    const syncComponents = () => {
      const children$1 = children(item2);
      const subs2 = bind$3(children$1, (child2) => systemApi.get().getByDom(child2).fold(() => [], pure$2));
      subcomponents.set(subs2);
    };
    const config2 = (behaviour) => {
      const b2 = bData;
      const f = isFunction(b2[behaviour.name()]) ? b2[behaviour.name()] : () => {
        throw new Error("Could not find " + behaviour.name() + " in " + JSON.stringify(spec, null, 2));
      };
      return f();
    };
    const hasConfigured = (behaviour) => isFunction(bData[behaviour.name()]);
    const getApis = () => info.apis;
    const readState = (behaviourName) => bData[behaviourName]().map((b2) => b2.state.readState()).getOr("not enabled");
    const me = {
      uid: spec.uid,
      getSystem: systemApi.get,
      config: config2,
      hasConfigured,
      spec,
      readState,
      getApis,
      connect,
      disconnect,
      element: item2,
      syncComponents,
      components: subcomponents.get,
      events: events2
    };
    return me;
  };
  const buildSubcomponents = (spec, obsoleted) => {
    const components2 = get$g(spec, "components").getOr([]);
    return obsoleted.fold(() => map$2(components2, build$1), (obs) => map$2(components2, (c, i) => {
      return buildOrPatch(c, child$2(obs, i));
    }));
  };
  const buildFromSpec = (userSpec, obsoleted) => {
    const {
      events: specEvents,
      ...spec
    } = make$8(userSpec);
    const components2 = buildSubcomponents(spec, obsoleted);
    const completeSpec = {
      ...spec,
      events: {
        ...DefaultEvents,
        ...specEvents
      },
      components: components2
    };
    return Result.value(build$2(completeSpec, obsoleted));
  };
  const text$1 = (textContent) => {
    const element2 = SugarElement.fromText(textContent);
    return external$1({ element: element2 });
  };
  const external$1 = (spec) => {
    const extSpec = asRawOrDie$1("external.component", objOfOnly([
      required$1("element"),
      option$3("uid")
    ]), spec);
    const systemApi = Cell(NoContextApi());
    const connect = (newApi) => {
      systemApi.set(newApi);
    };
    const disconnect = () => {
      systemApi.set(NoContextApi(() => me));
    };
    const uid = extSpec.uid.getOrThunk(() => generate$5("external"));
    writeOnly(extSpec.element, uid);
    const me = {
      uid,
      getSystem: systemApi.get,
      config: Optional.none,
      hasConfigured: never,
      connect,
      disconnect,
      getApis: () => ({}),
      element: extSpec.element,
      spec,
      readState: constant$1("No state"),
      syncComponents: noop,
      components: constant$1([]),
      events: {}
    };
    return premade$1(me);
  };
  const uids = generate$5;
  const isSketchSpec$1 = (spec) => has$2(spec, "uid");
  const buildOrPatch = (spec, obsoleted) => getPremade(spec).getOrThunk(() => {
    const userSpecWithUid = isSketchSpec$1(spec) ? spec : {
      uid: uids(""),
      ...spec
    };
    return buildFromSpec(userSpecWithUid, obsoleted).getOrDie();
  });
  const build$1 = (spec) => buildOrPatch(spec, Optional.none());
  const premade = premade$1;
  var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot) => {
    if (is2(scope, a)) {
      return Optional.some(scope);
    } else if (isFunction(isRoot) && isRoot(scope)) {
      return Optional.none();
    } else {
      return ancestor2(scope, a, isRoot);
    }
  };
  const ancestor$1 = (scope, predicate, isRoot) => {
    let element2 = scope.dom;
    const stop2 = isFunction(isRoot) ? isRoot : never;
    while (element2.parentNode) {
      element2 = element2.parentNode;
      const el = SugarElement.fromDom(element2);
      if (predicate(el)) {
        return Optional.some(el);
      } else if (stop2(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const closest$3 = (scope, predicate, isRoot) => {
    const is2 = (s, test) => test(s);
    return ClosestOrAncestor(is2, ancestor$1, scope, predicate, isRoot);
  };
  const child$1 = (scope, predicate) => {
    const pred = (node) => predicate(SugarElement.fromDom(node));
    const result = find$5(scope.dom.childNodes, pred);
    return result.map(SugarElement.fromDom);
  };
  const descendant$1 = (scope, predicate) => {
    const descend = (node) => {
      for (let i = 0; i < node.childNodes.length; i++) {
        const child2 = SugarElement.fromDom(node.childNodes[i]);
        if (predicate(child2)) {
          return Optional.some(child2);
        }
        const res = descend(node.childNodes[i]);
        if (res.isSome()) {
          return res;
        }
      }
      return Optional.none();
    };
    return descend(scope.dom);
  };
  const closest$2 = (scope, predicate, isRoot) => closest$3(scope, predicate, isRoot).isSome();
  const ancestor = (scope, selector, isRoot) => ancestor$1(scope, (e) => is(e, selector), isRoot);
  const child = (scope, selector) => child$1(scope, (e) => is(e, selector));
  const descendant = (scope, selector) => one(selector, scope);
  const closest$1 = (scope, selector, isRoot) => {
    const is$12 = (element2, selector2) => is(element2, selector2);
    return ClosestOrAncestor(is$12, ancestor, scope, selector, isRoot);
  };
  const attribute = "aria-controls";
  const find$1 = (queryElem) => {
    const dependent = closest$3(queryElem, (elem) => {
      if (!isElement$1(elem)) {
        return false;
      }
      const id = get$f(elem, "id");
      return id !== void 0 && id.indexOf(attribute) > -1;
    });
    return dependent.bind((dep) => {
      const id = get$f(dep, "id");
      const dos = getRootNode(dep);
      return descendant(dos, `[${attribute}="${id}"]`);
    });
  };
  const manager = () => {
    const ariaId = generate$6(attribute);
    const link = (elem) => {
      set$9(elem, attribute, ariaId);
    };
    const unlink = (elem) => {
      remove$7(elem, attribute);
    };
    return {
      id: ariaId,
      link,
      unlink
    };
  };
  const isAriaPartOf = (component, queryElem) => find$1(queryElem).exists((owner2) => isPartOf$1(component, owner2));
  const isPartOf$1 = (component, queryElem) => closest$2(queryElem, (el) => eq(el, component.element), never) || isAriaPartOf(component, queryElem);
  const unknown = "unknown";
  var EventConfiguration;
  (function(EventConfiguration2) {
    EventConfiguration2[EventConfiguration2["STOP"] = 0] = "STOP";
    EventConfiguration2[EventConfiguration2["NORMAL"] = 1] = "NORMAL";
    EventConfiguration2[EventConfiguration2["LOGGING"] = 2] = "LOGGING";
  })(EventConfiguration || (EventConfiguration = {}));
  const eventConfig = Cell({});
  const makeEventLogger = (eventName, initialTarget) => {
    const sequence2 = [];
    const startTime = new Date().getTime();
    return {
      logEventCut: (_name, target, purpose) => {
        sequence2.push({
          outcome: "cut",
          target,
          purpose
        });
      },
      logEventStopped: (_name, target, purpose) => {
        sequence2.push({
          outcome: "stopped",
          target,
          purpose
        });
      },
      logNoParent: (_name, target, purpose) => {
        sequence2.push({
          outcome: "no-parent",
          target,
          purpose
        });
      },
      logEventNoHandlers: (_name, target) => {
        sequence2.push({
          outcome: "no-handlers-left",
          target
        });
      },
      logEventResponse: (_name, target, purpose) => {
        sequence2.push({
          outcome: "response",
          purpose,
          target
        });
      },
      write: () => {
        const finishTime = new Date().getTime();
        if (contains$2([
          "mousemove",
          "mouseover",
          "mouseout",
          systemInit()
        ], eventName)) {
          return;
        }
        console.log(eventName, {
          event: eventName,
          time: finishTime - startTime,
          target: initialTarget.dom,
          sequence: map$2(sequence2, (s) => {
            if (!contains$2([
              "cut",
              "stopped",
              "response"
            ], s.outcome)) {
              return s.outcome;
            } else {
              return "{" + s.purpose + "} " + s.outcome + " at (" + element(s.target) + ")";
            }
          })
        });
      }
    };
  };
  const processEvent = (eventName, initialTarget, f) => {
    const status = get$g(eventConfig.get(), eventName).orThunk(() => {
      const patterns = keys(eventConfig.get());
      return findMap(patterns, (p) => eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none());
    }).getOr(EventConfiguration.NORMAL);
    switch (status) {
      case EventConfiguration.NORMAL:
        return f(noLogger());
      case EventConfiguration.LOGGING: {
        const logger = makeEventLogger(eventName, initialTarget);
        const output2 = f(logger);
        logger.write();
        return output2;
      }
      case EventConfiguration.STOP:
        return true;
    }
  };
  const path = [
    "alloy/data/Fields",
    "alloy/debugging/Debugging"
  ];
  const getTrace = () => {
    const err = new Error();
    if (err.stack !== void 0) {
      const lines = err.stack.split("\n");
      return find$5(lines, (line) => line.indexOf("alloy") > 0 && !exists(path, (p) => line.indexOf(p) > -1)).getOr(unknown);
    } else {
      return unknown;
    }
  };
  const ignoreEvent = {
    logEventCut: noop,
    logEventStopped: noop,
    logNoParent: noop,
    logEventNoHandlers: noop,
    logEventResponse: noop,
    write: noop
  };
  const monitorEvent = (eventName, initialTarget, f) => processEvent(eventName, initialTarget, f);
  const noLogger = constant$1(ignoreEvent);
  const menuFields = constant$1([
    required$1("menu"),
    required$1("selectedMenu")
  ]);
  const itemFields = constant$1([
    required$1("item"),
    required$1("selectedItem")
  ]);
  constant$1(objOf(itemFields().concat(menuFields())));
  const itemSchema$3 = constant$1(objOf(itemFields()));
  const _initSize = requiredObjOf("initSize", [
    required$1("numColumns"),
    required$1("numRows")
  ]);
  const itemMarkers = () => requiredOf("markers", itemSchema$3());
  const tieredMenuMarkers = () => requiredObjOf("markers", [required$1("backgroundMenu")].concat(menuFields()).concat(itemFields()));
  const markers$1 = (required2) => requiredObjOf("markers", map$2(required2, required$1));
  const onPresenceHandler = (label2, fieldName, presence) => {
    getTrace();
    return field$1(fieldName, fieldName, presence, valueOf((f) => Result.value((...args) => {
      return f.apply(void 0, args);
    })));
  };
  const onHandler = (fieldName) => onPresenceHandler("onHandler", fieldName, defaulted$1(noop));
  const onKeyboardHandler = (fieldName) => onPresenceHandler("onKeyboardHandler", fieldName, defaulted$1(Optional.none));
  const onStrictHandler = (fieldName) => onPresenceHandler("onHandler", fieldName, required$2());
  const onStrictKeyboardHandler = (fieldName) => onPresenceHandler("onKeyboardHandler", fieldName, required$2());
  const output$1 = (name2, value2) => customField(name2, constant$1(value2));
  const snapshot = (name2) => customField(name2, identity);
  const initSize = constant$1(_initSize);
  const nu$6 = (x, y, bubble, direction, placement2, boundsRestriction2, labelPrefix2, alwaysFit = false) => ({
    x,
    y,
    bubble,
    direction,
    placement: placement2,
    restriction: boundsRestriction2,
    label: `${labelPrefix2}-${placement2}`,
    alwaysFit
  });
  const adt$a = Adt.generate([
    { southeast: [] },
    { southwest: [] },
    { northeast: [] },
    { northwest: [] },
    { south: [] },
    { north: [] },
    { east: [] },
    { west: [] }
  ]);
  const cata$2 = (subject, southeast2, southwest2, northeast2, northwest2, south2, north2, east2, west2) => subject.fold(southeast2, southwest2, northeast2, northwest2, south2, north2, east2, west2);
  const cataVertical = (subject, south2, middle, north2) => subject.fold(south2, south2, north2, north2, south2, north2, middle, middle);
  const cataHorizontal = (subject, east2, middle, west2) => subject.fold(east2, west2, east2, west2, middle, middle, east2, west2);
  const southeast$3 = adt$a.southeast;
  const southwest$3 = adt$a.southwest;
  const northeast$3 = adt$a.northeast;
  const northwest$3 = adt$a.northwest;
  const south$3 = adt$a.south;
  const north$3 = adt$a.north;
  const east$3 = adt$a.east;
  const west$3 = adt$a.west;
  const cycleBy = (value2, delta, min2, max2) => {
    const r2 = value2 + delta;
    if (r2 > max2) {
      return min2;
    } else if (r2 < min2) {
      return max2;
    } else {
      return r2;
    }
  };
  const clamp = (value2, min2, max2) => Math.min(Math.max(value2, min2), max2);
  const getRestriction = (anchor2, restriction) => {
    switch (restriction) {
      case 1:
        return anchor2.x;
      case 0:
        return anchor2.x + anchor2.width;
      case 2:
        return anchor2.y;
      case 3:
        return anchor2.y + anchor2.height;
    }
  };
  const boundsRestriction = (anchor2, restrictions) => mapToObject([
    "left",
    "right",
    "top",
    "bottom"
  ], (dir) => get$g(restrictions, dir).map((restriction) => getRestriction(anchor2, restriction)));
  const adjustBounds = (bounds$12, restriction, bubbleOffset) => {
    const applyRestriction = (dir, current) => restriction[dir].map((pos) => {
      const isVerticalAxis = dir === "top" || dir === "bottom";
      const offset2 = isVerticalAxis ? bubbleOffset.top : bubbleOffset.left;
      const comparator = dir === "left" || dir === "top" ? Math.max : Math.min;
      const newPos = comparator(pos, current) + offset2;
      return isVerticalAxis ? clamp(newPos, bounds$12.y, bounds$12.bottom) : clamp(newPos, bounds$12.x, bounds$12.right);
    }).getOr(current);
    const adjustedLeft = applyRestriction("left", bounds$12.x);
    const adjustedTop = applyRestriction("top", bounds$12.y);
    const adjustedRight = applyRestriction("right", bounds$12.right);
    const adjustedBottom = applyRestriction("bottom", bounds$12.bottom);
    return bounds(adjustedLeft, adjustedTop, adjustedRight - adjustedLeft, adjustedBottom - adjustedTop);
  };
  const labelPrefix$2 = "layout";
  const eastX$1 = (anchor2) => anchor2.x;
  const middleX$1 = (anchor2, element2) => anchor2.x + anchor2.width / 2 - element2.width / 2;
  const westX$1 = (anchor2, element2) => anchor2.x + anchor2.width - element2.width;
  const northY$2 = (anchor2, element2) => anchor2.y - element2.height;
  const southY$2 = (anchor2) => anchor2.y + anchor2.height;
  const centreY$1 = (anchor2, element2) => anchor2.y + anchor2.height / 2 - element2.height / 2;
  const eastEdgeX$1 = (anchor2) => anchor2.x + anchor2.width;
  const westEdgeX$1 = (anchor2, element2) => anchor2.x - element2.width;
  const southeast$2 = (anchor2, element2, bubbles) => nu$6(eastX$1(anchor2), southY$2(anchor2), bubbles.southeast(), southeast$3(), "southeast", boundsRestriction(anchor2, {
    left: 1,
    top: 3
  }), labelPrefix$2);
  const southwest$2 = (anchor2, element2, bubbles) => nu$6(westX$1(anchor2, element2), southY$2(anchor2), bubbles.southwest(), southwest$3(), "southwest", boundsRestriction(anchor2, {
    right: 0,
    top: 3
  }), labelPrefix$2);
  const northeast$2 = (anchor2, element2, bubbles) => nu$6(eastX$1(anchor2), northY$2(anchor2, element2), bubbles.northeast(), northeast$3(), "northeast", boundsRestriction(anchor2, {
    left: 1,
    bottom: 2
  }), labelPrefix$2);
  const northwest$2 = (anchor2, element2, bubbles) => nu$6(westX$1(anchor2, element2), northY$2(anchor2, element2), bubbles.northwest(), northwest$3(), "northwest", boundsRestriction(anchor2, {
    right: 0,
    bottom: 2
  }), labelPrefix$2);
  const north$2 = (anchor2, element2, bubbles) => nu$6(middleX$1(anchor2, element2), northY$2(anchor2, element2), bubbles.north(), north$3(), "north", boundsRestriction(anchor2, { bottom: 2 }), labelPrefix$2);
  const south$2 = (anchor2, element2, bubbles) => nu$6(middleX$1(anchor2, element2), southY$2(anchor2), bubbles.south(), south$3(), "south", boundsRestriction(anchor2, { top: 3 }), labelPrefix$2);
  const east$2 = (anchor2, element2, bubbles) => nu$6(eastEdgeX$1(anchor2), centreY$1(anchor2, element2), bubbles.east(), east$3(), "east", boundsRestriction(anchor2, { left: 0 }), labelPrefix$2);
  const west$2 = (anchor2, element2, bubbles) => nu$6(westEdgeX$1(anchor2, element2), centreY$1(anchor2, element2), bubbles.west(), west$3(), "west", boundsRestriction(anchor2, { right: 1 }), labelPrefix$2);
  const all$1 = () => [
    southeast$2,
    southwest$2,
    northeast$2,
    northwest$2,
    south$2,
    north$2,
    east$2,
    west$2
  ];
  const allRtl$1 = () => [
    southwest$2,
    southeast$2,
    northwest$2,
    northeast$2,
    south$2,
    north$2,
    east$2,
    west$2
  ];
  const aboveOrBelow = () => [
    northeast$2,
    northwest$2,
    southeast$2,
    southwest$2,
    north$2,
    south$2
  ];
  const aboveOrBelowRtl = () => [
    northwest$2,
    northeast$2,
    southwest$2,
    southeast$2,
    north$2,
    south$2
  ];
  const belowOrAbove = () => [
    southeast$2,
    southwest$2,
    northeast$2,
    northwest$2,
    south$2,
    north$2
  ];
  const belowOrAboveRtl = () => [
    southwest$2,
    southeast$2,
    northwest$2,
    northeast$2,
    south$2,
    north$2
  ];
  const chooseChannels = (channels, message) => message.universal ? channels : filter$2(channels, (ch) => contains$2(message.channels, ch));
  const events$h = (receiveConfig) => derive$2([run$1(receive(), (component, message) => {
    const channelMap = receiveConfig.channels;
    const channels = keys(channelMap);
    const receivingData = message;
    const targetChannels = chooseChannels(channels, receivingData);
    each$1(targetChannels, (ch) => {
      const channelInfo = channelMap[ch];
      const channelSchema = channelInfo.schema;
      const data = asRawOrDie$1("channel[" + ch + "] data\nReceiver: " + element(component.element), channelSchema, receivingData.data);
      channelInfo.onReceive(component, data);
    });
  })]);
  var ActiveReceiving = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$h
  });
  var ReceivingSchema = [requiredOf("channels", setOf(Result.value, objOfOnly([
    onStrictHandler("onReceive"),
    defaulted("schema", anyValue())
  ])))];
  const executeEvent = (bConfig, bState, executor) => runOnExecute$1((component) => {
    executor(component, bConfig, bState);
  });
  const loadEvent = (bConfig, bState, f) => runOnInit((component, _simulatedEvent) => {
    f(component, bConfig, bState);
  });
  const create$4 = (schema2, name2, active2, apis, extra, state) => {
    const configSchema = objOfOnly(schema2);
    const schemaSchema = optionObjOf(name2, [optionObjOfOnly("config", schema2)]);
    return doCreate(configSchema, schemaSchema, name2, active2, apis, extra, state);
  };
  const createModes$1 = (modes, name2, active2, apis, extra, state) => {
    const configSchema = modes;
    const schemaSchema = optionObjOf(name2, [optionOf("config", modes)]);
    return doCreate(configSchema, schemaSchema, name2, active2, apis, extra, state);
  };
  const wrapApi = (bName, apiFunction, apiName) => {
    const f = (component, ...rest) => {
      const args = [component].concat(rest);
      return component.config({ name: constant$1(bName) }).fold(() => {
        throw new Error("We could not find any behaviour configuration for: " + bName + ". Using API: " + apiName);
      }, (info) => {
        const rest2 = Array.prototype.slice.call(args, 1);
        return apiFunction.apply(void 0, [
          component,
          info.config,
          info.state
        ].concat(rest2));
      });
    };
    return markAsBehaviourApi(f, apiName, apiFunction);
  };
  const revokeBehaviour = (name2) => ({
    key: name2,
    value: void 0
  });
  const doCreate = (configSchema, schemaSchema, name2, active2, apis, extra, state) => {
    const getConfig = (info) => hasNonNullableKey(info, name2) ? info[name2]() : Optional.none();
    const wrappedApis = map$1(apis, (apiF, apiName) => wrapApi(name2, apiF, apiName));
    const wrappedExtra = map$1(extra, (extraF, extraName) => markAsExtraApi(extraF, extraName));
    const me = {
      ...wrappedExtra,
      ...wrappedApis,
      revoke: curry(revokeBehaviour, name2),
      config: (spec) => {
        const prepared = asRawOrDie$1(name2 + "-config", configSchema, spec);
        return {
          key: name2,
          value: {
            config: prepared,
            me,
            configAsRaw: cached(() => asRawOrDie$1(name2 + "-config", configSchema, spec)),
            initialConfig: spec,
            state
          }
        };
      },
      schema: constant$1(schemaSchema),
      exhibit: (info, base2) => {
        return lift2(getConfig(info), get$g(active2, "exhibit"), (behaviourInfo, exhibitor) => {
          return exhibitor(base2, behaviourInfo.config, behaviourInfo.state);
        }).getOrThunk(() => nu$7({}));
      },
      name: constant$1(name2),
      handlers: (info) => {
        return getConfig(info).map((behaviourInfo) => {
          const getEvents2 = get$g(active2, "events").getOr(() => ({}));
          return getEvents2(behaviourInfo.config, behaviourInfo.state);
        }).getOr({});
      }
    };
    return me;
  };
  const derive$1 = (capabilities) => wrapAll(capabilities);
  const simpleSchema = objOfOnly([
    required$1("fields"),
    required$1("name"),
    defaulted("active", {}),
    defaulted("apis", {}),
    defaulted("state", NoState),
    defaulted("extra", {})
  ]);
  const create$3 = (data) => {
    const value2 = asRawOrDie$1("Creating behaviour: " + data.name, simpleSchema, data);
    return create$4(value2.fields, value2.name, value2.active, value2.apis, value2.extra, value2.state);
  };
  const modeSchema = objOfOnly([
    required$1("branchKey"),
    required$1("branches"),
    required$1("name"),
    defaulted("active", {}),
    defaulted("apis", {}),
    defaulted("state", NoState),
    defaulted("extra", {})
  ]);
  const createModes = (data) => {
    const value2 = asRawOrDie$1("Creating behaviour: " + data.name, modeSchema, data);
    return createModes$1(choose$1(value2.branchKey, value2.branches), value2.name, value2.active, value2.apis, value2.extra, value2.state);
  };
  const revoke = constant$1(void 0);
  const Receiving = create$3({
    fields: ReceivingSchema,
    name: "receiving",
    active: ActiveReceiving
  });
  const exhibit$6 = (base2, posConfig) => nu$7({
    classes: [],
    styles: posConfig.useFixed() ? {} : { position: "relative" }
  });
  var ActivePosition = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit: exhibit$6
  });
  const focus$3 = (element2) => element2.dom.focus();
  const blur$1 = (element2) => element2.dom.blur();
  const hasFocus = (element2) => {
    const root = getRootNode(element2).dom;
    return element2.dom === root.activeElement;
  };
  const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
  const search = (element2) => active$1(getRootNode(element2)).filter((e) => element2.dom.contains(e.dom));
  const preserve$1 = (f, container) => {
    const dos = getRootNode(container);
    const refocus = active$1(dos).bind((focused) => {
      const hasFocus2 = (elem) => eq(focused, elem);
      return hasFocus2(container) ? Optional.some(container) : descendant$1(container, hasFocus2);
    });
    const result = f(container);
    refocus.each((oldFocus) => {
      active$1(dos).filter((newFocus) => eq(newFocus, oldFocus)).fold(() => {
        focus$3(oldFocus);
      }, noop);
    });
    return result;
  };
  const NuPositionCss = (position2, left2, top2, right2, bottom2) => {
    const toPx = (num) => num + "px";
    return {
      position: position2,
      left: left2.map(toPx),
      top: top2.map(toPx),
      right: right2.map(toPx),
      bottom: bottom2.map(toPx)
    };
  };
  const toOptions = (position2) => ({
    ...position2,
    position: Optional.some(position2.position)
  });
  const applyPositionCss = (element2, position2) => {
    setOptions(element2, toOptions(position2));
  };
  const adt$9 = Adt.generate([
    { none: [] },
    {
      relative: [
        "x",
        "y",
        "width",
        "height"
      ]
    },
    {
      fixed: [
        "x",
        "y",
        "width",
        "height"
      ]
    }
  ]);
  const positionWithDirection = (posName, decision, x, y, width2, height2) => {
    const decisionRect = decision.rect;
    const decisionX = decisionRect.x - x;
    const decisionY = decisionRect.y - y;
    const decisionWidth = decisionRect.width;
    const decisionHeight = decisionRect.height;
    const decisionRight = width2 - (decisionX + decisionWidth);
    const decisionBottom = height2 - (decisionY + decisionHeight);
    const left2 = Optional.some(decisionX);
    const top2 = Optional.some(decisionY);
    const right2 = Optional.some(decisionRight);
    const bottom2 = Optional.some(decisionBottom);
    const none = Optional.none();
    return cata$2(decision.direction, () => NuPositionCss(posName, left2, top2, none, none), () => NuPositionCss(posName, none, top2, right2, none), () => NuPositionCss(posName, left2, none, none, bottom2), () => NuPositionCss(posName, none, none, right2, bottom2), () => NuPositionCss(posName, left2, top2, none, none), () => NuPositionCss(posName, left2, none, none, bottom2), () => NuPositionCss(posName, left2, top2, none, none), () => NuPositionCss(posName, none, top2, right2, none));
  };
  const reposition = (origin, decision) => origin.fold(() => {
    const decisionRect = decision.rect;
    return NuPositionCss("absolute", Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
  }, (x, y, width2, height2) => {
    return positionWithDirection("absolute", decision, x, y, width2, height2);
  }, (x, y, width2, height2) => {
    return positionWithDirection("fixed", decision, x, y, width2, height2);
  });
  const toBox = (origin, element2) => {
    const rel = curry(find$2, element2);
    const position2 = origin.fold(rel, rel, () => {
      const scroll = get$b();
      return find$2(element2).translate(-scroll.left, -scroll.top);
    });
    const width2 = getOuter$1(element2);
    const height2 = getOuter$2(element2);
    return bounds(position2.left, position2.top, width2, height2);
  };
  const viewport = (origin, getBounds2) => getBounds2.fold(() => origin.fold(win, win, bounds), (b2) => origin.fold(b2, b2, () => {
    const bounds$12 = b2();
    const pos = translate$2(origin, bounds$12.x, bounds$12.y);
    return bounds(pos.left, pos.top, bounds$12.width, bounds$12.height);
  }));
  const translate$2 = (origin, x, y) => {
    const pos = SugarPosition(x, y);
    const removeScroll = () => {
      const outerScroll = get$b();
      return pos.translate(-outerScroll.left, -outerScroll.top);
    };
    return origin.fold(constant$1(pos), constant$1(pos), removeScroll);
  };
  const cata$1 = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
  adt$9.none;
  const relative$1 = adt$9.relative;
  const fixed$1 = adt$9.fixed;
  const anchor = (anchorBox, origin) => ({
    anchorBox,
    origin
  });
  const box = (anchorBox, origin) => anchor(anchorBox, origin);
  const placementAttribute = "data-alloy-placement";
  const setPlacement$1 = (element2, placement2) => {
    set$9(element2, placementAttribute, placement2);
  };
  const getPlacement = (element2) => getOpt(element2, placementAttribute);
  const reset$2 = (element2) => remove$7(element2, placementAttribute);
  const adt$8 = Adt.generate([
    { fit: ["reposition"] },
    {
      nofit: [
        "reposition",
        "visibleW",
        "visibleH",
        "isVisible"
      ]
    }
  ]);
  const determinePosition = (box2, bounds2) => {
    const {
      x: boundsX,
      y: boundsY,
      right: boundsRight,
      bottom: boundsBottom
    } = bounds2;
    const { x, y, right: right2, bottom: bottom2, width: width2, height: height2 } = box2;
    const xInBounds = x >= boundsX && x <= boundsRight;
    const yInBounds = y >= boundsY && y <= boundsBottom;
    const originInBounds = xInBounds && yInBounds;
    const rightInBounds = right2 <= boundsRight && right2 >= boundsX;
    const bottomInBounds = bottom2 <= boundsBottom && bottom2 >= boundsY;
    const sizeInBounds = rightInBounds && bottomInBounds;
    const visibleW = Math.min(width2, x >= boundsX ? boundsRight - x : right2 - boundsX);
    const visibleH = Math.min(height2, y >= boundsY ? boundsBottom - y : bottom2 - boundsY);
    return {
      originInBounds,
      sizeInBounds,
      visibleW,
      visibleH
    };
  };
  const calcReposition = (box2, bounds$12) => {
    const {
      x: boundsX,
      y: boundsY,
      right: boundsRight,
      bottom: boundsBottom
    } = bounds$12;
    const { x, y, width: width2, height: height2 } = box2;
    const maxX2 = Math.max(boundsX, boundsRight - width2);
    const maxY2 = Math.max(boundsY, boundsBottom - height2);
    const restrictedX = clamp(x, boundsX, maxX2);
    const restrictedY = clamp(y, boundsY, maxY2);
    const restrictedWidth = Math.min(restrictedX + width2, boundsRight) - restrictedX;
    const restrictedHeight = Math.min(restrictedY + height2, boundsBottom) - restrictedY;
    return bounds(restrictedX, restrictedY, restrictedWidth, restrictedHeight);
  };
  const calcMaxSizes = (direction, box2, bounds2) => {
    const upAvailable = constant$1(box2.bottom - bounds2.y);
    const downAvailable = constant$1(bounds2.bottom - box2.y);
    const maxHeight = cataVertical(direction, downAvailable, downAvailable, upAvailable);
    const westAvailable = constant$1(box2.right - bounds2.x);
    const eastAvailable = constant$1(bounds2.right - box2.x);
    const maxWidth = cataHorizontal(direction, eastAvailable, eastAvailable, westAvailable);
    return {
      maxWidth,
      maxHeight
    };
  };
  const attempt = (candidate, width2, height2, bounds$12) => {
    const bubble = candidate.bubble;
    const bubbleOffset = bubble.offset;
    const adjustedBounds = adjustBounds(bounds$12, candidate.restriction, bubbleOffset);
    const newX = candidate.x + bubbleOffset.left;
    const newY = candidate.y + bubbleOffset.top;
    const box2 = bounds(newX, newY, width2, height2);
    const { originInBounds, sizeInBounds, visibleW, visibleH } = determinePosition(box2, adjustedBounds);
    const fits = originInBounds && sizeInBounds;
    const fittedBox = fits ? box2 : calcReposition(box2, adjustedBounds);
    const isPartlyVisible = fittedBox.width > 0 && fittedBox.height > 0;
    const { maxWidth, maxHeight } = calcMaxSizes(candidate.direction, fittedBox, bounds$12);
    const reposition2 = {
      rect: fittedBox,
      maxHeight,
      maxWidth,
      direction: candidate.direction,
      placement: candidate.placement,
      classes: {
        on: bubble.classesOn,
        off: bubble.classesOff
      },
      layout: candidate.label,
      testY: newY
    };
    return fits || candidate.alwaysFit ? adt$8.fit(reposition2) : adt$8.nofit(reposition2, visibleW, visibleH, isPartlyVisible);
  };
  const attempts = (element2, candidates, anchorBox, elementBox, bubbles, bounds2) => {
    const panelWidth = elementBox.width;
    const panelHeight = elementBox.height;
    const attemptBestFit = (layout2, reposition2, visibleW, visibleH, isVisible2) => {
      const next = layout2(anchorBox, elementBox, bubbles, element2, bounds2);
      const attemptLayout = attempt(next, panelWidth, panelHeight, bounds2);
      return attemptLayout.fold(constant$1(attemptLayout), (newReposition, newVisibleW, newVisibleH, newIsVisible) => {
        const improved = isVisible2 === newIsVisible ? newVisibleH > visibleH || newVisibleW > visibleW : !isVisible2 && newIsVisible;
        return improved ? attemptLayout : adt$8.nofit(reposition2, visibleW, visibleH, isVisible2);
      });
    };
    const abc = foldl(candidates, (b2, a) => {
      const bestNext = curry(attemptBestFit, a);
      return b2.fold(constant$1(b2), bestNext);
    }, adt$8.nofit({
      rect: anchorBox,
      maxHeight: elementBox.height,
      maxWidth: elementBox.width,
      direction: southeast$3(),
      placement: "southeast",
      classes: {
        on: [],
        off: []
      },
      layout: "none",
      testY: anchorBox.y
    }, -1, -1, false));
    return abc.fold(identity, identity);
  };
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke2 = () => subject.get().each(doRevoke);
    const clear2 = () => {
      revoke2();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get2 = () => subject.get();
    const set2 = (s) => {
      revoke2();
      subject.set(Optional.some(s));
    };
    return {
      clear: clear2,
      isSet,
      get: get2,
      set: set2
    };
  };
  const destroyable = () => singleton((s) => s.destroy());
  const unbindable = () => singleton((s) => s.unbind());
  const value$2 = () => {
    const subject = singleton(noop);
    const on2 = (f) => subject.get().each(f);
    return {
      ...subject,
      on: on2
    };
  };
  const filter = always;
  const bind = (element2, event, handler) => bind$2(element2, event, filter, handler);
  const capture = (element2, event, handler) => capture$1(element2, event, filter, handler);
  const fromRawEvent = fromRawEvent$1;
  const properties = [
    "top",
    "bottom",
    "right",
    "left"
  ];
  const timerAttr = "data-alloy-transition-timer";
  const isTransitioning$1 = (element2, transition) => hasAll(element2, transition.classes);
  const shouldApplyTransitionCss = (transition, decision, lastPlacement) => {
    return lastPlacement.exists((placer) => {
      const mode = transition.mode;
      return mode === "all" ? true : placer[mode] !== decision[mode];
    });
  };
  const hasChanges = (position2, intermediate) => {
    const round2 = (value2) => parseFloat(value2).toFixed(3);
    return find$4(intermediate, (value2, key) => {
      const newValue = position2[key].map(round2);
      const val = value2.map(round2);
      return !equals(newValue, val);
    }).isSome();
  };
  const getTransitionDuration = (element2) => {
    const get2 = (name2) => {
      const style = get$e(element2, name2);
      const times = style.split(/\s*,\s*/);
      return filter$2(times, isNotEmpty);
    };
    const parse2 = (value2) => {
      if (isString(value2) && /^[\d.]+/.test(value2)) {
        const num = parseFloat(value2);
        return endsWith(value2, "ms") ? num : num * 1e3;
      } else {
        return 0;
      }
    };
    const delay = get2("transition-delay");
    const duration = get2("transition-duration");
    return foldl(duration, (acc, dur, i) => {
      const time = parse2(delay[i]) + parse2(dur);
      return Math.max(acc, time);
    }, 0);
  };
  const setupTransitionListeners = (element2, transition) => {
    const transitionEnd = unbindable();
    const transitionCancel = unbindable();
    let timer;
    const isSourceTransition = (e) => {
      var _a;
      const pseudoElement = (_a = e.raw.pseudoElement) !== null && _a !== void 0 ? _a : "";
      return eq(e.target, element2) && isEmpty(pseudoElement) && contains$2(properties, e.raw.propertyName);
    };
    const transitionDone = (e) => {
      if (isNullable(e) || isSourceTransition(e)) {
        transitionEnd.clear();
        transitionCancel.clear();
        const type2 = e === null || e === void 0 ? void 0 : e.raw.type;
        if (isNullable(type2) || type2 === transitionend()) {
          clearTimeout(timer);
          remove$7(element2, timerAttr);
          remove$1(element2, transition.classes);
        }
      }
    };
    const transitionStart = bind(element2, transitionstart(), (e) => {
      if (isSourceTransition(e)) {
        transitionStart.unbind();
        transitionEnd.set(bind(element2, transitionend(), transitionDone));
        transitionCancel.set(bind(element2, transitioncancel(), transitionDone));
      }
    });
    const duration = getTransitionDuration(element2);
    requestAnimationFrame(() => {
      timer = setTimeout(transitionDone, duration + 17);
      set$9(element2, timerAttr, timer);
    });
  };
  const startTransitioning = (element2, transition) => {
    add$1(element2, transition.classes);
    getOpt(element2, timerAttr).each((timerId) => {
      clearTimeout(parseInt(timerId, 10));
      remove$7(element2, timerAttr);
    });
    setupTransitionListeners(element2, transition);
  };
  const applyTransitionCss = (element2, origin, position2, transition, decision, lastPlacement) => {
    const shouldTransition = shouldApplyTransitionCss(transition, decision, lastPlacement);
    if (shouldTransition || isTransitioning$1(element2, transition)) {
      set$8(element2, "position", position2.position);
      const rect2 = toBox(origin, element2);
      const intermediatePosition = reposition(origin, {
        ...decision,
        rect: rect2
      });
      const intermediateCssOptions = mapToObject(properties, (prop) => intermediatePosition[prop]);
      if (hasChanges(position2, intermediateCssOptions)) {
        setOptions(element2, intermediateCssOptions);
        if (shouldTransition) {
          startTransitioning(element2, transition);
        }
        reflow(element2);
      }
    } else {
      remove$1(element2, transition.classes);
    }
  };
  const elementSize = (p) => ({
    width: getOuter$1(p),
    height: getOuter$2(p)
  });
  const layout = (anchorBox, element2, bubbles, options) => {
    remove$6(element2, "max-height");
    remove$6(element2, "max-width");
    const elementBox = elementSize(element2);
    return attempts(element2, options.preference, anchorBox, elementBox, bubbles, options.bounds);
  };
  const setClasses = (element2, decision) => {
    const classInfo = decision.classes;
    remove$1(element2, classInfo.off);
    add$1(element2, classInfo.on);
  };
  const setHeight = (element2, decision, options) => {
    const maxHeightFunction = options.maxHeightFunction;
    maxHeightFunction(element2, decision.maxHeight);
  };
  const setWidth = (element2, decision, options) => {
    const maxWidthFunction = options.maxWidthFunction;
    maxWidthFunction(element2, decision.maxWidth);
  };
  const position$2 = (element2, decision, options) => {
    const positionCss = reposition(options.origin, decision);
    options.transition.each((transition) => {
      applyTransitionCss(element2, options.origin, positionCss, transition, decision, options.lastPlacement);
    });
    applyPositionCss(element2, positionCss);
  };
  const setPlacement = (element2, decision) => {
    setPlacement$1(element2, decision.placement);
  };
  const setMaxHeight = (element2, maxHeight) => {
    setMax$1(element2, Math.floor(maxHeight));
  };
  const anchored = constant$1((element2, available) => {
    setMaxHeight(element2, available);
    setAll(element2, {
      "overflow-x": "hidden",
      "overflow-y": "auto"
    });
  });
  const expandable$1 = constant$1((element2, available) => {
    setMaxHeight(element2, available);
  });
  const defaultOr = (options, key, dephault) => options[key] === void 0 ? dephault : options[key];
  const simple = (anchor2, element2, bubble, layouts2, lastPlacement, getBounds2, overrideOptions, transition) => {
    const maxHeightFunction = defaultOr(overrideOptions, "maxHeightFunction", anchored());
    const maxWidthFunction = defaultOr(overrideOptions, "maxWidthFunction", noop);
    const anchorBox = anchor2.anchorBox;
    const origin = anchor2.origin;
    const options = {
      bounds: viewport(origin, getBounds2),
      origin,
      preference: layouts2,
      maxHeightFunction,
      maxWidthFunction,
      lastPlacement,
      transition
    };
    return go(anchorBox, element2, bubble, options);
  };
  const go = (anchorBox, element2, bubble, options) => {
    const decision = layout(anchorBox, element2, bubble, options);
    position$2(element2, decision, options);
    setPlacement(element2, decision);
    setClasses(element2, decision);
    setHeight(element2, decision, options);
    setWidth(element2, decision, options);
    return {
      layout: decision.layout,
      placement: decision.placement
    };
  };
  const allAlignments = [
    "valignCentre",
    "alignLeft",
    "alignRight",
    "alignCentre",
    "top",
    "bottom",
    "left",
    "right",
    "inset"
  ];
  const nu$5 = (xOffset, yOffset, classes2, insetModifier = 1) => {
    const insetXOffset = xOffset * insetModifier;
    const insetYOffset = yOffset * insetModifier;
    const getClasses2 = (prop) => get$g(classes2, prop).getOr([]);
    const make2 = (xDelta, yDelta, alignmentsOn) => {
      const alignmentsOff = difference(allAlignments, alignmentsOn);
      return {
        offset: SugarPosition(xDelta, yDelta),
        classesOn: bind$3(alignmentsOn, getClasses2),
        classesOff: bind$3(alignmentsOff, getClasses2)
      };
    };
    return {
      southeast: () => make2(-xOffset, yOffset, [
        "top",
        "alignLeft"
      ]),
      southwest: () => make2(xOffset, yOffset, [
        "top",
        "alignRight"
      ]),
      south: () => make2(-xOffset / 2, yOffset, [
        "top",
        "alignCentre"
      ]),
      northeast: () => make2(-xOffset, -yOffset, [
        "bottom",
        "alignLeft"
      ]),
      northwest: () => make2(xOffset, -yOffset, [
        "bottom",
        "alignRight"
      ]),
      north: () => make2(-xOffset / 2, -yOffset, [
        "bottom",
        "alignCentre"
      ]),
      east: () => make2(xOffset, -yOffset / 2, [
        "valignCentre",
        "left"
      ]),
      west: () => make2(-xOffset, -yOffset / 2, [
        "valignCentre",
        "right"
      ]),
      insetNortheast: () => make2(insetXOffset, insetYOffset, [
        "top",
        "alignLeft",
        "inset"
      ]),
      insetNorthwest: () => make2(-insetXOffset, insetYOffset, [
        "top",
        "alignRight",
        "inset"
      ]),
      insetNorth: () => make2(-insetXOffset / 2, insetYOffset, [
        "top",
        "alignCentre",
        "inset"
      ]),
      insetSoutheast: () => make2(insetXOffset, -insetYOffset, [
        "bottom",
        "alignLeft",
        "inset"
      ]),
      insetSouthwest: () => make2(-insetXOffset, -insetYOffset, [
        "bottom",
        "alignRight",
        "inset"
      ]),
      insetSouth: () => make2(-insetXOffset / 2, -insetYOffset, [
        "bottom",
        "alignCentre",
        "inset"
      ]),
      insetEast: () => make2(-insetXOffset, -insetYOffset / 2, [
        "valignCentre",
        "right",
        "inset"
      ]),
      insetWest: () => make2(insetXOffset, -insetYOffset / 2, [
        "valignCentre",
        "left",
        "inset"
      ])
    };
  };
  const fallback = () => nu$5(0, 0, {});
  const nu$4 = identity;
  const onDirection = (isLtr, isRtl) => (element2) => getDirection(element2) === "rtl" ? isRtl : isLtr;
  const getDirection = (element2) => get$e(element2, "direction") === "rtl" ? "rtl" : "ltr";
  var AttributeValue;
  (function(AttributeValue2) {
    AttributeValue2["TopToBottom"] = "toptobottom";
    AttributeValue2["BottomToTop"] = "bottomtotop";
  })(AttributeValue || (AttributeValue = {}));
  const Attribute = "data-alloy-vertical-dir";
  const isBottomToTopDir = (el) => closest$2(el, (current) => isElement$1(current) && get$f(current, "data-alloy-vertical-dir") === AttributeValue.BottomToTop);
  const schema$y = () => optionObjOf("layouts", [
    required$1("onLtr"),
    required$1("onRtl"),
    option$3("onBottomLtr"),
    option$3("onBottomRtl")
  ]);
  const get$5 = (elem, info, defaultLtr, defaultRtl, defaultBottomLtr, defaultBottomRtl, dirElement) => {
    const isBottomToTop = dirElement.map(isBottomToTopDir).getOr(false);
    const customLtr = info.layouts.map((ls) => ls.onLtr(elem));
    const customRtl = info.layouts.map((ls) => ls.onRtl(elem));
    const ltr = isBottomToTop ? info.layouts.bind((ls) => ls.onBottomLtr.map((f2) => f2(elem))).or(customLtr).getOr(defaultBottomLtr) : customLtr.getOr(defaultLtr);
    const rtl = isBottomToTop ? info.layouts.bind((ls) => ls.onBottomRtl.map((f2) => f2(elem))).or(customRtl).getOr(defaultBottomRtl) : customRtl.getOr(defaultRtl);
    const f = onDirection(ltr, rtl);
    return f(elem);
  };
  const placement$4 = (component, anchorInfo, origin) => {
    const hotspot = anchorInfo.hotspot;
    const anchorBox = toBox(origin, hotspot.element);
    const layouts2 = get$5(component.element, anchorInfo, belowOrAbove(), belowOrAboveRtl(), aboveOrBelow(), aboveOrBelowRtl(), Optional.some(anchorInfo.hotspot.element));
    return Optional.some(nu$4({
      anchorBox,
      bubble: anchorInfo.bubble.getOr(fallback()),
      overrides: anchorInfo.overrides,
      layouts: layouts2,
      placer: Optional.none()
    }));
  };
  var HotspotAnchor = [
    required$1("hotspot"),
    option$3("bubble"),
    defaulted("overrides", {}),
    schema$y(),
    output$1("placement", placement$4)
  ];
  const placement$3 = (component, anchorInfo, origin) => {
    const pos = translate$2(origin, anchorInfo.x, anchorInfo.y);
    const anchorBox = bounds(pos.left, pos.top, anchorInfo.width, anchorInfo.height);
    const layouts2 = get$5(component.element, anchorInfo, all$1(), allRtl$1(), all$1(), allRtl$1(), Optional.none());
    return Optional.some(nu$4({
      anchorBox,
      bubble: anchorInfo.bubble,
      overrides: anchorInfo.overrides,
      layouts: layouts2,
      placer: Optional.none()
    }));
  };
  var MakeshiftAnchor = [
    required$1("x"),
    required$1("y"),
    defaulted("height", 0),
    defaulted("width", 0),
    defaulted("bubble", fallback()),
    defaulted("overrides", {}),
    schema$y(),
    output$1("placement", placement$3)
  ];
  const adt$7 = Adt.generate([
    { screen: ["point"] },
    {
      absolute: [
        "point",
        "scrollLeft",
        "scrollTop"
      ]
    }
  ]);
  const toFixed = (pos) => pos.fold(identity, (point2, scrollLeft, scrollTop) => point2.translate(-scrollLeft, -scrollTop));
  const toAbsolute = (pos) => pos.fold(identity, identity);
  const sum = (points) => foldl(points, (b2, a) => b2.translate(a.left, a.top), SugarPosition(0, 0));
  const sumAsFixed = (positions) => {
    const points = map$2(positions, toFixed);
    return sum(points);
  };
  const sumAsAbsolute = (positions) => {
    const points = map$2(positions, toAbsolute);
    return sum(points);
  };
  const screen = adt$7.screen;
  const absolute$1 = adt$7.absolute;
  const getOffset = (component, origin, anchorInfo) => {
    const win2 = defaultView(anchorInfo.root).dom;
    const hasSameOwner = (frame) => {
      const frameOwner = owner$4(frame);
      const compOwner = owner$4(component.element);
      return eq(frameOwner, compOwner);
    };
    return Optional.from(win2.frameElement).map(SugarElement.fromDom).filter(hasSameOwner).map(absolute$3);
  };
  const getRootPoint = (component, origin, anchorInfo) => {
    const doc = owner$4(component.element);
    const outerScroll = get$b(doc);
    const offset2 = getOffset(component, origin, anchorInfo).getOr(outerScroll);
    return absolute$1(offset2, outerScroll.left, outerScroll.top);
  };
  const getBox = (left2, top2, width2, height2) => {
    const point2 = screen(SugarPosition(left2, top2));
    return Optional.some(pointed(point2, width2, height2));
  };
  const calcNewAnchor = (optBox, rootPoint, anchorInfo, origin, elem) => optBox.map((box2) => {
    const points = [
      rootPoint,
      box2.point
    ];
    const topLeft = cata$1(origin, () => sumAsAbsolute(points), () => sumAsAbsolute(points), () => sumAsFixed(points));
    const anchorBox = rect(topLeft.left, topLeft.top, box2.width, box2.height);
    const layoutsLtr = anchorInfo.showAbove ? aboveOrBelow() : belowOrAbove();
    const layoutsRtl = anchorInfo.showAbove ? aboveOrBelowRtl() : belowOrAboveRtl();
    const layouts2 = get$5(elem, anchorInfo, layoutsLtr, layoutsRtl, layoutsLtr, layoutsRtl, Optional.none());
    return nu$4({
      anchorBox,
      bubble: anchorInfo.bubble.getOr(fallback()),
      overrides: anchorInfo.overrides,
      layouts: layouts2,
      placer: Optional.none()
    });
  });
  const placement$2 = (component, anchorInfo, origin) => {
    const rootPoint = getRootPoint(component, origin, anchorInfo);
    return anchorInfo.node.filter(inBody).bind((target) => {
      const rect2 = target.dom.getBoundingClientRect();
      const nodeBox = getBox(rect2.left, rect2.top, rect2.width, rect2.height);
      const elem = anchorInfo.node.getOr(component.element);
      return calcNewAnchor(nodeBox, rootPoint, anchorInfo, origin, elem);
    });
  };
  var NodeAnchor = [
    required$1("node"),
    required$1("root"),
    option$3("bubble"),
    schema$y(),
    defaulted("overrides", {}),
    defaulted("showAbove", false),
    output$1("placement", placement$2)
  ];
  const zeroWidth = "\uFEFF";
  const nbsp = "\xA0";
  const create$2 = (start, soffset, finish, foffset) => ({
    start,
    soffset,
    finish,
    foffset
  });
  const SimRange = { create: create$2 };
  const adt$6 = Adt.generate([
    { before: ["element"] },
    {
      on: [
        "element",
        "offset"
      ]
    },
    { after: ["element"] }
  ]);
  const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
  const getStart$1 = (situ) => situ.fold(identity, identity, identity);
  const before = adt$6.before;
  const on$1 = adt$6.on;
  const after$1 = adt$6.after;
  const Situ = {
    before,
    on: on$1,
    after: after$1,
    cata,
    getStart: getStart$1
  };
  const adt$5 = Adt.generate([
    { domRange: ["rng"] },
    {
      relative: [
        "startSitu",
        "finishSitu"
      ]
    },
    {
      exact: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    }
  ]);
  const exactFromRange = (simRange) => adt$5.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
  const getStart = (selection) => selection.match({
    domRange: (rng) => SugarElement.fromDom(rng.startContainer),
    relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
    exact: (start, _soffset, _finish, _foffset) => start
  });
  const domRange = adt$5.domRange;
  const relative = adt$5.relative;
  const exact = adt$5.exact;
  const getWin = (selection) => {
    const start = getStart(selection);
    return defaultView(start);
  };
  const range$1 = SimRange.create;
  const SimSelection = {
    domRange,
    relative,
    exact,
    exactFromRange,
    getWin,
    range: range$1
  };
  const setStart = (rng, situ) => {
    situ.fold((e) => {
      rng.setStartBefore(e.dom);
    }, (e, o) => {
      rng.setStart(e.dom, o);
    }, (e) => {
      rng.setStartAfter(e.dom);
    });
  };
  const setFinish = (rng, situ) => {
    situ.fold((e) => {
      rng.setEndBefore(e.dom);
    }, (e, o) => {
      rng.setEnd(e.dom, o);
    }, (e) => {
      rng.setEndAfter(e.dom);
    });
  };
  const relativeToNative = (win2, startSitu, finishSitu) => {
    const range2 = win2.document.createRange();
    setStart(range2, startSitu);
    setFinish(range2, finishSitu);
    return range2;
  };
  const exactToNative = (win2, start, soffset, finish, foffset) => {
    const rng = win2.document.createRange();
    rng.setStart(start.dom, soffset);
    rng.setEnd(finish.dom, foffset);
    return rng;
  };
  const toRect = (rect2) => ({
    left: rect2.left,
    top: rect2.top,
    right: rect2.right,
    bottom: rect2.bottom,
    width: rect2.width,
    height: rect2.height
  });
  const getFirstRect$1 = (rng) => {
    const rects = rng.getClientRects();
    const rect2 = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
    return rect2.width > 0 || rect2.height > 0 ? Optional.some(rect2).map(toRect) : Optional.none();
  };
  const getBounds$2 = (rng) => {
    const rect2 = rng.getBoundingClientRect();
    return rect2.width > 0 || rect2.height > 0 ? Optional.some(rect2).map(toRect) : Optional.none();
  };
  const adt$4 = Adt.generate([
    {
      ltr: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    },
    {
      rtl: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    }
  ]);
  const fromRange = (win2, type2, range2) => type2(SugarElement.fromDom(range2.startContainer), range2.startOffset, SugarElement.fromDom(range2.endContainer), range2.endOffset);
  const getRanges = (win2, selection) => selection.match({
    domRange: (rng) => {
      return {
        ltr: constant$1(rng),
        rtl: Optional.none
      };
    },
    relative: (startSitu, finishSitu) => {
      return {
        ltr: cached(() => relativeToNative(win2, startSitu, finishSitu)),
        rtl: cached(() => Optional.some(relativeToNative(win2, finishSitu, startSitu)))
      };
    },
    exact: (start, soffset, finish, foffset) => {
      return {
        ltr: cached(() => exactToNative(win2, start, soffset, finish, foffset)),
        rtl: cached(() => Optional.some(exactToNative(win2, finish, foffset, start, soffset)))
      };
    }
  });
  const doDiagnose = (win2, ranges) => {
    const rng = ranges.ltr();
    if (rng.collapsed) {
      const reversed = ranges.rtl().filter((rev) => rev.collapsed === false);
      return reversed.map((rev) => adt$4.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win2, adt$4.ltr, rng));
    } else {
      return fromRange(win2, adt$4.ltr, rng);
    }
  };
  const diagnose = (win2, selection) => {
    const ranges = getRanges(win2, selection);
    return doDiagnose(win2, ranges);
  };
  const asLtrRange = (win2, selection) => {
    const diagnosis = diagnose(win2, selection);
    return diagnosis.match({
      ltr: (start, soffset, finish, foffset) => {
        const rng = win2.document.createRange();
        rng.setStart(start.dom, soffset);
        rng.setEnd(finish.dom, foffset);
        return rng;
      },
      rtl: (start, soffset, finish, foffset) => {
        const rng = win2.document.createRange();
        rng.setStart(finish.dom, foffset);
        rng.setEnd(start.dom, soffset);
        return rng;
      }
    });
  };
  adt$4.ltr;
  adt$4.rtl;
  const descendants = (scope, selector) => all$3(selector, scope);
  const makeRange = (start, soffset, finish, foffset) => {
    const doc = owner$4(start);
    const rng = doc.dom.createRange();
    rng.setStart(start.dom, soffset);
    rng.setEnd(finish.dom, foffset);
    return rng;
  };
  const after = (start, soffset, finish, foffset) => {
    const r2 = makeRange(start, soffset, finish, foffset);
    const same = eq(start, finish) && soffset === foffset;
    return r2.collapsed && !same;
  };
  const getNativeSelection = (win2) => Optional.from(win2.getSelection());
  const readRange = (selection) => {
    if (selection.rangeCount > 0) {
      const firstRng = selection.getRangeAt(0);
      const lastRng = selection.getRangeAt(selection.rangeCount - 1);
      return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
    } else {
      return Optional.none();
    }
  };
  const doGetExact = (selection) => {
    if (selection.anchorNode === null || selection.focusNode === null) {
      return readRange(selection);
    } else {
      const anchor2 = SugarElement.fromDom(selection.anchorNode);
      const focus2 = SugarElement.fromDom(selection.focusNode);
      return after(anchor2, selection.anchorOffset, focus2, selection.focusOffset) ? Optional.some(SimRange.create(anchor2, selection.anchorOffset, focus2, selection.focusOffset)) : readRange(selection);
    }
  };
  const getExact = (win2) => getNativeSelection(win2).filter((sel) => sel.rangeCount > 0).bind(doGetExact);
  const getFirstRect = (win2, selection) => {
    const rng = asLtrRange(win2, selection);
    return getFirstRect$1(rng);
  };
  const getBounds$1 = (win2, selection) => {
    const rng = asLtrRange(win2, selection);
    return getBounds$2(rng);
  };
  const NodeValue = (is2, name2) => {
    const get2 = (element2) => {
      if (!is2(element2)) {
        throw new Error("Can only get " + name2 + " value of a " + name2 + " node");
      }
      return getOption(element2).getOr("");
    };
    const getOption = (element2) => is2(element2) ? Optional.from(element2.dom.nodeValue) : Optional.none();
    const set2 = (element2, value2) => {
      if (!is2(element2)) {
        throw new Error("Can only set raw " + name2 + " value of a " + name2 + " node");
      }
      element2.dom.nodeValue = value2;
    };
    return {
      get: get2,
      getOption,
      set: set2
    };
  };
  const api = NodeValue(isText, "text");
  const get$4 = (element2) => api.get(element2);
  const point = (element2, offset2) => ({
    element: element2,
    offset: offset2
  });
  const descendOnce$1 = (element2, offset2) => {
    const children$1 = children(element2);
    if (children$1.length === 0) {
      return point(element2, offset2);
    } else if (offset2 < children$1.length) {
      return point(children$1[offset2], 0);
    } else {
      const last2 = children$1[children$1.length - 1];
      const len = isText(last2) ? get$4(last2).length : children(last2).length;
      return point(last2, len);
    }
  };
  const descendOnce = (element2, offset2) => isText(element2) ? point(element2, offset2) : descendOnce$1(element2, offset2);
  const getAnchorSelection = (win2, anchorInfo) => {
    const getSelection = anchorInfo.getSelection.getOrThunk(() => () => getExact(win2));
    return getSelection().map((sel) => {
      const modStart = descendOnce(sel.start, sel.soffset);
      const modFinish = descendOnce(sel.finish, sel.foffset);
      return SimSelection.range(modStart.element, modStart.offset, modFinish.element, modFinish.offset);
    });
  };
  const placement$1 = (component, anchorInfo, origin) => {
    const win2 = defaultView(anchorInfo.root).dom;
    const rootPoint = getRootPoint(component, origin, anchorInfo);
    const selectionBox = getAnchorSelection(win2, anchorInfo).bind((sel) => {
      const optRect = getBounds$1(win2, SimSelection.exactFromRange(sel)).orThunk(() => {
        const x = SugarElement.fromText(zeroWidth);
        before$1(sel.start, x);
        const rect2 = getFirstRect(win2, SimSelection.exact(x, 0, x, 1));
        remove$5(x);
        return rect2;
      });
      return optRect.bind((rawRect) => getBox(rawRect.left, rawRect.top, rawRect.width, rawRect.height));
    });
    const targetElement = getAnchorSelection(win2, anchorInfo).bind((sel) => isElement$1(sel.start) ? Optional.some(sel.start) : parentElement(sel.start));
    const elem = targetElement.getOr(component.element);
    return calcNewAnchor(selectionBox, rootPoint, anchorInfo, origin, elem);
  };
  var SelectionAnchor = [
    option$3("getSelection"),
    required$1("root"),
    option$3("bubble"),
    schema$y(),
    defaulted("overrides", {}),
    defaulted("showAbove", false),
    output$1("placement", placement$1)
  ];
  const labelPrefix$1 = "link-layout";
  const eastX = (anchor2) => anchor2.x + anchor2.width;
  const westX = (anchor2, element2) => anchor2.x - element2.width;
  const northY$1 = (anchor2, element2) => anchor2.y - element2.height + anchor2.height;
  const southY$1 = (anchor2) => anchor2.y;
  const southeast$1 = (anchor2, element2, bubbles) => nu$6(eastX(anchor2), southY$1(anchor2), bubbles.southeast(), southeast$3(), "southeast", boundsRestriction(anchor2, {
    left: 0,
    top: 2
  }), labelPrefix$1);
  const southwest$1 = (anchor2, element2, bubbles) => nu$6(westX(anchor2, element2), southY$1(anchor2), bubbles.southwest(), southwest$3(), "southwest", boundsRestriction(anchor2, {
    right: 1,
    top: 2
  }), labelPrefix$1);
  const northeast$1 = (anchor2, element2, bubbles) => nu$6(eastX(anchor2), northY$1(anchor2, element2), bubbles.northeast(), northeast$3(), "northeast", boundsRestriction(anchor2, {
    left: 0,
    bottom: 3
  }), labelPrefix$1);
  const northwest$1 = (anchor2, element2, bubbles) => nu$6(westX(anchor2, element2), northY$1(anchor2, element2), bubbles.northwest(), northwest$3(), "northwest", boundsRestriction(anchor2, {
    right: 1,
    bottom: 3
  }), labelPrefix$1);
  const all = () => [
    southeast$1,
    southwest$1,
    northeast$1,
    northwest$1
  ];
  const allRtl = () => [
    southwest$1,
    southeast$1,
    northwest$1,
    northeast$1
  ];
  const placement = (component, submenuInfo, origin) => {
    const anchorBox = toBox(origin, submenuInfo.item.element);
    const layouts2 = get$5(component.element, submenuInfo, all(), allRtl(), all(), allRtl(), Optional.none());
    return Optional.some(nu$4({
      anchorBox,
      bubble: fallback(),
      overrides: submenuInfo.overrides,
      layouts: layouts2,
      placer: Optional.none()
    }));
  };
  var SubmenuAnchor = [
    required$1("item"),
    schema$y(),
    defaulted("overrides", {}),
    output$1("placement", placement)
  ];
  var AnchorSchema = choose$1("type", {
    selection: SelectionAnchor,
    node: NodeAnchor,
    hotspot: HotspotAnchor,
    submenu: SubmenuAnchor,
    makeshift: MakeshiftAnchor
  });
  const TransitionSchema = [
    requiredArrayOf("classes", string),
    defaultedStringEnum("mode", "all", [
      "all",
      "layout",
      "placement"
    ])
  ];
  const PositionSchema = [
    defaulted("useFixed", never),
    option$3("getBounds")
  ];
  const PlacementSchema = [
    requiredOf("anchor", AnchorSchema),
    optionObjOf("transition", TransitionSchema)
  ];
  const getFixedOrigin = () => {
    const html = document.documentElement;
    return fixed$1(0, 0, html.clientWidth, html.clientHeight);
  };
  const getRelativeOrigin = (component) => {
    const position2 = absolute$3(component.element);
    const bounds2 = component.element.dom.getBoundingClientRect();
    return relative$1(position2.left, position2.top, bounds2.width, bounds2.height);
  };
  const place = (component, origin, anchoring, getBounds2, placee, lastPlace, transition) => {
    const anchor2 = box(anchoring.anchorBox, origin);
    return simple(anchor2, placee.element, anchoring.bubble, anchoring.layouts, lastPlace, getBounds2, anchoring.overrides, transition);
  };
  const position$1 = (component, posConfig, posState, placee, placementSpec) => {
    positionWithin(component, posConfig, posState, placee, placementSpec, Optional.none());
  };
  const positionWithin = (component, posConfig, posState, placee, placementSpec, boxElement) => {
    const boundsBox = boxElement.map(box$1);
    return positionWithinBounds(component, posConfig, posState, placee, placementSpec, boundsBox);
  };
  const positionWithinBounds = (component, posConfig, posState, placee, placementSpec, bounds2) => {
    const placeeDetail = asRawOrDie$1("placement.info", objOf(PlacementSchema), placementSpec);
    const anchorage = placeeDetail.anchor;
    const element2 = placee.element;
    const placeeState = posState.get(placee.uid);
    preserve$1(() => {
      set$8(element2, "position", "fixed");
      const oldVisibility = getRaw(element2, "visibility");
      set$8(element2, "visibility", "hidden");
      const origin = posConfig.useFixed() ? getFixedOrigin() : getRelativeOrigin(component);
      const placer = anchorage.placement;
      const getBounds2 = bounds2.map(constant$1).or(posConfig.getBounds);
      placer(component, anchorage, origin).each((anchoring) => {
        const doPlace = anchoring.placer.getOr(place);
        const newState = doPlace(component, origin, anchoring, getBounds2, placee, placeeState, placeeDetail.transition);
        posState.set(placee.uid, newState);
      });
      oldVisibility.fold(() => {
        remove$6(element2, "visibility");
      }, (vis) => {
        set$8(element2, "visibility", vis);
      });
      if (getRaw(element2, "left").isNone() && getRaw(element2, "top").isNone() && getRaw(element2, "right").isNone() && getRaw(element2, "bottom").isNone() && is$1(getRaw(element2, "position"), "fixed")) {
        remove$6(element2, "position");
      }
    }, element2);
  };
  const getMode = (component, pConfig, _pState) => pConfig.useFixed() ? "fixed" : "absolute";
  const reset$1 = (component, pConfig, posState, placee) => {
    const element2 = placee.element;
    each$1([
      "position",
      "left",
      "right",
      "top",
      "bottom"
    ], (prop) => remove$6(element2, prop));
    reset$2(element2);
    posState.clear(placee.uid);
  };
  var PositionApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    position: position$1,
    positionWithin,
    positionWithinBounds,
    getMode,
    reset: reset$1
  });
  const init$g = () => {
    let state = {};
    const set2 = (id, data) => {
      state[id] = data;
    };
    const get2 = (id) => get$g(state, id);
    const clear2 = (id) => {
      if (isNonNullable(id)) {
        delete state[id];
      } else {
        state = {};
      }
    };
    return nu$8({
      readState: () => state,
      clear: clear2,
      set: set2,
      get: get2
    });
  };
  var PositioningState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$g
  });
  const Positioning = create$3({
    fields: PositionSchema,
    name: "positioning",
    active: ActivePosition,
    apis: PositionApis,
    state: PositioningState
  });
  const isConnected = (comp) => comp.getSystem().isConnected();
  const fireDetaching = (component) => {
    emit(component, detachedFromDom());
    const children2 = component.components();
    each$1(children2, fireDetaching);
  };
  const fireAttaching = (component) => {
    const children2 = component.components();
    each$1(children2, fireAttaching);
    emit(component, attachedToDom());
  };
  const virtualAttach = (parent2, child2) => {
    parent2.getSystem().addToWorld(child2);
    if (inBody(parent2.element)) {
      fireAttaching(child2);
    }
  };
  const virtualDetach = (comp) => {
    fireDetaching(comp);
    comp.getSystem().removeFromWorld(comp);
  };
  const attach$1 = (parent2, child2) => {
    append$2(parent2.element, child2.element);
  };
  const detachChildren$1 = (component) => {
    each$1(component.components(), (childComp) => remove$5(childComp.element));
    empty(component.element);
    component.syncComponents();
  };
  const replaceChildren = (component, newSpecs, buildNewChildren) => {
    const subs2 = component.components();
    detachChildren$1(component);
    const newChildren = buildNewChildren(newSpecs);
    const deleted = difference(subs2, newChildren);
    each$1(deleted, (comp) => {
      fireDetaching(comp);
      component.getSystem().removeFromWorld(comp);
    });
    each$1(newChildren, (childComp) => {
      if (!isConnected(childComp)) {
        component.getSystem().addToWorld(childComp);
        attach$1(component, childComp);
        if (inBody(component.element)) {
          fireAttaching(childComp);
        }
      } else {
        attach$1(component, childComp);
      }
    });
    component.syncComponents();
  };
  const virtualReplaceChildren = (component, newSpecs, buildNewChildren) => {
    const subs2 = component.components();
    const existingComps = bind$3(newSpecs, (spec) => getPremade(spec).toArray());
    each$1(subs2, (childComp) => {
      if (!contains$2(existingComps, childComp)) {
        virtualDetach(childComp);
      }
    });
    const newChildren = buildNewChildren(newSpecs);
    const deleted = difference(subs2, newChildren);
    each$1(deleted, (deletedComp) => {
      if (isConnected(deletedComp)) {
        virtualDetach(deletedComp);
      }
    });
    each$1(newChildren, (childComp) => {
      if (!isConnected(childComp)) {
        virtualAttach(component, childComp);
      }
    });
    component.syncComponents();
  };
  const attach = (parent2, child2) => {
    attachWith(parent2, child2, append$2);
  };
  const attachWith = (parent2, child2, insertion) => {
    parent2.getSystem().addToWorld(child2);
    insertion(parent2.element, child2.element);
    if (inBody(parent2.element)) {
      fireAttaching(child2);
    }
    parent2.syncComponents();
  };
  const doDetach = (component) => {
    fireDetaching(component);
    remove$5(component.element);
    component.getSystem().removeFromWorld(component);
  };
  const detach = (component) => {
    const parent$1 = parent(component.element).bind((p) => component.getSystem().getByDom(p).toOptional());
    doDetach(component);
    parent$1.each((p) => {
      p.syncComponents();
    });
  };
  const detachChildren = (component) => {
    const subs2 = component.components();
    each$1(subs2, doDetach);
    empty(component.element);
    component.syncComponents();
  };
  const attachSystem = (element2, guiSystem) => {
    attachSystemWith(element2, guiSystem, append$2);
  };
  const attachSystemAfter = (element2, guiSystem) => {
    attachSystemWith(element2, guiSystem, after$2);
  };
  const attachSystemWith = (element2, guiSystem, inserter) => {
    inserter(element2, guiSystem.element);
    const children$1 = children(guiSystem.element);
    each$1(children$1, (child2) => {
      guiSystem.getByDom(child2).each(fireAttaching);
    });
  };
  const detachSystem = (guiSystem) => {
    const children$1 = children(guiSystem.element);
    each$1(children$1, (child2) => {
      guiSystem.getByDom(child2).each(fireDetaching);
    });
    remove$5(guiSystem.element);
  };
  const rebuild = (sandbox, sConfig, sState, data) => {
    sState.get().each((_data) => {
      detachChildren(sandbox);
    });
    const point2 = sConfig.getAttachPoint(sandbox);
    attach(point2, sandbox);
    const built = sandbox.getSystem().build(data);
    attach(sandbox, built);
    sState.set(built);
    return built;
  };
  const open$1 = (sandbox, sConfig, sState, data) => {
    const newState = rebuild(sandbox, sConfig, sState, data);
    sConfig.onOpen(sandbox, newState);
    return newState;
  };
  const setContent = (sandbox, sConfig, sState, data) => sState.get().map(() => rebuild(sandbox, sConfig, sState, data));
  const openWhileCloaked = (sandbox, sConfig, sState, data, transaction) => {
    cloak(sandbox, sConfig);
    open$1(sandbox, sConfig, sState, data);
    transaction();
    decloak(sandbox, sConfig);
  };
  const close$1 = (sandbox, sConfig, sState) => {
    sState.get().each((data) => {
      detachChildren(sandbox);
      detach(sandbox);
      sConfig.onClose(sandbox, data);
      sState.clear();
    });
  };
  const isOpen$1 = (_sandbox, _sConfig, sState) => sState.isOpen();
  const isPartOf = (sandbox, sConfig, sState, queryElem) => isOpen$1(sandbox, sConfig, sState) && sState.get().exists((data) => sConfig.isPartOf(sandbox, data, queryElem));
  const getState$2 = (_sandbox, _sConfig, sState) => sState.get();
  const store = (sandbox, cssKey, attr, newValue) => {
    getRaw(sandbox.element, cssKey).fold(() => {
      remove$7(sandbox.element, attr);
    }, (v) => {
      set$9(sandbox.element, attr, v);
    });
    set$8(sandbox.element, cssKey, newValue);
  };
  const restore = (sandbox, cssKey, attr) => {
    getOpt(sandbox.element, attr).fold(() => remove$6(sandbox.element, cssKey), (oldValue) => set$8(sandbox.element, cssKey, oldValue));
  };
  const cloak = (sandbox, sConfig, _sState) => {
    const sink = sConfig.getAttachPoint(sandbox);
    set$8(sandbox.element, "position", Positioning.getMode(sink));
    store(sandbox, "visibility", sConfig.cloakVisibilityAttr, "hidden");
  };
  const hasPosition = (element2) => exists([
    "top",
    "left",
    "right",
    "bottom"
  ], (pos) => getRaw(element2, pos).isSome());
  const decloak = (sandbox, sConfig, _sState) => {
    if (!hasPosition(sandbox.element)) {
      remove$6(sandbox.element, "position");
    }
    restore(sandbox, "visibility", sConfig.cloakVisibilityAttr);
  };
  var SandboxApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    cloak,
    decloak,
    open: open$1,
    openWhileCloaked,
    close: close$1,
    isOpen: isOpen$1,
    isPartOf,
    getState: getState$2,
    setContent
  });
  const events$g = (sandboxConfig, sandboxState) => derive$2([run$1(sandboxClose(), (sandbox, _simulatedEvent) => {
    close$1(sandbox, sandboxConfig, sandboxState);
  })]);
  var ActiveSandbox = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$g
  });
  var SandboxSchema = [
    onHandler("onOpen"),
    onHandler("onClose"),
    required$1("isPartOf"),
    required$1("getAttachPoint"),
    defaulted("cloakVisibilityAttr", "data-precloak-visibility")
  ];
  const init$f = () => {
    const contents2 = value$2();
    const readState = constant$1("not-implemented");
    return nu$8({
      readState,
      isOpen: contents2.isSet,
      clear: contents2.clear,
      set: contents2.set,
      get: contents2.get
    });
  };
  var SandboxState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$f
  });
  const Sandboxing = create$3({
    fields: SandboxSchema,
    name: "sandboxing",
    active: ActiveSandbox,
    apis: SandboxApis,
    state: SandboxState
  });
  const dismissPopups = constant$1("dismiss.popups");
  const repositionPopups = constant$1("reposition.popups");
  const mouseReleased = constant$1("mouse.released");
  const schema$x = objOfOnly([
    defaulted("isExtraPart", never),
    optionObjOf("fireEventInstead", [defaulted("event", dismissRequested())])
  ]);
  const receivingChannel$1 = (rawSpec) => {
    const detail = asRawOrDie$1("Dismissal", schema$x, rawSpec);
    return {
      [dismissPopups()]: {
        schema: objOfOnly([required$1("target")]),
        onReceive: (sandbox, data) => {
          if (Sandboxing.isOpen(sandbox)) {
            const isPart = Sandboxing.isPartOf(sandbox, data.target) || detail.isExtraPart(sandbox, data.target);
            if (!isPart) {
              detail.fireEventInstead.fold(() => Sandboxing.close(sandbox), (fe) => emit(sandbox, fe.event));
            }
          }
        }
      }
    };
  };
  const schema$w = objOfOnly([
    optionObjOf("fireEventInstead", [defaulted("event", repositionRequested())]),
    requiredFunction("doReposition")
  ]);
  const receivingChannel = (rawSpec) => {
    const detail = asRawOrDie$1("Reposition", schema$w, rawSpec);
    return {
      [repositionPopups()]: {
        onReceive: (sandbox) => {
          if (Sandboxing.isOpen(sandbox)) {
            detail.fireEventInstead.fold(() => detail.doReposition(sandbox), (fe) => emit(sandbox, fe.event));
          }
        }
      }
    };
  };
  const onLoad$5 = (component, repConfig, repState) => {
    repConfig.store.manager.onLoad(component, repConfig, repState);
  };
  const onUnload$2 = (component, repConfig, repState) => {
    repConfig.store.manager.onUnload(component, repConfig, repState);
  };
  const setValue$3 = (component, repConfig, repState, data) => {
    repConfig.store.manager.setValue(component, repConfig, repState, data);
  };
  const getValue$3 = (component, repConfig, repState) => repConfig.store.manager.getValue(component, repConfig, repState);
  const getState$1 = (component, repConfig, repState) => repState;
  var RepresentApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    onLoad: onLoad$5,
    onUnload: onUnload$2,
    setValue: setValue$3,
    getValue: getValue$3,
    getState: getState$1
  });
  const events$f = (repConfig, repState) => {
    const es = repConfig.resetOnDom ? [
      runOnAttached((comp, _se) => {
        onLoad$5(comp, repConfig, repState);
      }),
      runOnDetached((comp, _se) => {
        onUnload$2(comp, repConfig, repState);
      })
    ] : [loadEvent(repConfig, repState, onLoad$5)];
    return derive$2(es);
  };
  var ActiveRepresenting = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$f
  });
  const memory$1 = () => {
    const data = Cell(null);
    const readState = () => ({
      mode: "memory",
      value: data.get()
    });
    const isNotSet = () => data.get() === null;
    const clear2 = () => {
      data.set(null);
    };
    return nu$8({
      set: data.set,
      get: data.get,
      isNotSet,
      clear: clear2,
      readState
    });
  };
  const manual = () => {
    const readState = noop;
    return nu$8({ readState });
  };
  const dataset = () => {
    const dataByValue = Cell({});
    const dataByText = Cell({});
    const readState = () => ({
      mode: "dataset",
      dataByValue: dataByValue.get(),
      dataByText: dataByText.get()
    });
    const clear2 = () => {
      dataByValue.set({});
      dataByText.set({});
    };
    const lookup2 = (itemString) => get$g(dataByValue.get(), itemString).orThunk(() => get$g(dataByText.get(), itemString));
    const update = (items) => {
      const currentDataByValue = dataByValue.get();
      const currentDataByText = dataByText.get();
      const newDataByValue = {};
      const newDataByText = {};
      each$1(items, (item2) => {
        newDataByValue[item2.value] = item2;
        get$g(item2, "meta").each((meta) => {
          get$g(meta, "text").each((text2) => {
            newDataByText[text2] = item2;
          });
        });
      });
      dataByValue.set({
        ...currentDataByValue,
        ...newDataByValue
      });
      dataByText.set({
        ...currentDataByText,
        ...newDataByText
      });
    };
    return nu$8({
      readState,
      lookup: lookup2,
      update,
      clear: clear2
    });
  };
  const init$e = (spec) => spec.store.manager.state(spec);
  var RepresentState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    memory: memory$1,
    dataset,
    manual,
    init: init$e
  });
  const setValue$2 = (component, repConfig, repState, data) => {
    const store2 = repConfig.store;
    repState.update([data]);
    store2.setValue(component, data);
    repConfig.onSetValue(component, data);
  };
  const getValue$2 = (component, repConfig, repState) => {
    const store2 = repConfig.store;
    const key = store2.getDataKey(component);
    return repState.lookup(key).getOrThunk(() => store2.getFallbackEntry(key));
  };
  const onLoad$4 = (component, repConfig, repState) => {
    const store2 = repConfig.store;
    store2.initialValue.each((data) => {
      setValue$2(component, repConfig, repState, data);
    });
  };
  const onUnload$1 = (component, repConfig, repState) => {
    repState.clear();
  };
  var DatasetStore = [
    option$3("initialValue"),
    required$1("getFallbackEntry"),
    required$1("getDataKey"),
    required$1("setValue"),
    output$1("manager", {
      setValue: setValue$2,
      getValue: getValue$2,
      onLoad: onLoad$4,
      onUnload: onUnload$1,
      state: dataset
    })
  ];
  const getValue$1 = (component, repConfig, _repState) => repConfig.store.getValue(component);
  const setValue$1 = (component, repConfig, _repState, data) => {
    repConfig.store.setValue(component, data);
    repConfig.onSetValue(component, data);
  };
  const onLoad$3 = (component, repConfig, _repState) => {
    repConfig.store.initialValue.each((data) => {
      repConfig.store.setValue(component, data);
    });
  };
  var ManualStore = [
    required$1("getValue"),
    defaulted("setValue", noop),
    option$3("initialValue"),
    output$1("manager", {
      setValue: setValue$1,
      getValue: getValue$1,
      onLoad: onLoad$3,
      onUnload: noop,
      state: NoState.init
    })
  ];
  const setValue = (component, repConfig, repState, data) => {
    repState.set(data);
    repConfig.onSetValue(component, data);
  };
  const getValue = (component, repConfig, repState) => repState.get();
  const onLoad$2 = (component, repConfig, repState) => {
    repConfig.store.initialValue.each((initVal) => {
      if (repState.isNotSet()) {
        repState.set(initVal);
      }
    });
  };
  const onUnload = (component, repConfig, repState) => {
    repState.clear();
  };
  var MemoryStore = [
    option$3("initialValue"),
    output$1("manager", {
      setValue,
      getValue,
      onLoad: onLoad$2,
      onUnload,
      state: memory$1
    })
  ];
  var RepresentSchema = [
    defaultedOf("store", { mode: "memory" }, choose$1("mode", {
      memory: MemoryStore,
      manual: ManualStore,
      dataset: DatasetStore
    })),
    onHandler("onSetValue"),
    defaulted("resetOnDom", false)
  ];
  const Representing = create$3({
    fields: RepresentSchema,
    name: "representing",
    active: ActiveRepresenting,
    apis: RepresentApis,
    extra: {
      setValueFrom: (component, source) => {
        const value2 = Representing.getValue(source);
        Representing.setValue(component, value2);
      }
    },
    state: RepresentState
  });
  const field = (name2, forbidden) => defaultedObjOf(name2, {}, map$2(forbidden, (f) => forbid(f.name(), "Cannot configure " + f.name() + " for " + name2)).concat([customField("dump", identity)]));
  const get$3 = (data) => data.dump;
  const augment = (data, original2) => ({
    ...derive$1(original2),
    ...data.dump
  });
  const SketchBehaviours = {
    field,
    augment,
    get: get$3
  };
  const _placeholder = "placeholder";
  const adt$3 = Adt.generate([
    {
      single: [
        "required",
        "valueThunk"
      ]
    },
    {
      multiple: [
        "required",
        "valueThunks"
      ]
    }
  ]);
  const isSubstituted = (spec) => has$2(spec, "uiType");
  const subPlaceholder = (owner2, detail, compSpec, placeholders) => {
    if (owner2.exists((o) => o !== compSpec.owner)) {
      return adt$3.single(true, constant$1(compSpec));
    }
    return get$g(placeholders, compSpec.name).fold(() => {
      throw new Error("Unknown placeholder component: " + compSpec.name + "\nKnown: [" + keys(placeholders) + "]\nNamespace: " + owner2.getOr("none") + "\nSpec: " + JSON.stringify(compSpec, null, 2));
    }, (newSpec) => newSpec.replace());
  };
  const scan = (owner2, detail, compSpec, placeholders) => {
    if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
      return subPlaceholder(owner2, detail, compSpec, placeholders);
    } else {
      return adt$3.single(false, constant$1(compSpec));
    }
  };
  const substitute = (owner2, detail, compSpec, placeholders) => {
    const base2 = scan(owner2, detail, compSpec, placeholders);
    return base2.fold((req, valueThunk2) => {
      const value2 = isSubstituted(compSpec) ? valueThunk2(detail, compSpec.config, compSpec.validated) : valueThunk2(detail);
      const childSpecs = get$g(value2, "components").getOr([]);
      const substituted = bind$3(childSpecs, (c) => substitute(owner2, detail, c, placeholders));
      return [{
        ...value2,
        components: substituted
      }];
    }, (req, valuesThunk) => {
      if (isSubstituted(compSpec)) {
        const values2 = valuesThunk(detail, compSpec.config, compSpec.validated);
        const preprocessor = compSpec.validated.preprocess.getOr(identity);
        return preprocessor(values2);
      } else {
        return valuesThunk(detail);
      }
    });
  };
  const substituteAll = (owner2, detail, components2, placeholders) => bind$3(components2, (c) => substitute(owner2, detail, c, placeholders));
  const oneReplace = (label2, replacements) => {
    let called = false;
    const used = () => called;
    const replace2 = () => {
      if (called) {
        throw new Error("Trying to use the same placeholder more than once: " + label2);
      }
      called = true;
      return replacements;
    };
    const required2 = () => replacements.fold((req, _) => req, (req, _) => req);
    return {
      name: constant$1(label2),
      required: required2,
      used,
      replace: replace2
    };
  };
  const substitutePlaces = (owner2, detail, components2, placeholders) => {
    const ps = map$1(placeholders, (ph, name2) => oneReplace(name2, ph));
    const outcome = substituteAll(owner2, detail, components2, ps);
    each(ps, (p) => {
      if (p.used() === false && p.required()) {
        throw new Error("Placeholder: " + p.name() + " was not found in components list\nNamespace: " + owner2.getOr("none") + "\nComponents: " + JSON.stringify(detail.components, null, 2));
      }
    });
    return outcome;
  };
  const single$2 = adt$3.single;
  const multiple = adt$3.multiple;
  const placeholder = constant$1(_placeholder);
  const adt$2 = Adt.generate([
    { required: ["data"] },
    { external: ["data"] },
    { optional: ["data"] },
    { group: ["data"] }
  ]);
  const fFactory = defaulted("factory", { sketch: identity });
  const fSchema = defaulted("schema", []);
  const fName = required$1("name");
  const fPname = field$1("pname", "pname", defaultedThunk((typeSpec) => "<alloy." + generate$6(typeSpec.name) + ">"), anyValue());
  const fGroupSchema = customField("schema", () => [option$3("preprocess")]);
  const fDefaults = defaulted("defaults", constant$1({}));
  const fOverrides = defaulted("overrides", constant$1({}));
  const requiredSpec = objOf([
    fFactory,
    fSchema,
    fName,
    fPname,
    fDefaults,
    fOverrides
  ]);
  const externalSpec = objOf([
    fFactory,
    fSchema,
    fName,
    fDefaults,
    fOverrides
  ]);
  const optionalSpec = objOf([
    fFactory,
    fSchema,
    fName,
    fPname,
    fDefaults,
    fOverrides
  ]);
  const groupSpec = objOf([
    fFactory,
    fGroupSchema,
    fName,
    required$1("unit"),
    fPname,
    fDefaults,
    fOverrides
  ]);
  const asNamedPart = (part2) => {
    return part2.fold(Optional.some, Optional.none, Optional.some, Optional.some);
  };
  const name$2 = (part2) => {
    const get2 = (data) => data.name;
    return part2.fold(get2, get2, get2, get2);
  };
  const asCommon = (part2) => {
    return part2.fold(identity, identity, identity, identity);
  };
  const convert = (adtConstructor, partSchema) => (spec) => {
    const data = asRawOrDie$1("Converting part type", partSchema, spec);
    return adtConstructor(data);
  };
  const required = convert(adt$2.required, requiredSpec);
  const external = convert(adt$2.external, externalSpec);
  const optional = convert(adt$2.optional, optionalSpec);
  const group = convert(adt$2.group, groupSpec);
  const original = constant$1("entirety");
  var PartType = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    required,
    external,
    optional,
    group,
    asNamedPart,
    name: name$2,
    asCommon,
    original
  });
  const combine = (detail, data, partSpec, partValidated) => deepMerge(data.defaults(detail, partSpec, partValidated), partSpec, { uid: detail.partUids[data.name] }, data.overrides(detail, partSpec, partValidated));
  const subs = (owner2, detail, parts2) => {
    const internals = {};
    const externals = {};
    each$1(parts2, (part2) => {
      part2.fold((data) => {
        internals[data.pname] = single$2(true, (detail2, partSpec, partValidated) => data.factory.sketch(combine(detail2, data, partSpec, partValidated)));
      }, (data) => {
        const partSpec = detail.parts[data.name];
        externals[data.name] = constant$1(data.factory.sketch(combine(detail, data, partSpec[original()]), partSpec));
      }, (data) => {
        internals[data.pname] = single$2(false, (detail2, partSpec, partValidated) => data.factory.sketch(combine(detail2, data, partSpec, partValidated)));
      }, (data) => {
        internals[data.pname] = multiple(true, (detail2, _partSpec, _partValidated) => {
          const units2 = detail2[data.name];
          return map$2(units2, (u) => data.factory.sketch(deepMerge(data.defaults(detail2, u, _partValidated), u, data.overrides(detail2, u))));
        });
      });
    });
    return {
      internals: constant$1(internals),
      externals: constant$1(externals)
    };
  };
  const generate$3 = (owner2, parts2) => {
    const r2 = {};
    each$1(parts2, (part2) => {
      asNamedPart(part2).each((np) => {
        const g = doGenerateOne(owner2, np.pname);
        r2[np.name] = (config2) => {
          const validated = asRawOrDie$1("Part: " + np.name + " in " + owner2, objOf(np.schema), config2);
          return {
            ...g,
            config: config2,
            validated
          };
        };
      });
    });
    return r2;
  };
  const doGenerateOne = (owner2, pname) => ({
    uiType: placeholder(),
    owner: owner2,
    name: pname
  });
  const generateOne$1 = (owner2, pname, config2) => ({
    uiType: placeholder(),
    owner: owner2,
    name: pname,
    config: config2,
    validated: {}
  });
  const schemas = (parts2) => bind$3(parts2, (part2) => part2.fold(Optional.none, Optional.some, Optional.none, Optional.none).map((data) => requiredObjOf(data.name, data.schema.concat([snapshot(original())]))).toArray());
  const names = (parts2) => map$2(parts2, name$2);
  const substitutes = (owner2, detail, parts2) => subs(owner2, detail, parts2);
  const components$1 = (owner2, detail, internals) => substitutePlaces(Optional.some(owner2), detail, detail.components, internals);
  const getPart = (component, detail, partKey) => {
    const uid = detail.partUids[partKey];
    return component.getSystem().getByUid(uid).toOptional();
  };
  const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie("Could not find part: " + partKey);
  const getParts = (component, detail, partKeys) => {
    const r2 = {};
    const uids2 = detail.partUids;
    const system = component.getSystem();
    each$1(partKeys, (pk) => {
      r2[pk] = constant$1(system.getByUid(uids2[pk]));
    });
    return r2;
  };
  const getAllParts = (component, detail) => {
    const system = component.getSystem();
    return map$1(detail.partUids, (pUid, _k) => constant$1(system.getByUid(pUid)));
  };
  const getAllPartNames = (detail) => keys(detail.partUids);
  const getPartsOrDie = (component, detail, partKeys) => {
    const r2 = {};
    const uids2 = detail.partUids;
    const system = component.getSystem();
    each$1(partKeys, (pk) => {
      r2[pk] = constant$1(system.getByUid(uids2[pk]).getOrDie());
    });
    return r2;
  };
  const defaultUids = (baseUid, partTypes) => {
    const partNames = names(partTypes);
    return wrapAll(map$2(partNames, (pn) => ({
      key: pn,
      value: baseUid + "-" + pn
    })));
  };
  const defaultUidsSchema = (partTypes) => field$1("partUids", "partUids", mergeWithThunk((spec) => defaultUids(spec.uid, partTypes)), anyValue());
  var AlloyParts = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    generate: generate$3,
    generateOne: generateOne$1,
    schemas,
    names,
    substitutes,
    components: components$1,
    defaultUids,
    defaultUidsSchema,
    getAllParts,
    getAllPartNames,
    getPart,
    getPartOrDie,
    getParts,
    getPartsOrDie
  });
  const base = (partSchemas, partUidsSchemas) => {
    const ps = partSchemas.length > 0 ? [requiredObjOf("parts", partSchemas)] : [];
    return ps.concat([
      required$1("uid"),
      defaulted("dom", {}),
      defaulted("components", []),
      snapshot("originalSpec"),
      defaulted("debug.sketcher", {})
    ]).concat(partUidsSchemas);
  };
  const asRawOrDie = (label2, schema2, spec, partSchemas, partUidsSchemas) => {
    const baseS = base(partSchemas, partUidsSchemas);
    return asRawOrDie$1(label2 + " [SpecSchema]", objOfOnly(baseS.concat(schema2)), spec);
  };
  const single$1 = (owner2, schema2, factory2, spec) => {
    const specWithUid = supplyUid(spec);
    const detail = asRawOrDie(owner2, schema2, specWithUid, [], []);
    return factory2(detail, specWithUid);
  };
  const composite$1 = (owner2, schema2, partTypes, factory2, spec) => {
    const specWithUid = supplyUid(spec);
    const partSchemas = schemas(partTypes);
    const partUidsSchema = defaultUidsSchema(partTypes);
    const detail = asRawOrDie(owner2, schema2, specWithUid, partSchemas, [partUidsSchema]);
    const subs2 = substitutes(owner2, detail, partTypes);
    const components2 = components$1(owner2, detail, subs2.internals());
    return factory2(detail, components2, specWithUid, subs2.externals());
  };
  const hasUid = (spec) => has$2(spec, "uid");
  const supplyUid = (spec) => {
    return hasUid(spec) ? spec : {
      ...spec,
      uid: generate$5("uid")
    };
  };
  const isSketchSpec = (spec) => {
    return spec.uid !== void 0;
  };
  const singleSchema = objOfOnly([
    required$1("name"),
    required$1("factory"),
    required$1("configFields"),
    defaulted("apis", {}),
    defaulted("extraApis", {})
  ]);
  const compositeSchema = objOfOnly([
    required$1("name"),
    required$1("factory"),
    required$1("configFields"),
    required$1("partFields"),
    defaulted("apis", {}),
    defaulted("extraApis", {})
  ]);
  const single = (rawConfig) => {
    const config2 = asRawOrDie$1("Sketcher for " + rawConfig.name, singleSchema, rawConfig);
    const sketch2 = (spec) => single$1(config2.name, config2.configFields, config2.factory, spec);
    const apis = map$1(config2.apis, makeApi);
    const extraApis = map$1(config2.extraApis, (f, k) => markAsExtraApi(f, k));
    return {
      name: config2.name,
      configFields: config2.configFields,
      sketch: sketch2,
      ...apis,
      ...extraApis
    };
  };
  const composite = (rawConfig) => {
    const config2 = asRawOrDie$1("Sketcher for " + rawConfig.name, compositeSchema, rawConfig);
    const sketch2 = (spec) => composite$1(config2.name, config2.configFields, config2.partFields, config2.factory, spec);
    const parts2 = generate$3(config2.name, config2.partFields);
    const apis = map$1(config2.apis, makeApi);
    const extraApis = map$1(config2.extraApis, (f, k) => markAsExtraApi(f, k));
    return {
      name: config2.name,
      partFields: config2.partFields,
      configFields: config2.configFields,
      sketch: sketch2,
      parts: parts2,
      ...apis,
      ...extraApis
    };
  };
  const inside = (target) => isTag("input")(target) && get$f(target, "type") !== "radio" || isTag("textarea")(target);
  const getCurrent = (component, composeConfig, _composeState) => composeConfig.find(component);
  var ComposeApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    getCurrent
  });
  const ComposeSchema = [required$1("find")];
  const Composing = create$3({
    fields: ComposeSchema,
    name: "composing",
    apis: ComposeApis
  });
  const nativeDisabled = [
    "input",
    "button",
    "textarea",
    "select"
  ];
  const onLoad$1 = (component, disableConfig, disableState) => {
    const f = disableConfig.disabled() ? disable : enable;
    f(component, disableConfig);
  };
  const hasNative = (component, config2) => config2.useNative === true && contains$2(nativeDisabled, name$3(component.element));
  const nativeIsDisabled = (component) => has$1(component.element, "disabled");
  const nativeDisable = (component) => {
    set$9(component.element, "disabled", "disabled");
  };
  const nativeEnable = (component) => {
    remove$7(component.element, "disabled");
  };
  const ariaIsDisabled = (component) => get$f(component.element, "aria-disabled") === "true";
  const ariaDisable = (component) => {
    set$9(component.element, "aria-disabled", "true");
  };
  const ariaEnable = (component) => {
    set$9(component.element, "aria-disabled", "false");
  };
  const disable = (component, disableConfig, _disableState) => {
    disableConfig.disableClass.each((disableClass) => {
      add$2(component.element, disableClass);
    });
    const f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable;
    f(component);
    disableConfig.onDisabled(component);
  };
  const enable = (component, disableConfig, _disableState) => {
    disableConfig.disableClass.each((disableClass) => {
      remove$2(component.element, disableClass);
    });
    const f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable;
    f(component);
    disableConfig.onEnabled(component);
  };
  const isDisabled = (component, disableConfig) => hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component);
  const set$4 = (component, disableConfig, disableState, disabled) => {
    const f = disabled ? disable : enable;
    f(component, disableConfig);
  };
  var DisableApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    enable,
    disable,
    isDisabled,
    onLoad: onLoad$1,
    set: set$4
  });
  const exhibit$5 = (base2, disableConfig) => nu$7({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] });
  const events$e = (disableConfig, disableState) => derive$2([
    abort(execute$5(), (component, _simulatedEvent) => isDisabled(component, disableConfig)),
    loadEvent(disableConfig, disableState, onLoad$1)
  ]);
  var ActiveDisable = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit: exhibit$5,
    events: events$e
  });
  var DisableSchema = [
    defaultedFunction("disabled", never),
    defaulted("useNative", true),
    option$3("disableClass"),
    onHandler("onDisabled"),
    onHandler("onEnabled")
  ];
  const Disabling = create$3({
    fields: DisableSchema,
    name: "disabling",
    active: ActiveDisable,
    apis: DisableApis
  });
  const dehighlightAllExcept = (component, hConfig, hState, skip) => {
    const highlighted = descendants(component.element, "." + hConfig.highlightClass);
    each$1(highlighted, (h2) => {
      if (!exists(skip, (skipComp) => skipComp.element === h2)) {
        remove$2(h2, hConfig.highlightClass);
        component.getSystem().getByDom(h2).each((target) => {
          hConfig.onDehighlight(component, target);
          emit(target, dehighlight$1());
        });
      }
    });
  };
  const dehighlightAll = (component, hConfig, hState) => dehighlightAllExcept(component, hConfig, hState, []);
  const dehighlight = (component, hConfig, hState, target) => {
    if (isHighlighted(component, hConfig, hState, target)) {
      remove$2(target.element, hConfig.highlightClass);
      hConfig.onDehighlight(component, target);
      emit(target, dehighlight$1());
    }
  };
  const highlight = (component, hConfig, hState, target) => {
    dehighlightAllExcept(component, hConfig, hState, [target]);
    if (!isHighlighted(component, hConfig, hState, target)) {
      add$2(target.element, hConfig.highlightClass);
      hConfig.onHighlight(component, target);
      emit(target, highlight$1());
    }
  };
  const highlightFirst = (component, hConfig, hState) => {
    getFirst(component, hConfig).each((firstComp) => {
      highlight(component, hConfig, hState, firstComp);
    });
  };
  const highlightLast = (component, hConfig, hState) => {
    getLast(component, hConfig).each((lastComp) => {
      highlight(component, hConfig, hState, lastComp);
    });
  };
  const highlightAt = (component, hConfig, hState, index2) => {
    getByIndex(component, hConfig, hState, index2).fold((err) => {
      throw err;
    }, (firstComp) => {
      highlight(component, hConfig, hState, firstComp);
    });
  };
  const highlightBy = (component, hConfig, hState, predicate) => {
    const candidates = getCandidates(component, hConfig);
    const targetComp = find$5(candidates, predicate);
    targetComp.each((c) => {
      highlight(component, hConfig, hState, c);
    });
  };
  const isHighlighted = (component, hConfig, hState, queryTarget) => has(queryTarget.element, hConfig.highlightClass);
  const getHighlighted = (component, hConfig, _hState) => descendant(component.element, "." + hConfig.highlightClass).bind((e) => component.getSystem().getByDom(e).toOptional());
  const getByIndex = (component, hConfig, hState, index2) => {
    const items = descendants(component.element, "." + hConfig.itemClass);
    return Optional.from(items[index2]).fold(() => Result.error(new Error("No element found with index " + index2)), component.getSystem().getByDom);
  };
  const getFirst = (component, hConfig, _hState) => descendant(component.element, "." + hConfig.itemClass).bind((e) => component.getSystem().getByDom(e).toOptional());
  const getLast = (component, hConfig, _hState) => {
    const items = descendants(component.element, "." + hConfig.itemClass);
    const last2 = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none();
    return last2.bind((c) => component.getSystem().getByDom(c).toOptional());
  };
  const getDelta$2 = (component, hConfig, hState, delta) => {
    const items = descendants(component.element, "." + hConfig.itemClass);
    const current = findIndex$1(items, (item2) => has(item2, hConfig.highlightClass));
    return current.bind((selected) => {
      const dest = cycleBy(selected, delta, 0, items.length - 1);
      return component.getSystem().getByDom(items[dest]).toOptional();
    });
  };
  const getPrevious = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, -1);
  const getNext = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, 1);
  const getCandidates = (component, hConfig, _hState) => {
    const items = descendants(component.element, "." + hConfig.itemClass);
    return cat(map$2(items, (i) => component.getSystem().getByDom(i).toOptional()));
  };
  var HighlightApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    dehighlightAll,
    dehighlight,
    highlight,
    highlightFirst,
    highlightLast,
    highlightAt,
    highlightBy,
    isHighlighted,
    getHighlighted,
    getFirst,
    getLast,
    getPrevious,
    getNext,
    getCandidates
  });
  var HighlightSchema = [
    required$1("highlightClass"),
    required$1("itemClass"),
    onHandler("onHighlight"),
    onHandler("onDehighlight")
  ];
  const Highlighting = create$3({
    fields: HighlightSchema,
    name: "highlighting",
    apis: HighlightApis
  });
  const BACKSPACE = [8];
  const TAB = [9];
  const ENTER = [13];
  const ESCAPE = [27];
  const SPACE = [32];
  const LEFT = [37];
  const UP = [38];
  const RIGHT = [39];
  const DOWN = [40];
  const cyclePrev = (values2, index2, predicate) => {
    const before2 = reverse(values2.slice(0, index2));
    const after2 = reverse(values2.slice(index2 + 1));
    return find$5(before2.concat(after2), predicate);
  };
  const tryPrev = (values2, index2, predicate) => {
    const before2 = reverse(values2.slice(0, index2));
    return find$5(before2, predicate);
  };
  const cycleNext = (values2, index2, predicate) => {
    const before2 = values2.slice(0, index2);
    const after2 = values2.slice(index2 + 1);
    return find$5(after2.concat(before2), predicate);
  };
  const tryNext = (values2, index2, predicate) => {
    const after2 = values2.slice(index2 + 1);
    return find$5(after2, predicate);
  };
  const inSet = (keys2) => (event) => {
    const raw = event.raw;
    return contains$2(keys2, raw.which);
  };
  const and = (preds) => (event) => forall(preds, (pred) => pred(event));
  const isShift = (event) => {
    const raw = event.raw;
    return raw.shiftKey === true;
  };
  const isControl = (event) => {
    const raw = event.raw;
    return raw.ctrlKey === true;
  };
  const isNotShift = not(isShift);
  const rule = (matches, action) => ({
    matches,
    classification: action
  });
  const choose = (transitions, event) => {
    const transition = find$5(transitions, (t2) => t2.matches(event));
    return transition.map((t2) => t2.classification);
  };
  const reportFocusShifting = (component, prevFocus, newFocus) => {
    const noChange = prevFocus.exists((p) => newFocus.exists((n) => eq(n, p)));
    if (!noChange) {
      emitWith(component, focusShifted(), {
        prevFocus,
        newFocus
      });
    }
  };
  const dom$2 = () => {
    const get2 = (component) => search(component.element);
    const set2 = (component, focusee) => {
      const prevFocus = get2(component);
      component.getSystem().triggerFocus(focusee, component.element);
      const newFocus = get2(component);
      reportFocusShifting(component, prevFocus, newFocus);
    };
    return {
      get: get2,
      set: set2
    };
  };
  const highlights = () => {
    const get2 = (component) => Highlighting.getHighlighted(component).map((item2) => item2.element);
    const set2 = (component, element2) => {
      const prevFocus = get2(component);
      component.getSystem().getByDom(element2).fold(noop, (item2) => {
        Highlighting.highlight(component, item2);
      });
      const newFocus = get2(component);
      reportFocusShifting(component, prevFocus, newFocus);
    };
    return {
      get: get2,
      set: set2
    };
  };
  var FocusInsideModes;
  (function(FocusInsideModes2) {
    FocusInsideModes2["OnFocusMode"] = "onFocus";
    FocusInsideModes2["OnEnterOrSpaceMode"] = "onEnterOrSpace";
    FocusInsideModes2["OnApiMode"] = "onApi";
  })(FocusInsideModes || (FocusInsideModes = {}));
  const typical = (infoSchema, stateInit, getKeydownRules2, getKeyupRules2, optFocusIn) => {
    const schema2 = () => infoSchema.concat([
      defaulted("focusManager", dom$2()),
      defaultedOf("focusInside", "onFocus", valueOf((val) => contains$2([
        "onFocus",
        "onEnterOrSpace",
        "onApi"
      ], val) ? Result.value(val) : Result.error("Invalid value for focusInside"))),
      output$1("handler", me),
      output$1("state", stateInit),
      output$1("sendFocusIn", optFocusIn)
    ]);
    const processKey = (component, simulatedEvent, getRules, keyingConfig, keyingState) => {
      const rules = getRules(component, simulatedEvent, keyingConfig, keyingState);
      return choose(rules, simulatedEvent.event).bind((rule2) => rule2(component, simulatedEvent, keyingConfig, keyingState));
    };
    const toEvents2 = (keyingConfig, keyingState) => {
      const onFocusHandler = keyingConfig.focusInside !== FocusInsideModes.OnFocusMode ? Optional.none() : optFocusIn(keyingConfig).map((focusIn2) => run$1(focus$4(), (component, simulatedEvent) => {
        focusIn2(component, keyingConfig, keyingState);
        simulatedEvent.stop();
      }));
      const tryGoInsideComponent = (component, simulatedEvent) => {
        const isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event);
        if (keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode && isEnterOrSpace && isSource(component, simulatedEvent)) {
          optFocusIn(keyingConfig).each((focusIn2) => {
            focusIn2(component, keyingConfig, keyingState);
            simulatedEvent.stop();
          });
        }
      };
      const keyboardEvents = [
        run$1(keydown(), (component, simulatedEvent) => {
          processKey(component, simulatedEvent, getKeydownRules2, keyingConfig, keyingState).fold(() => {
            tryGoInsideComponent(component, simulatedEvent);
          }, (_) => {
            simulatedEvent.stop();
          });
        }),
        run$1(keyup(), (component, simulatedEvent) => {
          processKey(component, simulatedEvent, getKeyupRules2, keyingConfig, keyingState).each((_) => {
            simulatedEvent.stop();
          });
        })
      ];
      return derive$2(onFocusHandler.toArray().concat(keyboardEvents));
    };
    const me = {
      schema: schema2,
      processKey,
      toEvents: toEvents2
    };
    return me;
  };
  const create$1 = (cyclicField) => {
    const schema2 = [
      option$3("onEscape"),
      option$3("onEnter"),
      defaulted("selector", '[data-alloy-tabstop="true"]:not(:disabled)'),
      defaulted("firstTabstop", 0),
      defaulted("useTabstopAt", always),
      option$3("visibilitySelector")
    ].concat([cyclicField]);
    const isVisible2 = (tabbingConfig, element2) => {
      const target = tabbingConfig.visibilitySelector.bind((sel) => closest$1(element2, sel)).getOr(element2);
      return get$d(target) > 0;
    };
    const findInitial = (component, tabbingConfig) => {
      const tabstops = descendants(component.element, tabbingConfig.selector);
      const visibles = filter$2(tabstops, (elem) => isVisible2(tabbingConfig, elem));
      return Optional.from(visibles[tabbingConfig.firstTabstop]);
    };
    const findCurrent2 = (component, tabbingConfig) => tabbingConfig.focusManager.get(component).bind((elem) => closest$1(elem, tabbingConfig.selector));
    const isTabstop = (tabbingConfig, element2) => isVisible2(tabbingConfig, element2) && tabbingConfig.useTabstopAt(element2);
    const focusIn2 = (component, tabbingConfig, _tabbingState) => {
      findInitial(component, tabbingConfig).each((target) => {
        tabbingConfig.focusManager.set(component, target);
      });
    };
    const goFromTabstop = (component, tabstops, stopIndex, tabbingConfig, cycle) => cycle(tabstops, stopIndex, (elem) => isTabstop(tabbingConfig, elem)).fold(() => tabbingConfig.cyclic ? Optional.some(true) : Optional.none(), (target) => {
      tabbingConfig.focusManager.set(component, target);
      return Optional.some(true);
    });
    const go2 = (component, _simulatedEvent, tabbingConfig, cycle) => {
      const tabstops = descendants(component.element, tabbingConfig.selector);
      return findCurrent2(component, tabbingConfig).bind((tabstop) => {
        const optStopIndex = findIndex$1(tabstops, curry(eq, tabstop));
        return optStopIndex.bind((stopIndex) => goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle));
      });
    };
    const goBackwards = (component, simulatedEvent, tabbingConfig) => {
      const navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev;
      return go2(component, simulatedEvent, tabbingConfig, navigate);
    };
    const goForwards = (component, simulatedEvent, tabbingConfig) => {
      const navigate = tabbingConfig.cyclic ? cycleNext : tryNext;
      return go2(component, simulatedEvent, tabbingConfig, navigate);
    };
    const execute2 = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEnter.bind((f) => f(component, simulatedEvent));
    const exit = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEscape.bind((f) => f(component, simulatedEvent));
    const getKeydownRules2 = constant$1([
      rule(and([
        isShift,
        inSet(TAB)
      ]), goBackwards),
      rule(inSet(TAB), goForwards),
      rule(and([
        isNotShift,
        inSet(ENTER)
      ]), execute2)
    ]);
    const getKeyupRules2 = constant$1([rule(inSet(ESCAPE), exit)]);
    return typical(schema2, NoState.init, getKeydownRules2, getKeyupRules2, () => Optional.some(focusIn2));
  };
  var AcyclicType = create$1(customField("cyclic", never));
  var CyclicType = create$1(customField("cyclic", always));
  const doDefaultExecute = (component, _simulatedEvent, focused) => {
    dispatch(component, focused, execute$5());
    return Optional.some(true);
  };
  const defaultExecute = (component, simulatedEvent, focused) => {
    const isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event);
    return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused);
  };
  const stopEventForFirefox = (_component, _simulatedEvent) => Optional.some(true);
  const schema$v = [
    defaulted("execute", defaultExecute),
    defaulted("useSpace", false),
    defaulted("useEnter", true),
    defaulted("useControlEnter", false),
    defaulted("useDown", false)
  ];
  const execute$4 = (component, simulatedEvent, executeConfig) => executeConfig.execute(component, simulatedEvent, component.element);
  const getKeydownRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => {
    const spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : [];
    const enterExec = executeConfig.useEnter ? ENTER : [];
    const downExec = executeConfig.useDown ? DOWN : [];
    const execKeys = spaceExec.concat(enterExec).concat(downExec);
    return [rule(inSet(execKeys), execute$4)].concat(executeConfig.useControlEnter ? [rule(and([
      isControl,
      inSet(ENTER)
    ]), execute$4)] : []);
  };
  const getKeyupRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : [];
  var ExecutionType = typical(schema$v, NoState.init, getKeydownRules$5, getKeyupRules$5, () => Optional.none());
  const flatgrid$1 = () => {
    const dimensions = value$2();
    const setGridSize = (numRows, numColumns) => {
      dimensions.set({
        numRows,
        numColumns
      });
    };
    const getNumRows = () => dimensions.get().map((d) => d.numRows);
    const getNumColumns = () => dimensions.get().map((d) => d.numColumns);
    return nu$8({
      readState: () => dimensions.get().map((d) => ({
        numRows: String(d.numRows),
        numColumns: String(d.numColumns)
      })).getOr({
        numRows: "?",
        numColumns: "?"
      }),
      setGridSize,
      getNumRows,
      getNumColumns
    });
  };
  const init$d = (spec) => spec.state(spec);
  var KeyingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    flatgrid: flatgrid$1,
    init: init$d
  });
  const useH = (movement) => (component, simulatedEvent, config2, state) => {
    const move2 = movement(component.element);
    return use(move2, component, simulatedEvent, config2, state);
  };
  const west$1 = (moveLeft2, moveRight2) => {
    const movement = onDirection(moveLeft2, moveRight2);
    return useH(movement);
  };
  const east$1 = (moveLeft2, moveRight2) => {
    const movement = onDirection(moveRight2, moveLeft2);
    return useH(movement);
  };
  const useV = (move2) => (component, simulatedEvent, config2, state) => use(move2, component, simulatedEvent, config2, state);
  const use = (move2, component, simulatedEvent, config2, state) => {
    const outcome = config2.focusManager.get(component).bind((focused) => move2(component.element, focused, config2, state));
    return outcome.map((newFocus) => {
      config2.focusManager.set(component, newFocus);
      return true;
    });
  };
  const north$1 = useV;
  const south$1 = useV;
  const move$1 = useV;
  const isHidden$1 = (dom2) => dom2.offsetWidth <= 0 && dom2.offsetHeight <= 0;
  const isVisible = (element2) => !isHidden$1(element2.dom);
  const locate = (candidates, predicate) => findIndex$1(candidates, predicate).map((index2) => ({
    index: index2,
    candidates
  }));
  const locateVisible = (container, current, selector) => {
    const predicate = (x) => eq(x, current);
    const candidates = descendants(container, selector);
    const visible = filter$2(candidates, isVisible);
    return locate(visible, predicate);
  };
  const findIndex = (elements, target) => findIndex$1(elements, (elem) => eq(target, elem));
  const withGrid = (values2, index2, numCols, f) => {
    const oldRow = Math.floor(index2 / numCols);
    const oldColumn = index2 % numCols;
    return f(oldRow, oldColumn).bind((address) => {
      const newIndex = address.row * numCols + address.column;
      return newIndex >= 0 && newIndex < values2.length ? Optional.some(values2[newIndex]) : Optional.none();
    });
  };
  const cycleHorizontal$1 = (values2, index2, numRows, numCols, delta) => withGrid(values2, index2, numCols, (oldRow, oldColumn) => {
    const onLastRow = oldRow === numRows - 1;
    const colsInRow = onLastRow ? values2.length - oldRow * numCols : numCols;
    const newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1);
    return Optional.some({
      row: oldRow,
      column: newColumn
    });
  });
  const cycleVertical$1 = (values2, index2, numRows, numCols, delta) => withGrid(values2, index2, numCols, (oldRow, oldColumn) => {
    const newRow = cycleBy(oldRow, delta, 0, numRows - 1);
    const onLastRow = newRow === numRows - 1;
    const colsInRow = onLastRow ? values2.length - newRow * numCols : numCols;
    const newCol = clamp(oldColumn, 0, colsInRow - 1);
    return Optional.some({
      row: newRow,
      column: newCol
    });
  });
  const cycleRight$1 = (values2, index2, numRows, numCols) => cycleHorizontal$1(values2, index2, numRows, numCols, 1);
  const cycleLeft$1 = (values2, index2, numRows, numCols) => cycleHorizontal$1(values2, index2, numRows, numCols, -1);
  const cycleUp$1 = (values2, index2, numRows, numCols) => cycleVertical$1(values2, index2, numRows, numCols, -1);
  const cycleDown$1 = (values2, index2, numRows, numCols) => cycleVertical$1(values2, index2, numRows, numCols, 1);
  const schema$u = [
    required$1("selector"),
    defaulted("execute", defaultExecute),
    onKeyboardHandler("onEscape"),
    defaulted("captureTab", false),
    initSize()
  ];
  const focusIn$3 = (component, gridConfig, _gridState) => {
    descendant(component.element, gridConfig.selector).each((first2) => {
      gridConfig.focusManager.set(component, first2);
    });
  };
  const findCurrent$1 = (component, gridConfig) => gridConfig.focusManager.get(component).bind((elem) => closest$1(elem, gridConfig.selector));
  const execute$3 = (component, simulatedEvent, gridConfig, _gridState) => findCurrent$1(component, gridConfig).bind((focused) => gridConfig.execute(component, simulatedEvent, focused));
  const doMove$2 = (cycle) => (element2, focused, gridConfig, gridState) => locateVisible(element2, focused, gridConfig.selector).bind((identified) => cycle(identified.candidates, identified.index, gridState.getNumRows().getOr(gridConfig.initSize.numRows), gridState.getNumColumns().getOr(gridConfig.initSize.numColumns)));
  const handleTab = (_component, _simulatedEvent, gridConfig) => gridConfig.captureTab ? Optional.some(true) : Optional.none();
  const doEscape$1 = (component, simulatedEvent, gridConfig) => gridConfig.onEscape(component, simulatedEvent);
  const moveLeft$3 = doMove$2(cycleLeft$1);
  const moveRight$3 = doMove$2(cycleRight$1);
  const moveNorth$1 = doMove$2(cycleUp$1);
  const moveSouth$1 = doMove$2(cycleDown$1);
  const getKeydownRules$4 = constant$1([
    rule(inSet(LEFT), west$1(moveLeft$3, moveRight$3)),
    rule(inSet(RIGHT), east$1(moveLeft$3, moveRight$3)),
    rule(inSet(UP), north$1(moveNorth$1)),
    rule(inSet(DOWN), south$1(moveSouth$1)),
    rule(and([
      isShift,
      inSet(TAB)
    ]), handleTab),
    rule(and([
      isNotShift,
      inSet(TAB)
    ]), handleTab),
    rule(inSet(SPACE.concat(ENTER)), execute$3)
  ]);
  const getKeyupRules$4 = constant$1([
    rule(inSet(ESCAPE), doEscape$1),
    rule(inSet(SPACE), stopEventForFirefox)
  ]);
  var FlatgridType = typical(schema$u, flatgrid$1, getKeydownRules$4, getKeyupRules$4, () => Optional.some(focusIn$3));
  const horizontal = (container, selector, current, delta) => {
    const isDisabledButton = (candidate) => name$3(candidate) === "button" && get$f(candidate, "disabled") === "disabled";
    const tryCycle = (initial, index2, candidates) => {
      const newIndex = cycleBy(index2, delta, 0, candidates.length - 1);
      if (newIndex === initial) {
        return Optional.none();
      } else {
        return isDisabledButton(candidates[newIndex]) ? tryCycle(initial, newIndex, candidates) : Optional.from(candidates[newIndex]);
      }
    };
    return locateVisible(container, current, selector).bind((identified) => {
      const index2 = identified.index;
      const candidates = identified.candidates;
      return tryCycle(index2, index2, candidates);
    });
  };
  const schema$t = [
    required$1("selector"),
    defaulted("getInitial", Optional.none),
    defaulted("execute", defaultExecute),
    onKeyboardHandler("onEscape"),
    defaulted("executeOnMove", false),
    defaulted("allowVertical", true)
  ];
  const findCurrent = (component, flowConfig) => flowConfig.focusManager.get(component).bind((elem) => closest$1(elem, flowConfig.selector));
  const execute$2 = (component, simulatedEvent, flowConfig) => findCurrent(component, flowConfig).bind((focused) => flowConfig.execute(component, simulatedEvent, focused));
  const focusIn$2 = (component, flowConfig, _state) => {
    flowConfig.getInitial(component).orThunk(() => descendant(component.element, flowConfig.selector)).each((first2) => {
      flowConfig.focusManager.set(component, first2);
    });
  };
  const moveLeft$2 = (element2, focused, info) => horizontal(element2, info.selector, focused, -1);
  const moveRight$2 = (element2, focused, info) => horizontal(element2, info.selector, focused, 1);
  const doMove$1 = (movement) => (component, simulatedEvent, flowConfig, flowState) => movement(component, simulatedEvent, flowConfig, flowState).bind(() => flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true));
  const doEscape = (component, simulatedEvent, flowConfig) => flowConfig.onEscape(component, simulatedEvent);
  const getKeydownRules$3 = (_component, _se, flowConfig, _flowState) => {
    const westMovers = LEFT.concat(flowConfig.allowVertical ? UP : []);
    const eastMovers = RIGHT.concat(flowConfig.allowVertical ? DOWN : []);
    return [
      rule(inSet(westMovers), doMove$1(west$1(moveLeft$2, moveRight$2))),
      rule(inSet(eastMovers), doMove$1(east$1(moveLeft$2, moveRight$2))),
      rule(inSet(ENTER), execute$2),
      rule(inSet(SPACE), execute$2)
    ];
  };
  const getKeyupRules$3 = constant$1([
    rule(inSet(SPACE), stopEventForFirefox),
    rule(inSet(ESCAPE), doEscape)
  ]);
  var FlowType = typical(schema$t, NoState.init, getKeydownRules$3, getKeyupRules$3, () => Optional.some(focusIn$2));
  const toCell = (matrix2, rowIndex, columnIndex) => Optional.from(matrix2[rowIndex]).bind((row) => Optional.from(row[columnIndex]).map((cell) => ({
    rowIndex,
    columnIndex,
    cell
  })));
  const cycleHorizontal = (matrix2, rowIndex, startCol, deltaCol) => {
    const row = matrix2[rowIndex];
    const colsInRow = row.length;
    const newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1);
    return toCell(matrix2, rowIndex, newColIndex);
  };
  const cycleVertical = (matrix2, colIndex, startRow, deltaRow) => {
    const nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix2.length - 1);
    const colsInNextRow = matrix2[nextRowIndex].length;
    const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
    return toCell(matrix2, nextRowIndex, nextColIndex);
  };
  const moveHorizontal = (matrix2, rowIndex, startCol, deltaCol) => {
    const row = matrix2[rowIndex];
    const colsInRow = row.length;
    const newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1);
    return toCell(matrix2, rowIndex, newColIndex);
  };
  const moveVertical = (matrix2, colIndex, startRow, deltaRow) => {
    const nextRowIndex = clamp(startRow + deltaRow, 0, matrix2.length - 1);
    const colsInNextRow = matrix2[nextRowIndex].length;
    const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
    return toCell(matrix2, nextRowIndex, nextColIndex);
  };
  const cycleRight = (matrix2, startRow, startCol) => cycleHorizontal(matrix2, startRow, startCol, 1);
  const cycleLeft = (matrix2, startRow, startCol) => cycleHorizontal(matrix2, startRow, startCol, -1);
  const cycleUp = (matrix2, startRow, startCol) => cycleVertical(matrix2, startCol, startRow, -1);
  const cycleDown = (matrix2, startRow, startCol) => cycleVertical(matrix2, startCol, startRow, 1);
  const moveLeft$1 = (matrix2, startRow, startCol) => moveHorizontal(matrix2, startRow, startCol, -1);
  const moveRight$1 = (matrix2, startRow, startCol) => moveHorizontal(matrix2, startRow, startCol, 1);
  const moveUp$1 = (matrix2, startRow, startCol) => moveVertical(matrix2, startCol, startRow, -1);
  const moveDown$1 = (matrix2, startRow, startCol) => moveVertical(matrix2, startCol, startRow, 1);
  const schema$s = [
    requiredObjOf("selectors", [
      required$1("row"),
      required$1("cell")
    ]),
    defaulted("cycles", true),
    defaulted("previousSelector", Optional.none),
    defaulted("execute", defaultExecute)
  ];
  const focusIn$1 = (component, matrixConfig, _state) => {
    const focused = matrixConfig.previousSelector(component).orThunk(() => {
      const selectors = matrixConfig.selectors;
      return descendant(component.element, selectors.cell);
    });
    focused.each((cell) => {
      matrixConfig.focusManager.set(component, cell);
    });
  };
  const execute$1 = (component, simulatedEvent, matrixConfig) => search(component.element).bind((focused) => matrixConfig.execute(component, simulatedEvent, focused));
  const toMatrix = (rows, matrixConfig) => map$2(rows, (row) => descendants(row, matrixConfig.selectors.cell));
  const doMove = (ifCycle, ifMove) => (element2, focused, matrixConfig) => {
    const move2 = matrixConfig.cycles ? ifCycle : ifMove;
    return closest$1(focused, matrixConfig.selectors.row).bind((inRow) => {
      const cellsInRow = descendants(inRow, matrixConfig.selectors.cell);
      return findIndex(cellsInRow, focused).bind((colIndex) => {
        const allRows = descendants(element2, matrixConfig.selectors.row);
        return findIndex(allRows, inRow).bind((rowIndex) => {
          const matrix2 = toMatrix(allRows, matrixConfig);
          return move2(matrix2, rowIndex, colIndex).map((next) => next.cell);
        });
      });
    });
  };
  const moveLeft = doMove(cycleLeft, moveLeft$1);
  const moveRight = doMove(cycleRight, moveRight$1);
  const moveNorth = doMove(cycleUp, moveUp$1);
  const moveSouth = doMove(cycleDown, moveDown$1);
  const getKeydownRules$2 = constant$1([
    rule(inSet(LEFT), west$1(moveLeft, moveRight)),
    rule(inSet(RIGHT), east$1(moveLeft, moveRight)),
    rule(inSet(UP), north$1(moveNorth)),
    rule(inSet(DOWN), south$1(moveSouth)),
    rule(inSet(SPACE.concat(ENTER)), execute$1)
  ]);
  const getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  var MatrixType = typical(schema$s, NoState.init, getKeydownRules$2, getKeyupRules$2, () => Optional.some(focusIn$1));
  const schema$r = [
    required$1("selector"),
    defaulted("execute", defaultExecute),
    defaulted("moveOnTab", false)
  ];
  const execute = (component, simulatedEvent, menuConfig) => menuConfig.focusManager.get(component).bind((focused) => menuConfig.execute(component, simulatedEvent, focused));
  const focusIn = (component, menuConfig, _state) => {
    descendant(component.element, menuConfig.selector).each((first2) => {
      menuConfig.focusManager.set(component, first2);
    });
  };
  const moveUp = (element2, focused, info) => horizontal(element2, info.selector, focused, -1);
  const moveDown = (element2, focused, info) => horizontal(element2, info.selector, focused, 1);
  const fireShiftTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  const fireTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  const getKeydownRules$1 = constant$1([
    rule(inSet(UP), move$1(moveUp)),
    rule(inSet(DOWN), move$1(moveDown)),
    rule(and([
      isShift,
      inSet(TAB)
    ]), fireShiftTab),
    rule(and([
      isNotShift,
      inSet(TAB)
    ]), fireTab),
    rule(inSet(ENTER), execute),
    rule(inSet(SPACE), execute)
  ]);
  const getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  var MenuType = typical(schema$r, NoState.init, getKeydownRules$1, getKeyupRules$1, () => Optional.some(focusIn));
  const schema$q = [
    onKeyboardHandler("onSpace"),
    onKeyboardHandler("onEnter"),
    onKeyboardHandler("onShiftEnter"),
    onKeyboardHandler("onLeft"),
    onKeyboardHandler("onRight"),
    onKeyboardHandler("onTab"),
    onKeyboardHandler("onShiftTab"),
    onKeyboardHandler("onUp"),
    onKeyboardHandler("onDown"),
    onKeyboardHandler("onEscape"),
    defaulted("stopSpaceKeyup", false),
    option$3("focusIn")
  ];
  const getKeydownRules = (component, simulatedEvent, specialInfo) => [
    rule(inSet(SPACE), specialInfo.onSpace),
    rule(and([
      isNotShift,
      inSet(ENTER)
    ]), specialInfo.onEnter),
    rule(and([
      isShift,
      inSet(ENTER)
    ]), specialInfo.onShiftEnter),
    rule(and([
      isShift,
      inSet(TAB)
    ]), specialInfo.onShiftTab),
    rule(and([
      isNotShift,
      inSet(TAB)
    ]), specialInfo.onTab),
    rule(inSet(UP), specialInfo.onUp),
    rule(inSet(DOWN), specialInfo.onDown),
    rule(inSet(LEFT), specialInfo.onLeft),
    rule(inSet(RIGHT), specialInfo.onRight),
    rule(inSet(SPACE), specialInfo.onSpace)
  ];
  const getKeyupRules = (component, simulatedEvent, specialInfo) => [
    ...specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : [],
    rule(inSet(ESCAPE), specialInfo.onEscape)
  ];
  var SpecialType = typical(schema$q, NoState.init, getKeydownRules, getKeyupRules, (specialInfo) => specialInfo.focusIn);
  const acyclic = AcyclicType.schema();
  const cyclic = CyclicType.schema();
  const flow = FlowType.schema();
  const flatgrid = FlatgridType.schema();
  const matrix = MatrixType.schema();
  const execution = ExecutionType.schema();
  const menu = MenuType.schema();
  const special = SpecialType.schema();
  var KeyboardBranches = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    acyclic,
    cyclic,
    flow,
    flatgrid,
    matrix,
    execution,
    menu,
    special
  });
  const isFlatgridState = (keyState) => hasNonNullableKey(keyState, "setGridSize");
  const Keying = createModes({
    branchKey: "mode",
    branches: KeyboardBranches,
    name: "keying",
    active: {
      events: (keyingConfig, keyingState) => {
        const handler = keyingConfig.handler;
        return handler.toEvents(keyingConfig, keyingState);
      }
    },
    apis: {
      focusIn: (component, keyConfig, keyState) => {
        keyConfig.sendFocusIn(keyConfig).fold(() => {
          component.getSystem().triggerFocus(component.element, component.element);
        }, (sendFocusIn) => {
          sendFocusIn(component, keyConfig, keyState);
        });
      },
      setGridSize: (component, keyConfig, keyState, numRows, numColumns) => {
        if (!isFlatgridState(keyState)) {
          console.error("Layout does not support setGridSize");
        } else {
          keyState.setGridSize(numRows, numColumns);
        }
      }
    },
    state: KeyingState
  });
  const withoutReuse = (parent2, data) => {
    preserve$1(() => {
      replaceChildren(parent2, data, () => map$2(data, parent2.getSystem().build));
    }, parent2.element);
  };
  const withReuse = (parent2, data) => {
    preserve$1(() => {
      virtualReplaceChildren(parent2, data, () => {
        return patchSpecChildren(parent2.element, data, parent2.getSystem().buildOrPatch);
      });
    }, parent2.element);
  };
  const virtualReplace = (component, replacee, replaceeIndex, childSpec) => {
    virtualDetach(replacee);
    const child2 = patchSpecChild(component.element, replaceeIndex, childSpec, component.getSystem().buildOrPatch);
    virtualAttach(component, child2);
    component.syncComponents();
  };
  const insert = (component, insertion, childSpec) => {
    const child2 = component.getSystem().build(childSpec);
    attachWith(component, child2, insertion);
  };
  const replace = (component, replacee, replaceeIndex, childSpec) => {
    detach(replacee);
    insert(component, (p, c) => appendAt(p, c, replaceeIndex), childSpec);
  };
  const set$3 = (component, replaceConfig, replaceState, data) => {
    const replacer = replaceConfig.reuseDom ? withReuse : withoutReuse;
    return replacer(component, data);
  };
  const append = (component, replaceConfig, replaceState, appendee) => {
    insert(component, append$2, appendee);
  };
  const prepend = (component, replaceConfig, replaceState, prependee) => {
    insert(component, prepend$1, prependee);
  };
  const remove = (component, replaceConfig, replaceState, removee) => {
    const children2 = contents(component);
    const foundChild = find$5(children2, (child2) => eq(removee.element, child2.element));
    foundChild.each(detach);
  };
  const contents = (component, _replaceConfig) => component.components();
  const replaceAt = (component, replaceConfig, replaceState, replaceeIndex, replacer) => {
    const children2 = contents(component);
    return Optional.from(children2[replaceeIndex]).map((replacee) => {
      replacer.fold(() => detach(replacee), (r2) => {
        const replacer2 = replaceConfig.reuseDom ? virtualReplace : replace;
        replacer2(component, replacee, replaceeIndex, r2);
      });
      return replacee;
    });
  };
  const replaceBy = (component, replaceConfig, replaceState, replaceePred, replacer) => {
    const children2 = contents(component);
    return findIndex$1(children2, replaceePred).bind((replaceeIndex) => replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer));
  };
  var ReplaceApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    append,
    prepend,
    remove,
    replaceAt,
    replaceBy,
    set: set$3,
    contents
  });
  const Replacing = create$3({
    fields: [defaultedBoolean("reuseDom", true)],
    name: "replacing",
    apis: ReplaceApis
  });
  const events$d = (name2, eventHandlers) => {
    const events2 = derive$2(eventHandlers);
    return create$3({
      fields: [required$1("enabled")],
      name: name2,
      active: { events: constant$1(events2) }
    });
  };
  const config = (name2, eventHandlers) => {
    const me = events$d(name2, eventHandlers);
    return {
      key: name2,
      value: {
        config: {},
        me,
        configAsRaw: constant$1({}),
        initialConfig: {},
        state: NoState
      }
    };
  };
  const focus$2 = (component, focusConfig) => {
    if (!focusConfig.ignore) {
      focus$3(component.element);
      focusConfig.onFocus(component);
    }
  };
  const blur = (component, focusConfig) => {
    if (!focusConfig.ignore) {
      blur$1(component.element);
    }
  };
  const isFocused = (component) => hasFocus(component.element);
  var FocusApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    focus: focus$2,
    blur,
    isFocused
  });
  const exhibit$4 = (base2, focusConfig) => {
    const mod = focusConfig.ignore ? {} : { attributes: { tabindex: "-1" } };
    return nu$7(mod);
  };
  const events$c = (focusConfig) => derive$2([run$1(focus$4(), (component, simulatedEvent) => {
    focus$2(component, focusConfig);
    simulatedEvent.stop();
  })].concat(focusConfig.stopMousedown ? [run$1(mousedown(), (_, simulatedEvent) => {
    simulatedEvent.event.prevent();
  })] : []));
  var ActiveFocus = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit: exhibit$4,
    events: events$c
  });
  var FocusSchema = [
    onHandler("onFocus"),
    defaulted("stopMousedown", false),
    defaulted("ignore", false)
  ];
  const Focusing = create$3({
    fields: FocusSchema,
    name: "focusing",
    active: ActiveFocus,
    apis: FocusApis
  });
  const SetupBehaviourCellState = (initialState) => {
    const init2 = () => {
      const cell = Cell(initialState);
      const get2 = () => cell.get();
      const set2 = (newState) => cell.set(newState);
      const clear2 = () => cell.set(initialState);
      const readState = () => cell.get();
      return {
        get: get2,
        set: set2,
        clear: clear2,
        readState
      };
    };
    return { init: init2 };
  };
  const updateAriaState = (component, toggleConfig, toggleState) => {
    const ariaInfo = toggleConfig.aria;
    ariaInfo.update(component, ariaInfo, toggleState.get());
  };
  const updateClass = (component, toggleConfig, toggleState) => {
    toggleConfig.toggleClass.each((toggleClass) => {
      if (toggleState.get()) {
        add$2(component.element, toggleClass);
      } else {
        remove$2(component.element, toggleClass);
      }
    });
  };
  const set$2 = (component, toggleConfig, toggleState, state) => {
    const initialState = toggleState.get();
    toggleState.set(state);
    updateClass(component, toggleConfig, toggleState);
    updateAriaState(component, toggleConfig, toggleState);
    if (initialState !== state) {
      toggleConfig.onToggled(component, state);
    }
  };
  const toggle$2 = (component, toggleConfig, toggleState) => {
    set$2(component, toggleConfig, toggleState, !toggleState.get());
  };
  const on = (component, toggleConfig, toggleState) => {
    set$2(component, toggleConfig, toggleState, true);
  };
  const off = (component, toggleConfig, toggleState) => {
    set$2(component, toggleConfig, toggleState, false);
  };
  const isOn = (component, toggleConfig, toggleState) => toggleState.get();
  const onLoad = (component, toggleConfig, toggleState) => {
    set$2(component, toggleConfig, toggleState, toggleConfig.selected);
  };
  var ToggleApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    onLoad,
    toggle: toggle$2,
    isOn,
    on,
    off,
    set: set$2
  });
  const exhibit$3 = () => nu$7({});
  const events$b = (toggleConfig, toggleState) => {
    const execute2 = executeEvent(toggleConfig, toggleState, toggle$2);
    const load = loadEvent(toggleConfig, toggleState, onLoad);
    return derive$2(flatten([
      toggleConfig.toggleOnExecute ? [execute2] : [],
      [load]
    ]));
  };
  var ActiveToggle = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit: exhibit$3,
    events: events$b
  });
  const updatePressed = (component, ariaInfo, status) => {
    set$9(component.element, "aria-pressed", status);
    if (ariaInfo.syncWithExpanded) {
      updateExpanded(component, ariaInfo, status);
    }
  };
  const updateSelected = (component, ariaInfo, status) => {
    set$9(component.element, "aria-selected", status);
  };
  const updateChecked = (component, ariaInfo, status) => {
    set$9(component.element, "aria-checked", status);
  };
  const updateExpanded = (component, ariaInfo, status) => {
    set$9(component.element, "aria-expanded", status);
  };
  var ToggleSchema = [
    defaulted("selected", false),
    option$3("toggleClass"),
    defaulted("toggleOnExecute", true),
    onHandler("onToggled"),
    defaultedOf("aria", { mode: "none" }, choose$1("mode", {
      pressed: [
        defaulted("syncWithExpanded", false),
        output$1("update", updatePressed)
      ],
      checked: [output$1("update", updateChecked)],
      expanded: [output$1("update", updateExpanded)],
      selected: [output$1("update", updateSelected)],
      none: [output$1("update", noop)]
    }))
  ];
  const Toggling = create$3({
    fields: ToggleSchema,
    name: "toggling",
    active: ActiveToggle,
    apis: ToggleApis,
    state: SetupBehaviourCellState(false)
  });
  const pointerEvents = () => {
    const onClick = (component, simulatedEvent) => {
      simulatedEvent.stop();
      emitExecute(component);
    };
    return [
      run$1(click(), onClick),
      run$1(tap(), onClick),
      cutter(touchstart()),
      cutter(mousedown())
    ];
  };
  const events$a = (optAction) => {
    const executeHandler = (action) => runOnExecute$1((component, simulatedEvent) => {
      action(component);
      simulatedEvent.stop();
    });
    return derive$2(flatten([
      optAction.map(executeHandler).toArray(),
      pointerEvents()
    ]));
  };
  const hoverEvent = "alloy.item-hover";
  const focusEvent = "alloy.item-focus";
  const toggledEvent = "alloy.item-toggled";
  const onHover = (item2) => {
    if (search(item2.element).isNone() || Focusing.isFocused(item2)) {
      if (!Focusing.isFocused(item2)) {
        Focusing.focus(item2);
      }
      emitWith(item2, hoverEvent, { item: item2 });
    }
  };
  const onFocus$1 = (item2) => {
    emitWith(item2, focusEvent, { item: item2 });
  };
  const onToggled = (item2, state) => {
    emitWith(item2, toggledEvent, {
      item: item2,
      state
    });
  };
  const hover = constant$1(hoverEvent);
  const focus$1 = constant$1(focusEvent);
  const toggled = constant$1(toggledEvent);
  const getItemRole = (detail) => detail.toggling.map((toggling) => toggling.exclusive ? "menuitemradio" : "menuitemcheckbox").getOr("menuitem");
  const getTogglingSpec = (tConfig) => ({
    aria: { mode: "checked" },
    ...filter$1(tConfig, (_value, name2) => name2 !== "exclusive"),
    onToggled: (component, state) => {
      if (isFunction(tConfig.onToggled)) {
        tConfig.onToggled(component, state);
      }
      onToggled(component, state);
    }
  });
  const builder$2 = (detail) => ({
    dom: detail.dom,
    domModification: {
      ...detail.domModification,
      attributes: {
        "role": getItemRole(detail),
        ...detail.domModification.attributes,
        "aria-haspopup": detail.hasSubmenu,
        ...detail.hasSubmenu ? { "aria-expanded": false } : {}
      }
    },
    behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
      detail.toggling.fold(Toggling.revoke, (tConfig) => Toggling.config(getTogglingSpec(tConfig))),
      Focusing.config({
        ignore: detail.ignoreFocus,
        stopMousedown: detail.ignoreFocus,
        onFocus: (component) => {
          onFocus$1(component);
        }
      }),
      Keying.config({ mode: "execution" }),
      Representing.config({
        store: {
          mode: "memory",
          initialValue: detail.data
        }
      }),
      config("item-type-events", [
        ...pointerEvents(),
        run$1(mouseover(), onHover),
        run$1(focusItem(), Focusing.focus)
      ])
    ]),
    components: detail.components,
    eventOrder: detail.eventOrder
  });
  const schema$p = [
    required$1("data"),
    required$1("components"),
    required$1("dom"),
    defaulted("hasSubmenu", false),
    option$3("toggling"),
    SketchBehaviours.field("itemBehaviours", [
      Toggling,
      Focusing,
      Keying,
      Representing
    ]),
    defaulted("ignoreFocus", false),
    defaulted("domModification", {}),
    output$1("builder", builder$2),
    defaulted("eventOrder", {})
  ];
  const builder$1 = (detail) => ({
    dom: detail.dom,
    components: detail.components,
    events: derive$2([stopper(focusItem())])
  });
  const schema$o = [
    required$1("dom"),
    required$1("components"),
    output$1("builder", builder$1)
  ];
  const owner$2 = constant$1("item-widget");
  const parts$h = constant$1([required({
    name: "widget",
    overrides: (detail) => {
      return {
        behaviours: derive$1([Representing.config({
          store: {
            mode: "manual",
            getValue: (_component) => {
              return detail.data;
            },
            setValue: noop
          }
        })])
      };
    }
  })]);
  const builder = (detail) => {
    const subs2 = substitutes(owner$2(), detail, parts$h());
    const components2 = components$1(owner$2(), detail, subs2.internals());
    const focusWidget = (component) => getPart(component, detail, "widget").map((widget) => {
      Keying.focusIn(widget);
      return widget;
    });
    const onHorizontalArrow = (component, simulatedEvent) => inside(simulatedEvent.event.target) ? Optional.none() : (() => {
      if (detail.autofocus) {
        simulatedEvent.setSource(component.element);
        return Optional.none();
      } else {
        return Optional.none();
      }
    })();
    return {
      dom: detail.dom,
      components: components2,
      domModification: detail.domModification,
      events: derive$2([
        runOnExecute$1((component, simulatedEvent) => {
          focusWidget(component).each((_widget) => {
            simulatedEvent.stop();
          });
        }),
        run$1(mouseover(), onHover),
        run$1(focusItem(), (component, _simulatedEvent) => {
          if (detail.autofocus) {
            focusWidget(component);
          } else {
            Focusing.focus(component);
          }
        })
      ]),
      behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
        Representing.config({
          store: {
            mode: "memory",
            initialValue: detail.data
          }
        }),
        Focusing.config({
          ignore: detail.ignoreFocus,
          onFocus: (component) => {
            onFocus$1(component);
          }
        }),
        Keying.config({
          mode: "special",
          focusIn: detail.autofocus ? (component) => {
            focusWidget(component);
          } : revoke(),
          onLeft: onHorizontalArrow,
          onRight: onHorizontalArrow,
          onEscape: (component, simulatedEvent) => {
            if (!Focusing.isFocused(component) && !detail.autofocus) {
              Focusing.focus(component);
              return Optional.some(true);
            } else if (detail.autofocus) {
              simulatedEvent.setSource(component.element);
              return Optional.none();
            } else {
              return Optional.none();
            }
          }
        })
      ])
    };
  };
  const schema$n = [
    required$1("uid"),
    required$1("data"),
    required$1("components"),
    required$1("dom"),
    defaulted("autofocus", false),
    defaulted("ignoreFocus", false),
    SketchBehaviours.field("widgetBehaviours", [
      Representing,
      Focusing,
      Keying
    ]),
    defaulted("domModification", {}),
    defaultUidsSchema(parts$h()),
    output$1("builder", builder)
  ];
  const itemSchema$2 = choose$1("type", {
    widget: schema$n,
    item: schema$p,
    separator: schema$o
  });
  const configureGrid = (detail, movementInfo) => ({
    mode: "flatgrid",
    selector: "." + detail.markers.item,
    initSize: {
      numColumns: movementInfo.initSize.numColumns,
      numRows: movementInfo.initSize.numRows
    },
    focusManager: detail.focusManager
  });
  const configureMatrix = (detail, movementInfo) => ({
    mode: "matrix",
    selectors: {
      row: movementInfo.rowSelector,
      cell: "." + detail.markers.item
    },
    focusManager: detail.focusManager
  });
  const configureMenu = (detail, movementInfo) => ({
    mode: "menu",
    selector: "." + detail.markers.item,
    moveOnTab: movementInfo.moveOnTab,
    focusManager: detail.focusManager
  });
  const parts$g = constant$1([group({
    factory: {
      sketch: (spec) => {
        const itemInfo = asRawOrDie$1("menu.spec item", itemSchema$2, spec);
        return itemInfo.builder(itemInfo);
      }
    },
    name: "items",
    unit: "item",
    defaults: (detail, u) => {
      return has$2(u, "uid") ? u : {
        ...u,
        uid: generate$5("item")
      };
    },
    overrides: (detail, u) => {
      return {
        type: u.type,
        ignoreFocus: detail.fakeFocus,
        domModification: { classes: [detail.markers.item] }
      };
    }
  })]);
  const schema$m = constant$1([
    required$1("value"),
    required$1("items"),
    required$1("dom"),
    required$1("components"),
    defaulted("eventOrder", {}),
    field("menuBehaviours", [
      Highlighting,
      Representing,
      Composing,
      Keying
    ]),
    defaultedOf("movement", {
      mode: "menu",
      moveOnTab: true
    }, choose$1("mode", {
      grid: [
        initSize(),
        output$1("config", configureGrid)
      ],
      matrix: [
        output$1("config", configureMatrix),
        required$1("rowSelector")
      ],
      menu: [
        defaulted("moveOnTab", true),
        output$1("config", configureMenu)
      ]
    })),
    itemMarkers(),
    defaulted("fakeFocus", false),
    defaulted("focusManager", dom$2()),
    onHandler("onHighlight")
  ]);
  const focus = constant$1("alloy.menu-focus");
  const deselectOtherRadioItems = (menu2, item2) => {
    const checkedRadioItems = descendants(menu2.element, '[role="menuitemradio"][aria-checked="true"]');
    each$1(checkedRadioItems, (ele) => {
      if (!eq(ele, item2.element)) {
        menu2.getSystem().getByDom(ele).each((c) => {
          Toggling.off(c);
        });
      }
    });
  };
  const make$7 = (detail, components2, _spec, _externals) => ({
    uid: detail.uid,
    dom: detail.dom,
    markers: detail.markers,
    behaviours: augment(detail.menuBehaviours, [
      Highlighting.config({
        highlightClass: detail.markers.selectedItem,
        itemClass: detail.markers.item,
        onHighlight: detail.onHighlight
      }),
      Representing.config({
        store: {
          mode: "memory",
          initialValue: detail.value
        }
      }),
      Composing.config({ find: Optional.some }),
      Keying.config(detail.movement.config(detail, detail.movement))
    ]),
    events: derive$2([
      run$1(focus$1(), (menu2, simulatedEvent) => {
        const event = simulatedEvent.event;
        menu2.getSystem().getByDom(event.target).each((item2) => {
          Highlighting.highlight(menu2, item2);
          simulatedEvent.stop();
          emitWith(menu2, focus(), {
            menu: menu2,
            item: item2
          });
        });
      }),
      run$1(hover(), (menu2, simulatedEvent) => {
        const item2 = simulatedEvent.event.item;
        Highlighting.highlight(menu2, item2);
      }),
      run$1(toggled(), (menu2, simulatedEvent) => {
        const { item: item2, state } = simulatedEvent.event;
        if (state && get$f(item2.element, "role") === "menuitemradio") {
          deselectOtherRadioItems(menu2, item2);
        }
      })
    ]),
    components: components2,
    eventOrder: detail.eventOrder,
    domModification: { attributes: { role: "menu" } }
  });
  const Menu = composite({
    name: "Menu",
    configFields: schema$m(),
    partFields: parts$g(),
    factory: make$7
  });
  const transpose$1 = (obj) => tupleMap(obj, (v, k) => ({
    k: v,
    v: k
  }));
  const trace = (items, byItem, byMenu, finish) => get$g(byMenu, finish).bind((triggerItem) => get$g(items, triggerItem).bind((triggerMenu) => {
    const rest = trace(items, byItem, byMenu, triggerMenu);
    return Optional.some([triggerMenu].concat(rest));
  })).getOr([]);
  const generate$2 = (menus, expansions) => {
    const items = {};
    each(menus, (menuItems, menu2) => {
      each$1(menuItems, (item2) => {
        items[item2] = menu2;
      });
    });
    const byItem = expansions;
    const byMenu = transpose$1(expansions);
    const menuPaths = map$1(byMenu, (_triggerItem, submenu) => [submenu].concat(trace(items, byItem, byMenu, submenu)));
    return map$1(items, (menu2) => get$g(menuPaths, menu2).getOr([menu2]));
  };
  const init$c = () => {
    const expansions = Cell({});
    const menus = Cell({});
    const paths = Cell({});
    const primary2 = value$2();
    const directory = Cell({});
    const clear2 = () => {
      expansions.set({});
      menus.set({});
      paths.set({});
      primary2.clear();
    };
    const isClear = () => primary2.get().isNone();
    const setMenuBuilt = (menuName, built) => {
      menus.set({
        ...menus.get(),
        [menuName]: {
          type: "prepared",
          menu: built
        }
      });
    };
    const setContents = (sPrimary, sMenus, sExpansions, dir) => {
      primary2.set(sPrimary);
      expansions.set(sExpansions);
      menus.set(sMenus);
      directory.set(dir);
      const sPaths = generate$2(dir, sExpansions);
      paths.set(sPaths);
    };
    const getTriggeringItem = (menuValue) => find$4(expansions.get(), (v, _k) => v === menuValue);
    const getTriggerData = (menuValue, getItemByValue, path2) => getPreparedMenu(menuValue).bind((menu2) => getTriggeringItem(menuValue).bind((triggeringItemValue) => getItemByValue(triggeringItemValue).map((triggeredItem) => ({
      triggeredMenu: menu2,
      triggeringItem: triggeredItem,
      triggeringPath: path2
    }))));
    const getTriggeringPath = (itemValue, getItemByValue) => {
      const extraPath = filter$2(lookupItem(itemValue).toArray(), (menuValue) => getPreparedMenu(menuValue).isSome());
      return get$g(paths.get(), itemValue).bind((path2) => {
        const revPath = reverse(extraPath.concat(path2));
        const triggers = bind$3(revPath, (menuValue, menuIndex) => getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(() => is$1(primary2.get(), menuValue) ? [] : [Optional.none()], (data) => [Optional.some(data)]));
        return sequence(triggers);
      });
    };
    const expand2 = (itemValue) => get$g(expansions.get(), itemValue).map((menu2) => {
      const current = get$g(paths.get(), itemValue).getOr([]);
      return [menu2].concat(current);
    });
    const collapse = (itemValue) => get$g(paths.get(), itemValue).bind((path2) => path2.length > 1 ? Optional.some(path2.slice(1)) : Optional.none());
    const refresh2 = (itemValue) => get$g(paths.get(), itemValue);
    const getPreparedMenu = (menuValue) => lookupMenu(menuValue).bind(extractPreparedMenu);
    const lookupMenu = (menuValue) => get$g(menus.get(), menuValue);
    const lookupItem = (itemValue) => get$g(expansions.get(), itemValue);
    const otherMenus = (path2) => {
      const menuValues = directory.get();
      return difference(keys(menuValues), path2);
    };
    const getPrimary = () => primary2.get().bind(getPreparedMenu);
    const getMenus2 = () => menus.get();
    return {
      setMenuBuilt,
      setContents,
      expand: expand2,
      refresh: refresh2,
      collapse,
      lookupMenu,
      lookupItem,
      otherMenus,
      getPrimary,
      getMenus: getMenus2,
      clear: clear2,
      isClear,
      getTriggeringPath
    };
  };
  const extractPreparedMenu = (prep) => prep.type === "prepared" ? Optional.some(prep.menu) : Optional.none();
  const LayeredState = {
    init: init$c,
    extractPreparedMenu
  };
  const make$6 = (detail, _rawUiSpec) => {
    const submenuParentItems = value$2();
    const buildMenus = (container, primaryName, menus) => map$1(menus, (spec, name2) => {
      const makeSketch = () => Menu.sketch({
        ...spec,
        value: name2,
        markers: detail.markers,
        fakeFocus: detail.fakeFocus,
        onHighlight: detail.onHighlight,
        focusManager: detail.fakeFocus ? highlights() : dom$2()
      });
      return name2 === primaryName ? {
        type: "prepared",
        menu: container.getSystem().build(makeSketch())
      } : {
        type: "notbuilt",
        nbMenu: makeSketch
      };
    });
    const layeredState = LayeredState.init();
    const setup2 = (container) => {
      const componentMap = buildMenus(container, detail.data.primary, detail.data.menus);
      const directory = toDirectory();
      layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory);
      return layeredState.getPrimary();
    };
    const getItemValue = (item2) => Representing.getValue(item2).value;
    const getItemByValue = (_container, menus, itemValue) => findMap(menus, (menu2) => {
      if (!menu2.getSystem().isConnected()) {
        return Optional.none();
      }
      const candidates = Highlighting.getCandidates(menu2);
      return find$5(candidates, (c) => getItemValue(c) === itemValue);
    });
    const toDirectory = (_container) => map$1(detail.data.menus, (data, _menuName) => bind$3(data.items, (item2) => item2.type === "separator" ? [] : [item2.data.value]));
    const setActiveMenu = (container, menu2) => {
      Highlighting.highlight(container, menu2);
      Highlighting.getHighlighted(menu2).orThunk(() => Highlighting.getFirst(menu2)).each((item2) => {
        dispatch(container, item2.element, focusItem());
      });
    };
    const getMenus2 = (state, menuValues) => cat(map$2(menuValues, (mv) => state.lookupMenu(mv).bind((prep) => prep.type === "prepared" ? Optional.some(prep.menu) : Optional.none())));
    const closeOthers = (container, state, path2) => {
      const others = getMenus2(state, state.otherMenus(path2));
      each$1(others, (o) => {
        remove$1(o.element, [detail.markers.backgroundMenu]);
        if (!detail.stayInDom) {
          Replacing.remove(container, o);
        }
      });
    };
    const getSubmenuParents = (container) => submenuParentItems.get().getOrThunk(() => {
      const r2 = {};
      const items = descendants(container.element, `.${detail.markers.item}`);
      const parentItems = filter$2(items, (i) => get$f(i, "aria-haspopup") === "true");
      each$1(parentItems, (i) => {
        container.getSystem().getByDom(i).each((itemComp) => {
          const key = getItemValue(itemComp);
          r2[key] = itemComp;
        });
      });
      submenuParentItems.set(r2);
      return r2;
    });
    const updateAriaExpansions = (container, path2) => {
      const parentItems = getSubmenuParents(container);
      each(parentItems, (v, k) => {
        const expanded = contains$2(path2, k);
        set$9(v.element, "aria-expanded", expanded);
      });
    };
    const updateMenuPath = (container, state, path2) => Optional.from(path2[0]).bind((latestMenuName) => state.lookupMenu(latestMenuName).bind((menuPrep) => {
      if (menuPrep.type === "notbuilt") {
        return Optional.none();
      } else {
        const activeMenu = menuPrep.menu;
        const rest = getMenus2(state, path2.slice(1));
        each$1(rest, (r2) => {
          add$2(r2.element, detail.markers.backgroundMenu);
        });
        if (!inBody(activeMenu.element)) {
          Replacing.append(container, premade(activeMenu));
        }
        remove$1(activeMenu.element, [detail.markers.backgroundMenu]);
        setActiveMenu(container, activeMenu);
        closeOthers(container, state, path2);
        return Optional.some(activeMenu);
      }
    }));
    let ExpandHighlightDecision;
    (function(ExpandHighlightDecision2) {
      ExpandHighlightDecision2[ExpandHighlightDecision2["HighlightSubmenu"] = 0] = "HighlightSubmenu";
      ExpandHighlightDecision2[ExpandHighlightDecision2["HighlightParent"] = 1] = "HighlightParent";
    })(ExpandHighlightDecision || (ExpandHighlightDecision = {}));
    const buildIfRequired = (container, menuName, menuPrep) => {
      if (menuPrep.type === "notbuilt") {
        const menu2 = container.getSystem().build(menuPrep.nbMenu());
        layeredState.setMenuBuilt(menuName, menu2);
        return menu2;
      } else {
        return menuPrep.menu;
      }
    };
    const expandRight = (container, item2, decision = ExpandHighlightDecision.HighlightSubmenu) => {
      if (item2.hasConfigured(Disabling) && Disabling.isDisabled(item2)) {
        return Optional.some(item2);
      } else {
        const value2 = getItemValue(item2);
        return layeredState.expand(value2).bind((path2) => {
          updateAriaExpansions(container, path2);
          return Optional.from(path2[0]).bind((menuName) => layeredState.lookupMenu(menuName).bind((activeMenuPrep) => {
            const activeMenu = buildIfRequired(container, menuName, activeMenuPrep);
            if (!inBody(activeMenu.element)) {
              Replacing.append(container, premade(activeMenu));
            }
            detail.onOpenSubmenu(container, item2, activeMenu, reverse(path2));
            if (decision === ExpandHighlightDecision.HighlightSubmenu) {
              Highlighting.highlightFirst(activeMenu);
              return updateMenuPath(container, layeredState, path2);
            } else {
              Highlighting.dehighlightAll(activeMenu);
              return Optional.some(item2);
            }
          }));
        });
      }
    };
    const collapseLeft = (container, item2) => {
      const value2 = getItemValue(item2);
      return layeredState.collapse(value2).bind((path2) => {
        updateAriaExpansions(container, path2);
        return updateMenuPath(container, layeredState, path2).map((activeMenu) => {
          detail.onCollapseMenu(container, item2, activeMenu);
          return activeMenu;
        });
      });
    };
    const updateView = (container, item2) => {
      const value2 = getItemValue(item2);
      return layeredState.refresh(value2).bind((path2) => {
        updateAriaExpansions(container, path2);
        return updateMenuPath(container, layeredState, path2);
      });
    };
    const onRight2 = (container, item2) => inside(item2.element) ? Optional.none() : expandRight(container, item2, ExpandHighlightDecision.HighlightSubmenu);
    const onLeft2 = (container, item2) => inside(item2.element) ? Optional.none() : collapseLeft(container, item2);
    const onEscape = (container, item2) => collapseLeft(container, item2).orThunk(() => detail.onEscape(container, item2).map(() => container));
    const keyOnItem = (f) => (container, simulatedEvent) => closest$1(simulatedEvent.getSource(), "." + detail.markers.item).bind((target) => container.getSystem().getByDom(target).toOptional().bind((item2) => f(container, item2).map(always)));
    const events2 = derive$2([
      run$1(focus(), (sandbox, simulatedEvent) => {
        const item2 = simulatedEvent.event.item;
        layeredState.lookupItem(getItemValue(item2)).each(() => {
          const menu2 = simulatedEvent.event.menu;
          Highlighting.highlight(sandbox, menu2);
          const value2 = getItemValue(simulatedEvent.event.item);
          layeredState.refresh(value2).each((path2) => closeOthers(sandbox, layeredState, path2));
        });
      }),
      runOnExecute$1((component, simulatedEvent) => {
        const target = simulatedEvent.event.target;
        component.getSystem().getByDom(target).each((item2) => {
          const itemValue = getItemValue(item2);
          if (itemValue.indexOf("collapse-item") === 0) {
            collapseLeft(component, item2);
          }
          expandRight(component, item2, ExpandHighlightDecision.HighlightSubmenu).fold(() => {
            detail.onExecute(component, item2);
          }, noop);
        });
      }),
      runOnAttached((container, _simulatedEvent) => {
        setup2(container).each((primary2) => {
          Replacing.append(container, premade(primary2));
          detail.onOpenMenu(container, primary2);
          if (detail.highlightImmediately) {
            setActiveMenu(container, primary2);
          }
        });
      })
    ].concat(detail.navigateOnHover ? [run$1(hover(), (sandbox, simulatedEvent) => {
      const item2 = simulatedEvent.event.item;
      updateView(sandbox, item2);
      expandRight(sandbox, item2, ExpandHighlightDecision.HighlightParent);
      detail.onHover(sandbox, item2);
    })] : []));
    const getActiveItem = (container) => Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted);
    const collapseMenuApi = (container) => {
      getActiveItem(container).each((currentItem) => {
        collapseLeft(container, currentItem);
      });
    };
    const highlightPrimary = (container) => {
      layeredState.getPrimary().each((primary2) => {
        setActiveMenu(container, primary2);
      });
    };
    const extractMenuFromContainer = (container) => Optional.from(container.components()[0]).filter((comp) => get$f(comp.element, "role") === "menu");
    const repositionMenus2 = (container) => {
      const maybeActivePrimary = layeredState.getPrimary().bind((primary2) => getActiveItem(container).bind((currentItem) => {
        const itemValue = getItemValue(currentItem);
        const allMenus = values(layeredState.getMenus());
        const preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu));
        return layeredState.getTriggeringPath(itemValue, (v) => getItemByValue(container, preparedMenus, v));
      }).map((triggeringPath) => ({
        primary: primary2,
        triggeringPath
      })));
      maybeActivePrimary.fold(() => {
        extractMenuFromContainer(container).each((primaryMenu) => {
          detail.onRepositionMenu(container, primaryMenu, []);
        });
      }, ({ primary: primary2, triggeringPath }) => {
        detail.onRepositionMenu(container, primary2, triggeringPath);
      });
    };
    const apis = {
      collapseMenu: collapseMenuApi,
      highlightPrimary,
      repositionMenus: repositionMenus2
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      markers: detail.markers,
      behaviours: augment(detail.tmenuBehaviours, [
        Keying.config({
          mode: "special",
          onRight: keyOnItem(onRight2),
          onLeft: keyOnItem(onLeft2),
          onEscape: keyOnItem(onEscape),
          focusIn: (container, _keyInfo) => {
            layeredState.getPrimary().each((primary2) => {
              dispatch(container, primary2.element, focusItem());
            });
          }
        }),
        Highlighting.config({
          highlightClass: detail.markers.selectedMenu,
          itemClass: detail.markers.menu
        }),
        Composing.config({
          find: (container) => {
            return Highlighting.getHighlighted(container);
          }
        }),
        Replacing.config({})
      ]),
      eventOrder: detail.eventOrder,
      apis,
      events: events2
    };
  };
  const collapseItem$1 = constant$1("collapse-item");
  const tieredData = (primary2, menus, expansions) => ({
    primary: primary2,
    menus,
    expansions
  });
  const singleData = (name2, menu2) => ({
    primary: name2,
    menus: wrap$1(name2, menu2),
    expansions: {}
  });
  const collapseItem = (text2) => ({
    value: generate$6(collapseItem$1()),
    meta: { text: text2 }
  });
  const tieredMenu = single({
    name: "TieredMenu",
    configFields: [
      onStrictKeyboardHandler("onExecute"),
      onStrictKeyboardHandler("onEscape"),
      onStrictHandler("onOpenMenu"),
      onStrictHandler("onOpenSubmenu"),
      onHandler("onRepositionMenu"),
      onHandler("onCollapseMenu"),
      defaulted("highlightImmediately", true),
      requiredObjOf("data", [
        required$1("primary"),
        required$1("menus"),
        required$1("expansions")
      ]),
      defaulted("fakeFocus", false),
      onHandler("onHighlight"),
      onHandler("onHover"),
      tieredMenuMarkers(),
      required$1("dom"),
      defaulted("navigateOnHover", true),
      defaulted("stayInDom", false),
      field("tmenuBehaviours", [
        Keying,
        Highlighting,
        Composing,
        Replacing
      ]),
      defaulted("eventOrder", {})
    ],
    apis: {
      collapseMenu: (apis, tmenu) => {
        apis.collapseMenu(tmenu);
      },
      highlightPrimary: (apis, tmenu) => {
        apis.highlightPrimary(tmenu);
      },
      repositionMenus: (apis, tmenu) => {
        apis.repositionMenus(tmenu);
      }
    },
    factory: make$6,
    extraApis: {
      tieredData,
      singleData,
      collapseItem
    }
  });
  const makeMenu = (detail, menuSandbox, placementSpec, menuSpec, getBounds2) => {
    const lazySink = () => detail.lazySink(menuSandbox);
    const layouts2 = menuSpec.type === "horizontal" ? {
      layouts: {
        onLtr: () => belowOrAbove(),
        onRtl: () => belowOrAboveRtl()
      }
    } : {};
    const isFirstTierSubmenu = (triggeringPaths) => triggeringPaths.length === 2;
    const getSubmenuLayouts = (triggeringPaths) => isFirstTierSubmenu(triggeringPaths) ? layouts2 : {};
    return tieredMenu.sketch({
      dom: { tag: "div" },
      data: menuSpec.data,
      markers: menuSpec.menu.markers,
      highlightImmediately: menuSpec.menu.highlightImmediately,
      fakeFocus: menuSpec.menu.fakeFocus,
      onEscape: () => {
        Sandboxing.close(menuSandbox);
        detail.onEscape.map((handler) => handler(menuSandbox));
        return Optional.some(true);
      },
      onExecute: () => {
        return Optional.some(true);
      },
      onOpenMenu: (tmenu, menu2) => {
        Positioning.positionWithinBounds(lazySink().getOrDie(), menu2, placementSpec, getBounds2());
      },
      onOpenSubmenu: (tmenu, item2, submenu, triggeringPaths) => {
        const sink = lazySink().getOrDie();
        Positioning.position(sink, submenu, {
          anchor: {
            type: "submenu",
            item: item2,
            ...getSubmenuLayouts(triggeringPaths)
          }
        });
      },
      onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
        const sink = lazySink().getOrDie();
        Positioning.positionWithinBounds(sink, primaryMenu, placementSpec, getBounds2());
        each$1(submenuTriggers, (st) => {
          const submenuLayouts = getSubmenuLayouts(st.triggeringPath);
          Positioning.position(sink, st.triggeredMenu, {
            anchor: {
              type: "submenu",
              item: st.triggeringItem,
              ...submenuLayouts
            }
          });
        });
      }
    });
  };
  const factory$m = (detail, spec) => {
    const isPartOfRelated = (sandbox, queryElem) => {
      const related = detail.getRelated(sandbox);
      return related.exists((rel) => isPartOf$1(rel, queryElem));
    };
    const setContent2 = (sandbox, thing) => {
      Sandboxing.setContent(sandbox, thing);
    };
    const showAt = (sandbox, thing, placementSpec) => {
      showWithin(sandbox, thing, placementSpec, Optional.none());
    };
    const showWithin = (sandbox, thing, placementSpec, boxElement) => {
      showWithinBounds(sandbox, thing, placementSpec, () => boxElement.map((elem) => box$1(elem)));
    };
    const showWithinBounds = (sandbox, thing, placementSpec, getBounds2) => {
      const sink = detail.lazySink(sandbox).getOrDie();
      Sandboxing.openWhileCloaked(sandbox, thing, () => Positioning.positionWithinBounds(sink, sandbox, placementSpec, getBounds2()));
      Representing.setValue(sandbox, Optional.some({
        mode: "position",
        config: placementSpec,
        getBounds: getBounds2
      }));
    };
    const showMenuAt = (sandbox, placementSpec, menuSpec) => {
      showMenuWithinBounds(sandbox, placementSpec, menuSpec, Optional.none);
    };
    const showMenuWithinBounds = (sandbox, placementSpec, menuSpec, getBounds2) => {
      const menu2 = makeMenu(detail, sandbox, placementSpec, menuSpec, getBounds2);
      Sandboxing.open(sandbox, menu2);
      Representing.setValue(sandbox, Optional.some({
        mode: "menu",
        menu: menu2
      }));
    };
    const hide = (sandbox) => {
      if (Sandboxing.isOpen(sandbox)) {
        Representing.setValue(sandbox, Optional.none());
        Sandboxing.close(sandbox);
      }
    };
    const getContent = (sandbox) => Sandboxing.getState(sandbox);
    const reposition2 = (sandbox) => {
      if (Sandboxing.isOpen(sandbox)) {
        Representing.getValue(sandbox).each((state) => {
          switch (state.mode) {
            case "menu":
              Sandboxing.getState(sandbox).each(tieredMenu.repositionMenus);
              break;
            case "position":
              const sink = detail.lazySink(sandbox).getOrDie();
              Positioning.positionWithinBounds(sink, sandbox, state.config, state.getBounds());
              break;
          }
        });
      }
    };
    const apis = {
      setContent: setContent2,
      showAt,
      showWithin,
      showWithinBounds,
      showMenuAt,
      showMenuWithinBounds,
      hide,
      getContent,
      reposition: reposition2,
      isOpen: Sandboxing.isOpen
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      behaviours: augment(detail.inlineBehaviours, [
        Sandboxing.config({
          isPartOf: (sandbox, data, queryElem) => {
            return isPartOf$1(data, queryElem) || isPartOfRelated(sandbox, queryElem);
          },
          getAttachPoint: (sandbox) => {
            return detail.lazySink(sandbox).getOrDie();
          },
          onOpen: (sandbox) => {
            detail.onShow(sandbox);
          },
          onClose: (sandbox) => {
            detail.onHide(sandbox);
          }
        }),
        Representing.config({
          store: {
            mode: "memory",
            initialValue: Optional.none()
          }
        }),
        Receiving.config({
          channels: {
            ...receivingChannel$1({
              isExtraPart: spec.isExtraPart,
              ...detail.fireDismissalEventInstead.map((fe) => ({ fireEventInstead: { event: fe.event } })).getOr({})
            }),
            ...receivingChannel({
              ...detail.fireRepositionEventInstead.map((fe) => ({ fireEventInstead: { event: fe.event } })).getOr({}),
              doReposition: reposition2
            })
          }
        })
      ]),
      eventOrder: detail.eventOrder,
      apis
    };
  };
  const InlineView = single({
    name: "InlineView",
    configFields: [
      required$1("lazySink"),
      onHandler("onShow"),
      onHandler("onHide"),
      optionFunction("onEscape"),
      field("inlineBehaviours", [
        Sandboxing,
        Representing,
        Receiving
      ]),
      optionObjOf("fireDismissalEventInstead", [defaulted("event", dismissRequested())]),
      optionObjOf("fireRepositionEventInstead", [defaulted("event", repositionRequested())]),
      defaulted("getRelated", Optional.none),
      defaulted("isExtraPart", never),
      defaulted("eventOrder", Optional.none)
    ],
    factory: factory$m,
    apis: {
      showAt: (apis, component, anchor2, thing) => {
        apis.showAt(component, anchor2, thing);
      },
      showWithin: (apis, component, anchor2, thing, boxElement) => {
        apis.showWithin(component, anchor2, thing, boxElement);
      },
      showWithinBounds: (apis, component, anchor2, thing, bounds2) => {
        apis.showWithinBounds(component, anchor2, thing, bounds2);
      },
      showMenuAt: (apis, component, anchor2, menuSpec) => {
        apis.showMenuAt(component, anchor2, menuSpec);
      },
      showMenuWithinBounds: (apis, component, anchor2, menuSpec, bounds2) => {
        apis.showMenuWithinBounds(component, anchor2, menuSpec, bounds2);
      },
      hide: (apis, component) => {
        apis.hide(component);
      },
      isOpen: (apis, component) => apis.isOpen(component),
      getContent: (apis, component) => apis.getContent(component),
      setContent: (apis, component, thing) => {
        apis.setContent(component, thing);
      },
      reposition: (apis, component) => {
        apis.reposition(component);
      }
    }
  });
  var global$9 = tinymce.util.Tools.resolve("tinymce.util.Delay");
  const factory$l = (detail) => {
    const events2 = events$a(detail.action);
    const tag = detail.dom.tag;
    const lookupAttr = (attr) => get$g(detail.dom, "attributes").bind((attrs) => get$g(attrs, attr));
    const getModAttributes = () => {
      if (tag === "button") {
        const type2 = lookupAttr("type").getOr("button");
        const roleAttrs = lookupAttr("role").map((role) => ({ role })).getOr({});
        return {
          type: type2,
          ...roleAttrs
        };
      } else {
        const role = lookupAttr("role").getOr("button");
        return { role };
      }
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: detail.components,
      events: events2,
      behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
        Focusing.config({}),
        Keying.config({
          mode: "execution",
          useSpace: true,
          useEnter: true
        })
      ]),
      domModification: { attributes: getModAttributes() },
      eventOrder: detail.eventOrder
    };
  };
  const Button = single({
    name: "Button",
    factory: factory$l,
    configFields: [
      defaulted("uid", void 0),
      required$1("dom"),
      defaulted("components", []),
      SketchBehaviours.field("buttonBehaviours", [
        Focusing,
        Keying
      ]),
      option$3("action"),
      option$3("role"),
      defaulted("eventOrder", {})
    ]
  });
  const record = (spec) => {
    const uid = isSketchSpec(spec) && hasNonNullableKey(spec, "uid") ? spec.uid : generate$5("memento");
    const get2 = (anyInSystem) => anyInSystem.getSystem().getByUid(uid).getOrDie();
    const getOpt2 = (anyInSystem) => anyInSystem.getSystem().getByUid(uid).toOptional();
    const asSpec = () => ({
      ...spec,
      uid
    });
    return {
      get: get2,
      getOpt: getOpt2,
      asSpec
    };
  };
  var global$8 = tinymce.util.Tools.resolve("tinymce.util.I18n");
  const rtlTransform = {
    "indent": true,
    "outdent": true,
    "table-insert-column-after": true,
    "table-insert-column-before": true,
    "paste-column-after": true,
    "paste-column-before": true,
    "unordered-list": true,
    "list-bull-circle": true,
    "list-bull-default": true,
    "list-bull-square": true
  };
  const defaultIconName = "temporary-placeholder";
  const defaultIcon = (icons) => () => get$g(icons, defaultIconName).getOr("!not found!");
  const getIconName = (name2, icons) => {
    const lcName = name2.toLowerCase();
    if (global$8.isRtl()) {
      const rtlName = ensureTrailing(lcName, "-rtl");
      return has$2(icons, rtlName) ? rtlName : lcName;
    } else {
      return lcName;
    }
  };
  const lookupIcon = (name2, icons) => get$g(icons, getIconName(name2, icons));
  const get$2 = (name2, iconProvider) => {
    const icons = iconProvider();
    return lookupIcon(name2, icons).getOrThunk(defaultIcon(icons));
  };
  const getOr = (name2, iconProvider, fallbackIcon) => {
    const icons = iconProvider();
    return lookupIcon(name2, icons).or(fallbackIcon).getOrThunk(defaultIcon(icons));
  };
  const needsRtlTransform = (iconName) => global$8.isRtl() ? has$2(rtlTransform, iconName) : false;
  const addFocusableBehaviour = () => config("add-focusable", [runOnAttached((comp) => {
    child(comp.element, "svg").each((svg) => set$9(svg, "focusable", "false"));
  })]);
  const renderIcon$2 = (spec, iconName, icons, fallbackIcon) => {
    var _a, _b;
    const rtlIconClasses = needsRtlTransform(iconName) ? ["tox-icon--flip"] : [];
    const iconHtml = get$g(icons, getIconName(iconName, icons)).or(fallbackIcon).getOrThunk(defaultIcon(icons));
    return {
      dom: {
        tag: spec.tag,
        attributes: (_a = spec.attributes) !== null && _a !== void 0 ? _a : {},
        classes: spec.classes.concat(rtlIconClasses),
        innerHtml: iconHtml
      },
      behaviours: derive$1([
        ...(_b = spec.behaviours) !== null && _b !== void 0 ? _b : [],
        addFocusableBehaviour()
      ])
    };
  };
  const render$3 = (iconName, spec, iconProvider, fallbackIcon = Optional.none()) => renderIcon$2(spec, iconName, iconProvider(), fallbackIcon);
  const renderFirst = (iconNames, spec, iconProvider) => {
    const icons = iconProvider();
    const iconName = find$5(iconNames, (name2) => has$2(icons, getIconName(name2, icons)));
    return renderIcon$2(spec, iconName.getOr(defaultIconName), icons, Optional.none());
  };
  const notificationIconMap = {
    success: "checkmark",
    error: "warning",
    err: "error",
    warning: "warning",
    warn: "warning",
    info: "info"
  };
  const factory$k = (detail) => {
    const memBannerText = record({
      dom: {
        tag: "p",
        innerHtml: detail.translationProvider(detail.text)
      },
      behaviours: derive$1([Replacing.config({})])
    });
    const renderPercentBar = (percent) => ({
      dom: {
        tag: "div",
        classes: ["tox-bar"],
        styles: { width: `${percent}%` }
      }
    });
    const renderPercentText = (percent) => ({
      dom: {
        tag: "div",
        classes: ["tox-text"],
        innerHtml: `${percent}%`
      }
    });
    const memBannerProgress = record({
      dom: {
        tag: "div",
        classes: detail.progress ? [
          "tox-progress-bar",
          "tox-progress-indicator"
        ] : ["tox-progress-bar"]
      },
      components: [
        {
          dom: {
            tag: "div",
            classes: ["tox-bar-container"]
          },
          components: [renderPercentBar(0)]
        },
        renderPercentText(0)
      ],
      behaviours: derive$1([Replacing.config({})])
    });
    const updateProgress = (comp, percent) => {
      if (comp.getSystem().isConnected()) {
        memBannerProgress.getOpt(comp).each((progress) => {
          Replacing.set(progress, [
            {
              dom: {
                tag: "div",
                classes: ["tox-bar-container"]
              },
              components: [renderPercentBar(percent)]
            },
            renderPercentText(percent)
          ]);
        });
      }
    };
    const updateText = (comp, text2) => {
      if (comp.getSystem().isConnected()) {
        const banner = memBannerText.get(comp);
        Replacing.set(banner, [text$1(text2)]);
      }
    };
    const apis = {
      updateProgress,
      updateText
    };
    const iconChoices = flatten([
      detail.icon.toArray(),
      detail.level.toArray(),
      detail.level.bind((level) => Optional.from(notificationIconMap[level])).toArray()
    ]);
    const memButton = record(Button.sketch({
      dom: {
        tag: "button",
        classes: [
          "tox-notification__dismiss",
          "tox-button",
          "tox-button--naked",
          "tox-button--icon"
        ]
      },
      components: [render$3("close", {
        tag: "div",
        classes: ["tox-icon"],
        attributes: { "aria-label": detail.translationProvider("Close") }
      }, detail.iconProvider)],
      action: (comp) => {
        detail.onAction(comp);
      }
    }));
    const notificationIconSpec = renderFirst(iconChoices, {
      tag: "div",
      classes: ["tox-notification__icon"]
    }, detail.iconProvider);
    const notificationBodySpec = {
      dom: {
        tag: "div",
        classes: ["tox-notification__body"]
      },
      components: [memBannerText.asSpec()],
      behaviours: derive$1([Replacing.config({})])
    };
    const components2 = [
      notificationIconSpec,
      notificationBodySpec
    ];
    return {
      uid: detail.uid,
      dom: {
        tag: "div",
        attributes: { role: "alert" },
        classes: detail.level.map((level) => [
          "tox-notification",
          "tox-notification--in",
          `tox-notification--${level}`
        ]).getOr([
          "tox-notification",
          "tox-notification--in"
        ])
      },
      behaviours: derive$1([
        Focusing.config({}),
        config("notification-events", [run$1(focusin(), (comp) => {
          memButton.getOpt(comp).each(Focusing.focus);
        })])
      ]),
      components: components2.concat(detail.progress ? [memBannerProgress.asSpec()] : []).concat(!detail.closeButton ? [] : [memButton.asSpec()]),
      apis
    };
  };
  const Notification = single({
    name: "Notification",
    factory: factory$k,
    configFields: [
      option$3("level"),
      required$1("progress"),
      required$1("icon"),
      required$1("onAction"),
      required$1("text"),
      required$1("iconProvider"),
      required$1("translationProvider"),
      defaultedBoolean("closeButton", true)
    ],
    apis: {
      updateProgress: (apis, comp, percent) => {
        apis.updateProgress(comp, percent);
      },
      updateText: (apis, comp, text2) => {
        apis.updateText(comp, text2);
      }
    }
  });
  var NotificationManagerImpl = (editor, extras, uiMothership) => {
    const sharedBackstage = extras.backstage.shared;
    const getBounds2 = () => {
      const contentArea = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
      const win$1 = win();
      const x = clamp(win$1.x, contentArea.x, contentArea.right);
      const y = clamp(win$1.y, contentArea.y, contentArea.bottom);
      const right2 = Math.max(contentArea.right, win$1.right);
      const bottom2 = Math.max(contentArea.bottom, win$1.bottom);
      return Optional.some(bounds(x, y, right2 - x, bottom2 - y));
    };
    const open2 = (settings, closeCallback) => {
      const close3 = () => {
        closeCallback();
        InlineView.hide(notificationWrapper);
      };
      const notification = build$1(Notification.sketch({
        text: settings.text,
        level: contains$2([
          "success",
          "error",
          "warning",
          "warn",
          "info"
        ], settings.type) ? settings.type : void 0,
        progress: settings.progressBar === true,
        icon: Optional.from(settings.icon),
        closeButton: settings.closeButton,
        onAction: close3,
        iconProvider: sharedBackstage.providers.icons,
        translationProvider: sharedBackstage.providers.translate
      }));
      const notificationWrapper = build$1(InlineView.sketch({
        dom: {
          tag: "div",
          classes: ["tox-notifications-container"]
        },
        lazySink: sharedBackstage.getSink,
        fireDismissalEventInstead: {},
        ...sharedBackstage.header.isPositionedAtTop() ? {} : { fireRepositionEventInstead: {} }
      }));
      uiMothership.add(notificationWrapper);
      if (settings.timeout > 0) {
        global$9.setEditorTimeout(editor, () => {
          close3();
        }, settings.timeout);
      }
      const reposition2 = () => {
        const notificationSpec = premade(notification);
        const anchorOverrides2 = { maxHeightFunction: expandable$1() };
        const allNotifications = editor.notificationManager.getNotifications();
        if (allNotifications[0] === thisNotification) {
          const anchor2 = {
            ...sharedBackstage.anchors.banner(),
            overrides: anchorOverrides2
          };
          InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor: anchor2 }, getBounds2);
        } else {
          indexOf(allNotifications, thisNotification).each((idx) => {
            const previousNotification = allNotifications[idx - 1].getEl();
            const nodeAnchor = {
              type: "node",
              root: body(),
              node: Optional.some(SugarElement.fromDom(previousNotification)),
              overrides: anchorOverrides2,
              layouts: {
                onRtl: () => [south$2],
                onLtr: () => [south$2]
              }
            };
            InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor: nodeAnchor }, getBounds2);
          });
        }
      };
      const thisNotification = {
        close: close3,
        reposition: reposition2,
        text: (nuText) => {
          Notification.updateText(notification, nuText);
        },
        settings,
        getEl: () => notification.element.dom,
        progressBar: {
          value: (percent) => {
            Notification.updateProgress(notification, percent);
          }
        }
      };
      return thisNotification;
    };
    const close2 = (notification) => {
      notification.close();
    };
    const getArgs = (notification) => {
      return notification.settings;
    };
    return {
      open: open2,
      close: close2,
      getArgs
    };
  };
  var global$7 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");
  var global$6 = tinymce.util.Tools.resolve("tinymce.EditorManager");
  var global$5 = tinymce.util.Tools.resolve("tinymce.Env");
  var ToolbarMode$1;
  (function(ToolbarMode2) {
    ToolbarMode2["default"] = "wrap";
    ToolbarMode2["floating"] = "floating";
    ToolbarMode2["sliding"] = "sliding";
    ToolbarMode2["scrolling"] = "scrolling";
  })(ToolbarMode$1 || (ToolbarMode$1 = {}));
  var ToolbarLocation$1;
  (function(ToolbarLocation2) {
    ToolbarLocation2["auto"] = "auto";
    ToolbarLocation2["top"] = "top";
    ToolbarLocation2["bottom"] = "bottom";
  })(ToolbarLocation$1 || (ToolbarLocation$1 = {}));
  const option$2 = (name2) => (editor) => editor.options.get(name2);
  const wrapOptional = (fn) => (editor) => Optional.from(fn(editor));
  const register$e = (editor) => {
    const isPhone = global$5.deviceType.isPhone();
    const isMobile = global$5.deviceType.isTablet() || isPhone;
    const registerOption = editor.options.register;
    const stringOrFalseProcessor = (value2) => isString(value2) || value2 === false;
    const stringOrNumberProcessor = (value2) => isString(value2) || isNumber(value2);
    registerOption("skin", {
      processor: (value2) => isString(value2) || value2 === false,
      default: "oxide"
    });
    registerOption("skin_url", { processor: "string" });
    registerOption("height", {
      processor: stringOrNumberProcessor,
      default: Math.max(editor.getElement().offsetHeight, 400)
    });
    registerOption("width", {
      processor: stringOrNumberProcessor,
      default: global$7.DOM.getStyle(editor.getElement(), "width")
    });
    registerOption("min_height", {
      processor: "number",
      default: 100
    });
    registerOption("min_width", { processor: "number" });
    registerOption("max_height", { processor: "number" });
    registerOption("max_width", { processor: "number" });
    registerOption("style_formats", { processor: "object[]" });
    registerOption("style_formats_merge", {
      processor: "boolean",
      default: false
    });
    registerOption("style_formats_autohide", {
      processor: "boolean",
      default: false
    });
    registerOption("line_height_formats", {
      processor: "string",
      default: "1 1.1 1.2 1.3 1.4 1.5 2"
    });
    registerOption("font_family_formats", {
      processor: "string",
      default: "Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats"
    });
    registerOption("font_size_formats", {
      processor: "string",
      default: "8pt 10pt 12pt 14pt 18pt 24pt 36pt"
    });
    registerOption("block_formats", {
      processor: "string",
      default: "Paragraph=p;Heading 1=h1;Heading 2=h2;Heading 3=h3;Heading 4=h4;Heading 5=h5;Heading 6=h6;Preformatted=pre"
    });
    registerOption("content_langs", { processor: "object[]" });
    registerOption("removed_menuitems", {
      processor: "string",
      default: ""
    });
    registerOption("menubar", {
      processor: (value2) => isString(value2) || isBoolean(value2),
      default: !isPhone
    });
    registerOption("menu", {
      processor: "object",
      default: {}
    });
    registerOption("toolbar", {
      processor: (value2) => {
        if (isBoolean(value2) || isString(value2) || isArray(value2)) {
          return {
            value: value2,
            valid: true
          };
        } else {
          return {
            valid: false,
            message: "Must be a boolean, string or array."
          };
        }
      },
      default: true
    });
    range$2(9, (num) => {
      registerOption("toolbar" + (num + 1), { processor: "string" });
    });
    registerOption("toolbar_mode", {
      processor: "string",
      default: isMobile ? "scrolling" : "floating"
    });
    registerOption("toolbar_groups", {
      processor: "object",
      default: {}
    });
    registerOption("toolbar_location", {
      processor: "string",
      default: ToolbarLocation$1.auto
    });
    registerOption("toolbar_persist", {
      processor: "boolean",
      default: false
    });
    registerOption("toolbar_sticky", {
      processor: "boolean",
      default: editor.inline
    });
    registerOption("toolbar_sticky_offset", {
      processor: "number",
      default: 0
    });
    registerOption("fixed_toolbar_container", {
      processor: "string",
      default: ""
    });
    registerOption("fixed_toolbar_container_target", { processor: "object" });
    registerOption("file_picker_callback", { processor: "function" });
    registerOption("file_picker_validator_handler", { processor: "function" });
    registerOption("file_picker_types", { processor: "string" });
    registerOption("typeahead_urls", {
      processor: "boolean",
      default: true
    });
    registerOption("anchor_top", {
      processor: stringOrFalseProcessor,
      default: "#top"
    });
    registerOption("anchor_bottom", {
      processor: stringOrFalseProcessor,
      default: "#bottom"
    });
    registerOption("draggable_modal", {
      processor: "boolean",
      default: false
    });
    registerOption("statusbar", {
      processor: "boolean",
      default: true
    });
    registerOption("elementpath", {
      processor: "boolean",
      default: true
    });
    registerOption("branding", {
      processor: "boolean",
      default: true
    });
    registerOption("resize", {
      processor: (value2) => value2 === "both" || isBoolean(value2),
      default: !global$5.deviceType.isTouch()
    });
    registerOption("sidebar_show", { processor: "string" });
  };
  const isReadOnly = option$2("readonly");
  const getHeightOption = option$2("height");
  const getWidthOption = option$2("width");
  const getMinWidthOption = wrapOptional(option$2("min_width"));
  const getMinHeightOption = wrapOptional(option$2("min_height"));
  const getMaxWidthOption = wrapOptional(option$2("max_width"));
  const getMaxHeightOption = wrapOptional(option$2("max_height"));
  const getUserStyleFormats = wrapOptional(option$2("style_formats"));
  const shouldMergeStyleFormats = option$2("style_formats_merge");
  const shouldAutoHideStyleFormats = option$2("style_formats_autohide");
  const getContentLanguages = option$2("content_langs");
  const getRemovedMenuItems = option$2("removed_menuitems");
  const getToolbarMode = option$2("toolbar_mode");
  const getToolbarGroups = option$2("toolbar_groups");
  const getToolbarLocation = option$2("toolbar_location");
  const fixedContainerSelector = option$2("fixed_toolbar_container");
  const fixedToolbarContainerTarget = option$2("fixed_toolbar_container_target");
  const isToolbarPersist = option$2("toolbar_persist");
  const getStickyToolbarOffset = option$2("toolbar_sticky_offset");
  const getMenubar = option$2("menubar");
  const getToolbar = option$2("toolbar");
  const getFilePickerCallback = option$2("file_picker_callback");
  const getFilePickerValidatorHandler = option$2("file_picker_validator_handler");
  const getFilePickerTypes = option$2("file_picker_types");
  const useTypeaheadUrls = option$2("typeahead_urls");
  const getAnchorTop = option$2("anchor_top");
  const getAnchorBottom = option$2("anchor_bottom");
  const isDraggableModal$1 = option$2("draggable_modal");
  const useStatusBar = option$2("statusbar");
  const useElementPath = option$2("elementpath");
  const useBranding = option$2("branding");
  const getResize = option$2("resize");
  const getPasteAsText = option$2("paste_as_text");
  const getSidebarShow = option$2("sidebar_show");
  const isSkinDisabled = (editor) => editor.options.get("skin") === false;
  const isMenubarEnabled = (editor) => editor.options.get("menubar") !== false;
  const getSkinUrl = (editor) => {
    const skinUrl = editor.options.get("skin_url");
    if (isSkinDisabled(editor)) {
      return skinUrl;
    } else {
      if (skinUrl) {
        return editor.documentBaseURI.toAbsolute(skinUrl);
      } else {
        const skin = editor.options.get("skin");
        return global$6.baseURL + "/skins/ui/" + skin;
      }
    }
  };
  const getLineHeightFormats = (editor) => editor.options.get("line_height_formats").split(" ");
  const isToolbarEnabled = (editor) => {
    const toolbar = getToolbar(editor);
    const isToolbarString = isString(toolbar);
    const isToolbarObjectArray = isArray(toolbar) && toolbar.length > 0;
    return !isMultipleToolbars(editor) && (isToolbarObjectArray || isToolbarString || toolbar === true);
  };
  const getMultipleToolbarsOption = (editor) => {
    const toolbars = range$2(9, (num) => editor.options.get("toolbar" + (num + 1)));
    const toolbarArray = filter$2(toolbars, isString);
    return someIf(toolbarArray.length > 0, toolbarArray);
  };
  const isMultipleToolbars = (editor) => getMultipleToolbarsOption(editor).fold(() => {
    const toolbar = getToolbar(editor);
    return isArrayOf(toolbar, isString) && toolbar.length > 0;
  }, always);
  const isToolbarLocationBottom = (editor) => getToolbarLocation(editor) === ToolbarLocation$1.bottom;
  const fixedContainerTarget = (editor) => {
    if (!editor.inline) {
      return Optional.none();
    }
    const selector = fixedContainerSelector(editor);
    if (selector.length > 0) {
      return descendant(body(), selector);
    }
    const element2 = fixedToolbarContainerTarget(editor);
    if (isNonNullable(element2)) {
      return Optional.some(SugarElement.fromDom(element2));
    }
    return Optional.none();
  };
  const useFixedContainer = (editor) => editor.inline && fixedContainerTarget(editor).isSome();
  const getUiContainer = (editor) => {
    const fixedContainer = fixedContainerTarget(editor);
    return fixedContainer.getOrThunk(() => getContentContainer(getRootNode(SugarElement.fromDom(editor.getElement()))));
  };
  const isDistractionFree = (editor) => editor.inline && !isMenubarEnabled(editor) && !isToolbarEnabled(editor) && !isMultipleToolbars(editor);
  const isStickyToolbar = (editor) => {
    const isStickyToolbar2 = editor.options.get("toolbar_sticky");
    return (isStickyToolbar2 || editor.inline) && !useFixedContainer(editor) && !isDistractionFree(editor);
  };
  const getMenus = (editor) => {
    const menu2 = editor.options.get("menu");
    return map$1(menu2, (menu3) => ({
      ...menu3,
      items: menu3.items
    }));
  };
  var Options = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    get ToolbarMode() {
      return ToolbarMode$1;
    },
    get ToolbarLocation() {
      return ToolbarLocation$1;
    },
    register: register$e,
    getSkinUrl,
    isReadOnly,
    isSkinDisabled,
    getHeightOption,
    getWidthOption,
    getMinWidthOption,
    getMinHeightOption,
    getMaxWidthOption,
    getMaxHeightOption,
    getUserStyleFormats,
    shouldMergeStyleFormats,
    shouldAutoHideStyleFormats,
    getLineHeightFormats,
    getContentLanguages,
    getRemovedMenuItems,
    isMenubarEnabled,
    isMultipleToolbars,
    isToolbarEnabled,
    isToolbarPersist,
    getMultipleToolbarsOption,
    getUiContainer,
    useFixedContainer,
    getToolbarMode,
    isDraggableModal: isDraggableModal$1,
    isDistractionFree,
    isStickyToolbar,
    getStickyToolbarOffset,
    getToolbarLocation,
    isToolbarLocationBottom,
    getToolbarGroups,
    getMenus,
    getMenubar,
    getToolbar,
    getFilePickerCallback,
    getFilePickerTypes,
    useTypeaheadUrls,
    getAnchorTop,
    getAnchorBottom,
    getFilePickerValidatorHandler,
    useStatusBar,
    useElementPath,
    useBranding,
    getResize,
    getPasteAsText,
    getSidebarShow
  });
  const autocompleteSelector = "[data-mce-autocompleter]";
  const detect = (elm) => closest$1(elm, autocompleteSelector);
  const findIn = (elm) => descendant(elm, autocompleteSelector);
  const setup$e = (api2, editor) => {
    const redirectKeyToItem = (item2, e) => {
      emitWith(item2, keydown(), { raw: e });
    };
    const getItem = () => api2.getMenu().bind(Highlighting.getHighlighted);
    editor.on("keydown", (e) => {
      const keyCode = e.which;
      if (!api2.isActive()) {
        return;
      }
      if (api2.isMenuOpen()) {
        if (keyCode === 13) {
          getItem().each(emitExecute);
          e.preventDefault();
        } else if (keyCode === 40) {
          getItem().fold(() => {
            api2.getMenu().each(Highlighting.highlightFirst);
          }, (item2) => {
            redirectKeyToItem(item2, e);
          });
          e.preventDefault();
          e.stopImmediatePropagation();
        } else if (keyCode === 37 || keyCode === 38 || keyCode === 39) {
          getItem().each((item2) => {
            redirectKeyToItem(item2, e);
            e.preventDefault();
            e.stopImmediatePropagation();
          });
        }
      } else {
        if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
          api2.cancelIfNecessary();
        }
      }
    });
    editor.on("NodeChange", (e) => {
      if (api2.isActive() && !api2.isProcessingAction() && detect(SugarElement.fromDom(e.element)).isNone()) {
        api2.cancelIfNecessary();
      }
    });
  };
  const AutocompleterEditorEvents = { setup: setup$e };
  var ItemResponse;
  (function(ItemResponse2) {
    ItemResponse2[ItemResponse2["CLOSE_ON_EXECUTE"] = 0] = "CLOSE_ON_EXECUTE";
    ItemResponse2[ItemResponse2["BUBBLE_TO_SANDBOX"] = 1] = "BUBBLE_TO_SANDBOX";
  })(ItemResponse || (ItemResponse = {}));
  var ItemResponse$1 = ItemResponse;
  const navClass = "tox-menu-nav__js";
  const selectableClass = "tox-collection__item";
  const colorClass = "tox-swatch";
  const presetClasses = {
    normal: navClass,
    color: colorClass
  };
  const tickedClass = "tox-collection__item--enabled";
  const groupHeadingClass = "tox-collection__group-heading";
  const iconClass = "tox-collection__item-icon";
  const textClass = "tox-collection__item-label";
  const accessoryClass = "tox-collection__item-accessory";
  const caretClass = "tox-collection__item-caret";
  const checkmarkClass = "tox-collection__item-checkmark";
  const activeClass = "tox-collection__item--active";
  const containerClass = "tox-collection__item-container";
  const containerColumnClass = "tox-collection__item-container--column";
  const containerRowClass = "tox-collection__item-container--row";
  const containerAlignRightClass = "tox-collection__item-container--align-right";
  const containerAlignLeftClass = "tox-collection__item-container--align-left";
  const containerValignTopClass = "tox-collection__item-container--valign-top";
  const containerValignMiddleClass = "tox-collection__item-container--valign-middle";
  const containerValignBottomClass = "tox-collection__item-container--valign-bottom";
  const classForPreset = (presets) => get$g(presetClasses, presets).getOr(navClass);
  const forMenu = (presets) => {
    if (presets === "color") {
      return "tox-swatches";
    } else {
      return "tox-menu";
    }
  };
  const classes = (presets) => ({
    backgroundMenu: "tox-background-menu",
    selectedMenu: "tox-selected-menu",
    selectedItem: "tox-collection__item--active",
    hasIcons: "tox-menu--has-icons",
    menu: forMenu(presets),
    tieredMenu: "tox-tiered-menu"
  });
  const markers = (presets) => {
    const menuClasses = classes(presets);
    return {
      backgroundMenu: menuClasses.backgroundMenu,
      selectedMenu: menuClasses.selectedMenu,
      menu: menuClasses.menu,
      selectedItem: menuClasses.selectedItem,
      item: classForPreset(presets)
    };
  };
  const dom$1 = (hasIcons, columns, presets) => {
    const menuClasses = classes(presets);
    return {
      tag: "div",
      classes: flatten([
        [
          menuClasses.menu,
          `tox-menu-${columns}-column`
        ],
        hasIcons ? [menuClasses.hasIcons] : []
      ])
    };
  };
  const components = [Menu.parts.items({})];
  const part = (hasIcons, columns, presets) => {
    const menuClasses = classes(presets);
    const d = {
      tag: "div",
      classes: flatten([[menuClasses.tieredMenu]])
    };
    return {
      dom: d,
      markers: markers(presets)
    };
  };
  const chunk = (rowDom, numColumns) => (items) => {
    const chunks = chunk$1(items, numColumns);
    return map$2(chunks, (c) => ({
      dom: rowDom,
      components: c
    }));
  };
  const forSwatch = (columns) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-menu",
        "tox-swatches-menu"
      ]
    },
    components: [{
      dom: {
        tag: "div",
        classes: ["tox-swatches"]
      },
      components: [Menu.parts.items({
        preprocess: columns !== "auto" ? chunk({
          tag: "div",
          classes: ["tox-swatches__row"]
        }, columns) : identity
      })]
    }]
  });
  const forToolbar = (columns) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-menu",
        "tox-collection",
        "tox-collection--toolbar",
        "tox-collection--toolbar-lg"
      ]
    },
    components: [Menu.parts.items({
      preprocess: chunk({
        tag: "div",
        classes: ["tox-collection__group"]
      }, columns)
    })]
  });
  const preprocessCollection = (items, isSeparator2) => {
    const allSplits = [];
    let currentSplit = [];
    each$1(items, (item2, i) => {
      if (isSeparator2(item2, i)) {
        if (currentSplit.length > 0) {
          allSplits.push(currentSplit);
        }
        currentSplit = [];
        if (has$2(item2.dom, "innerHtml") || item2.components.length > 0) {
          currentSplit.push(item2);
        }
      } else {
        currentSplit.push(item2);
      }
    });
    if (currentSplit.length > 0) {
      allSplits.push(currentSplit);
    }
    return map$2(allSplits, (s) => ({
      dom: {
        tag: "div",
        classes: ["tox-collection__group"]
      },
      components: s
    }));
  };
  const forCollection = (columns, initItems, _hasIcons = true) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-menu",
        "tox-collection"
      ].concat(columns === 1 ? ["tox-collection--list"] : ["tox-collection--grid"])
    },
    components: [Menu.parts.items({
      preprocess: (items) => {
        if (columns !== "auto" && columns > 1) {
          return chunk({
            tag: "div",
            classes: ["tox-collection__group"]
          }, columns)(items);
        } else {
          return preprocessCollection(items, (_item, i) => initItems[i].type === "separator");
        }
      }
    })]
  });
  const forHorizontalCollection = (initItems, _hasIcons = true) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-collection",
        "tox-collection--horizontal"
      ]
    },
    components: [Menu.parts.items({ preprocess: (items) => preprocessCollection(items, (_item, i) => initItems[i].type === "separator") })]
  });
  const menuHasIcons = (xs) => exists(xs, (item2) => "icon" in item2 && item2.icon !== void 0);
  const handleError = (error2) => {
    console.error(formatError(error2));
    console.log(error2);
    return Optional.none();
  };
  const createHorizontalPartialMenuWithAlloyItems = (value2, _hasIcons, items, _columns, _presets) => {
    const structure = forHorizontalCollection(items);
    return {
      value: value2,
      dom: structure.dom,
      components: structure.components,
      items
    };
  };
  const createPartialMenuWithAlloyItems = (value2, hasIcons, items, columns, presets) => {
    if (presets === "color") {
      const structure = forSwatch(columns);
      return {
        value: value2,
        dom: structure.dom,
        components: structure.components,
        items
      };
    }
    if (presets === "normal" && columns === "auto") {
      const structure = forCollection(columns, items);
      return {
        value: value2,
        dom: structure.dom,
        components: structure.components,
        items
      };
    }
    if (presets === "normal" && columns === 1) {
      const structure = forCollection(1, items);
      return {
        value: value2,
        dom: structure.dom,
        components: structure.components,
        items
      };
    }
    if (presets === "normal") {
      const structure = forCollection(columns, items);
      return {
        value: value2,
        dom: structure.dom,
        components: structure.components,
        items
      };
    }
    if (presets === "listpreview" && columns !== "auto") {
      const structure = forToolbar(columns);
      return {
        value: value2,
        dom: structure.dom,
        components: structure.components,
        items
      };
    }
    return {
      value: value2,
      dom: dom$1(hasIcons, columns, presets),
      components,
      items
    };
  };
  const type = requiredString("type");
  const name$1 = requiredString("name");
  const label = requiredString("label");
  const text = requiredString("text");
  const title = requiredString("title");
  const icon = requiredString("icon");
  const value$1 = requiredString("value");
  const fetch$1 = requiredFunction("fetch");
  const getSubmenuItems = requiredFunction("getSubmenuItems");
  const onAction = requiredFunction("onAction");
  const onItemAction = requiredFunction("onItemAction");
  const onSetup = defaultedFunction("onSetup", () => noop);
  const optionalName = optionString("name");
  const optionalText = optionString("text");
  const optionalIcon = optionString("icon");
  const optionalTooltip = optionString("tooltip");
  const optionalLabel = optionString("label");
  const optionalShortcut = optionString("shortcut");
  const optionalSelect = optionFunction("select");
  const active = defaultedBoolean("active", false);
  const borderless = defaultedBoolean("borderless", false);
  const enabled = defaultedBoolean("enabled", true);
  const primary = defaultedBoolean("primary", false);
  const defaultedColumns = (num) => defaulted("columns", num);
  const defaultedMeta = defaulted("meta", {});
  const defaultedOnAction = defaultedFunction("onAction", noop);
  const defaultedType = (type2) => defaultedString("type", type2);
  const generatedName = (namePrefix) => field$1("name", "name", defaultedThunk(() => generate$6(`${namePrefix}-name`)), string);
  const generatedValue = (valuePrefix) => field$1("value", "value", defaultedThunk(() => generate$6(`${valuePrefix}-value`)), anyValue());
  const separatorMenuItemSchema = objOf([
    type,
    optionalText
  ]);
  const createSeparatorMenuItem = (spec) => asRaw("separatormenuitem", separatorMenuItemSchema, spec);
  const autocompleterItemSchema = objOf([
    defaultedType("autocompleteitem"),
    active,
    enabled,
    defaultedMeta,
    value$1,
    optionalText,
    optionalIcon
  ]);
  const createSeparatorItem = (spec) => asRaw("Autocompleter.Separator", separatorMenuItemSchema, spec);
  const createAutocompleterItem = (spec) => asRaw("Autocompleter.Item", autocompleterItemSchema, spec);
  const baseToolbarButtonFields = [
    enabled,
    optionalTooltip,
    optionalIcon,
    optionalText,
    onSetup
  ];
  const toolbarButtonSchema = objOf([
    type,
    onAction
  ].concat(baseToolbarButtonFields));
  const createToolbarButton = (spec) => asRaw("toolbarbutton", toolbarButtonSchema, spec);
  const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
  const toggleButtonSchema = objOf(baseToolbarToggleButtonFields.concat([
    type,
    onAction
  ]));
  const createToggleButton = (spec) => asRaw("ToggleButton", toggleButtonSchema, spec);
  const contextBarFields = [
    defaultedFunction("predicate", never),
    defaultedStringEnum("scope", "node", [
      "node",
      "editor"
    ]),
    defaultedStringEnum("position", "selection", [
      "node",
      "selection",
      "line"
    ])
  ];
  const contextButtonFields = baseToolbarButtonFields.concat([
    defaultedType("contextformbutton"),
    primary,
    onAction,
    customField("original", identity)
  ]);
  const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
    defaultedType("contextformbutton"),
    primary,
    onAction,
    customField("original", identity)
  ]);
  const launchButtonFields = baseToolbarButtonFields.concat([defaultedType("contextformbutton")]);
  const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType("contextformtogglebutton")]);
  const toggleOrNormal = choose$1("type", {
    contextformbutton: contextButtonFields,
    contextformtogglebutton: contextToggleButtonFields
  });
  const contextFormSchema = objOf([
    defaultedType("contextform"),
    defaultedFunction("initValue", constant$1("")),
    optionalLabel,
    requiredArrayOf("commands", toggleOrNormal),
    optionOf("launch", choose$1("type", {
      contextformbutton: launchButtonFields,
      contextformtogglebutton: launchToggleButtonFields
    }))
  ].concat(contextBarFields));
  const createContextForm = (spec) => asRaw("ContextForm", contextFormSchema, spec);
  const contextToolbarSchema = objOf([
    defaultedType("contexttoolbar"),
    requiredString("items")
  ].concat(contextBarFields));
  const createContextToolbar = (spec) => asRaw("ContextToolbar", contextToolbarSchema, spec);
  const cardImageFields = [
    type,
    requiredString("src"),
    optionString("alt"),
    defaultedArrayOf("classes", [], string)
  ];
  const cardImageSchema = objOf(cardImageFields);
  const cardTextFields = [
    type,
    text,
    optionalName,
    defaultedArrayOf("classes", ["tox-collection__item-label"], string)
  ];
  const cardTextSchema = objOf(cardTextFields);
  const itemSchema$1 = valueThunk(() => choose$2("type", {
    cardimage: cardImageSchema,
    cardtext: cardTextSchema,
    cardcontainer: cardContainerSchema
  }));
  const cardContainerSchema = objOf([
    type,
    defaultedString("direction", "horizontal"),
    defaultedString("align", "left"),
    defaultedString("valign", "middle"),
    requiredArrayOf("items", itemSchema$1)
  ]);
  const commonMenuItemFields = [
    enabled,
    optionalText,
    optionalShortcut,
    generatedValue("menuitem"),
    defaultedMeta
  ];
  const cardMenuItemSchema = objOf([
    type,
    optionalLabel,
    requiredArrayOf("items", itemSchema$1),
    onSetup,
    defaultedOnAction
  ].concat(commonMenuItemFields));
  const createCardMenuItem = (spec) => asRaw("cardmenuitem", cardMenuItemSchema, spec);
  const choiceMenuItemSchema = objOf([
    type,
    active,
    optionalIcon
  ].concat(commonMenuItemFields));
  const createChoiceMenuItem = (spec) => asRaw("choicemenuitem", choiceMenuItemSchema, spec);
  const baseFields = [
    type,
    requiredString("fancytype"),
    defaultedOnAction
  ];
  const insertTableFields = [defaulted("initData", {})].concat(baseFields);
  const colorSwatchFields = [defaultedObjOf("initData", {}, [
    defaultedBoolean("allowCustomColors", true),
    optionArrayOf("colors", anyValue())
  ])].concat(baseFields);
  const fancyMenuItemSchema = choose$1("fancytype", {
    inserttable: insertTableFields,
    colorswatch: colorSwatchFields
  });
  const createFancyMenuItem = (spec) => asRaw("fancymenuitem", fancyMenuItemSchema, spec);
  const menuItemSchema = objOf([
    type,
    onSetup,
    defaultedOnAction,
    optionalIcon
  ].concat(commonMenuItemFields));
  const createMenuItem = (spec) => asRaw("menuitem", menuItemSchema, spec);
  const nestedMenuItemSchema = objOf([
    type,
    getSubmenuItems,
    onSetup,
    optionalIcon
  ].concat(commonMenuItemFields));
  const createNestedMenuItem = (spec) => asRaw("nestedmenuitem", nestedMenuItemSchema, spec);
  const toggleMenuItemSchema = objOf([
    type,
    optionalIcon,
    active,
    onSetup,
    onAction
  ].concat(commonMenuItemFields));
  const createToggleMenuItem = (spec) => asRaw("togglemenuitem", toggleMenuItemSchema, spec);
  const detectSize = (comp, margin, selectorClass) => {
    const descendants$1 = descendants(comp.element, "." + selectorClass);
    if (descendants$1.length > 0) {
      const columnLength = findIndex$1(descendants$1, (c) => {
        const thisTop = c.dom.getBoundingClientRect().top;
        const cTop = descendants$1[0].dom.getBoundingClientRect().top;
        return Math.abs(thisTop - cTop) > margin;
      }).getOr(descendants$1.length);
      return Optional.some({
        numColumns: columnLength,
        numRows: Math.ceil(descendants$1.length / columnLength)
      });
    } else {
      return Optional.none();
    }
  };
  const namedEvents = (name2, handlers2) => derive$1([config(name2, handlers2)]);
  const unnamedEvents = (handlers2) => namedEvents(generate$6("unnamed-events"), handlers2);
  const SimpleBehaviours = {
    namedEvents,
    unnamedEvents
  };
  const ExclusivityChannel = generate$6("tooltip.exclusive");
  const ShowTooltipEvent = generate$6("tooltip.show");
  const HideTooltipEvent = generate$6("tooltip.hide");
  const hideAllExclusive = (component, _tConfig, _tState) => {
    component.getSystem().broadcastOn([ExclusivityChannel], {});
  };
  const setComponents = (component, tConfig, tState, specs) => {
    tState.getTooltip().each((tooltip) => {
      if (tooltip.getSystem().isConnected()) {
        Replacing.set(tooltip, specs);
      }
    });
  };
  var TooltippingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    hideAllExclusive,
    setComponents
  });
  const events$9 = (tooltipConfig, state) => {
    const hide = (comp) => {
      state.getTooltip().each((p) => {
        detach(p);
        tooltipConfig.onHide(comp, p);
        state.clearTooltip();
      });
      state.clearTimer();
    };
    const show2 = (comp) => {
      if (!state.isShowing()) {
        hideAllExclusive(comp);
        const sink = tooltipConfig.lazySink(comp).getOrDie();
        const popup = comp.getSystem().build({
          dom: tooltipConfig.tooltipDom,
          components: tooltipConfig.tooltipComponents,
          events: derive$2(tooltipConfig.mode === "normal" ? [
            run$1(mouseover(), (_) => {
              emit(comp, ShowTooltipEvent);
            }),
            run$1(mouseout(), (_) => {
              emit(comp, HideTooltipEvent);
            })
          ] : []),
          behaviours: derive$1([Replacing.config({})])
        });
        state.setTooltip(popup);
        attach(sink, popup);
        tooltipConfig.onShow(comp, popup);
        Positioning.position(sink, popup, { anchor: tooltipConfig.anchor(comp) });
      }
    };
    return derive$2(flatten([
      [
        run$1(ShowTooltipEvent, (comp) => {
          state.resetTimer(() => {
            show2(comp);
          }, tooltipConfig.delay);
        }),
        run$1(HideTooltipEvent, (comp) => {
          state.resetTimer(() => {
            hide(comp);
          }, tooltipConfig.delay);
        }),
        run$1(receive(), (comp, message) => {
          const receivingData = message;
          if (!receivingData.universal) {
            if (contains$2(receivingData.channels, ExclusivityChannel)) {
              hide(comp);
            }
          }
        }),
        runOnDetached((comp) => {
          hide(comp);
        })
      ],
      tooltipConfig.mode === "normal" ? [
        run$1(focusin(), (comp) => {
          emit(comp, ShowTooltipEvent);
        }),
        run$1(postBlur(), (comp) => {
          emit(comp, HideTooltipEvent);
        }),
        run$1(mouseover(), (comp) => {
          emit(comp, ShowTooltipEvent);
        }),
        run$1(mouseout(), (comp) => {
          emit(comp, HideTooltipEvent);
        })
      ] : [
        run$1(highlight$1(), (comp, _se) => {
          emit(comp, ShowTooltipEvent);
        }),
        run$1(dehighlight$1(), (comp) => {
          emit(comp, HideTooltipEvent);
        })
      ]
    ]));
  };
  var ActiveTooltipping = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$9
  });
  var TooltippingSchema = [
    required$1("lazySink"),
    required$1("tooltipDom"),
    defaulted("exclusive", true),
    defaulted("tooltipComponents", []),
    defaulted("delay", 300),
    defaultedStringEnum("mode", "normal", [
      "normal",
      "follow-highlight"
    ]),
    defaulted("anchor", (comp) => ({
      type: "hotspot",
      hotspot: comp,
      layouts: {
        onLtr: constant$1([
          south$2,
          north$2,
          southeast$2,
          northeast$2,
          southwest$2,
          northwest$2
        ]),
        onRtl: constant$1([
          south$2,
          north$2,
          southeast$2,
          northeast$2,
          southwest$2,
          northwest$2
        ])
      }
    })),
    onHandler("onHide"),
    onHandler("onShow")
  ];
  const init$b = () => {
    const timer = value$2();
    const popup = value$2();
    const clearTimer = () => {
      timer.on(clearTimeout);
    };
    const resetTimer = (f, delay) => {
      clearTimer();
      timer.set(setTimeout(f, delay));
    };
    const readState = constant$1("not-implemented");
    return nu$8({
      getTooltip: popup.get,
      isShowing: popup.isSet,
      setTooltip: popup.set,
      clearTooltip: popup.clear,
      clearTimer,
      resetTimer,
      readState
    });
  };
  var TooltippingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$b
  });
  const Tooltipping = create$3({
    fields: TooltippingSchema,
    name: "tooltipping",
    active: ActiveTooltipping,
    state: TooltippingState,
    apis: TooltippingApis
  });
  const escape2 = (text2) => text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  const ReadOnlyChannel = "silver.readonly";
  const ReadOnlyDataSchema = objOf([requiredBoolean("readonly")]);
  const broadcastReadonly = (uiComponents, readonly) => {
    const outerContainer = uiComponents.outerContainer;
    const target = outerContainer.element;
    if (readonly) {
      uiComponents.mothership.broadcastOn([dismissPopups()], { target });
      uiComponents.uiMothership.broadcastOn([dismissPopups()], { target });
    }
    uiComponents.mothership.broadcastOn([ReadOnlyChannel], { readonly });
    uiComponents.uiMothership.broadcastOn([ReadOnlyChannel], { readonly });
  };
  const setupReadonlyModeSwitch = (editor, uiComponents) => {
    editor.on("init", () => {
      if (editor.mode.isReadOnly()) {
        broadcastReadonly(uiComponents, true);
      }
    });
    editor.on("SwitchMode", () => broadcastReadonly(uiComponents, editor.mode.isReadOnly()));
    if (isReadOnly(editor)) {
      editor.mode.set("readonly");
    }
  };
  const receivingConfig = () => Receiving.config({
    channels: {
      [ReadOnlyChannel]: {
        schema: ReadOnlyDataSchema,
        onReceive: (comp, data) => {
          Disabling.set(comp, data.readonly);
        }
      }
    }
  });
  const item = (disabled) => Disabling.config({
    disabled,
    disableClass: "tox-collection__item--state-disabled"
  });
  const button = (disabled) => Disabling.config({ disabled });
  const splitButton = (disabled) => Disabling.config({
    disabled,
    disableClass: "tox-tbtn--disabled"
  });
  const toolbarButton = (disabled) => Disabling.config({
    disabled,
    disableClass: "tox-tbtn--disabled",
    useNative: false
  });
  const DisablingConfigs = {
    item,
    button,
    splitButton,
    toolbarButton
  };
  const runWithApi = (info, comp) => {
    const api2 = info.getApi(comp);
    return (f) => {
      f(api2);
    };
  };
  const onControlAttached = (info, editorOffCell) => runOnAttached((comp) => {
    const run2 = runWithApi(info, comp);
    run2((api2) => {
      const onDestroy = info.onSetup(api2);
      if (isFunction(onDestroy)) {
        editorOffCell.set(onDestroy);
      }
    });
  });
  const onControlDetached = (getApi2, editorOffCell) => runOnDetached((comp) => runWithApi(getApi2, comp)(editorOffCell.get()));
  const onMenuItemExecute = (info, itemResponse) => runOnExecute$1((comp, simulatedEvent) => {
    runWithApi(info, comp)(info.onAction);
    if (!info.triggersSubmenu && itemResponse === ItemResponse$1.CLOSE_ON_EXECUTE) {
      if (comp.getSystem().isConnected()) {
        emit(comp, sandboxClose());
      }
      simulatedEvent.stop();
    }
  });
  const menuItemEventOrder = {
    [execute$5()]: [
      "disabling",
      "alloy.base.behaviour",
      "toggling",
      "item-events"
    ]
  };
  const componentRenderPipeline = cat;
  const renderCommonItem = (spec, structure, itemResponse, providersbackstage) => {
    const editorOffCell = Cell(noop);
    return {
      type: "item",
      dom: structure.dom,
      components: componentRenderPipeline(structure.optComponents),
      data: spec.data,
      eventOrder: menuItemEventOrder,
      hasSubmenu: spec.triggersSubmenu,
      itemBehaviours: derive$1([
        config("item-events", [
          onMenuItemExecute(spec, itemResponse),
          onControlAttached(spec, editorOffCell),
          onControlDetached(spec, editorOffCell)
        ]),
        DisablingConfigs.item(() => !spec.enabled || providersbackstage.isDisabled()),
        receivingConfig(),
        Replacing.config({})
      ].concat(spec.itemBehaviours))
    };
  };
  const buildData = (source) => ({
    value: source.value,
    meta: {
      text: source.text.getOr(""),
      ...source.meta
    }
  });
  const convertText = (source) => {
    const isMac = global$5.os.isMacOS() || global$5.os.isiOS();
    const mac = {
      alt: "\u2325",
      ctrl: "\u2303",
      shift: "\u21E7",
      meta: "\u2318",
      access: "\u2303\u2325"
    };
    const other = {
      meta: "Ctrl",
      access: "Shift+Alt"
    };
    const replace2 = isMac ? mac : other;
    const shortcut = source.split("+");
    const updated = map$2(shortcut, (segment) => {
      const search2 = segment.toLowerCase().trim();
      return has$2(replace2, search2) ? replace2[search2] : segment;
    });
    return isMac ? updated.join("") : updated.join("+");
  };
  const renderIcon$1 = (name2, icons, classes2 = [iconClass]) => render$3(name2, {
    tag: "div",
    classes: classes2
  }, icons);
  const renderText = (text2) => ({
    dom: {
      tag: "div",
      classes: [textClass]
    },
    components: [text$1(global$8.translate(text2))]
  });
  const renderHtml = (html, classes2) => ({
    dom: {
      tag: "div",
      classes: classes2,
      innerHtml: html
    }
  });
  const renderStyledText = (style, text2) => ({
    dom: {
      tag: "div",
      classes: [textClass]
    },
    components: [{
      dom: {
        tag: style.tag,
        styles: style.styles
      },
      components: [text$1(global$8.translate(text2))]
    }]
  });
  const renderShortcut = (shortcut) => ({
    dom: {
      tag: "div",
      classes: [accessoryClass]
    },
    components: [text$1(convertText(shortcut))]
  });
  const renderCheckmark = (icons) => renderIcon$1("checkmark", icons, [checkmarkClass]);
  const renderSubmenuCaret = (icons) => renderIcon$1("chevron-right", icons, [caretClass]);
  const renderDownwardsCaret = (icons) => renderIcon$1("chevron-down", icons, [caretClass]);
  const renderContainer = (container, components2) => {
    const directionClass = container.direction === "vertical" ? containerColumnClass : containerRowClass;
    const alignClass = container.align === "left" ? containerAlignLeftClass : containerAlignRightClass;
    const getValignClass = () => {
      switch (container.valign) {
        case "top":
          return containerValignTopClass;
        case "middle":
          return containerValignMiddleClass;
        case "bottom":
          return containerValignBottomClass;
      }
    };
    return {
      dom: {
        tag: "div",
        classes: [
          containerClass,
          directionClass,
          alignClass,
          getValignClass()
        ]
      },
      components: components2
    };
  };
  const renderImage = (src, classes2, alt) => ({
    dom: {
      tag: "img",
      classes: classes2,
      attributes: {
        src,
        alt: alt.getOr("")
      }
    }
  });
  const renderColorStructure = (item2, providerBackstage, fallbackIcon) => {
    const colorPickerCommand = "custom";
    const removeColorCommand = "remove";
    const itemText = item2.ariaLabel;
    const itemValue = item2.value;
    const iconSvg = item2.iconContent.map((name2) => getOr(name2, providerBackstage.icons, fallbackIcon));
    const getDom = () => {
      const common = colorClass;
      const icon2 = iconSvg.getOr("");
      const attributes = itemText.map((text2) => ({ title: providerBackstage.translate(text2) })).getOr({});
      const baseDom = {
        tag: "div",
        attributes,
        classes: [common]
      };
      if (itemValue === colorPickerCommand) {
        return {
          ...baseDom,
          tag: "button",
          classes: [
            ...baseDom.classes,
            "tox-swatches__picker-btn"
          ],
          innerHtml: icon2
        };
      } else if (itemValue === removeColorCommand) {
        return {
          ...baseDom,
          classes: [
            ...baseDom.classes,
            "tox-swatch--remove"
          ],
          innerHtml: icon2
        };
      } else {
        return {
          ...baseDom,
          attributes: {
            ...baseDom.attributes,
            "data-mce-color": itemValue
          },
          styles: { "background-color": itemValue }
        };
      }
    };
    return {
      dom: getDom(),
      optComponents: []
    };
  };
  const renderItemDomStructure = (ariaLabel) => {
    const domTitle = ariaLabel.map((label2) => ({ attributes: { title: global$8.translate(label2) } })).getOr({});
    return {
      tag: "div",
      classes: [
        navClass,
        selectableClass
      ],
      ...domTitle
    };
  };
  const renderNormalItemStructure = (info, providersBackstage, renderIcons, fallbackIcon) => {
    const iconSpec = {
      tag: "div",
      classes: [iconClass]
    };
    const renderIcon2 = (iconName) => render$3(iconName, iconSpec, providersBackstage.icons, fallbackIcon);
    const renderEmptyIcon = () => Optional.some({ dom: iconSpec });
    const leftIcon = renderIcons ? info.iconContent.map(renderIcon2).orThunk(renderEmptyIcon) : Optional.none();
    const checkmark = info.checkMark;
    const textRender = Optional.from(info.meta).fold(() => renderText, (meta) => has$2(meta, "style") ? curry(renderStyledText, meta.style) : renderText);
    const content = info.htmlContent.fold(() => info.textContent.map(textRender), (html) => Optional.some(renderHtml(html, [textClass])));
    const menuItem = {
      dom: renderItemDomStructure(info.ariaLabel),
      optComponents: [
        leftIcon,
        content,
        info.shortcutContent.map(renderShortcut),
        checkmark,
        info.caret
      ]
    };
    return menuItem;
  };
  const renderItemStructure = (info, providersBackstage, renderIcons, fallbackIcon = Optional.none()) => {
    if (info.presets === "color") {
      return renderColorStructure(info, providersBackstage, fallbackIcon);
    } else {
      return renderNormalItemStructure(info, providersBackstage, renderIcons, fallbackIcon);
    }
  };
  const tooltipBehaviour = (meta, sharedBackstage) => get$g(meta, "tooltipWorker").map((tooltipWorker) => [Tooltipping.config({
    lazySink: sharedBackstage.getSink,
    tooltipDom: {
      tag: "div",
      classes: ["tox-tooltip-worker-container"]
    },
    tooltipComponents: [],
    anchor: (comp) => ({
      type: "submenu",
      item: comp,
      overrides: { maxHeightFunction: expandable$1 }
    }),
    mode: "follow-highlight",
    onShow: (component, _tooltip) => {
      tooltipWorker((elm) => {
        Tooltipping.setComponents(component, [external$1({ element: SugarElement.fromDom(elm) })]);
      });
    }
  })]).getOr([]);
  const encodeText = (text2) => global$7.DOM.encode(text2);
  const replaceText = (text2, matchText) => {
    const translated = global$8.translate(text2);
    const encoded = encodeText(translated);
    if (matchText.length > 0) {
      const escapedMatchRegex = new RegExp(escape2(matchText), "gi");
      return encoded.replace(escapedMatchRegex, (match) => `<span class="tox-autocompleter-highlight">${match}</span>`);
    } else {
      return encoded;
    }
  };
  const renderAutocompleteItem = (spec, matchText, useText, presets, onItemValueHandler, itemResponse, sharedBackstage, renderIcons = true) => {
    const structure = renderItemStructure({
      presets,
      textContent: Optional.none(),
      htmlContent: useText ? spec.text.map((text2) => replaceText(text2, matchText)) : Optional.none(),
      ariaLabel: spec.text,
      iconContent: spec.icon,
      shortcutContent: Optional.none(),
      checkMark: Optional.none(),
      caret: Optional.none(),
      value: spec.value
    }, sharedBackstage.providers, renderIcons, spec.icon);
    return renderCommonItem({
      data: buildData(spec),
      enabled: spec.enabled,
      getApi: constant$1({}),
      onAction: (_api) => onItemValueHandler(spec.value, spec.meta),
      onSetup: constant$1(noop),
      triggersSubmenu: false,
      itemBehaviours: tooltipBehaviour(spec.meta, sharedBackstage)
    }, structure, itemResponse, sharedBackstage.providers);
  };
  const render$2 = (items, extras) => map$2(items, (item2) => {
    switch (item2.type) {
      case "cardcontainer":
        return renderContainer(item2, render$2(item2.items, extras));
      case "cardimage":
        return renderImage(item2.src, item2.classes, item2.alt);
      case "cardtext":
        const shouldHighlight = item2.name.exists((name2) => contains$2(extras.cardText.highlightOn, name2));
        const matchText = shouldHighlight ? Optional.from(extras.cardText.matchText).getOr("") : "";
        return renderHtml(replaceText(item2.text, matchText), item2.classes);
    }
  });
  const renderCardMenuItem = (spec, itemResponse, sharedBackstage, extras) => {
    const getApi2 = (component) => ({
      isEnabled: () => !Disabling.isDisabled(component),
      setEnabled: (state) => {
        Disabling.set(component, !state);
        each$1(descendants(component.element, "*"), (elm) => {
          component.getSystem().getByDom(elm).each((comp) => {
            if (comp.hasConfigured(Disabling)) {
              Disabling.set(comp, !state);
            }
          });
        });
      }
    });
    const structure = {
      dom: renderItemDomStructure(spec.label),
      optComponents: [Optional.some({
        dom: {
          tag: "div",
          classes: [
            containerClass,
            containerRowClass
          ]
        },
        components: render$2(spec.items, extras)
      })]
    };
    return renderCommonItem({
      data: buildData({
        text: Optional.none(),
        ...spec
      }),
      enabled: spec.enabled,
      getApi: getApi2,
      onAction: spec.onAction,
      onSetup: spec.onSetup,
      triggersSubmenu: false,
      itemBehaviours: Optional.from(extras.itemBehaviours).getOr([])
    }, structure, itemResponse, sharedBackstage.providers);
  };
  const renderChoiceItem = (spec, useText, presets, onItemValueHandler, isSelected, itemResponse, providersBackstage, renderIcons = true) => {
    const getApi2 = (component) => ({
      setActive: (state) => {
        Toggling.set(component, state);
      },
      isActive: () => Toggling.isOn(component),
      isEnabled: () => !Disabling.isDisabled(component),
      setEnabled: (state) => Disabling.set(component, !state)
    });
    const structure = renderItemStructure({
      presets,
      textContent: useText ? spec.text : Optional.none(),
      htmlContent: Optional.none(),
      ariaLabel: spec.text,
      iconContent: spec.icon,
      shortcutContent: useText ? spec.shortcut : Optional.none(),
      checkMark: useText ? Optional.some(renderCheckmark(providersBackstage.icons)) : Optional.none(),
      caret: Optional.none(),
      value: spec.value
    }, providersBackstage, renderIcons);
    return deepMerge(renderCommonItem({
      data: buildData(spec),
      enabled: spec.enabled,
      getApi: getApi2,
      onAction: (_api) => onItemValueHandler(spec.value),
      onSetup: (api2) => {
        api2.setActive(isSelected);
        return noop;
      },
      triggersSubmenu: false,
      itemBehaviours: []
    }, structure, itemResponse, providersBackstage), {
      toggling: {
        toggleClass: tickedClass,
        toggleOnExecute: false,
        selected: spec.active,
        exclusive: true
      }
    });
  };
  const parts$f = generate$3(owner$2(), parts$h());
  const hexColour = (value2) => ({ value: value2 });
  const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  const isHexString = (hex) => shorthandRegex.test(hex) || longformRegex.test(hex);
  const normalizeHex = (hex) => removeLeading(hex, "#").toUpperCase();
  const fromString$1 = (hex) => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
  const getLongForm = (hex) => {
    const hexString = hex.value.replace(shorthandRegex, (m, r2, g, b2) => r2 + r2 + g + g + b2 + b2);
    return { value: hexString };
  };
  const extractValues = (hex) => {
    const longForm = getLongForm(hex);
    const splitForm = longformRegex.exec(longForm.value);
    return splitForm === null ? [
      "FFFFFF",
      "FF",
      "FF",
      "FF"
    ] : splitForm;
  };
  const toHex = (component) => {
    const hex = component.toString(16);
    return (hex.length === 1 ? "0" + hex : hex).toUpperCase();
  };
  const fromRgba = (rgbaColour2) => {
    const value2 = toHex(rgbaColour2.red) + toHex(rgbaColour2.green) + toHex(rgbaColour2.blue);
    return hexColour(value2);
  };
  const min = Math.min;
  const max = Math.max;
  const round$1 = Math.round;
  const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  const rgbaColour = (red2, green, blue, alpha) => ({
    red: red2,
    green,
    blue,
    alpha
  });
  const isRgbaComponent = (value2) => {
    const num = parseInt(value2, 10);
    return num.toString() === value2 && num >= 0 && num <= 255;
  };
  const fromHsv = (hsv) => {
    let r2;
    let g;
    let b2;
    const hue = (hsv.hue || 0) % 360;
    let saturation = hsv.saturation / 100;
    let brightness = hsv.value / 100;
    saturation = max(0, min(saturation, 1));
    brightness = max(0, min(brightness, 1));
    if (saturation === 0) {
      r2 = g = b2 = round$1(255 * brightness);
      return rgbaColour(r2, g, b2, 1);
    }
    const side = hue / 60;
    const chroma = brightness * saturation;
    const x = chroma * (1 - Math.abs(side % 2 - 1));
    const match = brightness - chroma;
    switch (Math.floor(side)) {
      case 0:
        r2 = chroma;
        g = x;
        b2 = 0;
        break;
      case 1:
        r2 = x;
        g = chroma;
        b2 = 0;
        break;
      case 2:
        r2 = 0;
        g = chroma;
        b2 = x;
        break;
      case 3:
        r2 = 0;
        g = x;
        b2 = chroma;
        break;
      case 4:
        r2 = x;
        g = 0;
        b2 = chroma;
        break;
      case 5:
        r2 = chroma;
        g = 0;
        b2 = x;
        break;
      default:
        r2 = g = b2 = 0;
    }
    r2 = round$1(255 * (r2 + match));
    g = round$1(255 * (g + match));
    b2 = round$1(255 * (b2 + match));
    return rgbaColour(r2, g, b2, 1);
  };
  const fromHex = (hexColour2) => {
    const result = extractValues(hexColour2);
    const red2 = parseInt(result[1], 16);
    const green = parseInt(result[2], 16);
    const blue = parseInt(result[3], 16);
    return rgbaColour(red2, green, blue, 1);
  };
  const fromStringValues = (red2, green, blue, alpha) => {
    const r2 = parseInt(red2, 10);
    const g = parseInt(green, 10);
    const b2 = parseInt(blue, 10);
    const a = parseFloat(alpha);
    return rgbaColour(r2, g, b2, a);
  };
  const fromString = (rgbaString) => {
    if (rgbaString === "transparent") {
      return Optional.some(rgbaColour(0, 0, 0, 0));
    }
    const rgbMatch = rgbRegex.exec(rgbaString);
    if (rgbMatch !== null) {
      return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], "1"));
    }
    const rgbaMatch = rgbaRegex.exec(rgbaString);
    if (rgbaMatch !== null) {
      return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
    }
    return Optional.none();
  };
  const toString = (rgba) => `rgba(${rgba.red},${rgba.green},${rgba.blue},${rgba.alpha})`;
  const red = rgbaColour(255, 0, 0, 1);
  const fireSkinLoaded$1 = (editor) => editor.dispatch("SkinLoaded");
  const fireSkinLoadError$1 = (editor, error2) => editor.dispatch("SkinLoadError", error2);
  const fireResizeEditor = (editor) => editor.dispatch("ResizeEditor");
  const fireResizeContent = (editor, e) => editor.dispatch("ResizeContent", e);
  const fireScrollContent = (editor, e) => editor.dispatch("ScrollContent", e);
  const fireTextColorChange = (editor, data) => editor.dispatch("TextColorChange", data);
  const hsvColour = (hue, saturation, value2) => ({
    hue,
    saturation,
    value: value2
  });
  const fromRgb = (rgbaColour2) => {
    let h2 = 0;
    let s = 0;
    let v = 0;
    const r2 = rgbaColour2.red / 255;
    const g = rgbaColour2.green / 255;
    const b2 = rgbaColour2.blue / 255;
    const minRGB = Math.min(r2, Math.min(g, b2));
    const maxRGB = Math.max(r2, Math.max(g, b2));
    if (minRGB === maxRGB) {
      v = minRGB;
      return hsvColour(0, 0, v * 100);
    }
    const d = r2 === minRGB ? g - b2 : b2 === minRGB ? r2 - g : b2 - r2;
    h2 = r2 === minRGB ? 3 : b2 === minRGB ? 1 : 5;
    h2 = 60 * (h2 - d / (maxRGB - minRGB));
    s = (maxRGB - minRGB) / maxRGB;
    v = maxRGB;
    return hsvColour(Math.round(h2), Math.round(s * 100), Math.round(v * 100));
  };
  const hexToHsv = (hex) => fromRgb(fromHex(hex));
  const hsvToHex = (hsv) => fromRgba(fromHsv(hsv));
  const anyToHex = (color) => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
    const canvas = document.createElement("canvas");
    canvas.height = 1;
    canvas.width = 1;
    const canvasContext = canvas.getContext("2d");
    canvasContext.clearRect(0, 0, canvas.width, canvas.height);
    canvasContext.fillStyle = "#FFFFFF";
    canvasContext.fillStyle = color;
    canvasContext.fillRect(0, 0, 1, 1);
    const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
    const r2 = rgba[0];
    const g = rgba[1];
    const b2 = rgba[2];
    const a = rgba[3];
    return fromRgba(rgbaColour(r2, g, b2, a));
  });
  var global$4 = tinymce.util.Tools.resolve("tinymce.util.LocalStorage");
  const storageName = "tinymce-custom-colors";
  var ColorCache = (max2 = 10) => {
    const storageString = global$4.getItem(storageName);
    const localstorage = isString(storageString) ? JSON.parse(storageString) : [];
    const prune = (list) => {
      const diff = max2 - list.length;
      return diff < 0 ? list.slice(0, max2) : list;
    };
    const cache = prune(localstorage);
    const add2 = (key) => {
      indexOf(cache, key).each(remove2);
      cache.unshift(key);
      if (cache.length > max2) {
        cache.pop();
      }
      global$4.setItem(storageName, JSON.stringify(cache));
    };
    const remove2 = (idx) => {
      cache.splice(idx, 1);
    };
    const state = () => cache.slice(0);
    return {
      add: add2,
      state
    };
  };
  const colorCache = ColorCache(10);
  const calcCols = (colors) => Math.max(5, Math.ceil(Math.sqrt(colors)));
  const mapColors = (colorMap) => {
    const colors = [];
    for (let i = 0; i < colorMap.length; i += 2) {
      colors.push({
        text: colorMap[i + 1],
        value: "#" + anyToHex(colorMap[i]).value,
        type: "choiceitem"
      });
    }
    return colors;
  };
  const option$1 = (name2) => (editor) => editor.options.get(name2);
  const register$d = (editor) => {
    const registerOption = editor.options.register;
    registerOption("color_map", {
      processor: (value2) => {
        if (isArrayOf(value2, isString)) {
          return {
            value: mapColors(value2),
            valid: true
          };
        } else {
          return {
            valid: false,
            message: "Must be an array of strings."
          };
        }
      },
      default: [
        "#BFEDD2",
        "Light Green",
        "#FBEEB8",
        "Light Yellow",
        "#F8CAC6",
        "Light Red",
        "#ECCAFA",
        "Light Purple",
        "#C2E0F4",
        "Light Blue",
        "#2DC26B",
        "Green",
        "#F1C40F",
        "Yellow",
        "#E03E2D",
        "Red",
        "#B96AD9",
        "Purple",
        "#3598DB",
        "Blue",
        "#169179",
        "Dark Turquoise",
        "#E67E23",
        "Orange",
        "#BA372A",
        "Dark Red",
        "#843FA1",
        "Dark Purple",
        "#236FA1",
        "Dark Blue",
        "#ECF0F1",
        "Light Gray",
        "#CED4D9",
        "Medium Gray",
        "#95A5A6",
        "Gray",
        "#7E8C8D",
        "Dark Gray",
        "#34495E",
        "Navy Blue",
        "#000000",
        "Black",
        "#ffffff",
        "White"
      ]
    });
    registerOption("color_cols", {
      processor: "number",
      default: calcCols(getColors$2(editor).length)
    });
    registerOption("custom_colors", {
      processor: "boolean",
      default: true
    });
  };
  const getColorCols$1 = option$1("color_cols");
  const hasCustomColors$1 = option$1("custom_colors");
  const getColors$2 = option$1("color_map");
  const getCurrentColors = () => map$2(colorCache.state(), (color) => ({
    type: "choiceitem",
    text: color,
    value: color
  }));
  const addColor = (color) => {
    colorCache.add(color);
  };
  const fallbackColor = "#000000";
  const getCurrentColor = (editor, format) => {
    let color;
    editor.dom.getParents(editor.selection.getStart(), (elm) => {
      let value2;
      if (value2 = elm.style[format === "forecolor" ? "color" : "background-color"]) {
        color = color ? color : value2;
      }
    });
    return Optional.from(color);
  };
  const applyFormat = (editor, format, value2) => {
    editor.undoManager.transact(() => {
      editor.focus();
      editor.formatter.apply(format, { value: value2 });
      editor.nodeChanged();
    });
  };
  const removeFormat = (editor, format) => {
    editor.undoManager.transact(() => {
      editor.focus();
      editor.formatter.remove(format, { value: null }, null, true);
      editor.nodeChanged();
    });
  };
  const registerCommands = (editor) => {
    editor.addCommand("mceApplyTextcolor", (format, value2) => {
      applyFormat(editor, format, value2);
    });
    editor.addCommand("mceRemoveTextcolor", (format) => {
      removeFormat(editor, format);
    });
  };
  const getAdditionalColors = (hasCustom) => {
    const type2 = "choiceitem";
    const remove2 = {
      type: type2,
      text: "Remove color",
      icon: "color-swatch-remove-color",
      value: "remove"
    };
    const custom2 = {
      type: type2,
      text: "Custom color",
      icon: "color-picker",
      value: "custom"
    };
    return hasCustom ? [
      remove2,
      custom2
    ] : [remove2];
  };
  const applyColor = (editor, format, value2, onChoice) => {
    if (value2 === "custom") {
      const dialog = colorPickerDialog(editor);
      dialog((colorOpt) => {
        colorOpt.each((color) => {
          addColor(color);
          editor.execCommand("mceApplyTextcolor", format, color);
          onChoice(color);
        });
      }, fallbackColor);
    } else if (value2 === "remove") {
      onChoice("");
      editor.execCommand("mceRemoveTextcolor", format);
    } else {
      onChoice(value2);
      editor.execCommand("mceApplyTextcolor", format, value2);
    }
  };
  const getColors$1 = (colors, hasCustom) => colors.concat(getCurrentColors().concat(getAdditionalColors(hasCustom)));
  const getFetch$1 = (colors, hasCustom) => (callback) => {
    callback(getColors$1(colors, hasCustom));
  };
  const setIconColor = (splitButtonApi, name2, newColor) => {
    const id = name2 === "forecolor" ? "tox-icon-text-color__color" : "tox-icon-highlight-bg-color__color";
    splitButtonApi.setIconFill(id, newColor);
  };
  const registerTextColorButton = (editor, name2, format, tooltip, lastColor) => {
    editor.ui.registry.addSplitButton(name2, {
      tooltip,
      presets: "color",
      icon: name2 === "forecolor" ? "text-color" : "highlight-bg-color",
      select: (value2) => {
        const optCurrentRgb = getCurrentColor(editor, format);
        return optCurrentRgb.bind((currentRgb) => fromString(currentRgb).map((rgba) => {
          const currentHex = fromRgba(rgba).value;
          return contains$1(value2.toLowerCase(), currentHex);
        })).getOr(false);
      },
      columns: getColorCols$1(editor),
      fetch: getFetch$1(getColors$2(editor), hasCustomColors$1(editor)),
      onAction: (_splitButtonApi) => {
        applyColor(editor, format, lastColor.get(), noop);
      },
      onItemAction: (_splitButtonApi, value2) => {
        applyColor(editor, format, value2, (newColor) => {
          lastColor.set(newColor);
          fireTextColorChange(editor, {
            name: name2,
            color: newColor
          });
        });
      },
      onSetup: (splitButtonApi) => {
        setIconColor(splitButtonApi, name2, lastColor.get());
        const handler = (e) => {
          if (e.name === name2) {
            setIconColor(splitButtonApi, e.name, e.color);
          }
        };
        editor.on("TextColorChange", handler);
        return () => {
          editor.off("TextColorChange", handler);
        };
      }
    });
  };
  const registerTextColorMenuItem = (editor, name2, format, text2) => {
    editor.ui.registry.addNestedMenuItem(name2, {
      text: text2,
      icon: name2 === "forecolor" ? "text-color" : "highlight-bg-color",
      getSubmenuItems: () => [{
        type: "fancymenuitem",
        fancytype: "colorswatch",
        onAction: (data) => {
          applyColor(editor, format, data.value, noop);
        }
      }]
    });
  };
  const colorPickerDialog = (editor) => (callback, value2) => {
    let isValid = false;
    const onSubmit = (api2) => {
      const data = api2.getData();
      const hex = data.colorpicker;
      if (isValid) {
        callback(Optional.from(hex));
        api2.close();
      } else {
        editor.windowManager.alert(editor.translate([
          "Invalid hex color code: {0}",
          hex
        ]));
      }
    };
    const onAction2 = (_api, details) => {
      if (details.name === "hex-valid") {
        isValid = details.value;
      }
    };
    const initialData = { colorpicker: value2 };
    editor.windowManager.open({
      title: "Color Picker",
      size: "normal",
      body: {
        type: "panel",
        items: [{
          type: "colorpicker",
          name: "colorpicker",
          label: "Color"
        }]
      },
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData,
      onAction: onAction2,
      onSubmit,
      onClose: noop,
      onCancel: () => {
        callback(Optional.none());
      }
    });
  };
  const register$c = (editor) => {
    registerCommands(editor);
    const lastForeColor = Cell(fallbackColor);
    const lastBackColor = Cell(fallbackColor);
    registerTextColorButton(editor, "forecolor", "forecolor", "Text color", lastForeColor);
    registerTextColorButton(editor, "backcolor", "hilitecolor", "Background color", lastBackColor);
    registerTextColorMenuItem(editor, "forecolor", "forecolor", "Text color");
    registerTextColorMenuItem(editor, "backcolor", "hilitecolor", "Background color");
  };
  const createPartialChoiceMenu = (value2, items, onItemValueHandler, columns, presets, itemResponse, select2, providersBackstage) => {
    const hasIcons = menuHasIcons(items);
    const presetItemTypes = presets !== "color" ? "normal" : "color";
    const alloyItems = createChoiceItems(items, onItemValueHandler, columns, presetItemTypes, itemResponse, select2, providersBackstage);
    return createPartialMenuWithAlloyItems(value2, hasIcons, alloyItems, columns, presets);
  };
  const createChoiceItems = (items, onItemValueHandler, columns, itemPresets, itemResponse, select2, providersBackstage) => cat(map$2(items, (item2) => {
    if (item2.type === "choiceitem") {
      return createChoiceMenuItem(item2).fold(handleError, (d) => Optional.some(renderChoiceItem(d, columns === 1, itemPresets, onItemValueHandler, select2(item2.value), itemResponse, providersBackstage, menuHasIcons(items))));
    } else {
      return Optional.none();
    }
  }));
  const deriveMenuMovement = (columns, presets) => {
    const menuMarkers = markers(presets);
    if (columns === 1) {
      return {
        mode: "menu",
        moveOnTab: true
      };
    } else if (columns === "auto") {
      return {
        mode: "grid",
        selector: "." + menuMarkers.item,
        initSize: {
          numColumns: 1,
          numRows: 1
        }
      };
    } else {
      const rowClass = presets === "color" ? "tox-swatches__row" : "tox-collection__group";
      return {
        mode: "matrix",
        rowSelector: "." + rowClass
      };
    }
  };
  const deriveCollectionMovement = (columns, presets) => {
    if (columns === 1) {
      return {
        mode: "menu",
        moveOnTab: false,
        selector: ".tox-collection__item"
      };
    } else if (columns === "auto") {
      return {
        mode: "flatgrid",
        selector: ".tox-collection__item",
        initSize: {
          numColumns: 1,
          numRows: 1
        }
      };
    } else {
      return {
        mode: "matrix",
        selectors: {
          row: presets === "color" ? ".tox-swatches__row" : ".tox-collection__group",
          cell: presets === "color" ? `.${colorClass}` : `.${selectableClass}`
        }
      };
    }
  };
  const renderColorSwatchItem = (spec, backstage) => {
    const items = getColorItems(spec, backstage);
    const columns = backstage.colorinput.getColorCols();
    const presets = "color";
    const menuSpec = createPartialChoiceMenu(generate$6("menu-value"), items, (value2) => {
      spec.onAction({ value: value2 });
    }, columns, presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, backstage.shared.providers);
    const widgetSpec = {
      ...menuSpec,
      markers: markers(presets),
      movement: deriveMenuMovement(columns, presets)
    };
    return {
      type: "widget",
      data: { value: generate$6("widget-id") },
      dom: {
        tag: "div",
        classes: ["tox-fancymenuitem"]
      },
      autofocus: true,
      components: [parts$f.widget(Menu.sketch(widgetSpec))]
    };
  };
  const getColorItems = (spec, backstage) => {
    const useCustomColors = spec.initData.allowCustomColors && backstage.colorinput.hasCustomColors();
    return spec.initData.colors.fold(() => getColors$1(backstage.colorinput.getColors(), useCustomColors), (colors) => colors.concat(getAdditionalColors(useCustomColors)));
  };
  const cellOverEvent = generate$6("cell-over");
  const cellExecuteEvent = generate$6("cell-execute");
  const makeCell = (row, col, labelId) => {
    const emitCellOver = (c) => emitWith(c, cellOverEvent, {
      row,
      col
    });
    const emitExecute2 = (c) => emitWith(c, cellExecuteEvent, {
      row,
      col
    });
    const onClick = (c, se) => {
      se.stop();
      emitExecute2(c);
    };
    return build$1({
      dom: {
        tag: "div",
        attributes: {
          role: "button",
          ["aria-labelledby"]: labelId
        }
      },
      behaviours: derive$1([
        config("insert-table-picker-cell", [
          run$1(mouseover(), Focusing.focus),
          run$1(execute$5(), emitExecute2),
          run$1(click(), onClick),
          run$1(tap(), onClick)
        ]),
        Toggling.config({
          toggleClass: "tox-insert-table-picker__selected",
          toggleOnExecute: false
        }),
        Focusing.config({ onFocus: emitCellOver })
      ])
    });
  };
  const makeCells = (labelId, numRows, numCols) => {
    const cells = [];
    for (let i = 0; i < numRows; i++) {
      const row = [];
      for (let j = 0; j < numCols; j++) {
        row.push(makeCell(i, j, labelId));
      }
      cells.push(row);
    }
    return cells;
  };
  const selectCells = (cells, selectedRow, selectedColumn, numRows, numColumns) => {
    for (let i = 0; i < numRows; i++) {
      for (let j = 0; j < numColumns; j++) {
        Toggling.set(cells[i][j], i <= selectedRow && j <= selectedColumn);
      }
    }
  };
  const makeComponents = (cells) => bind$3(cells, (cellRow) => map$2(cellRow, premade));
  const makeLabelText = (row, col) => text$1(`${col}x${row}`);
  const renderInsertTableMenuItem = (spec) => {
    const numRows = 10;
    const numColumns = 10;
    const sizeLabelId = generate$6("size-label");
    const cells = makeCells(sizeLabelId, numRows, numColumns);
    const emptyLabelText = makeLabelText(0, 0);
    const memLabel = record({
      dom: {
        tag: "span",
        classes: ["tox-insert-table-picker__label"],
        attributes: { id: sizeLabelId }
      },
      components: [emptyLabelText],
      behaviours: derive$1([Replacing.config({})])
    });
    return {
      type: "widget",
      data: { value: generate$6("widget-id") },
      dom: {
        tag: "div",
        classes: ["tox-fancymenuitem"]
      },
      autofocus: true,
      components: [parts$f.widget({
        dom: {
          tag: "div",
          classes: ["tox-insert-table-picker"]
        },
        components: makeComponents(cells).concat(memLabel.asSpec()),
        behaviours: derive$1([
          config("insert-table-picker", [
            runOnAttached((c) => {
              Replacing.set(memLabel.get(c), [emptyLabelText]);
            }),
            runWithTarget(cellOverEvent, (c, t2, e) => {
              const { row, col } = e.event;
              selectCells(cells, row, col, numRows, numColumns);
              Replacing.set(memLabel.get(c), [makeLabelText(row + 1, col + 1)]);
            }),
            runWithTarget(cellExecuteEvent, (c, _, e) => {
              const { row, col } = e.event;
              spec.onAction({
                numRows: row + 1,
                numColumns: col + 1
              });
              emit(c, sandboxClose());
            })
          ]),
          Keying.config({
            initSize: {
              numRows,
              numColumns
            },
            mode: "flatgrid",
            selector: '[role="button"]'
          })
        ])
      })]
    };
  };
  const fancyMenuItems = {
    inserttable: renderInsertTableMenuItem,
    colorswatch: renderColorSwatchItem
  };
  const renderFancyMenuItem = (spec, backstage) => get$g(fancyMenuItems, spec.fancytype).map((render2) => render2(spec, backstage));
  const renderNestedItem = (spec, itemResponse, providersBackstage, renderIcons = true, downwardsCaret = false) => {
    const caret = downwardsCaret ? renderDownwardsCaret(providersBackstage.icons) : renderSubmenuCaret(providersBackstage.icons);
    const getApi2 = (component) => ({
      isEnabled: () => !Disabling.isDisabled(component),
      setEnabled: (state) => Disabling.set(component, !state)
    });
    const structure = renderItemStructure({
      presets: "normal",
      iconContent: spec.icon,
      textContent: spec.text,
      htmlContent: Optional.none(),
      ariaLabel: spec.text,
      caret: Optional.some(caret),
      checkMark: Optional.none(),
      shortcutContent: spec.shortcut
    }, providersBackstage, renderIcons);
    return renderCommonItem({
      data: buildData(spec),
      getApi: getApi2,
      enabled: spec.enabled,
      onAction: noop,
      onSetup: spec.onSetup,
      triggersSubmenu: true,
      itemBehaviours: []
    }, structure, itemResponse, providersBackstage);
  };
  const renderNormalItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
    const getApi2 = (component) => ({
      isEnabled: () => !Disabling.isDisabled(component),
      setEnabled: (state) => Disabling.set(component, !state)
    });
    const structure = renderItemStructure({
      presets: "normal",
      iconContent: spec.icon,
      textContent: spec.text,
      htmlContent: Optional.none(),
      ariaLabel: spec.text,
      caret: Optional.none(),
      checkMark: Optional.none(),
      shortcutContent: spec.shortcut
    }, providersBackstage, renderIcons);
    return renderCommonItem({
      data: buildData(spec),
      getApi: getApi2,
      enabled: spec.enabled,
      onAction: spec.onAction,
      onSetup: spec.onSetup,
      triggersSubmenu: false,
      itemBehaviours: []
    }, structure, itemResponse, providersBackstage);
  };
  const renderSeparatorItem = (spec) => ({
    type: "separator",
    dom: {
      tag: "div",
      classes: [
        selectableClass,
        groupHeadingClass
      ]
    },
    components: spec.text.map(text$1).toArray()
  });
  const renderToggleMenuItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
    const getApi2 = (component) => ({
      setActive: (state) => {
        Toggling.set(component, state);
      },
      isActive: () => Toggling.isOn(component),
      isEnabled: () => !Disabling.isDisabled(component),
      setEnabled: (state) => Disabling.set(component, !state)
    });
    const structure = renderItemStructure({
      iconContent: spec.icon,
      textContent: spec.text,
      htmlContent: Optional.none(),
      ariaLabel: spec.text,
      checkMark: Optional.some(renderCheckmark(providersBackstage.icons)),
      caret: Optional.none(),
      shortcutContent: spec.shortcut,
      presets: "normal",
      meta: spec.meta
    }, providersBackstage, renderIcons);
    return deepMerge(renderCommonItem({
      data: buildData(spec),
      enabled: spec.enabled,
      getApi: getApi2,
      onAction: spec.onAction,
      onSetup: spec.onSetup,
      triggersSubmenu: false,
      itemBehaviours: []
    }, structure, itemResponse, providersBackstage), {
      toggling: {
        toggleClass: tickedClass,
        toggleOnExecute: false,
        selected: spec.active
      }
    });
  };
  const autocomplete = renderAutocompleteItem;
  const separator$3 = renderSeparatorItem;
  const normal = renderNormalItem;
  const nested = renderNestedItem;
  const toggle$1 = renderToggleMenuItem;
  const fancy = renderFancyMenuItem;
  const card = renderCardMenuItem;
  var FocusMode;
  (function(FocusMode2) {
    FocusMode2[FocusMode2["ContentFocus"] = 0] = "ContentFocus";
    FocusMode2[FocusMode2["UiFocus"] = 1] = "UiFocus";
  })(FocusMode || (FocusMode = {}));
  const createMenuItemFromBridge = (item2, itemResponse, backstage, menuHasIcons2, isHorizontalMenu) => {
    const providersBackstage = backstage.shared.providers;
    const parseForHorizontalMenu = (menuitem) => !isHorizontalMenu ? menuitem : {
      ...menuitem,
      shortcut: Optional.none(),
      icon: menuitem.text.isSome() ? Optional.none() : menuitem.icon
    };
    switch (item2.type) {
      case "menuitem":
        return createMenuItem(item2).fold(handleError, (d) => Optional.some(normal(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons2)));
      case "nestedmenuitem":
        return createNestedMenuItem(item2).fold(handleError, (d) => Optional.some(nested(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons2, isHorizontalMenu)));
      case "togglemenuitem":
        return createToggleMenuItem(item2).fold(handleError, (d) => Optional.some(toggle$1(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons2)));
      case "separator":
        return createSeparatorMenuItem(item2).fold(handleError, (d) => Optional.some(separator$3(d)));
      case "fancymenuitem":
        return createFancyMenuItem(item2).fold(handleError, (d) => fancy(parseForHorizontalMenu(d), backstage));
      default: {
        console.error("Unknown item in general menu", item2);
        return Optional.none();
      }
    }
  };
  const createAutocompleteItems = (items, matchText, onItemValueHandler, columns, itemResponse, sharedBackstage, highlightOn) => {
    const renderText2 = columns === 1;
    const renderIcons = !renderText2 || menuHasIcons(items);
    return cat(map$2(items, (item2) => {
      switch (item2.type) {
        case "separator":
          return createSeparatorItem(item2).fold(handleError, (d) => Optional.some(separator$3(d)));
        case "cardmenuitem":
          return createCardMenuItem(item2).fold(handleError, (d) => Optional.some(card({
            ...d,
            onAction: (api2) => {
              d.onAction(api2);
              onItemValueHandler(d.value, d.meta);
            }
          }, itemResponse, sharedBackstage, {
            itemBehaviours: tooltipBehaviour(d.meta, sharedBackstage),
            cardText: {
              matchText,
              highlightOn
            }
          })));
        case "autocompleteitem":
        default:
          return createAutocompleterItem(item2).fold(handleError, (d) => Optional.some(autocomplete(d, matchText, renderText2, "normal", onItemValueHandler, itemResponse, sharedBackstage, renderIcons)));
      }
    }));
  };
  const createPartialMenu = (value2, items, itemResponse, backstage, isHorizontalMenu) => {
    const hasIcons = menuHasIcons(items);
    const alloyItems = cat(map$2(items, (item2) => {
      const itemHasIcon = (i) => isHorizontalMenu ? !has$2(i, "text") : hasIcons;
      const createItem = (i) => createMenuItemFromBridge(i, itemResponse, backstage, itemHasIcon(i), isHorizontalMenu);
      if (item2.type === "nestedmenuitem" && item2.getSubmenuItems().length <= 0) {
        return createItem({
          ...item2,
          enabled: false
        });
      } else {
        return createItem(item2);
      }
    }));
    const createPartial = isHorizontalMenu ? createHorizontalPartialMenuWithAlloyItems : createPartialMenuWithAlloyItems;
    return createPartial(value2, hasIcons, alloyItems, 1, "normal");
  };
  const createTieredDataFrom = (partialMenu) => tieredMenu.singleData(partialMenu.value, partialMenu);
  const createInlineMenuFrom = (partialMenu, columns, focusMode, presets) => {
    const movement = deriveMenuMovement(columns, presets);
    const menuMarkers = markers(presets);
    return {
      data: createTieredDataFrom({
        ...partialMenu,
        movement,
        menuBehaviours: SimpleBehaviours.unnamedEvents(columns !== "auto" ? [] : [runOnAttached((comp, _se) => {
          detectSize(comp, 4, menuMarkers.item).each(({ numColumns, numRows }) => {
            Keying.setGridSize(comp, numRows, numColumns);
          });
        })])
      }),
      menu: {
        markers: markers(presets),
        fakeFocus: focusMode === FocusMode.ContentFocus
      }
    };
  };
  const getAutocompleterRange = (dom2, initRange) => {
    return detect(SugarElement.fromDom(initRange.startContainer)).map((elm) => {
      const range2 = dom2.createRng();
      range2.selectNode(elm.dom);
      return range2;
    });
  };
  const register$b = (editor, sharedBackstage) => {
    const processingAction = Cell(false);
    const activeState = Cell(false);
    const autocompleter = build$1(InlineView.sketch({
      dom: {
        tag: "div",
        classes: ["tox-autocompleter"]
      },
      components: [],
      fireDismissalEventInstead: {},
      inlineBehaviours: derive$1([config("dismissAutocompleter", [run$1(dismissRequested(), () => cancelIfNecessary())])]),
      lazySink: sharedBackstage.getSink
    }));
    const isMenuOpen = () => InlineView.isOpen(autocompleter);
    const isActive = activeState.get;
    const hideIfNecessary = () => {
      if (isMenuOpen()) {
        InlineView.hide(autocompleter);
      }
    };
    const getMenu = () => InlineView.getContent(autocompleter).bind((tmenu) => {
      return get$h(tmenu.components(), 0);
    });
    const cancelIfNecessary = () => editor.execCommand("mceAutocompleterClose");
    const getCombinedItems = (matches) => {
      const columns = findMap(matches, (m) => Optional.from(m.columns)).getOr(1);
      return bind$3(matches, (match) => {
        const choices = match.items;
        return createAutocompleteItems(choices, match.matchText, (itemValue, itemMeta) => {
          const nr = editor.selection.getRng();
          getAutocompleterRange(editor.dom, nr).each((range2) => {
            const autocompleterApi = {
              hide: () => cancelIfNecessary(),
              reload: (fetchOptions) => {
                hideIfNecessary();
                editor.execCommand("mceAutocompleterReload", false, { fetchOptions });
              }
            };
            processingAction.set(true);
            match.onAction(autocompleterApi, range2, itemValue, itemMeta);
            processingAction.set(false);
          });
        }, columns, ItemResponse$1.BUBBLE_TO_SANDBOX, sharedBackstage, match.highlightOn);
      });
    };
    const display = (lookupData, items) => {
      findIn(SugarElement.fromDom(editor.getBody())).each((element2) => {
        const columns = findMap(lookupData, (ld) => Optional.from(ld.columns)).getOr(1);
        InlineView.showMenuAt(autocompleter, {
          anchor: {
            type: "node",
            root: SugarElement.fromDom(editor.getBody()),
            node: Optional.from(element2)
          }
        }, createInlineMenuFrom(createPartialMenuWithAlloyItems("autocompleter-value", true, items, columns, "normal"), columns, FocusMode.ContentFocus, "normal"));
      });
      getMenu().each(Highlighting.highlightFirst);
    };
    const updateDisplay = (lookupData) => {
      const combinedItems = getCombinedItems(lookupData);
      if (combinedItems.length > 0) {
        display(lookupData, combinedItems);
      } else {
        hideIfNecessary();
      }
    };
    editor.on("AutocompleterStart", ({ lookupData }) => {
      activeState.set(true);
      processingAction.set(false);
      updateDisplay(lookupData);
    });
    editor.on("AutocompleterUpdate", ({ lookupData }) => updateDisplay(lookupData));
    editor.on("AutocompleterEnd", () => {
      hideIfNecessary();
      activeState.set(false);
      processingAction.set(false);
    });
    const autocompleterUiApi = {
      cancelIfNecessary,
      isMenuOpen,
      isActive,
      isProcessingAction: processingAction.get,
      getMenu
    };
    AutocompleterEditorEvents.setup(autocompleterUiApi, editor);
  };
  const Autocompleter = { register: register$b };
  const closest = (scope, selector, isRoot) => closest$1(scope, selector, isRoot).isSome();
  const DelayedFunction = (fun, delay) => {
    let ref2 = null;
    const schedule = (...args) => {
      ref2 = setTimeout(() => {
        fun.apply(null, args);
        ref2 = null;
      }, delay);
    };
    const cancel = () => {
      if (ref2 !== null) {
        clearTimeout(ref2);
        ref2 = null;
      }
    };
    return {
      cancel,
      schedule
    };
  };
  const SIGNIFICANT_MOVE = 5;
  const LONGPRESS_DELAY = 400;
  const getTouch = (event) => {
    const raw = event.raw;
    if (raw.touches === void 0 || raw.touches.length !== 1) {
      return Optional.none();
    }
    return Optional.some(raw.touches[0]);
  };
  const isFarEnough = (touch2, data) => {
    const distX = Math.abs(touch2.clientX - data.x);
    const distY = Math.abs(touch2.clientY - data.y);
    return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
  };
  const monitor = (settings) => {
    const startData = value$2();
    const longpressFired = Cell(false);
    const longpress$1 = DelayedFunction((event) => {
      settings.triggerEvent(longpress(), event);
      longpressFired.set(true);
    }, LONGPRESS_DELAY);
    const handleTouchstart = (event) => {
      getTouch(event).each((touch2) => {
        longpress$1.cancel();
        const data = {
          x: touch2.clientX,
          y: touch2.clientY,
          target: event.target
        };
        longpress$1.schedule(event);
        longpressFired.set(false);
        startData.set(data);
      });
      return Optional.none();
    };
    const handleTouchmove = (event) => {
      longpress$1.cancel();
      getTouch(event).each((touch2) => {
        startData.on((data) => {
          if (isFarEnough(touch2, data)) {
            startData.clear();
          }
        });
      });
      return Optional.none();
    };
    const handleTouchend = (event) => {
      longpress$1.cancel();
      const isSame = (data) => eq(data.target, event.target);
      return startData.get().filter(isSame).map((_data) => {
        if (longpressFired.get()) {
          event.prevent();
          return false;
        } else {
          return settings.triggerEvent(tap(), event);
        }
      });
    };
    const handlers2 = wrapAll([
      {
        key: touchstart(),
        value: handleTouchstart
      },
      {
        key: touchmove(),
        value: handleTouchmove
      },
      {
        key: touchend(),
        value: handleTouchend
      }
    ]);
    const fireIfReady = (event, type2) => get$g(handlers2, type2).bind((handler) => handler(event));
    return { fireIfReady };
  };
  const isDangerous = (event) => {
    const keyEv = event.raw;
    return keyEv.which === BACKSPACE[0] && !contains$2([
      "input",
      "textarea"
    ], name$3(event.target)) && !closest(event.target, '[contenteditable="true"]');
  };
  const setup$d = (container, rawSettings) => {
    const settings = {
      stopBackspace: true,
      ...rawSettings
    };
    const pointerEvents2 = [
      "touchstart",
      "touchmove",
      "touchend",
      "touchcancel",
      "gesturestart",
      "mousedown",
      "mouseup",
      "mouseover",
      "mousemove",
      "mouseout",
      "click"
    ];
    const tapEvent = monitor(settings);
    const simpleEvents = map$2(pointerEvents2.concat([
      "selectstart",
      "input",
      "contextmenu",
      "change",
      "transitionend",
      "transitioncancel",
      "drag",
      "dragstart",
      "dragend",
      "dragenter",
      "dragleave",
      "dragover",
      "drop",
      "keyup"
    ]), (type2) => bind(container, type2, (event) => {
      tapEvent.fireIfReady(event, type2).each((tapStopped) => {
        if (tapStopped) {
          event.kill();
        }
      });
      const stopped = settings.triggerEvent(type2, event);
      if (stopped) {
        event.kill();
      }
    }));
    const pasteTimeout = value$2();
    const onPaste = bind(container, "paste", (event) => {
      tapEvent.fireIfReady(event, "paste").each((tapStopped) => {
        if (tapStopped) {
          event.kill();
        }
      });
      const stopped = settings.triggerEvent("paste", event);
      if (stopped) {
        event.kill();
      }
      pasteTimeout.set(setTimeout(() => {
        settings.triggerEvent(postPaste(), event);
      }, 0));
    });
    const onKeydown = bind(container, "keydown", (event) => {
      const stopped = settings.triggerEvent("keydown", event);
      if (stopped) {
        event.kill();
      } else if (settings.stopBackspace && isDangerous(event)) {
        event.prevent();
      }
    });
    const onFocusIn = bind(container, "focusin", (event) => {
      const stopped = settings.triggerEvent("focusin", event);
      if (stopped) {
        event.kill();
      }
    });
    const focusoutTimeout = value$2();
    const onFocusOut = bind(container, "focusout", (event) => {
      const stopped = settings.triggerEvent("focusout", event);
      if (stopped) {
        event.kill();
      }
      focusoutTimeout.set(setTimeout(() => {
        settings.triggerEvent(postBlur(), event);
      }, 0));
    });
    const unbind2 = () => {
      each$1(simpleEvents, (e) => {
        e.unbind();
      });
      onKeydown.unbind();
      onFocusIn.unbind();
      onFocusOut.unbind();
      onPaste.unbind();
      pasteTimeout.on(clearTimeout);
      focusoutTimeout.on(clearTimeout);
    };
    return { unbind: unbind2 };
  };
  const derive = (rawEvent, rawTarget) => {
    const source = get$g(rawEvent, "target").getOr(rawTarget);
    return Cell(source);
  };
  const fromSource = (event, source) => {
    const stopper2 = Cell(false);
    const cutter2 = Cell(false);
    const stop2 = () => {
      stopper2.set(true);
    };
    const cut = () => {
      cutter2.set(true);
    };
    return {
      stop: stop2,
      cut,
      isStopped: stopper2.get,
      isCut: cutter2.get,
      event,
      setSource: source.set,
      getSource: source.get
    };
  };
  const fromExternal = (event) => {
    const stopper2 = Cell(false);
    const stop2 = () => {
      stopper2.set(true);
    };
    return {
      stop: stop2,
      cut: noop,
      isStopped: stopper2.get,
      isCut: never,
      event,
      setSource: die("Cannot set source of a broadcasted event"),
      getSource: die("Cannot get source of a broadcasted event")
    };
  };
  const adt$1 = Adt.generate([
    { stopped: [] },
    { resume: ["element"] },
    { complete: [] }
  ]);
  const doTriggerHandler = (lookup2, eventType, rawEvent, target, source, logger) => {
    const handler = lookup2(eventType, target);
    const simulatedEvent = fromSource(rawEvent, source);
    return handler.fold(() => {
      logger.logEventNoHandlers(eventType, target);
      return adt$1.complete();
    }, (handlerInfo) => {
      const descHandler = handlerInfo.descHandler;
      const eventHandler2 = getCurried(descHandler);
      eventHandler2(simulatedEvent);
      if (simulatedEvent.isStopped()) {
        logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
        return adt$1.stopped();
      } else if (simulatedEvent.isCut()) {
        logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
        return adt$1.complete();
      } else {
        return parent(handlerInfo.element).fold(() => {
          logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
          return adt$1.complete();
        }, (parent2) => {
          logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
          return adt$1.resume(parent2);
        });
      }
    });
  };
  const doTriggerOnUntilStopped = (lookup2, eventType, rawEvent, rawTarget, source, logger) => doTriggerHandler(lookup2, eventType, rawEvent, rawTarget, source, logger).fold(always, (parent2) => doTriggerOnUntilStopped(lookup2, eventType, rawEvent, parent2, source, logger), never);
  const triggerHandler = (lookup2, eventType, rawEvent, target, logger) => {
    const source = derive(rawEvent, target);
    return doTriggerHandler(lookup2, eventType, rawEvent, target, source, logger);
  };
  const broadcast = (listeners, rawEvent, _logger) => {
    const simulatedEvent = fromExternal(rawEvent);
    each$1(listeners, (listener) => {
      const descHandler = listener.descHandler;
      const handler = getCurried(descHandler);
      handler(simulatedEvent);
    });
    return simulatedEvent.isStopped();
  };
  const triggerUntilStopped = (lookup2, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup2, eventType, rawEvent, rawEvent.target, logger);
  const triggerOnUntilStopped = (lookup2, eventType, rawEvent, rawTarget, logger) => {
    const source = derive(rawEvent, rawTarget);
    return doTriggerOnUntilStopped(lookup2, eventType, rawEvent, rawTarget, source, logger);
  };
  const eventHandler = (element2, descHandler) => ({
    element: element2,
    descHandler
  });
  const broadcastHandler = (id, handler) => ({
    id,
    descHandler: handler
  });
  const EventRegistry = () => {
    const registry = {};
    const registerId = (extraArgs, id, events2) => {
      each(events2, (v, k) => {
        const handlers2 = registry[k] !== void 0 ? registry[k] : {};
        handlers2[id] = curryArgs(v, extraArgs);
        registry[k] = handlers2;
      });
    };
    const findHandler = (handlers2, elem) => read$1(elem).bind((id) => get$g(handlers2, id)).map((descHandler) => eventHandler(elem, descHandler));
    const filterByType = (type2) => get$g(registry, type2).map((handlers2) => mapToArray(handlers2, (f, id) => broadcastHandler(id, f))).getOr([]);
    const find2 = (isAboveRoot, type2, target) => get$g(registry, type2).bind((handlers2) => closest$4(target, (elem) => findHandler(handlers2, elem), isAboveRoot));
    const unregisterId = (id) => {
      each(registry, (handlersById, _eventName) => {
        if (has$2(handlersById, id)) {
          delete handlersById[id];
        }
      });
    };
    return {
      registerId,
      unregisterId,
      filterByType,
      find: find2
    };
  };
  const Registry = () => {
    const events2 = EventRegistry();
    const components2 = {};
    const readOrTag = (component) => {
      const elem = component.element;
      return read$1(elem).getOrThunk(() => write("uid-", component.element));
    };
    const failOnDuplicate = (component, tagId) => {
      const conflict = components2[tagId];
      if (conflict === component) {
        unregister(component);
      } else {
        throw new Error('The tagId "' + tagId + '" is already used by: ' + element(conflict.element) + "\nCannot use it for: " + element(component.element) + "\nThe conflicting element is" + (inBody(conflict.element) ? " " : " not ") + "already in the DOM");
      }
    };
    const register2 = (component) => {
      const tagId = readOrTag(component);
      if (hasNonNullableKey(components2, tagId)) {
        failOnDuplicate(component, tagId);
      }
      const extraArgs = [component];
      events2.registerId(extraArgs, tagId, component.events);
      components2[tagId] = component;
    };
    const unregister = (component) => {
      read$1(component.element).each((tagId) => {
        delete components2[tagId];
        events2.unregisterId(tagId);
      });
    };
    const filter2 = (type2) => events2.filterByType(type2);
    const find2 = (isAboveRoot, type2, target) => events2.find(isAboveRoot, type2, target);
    const getById = (id) => get$g(components2, id);
    return {
      find: find2,
      filter: filter2,
      register: register2,
      unregister,
      getById
    };
  };
  const factory$j = (detail) => {
    const { attributes, ...domWithoutAttributes } = detail.dom;
    return {
      uid: detail.uid,
      dom: {
        tag: "div",
        attributes: {
          role: "presentation",
          ...attributes
        },
        ...domWithoutAttributes
      },
      components: detail.components,
      behaviours: get$3(detail.containerBehaviours),
      events: detail.events,
      domModification: detail.domModification,
      eventOrder: detail.eventOrder
    };
  };
  const Container = single({
    name: "Container",
    factory: factory$j,
    configFields: [
      defaulted("components", []),
      field("containerBehaviours", []),
      defaulted("events", {}),
      defaulted("domModification", {}),
      defaulted("eventOrder", {})
    ]
  });
  const takeover = (root) => {
    const isAboveRoot = (el) => parent(root.element).fold(always, (parent2) => eq(el, parent2));
    const registry = Registry();
    const lookup2 = (eventName, target) => registry.find(isAboveRoot, eventName, target);
    const domEvents = setup$d(root.element, {
      triggerEvent: (eventName, event) => {
        return monitorEvent(eventName, event.target, (logger) => triggerUntilStopped(lookup2, eventName, event, logger));
      }
    });
    const systemApi = {
      debugInfo: constant$1("real"),
      triggerEvent: (eventName, target, data) => {
        monitorEvent(eventName, target, (logger) => triggerOnUntilStopped(lookup2, eventName, data, target, logger));
      },
      triggerFocus: (target, originator) => {
        read$1(target).fold(() => {
          focus$3(target);
        }, (_alloyId) => {
          monitorEvent(focus$4(), target, (logger) => {
            triggerHandler(lookup2, focus$4(), {
              originator,
              kill: noop,
              prevent: noop,
              target
            }, target, logger);
            return false;
          });
        });
      },
      triggerEscape: (comp, simulatedEvent) => {
        systemApi.triggerEvent("keydown", comp.element, simulatedEvent.event);
      },
      getByUid: (uid) => {
        return getByUid(uid);
      },
      getByDom: (elem) => {
        return getByDom(elem);
      },
      build: build$1,
      buildOrPatch,
      addToGui: (c) => {
        add2(c);
      },
      removeFromGui: (c) => {
        remove2(c);
      },
      addToWorld: (c) => {
        addToWorld(c);
      },
      removeFromWorld: (c) => {
        removeFromWorld(c);
      },
      broadcast: (message) => {
        broadcast$1(message);
      },
      broadcastOn: (channels, message) => {
        broadcastOn(channels, message);
      },
      broadcastEvent: (eventName, event) => {
        broadcastEvent(eventName, event);
      },
      isConnected: always
    };
    const addToWorld = (component) => {
      component.connect(systemApi);
      if (!isText(component.element)) {
        registry.register(component);
        each$1(component.components(), addToWorld);
        systemApi.triggerEvent(systemInit(), component.element, { target: component.element });
      }
    };
    const removeFromWorld = (component) => {
      if (!isText(component.element)) {
        each$1(component.components(), removeFromWorld);
        registry.unregister(component);
      }
      component.disconnect();
    };
    const add2 = (component) => {
      attach(root, component);
    };
    const remove2 = (component) => {
      detach(component);
    };
    const destroy = () => {
      domEvents.unbind();
      remove$5(root.element);
    };
    const broadcastData = (data) => {
      const receivers = registry.filter(receive());
      each$1(receivers, (receiver) => {
        const descHandler = receiver.descHandler;
        const handler = getCurried(descHandler);
        handler(data);
      });
    };
    const broadcast$1 = (message) => {
      broadcastData({
        universal: true,
        data: message
      });
    };
    const broadcastOn = (channels, message) => {
      broadcastData({
        universal: false,
        channels,
        data: message
      });
    };
    const broadcastEvent = (eventName, event) => {
      const listeners = registry.filter(eventName);
      return broadcast(listeners, event);
    };
    const getByUid = (uid) => registry.getById(uid).fold(() => Result.error(new Error('Could not find component with uid: "' + uid + '" in system.')), Result.value);
    const getByDom = (elem) => {
      const uid = read$1(elem).getOr("not found");
      return getByUid(uid);
    };
    addToWorld(root);
    return {
      root,
      element: root.element,
      destroy,
      add: add2,
      remove: remove2,
      getByUid,
      getByDom,
      addToWorld,
      removeFromWorld,
      broadcast: broadcast$1,
      broadcastOn,
      broadcastEvent
    };
  };
  const renderBar = (spec, backstage) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-bar",
        "tox-form__controls-h-stack"
      ]
    },
    components: map$2(spec.items, backstage.interpreter)
  });
  const schema$l = constant$1([
    defaulted("prefix", "form-field"),
    field("fieldBehaviours", [
      Composing,
      Representing
    ])
  ]);
  const parts$e = constant$1([
    optional({
      schema: [required$1("dom")],
      name: "label"
    }),
    optional({
      factory: {
        sketch: (spec) => {
          return {
            uid: spec.uid,
            dom: {
              tag: "span",
              styles: { display: "none" },
              attributes: { "aria-hidden": "true" },
              innerHtml: spec.text
            }
          };
        }
      },
      schema: [required$1("text")],
      name: "aria-descriptor"
    }),
    required({
      factory: {
        sketch: (spec) => {
          const excludeFactory = exclude(spec, ["factory"]);
          return spec.factory.sketch(excludeFactory);
        }
      },
      schema: [required$1("factory")],
      name: "field"
    })
  ]);
  const factory$i = (detail, components2, _spec, _externals) => {
    const behaviours2 = augment(detail.fieldBehaviours, [
      Composing.config({
        find: (container) => {
          return getPart(container, detail, "field");
        }
      }),
      Representing.config({
        store: {
          mode: "manual",
          getValue: (field2) => {
            return Composing.getCurrent(field2).bind(Representing.getValue);
          },
          setValue: (field2, value2) => {
            Composing.getCurrent(field2).each((current) => {
              Representing.setValue(current, value2);
            });
          }
        }
      })
    ]);
    const events2 = derive$2([runOnAttached((component, _simulatedEvent) => {
      const ps = getParts(component, detail, [
        "label",
        "field",
        "aria-descriptor"
      ]);
      ps.field().each((field2) => {
        const id = generate$6(detail.prefix);
        ps.label().each((label2) => {
          set$9(label2.element, "for", id);
          set$9(field2.element, "id", id);
        });
        ps["aria-descriptor"]().each((descriptor) => {
          const descriptorId = generate$6(detail.prefix);
          set$9(descriptor.element, "id", descriptorId);
          set$9(field2.element, "aria-describedby", descriptorId);
        });
      });
    })]);
    const apis = {
      getField: (container) => getPart(container, detail, "field"),
      getLabel: (container) => getPart(container, detail, "label")
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: behaviours2,
      events: events2,
      apis
    };
  };
  const FormField = composite({
    name: "FormField",
    configFields: schema$l(),
    partFields: parts$e(),
    factory: factory$i,
    apis: {
      getField: (apis, comp) => apis.getField(comp),
      getLabel: (apis, comp) => apis.getLabel(comp)
    }
  });
  const exhibit$2 = (base2, tabConfig) => nu$7({
    attributes: wrapAll([{
      key: tabConfig.tabAttr,
      value: "true"
    }])
  });
  var ActiveTabstopping = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit: exhibit$2
  });
  var TabstopSchema = [defaulted("tabAttr", "data-alloy-tabstop")];
  const Tabstopping = create$3({
    fields: TabstopSchema,
    name: "tabstopping",
    active: ActiveTabstopping
  });
  var global$3 = tinymce.util.Tools.resolve("tinymce.html.Entities");
  const renderFormFieldWith = (pLabel, pField, extraClasses, extraBehaviours) => {
    const spec = renderFormFieldSpecWith(pLabel, pField, extraClasses, extraBehaviours);
    return FormField.sketch(spec);
  };
  const renderFormField = (pLabel, pField) => renderFormFieldWith(pLabel, pField, [], []);
  const renderFormFieldSpecWith = (pLabel, pField, extraClasses, extraBehaviours) => ({
    dom: renderFormFieldDomWith(extraClasses),
    components: pLabel.toArray().concat([pField]),
    fieldBehaviours: derive$1(extraBehaviours)
  });
  const renderFormFieldDom = () => renderFormFieldDomWith([]);
  const renderFormFieldDomWith = (extraClasses) => ({
    tag: "div",
    classes: ["tox-form__group"].concat(extraClasses)
  });
  const renderLabel$2 = (label2, providersBackstage) => FormField.parts.label({
    dom: {
      tag: "label",
      classes: ["tox-label"]
    },
    components: [text$1(providersBackstage.translate(label2))]
  });
  const formChangeEvent = generate$6("form-component-change");
  const formCloseEvent = generate$6("form-close");
  const formCancelEvent = generate$6("form-cancel");
  const formActionEvent = generate$6("form-action");
  const formSubmitEvent = generate$6("form-submit");
  const formBlockEvent = generate$6("form-block");
  const formUnblockEvent = generate$6("form-unblock");
  const formTabChangeEvent = generate$6("form-tabchange");
  const formResizeEvent = generate$6("form-resize");
  const renderCollection = (spec, providersBackstage, initialData) => {
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const runOnItem = (f) => (comp, se) => {
      closest$1(se.event.target, "[data-collection-item-value]").each((target) => {
        f(comp, se, target, get$f(target, "data-collection-item-value"));
      });
    };
    const setContents = (comp, items) => {
      const htmlLines = map$2(items, (item2) => {
        const itemText = global$8.translate(item2.text);
        const textContent = spec.columns === 1 ? `<div class="tox-collection__item-label">${itemText}</div>` : "";
        const iconContent = `<div class="tox-collection__item-icon">${item2.icon}</div>`;
        const mapItemName = {
          "_": " ",
          " - ": " ",
          "-": " "
        };
        const ariaLabel = itemText.replace(/\_| \- |\-/g, (match) => mapItemName[match]);
        const disabledClass = providersBackstage.isDisabled() ? " tox-collection__item--state-disabled" : "";
        return `<div class="tox-collection__item${disabledClass}" tabindex="-1" data-collection-item-value="${global$3.encodeAllRaw(item2.value)}" title="${ariaLabel}" aria-label="${ariaLabel}">${iconContent}${textContent}</div>`;
      });
      const chunks = spec.columns !== "auto" && spec.columns > 1 ? chunk$1(htmlLines, spec.columns) : [htmlLines];
      const html = map$2(chunks, (ch) => `<div class="tox-collection__group">${ch.join("")}</div>`);
      set$6(comp.element, html.join(""));
    };
    const onClick = runOnItem((comp, se, tgt, itemValue) => {
      se.stop();
      if (!providersBackstage.isDisabled()) {
        emitWith(comp, formActionEvent, {
          name: spec.name,
          value: itemValue
        });
      }
    });
    const collectionEvents = [
      run$1(mouseover(), runOnItem((comp, se, tgt) => {
        focus$3(tgt);
      })),
      run$1(click(), onClick),
      run$1(tap(), onClick),
      run$1(focusin(), runOnItem((comp, se, tgt) => {
        descendant(comp.element, "." + activeClass).each((currentActive) => {
          remove$2(currentActive, activeClass);
        });
        add$2(tgt, activeClass);
      })),
      run$1(focusout(), runOnItem((comp) => {
        descendant(comp.element, "." + activeClass).each((currentActive) => {
          remove$2(currentActive, activeClass);
        });
      })),
      runOnExecute$1(runOnItem((comp, se, tgt, itemValue) => {
        emitWith(comp, formActionEvent, {
          name: spec.name,
          value: itemValue
        });
      }))
    ];
    const iterCollectionItems = (comp, applyAttributes) => map$2(descendants(comp.element, ".tox-collection__item"), applyAttributes);
    const pField = FormField.parts.field({
      dom: {
        tag: "div",
        classes: ["tox-collection"].concat(spec.columns !== 1 ? ["tox-collection--grid"] : ["tox-collection--list"])
      },
      components: [],
      factory: { sketch: identity },
      behaviours: derive$1([
        Disabling.config({
          disabled: providersBackstage.isDisabled,
          onDisabled: (comp) => {
            iterCollectionItems(comp, (childElm) => {
              add$2(childElm, "tox-collection__item--state-disabled");
              set$9(childElm, "aria-disabled", true);
            });
          },
          onEnabled: (comp) => {
            iterCollectionItems(comp, (childElm) => {
              remove$2(childElm, "tox-collection__item--state-disabled");
              remove$7(childElm, "aria-disabled");
            });
          }
        }),
        receivingConfig(),
        Replacing.config({}),
        Representing.config({
          store: {
            mode: "memory",
            initialValue: initialData.getOr([])
          },
          onSetValue: (comp, items) => {
            setContents(comp, items);
            if (spec.columns === "auto") {
              detectSize(comp, 5, "tox-collection__item").each(({ numRows, numColumns }) => {
                Keying.setGridSize(comp, numRows, numColumns);
              });
            }
            emit(comp, formResizeEvent);
          }
        }),
        Tabstopping.config({}),
        Keying.config(deriveCollectionMovement(spec.columns, "normal")),
        config("collection-events", collectionEvents)
      ]),
      eventOrder: {
        [execute$5()]: [
          "disabling",
          "alloy.base.behaviour",
          "collection-events"
        ]
      }
    });
    const extraClasses = ["tox-form__group--collection"];
    return renderFormFieldWith(pLabel, pField, extraClasses, []);
  };
  const schema$k = constant$1([
    option$3("data"),
    defaulted("inputAttributes", {}),
    defaulted("inputStyles", {}),
    defaulted("tag", "input"),
    defaulted("inputClasses", []),
    onHandler("onSetValue"),
    defaulted("styles", {}),
    defaulted("eventOrder", {}),
    field("inputBehaviours", [
      Representing,
      Focusing
    ]),
    defaulted("selectOnFocus", true)
  ]);
  const focusBehaviours = (detail) => derive$1([Focusing.config({
    onFocus: !detail.selectOnFocus ? noop : (component) => {
      const input2 = component.element;
      const value2 = get$6(input2);
      input2.dom.setSelectionRange(0, value2.length);
    }
  })]);
  const behaviours = (detail) => ({
    ...focusBehaviours(detail),
    ...augment(detail.inputBehaviours, [Representing.config({
      store: {
        mode: "manual",
        ...detail.data.map((data) => ({ initialValue: data })).getOr({}),
        getValue: (input2) => {
          return get$6(input2.element);
        },
        setValue: (input2, data) => {
          const current = get$6(input2.element);
          if (current !== data) {
            set$5(input2.element, data);
          }
        }
      },
      onSetValue: detail.onSetValue
    })])
  });
  const dom = (detail) => ({
    tag: detail.tag,
    attributes: {
      type: "text",
      ...detail.inputAttributes
    },
    styles: detail.inputStyles,
    classes: detail.inputClasses
  });
  const factory$h = (detail, _spec) => ({
    uid: detail.uid,
    dom: dom(detail),
    components: [],
    behaviours: behaviours(detail),
    eventOrder: detail.eventOrder
  });
  const Input = single({
    name: "Input",
    configFields: schema$k(),
    factory: factory$h
  });
  const nu$3 = (baseFn) => {
    let data = Optional.none();
    let callbacks = [];
    const map2 = (f) => nu$3((nCallback) => {
      get2((data2) => {
        nCallback(f(data2));
      });
    });
    const get2 = (nCallback) => {
      if (isReady()) {
        call(nCallback);
      } else {
        callbacks.push(nCallback);
      }
    };
    const set2 = (x) => {
      if (!isReady()) {
        data = Optional.some(x);
        run2(callbacks);
        callbacks = [];
      }
    };
    const isReady = () => data.isSome();
    const run2 = (cbs) => {
      each$1(cbs, call);
    };
    const call = (cb) => {
      data.each((x) => {
        setTimeout(() => {
          cb(x);
        }, 0);
      });
    };
    baseFn(set2);
    return {
      get: get2,
      map: map2,
      isReady
    };
  };
  const pure$1 = (a) => nu$3((callback) => {
    callback(a);
  });
  const LazyValue = {
    nu: nu$3,
    pure: pure$1
  };
  const errorReporter = (err) => {
    setTimeout(() => {
      throw err;
    }, 0);
  };
  const make$5 = (run2) => {
    const get2 = (callback) => {
      run2().then(callback, errorReporter);
    };
    const map2 = (fab) => {
      return make$5(() => run2().then(fab));
    };
    const bind2 = (aFutureB) => {
      return make$5(() => run2().then((v) => aFutureB(v).toPromise()));
    };
    const anonBind = (futureB) => {
      return make$5(() => run2().then(() => futureB.toPromise()));
    };
    const toLazy = () => {
      return LazyValue.nu(get2);
    };
    const toCached = () => {
      let cache = null;
      return make$5(() => {
        if (cache === null) {
          cache = run2();
        }
        return cache;
      });
    };
    const toPromise = run2;
    return {
      map: map2,
      bind: bind2,
      anonBind,
      toLazy,
      toCached,
      toPromise,
      get: get2
    };
  };
  const nu$2 = (baseFn) => {
    return make$5(() => new Promise(baseFn));
  };
  const pure = (a) => {
    return make$5(() => Promise.resolve(a));
  };
  const Future = {
    nu: nu$2,
    pure
  };
  const ariaElements = [
    "input",
    "textarea"
  ];
  const isAriaElement = (elem) => {
    const name2 = name$3(elem);
    return contains$2(ariaElements, name2);
  };
  const markValid = (component, invalidConfig) => {
    const elem = invalidConfig.getRoot(component).getOr(component.element);
    remove$2(elem, invalidConfig.invalidClass);
    invalidConfig.notify.each((notifyInfo) => {
      if (isAriaElement(component.element)) {
        set$9(component.element, "aria-invalid", false);
      }
      notifyInfo.getContainer(component).each((container) => {
        set$6(container, notifyInfo.validHtml);
      });
      notifyInfo.onValid(component);
    });
  };
  const markInvalid = (component, invalidConfig, invalidState, text2) => {
    const elem = invalidConfig.getRoot(component).getOr(component.element);
    add$2(elem, invalidConfig.invalidClass);
    invalidConfig.notify.each((notifyInfo) => {
      if (isAriaElement(component.element)) {
        set$9(component.element, "aria-invalid", true);
      }
      notifyInfo.getContainer(component).each((container) => {
        set$6(container, text2);
      });
      notifyInfo.onInvalid(component, text2);
    });
  };
  const query = (component, invalidConfig, _invalidState) => invalidConfig.validator.fold(() => Future.pure(Result.value(true)), (validatorInfo) => validatorInfo.validate(component));
  const run = (component, invalidConfig, invalidState) => {
    invalidConfig.notify.each((notifyInfo) => {
      notifyInfo.onValidate(component);
    });
    return query(component, invalidConfig).map((valid) => {
      if (component.getSystem().isConnected()) {
        return valid.fold((err) => {
          markInvalid(component, invalidConfig, invalidState, err);
          return Result.error(err);
        }, (v) => {
          markValid(component, invalidConfig);
          return Result.value(v);
        });
      } else {
        return Result.error("No longer in system");
      }
    });
  };
  const isInvalid = (component, invalidConfig) => {
    const elem = invalidConfig.getRoot(component).getOr(component.element);
    return has(elem, invalidConfig.invalidClass);
  };
  var InvalidateApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    markValid,
    markInvalid,
    query,
    run,
    isInvalid
  });
  const events$8 = (invalidConfig, invalidState) => invalidConfig.validator.map((validatorInfo) => derive$2([run$1(validatorInfo.onEvent, (component) => {
    run(component, invalidConfig, invalidState).get(identity);
  })].concat(validatorInfo.validateOnLoad ? [runOnAttached((component) => {
    run(component, invalidConfig, invalidState).get(noop);
  })] : []))).getOr({});
  var ActiveInvalidate = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$8
  });
  var InvalidateSchema = [
    required$1("invalidClass"),
    defaulted("getRoot", Optional.none),
    optionObjOf("notify", [
      defaulted("aria", "alert"),
      defaulted("getContainer", Optional.none),
      defaulted("validHtml", ""),
      onHandler("onValid"),
      onHandler("onInvalid"),
      onHandler("onValidate")
    ]),
    optionObjOf("validator", [
      required$1("validate"),
      defaulted("onEvent", "input"),
      defaulted("validateOnLoad", true)
    ])
  ];
  const Invalidating = create$3({
    fields: InvalidateSchema,
    name: "invalidating",
    active: ActiveInvalidate,
    apis: InvalidateApis,
    extra: {
      validation: (validator) => {
        return (component) => {
          const v = Representing.getValue(component);
          return Future.pure(validator(v));
        };
      }
    }
  });
  const getCoupled = (component, coupleConfig, coupleState, name2) => coupleState.getOrCreate(component, coupleConfig, name2);
  var CouplingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    getCoupled
  });
  var CouplingSchema = [requiredOf("others", setOf(Result.value, anyValue()))];
  const init$a = () => {
    const coupled = {};
    const getOrCreate = (component, coupleConfig, name2) => {
      const available = keys(coupleConfig.others);
      if (!available) {
        throw new Error("Cannot find coupled component: " + name2 + ". Known coupled components: " + JSON.stringify(available, null, 2));
      } else {
        return get$g(coupled, name2).getOrThunk(() => {
          const builder2 = get$g(coupleConfig.others, name2).getOrDie("No information found for coupled component: " + name2);
          const spec = builder2(component);
          const built = component.getSystem().build(spec);
          coupled[name2] = built;
          return built;
        });
      }
    };
    const readState = constant$1({});
    return nu$8({
      readState,
      getOrCreate
    });
  };
  var CouplingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$a
  });
  const Coupling = create$3({
    fields: CouplingSchema,
    name: "coupling",
    apis: CouplingApis,
    state: CouplingState
  });
  const suffix = constant$1("sink");
  const partType$1 = constant$1(optional({
    name: suffix(),
    overrides: constant$1({
      dom: { tag: "div" },
      behaviours: derive$1([Positioning.config({ useFixed: always })]),
      events: derive$2([
        cutter(keydown()),
        cutter(mousedown()),
        cutter(click())
      ])
    })
  }));
  var HighlightOnOpen;
  (function(HighlightOnOpen2) {
    HighlightOnOpen2[HighlightOnOpen2["HighlightFirst"] = 0] = "HighlightFirst";
    HighlightOnOpen2[HighlightOnOpen2["HighlightNone"] = 1] = "HighlightNone";
  })(HighlightOnOpen || (HighlightOnOpen = {}));
  const getAnchor = (detail, component) => {
    const hotspot = detail.getHotspot(component).getOr(component);
    const type2 = "hotspot";
    const overrides = detail.getAnchorOverrides();
    return detail.layouts.fold(() => ({
      type: type2,
      hotspot,
      overrides
    }), (layouts2) => ({
      type: type2,
      hotspot,
      overrides,
      layouts: layouts2
    }));
  };
  const fetch2 = (detail, mapFetch, component) => {
    const fetcher = detail.fetch;
    return fetcher(component).map(mapFetch);
  };
  const openF = (detail, mapFetch, anchor2, component, sandbox, externals, highlightOnOpen) => {
    const futureData = fetch2(detail, mapFetch, component);
    const getLazySink = getSink(component, detail);
    return futureData.map((tdata) => tdata.bind((data) => Optional.from(tieredMenu.sketch({
      ...externals.menu(),
      uid: generate$5(""),
      data,
      highlightImmediately: highlightOnOpen === HighlightOnOpen.HighlightFirst,
      onOpenMenu: (tmenu, menu2) => {
        const sink = getLazySink().getOrDie();
        Positioning.position(sink, menu2, { anchor: anchor2 });
        Sandboxing.decloak(sandbox);
      },
      onOpenSubmenu: (tmenu, item2, submenu) => {
        const sink = getLazySink().getOrDie();
        Positioning.position(sink, submenu, {
          anchor: {
            type: "submenu",
            item: item2
          }
        });
        Sandboxing.decloak(sandbox);
      },
      onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
        const sink = getLazySink().getOrDie();
        Positioning.position(sink, primaryMenu, { anchor: anchor2 });
        each$1(submenuTriggers, (st) => {
          Positioning.position(sink, st.triggeredMenu, {
            anchor: {
              type: "submenu",
              item: st.triggeringItem
            }
          });
        });
      },
      onEscape: () => {
        Focusing.focus(component);
        Sandboxing.close(sandbox);
        return Optional.some(true);
      }
    }))));
  };
  const open = (detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen) => {
    const anchor2 = getAnchor(detail, hotspot);
    const processed = openF(detail, mapFetch, anchor2, hotspot, sandbox, externals, highlightOnOpen);
    return processed.map((tdata) => {
      tdata.fold(() => {
        if (Sandboxing.isOpen(sandbox)) {
          Sandboxing.close(sandbox);
        }
      }, (data) => {
        Sandboxing.cloak(sandbox);
        Sandboxing.open(sandbox, data);
        onOpenSync(sandbox);
      });
      return sandbox;
    });
  };
  const close = (detail, mapFetch, component, sandbox, _externals, _onOpenSync, _highlightOnOpen) => {
    Sandboxing.close(sandbox);
    return Future.pure(sandbox);
  };
  const togglePopup = (detail, mapFetch, hotspot, externals, onOpenSync, highlightOnOpen) => {
    const sandbox = Coupling.getCoupled(hotspot, "sandbox");
    const showing = Sandboxing.isOpen(sandbox);
    const action = showing ? close : open;
    return action(detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen);
  };
  const matchWidth = (hotspot, container, useMinWidth) => {
    const menu2 = Composing.getCurrent(container).getOr(container);
    const buttonWidth = get$c(hotspot.element);
    if (useMinWidth) {
      set$8(menu2.element, "min-width", buttonWidth + "px");
    } else {
      set$7(menu2.element, buttonWidth);
    }
  };
  const getSink = (anyInSystem, sinkDetail) => anyInSystem.getSystem().getByUid(sinkDetail.uid + "-" + suffix()).map((internalSink) => () => Result.value(internalSink)).getOrThunk(() => sinkDetail.lazySink.fold(() => () => Result.error(new Error("No internal sink is specified, nor could an external sink be found")), (lazySinkFn) => () => lazySinkFn(anyInSystem)));
  const doRepositionMenus = (sandbox) => {
    Sandboxing.getState(sandbox).each((tmenu) => {
      tieredMenu.repositionMenus(tmenu);
    });
  };
  const makeSandbox$1 = (detail, hotspot, extras) => {
    const ariaControls = manager();
    const onOpen = (component, menu2) => {
      const anchor2 = getAnchor(detail, hotspot);
      ariaControls.link(hotspot.element);
      if (detail.matchWidth) {
        matchWidth(anchor2.hotspot, menu2, detail.useMinWidth);
      }
      detail.onOpen(anchor2, component, menu2);
      if (extras !== void 0 && extras.onOpen !== void 0) {
        extras.onOpen(component, menu2);
      }
    };
    const onClose = (component, menu2) => {
      ariaControls.unlink(hotspot.element);
      if (extras !== void 0 && extras.onClose !== void 0) {
        extras.onClose(component, menu2);
      }
    };
    const lazySink = getSink(hotspot, detail);
    return {
      dom: {
        tag: "div",
        classes: detail.sandboxClasses,
        attributes: {
          id: ariaControls.id,
          role: "listbox"
        }
      },
      behaviours: SketchBehaviours.augment(detail.sandboxBehaviours, [
        Representing.config({
          store: {
            mode: "memory",
            initialValue: hotspot
          }
        }),
        Sandboxing.config({
          onOpen,
          onClose,
          isPartOf: (container, data, queryElem) => {
            return isPartOf$1(data, queryElem) || isPartOf$1(hotspot, queryElem);
          },
          getAttachPoint: () => {
            return lazySink().getOrDie();
          }
        }),
        Composing.config({
          find: (sandbox) => {
            return Sandboxing.getState(sandbox).bind((menu2) => Composing.getCurrent(menu2));
          }
        }),
        Receiving.config({
          channels: {
            ...receivingChannel$1({ isExtraPart: never }),
            ...receivingChannel({ doReposition: doRepositionMenus })
          }
        })
      ])
    };
  };
  const repositionMenus = (comp) => {
    const sandbox = Coupling.getCoupled(comp, "sandbox");
    doRepositionMenus(sandbox);
  };
  const sandboxFields = () => [
    defaulted("sandboxClasses", []),
    SketchBehaviours.field("sandboxBehaviours", [
      Composing,
      Receiving,
      Sandboxing,
      Representing
    ])
  ];
  const schema$j = constant$1([
    required$1("dom"),
    required$1("fetch"),
    onHandler("onOpen"),
    onKeyboardHandler("onExecute"),
    defaulted("getHotspot", Optional.some),
    defaulted("getAnchorOverrides", constant$1({})),
    schema$y(),
    field("dropdownBehaviours", [
      Toggling,
      Coupling,
      Keying,
      Focusing
    ]),
    required$1("toggleClass"),
    defaulted("eventOrder", {}),
    option$3("lazySink"),
    defaulted("matchWidth", false),
    defaulted("useMinWidth", false),
    option$3("role")
  ].concat(sandboxFields()));
  const parts$d = constant$1([
    external({
      schema: [tieredMenuMarkers()],
      name: "menu",
      defaults: (detail) => {
        return { onExecute: detail.onExecute };
      }
    }),
    partType$1()
  ]);
  const factory$g = (detail, components2, _spec, externals) => {
    const lookupAttr = (attr) => get$g(detail.dom, "attributes").bind((attrs) => get$g(attrs, attr));
    const switchToMenu = (sandbox) => {
      Sandboxing.getState(sandbox).each((tmenu) => {
        tieredMenu.highlightPrimary(tmenu);
      });
    };
    const action = (component) => {
      const onOpenSync = switchToMenu;
      togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
    };
    const apis = {
      expand: (comp) => {
        if (!Toggling.isOn(comp)) {
          togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightNone).get(noop);
        }
      },
      open: (comp) => {
        if (!Toggling.isOn(comp)) {
          togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightFirst).get(noop);
        }
      },
      isOpen: Toggling.isOn,
      close: (comp) => {
        if (Toggling.isOn(comp)) {
          togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightFirst).get(noop);
        }
      },
      repositionMenus: (comp) => {
        if (Toggling.isOn(comp)) {
          repositionMenus(comp);
        }
      }
    };
    const triggerExecute = (comp, _se) => {
      emitExecute(comp);
      return Optional.some(true);
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: augment(detail.dropdownBehaviours, [
        Toggling.config({
          toggleClass: detail.toggleClass,
          aria: { mode: "expanded" }
        }),
        Coupling.config({
          others: {
            sandbox: (hotspot) => {
              return makeSandbox$1(detail, hotspot, {
                onOpen: () => Toggling.on(hotspot),
                onClose: () => Toggling.off(hotspot)
              });
            }
          }
        }),
        Keying.config({
          mode: "special",
          onSpace: triggerExecute,
          onEnter: triggerExecute,
          onDown: (comp, _se) => {
            if (Dropdown.isOpen(comp)) {
              const sandbox = Coupling.getCoupled(comp, "sandbox");
              switchToMenu(sandbox);
            } else {
              Dropdown.open(comp);
            }
            return Optional.some(true);
          },
          onEscape: (comp, _se) => {
            if (Dropdown.isOpen(comp)) {
              Dropdown.close(comp);
              return Optional.some(true);
            } else {
              return Optional.none();
            }
          }
        }),
        Focusing.config({})
      ]),
      events: events$a(Optional.some(action)),
      eventOrder: {
        ...detail.eventOrder,
        [execute$5()]: [
          "disabling",
          "toggling",
          "alloy.base.behaviour"
        ]
      },
      apis,
      domModification: {
        attributes: {
          "aria-haspopup": "true",
          ...detail.role.fold(() => ({}), (role) => ({ role })),
          ...detail.dom.tag === "button" ? { type: lookupAttr("type").getOr("button") } : {}
        }
      }
    };
  };
  const Dropdown = composite({
    name: "Dropdown",
    configFields: schema$j(),
    partFields: parts$d(),
    factory: factory$g,
    apis: {
      open: (apis, comp) => apis.open(comp),
      expand: (apis, comp) => apis.expand(comp),
      close: (apis, comp) => apis.close(comp),
      isOpen: (apis, comp) => apis.isOpen(comp),
      repositionMenus: (apis, comp) => apis.repositionMenus(comp)
    }
  });
  const exhibit$1 = () => nu$7({
    styles: {
      "-webkit-user-select": "none",
      "user-select": "none",
      "-ms-user-select": "none",
      "-moz-user-select": "-moz-none"
    },
    attributes: { unselectable: "on" }
  });
  const events$7 = () => derive$2([abort(selectstart(), always)]);
  var ActiveUnselecting = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$7,
    exhibit: exhibit$1
  });
  const Unselecting = create$3({
    fields: [],
    name: "unselecting",
    active: ActiveUnselecting
  });
  const renderPanelButton = (spec, sharedBackstage) => Dropdown.sketch({
    dom: spec.dom,
    components: spec.components,
    toggleClass: "mce-active",
    dropdownBehaviours: derive$1([
      DisablingConfigs.button(sharedBackstage.providers.isDisabled),
      receivingConfig(),
      Unselecting.config({}),
      Tabstopping.config({})
    ]),
    layouts: spec.layouts,
    sandboxClasses: ["tox-dialog__popups"],
    lazySink: sharedBackstage.getSink,
    fetch: (comp) => Future.nu((callback) => spec.fetch(callback)).map((items) => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6("menu-value"), items, (value2) => {
      spec.onItemAction(comp, value2);
    }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, sharedBackstage.providers), { movement: deriveMenuMovement(spec.columns, spec.presets) })))),
    parts: { menu: part(false, 1, spec.presets) }
  });
  const colorInputChangeEvent = generate$6("color-input-change");
  const colorSwatchChangeEvent = generate$6("color-swatch-change");
  const colorPickerCancelEvent = generate$6("color-picker-cancel");
  const renderColorInput = (spec, sharedBackstage, colorInputBackstage, initialData) => {
    const pField = FormField.parts.field({
      factory: Input,
      inputClasses: ["tox-textfield"],
      data: initialData,
      onSetValue: (c) => Invalidating.run(c).get(noop),
      inputBehaviours: derive$1([
        Disabling.config({ disabled: sharedBackstage.providers.isDisabled }),
        receivingConfig(),
        Tabstopping.config({}),
        Invalidating.config({
          invalidClass: "tox-textbox-field-invalid",
          getRoot: (comp) => parentElement(comp.element),
          notify: {
            onValid: (comp) => {
              const val = Representing.getValue(comp);
              emitWith(comp, colorInputChangeEvent, { color: val });
            }
          },
          validator: {
            validateOnLoad: false,
            validate: (input2) => {
              const inputValue = Representing.getValue(input2);
              if (inputValue.length === 0) {
                return Future.pure(Result.value(true));
              } else {
                const span = SugarElement.fromTag("span");
                set$8(span, "background-color", inputValue);
                const res = getRaw(span, "background-color").fold(() => Result.error("blah"), (_) => Result.value(inputValue));
                return Future.pure(res);
              }
            }
          }
        })
      ]),
      selectOnFocus: false
    });
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, sharedBackstage.providers));
    const emitSwatchChange = (colorBit, value2) => {
      emitWith(colorBit, colorSwatchChangeEvent, { value: value2 });
    };
    const onItemAction2 = (comp, value2) => {
      memColorButton.getOpt(comp).each((colorBit) => {
        if (value2 === "custom") {
          colorInputBackstage.colorPicker((valueOpt) => {
            valueOpt.fold(() => emit(colorBit, colorPickerCancelEvent), (value3) => {
              emitSwatchChange(colorBit, value3);
              addColor(value3);
            });
          }, "#ffffff");
        } else if (value2 === "remove") {
          emitSwatchChange(colorBit, "");
        } else {
          emitSwatchChange(colorBit, value2);
        }
      });
    };
    const memColorButton = record(renderPanelButton({
      dom: {
        tag: "span",
        attributes: { "aria-label": sharedBackstage.providers.translate("Color swatch") }
      },
      layouts: {
        onRtl: () => [
          southwest$2,
          southeast$2,
          south$2
        ],
        onLtr: () => [
          southeast$2,
          southwest$2,
          south$2
        ]
      },
      components: [],
      fetch: getFetch$1(colorInputBackstage.getColors(), colorInputBackstage.hasCustomColors()),
      columns: colorInputBackstage.getColorCols(),
      presets: "color",
      onItemAction: onItemAction2
    }, sharedBackstage));
    return FormField.sketch({
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: pLabel.toArray().concat([{
        dom: {
          tag: "div",
          classes: ["tox-color-input"]
        },
        components: [
          pField,
          memColorButton.asSpec()
        ]
      }]),
      fieldBehaviours: derive$1([config("form-field-events", [
        run$1(colorInputChangeEvent, (comp, se) => {
          memColorButton.getOpt(comp).each((colorButton) => {
            set$8(colorButton.element, "background-color", se.event.color);
          });
          emitWith(comp, formChangeEvent, { name: spec.name });
        }),
        run$1(colorSwatchChangeEvent, (comp, se) => {
          FormField.getField(comp).each((field2) => {
            Representing.setValue(field2, se.event.value);
            Composing.getCurrent(comp).each(Focusing.focus);
          });
        }),
        run$1(colorPickerCancelEvent, (comp, _se) => {
          FormField.getField(comp).each((_field) => {
            Composing.getCurrent(comp).each(Focusing.focus);
          });
        })
      ])])
    });
  };
  const labelPart = optional({
    schema: [required$1("dom")],
    name: "label"
  });
  const edgePart = (name2) => optional({
    name: "" + name2 + "-edge",
    overrides: (detail) => {
      const action = detail.model.manager.edgeActions[name2];
      return action.fold(() => ({}), (a) => ({
        events: derive$2([
          runActionExtra(touchstart(), (comp, se, d) => a(comp, d), [detail]),
          runActionExtra(mousedown(), (comp, se, d) => a(comp, d), [detail]),
          runActionExtra(mousemove(), (comp, se, det) => {
            if (det.mouseIsDown.get()) {
              a(comp, det);
            }
          }, [detail])
        ])
      }));
    }
  });
  const tlEdgePart = edgePart("top-left");
  const tedgePart = edgePart("top");
  const trEdgePart = edgePart("top-right");
  const redgePart = edgePart("right");
  const brEdgePart = edgePart("bottom-right");
  const bedgePart = edgePart("bottom");
  const blEdgePart = edgePart("bottom-left");
  const ledgePart = edgePart("left");
  const thumbPart = required({
    name: "thumb",
    defaults: constant$1({ dom: { styles: { position: "absolute" } } }),
    overrides: (detail) => {
      return {
        events: derive$2([
          redirectToPart(touchstart(), detail, "spectrum"),
          redirectToPart(touchmove(), detail, "spectrum"),
          redirectToPart(touchend(), detail, "spectrum"),
          redirectToPart(mousedown(), detail, "spectrum"),
          redirectToPart(mousemove(), detail, "spectrum"),
          redirectToPart(mouseup(), detail, "spectrum")
        ])
      };
    }
  });
  const spectrumPart = required({
    schema: [customField("mouseIsDown", () => Cell(false))],
    name: "spectrum",
    overrides: (detail) => {
      const modelDetail = detail.model;
      const model = modelDetail.manager;
      const setValueFrom2 = (component, simulatedEvent) => model.getValueFromEvent(simulatedEvent).map((value2) => model.setValueFrom(component, detail, value2));
      return {
        behaviours: derive$1([
          Keying.config({
            mode: "special",
            onLeft: (spectrum) => model.onLeft(spectrum, detail),
            onRight: (spectrum) => model.onRight(spectrum, detail),
            onUp: (spectrum) => model.onUp(spectrum, detail),
            onDown: (spectrum) => model.onDown(spectrum, detail)
          }),
          Focusing.config({})
        ]),
        events: derive$2([
          run$1(touchstart(), setValueFrom2),
          run$1(touchmove(), setValueFrom2),
          run$1(mousedown(), setValueFrom2),
          run$1(mousemove(), (spectrum, se) => {
            if (detail.mouseIsDown.get()) {
              setValueFrom2(spectrum, se);
            }
          })
        ])
      };
    }
  });
  var SliderParts = [
    labelPart,
    ledgePart,
    redgePart,
    tedgePart,
    bedgePart,
    tlEdgePart,
    trEdgePart,
    blEdgePart,
    brEdgePart,
    thumbPart,
    spectrumPart
  ];
  const _sliderChangeEvent = "slider.change.value";
  const sliderChangeEvent = constant$1(_sliderChangeEvent);
  const isTouchEvent$1 = (evt) => evt.type.indexOf("touch") !== -1;
  const getEventSource = (simulatedEvent) => {
    const evt = simulatedEvent.event.raw;
    if (isTouchEvent$1(evt)) {
      const touchEvent = evt;
      return touchEvent.touches !== void 0 && touchEvent.touches.length === 1 ? Optional.some(touchEvent.touches[0]).map((t2) => SugarPosition(t2.clientX, t2.clientY)) : Optional.none();
    } else {
      const mouseEvent = evt;
      return mouseEvent.clientX !== void 0 ? Optional.some(mouseEvent).map((me) => SugarPosition(me.clientX, me.clientY)) : Optional.none();
    }
  };
  const t = "top", r = "right", b = "bottom", l = "left";
  const minX = (detail) => detail.model.minX;
  const minY = (detail) => detail.model.minY;
  const min1X = (detail) => detail.model.minX - 1;
  const min1Y = (detail) => detail.model.minY - 1;
  const maxX = (detail) => detail.model.maxX;
  const maxY = (detail) => detail.model.maxY;
  const max1X = (detail) => detail.model.maxX + 1;
  const max1Y = (detail) => detail.model.maxY + 1;
  const range = (detail, max2, min2) => max2(detail) - min2(detail);
  const xRange = (detail) => range(detail, maxX, minX);
  const yRange = (detail) => range(detail, maxY, minY);
  const halfX = (detail) => xRange(detail) / 2;
  const halfY = (detail) => yRange(detail) / 2;
  const step = (detail) => detail.stepSize;
  const snap = (detail) => detail.snapToGrid;
  const snapStart = (detail) => detail.snapStart;
  const rounded = (detail) => detail.rounded;
  const hasEdge = (detail, edgeName) => detail[edgeName + "-edge"] !== void 0;
  const hasLEdge = (detail) => hasEdge(detail, l);
  const hasREdge = (detail) => hasEdge(detail, r);
  const hasTEdge = (detail) => hasEdge(detail, t);
  const hasBEdge = (detail) => hasEdge(detail, b);
  const currentValue = (detail) => detail.model.value.get();
  const xyValue = (x, y) => ({
    x,
    y
  });
  const fireSliderChange$3 = (component, value2) => {
    emitWith(component, sliderChangeEvent(), { value: value2 });
  };
  const setToTLEdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(min1X(detail), min1Y(detail)));
  };
  const setToTEdge = (edge2, detail) => {
    fireSliderChange$3(edge2, min1Y(detail));
  };
  const setToTEdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(halfX(detail), min1Y(detail)));
  };
  const setToTREdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(max1X(detail), min1Y(detail)));
  };
  const setToREdge = (edge2, detail) => {
    fireSliderChange$3(edge2, max1X(detail));
  };
  const setToREdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(max1X(detail), halfY(detail)));
  };
  const setToBREdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(max1X(detail), max1Y(detail)));
  };
  const setToBEdge = (edge2, detail) => {
    fireSliderChange$3(edge2, max1Y(detail));
  };
  const setToBEdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(halfX(detail), max1Y(detail)));
  };
  const setToBLEdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(min1X(detail), max1Y(detail)));
  };
  const setToLEdge = (edge2, detail) => {
    fireSliderChange$3(edge2, min1X(detail));
  };
  const setToLEdgeXY = (edge2, detail) => {
    fireSliderChange$3(edge2, xyValue(min1X(detail), halfY(detail)));
  };
  const reduceBy = (value2, min2, max2, step2) => {
    if (value2 < min2) {
      return value2;
    } else if (value2 > max2) {
      return max2;
    } else if (value2 === min2) {
      return min2 - 1;
    } else {
      return Math.max(min2, value2 - step2);
    }
  };
  const increaseBy = (value2, min2, max2, step2) => {
    if (value2 > max2) {
      return value2;
    } else if (value2 < min2) {
      return min2;
    } else if (value2 === max2) {
      return max2 + 1;
    } else {
      return Math.min(max2, value2 + step2);
    }
  };
  const capValue = (value2, min2, max2) => Math.max(min2, Math.min(max2, value2));
  const snapValueOf = (value2, min2, max2, step2, snapStart2) => snapStart2.fold(() => {
    const initValue = value2 - min2;
    const extraValue = Math.round(initValue / step2) * step2;
    return capValue(min2 + extraValue, min2 - 1, max2 + 1);
  }, (start) => {
    const remainder = (value2 - start) % step2;
    const adjustment = Math.round(remainder / step2);
    const rawSteps = Math.floor((value2 - start) / step2);
    const maxSteps = Math.floor((max2 - start) / step2);
    const numSteps = Math.min(maxSteps, rawSteps + adjustment);
    const r2 = start + numSteps * step2;
    return Math.max(start, r2);
  });
  const findOffsetOf = (value2, min2, max2) => Math.min(max2, Math.max(value2, min2)) - min2;
  const findValueOf = (args) => {
    const { min: min2, max: max2, range: range2, value: value2, step: step2, snap: snap2, snapStart: snapStart2, rounded: rounded2, hasMinEdge, hasMaxEdge, minBound, maxBound, screenRange } = args;
    const capMin = hasMinEdge ? min2 - 1 : min2;
    const capMax = hasMaxEdge ? max2 + 1 : max2;
    if (value2 < minBound) {
      return capMin;
    } else if (value2 > maxBound) {
      return capMax;
    } else {
      const offset2 = findOffsetOf(value2, minBound, maxBound);
      const newValue = capValue(offset2 / screenRange * range2 + min2, capMin, capMax);
      if (snap2 && newValue >= min2 && newValue <= max2) {
        return snapValueOf(newValue, min2, max2, step2, snapStart2);
      } else if (rounded2) {
        return Math.round(newValue);
      } else {
        return newValue;
      }
    }
  };
  const findOffsetOfValue$2 = (args) => {
    const { min: min2, max: max2, range: range2, value: value2, hasMinEdge, hasMaxEdge, maxBound, maxOffset, centerMinEdge, centerMaxEdge } = args;
    if (value2 < min2) {
      return hasMinEdge ? 0 : centerMinEdge;
    } else if (value2 > max2) {
      return hasMaxEdge ? maxBound : centerMaxEdge;
    } else {
      return (value2 - min2) / range2 * maxOffset;
    }
  };
  const top = "top", right = "right", bottom = "bottom", left = "left", width = "width", height = "height";
  const getBounds = (component) => component.element.dom.getBoundingClientRect();
  const getBoundsProperty = (bounds2, property) => bounds2[property];
  const getMinXBounds = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, left);
  };
  const getMaxXBounds = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, right);
  };
  const getMinYBounds = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, top);
  };
  const getMaxYBounds = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, bottom);
  };
  const getXScreenRange = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, width);
  };
  const getYScreenRange = (component) => {
    const bounds2 = getBounds(component);
    return getBoundsProperty(bounds2, height);
  };
  const getCenterOffsetOf = (componentMinEdge, componentMaxEdge, spectrumMinEdge) => (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge;
  const getXCenterOffSetOf = (component, spectrum) => {
    const componentBounds = getBounds(component);
    const spectrumBounds = getBounds(spectrum);
    const componentMinEdge = getBoundsProperty(componentBounds, left);
    const componentMaxEdge = getBoundsProperty(componentBounds, right);
    const spectrumMinEdge = getBoundsProperty(spectrumBounds, left);
    return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  };
  const getYCenterOffSetOf = (component, spectrum) => {
    const componentBounds = getBounds(component);
    const spectrumBounds = getBounds(spectrum);
    const componentMinEdge = getBoundsProperty(componentBounds, top);
    const componentMaxEdge = getBoundsProperty(componentBounds, bottom);
    const spectrumMinEdge = getBoundsProperty(spectrumBounds, top);
    return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  };
  const fireSliderChange$2 = (spectrum, value2) => {
    emitWith(spectrum, sliderChangeEvent(), { value: value2 });
  };
  const findValueOfOffset$1 = (spectrum, detail, left2) => {
    const args = {
      min: minX(detail),
      max: maxX(detail),
      range: xRange(detail),
      value: left2,
      step: step(detail),
      snap: snap(detail),
      snapStart: snapStart(detail),
      rounded: rounded(detail),
      hasMinEdge: hasLEdge(detail),
      hasMaxEdge: hasREdge(detail),
      minBound: getMinXBounds(spectrum),
      maxBound: getMaxXBounds(spectrum),
      screenRange: getXScreenRange(spectrum)
    };
    return findValueOf(args);
  };
  const setValueFrom$2 = (spectrum, detail, value2) => {
    const xValue = findValueOfOffset$1(spectrum, detail, value2);
    const sliderVal = xValue;
    fireSliderChange$2(spectrum, sliderVal);
    return xValue;
  };
  const setToMin$2 = (spectrum, detail) => {
    const min2 = minX(detail);
    fireSliderChange$2(spectrum, min2);
  };
  const setToMax$2 = (spectrum, detail) => {
    const max2 = maxX(detail);
    fireSliderChange$2(spectrum, max2);
  };
  const moveBy$2 = (direction, spectrum, detail) => {
    const f = direction > 0 ? increaseBy : reduceBy;
    const xValue = f(currentValue(detail), minX(detail), maxX(detail), step(detail));
    fireSliderChange$2(spectrum, xValue);
    return Optional.some(xValue);
  };
  const handleMovement$2 = (direction) => (spectrum, detail) => moveBy$2(direction, spectrum, detail).map(always);
  const getValueFromEvent$2 = (simulatedEvent) => {
    const pos = getEventSource(simulatedEvent);
    return pos.map((p) => p.left);
  };
  const findOffsetOfValue$1 = (spectrum, detail, value2, minEdge, maxEdge) => {
    const minOffset = 0;
    const maxOffset = getXScreenRange(spectrum);
    const centerMinEdge = minEdge.bind((edge2) => Optional.some(getXCenterOffSetOf(edge2, spectrum))).getOr(minOffset);
    const centerMaxEdge = maxEdge.bind((edge2) => Optional.some(getXCenterOffSetOf(edge2, spectrum))).getOr(maxOffset);
    const args = {
      min: minX(detail),
      max: maxX(detail),
      range: xRange(detail),
      value: value2,
      hasMinEdge: hasLEdge(detail),
      hasMaxEdge: hasREdge(detail),
      minBound: getMinXBounds(spectrum),
      minOffset,
      maxBound: getMaxXBounds(spectrum),
      maxOffset,
      centerMinEdge,
      centerMaxEdge
    };
    return findOffsetOfValue$2(args);
  };
  const findPositionOfValue$1 = (slider, spectrum, value2, minEdge, maxEdge, detail) => {
    const offset2 = findOffsetOfValue$1(spectrum, detail, value2, minEdge, maxEdge);
    return getMinXBounds(spectrum) - getMinXBounds(slider) + offset2;
  };
  const setPositionFromValue$2 = (slider, thumb, detail, edges) => {
    const value2 = currentValue(detail);
    const pos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value2, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
    const thumbRadius = get$c(thumb.element) / 2;
    set$8(thumb.element, "left", pos - thumbRadius + "px");
  };
  const onLeft$2 = handleMovement$2(-1);
  const onRight$2 = handleMovement$2(1);
  const onUp$2 = Optional.none;
  const onDown$2 = Optional.none;
  const edgeActions$2 = {
    "top-left": Optional.none(),
    "top": Optional.none(),
    "top-right": Optional.none(),
    "right": Optional.some(setToREdge),
    "bottom-right": Optional.none(),
    "bottom": Optional.none(),
    "bottom-left": Optional.none(),
    "left": Optional.some(setToLEdge)
  };
  var HorizontalModel = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    setValueFrom: setValueFrom$2,
    setToMin: setToMin$2,
    setToMax: setToMax$2,
    findValueOfOffset: findValueOfOffset$1,
    getValueFromEvent: getValueFromEvent$2,
    findPositionOfValue: findPositionOfValue$1,
    setPositionFromValue: setPositionFromValue$2,
    onLeft: onLeft$2,
    onRight: onRight$2,
    onUp: onUp$2,
    onDown: onDown$2,
    edgeActions: edgeActions$2
  });
  const fireSliderChange$1 = (spectrum, value2) => {
    emitWith(spectrum, sliderChangeEvent(), { value: value2 });
  };
  const findValueOfOffset = (spectrum, detail, top2) => {
    const args = {
      min: minY(detail),
      max: maxY(detail),
      range: yRange(detail),
      value: top2,
      step: step(detail),
      snap: snap(detail),
      snapStart: snapStart(detail),
      rounded: rounded(detail),
      hasMinEdge: hasTEdge(detail),
      hasMaxEdge: hasBEdge(detail),
      minBound: getMinYBounds(spectrum),
      maxBound: getMaxYBounds(spectrum),
      screenRange: getYScreenRange(spectrum)
    };
    return findValueOf(args);
  };
  const setValueFrom$1 = (spectrum, detail, value2) => {
    const yValue = findValueOfOffset(spectrum, detail, value2);
    const sliderVal = yValue;
    fireSliderChange$1(spectrum, sliderVal);
    return yValue;
  };
  const setToMin$1 = (spectrum, detail) => {
    const min2 = minY(detail);
    fireSliderChange$1(spectrum, min2);
  };
  const setToMax$1 = (spectrum, detail) => {
    const max2 = maxY(detail);
    fireSliderChange$1(spectrum, max2);
  };
  const moveBy$1 = (direction, spectrum, detail) => {
    const f = direction > 0 ? increaseBy : reduceBy;
    const yValue = f(currentValue(detail), minY(detail), maxY(detail), step(detail));
    fireSliderChange$1(spectrum, yValue);
    return Optional.some(yValue);
  };
  const handleMovement$1 = (direction) => (spectrum, detail) => moveBy$1(direction, spectrum, detail).map(always);
  const getValueFromEvent$1 = (simulatedEvent) => {
    const pos = getEventSource(simulatedEvent);
    return pos.map((p) => {
      return p.top;
    });
  };
  const findOffsetOfValue = (spectrum, detail, value2, minEdge, maxEdge) => {
    const minOffset = 0;
    const maxOffset = getYScreenRange(spectrum);
    const centerMinEdge = minEdge.bind((edge2) => Optional.some(getYCenterOffSetOf(edge2, spectrum))).getOr(minOffset);
    const centerMaxEdge = maxEdge.bind((edge2) => Optional.some(getYCenterOffSetOf(edge2, spectrum))).getOr(maxOffset);
    const args = {
      min: minY(detail),
      max: maxY(detail),
      range: yRange(detail),
      value: value2,
      hasMinEdge: hasTEdge(detail),
      hasMaxEdge: hasBEdge(detail),
      minBound: getMinYBounds(spectrum),
      minOffset,
      maxBound: getMaxYBounds(spectrum),
      maxOffset,
      centerMinEdge,
      centerMaxEdge
    };
    return findOffsetOfValue$2(args);
  };
  const findPositionOfValue = (slider, spectrum, value2, minEdge, maxEdge, detail) => {
    const offset2 = findOffsetOfValue(spectrum, detail, value2, minEdge, maxEdge);
    return getMinYBounds(spectrum) - getMinYBounds(slider) + offset2;
  };
  const setPositionFromValue$1 = (slider, thumb, detail, edges) => {
    const value2 = currentValue(detail);
    const pos = findPositionOfValue(slider, edges.getSpectrum(slider), value2, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
    const thumbRadius = get$d(thumb.element) / 2;
    set$8(thumb.element, "top", pos - thumbRadius + "px");
  };
  const onLeft$1 = Optional.none;
  const onRight$1 = Optional.none;
  const onUp$1 = handleMovement$1(-1);
  const onDown$1 = handleMovement$1(1);
  const edgeActions$1 = {
    "top-left": Optional.none(),
    "top": Optional.some(setToTEdge),
    "top-right": Optional.none(),
    "right": Optional.none(),
    "bottom-right": Optional.none(),
    "bottom": Optional.some(setToBEdge),
    "bottom-left": Optional.none(),
    "left": Optional.none()
  };
  var VerticalModel = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    setValueFrom: setValueFrom$1,
    setToMin: setToMin$1,
    setToMax: setToMax$1,
    findValueOfOffset,
    getValueFromEvent: getValueFromEvent$1,
    findPositionOfValue,
    setPositionFromValue: setPositionFromValue$1,
    onLeft: onLeft$1,
    onRight: onRight$1,
    onUp: onUp$1,
    onDown: onDown$1,
    edgeActions: edgeActions$1
  });
  const fireSliderChange = (spectrum, value2) => {
    emitWith(spectrum, sliderChangeEvent(), { value: value2 });
  };
  const sliderValue = (x, y) => ({
    x,
    y
  });
  const setValueFrom = (spectrum, detail, value2) => {
    const xValue = findValueOfOffset$1(spectrum, detail, value2.left);
    const yValue = findValueOfOffset(spectrum, detail, value2.top);
    const val = sliderValue(xValue, yValue);
    fireSliderChange(spectrum, val);
    return val;
  };
  const moveBy = (direction, isVerticalMovement, spectrum, detail) => {
    const f = direction > 0 ? increaseBy : reduceBy;
    const xValue = isVerticalMovement ? currentValue(detail).x : f(currentValue(detail).x, minX(detail), maxX(detail), step(detail));
    const yValue = !isVerticalMovement ? currentValue(detail).y : f(currentValue(detail).y, minY(detail), maxY(detail), step(detail));
    fireSliderChange(spectrum, sliderValue(xValue, yValue));
    return Optional.some(xValue);
  };
  const handleMovement = (direction, isVerticalMovement) => (spectrum, detail) => moveBy(direction, isVerticalMovement, spectrum, detail).map(always);
  const setToMin = (spectrum, detail) => {
    const mX = minX(detail);
    const mY = minY(detail);
    fireSliderChange(spectrum, sliderValue(mX, mY));
  };
  const setToMax = (spectrum, detail) => {
    const mX = maxX(detail);
    const mY = maxY(detail);
    fireSliderChange(spectrum, sliderValue(mX, mY));
  };
  const getValueFromEvent = (simulatedEvent) => getEventSource(simulatedEvent);
  const setPositionFromValue = (slider, thumb, detail, edges) => {
    const value2 = currentValue(detail);
    const xPos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value2.x, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
    const yPos = findPositionOfValue(slider, edges.getSpectrum(slider), value2.y, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
    const thumbXRadius = get$c(thumb.element) / 2;
    const thumbYRadius = get$d(thumb.element) / 2;
    set$8(thumb.element, "left", xPos - thumbXRadius + "px");
    set$8(thumb.element, "top", yPos - thumbYRadius + "px");
  };
  const onLeft = handleMovement(-1, false);
  const onRight = handleMovement(1, false);
  const onUp = handleMovement(-1, true);
  const onDown = handleMovement(1, true);
  const edgeActions = {
    "top-left": Optional.some(setToTLEdgeXY),
    "top": Optional.some(setToTEdgeXY),
    "top-right": Optional.some(setToTREdgeXY),
    "right": Optional.some(setToREdgeXY),
    "bottom-right": Optional.some(setToBREdgeXY),
    "bottom": Optional.some(setToBEdgeXY),
    "bottom-left": Optional.some(setToBLEdgeXY),
    "left": Optional.some(setToLEdgeXY)
  };
  var TwoDModel = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    setValueFrom,
    setToMin,
    setToMax,
    getValueFromEvent,
    setPositionFromValue,
    onLeft,
    onRight,
    onUp,
    onDown,
    edgeActions
  });
  const SliderSchema = [
    defaulted("stepSize", 1),
    defaulted("onChange", noop),
    defaulted("onChoose", noop),
    defaulted("onInit", noop),
    defaulted("onDragStart", noop),
    defaulted("onDragEnd", noop),
    defaulted("snapToGrid", false),
    defaulted("rounded", true),
    option$3("snapStart"),
    requiredOf("model", choose$1("mode", {
      x: [
        defaulted("minX", 0),
        defaulted("maxX", 100),
        customField("value", (spec) => Cell(spec.mode.minX)),
        required$1("getInitialValue"),
        output$1("manager", HorizontalModel)
      ],
      y: [
        defaulted("minY", 0),
        defaulted("maxY", 100),
        customField("value", (spec) => Cell(spec.mode.minY)),
        required$1("getInitialValue"),
        output$1("manager", VerticalModel)
      ],
      xy: [
        defaulted("minX", 0),
        defaulted("maxX", 100),
        defaulted("minY", 0),
        defaulted("maxY", 100),
        customField("value", (spec) => Cell({
          x: spec.mode.minX,
          y: spec.mode.minY
        })),
        required$1("getInitialValue"),
        output$1("manager", TwoDModel)
      ]
    })),
    field("sliderBehaviours", [
      Keying,
      Representing
    ]),
    customField("mouseIsDown", () => Cell(false))
  ];
  const sketch$2 = (detail, components2, _spec, _externals) => {
    const getThumb = (component) => getPartOrDie(component, detail, "thumb");
    const getSpectrum = (component) => getPartOrDie(component, detail, "spectrum");
    const getLeftEdge = (component) => getPart(component, detail, "left-edge");
    const getRightEdge = (component) => getPart(component, detail, "right-edge");
    const getTopEdge = (component) => getPart(component, detail, "top-edge");
    const getBottomEdge = (component) => getPart(component, detail, "bottom-edge");
    const modelDetail = detail.model;
    const model = modelDetail.manager;
    const refresh2 = (slider, thumb) => {
      model.setPositionFromValue(slider, thumb, detail, {
        getLeftEdge,
        getRightEdge,
        getTopEdge,
        getBottomEdge,
        getSpectrum
      });
    };
    const setValue2 = (slider, newValue) => {
      modelDetail.value.set(newValue);
      const thumb = getThumb(slider);
      refresh2(slider, thumb);
    };
    const changeValue = (slider, newValue) => {
      setValue2(slider, newValue);
      const thumb = getThumb(slider);
      detail.onChange(slider, thumb, newValue);
      return Optional.some(true);
    };
    const resetToMin = (slider) => {
      model.setToMin(slider, detail);
    };
    const resetToMax = (slider) => {
      model.setToMax(slider, detail);
    };
    const choose2 = (slider) => {
      const fireOnChoose = () => {
        getPart(slider, detail, "thumb").each((thumb) => {
          const value2 = modelDetail.value.get();
          detail.onChoose(slider, thumb, value2);
        });
      };
      const wasDown = detail.mouseIsDown.get();
      detail.mouseIsDown.set(false);
      if (wasDown) {
        fireOnChoose();
      }
    };
    const onDragStart = (slider, simulatedEvent) => {
      simulatedEvent.stop();
      detail.mouseIsDown.set(true);
      detail.onDragStart(slider, getThumb(slider));
    };
    const onDragEnd = (slider, simulatedEvent) => {
      simulatedEvent.stop();
      detail.onDragEnd(slider, getThumb(slider));
      choose2(slider);
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: augment(detail.sliderBehaviours, [
        Keying.config({
          mode: "special",
          focusIn: (slider) => {
            return getPart(slider, detail, "spectrum").map(Keying.focusIn).map(always);
          }
        }),
        Representing.config({
          store: {
            mode: "manual",
            getValue: (_) => {
              return modelDetail.value.get();
            },
            setValue: setValue2
          }
        }),
        Receiving.config({ channels: { [mouseReleased()]: { onReceive: choose2 } } })
      ]),
      events: derive$2([
        run$1(sliderChangeEvent(), (slider, simulatedEvent) => {
          changeValue(slider, simulatedEvent.event.value);
        }),
        runOnAttached((slider, _simulatedEvent) => {
          const getInitial = modelDetail.getInitialValue();
          modelDetail.value.set(getInitial);
          const thumb = getThumb(slider);
          refresh2(slider, thumb);
          const spectrum = getSpectrum(slider);
          detail.onInit(slider, thumb, spectrum, modelDetail.value.get());
        }),
        run$1(touchstart(), onDragStart),
        run$1(touchend(), onDragEnd),
        run$1(mousedown(), onDragStart),
        run$1(mouseup(), onDragEnd)
      ]),
      apis: {
        resetToMin,
        resetToMax,
        setValue: setValue2,
        refresh: refresh2
      },
      domModification: { styles: { position: "relative" } }
    };
  };
  const Slider = composite({
    name: "Slider",
    configFields: SliderSchema,
    partFields: SliderParts,
    factory: sketch$2,
    apis: {
      setValue: (apis, slider, value2) => {
        apis.setValue(slider, value2);
      },
      resetToMin: (apis, slider) => {
        apis.resetToMin(slider);
      },
      resetToMax: (apis, slider) => {
        apis.resetToMax(slider);
      },
      refresh: (apis, slider) => {
        apis.refresh(slider);
      }
    }
  });
  const fieldsUpdate = generate$6("rgb-hex-update");
  const sliderUpdate = generate$6("slider-update");
  const paletteUpdate = generate$6("palette-update");
  const sliderFactory = (translate2, getClass) => {
    const spectrum = Slider.parts.spectrum({
      dom: {
        tag: "div",
        classes: [getClass("hue-slider-spectrum")],
        attributes: { role: "presentation" }
      }
    });
    const thumb = Slider.parts.thumb({
      dom: {
        tag: "div",
        classes: [getClass("hue-slider-thumb")],
        attributes: { role: "presentation" }
      }
    });
    return Slider.sketch({
      dom: {
        tag: "div",
        classes: [getClass("hue-slider")],
        attributes: { role: "presentation" }
      },
      rounded: false,
      model: {
        mode: "y",
        getInitialValue: constant$1(0)
      },
      components: [
        spectrum,
        thumb
      ],
      sliderBehaviours: derive$1([Focusing.config({})]),
      onChange: (slider, _thumb, value2) => {
        emitWith(slider, sliderUpdate, { value: value2 });
      }
    });
  };
  const owner$1 = "form";
  const schema$i = [field("formBehaviours", [Representing])];
  const getPartName$1 = (name2) => "<alloy.field." + name2 + ">";
  const sketch$1 = (fSpec) => {
    const parts2 = (() => {
      const record2 = [];
      const field2 = (name2, config2) => {
        record2.push(name2);
        return generateOne$1(owner$1, getPartName$1(name2), config2);
      };
      return {
        field: field2,
        record: constant$1(record2)
      };
    })();
    const spec = fSpec(parts2);
    const partNames = parts2.record();
    const fieldParts = map$2(partNames, (n) => required({
      name: n,
      pname: getPartName$1(n)
    }));
    return composite$1(owner$1, schema$i, fieldParts, make$4, spec);
  };
  const toResult = (o, e) => o.fold(() => Result.error(e), Result.value);
  const make$4 = (detail, components2) => ({
    uid: detail.uid,
    dom: detail.dom,
    components: components2,
    behaviours: augment(detail.formBehaviours, [Representing.config({
      store: {
        mode: "manual",
        getValue: (form) => {
          const resPs = getAllParts(form, detail);
          return map$1(resPs, (resPThunk, pName) => resPThunk().bind((v) => {
            const opt = Composing.getCurrent(v);
            return toResult(opt, new Error(`Cannot find a current component to extract the value from for form part '${pName}': ` + element(v.element)));
          }).map(Representing.getValue));
        },
        setValue: (form, values2) => {
          each(values2, (newValue, key) => {
            getPart(form, detail, key).each((wrapper) => {
              Composing.getCurrent(wrapper).each((field2) => {
                Representing.setValue(field2, newValue);
              });
            });
          });
        }
      }
    })]),
    apis: {
      getField: (form, key) => {
        return getPart(form, detail, key).bind(Composing.getCurrent);
      }
    }
  });
  const Form = {
    getField: makeApi((apis, component, key) => apis.getField(component, key)),
    sketch: sketch$1
  };
  const validInput = generate$6("valid-input");
  const invalidInput = generate$6("invalid-input");
  const validatingInput = generate$6("validating-input");
  const translatePrefix = "colorcustom.rgb.";
  const rgbFormFactory = (translate2, getClass, onValidHexx, onInvalidHexx) => {
    const invalidation = (label2, isValid) => Invalidating.config({
      invalidClass: getClass("invalid"),
      notify: {
        onValidate: (comp) => {
          emitWith(comp, validatingInput, { type: label2 });
        },
        onValid: (comp) => {
          emitWith(comp, validInput, {
            type: label2,
            value: Representing.getValue(comp)
          });
        },
        onInvalid: (comp) => {
          emitWith(comp, invalidInput, {
            type: label2,
            value: Representing.getValue(comp)
          });
        }
      },
      validator: {
        validate: (comp) => {
          const value2 = Representing.getValue(comp);
          const res = isValid(value2) ? Result.value(true) : Result.error(translate2("aria.input.invalid"));
          return Future.pure(res);
        },
        validateOnLoad: false
      }
    });
    const renderTextField2 = (isValid, name2, label2, description, data) => {
      const helptext = translate2(translatePrefix + "range");
      const pLabel = FormField.parts.label({
        dom: {
          tag: "label",
          attributes: { "aria-label": description }
        },
        components: [text$1(label2)]
      });
      const pField = FormField.parts.field({
        data,
        factory: Input,
        inputAttributes: {
          type: "text",
          ...name2 === "hex" ? { "aria-live": "polite" } : {}
        },
        inputClasses: [getClass("textfield")],
        inputBehaviours: derive$1([
          invalidation(name2, isValid),
          Tabstopping.config({})
        ]),
        onSetValue: (input2) => {
          if (Invalidating.isInvalid(input2)) {
            const run2 = Invalidating.run(input2);
            run2.get(noop);
          }
        }
      });
      const comps = [
        pLabel,
        pField
      ];
      const concats = name2 !== "hex" ? [FormField.parts["aria-descriptor"]({ text: helptext })] : [];
      const components2 = comps.concat(concats);
      return {
        dom: {
          tag: "div",
          attributes: { role: "presentation" }
        },
        components: components2
      };
    };
    const copyRgbToHex = (form, rgba) => {
      const hex = fromRgba(rgba);
      Form.getField(form, "hex").each((hexField) => {
        if (!Focusing.isFocused(hexField)) {
          Representing.setValue(form, { hex: hex.value });
        }
      });
      return hex;
    };
    const copyRgbToForm = (form, rgb) => {
      const red2 = rgb.red;
      const green = rgb.green;
      const blue = rgb.blue;
      Representing.setValue(form, {
        red: red2,
        green,
        blue
      });
    };
    const memPreview = record({
      dom: {
        tag: "div",
        classes: [getClass("rgba-preview")],
        styles: { "background-color": "white" },
        attributes: { role: "presentation" }
      }
    });
    const updatePreview = (anyInSystem, hex) => {
      memPreview.getOpt(anyInSystem).each((preview) => {
        set$8(preview.element, "background-color", "#" + hex.value);
      });
    };
    const factory2 = () => {
      const state = {
        red: Cell(Optional.some(255)),
        green: Cell(Optional.some(255)),
        blue: Cell(Optional.some(255)),
        hex: Cell(Optional.some("ffffff"))
      };
      const copyHexToRgb = (form, hex) => {
        const rgb = fromHex(hex);
        copyRgbToForm(form, rgb);
        setValueRgb(rgb);
      };
      const get2 = (prop) => state[prop].get();
      const set2 = (prop, value2) => {
        state[prop].set(value2);
      };
      const getValueRgb = () => get2("red").bind((red2) => get2("green").bind((green) => get2("blue").map((blue) => rgbaColour(red2, green, blue, 1))));
      const setValueRgb = (rgb) => {
        const red2 = rgb.red;
        const green = rgb.green;
        const blue = rgb.blue;
        set2("red", Optional.some(red2));
        set2("green", Optional.some(green));
        set2("blue", Optional.some(blue));
      };
      const onInvalidInput = (form, simulatedEvent) => {
        const data = simulatedEvent.event;
        if (data.type !== "hex") {
          set2(data.type, Optional.none());
        } else {
          onInvalidHexx(form);
        }
      };
      const onValidHex = (form, value2) => {
        onValidHexx(form);
        const hex = hexColour(value2);
        set2("hex", Optional.some(value2));
        const rgb = fromHex(hex);
        copyRgbToForm(form, rgb);
        setValueRgb(rgb);
        emitWith(form, fieldsUpdate, { hex });
        updatePreview(form, hex);
      };
      const onValidRgb = (form, prop, value2) => {
        const val = parseInt(value2, 10);
        set2(prop, Optional.some(val));
        getValueRgb().each((rgb) => {
          const hex = copyRgbToHex(form, rgb);
          emitWith(form, fieldsUpdate, { hex });
          updatePreview(form, hex);
        });
      };
      const isHexInputEvent = (data) => data.type === "hex";
      const onValidInput = (form, simulatedEvent) => {
        const data = simulatedEvent.event;
        if (isHexInputEvent(data)) {
          onValidHex(form, data.value);
        } else {
          onValidRgb(form, data.type, data.value);
        }
      };
      const formPartStrings = (key) => ({
        label: translate2(translatePrefix + key + ".label"),
        description: translate2(translatePrefix + key + ".description")
      });
      const redStrings = formPartStrings("red");
      const greenStrings = formPartStrings("green");
      const blueStrings = formPartStrings("blue");
      const hexStrings = formPartStrings("hex");
      return deepMerge(Form.sketch((parts2) => ({
        dom: {
          tag: "form",
          classes: [getClass("rgb-form")],
          attributes: { "aria-label": translate2("aria.color.picker") }
        },
        components: [
          parts2.field("red", FormField.sketch(renderTextField2(isRgbaComponent, "red", redStrings.label, redStrings.description, 255))),
          parts2.field("green", FormField.sketch(renderTextField2(isRgbaComponent, "green", greenStrings.label, greenStrings.description, 255))),
          parts2.field("blue", FormField.sketch(renderTextField2(isRgbaComponent, "blue", blueStrings.label, blueStrings.description, 255))),
          parts2.field("hex", FormField.sketch(renderTextField2(isHexString, "hex", hexStrings.label, hexStrings.description, "ffffff"))),
          memPreview.asSpec()
        ],
        formBehaviours: derive$1([
          Invalidating.config({ invalidClass: getClass("form-invalid") }),
          config("rgb-form-events", [
            run$1(validInput, onValidInput),
            run$1(invalidInput, onInvalidInput),
            run$1(validatingInput, onInvalidInput)
          ])
        ])
      })), {
        apis: {
          updateHex: (form, hex) => {
            Representing.setValue(form, { hex: hex.value });
            copyHexToRgb(form, hex);
            updatePreview(form, hex);
          }
        }
      });
    };
    const rgbFormSketcher = single({
      factory: factory2,
      name: "RgbForm",
      configFields: [],
      apis: {
        updateHex: (apis, form, hex) => {
          apis.updateHex(form, hex);
        }
      },
      extraApis: {}
    });
    return rgbFormSketcher;
  };
  const paletteFactory = (_translate, getClass) => {
    const spectrumPart2 = Slider.parts.spectrum({
      dom: {
        tag: "canvas",
        attributes: { role: "presentation" },
        classes: [getClass("sv-palette-spectrum")]
      }
    });
    const thumbPart2 = Slider.parts.thumb({
      dom: {
        tag: "div",
        attributes: { role: "presentation" },
        classes: [getClass("sv-palette-thumb")],
        innerHtml: `<div class=${getClass("sv-palette-inner-thumb")} role="presentation"></div>`
      }
    });
    const setColour = (canvas, rgba) => {
      const { width: width2, height: height2 } = canvas;
      const ctx = canvas.getContext("2d");
      if (ctx === null) {
        return;
      }
      ctx.fillStyle = rgba;
      ctx.fillRect(0, 0, width2, height2);
      const grdWhite = ctx.createLinearGradient(0, 0, width2, 0);
      grdWhite.addColorStop(0, "rgba(255,255,255,1)");
      grdWhite.addColorStop(1, "rgba(255,255,255,0)");
      ctx.fillStyle = grdWhite;
      ctx.fillRect(0, 0, width2, height2);
      const grdBlack = ctx.createLinearGradient(0, 0, 0, height2);
      grdBlack.addColorStop(0, "rgba(0,0,0,0)");
      grdBlack.addColorStop(1, "rgba(0,0,0,1)");
      ctx.fillStyle = grdBlack;
      ctx.fillRect(0, 0, width2, height2);
    };
    const setPaletteHue = (slider, hue) => {
      const canvas = slider.components()[0].element.dom;
      const hsv = hsvColour(hue, 100, 100);
      const rgba = fromHsv(hsv);
      setColour(canvas, toString(rgba));
    };
    const setPaletteThumb = (slider, hex) => {
      const hsv = fromRgb(fromHex(hex));
      Slider.setValue(slider, {
        x: hsv.saturation,
        y: 100 - hsv.value
      });
    };
    const factory2 = (_detail) => {
      const getInitialValue = constant$1({
        x: 0,
        y: 0
      });
      const onChange = (slider, _thumb, value2) => {
        emitWith(slider, paletteUpdate, { value: value2 });
      };
      const onInit = (_slider, _thumb, spectrum, _value) => {
        setColour(spectrum.element.dom, toString(red));
      };
      const sliderBehaviours = derive$1([
        Composing.config({ find: Optional.some }),
        Focusing.config({})
      ]);
      return Slider.sketch({
        dom: {
          tag: "div",
          attributes: { role: "presentation" },
          classes: [getClass("sv-palette")]
        },
        model: {
          mode: "xy",
          getInitialValue
        },
        rounded: false,
        components: [
          spectrumPart2,
          thumbPart2
        ],
        onChange,
        onInit,
        sliderBehaviours
      });
    };
    const saturationBrightnessPaletteSketcher = single({
      factory: factory2,
      name: "SaturationBrightnessPalette",
      configFields: [],
      apis: {
        setHue: (_apis, slider, hue) => {
          setPaletteHue(slider, hue);
        },
        setThumb: (_apis, slider, hex) => {
          setPaletteThumb(slider, hex);
        }
      },
      extraApis: {}
    });
    return saturationBrightnessPaletteSketcher;
  };
  const makeFactory = (translate2, getClass) => {
    const factory2 = (detail) => {
      const rgbForm = rgbFormFactory(translate2, getClass, detail.onValidHex, detail.onInvalidHex);
      const sbPalette = paletteFactory(translate2, getClass);
      const hueSliderToDegrees = (hue) => (100 - hue) / 100 * 360;
      const hueDegreesToSlider = (hue) => 100 - hue / 360 * 100;
      const state = {
        paletteRgba: Cell(red),
        paletteHue: Cell(0)
      };
      const memSlider = record(sliderFactory(translate2, getClass));
      const memPalette = record(sbPalette.sketch({}));
      const memRgb = record(rgbForm.sketch({}));
      const updatePalette = (anyInSystem, _hex, hue) => {
        memPalette.getOpt(anyInSystem).each((palette) => {
          sbPalette.setHue(palette, hue);
        });
      };
      const updateFields = (anyInSystem, hex) => {
        memRgb.getOpt(anyInSystem).each((form) => {
          rgbForm.updateHex(form, hex);
        });
      };
      const updateSlider = (anyInSystem, _hex, hue) => {
        memSlider.getOpt(anyInSystem).each((slider) => {
          Slider.setValue(slider, hueDegreesToSlider(hue));
        });
      };
      const updatePaletteThumb = (anyInSystem, hex) => {
        memPalette.getOpt(anyInSystem).each((palette) => {
          sbPalette.setThumb(palette, hex);
        });
      };
      const updateState = (hex, hue) => {
        const rgba = fromHex(hex);
        state.paletteRgba.set(rgba);
        state.paletteHue.set(hue);
      };
      const runUpdates = (anyInSystem, hex, hue, updates) => {
        updateState(hex, hue);
        each$1(updates, (update) => {
          update(anyInSystem, hex, hue);
        });
      };
      const onPaletteUpdate = () => {
        const updates = [updateFields];
        return (form, simulatedEvent) => {
          const value2 = simulatedEvent.event.value;
          const oldHue = state.paletteHue.get();
          const newHsv = hsvColour(oldHue, value2.x, 100 - value2.y);
          const newHex = hsvToHex(newHsv);
          runUpdates(form, newHex, oldHue, updates);
        };
      };
      const onSliderUpdate = () => {
        const updates = [
          updatePalette,
          updateFields
        ];
        return (form, simulatedEvent) => {
          const hue = hueSliderToDegrees(simulatedEvent.event.value);
          const oldRgb = state.paletteRgba.get();
          const oldHsv = fromRgb(oldRgb);
          const newHsv = hsvColour(hue, oldHsv.saturation, oldHsv.value);
          const newHex = hsvToHex(newHsv);
          runUpdates(form, newHex, hue, updates);
        };
      };
      const onFieldsUpdate = () => {
        const updates = [
          updatePalette,
          updateSlider,
          updatePaletteThumb
        ];
        return (form, simulatedEvent) => {
          const hex = simulatedEvent.event.hex;
          const hsv = hexToHsv(hex);
          runUpdates(form, hex, hsv.hue, updates);
        };
      };
      return {
        uid: detail.uid,
        dom: detail.dom,
        components: [
          memPalette.asSpec(),
          memSlider.asSpec(),
          memRgb.asSpec()
        ],
        behaviours: derive$1([
          config("colour-picker-events", [
            run$1(fieldsUpdate, onFieldsUpdate()),
            run$1(paletteUpdate, onPaletteUpdate()),
            run$1(sliderUpdate, onSliderUpdate())
          ]),
          Composing.config({ find: (comp) => memRgb.getOpt(comp) }),
          Keying.config({ mode: "acyclic" })
        ])
      };
    };
    const colourPickerSketcher = single({
      name: "ColourPicker",
      configFields: [
        required$1("dom"),
        defaulted("onValidHex", noop),
        defaulted("onInvalidHex", noop)
      ],
      factory: factory2
    });
    return colourPickerSketcher;
  };
  const self = () => Composing.config({ find: Optional.some });
  const memento$1 = (mem) => Composing.config({ find: mem.getOpt });
  const childAt = (index2) => Composing.config({ find: (comp) => child$2(comp.element, index2).bind((element2) => comp.getSystem().getByDom(element2).toOptional()) });
  const ComposingConfigs = {
    self,
    memento: memento$1,
    childAt
  };
  const processors = objOf([
    defaulted("preprocess", identity),
    defaulted("postprocess", identity)
  ]);
  const memento = (mem, rawProcessors) => {
    const ps = asRawOrDie$1("RepresentingConfigs.memento processors", processors, rawProcessors);
    return Representing.config({
      store: {
        mode: "manual",
        getValue: (comp) => {
          const other = mem.get(comp);
          const rawValue = Representing.getValue(other);
          return ps.postprocess(rawValue);
        },
        setValue: (comp, rawValue) => {
          const newValue = ps.preprocess(rawValue);
          const other = mem.get(comp);
          Representing.setValue(other, newValue);
        }
      }
    });
  };
  const withComp = (optInitialValue, getter, setter) => Representing.config({
    store: {
      mode: "manual",
      ...optInitialValue.map((initialValue) => ({ initialValue })).getOr({}),
      getValue: getter,
      setValue: setter
    }
  });
  const withElement = (initialValue, getter, setter) => withComp(initialValue, (c) => getter(c.element), (c, v) => setter(c.element, v));
  const domValue = (optInitialValue) => withElement(optInitialValue, get$6, set$5);
  const domHtml = (optInitialValue) => withElement(optInitialValue, get$9, set$6);
  const memory = (initialValue) => Representing.config({
    store: {
      mode: "memory",
      initialValue
    }
  });
  const RepresentingConfigs = {
    memento,
    withElement,
    withComp,
    domValue,
    domHtml,
    memory
  };
  const english = {
    "colorcustom.rgb.red.label": "R",
    "colorcustom.rgb.red.description": "Red component",
    "colorcustom.rgb.green.label": "G",
    "colorcustom.rgb.green.description": "Green component",
    "colorcustom.rgb.blue.label": "B",
    "colorcustom.rgb.blue.description": "Blue component",
    "colorcustom.rgb.hex.label": "#",
    "colorcustom.rgb.hex.description": "Hex color code",
    "colorcustom.rgb.range": "Range 0 to 255",
    "aria.color.picker": "Color Picker",
    "aria.input.invalid": "Invalid input"
  };
  const translate$1 = (providerBackstage) => (key) => {
    return providerBackstage.translate(english[key]);
  };
  const renderColorPicker = (_spec, providerBackstage, initialData) => {
    const getClass = (key) => "tox-" + key;
    const colourPickerFactory = makeFactory(translate$1(providerBackstage), getClass);
    const onValidHex = (form) => {
      emitWith(form, formActionEvent, {
        name: "hex-valid",
        value: true
      });
    };
    const onInvalidHex = (form) => {
      emitWith(form, formActionEvent, {
        name: "hex-valid",
        value: false
      });
    };
    const memPicker = record(colourPickerFactory.sketch({
      dom: {
        tag: "div",
        classes: [getClass("color-picker-container")],
        attributes: { role: "presentation" }
      },
      onValidHex,
      onInvalidHex
    }));
    return {
      dom: { tag: "div" },
      components: [memPicker.asSpec()],
      behaviours: derive$1([
        RepresentingConfigs.withComp(initialData, (comp) => {
          const picker = memPicker.get(comp);
          const optRgbForm = Composing.getCurrent(picker);
          const optHex = optRgbForm.bind((rgbForm) => {
            const formValues = Representing.getValue(rgbForm);
            return formValues.hex;
          });
          return optHex.map((hex) => "#" + hex).getOr("");
        }, (comp, newValue) => {
          const pattern2 = /^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/;
          const m = pattern2.exec(newValue);
          const picker = memPicker.get(comp);
          const optRgbForm = Composing.getCurrent(picker);
          optRgbForm.fold(() => {
            console.log("Can not find form");
          }, (rgbForm) => {
            Representing.setValue(rgbForm, { hex: Optional.from(m[1]).getOr("") });
            Form.getField(rgbForm, "hex").each((hexField) => {
              emit(hexField, input());
            });
          });
        }),
        ComposingConfigs.self()
      ])
    };
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.Resource");
  const isOldCustomEditor = (spec) => has$2(spec, "init");
  const renderCustomEditor = (spec) => {
    const editorApi = value$2();
    const memReplaced = record({ dom: { tag: spec.tag } });
    const initialValue = value$2();
    return {
      dom: {
        tag: "div",
        classes: ["tox-custom-editor"]
      },
      behaviours: derive$1([
        config("custom-editor-events", [runOnAttached((component) => {
          memReplaced.getOpt(component).each((ta) => {
            (isOldCustomEditor(spec) ? spec.init(ta.element.dom) : global$2.load(spec.scriptId, spec.scriptUrl).then((init2) => init2(ta.element.dom, spec.settings))).then((ea) => {
              initialValue.on((cvalue) => {
                ea.setValue(cvalue);
              });
              initialValue.clear();
              editorApi.set(ea);
            });
          });
        })]),
        RepresentingConfigs.withComp(Optional.none(), () => editorApi.get().fold(() => initialValue.get().getOr(""), (ed) => ed.getValue()), (component, value2) => {
          editorApi.get().fold(() => initialValue.set(value2), (ed) => ed.setValue(value2));
        }),
        ComposingConfigs.self()
      ]),
      components: [memReplaced.asSpec()]
    };
  };
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const filterByExtension = (files, providersBackstage) => {
    const allowedImageFileTypes = global$1.explode(providersBackstage.getOption("images_file_types"));
    const isFileInAllowedTypes = (file) => exists(allowedImageFileTypes, (type2) => endsWith(file.name.toLowerCase(), `.${type2.toLowerCase()}`));
    return filter$2(from(files), isFileInAllowedTypes);
  };
  const renderDropZone = (spec, providersBackstage, initialData) => {
    const stopper2 = (_, se) => {
      se.stop();
    };
    const sequence2 = (actions) => (comp, se) => {
      each$1(actions, (a) => {
        a(comp, se);
      });
    };
    const onDrop = (comp, se) => {
      if (!Disabling.isDisabled(comp)) {
        const transferEvent = se.event.raw;
        handleFiles(comp, transferEvent.dataTransfer.files);
      }
    };
    const onSelect = (component, simulatedEvent) => {
      const input2 = simulatedEvent.event.raw.target;
      handleFiles(component, input2.files);
    };
    const handleFiles = (component, files) => {
      Representing.setValue(component, filterByExtension(files, providersBackstage));
      emitWith(component, formChangeEvent, { name: spec.name });
    };
    const memInput = record({
      dom: {
        tag: "input",
        attributes: {
          type: "file",
          accept: "image/*"
        },
        styles: { display: "none" }
      },
      behaviours: derive$1([config("input-file-events", [
        cutter(click()),
        cutter(tap())
      ])])
    });
    const renderField = (s) => ({
      uid: s.uid,
      dom: {
        tag: "div",
        classes: ["tox-dropzone-container"]
      },
      behaviours: derive$1([
        RepresentingConfigs.memory(initialData.getOr([])),
        ComposingConfigs.self(),
        Disabling.config({}),
        Toggling.config({
          toggleClass: "dragenter",
          toggleOnExecute: false
        }),
        config("dropzone-events", [
          run$1("dragenter", sequence2([
            stopper2,
            Toggling.toggle
          ])),
          run$1("dragleave", sequence2([
            stopper2,
            Toggling.toggle
          ])),
          run$1("dragover", stopper2),
          run$1("drop", sequence2([
            stopper2,
            onDrop
          ])),
          run$1(change(), onSelect)
        ])
      ]),
      components: [{
        dom: {
          tag: "div",
          classes: ["tox-dropzone"],
          styles: {}
        },
        components: [
          {
            dom: { tag: "p" },
            components: [text$1(providersBackstage.translate("Drop an image here"))]
          },
          Button.sketch({
            dom: {
              tag: "button",
              styles: { position: "relative" },
              classes: [
                "tox-button",
                "tox-button--secondary"
              ]
            },
            components: [
              text$1(providersBackstage.translate("Browse for an image")),
              memInput.asSpec()
            ],
            action: (comp) => {
              const inputComp = memInput.get(comp);
              inputComp.element.dom.click();
            },
            buttonBehaviours: derive$1([
              Tabstopping.config({}),
              DisablingConfigs.button(providersBackstage.isDisabled),
              receivingConfig()
            ])
          })
        ]
      }]
    });
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const pField = FormField.parts.field({ factory: { sketch: renderField } });
    return renderFormFieldWith(pLabel, pField, ["tox-form__group--stretched"], []);
  };
  const renderGrid = (spec, backstage) => ({
    dom: {
      tag: "div",
      classes: [
        "tox-form__grid",
        `tox-form__grid--${spec.columns}col`
      ]
    },
    components: map$2(spec.items, backstage.interpreter)
  });
  const beforeObject = generate$6("alloy-fake-before-tabstop");
  const afterObject = generate$6("alloy-fake-after-tabstop");
  const craftWithClasses = (classes2) => {
    return {
      dom: {
        tag: "div",
        styles: {
          width: "1px",
          height: "1px",
          outline: "none"
        },
        attributes: { tabindex: "0" },
        classes: classes2
      },
      behaviours: derive$1([
        Focusing.config({ ignore: true }),
        Tabstopping.config({})
      ])
    };
  };
  const craft = (spec) => {
    return {
      dom: {
        tag: "div",
        classes: ["tox-navobj"]
      },
      components: [
        craftWithClasses([beforeObject]),
        spec,
        craftWithClasses([afterObject])
      ],
      behaviours: derive$1([ComposingConfigs.childAt(1)])
    };
  };
  const triggerTab = (placeholder2, shiftKey) => {
    emitWith(placeholder2, keydown(), {
      raw: {
        which: 9,
        shiftKey
      }
    });
  };
  const onFocus = (container, targetComp) => {
    const target = targetComp.element;
    if (has(target, beforeObject)) {
      triggerTab(container, true);
    } else if (has(target, afterObject)) {
      triggerTab(container, false);
    }
  };
  const isPseudoStop = (element2) => {
    return closest(element2, [
      "." + beforeObject,
      "." + afterObject
    ].join(","), never);
  };
  const getDynamicSource = (initialData) => {
    const cachedValue = Cell(initialData.getOr(""));
    return {
      getValue: (_frameComponent) => cachedValue.get(),
      setValue: (frameComponent, html) => {
        if (cachedValue.get() !== html) {
          set$9(frameComponent.element, "srcdoc", html);
        }
        cachedValue.set(html);
      }
    };
  };
  const renderIFrame = (spec, providersBackstage, initialData) => {
    const isSandbox = spec.sandboxed;
    const isTransparent = spec.transparent;
    const baseClass = "tox-dialog__iframe";
    const attributes = {
      ...spec.label.map((title2) => ({ title: title2 })).getOr({}),
      ...initialData.map((html) => ({ srcdoc: html })).getOr({}),
      ...isSandbox ? { sandbox: "allow-scripts allow-same-origin" } : {}
    };
    const sourcing = getDynamicSource(initialData);
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const factory2 = (newSpec) => craft({
      uid: newSpec.uid,
      dom: {
        tag: "iframe",
        attributes,
        classes: isTransparent ? [baseClass] : [
          baseClass,
          `${baseClass}--opaque`
        ]
      },
      behaviours: derive$1([
        Tabstopping.config({}),
        Focusing.config({}),
        RepresentingConfigs.withComp(initialData, sourcing.getValue, sourcing.setValue)
      ])
    });
    const pField = FormField.parts.field({ factory: { sketch: factory2 } });
    return renderFormFieldWith(pLabel, pField, ["tox-form__group--stretched"], []);
  };
  const image = (image2) => new Promise((resolve, reject) => {
    const loaded = () => {
      destroy();
      resolve(image2);
    };
    const listeners = [
      bind(image2, "load", loaded),
      bind(image2, "error", () => {
        destroy();
        reject("Unable to load data from image: " + image2.dom.src);
      })
    ];
    const destroy = () => each$1(listeners, (l2) => l2.unbind());
    if (image2.dom.complete) {
      loaded();
    }
  });
  const calculateImagePosition = (panelWidth, panelHeight, imageWidth, imageHeight, zoom) => {
    const width2 = imageWidth * zoom;
    const height2 = imageHeight * zoom;
    const left2 = Math.max(0, panelWidth / 2 - width2 / 2);
    const top2 = Math.max(0, panelHeight / 2 - height2 / 2);
    return {
      left: left2.toString() + "px",
      top: top2.toString() + "px",
      width: width2.toString() + "px",
      height: height2.toString() + "px"
    };
  };
  const zoomToFit = (panel, width2, height2) => {
    const panelW = get$c(panel);
    const panelH = get$d(panel);
    return Math.min(panelW / width2, panelH / height2, 1);
  };
  const renderImagePreview = (spec, initialData) => {
    const cachedData = Cell(initialData.getOr({ url: "" }));
    const memImage = record({
      dom: {
        tag: "img",
        classes: ["tox-imagepreview__image"],
        attributes: initialData.map((data) => ({ src: data.url })).getOr({})
      }
    });
    const memContainer = record({
      dom: {
        tag: "div",
        classes: ["tox-imagepreview__container"],
        attributes: { role: "presentation" }
      },
      components: [memImage.asSpec()]
    });
    const setValue2 = (frameComponent, data) => {
      const translatedData = { url: data.url };
      data.zoom.each((z) => translatedData.zoom = z);
      data.cachedWidth.each((z) => translatedData.cachedWidth = z);
      data.cachedHeight.each((z) => translatedData.cachedHeight = z);
      cachedData.set(translatedData);
      const applyFramePositioning = () => {
        const imageWidth = translatedData.cachedWidth;
        const imageHeight = translatedData.cachedHeight;
        if (isUndefined(translatedData.zoom)) {
          const z = zoomToFit(frameComponent.element, imageWidth, imageHeight);
          translatedData.zoom = z;
        }
        const position2 = calculateImagePosition(get$c(frameComponent.element), get$d(frameComponent.element), imageWidth, imageHeight, translatedData.zoom);
        memContainer.getOpt(frameComponent).each((container) => {
          setAll(container.element, position2);
        });
      };
      memImage.getOpt(frameComponent).each((imageComponent) => {
        const img = imageComponent.element;
        if (data.url !== get$f(img, "src")) {
          set$9(img, "src", data.url);
          remove$2(frameComponent.element, "tox-imagepreview__loaded");
        }
        if (!isUndefined(translatedData.cachedWidth) && !isUndefined(translatedData.cachedHeight)) {
          applyFramePositioning();
        }
        image(img).then((img2) => {
          if (frameComponent.getSystem().isConnected()) {
            add$2(frameComponent.element, "tox-imagepreview__loaded");
            translatedData.cachedWidth = img2.dom.naturalWidth;
            translatedData.cachedHeight = img2.dom.naturalHeight;
            applyFramePositioning();
          }
        });
      });
    };
    const styles = {};
    spec.height.each((h2) => styles.height = h2);
    const fakeValidatedData = initialData.map((d) => ({
      url: d.url,
      zoom: Optional.from(d.zoom),
      cachedWidth: Optional.from(d.cachedWidth),
      cachedHeight: Optional.from(d.cachedHeight)
    }));
    return {
      dom: {
        tag: "div",
        classes: ["tox-imagepreview"],
        styles,
        attributes: { role: "presentation" }
      },
      components: [memContainer.asSpec()],
      behaviours: derive$1([
        ComposingConfigs.self(),
        RepresentingConfigs.withComp(fakeValidatedData, () => cachedData.get(), setValue2)
      ])
    };
  };
  const renderLabel$1 = (spec, backstageShared) => {
    const label2 = {
      dom: {
        tag: "label",
        classes: ["tox-label"]
      },
      components: [text$1(backstageShared.providers.translate(spec.label))]
    };
    const comps = map$2(spec.items, backstageShared.interpreter);
    return {
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: [
        label2,
        ...comps
      ],
      behaviours: derive$1([
        ComposingConfigs.self(),
        Replacing.config({}),
        RepresentingConfigs.domHtml(Optional.none()),
        Keying.config({ mode: "acyclic" })
      ])
    };
  };
  const internalToolbarButtonExecute = generate$6("toolbar.button.execute");
  const onToolbarButtonExecute = (info) => runOnExecute$1((comp, _simulatedEvent) => {
    runWithApi(info, comp)((itemApi) => {
      emitWith(comp, internalToolbarButtonExecute, { buttonApi: itemApi });
      info.onAction(itemApi);
    });
  });
  const toolbarButtonEventOrder = {
    [execute$5()]: [
      "disabling",
      "alloy.base.behaviour",
      "toggling",
      "toolbar-button-events"
    ]
  };
  const renderIcon = (iconName, iconsProvider, behaviours2) => render$3(iconName, {
    tag: "span",
    classes: [
      "tox-icon",
      "tox-tbtn__icon-wrap"
    ],
    behaviours: behaviours2
  }, iconsProvider);
  const renderIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, []);
  const renderReplacableIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, [Replacing.config({})]);
  const renderLabel = (text2, prefix2, providersBackstage) => ({
    dom: {
      tag: "span",
      classes: [`${prefix2}__select-label`]
    },
    components: [text$1(providersBackstage.translate(text2))],
    behaviours: derive$1([Replacing.config({})])
  });
  const updateMenuText = generate$6("update-menu-text");
  const updateMenuIcon = generate$6("update-menu-icon");
  const renderCommonDropdown = (spec, prefix2, sharedBackstage) => {
    const editorOffCell = Cell(noop);
    const optMemDisplayText = spec.text.map((text2) => record(renderLabel(text2, prefix2, sharedBackstage.providers)));
    const optMemDisplayIcon = spec.icon.map((iconName) => record(renderReplacableIconFromPack(iconName, sharedBackstage.providers.icons)));
    const onLeftOrRightInMenu = (comp, se) => {
      const dropdown = Representing.getValue(comp);
      Focusing.focus(dropdown);
      emitWith(dropdown, "keydown", { raw: se.event.raw });
      Dropdown.close(dropdown);
      return Optional.some(true);
    };
    const role = spec.role.fold(() => ({}), (role2) => ({ role: role2 }));
    const tooltipAttributes = spec.tooltip.fold(() => ({}), (tooltip) => {
      const translatedTooltip = sharedBackstage.providers.translate(tooltip);
      return {
        "title": translatedTooltip,
        "aria-label": translatedTooltip
      };
    });
    const iconSpec = render$3("chevron-down", {
      tag: "div",
      classes: [`${prefix2}__select-chevron`]
    }, sharedBackstage.providers.icons);
    const memDropdown = record(Dropdown.sketch({
      ...spec.uid ? { uid: spec.uid } : {},
      ...role,
      dom: {
        tag: "button",
        classes: [
          prefix2,
          `${prefix2}--select`
        ].concat(map$2(spec.classes, (c) => `${prefix2}--${c}`)),
        attributes: { ...tooltipAttributes }
      },
      components: componentRenderPipeline([
        optMemDisplayIcon.map((mem) => mem.asSpec()),
        optMemDisplayText.map((mem) => mem.asSpec()),
        Optional.some(iconSpec)
      ]),
      matchWidth: true,
      useMinWidth: true,
      dropdownBehaviours: derive$1([
        ...spec.dropdownBehaviours,
        DisablingConfigs.button(() => spec.disabled || sharedBackstage.providers.isDisabled()),
        receivingConfig(),
        Unselecting.config({}),
        Replacing.config({}),
        config("dropdown-events", [
          onControlAttached(spec, editorOffCell),
          onControlDetached(spec, editorOffCell)
        ]),
        config("menubutton-update-display-text", [
          run$1(updateMenuText, (comp, se) => {
            optMemDisplayText.bind((mem) => mem.getOpt(comp)).each((displayText) => {
              Replacing.set(displayText, [text$1(sharedBackstage.providers.translate(se.event.text))]);
            });
          }),
          run$1(updateMenuIcon, (comp, se) => {
            optMemDisplayIcon.bind((mem) => mem.getOpt(comp)).each((displayIcon) => {
              Replacing.set(displayIcon, [renderReplacableIconFromPack(se.event.icon, sharedBackstage.providers.icons)]);
            });
          })
        ])
      ]),
      eventOrder: deepMerge(toolbarButtonEventOrder, {
        mousedown: [
          "focusing",
          "alloy.base.behaviour",
          "item-type-events",
          "normal-dropdown-events"
        ]
      }),
      sandboxBehaviours: derive$1([Keying.config({
        mode: "special",
        onLeft: onLeftOrRightInMenu,
        onRight: onLeftOrRightInMenu
      })]),
      lazySink: sharedBackstage.getSink,
      toggleClass: `${prefix2}--active`,
      parts: { menu: part(false, spec.columns, spec.presets) },
      fetch: (comp) => Future.nu(curry(spec.fetch, comp))
    }));
    return memDropdown.asSpec();
  };
  const isMenuItemReference = (item2) => isString(item2);
  const isSeparator$1 = (item2) => item2.type === "separator";
  const isExpandingMenuItem = (item2) => has$2(item2, "getSubmenuItems");
  const separator$2 = { type: "separator" };
  const unwrapReferences = (items, menuItems) => {
    const realItems = foldl(items, (acc, item2) => {
      if (isMenuItemReference(item2)) {
        if (item2 === "") {
          return acc;
        } else if (item2 === "|") {
          return acc.length > 0 && !isSeparator$1(acc[acc.length - 1]) ? acc.concat([separator$2]) : acc;
        } else if (has$2(menuItems, item2.toLowerCase())) {
          return acc.concat([menuItems[item2.toLowerCase()]]);
        } else {
          return acc;
        }
      } else {
        return acc.concat([item2]);
      }
    }, []);
    if (realItems.length > 0 && isSeparator$1(realItems[realItems.length - 1])) {
      realItems.pop();
    }
    return realItems;
  };
  const getFromExpandingItem = (item2, menuItems) => {
    const submenuItems = item2.getSubmenuItems();
    const rest = expand(submenuItems, menuItems);
    const newMenus = deepMerge(rest.menus, wrap$1(item2.value, rest.items));
    const newExpansions = deepMerge(rest.expansions, wrap$1(item2.value, item2.value));
    return {
      item: item2,
      menus: newMenus,
      expansions: newExpansions
    };
  };
  const getFromItem = (item2, menuItems) => isExpandingMenuItem(item2) ? getFromExpandingItem(item2, menuItems) : {
    item: item2,
    menus: {},
    expansions: {}
  };
  const generateValueIfRequired = (item2) => {
    if (isSeparator$1(item2)) {
      return item2;
    } else {
      const itemValue = get$g(item2, "value").getOrThunk(() => generate$6("generated-menu-item"));
      return deepMerge({ value: itemValue }, item2);
    }
  };
  const expand = (items, menuItems) => {
    const realItems = unwrapReferences(isString(items) ? items.split(" ") : items, menuItems);
    return foldr(realItems, (acc, item2) => {
      const itemWithValue = generateValueIfRequired(item2);
      const newData = getFromItem(itemWithValue, menuItems);
      return {
        menus: deepMerge(acc.menus, newData.menus),
        items: [newData.item].concat(acc.items),
        expansions: deepMerge(acc.expansions, newData.expansions)
      };
    }, {
      menus: {},
      expansions: {},
      items: []
    });
  };
  const build = (items, itemResponse, backstage, isHorizontalMenu) => {
    const primary2 = generate$6("primary-menu");
    const data = expand(items, backstage.shared.providers.menuItems());
    if (data.items.length === 0) {
      return Optional.none();
    }
    const mainMenu = createPartialMenu(primary2, data.items, itemResponse, backstage, isHorizontalMenu);
    const submenus = map$1(data.menus, (menuItems, menuName) => createPartialMenu(menuName, menuItems, itemResponse, backstage, false));
    const menus = deepMerge(submenus, wrap$1(primary2, mainMenu));
    return Optional.from(tieredMenu.tieredData(primary2, menus, data.expansions));
  };
  const isSingleListItem = (item2) => !has$2(item2, "items");
  const dataAttribute = "data-value";
  const fetchItems = (dropdownComp, name2, items, selectedValue) => map$2(items, (item2) => {
    if (!isSingleListItem(item2)) {
      return {
        type: "nestedmenuitem",
        text: item2.text,
        getSubmenuItems: () => fetchItems(dropdownComp, name2, item2.items, selectedValue)
      };
    } else {
      return {
        type: "togglemenuitem",
        text: item2.text,
        value: item2.value,
        active: item2.value === selectedValue,
        onAction: () => {
          Representing.setValue(dropdownComp, item2.value);
          emitWith(dropdownComp, formChangeEvent, { name: name2 });
          Focusing.focus(dropdownComp);
        }
      };
    }
  });
  const findItemByValue = (items, value2) => findMap(items, (item2) => {
    if (!isSingleListItem(item2)) {
      return findItemByValue(item2.items, value2);
    } else {
      return someIf(item2.value === value2, item2);
    }
  });
  const renderListBox = (spec, backstage, initialData) => {
    const providersBackstage = backstage.shared.providers;
    const initialItem = initialData.bind((value2) => findItemByValue(spec.items, value2)).orThunk(() => head(spec.items).filter(isSingleListItem));
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const pField = FormField.parts.field({
      dom: {},
      factory: {
        sketch: (sketchSpec) => renderCommonDropdown({
          uid: sketchSpec.uid,
          text: initialItem.map((item2) => item2.text),
          icon: Optional.none(),
          tooltip: spec.label,
          role: Optional.none(),
          fetch: (comp, callback) => {
            const items = fetchItems(comp, spec.name, spec.items, Representing.getValue(comp));
            callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false));
          },
          onSetup: constant$1(noop),
          getApi: constant$1({}),
          columns: 1,
          presets: "normal",
          classes: [],
          dropdownBehaviours: [
            Tabstopping.config({}),
            RepresentingConfigs.withComp(initialItem.map((item2) => item2.value), (comp) => get$f(comp.element, dataAttribute), (comp, data) => {
              findItemByValue(spec.items, data).each((item2) => {
                set$9(comp.element, dataAttribute, item2.value);
                emitWith(comp, updateMenuText, { text: item2.text });
              });
            })
          ]
        }, "tox-listbox", backstage.shared)
      }
    });
    const listBoxWrap = {
      dom: {
        tag: "div",
        classes: ["tox-listboxfield"]
      },
      components: [pField]
    };
    return FormField.sketch({
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: flatten([
        pLabel.toArray(),
        [listBoxWrap]
      ]),
      fieldBehaviours: derive$1([Disabling.config({
        disabled: constant$1(!spec.enabled),
        onDisabled: (comp) => {
          FormField.getField(comp).each(Disabling.disable);
        },
        onEnabled: (comp) => {
          FormField.getField(comp).each(Disabling.enable);
        }
      })])
    });
  };
  const renderPanel = (spec, backstage) => ({
    dom: {
      tag: "div",
      classes: spec.classes
    },
    components: map$2(spec.items, backstage.shared.interpreter)
  });
  const factory$f = (detail, _spec) => {
    const options = map$2(detail.options, (option2) => ({
      dom: {
        tag: "option",
        value: option2.value,
        innerHtml: option2.text
      }
    }));
    const initialValues = detail.data.map((v) => wrap$1("initialValue", v)).getOr({});
    return {
      uid: detail.uid,
      dom: {
        tag: "select",
        classes: detail.selectClasses,
        attributes: detail.selectAttributes
      },
      components: options,
      behaviours: augment(detail.selectBehaviours, [
        Focusing.config({}),
        Representing.config({
          store: {
            mode: "manual",
            getValue: (select2) => {
              return get$6(select2.element);
            },
            setValue: (select2, newValue) => {
              const found = find$5(detail.options, (opt) => opt.value === newValue);
              if (found.isSome()) {
                set$5(select2.element, newValue);
              }
            },
            ...initialValues
          }
        })
      ])
    };
  };
  const HtmlSelect = single({
    name: "HtmlSelect",
    configFields: [
      required$1("options"),
      field("selectBehaviours", [
        Focusing,
        Representing
      ]),
      defaulted("selectClasses", []),
      defaulted("selectAttributes", {}),
      option$3("data")
    ],
    factory: factory$f
  });
  const renderSelectBox = (spec, providersBackstage, initialData) => {
    const translatedOptions = map$2(spec.items, (item2) => ({
      text: providersBackstage.translate(item2.text),
      value: item2.value
    }));
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const pField = FormField.parts.field({
      dom: {},
      ...initialData.map((data) => ({ data })).getOr({}),
      selectAttributes: { size: spec.size },
      options: translatedOptions,
      factory: HtmlSelect,
      selectBehaviours: derive$1([
        Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
        Tabstopping.config({}),
        config("selectbox-change", [run$1(change(), (component, _) => {
          emitWith(component, formChangeEvent, { name: spec.name });
        })])
      ])
    });
    const chevron = spec.size > 1 ? Optional.none() : Optional.some(render$3("chevron-down", {
      tag: "div",
      classes: ["tox-selectfield__icon-js"]
    }, providersBackstage.icons));
    const selectWrap = {
      dom: {
        tag: "div",
        classes: ["tox-selectfield"]
      },
      components: flatten([
        [pField],
        chevron.toArray()
      ])
    };
    return FormField.sketch({
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: flatten([
        pLabel.toArray(),
        [selectWrap]
      ]),
      fieldBehaviours: derive$1([
        Disabling.config({
          disabled: () => !spec.enabled || providersBackstage.isDisabled(),
          onDisabled: (comp) => {
            FormField.getField(comp).each(Disabling.disable);
          },
          onEnabled: (comp) => {
            FormField.getField(comp).each(Disabling.enable);
          }
        }),
        receivingConfig()
      ])
    });
  };
  const schema$h = constant$1([
    defaulted("field1Name", "field1"),
    defaulted("field2Name", "field2"),
    onStrictHandler("onLockedChange"),
    markers$1(["lockClass"]),
    defaulted("locked", false),
    SketchBehaviours.field("coupledFieldBehaviours", [
      Composing,
      Representing
    ])
  ]);
  const getField = (comp, detail, partName) => getPart(comp, detail, partName).bind(Composing.getCurrent);
  const coupledPart = (selfName, otherName) => required({
    factory: FormField,
    name: selfName,
    overrides: (detail) => {
      return {
        fieldBehaviours: derive$1([config("coupled-input-behaviour", [run$1(input(), (me) => {
          getField(me, detail, otherName).each((other) => {
            getPart(me, detail, "lock").each((lock) => {
              if (Toggling.isOn(lock)) {
                detail.onLockedChange(me, other, lock);
              }
            });
          });
        })])])
      };
    }
  });
  const parts$c = constant$1([
    coupledPart("field1", "field2"),
    coupledPart("field2", "field1"),
    required({
      factory: Button,
      schema: [required$1("dom")],
      name: "lock",
      overrides: (detail) => {
        return {
          buttonBehaviours: derive$1([Toggling.config({
            selected: detail.locked,
            toggleClass: detail.markers.lockClass,
            aria: { mode: "pressed" }
          })])
        };
      }
    })
  ]);
  const factory$e = (detail, components2, _spec, _externals) => ({
    uid: detail.uid,
    dom: detail.dom,
    components: components2,
    behaviours: SketchBehaviours.augment(detail.coupledFieldBehaviours, [
      Composing.config({ find: Optional.some }),
      Representing.config({
        store: {
          mode: "manual",
          getValue: (comp) => {
            const parts2 = getPartsOrDie(comp, detail, [
              "field1",
              "field2"
            ]);
            return {
              [detail.field1Name]: Representing.getValue(parts2.field1()),
              [detail.field2Name]: Representing.getValue(parts2.field2())
            };
          },
          setValue: (comp, value2) => {
            const parts2 = getPartsOrDie(comp, detail, [
              "field1",
              "field2"
            ]);
            if (hasNonNullableKey(value2, detail.field1Name)) {
              Representing.setValue(parts2.field1(), value2[detail.field1Name]);
            }
            if (hasNonNullableKey(value2, detail.field2Name)) {
              Representing.setValue(parts2.field2(), value2[detail.field2Name]);
            }
          }
        }
      })
    ]),
    apis: {
      getField1: (component) => getPart(component, detail, "field1"),
      getField2: (component) => getPart(component, detail, "field2"),
      getLock: (component) => getPart(component, detail, "lock")
    }
  });
  const FormCoupledInputs = composite({
    name: "FormCoupledInputs",
    configFields: schema$h(),
    partFields: parts$c(),
    factory: factory$e,
    apis: {
      getField1: (apis, component) => apis.getField1(component),
      getField2: (apis, component) => apis.getField2(component),
      getLock: (apis, component) => apis.getLock(component)
    }
  });
  const formatSize = (size) => {
    const unitDec = {
      "": 0,
      "px": 0,
      "pt": 1,
      "mm": 1,
      "pc": 2,
      "ex": 2,
      "em": 2,
      "ch": 2,
      "rem": 2,
      "cm": 3,
      "in": 4,
      "%": 4
    };
    const maxDecimal = (unit) => unit in unitDec ? unitDec[unit] : 1;
    let numText = size.value.toFixed(maxDecimal(size.unit));
    if (numText.indexOf(".") !== -1) {
      numText = numText.replace(/\.?0*$/, "");
    }
    return numText + size.unit;
  };
  const parseSize = (sizeText) => {
    const numPattern = /^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/;
    const match = numPattern.exec(sizeText);
    if (match !== null) {
      const value2 = parseFloat(match[1]);
      const unit = match[2];
      return Result.value({
        value: value2,
        unit
      });
    } else {
      return Result.error(sizeText);
    }
  };
  const convertUnit = (size, unit) => {
    const inInch = {
      "": 96,
      "px": 96,
      "pt": 72,
      "cm": 2.54,
      "pc": 12,
      "mm": 25.4,
      "in": 1
    };
    const supported2 = (u) => has$2(inInch, u);
    if (size.unit === unit) {
      return Optional.some(size.value);
    } else if (supported2(size.unit) && supported2(unit)) {
      if (inInch[size.unit] === inInch[unit]) {
        return Optional.some(size.value);
      } else {
        return Optional.some(size.value / inInch[size.unit] * inInch[unit]);
      }
    } else {
      return Optional.none();
    }
  };
  const noSizeConversion = (_input) => Optional.none();
  const ratioSizeConversion = (scale, unit) => (size) => convertUnit(size, unit).map((value2) => ({
    value: value2 * scale,
    unit
  }));
  const makeRatioConverter = (currentFieldText, otherFieldText) => {
    const cValue = parseSize(currentFieldText).toOptional();
    const oValue = parseSize(otherFieldText).toOptional();
    return lift2(cValue, oValue, (cSize, oSize) => convertUnit(cSize, oSize.unit).map((val) => oSize.value / val).map((r2) => ratioSizeConversion(r2, oSize.unit)).getOr(noSizeConversion)).getOr(noSizeConversion);
  };
  const renderSizeInput = (spec, providersBackstage) => {
    let converter = noSizeConversion;
    const ratioEvent = generate$6("ratio-event");
    const makeIcon = (iconName) => render$3(iconName, {
      tag: "span",
      classes: [
        "tox-icon",
        "tox-lock-icon__" + iconName
      ]
    }, providersBackstage.icons);
    const pLock = FormCoupledInputs.parts.lock({
      dom: {
        tag: "button",
        classes: [
          "tox-lock",
          "tox-button",
          "tox-button--naked",
          "tox-button--icon"
        ],
        attributes: { title: providersBackstage.translate(spec.label.getOr("Constrain proportions")) }
      },
      components: [
        makeIcon("lock"),
        makeIcon("unlock")
      ],
      buttonBehaviours: derive$1([
        Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
        receivingConfig(),
        Tabstopping.config({})
      ])
    });
    const formGroup = (components2) => ({
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: components2
    });
    const getFieldPart = (isField1) => FormField.parts.field({
      factory: Input,
      inputClasses: ["tox-textfield"],
      inputBehaviours: derive$1([
        Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
        receivingConfig(),
        Tabstopping.config({}),
        config("size-input-events", [
          run$1(focusin(), (component, _simulatedEvent) => {
            emitWith(component, ratioEvent, { isField1 });
          }),
          run$1(change(), (component, _simulatedEvent) => {
            emitWith(component, formChangeEvent, { name: spec.name });
          })
        ])
      ]),
      selectOnFocus: false
    });
    const getLabel = (label2) => ({
      dom: {
        tag: "label",
        classes: ["tox-label"]
      },
      components: [text$1(providersBackstage.translate(label2))]
    });
    const widthField = FormCoupledInputs.parts.field1(formGroup([
      FormField.parts.label(getLabel("Width")),
      getFieldPart(true)
    ]));
    const heightField = FormCoupledInputs.parts.field2(formGroup([
      FormField.parts.label(getLabel("Height")),
      getFieldPart(false)
    ]));
    return FormCoupledInputs.sketch({
      dom: {
        tag: "div",
        classes: ["tox-form__group"]
      },
      components: [{
        dom: {
          tag: "div",
          classes: ["tox-form__controls-h-stack"]
        },
        components: [
          widthField,
          heightField,
          formGroup([
            getLabel(nbsp),
            pLock
          ])
        ]
      }],
      field1Name: "width",
      field2Name: "height",
      locked: true,
      markers: { lockClass: "tox-locked" },
      onLockedChange: (current, other, _lock) => {
        parseSize(Representing.getValue(current)).each((size) => {
          converter(size).each((newSize) => {
            Representing.setValue(other, formatSize(newSize));
          });
        });
      },
      coupledFieldBehaviours: derive$1([
        Disabling.config({
          disabled: () => !spec.enabled || providersBackstage.isDisabled(),
          onDisabled: (comp) => {
            FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
            FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
            FormCoupledInputs.getLock(comp).each(Disabling.disable);
          },
          onEnabled: (comp) => {
            FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
            FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
            FormCoupledInputs.getLock(comp).each(Disabling.enable);
          }
        }),
        receivingConfig(),
        config("size-input-events2", [run$1(ratioEvent, (component, simulatedEvent) => {
          const isField1 = simulatedEvent.event.isField1;
          const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
          const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
          const value1 = optCurrent.map(Representing.getValue).getOr("");
          const value2 = optOther.map(Representing.getValue).getOr("");
          converter = makeRatioConverter(value1, value2);
        })])
      ])
    });
  };
  const renderSlider = (spec, providerBackstage, initialData) => {
    const labelPart2 = Slider.parts.label({
      dom: {
        tag: "label",
        classes: ["tox-label"]
      },
      components: [text$1(providerBackstage.translate(spec.label))]
    });
    const spectrum = Slider.parts.spectrum({
      dom: {
        tag: "div",
        classes: ["tox-slider__rail"],
        attributes: { role: "presentation" }
      }
    });
    const thumb = Slider.parts.thumb({
      dom: {
        tag: "div",
        classes: ["tox-slider__handle"],
        attributes: { role: "presentation" }
      }
    });
    return Slider.sketch({
      dom: {
        tag: "div",
        classes: ["tox-slider"],
        attributes: { role: "presentation" }
      },
      model: {
        mode: "x",
        minX: spec.min,
        maxX: spec.max,
        getInitialValue: constant$1(initialData.getOrThunk(() => (Math.abs(spec.max) - Math.abs(spec.min)) / 2))
      },
      components: [
        labelPart2,
        spectrum,
        thumb
      ],
      sliderBehaviours: derive$1([
        ComposingConfigs.self(),
        Focusing.config({})
      ]),
      onChoose: (component, thumb2, value2) => {
        emitWith(component, formChangeEvent, {
          name: spec.name,
          value: value2
        });
      }
    });
  };
  const renderTable = (spec, providersBackstage) => {
    const renderTh = (text2) => ({
      dom: {
        tag: "th",
        innerHtml: providersBackstage.translate(text2)
      }
    });
    const renderHeader2 = (header) => ({
      dom: { tag: "thead" },
      components: [{
        dom: { tag: "tr" },
        components: map$2(header, renderTh)
      }]
    });
    const renderTd = (text2) => ({
      dom: {
        tag: "td",
        innerHtml: providersBackstage.translate(text2)
      }
    });
    const renderTr = (row) => ({
      dom: { tag: "tr" },
      components: map$2(row, renderTd)
    });
    const renderRows = (rows) => ({
      dom: { tag: "tbody" },
      components: map$2(rows, renderTr)
    });
    return {
      dom: {
        tag: "table",
        classes: ["tox-dialog__table"]
      },
      components: [
        renderHeader2(spec.header),
        renderRows(spec.cells)
      ],
      behaviours: derive$1([
        Tabstopping.config({}),
        Focusing.config({})
      ])
    };
  };
  const renderTextField = (spec, providersBackstage) => {
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const baseInputBehaviours = [
      Disabling.config({ disabled: () => spec.disabled || providersBackstage.isDisabled() }),
      receivingConfig(),
      Keying.config({
        mode: "execution",
        useEnter: spec.multiline !== true,
        useControlEnter: spec.multiline === true,
        execute: (comp) => {
          emit(comp, formSubmitEvent);
          return Optional.some(true);
        }
      }),
      config("textfield-change", [
        run$1(input(), (component, _) => {
          emitWith(component, formChangeEvent, { name: spec.name });
        }),
        run$1(postPaste(), (component, _) => {
          emitWith(component, formChangeEvent, { name: spec.name });
        })
      ]),
      Tabstopping.config({})
    ];
    const validatingBehaviours = spec.validation.map((vl) => Invalidating.config({
      getRoot: (input2) => {
        return parentElement(input2.element);
      },
      invalidClass: "tox-invalid",
      validator: {
        validate: (input2) => {
          const v = Representing.getValue(input2);
          const result = vl.validator(v);
          return Future.pure(result === true ? Result.value(v) : Result.error(result));
        },
        validateOnLoad: vl.validateOnLoad
      }
    })).toArray();
    const placeholder2 = spec.placeholder.fold(constant$1({}), (p) => ({ placeholder: providersBackstage.translate(p) }));
    const inputMode = spec.inputMode.fold(constant$1({}), (mode) => ({ inputmode: mode }));
    const inputAttributes = {
      ...placeholder2,
      ...inputMode
    };
    const pField = FormField.parts.field({
      tag: spec.multiline === true ? "textarea" : "input",
      ...spec.data.map((data) => ({ data })).getOr({}),
      inputAttributes,
      inputClasses: [spec.classname],
      inputBehaviours: derive$1(flatten([
        baseInputBehaviours,
        validatingBehaviours
      ])),
      selectOnFocus: false,
      factory: Input
    });
    const extraClasses = spec.flex ? ["tox-form__group--stretched"] : [];
    const extraClasses2 = extraClasses.concat(spec.maximized ? ["tox-form-group--maximize"] : []);
    const extraBehaviours = [
      Disabling.config({
        disabled: () => spec.disabled || providersBackstage.isDisabled(),
        onDisabled: (comp) => {
          FormField.getField(comp).each(Disabling.disable);
        },
        onEnabled: (comp) => {
          FormField.getField(comp).each(Disabling.enable);
        }
      }),
      receivingConfig()
    ];
    return renderFormFieldWith(pLabel, pField, extraClasses2, extraBehaviours);
  };
  const renderInput = (spec, providersBackstage, initialData) => renderTextField({
    name: spec.name,
    multiline: false,
    label: spec.label,
    inputMode: spec.inputMode,
    placeholder: spec.placeholder,
    flex: false,
    disabled: !spec.enabled,
    classname: "tox-textfield",
    validation: Optional.none(),
    maximized: spec.maximized,
    data: initialData
  }, providersBackstage);
  const renderTextarea = (spec, providersBackstage, initialData) => renderTextField({
    name: spec.name,
    multiline: true,
    label: spec.label,
    inputMode: Optional.none(),
    placeholder: spec.placeholder,
    flex: true,
    disabled: !spec.enabled,
    classname: "tox-textarea",
    validation: Optional.none(),
    maximized: spec.maximized,
    data: initialData
  }, providersBackstage);
  const events$6 = (streamConfig, streamState) => {
    const streams = streamConfig.stream.streams;
    const processor = streams.setup(streamConfig, streamState);
    return derive$2([
      run$1(streamConfig.event, processor),
      runOnDetached(() => streamState.cancel())
    ].concat(streamConfig.cancelEvent.map((e) => [run$1(e, () => streamState.cancel())]).getOr([])));
  };
  var ActiveStreaming = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$6
  });
  const first = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle2 = (...args) => {
      if (isNull(timer)) {
        timer = setTimeout(() => {
          timer = null;
          fn.apply(null, args);
        }, rate);
      }
    };
    return {
      cancel,
      throttle: throttle2
    };
  };
  const last = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle2 = (...args) => {
      cancel();
      timer = setTimeout(() => {
        timer = null;
        fn.apply(null, args);
      }, rate);
    };
    return {
      cancel,
      throttle: throttle2
    };
  };
  const throttle = (_config) => {
    const state = Cell(null);
    const readState = () => ({ timer: state.get() !== null ? "set" : "unset" });
    const setTimer = (t2) => {
      state.set(t2);
    };
    const cancel = () => {
      const t2 = state.get();
      if (t2 !== null) {
        t2.cancel();
      }
    };
    return nu$8({
      readState,
      setTimer,
      cancel
    });
  };
  const init$9 = (spec) => spec.stream.streams.state(spec);
  var StreamingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    throttle,
    init: init$9
  });
  const setup$c = (streamInfo, streamState) => {
    const sInfo = streamInfo.stream;
    const throttler = last(streamInfo.onStream, sInfo.delay);
    streamState.setTimer(throttler);
    return (component, simulatedEvent) => {
      throttler.throttle(component, simulatedEvent);
      if (sInfo.stopEvent) {
        simulatedEvent.stop();
      }
    };
  };
  var StreamingSchema = [
    requiredOf("stream", choose$1("mode", {
      throttle: [
        required$1("delay"),
        defaulted("stopEvent", true),
        output$1("streams", {
          setup: setup$c,
          state: throttle
        })
      ]
    })),
    defaulted("event", "input"),
    option$3("cancelEvent"),
    onStrictHandler("onStream")
  ];
  const Streaming = create$3({
    fields: StreamingSchema,
    name: "streaming",
    active: ActiveStreaming,
    state: StreamingState
  });
  const setValueFromItem = (model, input2, item2) => {
    const itemData = Representing.getValue(item2);
    Representing.setValue(input2, itemData);
    setCursorAtEnd(input2);
  };
  const setSelectionOn = (input2, f) => {
    const el = input2.element;
    const value2 = get$6(el);
    const node = el.dom;
    if (get$f(el, "type") !== "number") {
      f(node, value2);
    }
  };
  const setCursorAtEnd = (input2) => {
    setSelectionOn(input2, (node, value2) => node.setSelectionRange(value2.length, value2.length));
  };
  const setSelectionToEnd = (input2, startOffset) => {
    setSelectionOn(input2, (node, value2) => node.setSelectionRange(startOffset, value2.length));
  };
  const attemptSelectOver = (model, input2, item2) => {
    if (!model.selectsOver) {
      return Optional.none();
    } else {
      const currentValue2 = Representing.getValue(input2);
      const inputDisplay = model.getDisplayText(currentValue2);
      const itemValue = Representing.getValue(item2);
      const itemDisplay = model.getDisplayText(itemValue);
      return itemDisplay.indexOf(inputDisplay) === 0 ? Optional.some(() => {
        setValueFromItem(model, input2, item2);
        setSelectionToEnd(input2, inputDisplay.length);
      }) : Optional.none();
    }
  };
  const itemExecute = constant$1("alloy.typeahead.itemexecute");
  const make$3 = (detail, components2, spec, externals) => {
    const navigateList = (comp, simulatedEvent, highlighter) => {
      detail.previewing.set(false);
      const sandbox = Coupling.getCoupled(comp, "sandbox");
      if (Sandboxing.isOpen(sandbox)) {
        Composing.getCurrent(sandbox).each((menu2) => {
          Highlighting.getHighlighted(menu2).fold(() => {
            highlighter(menu2);
          }, () => {
            dispatchEvent(sandbox, menu2.element, "keydown", simulatedEvent);
          });
        });
      } else {
        const onOpenSync = (sandbox2) => {
          Composing.getCurrent(sandbox2).each(highlighter);
        };
        open(detail, mapFetch(comp), comp, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
      }
    };
    const focusBehaviours$1 = focusBehaviours(detail);
    const mapFetch = (comp) => (tdata) => tdata.map((data) => {
      const menus = values(data.menus);
      const items = bind$3(menus, (menu2) => filter$2(menu2.items, (item2) => item2.type === "item"));
      const repState = Representing.getState(comp);
      repState.update(map$2(items, (item2) => item2.data));
      return data;
    });
    const behaviours2 = [
      Focusing.config({}),
      Representing.config({
        onSetValue: detail.onSetValue,
        store: {
          mode: "dataset",
          getDataKey: (comp) => get$6(comp.element),
          getFallbackEntry: (itemString) => ({
            value: itemString,
            meta: {}
          }),
          setValue: (comp, data) => {
            set$5(comp.element, detail.model.getDisplayText(data));
          },
          ...detail.initialData.map((d) => wrap$1("initialValue", d)).getOr({})
        }
      }),
      Streaming.config({
        stream: {
          mode: "throttle",
          delay: detail.responseTime,
          stopEvent: false
        },
        onStream: (component, _simulatedEvent) => {
          const sandbox = Coupling.getCoupled(component, "sandbox");
          const focusInInput = Focusing.isFocused(component);
          if (focusInInput) {
            if (get$6(component.element).length >= detail.minChars) {
              const previousValue = Composing.getCurrent(sandbox).bind((menu2) => Highlighting.getHighlighted(menu2).map(Representing.getValue));
              detail.previewing.set(true);
              const onOpenSync = (_sandbox) => {
                Composing.getCurrent(sandbox).each((menu2) => {
                  previousValue.fold(() => {
                    if (detail.model.selectsOver) {
                      Highlighting.highlightFirst(menu2);
                    }
                  }, (pv) => {
                    Highlighting.highlightBy(menu2, (item2) => {
                      const itemData = Representing.getValue(item2);
                      return itemData.value === pv.value;
                    });
                    Highlighting.getHighlighted(menu2).orThunk(() => {
                      Highlighting.highlightFirst(menu2);
                      return Optional.none();
                    });
                  });
                });
              };
              open(detail, mapFetch(component), component, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
            }
          }
        },
        cancelEvent: typeaheadCancel()
      }),
      Keying.config({
        mode: "special",
        onDown: (comp, simulatedEvent) => {
          navigateList(comp, simulatedEvent, Highlighting.highlightFirst);
          return Optional.some(true);
        },
        onEscape: (comp) => {
          const sandbox = Coupling.getCoupled(comp, "sandbox");
          if (Sandboxing.isOpen(sandbox)) {
            Sandboxing.close(sandbox);
            return Optional.some(true);
          }
          return Optional.none();
        },
        onUp: (comp, simulatedEvent) => {
          navigateList(comp, simulatedEvent, Highlighting.highlightLast);
          return Optional.some(true);
        },
        onEnter: (comp) => {
          const sandbox = Coupling.getCoupled(comp, "sandbox");
          const sandboxIsOpen = Sandboxing.isOpen(sandbox);
          if (sandboxIsOpen && !detail.previewing.get()) {
            return Composing.getCurrent(sandbox).bind((menu2) => Highlighting.getHighlighted(menu2)).map((item2) => {
              emitWith(comp, itemExecute(), { item: item2 });
              return true;
            });
          } else {
            const currentValue2 = Representing.getValue(comp);
            emit(comp, typeaheadCancel());
            detail.onExecute(sandbox, comp, currentValue2);
            if (sandboxIsOpen) {
              Sandboxing.close(sandbox);
            }
            return Optional.some(true);
          }
        }
      }),
      Toggling.config({
        toggleClass: detail.markers.openClass,
        aria: { mode: "expanded" }
      }),
      Coupling.config({
        others: {
          sandbox: (hotspot) => {
            return makeSandbox$1(detail, hotspot, {
              onOpen: () => Toggling.on(hotspot),
              onClose: () => Toggling.off(hotspot)
            });
          }
        }
      }),
      config("typeaheadevents", [
        runOnExecute$1((comp) => {
          const onOpenSync = noop;
          togglePopup(detail, mapFetch(comp), comp, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
        }),
        run$1(itemExecute(), (comp, se) => {
          const sandbox = Coupling.getCoupled(comp, "sandbox");
          setValueFromItem(detail.model, comp, se.event.item);
          emit(comp, typeaheadCancel());
          detail.onItemExecute(comp, sandbox, se.event.item, Representing.getValue(comp));
          Sandboxing.close(sandbox);
          setCursorAtEnd(comp);
        })
      ].concat(detail.dismissOnBlur ? [run$1(postBlur(), (typeahead) => {
        const sandbox = Coupling.getCoupled(typeahead, "sandbox");
        if (search(sandbox.element).isNone()) {
          Sandboxing.close(sandbox);
        }
      })] : []))
    ];
    return {
      uid: detail.uid,
      dom: dom(deepMerge(detail, {
        inputAttributes: {
          "role": "combobox",
          "aria-autocomplete": "list",
          "aria-haspopup": "true"
        }
      })),
      behaviours: {
        ...focusBehaviours$1,
        ...augment(detail.typeaheadBehaviours, behaviours2)
      },
      eventOrder: detail.eventOrder
    };
  };
  const schema$g = constant$1([
    option$3("lazySink"),
    required$1("fetch"),
    defaulted("minChars", 5),
    defaulted("responseTime", 1e3),
    onHandler("onOpen"),
    defaulted("getHotspot", Optional.some),
    defaulted("getAnchorOverrides", constant$1({})),
    defaulted("layouts", Optional.none()),
    defaulted("eventOrder", {}),
    defaultedObjOf("model", {}, [
      defaulted("getDisplayText", (itemData) => itemData.meta !== void 0 && itemData.meta.text !== void 0 ? itemData.meta.text : itemData.value),
      defaulted("selectsOver", true),
      defaulted("populateFromBrowse", true)
    ]),
    onHandler("onSetValue"),
    onKeyboardHandler("onExecute"),
    onHandler("onItemExecute"),
    defaulted("inputClasses", []),
    defaulted("inputAttributes", {}),
    defaulted("inputStyles", {}),
    defaulted("matchWidth", true),
    defaulted("useMinWidth", false),
    defaulted("dismissOnBlur", true),
    markers$1(["openClass"]),
    option$3("initialData"),
    field("typeaheadBehaviours", [
      Focusing,
      Representing,
      Streaming,
      Keying,
      Toggling,
      Coupling
    ]),
    customField("previewing", () => Cell(true))
  ].concat(schema$k()).concat(sandboxFields()));
  const parts$b = constant$1([external({
    schema: [tieredMenuMarkers()],
    name: "menu",
    overrides: (detail) => {
      return {
        fakeFocus: true,
        onHighlight: (menu2, item2) => {
          if (!detail.previewing.get()) {
            menu2.getSystem().getByUid(detail.uid).each((input2) => {
              if (detail.model.populateFromBrowse) {
                setValueFromItem(detail.model, input2, item2);
              }
            });
          } else {
            menu2.getSystem().getByUid(detail.uid).each((input2) => {
              attemptSelectOver(detail.model, input2, item2).fold(() => Highlighting.dehighlight(menu2, item2), (fn) => fn());
            });
          }
          detail.previewing.set(false);
        },
        onExecute: (menu2, item2) => {
          return menu2.getSystem().getByUid(detail.uid).toOptional().map((typeahead) => {
            emitWith(typeahead, itemExecute(), { item: item2 });
            return true;
          });
        },
        onHover: (menu2, item2) => {
          detail.previewing.set(false);
          menu2.getSystem().getByUid(detail.uid).each((input2) => {
            if (detail.model.populateFromBrowse) {
              setValueFromItem(detail.model, input2, item2);
            }
          });
        }
      };
    }
  })]);
  const Typeahead = composite({
    name: "Typeahead",
    configFields: schema$g(),
    partFields: parts$b(),
    factory: make$3
  });
  const wrap = (delegate) => {
    const toCached = () => {
      return wrap(delegate.toCached());
    };
    const bindFuture = (f) => {
      return wrap(delegate.bind((resA) => resA.fold((err) => Future.pure(Result.error(err)), (a) => f(a))));
    };
    const bindResult = (f) => {
      return wrap(delegate.map((resA) => resA.bind(f)));
    };
    const mapResult = (f) => {
      return wrap(delegate.map((resA) => resA.map(f)));
    };
    const mapError2 = (f) => {
      return wrap(delegate.map((resA) => resA.mapError(f)));
    };
    const foldResult = (whenError, whenValue) => {
      return delegate.map((res) => res.fold(whenError, whenValue));
    };
    const withTimeout = (timeout, errorThunk) => {
      return wrap(Future.nu((callback) => {
        let timedOut = false;
        const timer = setTimeout(() => {
          timedOut = true;
          callback(Result.error(errorThunk()));
        }, timeout);
        delegate.get((result) => {
          if (!timedOut) {
            clearTimeout(timer);
            callback(result);
          }
        });
      }));
    };
    return {
      ...delegate,
      toCached,
      bindFuture,
      bindResult,
      mapResult,
      mapError: mapError2,
      foldResult,
      withTimeout
    };
  };
  const nu$1 = (worker) => {
    return wrap(Future.nu(worker));
  };
  const value = (value2) => {
    return wrap(Future.pure(Result.value(value2)));
  };
  const error = (error2) => {
    return wrap(Future.pure(Result.error(error2)));
  };
  const fromResult = (result) => {
    return wrap(Future.pure(result));
  };
  const fromFuture = (future) => {
    return wrap(future.map(Result.value));
  };
  const fromPromise = (promise) => {
    return nu$1((completer) => {
      promise.then((value2) => {
        completer(Result.value(value2));
      }, (error2) => {
        completer(Result.error(error2));
      });
    });
  };
  const FutureResult = {
    nu: nu$1,
    wrap,
    pure: value,
    value,
    error,
    fromResult,
    fromFuture,
    fromPromise
  };
  const getMenuButtonApi = (component) => ({
    isEnabled: () => !Disabling.isDisabled(component),
    setEnabled: (state) => Disabling.set(component, !state),
    setActive: (state) => {
      const elm = component.element;
      if (state) {
        add$2(elm, "tox-tbtn--enabled");
        set$9(elm, "aria-pressed", true);
      } else {
        remove$2(elm, "tox-tbtn--enabled");
        remove$7(elm, "aria-pressed");
      }
    },
    isActive: () => has(component.element, "tox-tbtn--enabled")
  });
  const renderMenuButton = (spec, prefix2, backstage, role) => renderCommonDropdown({
    text: spec.text,
    icon: spec.icon,
    tooltip: spec.tooltip,
    role,
    fetch: (_comp, callback) => {
      spec.fetch((items) => {
        callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false));
      });
    },
    onSetup: spec.onSetup,
    getApi: getMenuButtonApi,
    columns: 1,
    presets: "normal",
    classes: [],
    dropdownBehaviours: [Tabstopping.config({})]
  }, prefix2, backstage.shared);
  const getFetch = (items, getButton, backstage) => {
    const getMenuItemAction = (item2) => (api2) => {
      const newValue = !api2.isActive();
      api2.setActive(newValue);
      item2.storage.set(newValue);
      backstage.shared.getSink().each((sink) => {
        getButton().getOpt(sink).each((orig) => {
          focus$3(orig.element);
          emitWith(orig, formActionEvent, {
            name: item2.name,
            value: item2.storage.get()
          });
        });
      });
    };
    const getMenuItemSetup = (item2) => (api2) => {
      api2.setActive(item2.storage.get());
    };
    return (success) => {
      success(map$2(items, (item2) => {
        const text2 = item2.text.fold(() => ({}), (text3) => ({ text: text3 }));
        return {
          type: item2.type,
          active: false,
          ...text2,
          onAction: getMenuItemAction(item2),
          onSetup: getMenuItemSetup(item2)
        };
      }));
    };
  };
  const renderCommonSpec = (spec, actionOpt, extraBehaviours = [], dom2, components2, providersBackstage) => {
    const action = actionOpt.fold(() => ({}), (action2) => ({ action: action2 }));
    const common = {
      buttonBehaviours: derive$1([
        DisablingConfigs.button(() => !spec.enabled || providersBackstage.isDisabled()),
        receivingConfig(),
        Tabstopping.config({}),
        config("button press", [
          preventDefault("click"),
          preventDefault("mousedown")
        ])
      ].concat(extraBehaviours)),
      eventOrder: {
        click: [
          "button press",
          "alloy.base.behaviour"
        ],
        mousedown: [
          "button press",
          "alloy.base.behaviour"
        ]
      },
      ...action
    };
    const domFinal = deepMerge(common, { dom: dom2 });
    return deepMerge(domFinal, { components: components2 });
  };
  const renderIconButtonSpec = (spec, action, providersBackstage, extraBehaviours = []) => {
    const tooltipAttributes = spec.tooltip.map((tooltip) => ({
      "aria-label": providersBackstage.translate(tooltip),
      "title": providersBackstage.translate(tooltip)
    })).getOr({});
    const dom2 = {
      tag: "button",
      classes: ["tox-tbtn"],
      attributes: tooltipAttributes
    };
    const icon2 = spec.icon.map((iconName) => renderIconFromPack(iconName, providersBackstage.icons));
    const components2 = componentRenderPipeline([icon2]);
    return renderCommonSpec(spec, action, extraBehaviours, dom2, components2, providersBackstage);
  };
  const calculateClassesFromButtonType = (buttonType) => {
    switch (buttonType) {
      case "primary":
        return ["tox-button"];
      case "toolbar":
        return ["tox-tbtn"];
      case "secondary":
      default:
        return [
          "tox-button",
          "tox-button--secondary"
        ];
    }
  };
  const renderButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
    const translatedText = providersBackstage.translate(spec.text);
    const icon2 = spec.icon.map((iconName) => renderIconFromPack(iconName, providersBackstage.icons));
    const components2 = [icon2.getOrThunk(() => text$1(translatedText))];
    const buttonType = spec.buttonType.getOr(!spec.primary && !spec.borderless ? "secondary" : "primary");
    const baseClasses = calculateClassesFromButtonType(buttonType);
    const classes2 = [
      ...baseClasses,
      ...icon2.isSome() ? ["tox-button--icon"] : [],
      ...spec.borderless ? ["tox-button--naked"] : [],
      ...extraClasses
    ];
    const dom2 = {
      tag: "button",
      classes: classes2,
      attributes: { title: translatedText }
    };
    return renderCommonSpec(spec, action, extraBehaviours, dom2, components2, providersBackstage);
  };
  const renderButton = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
    const buttonSpec = renderButtonSpec(spec, Optional.some(action), providersBackstage, extraBehaviours, extraClasses);
    return Button.sketch(buttonSpec);
  };
  const getAction = (name2, buttonType) => (comp) => {
    if (buttonType === "custom") {
      emitWith(comp, formActionEvent, {
        name: name2,
        value: {}
      });
    } else if (buttonType === "submit") {
      emit(comp, formSubmitEvent);
    } else if (buttonType === "cancel") {
      emit(comp, formCancelEvent);
    } else {
      console.error("Unknown button type: ", buttonType);
    }
  };
  const isMenuFooterButtonSpec = (spec, buttonType) => buttonType === "menu";
  const isNormalFooterButtonSpec = (spec, buttonType) => buttonType === "custom" || buttonType === "cancel" || buttonType === "submit";
  const renderFooterButton = (spec, buttonType, backstage) => {
    if (isMenuFooterButtonSpec(spec, buttonType)) {
      const getButton = () => memButton;
      const menuButtonSpec = spec;
      const fixedSpec = {
        ...spec,
        onSetup: (api2) => {
          api2.setEnabled(spec.enabled);
          return noop;
        },
        fetch: getFetch(menuButtonSpec.items, getButton, backstage)
      };
      const memButton = record(renderMenuButton(fixedSpec, "tox-tbtn", backstage, Optional.none()));
      return memButton.asSpec();
    } else if (isNormalFooterButtonSpec(spec, buttonType)) {
      const action = getAction(spec.name, buttonType);
      const buttonSpec = {
        ...spec,
        borderless: false
      };
      return renderButton(buttonSpec, action, backstage.shared.providers, []);
    } else {
      console.error("Unknown footer button type: ", buttonType);
    }
  };
  const renderDialogButton = (spec, providersBackstage) => {
    const action = getAction(spec.name, "custom");
    return renderFormField(Optional.none(), FormField.parts.field({
      factory: Button,
      ...renderButtonSpec(spec, Optional.some(action), providersBackstage, [
        RepresentingConfigs.memory(""),
        ComposingConfigs.self()
      ])
    }));
  };
  const separator$1 = { type: "separator" };
  const toMenuItem = (target) => ({
    type: "menuitem",
    value: target.url,
    text: target.title,
    meta: { attach: target.attach },
    onAction: noop
  });
  const staticMenuItem = (title2, url) => ({
    type: "menuitem",
    value: url,
    text: title2,
    meta: { attach: void 0 },
    onAction: noop
  });
  const toMenuItems = (targets) => map$2(targets, toMenuItem);
  const filterLinkTargets = (type2, targets) => filter$2(targets, (target) => target.type === type2);
  const filteredTargets = (type2, targets) => toMenuItems(filterLinkTargets(type2, targets));
  const headerTargets = (linkInfo) => filteredTargets("header", linkInfo.targets);
  const anchorTargets = (linkInfo) => filteredTargets("anchor", linkInfo.targets);
  const anchorTargetTop = (linkInfo) => Optional.from(linkInfo.anchorTop).map((url) => staticMenuItem("<top>", url)).toArray();
  const anchorTargetBottom = (linkInfo) => Optional.from(linkInfo.anchorBottom).map((url) => staticMenuItem("<bottom>", url)).toArray();
  const historyTargets = (history) => map$2(history, (url) => staticMenuItem(url, url));
  const joinMenuLists = (items) => {
    return foldl(items, (a, b2) => {
      const bothEmpty = a.length === 0 || b2.length === 0;
      return bothEmpty ? a.concat(b2) : a.concat(separator$1, b2);
    }, []);
  };
  const filterByQuery = (term, menuItems) => {
    const lowerCaseTerm = term.toLowerCase();
    return filter$2(menuItems, (item2) => {
      const text2 = item2.meta !== void 0 && item2.meta.text !== void 0 ? item2.meta.text : item2.text;
      return contains$1(text2.toLowerCase(), lowerCaseTerm) || contains$1(item2.value.toLowerCase(), lowerCaseTerm);
    });
  };
  const getItems = (fileType, input2, urlBackstage) => {
    const urlInputValue = Representing.getValue(input2);
    const term = urlInputValue.meta.text !== void 0 ? urlInputValue.meta.text : urlInputValue.value;
    const info = urlBackstage.getLinkInformation();
    return info.fold(() => [], (linkInfo) => {
      const history = filterByQuery(term, historyTargets(urlBackstage.getHistory(fileType)));
      return fileType === "file" ? joinMenuLists([
        history,
        filterByQuery(term, headerTargets(linkInfo)),
        filterByQuery(term, flatten([
          anchorTargetTop(linkInfo),
          anchorTargets(linkInfo),
          anchorTargetBottom(linkInfo)
        ]))
      ]) : history;
    });
  };
  const errorId = generate$6("aria-invalid");
  const renderUrlInput = (spec, backstage, urlBackstage, initialData) => {
    const providersBackstage = backstage.shared.providers;
    const updateHistory = (component) => {
      const urlEntry = Representing.getValue(component);
      urlBackstage.addToHistory(urlEntry.value, spec.filetype);
    };
    const pField = FormField.parts.field({
      factory: Typeahead,
      ...initialData.map((initialData2) => ({ initialData: initialData2 })).getOr({}),
      dismissOnBlur: true,
      inputClasses: ["tox-textfield"],
      sandboxClasses: ["tox-dialog__popups"],
      inputAttributes: {
        "aria-errormessage": errorId,
        "type": "url"
      },
      minChars: 0,
      responseTime: 0,
      fetch: (input2) => {
        const items = getItems(spec.filetype, input2, urlBackstage);
        const tdata = build(items, ItemResponse$1.BUBBLE_TO_SANDBOX, backstage, false);
        return Future.pure(tdata);
      },
      getHotspot: (comp) => memUrlBox.getOpt(comp),
      onSetValue: (comp, _newValue) => {
        if (comp.hasConfigured(Invalidating)) {
          Invalidating.run(comp).get(noop);
        }
      },
      typeaheadBehaviours: derive$1(flatten([
        urlBackstage.getValidationHandler().map((handler) => Invalidating.config({
          getRoot: (comp) => parentElement(comp.element),
          invalidClass: "tox-control-wrap--status-invalid",
          notify: {
            onInvalid: (comp, err) => {
              memInvalidIcon.getOpt(comp).each((invalidComp) => {
                set$9(invalidComp.element, "title", providersBackstage.translate(err));
              });
            }
          },
          validator: {
            validate: (input2) => {
              const urlEntry = Representing.getValue(input2);
              return FutureResult.nu((completer) => {
                handler({
                  type: spec.filetype,
                  url: urlEntry.value
                }, (validation) => {
                  if (validation.status === "invalid") {
                    const err = Result.error(validation.message);
                    completer(err);
                  } else {
                    const val = Result.value(validation.message);
                    completer(val);
                  }
                });
              });
            },
            validateOnLoad: false
          }
        })).toArray(),
        [
          Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
          Tabstopping.config({}),
          config("urlinput-events", flatten([
            spec.filetype === "file" ? [run$1(input(), (comp) => {
              emitWith(comp, formChangeEvent, { name: spec.name });
            })] : [],
            [
              run$1(change(), (comp) => {
                emitWith(comp, formChangeEvent, { name: spec.name });
                updateHistory(comp);
              }),
              run$1(postPaste(), (comp) => {
                emitWith(comp, formChangeEvent, { name: spec.name });
                updateHistory(comp);
              })
            ]
          ]))
        ]
      ])),
      eventOrder: {
        [input()]: [
          "streaming",
          "urlinput-events",
          "invalidating"
        ]
      },
      model: {
        getDisplayText: (itemData) => itemData.value,
        selectsOver: false,
        populateFromBrowse: false
      },
      markers: { openClass: "tox-textfield--popup-open" },
      lazySink: backstage.shared.getSink,
      parts: { menu: part(false, 1, "normal") },
      onExecute: (_menu, component, _entry) => {
        emitWith(component, formSubmitEvent, {});
      },
      onItemExecute: (typeahead, _sandbox, _item, _value) => {
        updateHistory(typeahead);
        emitWith(typeahead, formChangeEvent, { name: spec.name });
      }
    });
    const pLabel = spec.label.map((label2) => renderLabel$2(label2, providersBackstage));
    const makeIcon = (name2, errId, icon2 = name2, label2 = name2) => render$3(icon2, {
      tag: "div",
      classes: [
        "tox-icon",
        "tox-control-wrap__status-icon-" + name2
      ],
      attributes: {
        "title": providersBackstage.translate(label2),
        "aria-live": "polite",
        ...errId.fold(() => ({}), (id) => ({ id }))
      }
    }, providersBackstage.icons);
    const memInvalidIcon = record(makeIcon("invalid", Optional.some(errorId), "warning"));
    const memStatus = record({
      dom: {
        tag: "div",
        classes: ["tox-control-wrap__status-icon-wrap"]
      },
      components: [memInvalidIcon.asSpec()]
    });
    const optUrlPicker = urlBackstage.getUrlPicker(spec.filetype);
    const browseUrlEvent = generate$6("browser.url.event");
    const memUrlBox = record({
      dom: {
        tag: "div",
        classes: ["tox-control-wrap"]
      },
      components: [
        pField,
        memStatus.asSpec()
      ],
      behaviours: derive$1([Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() })])
    });
    const memUrlPickerButton = record(renderButton({
      name: spec.name,
      icon: Optional.some("browse"),
      text: spec.label.getOr(""),
      enabled: spec.enabled,
      primary: false,
      buttonType: Optional.none(),
      borderless: true
    }, (component) => emit(component, browseUrlEvent), providersBackstage, [], ["tox-browse-url"]));
    const controlHWrapper = () => ({
      dom: {
        tag: "div",
        classes: ["tox-form__controls-h-stack"]
      },
      components: flatten([
        [memUrlBox.asSpec()],
        optUrlPicker.map(() => memUrlPickerButton.asSpec()).toArray()
      ])
    });
    const openUrlPicker = (comp) => {
      Composing.getCurrent(comp).each((field2) => {
        const componentData = Representing.getValue(field2);
        const urlData = {
          fieldname: spec.name,
          ...componentData
        };
        optUrlPicker.each((picker) => {
          picker(urlData).get((chosenData) => {
            Representing.setValue(field2, chosenData);
            emitWith(comp, formChangeEvent, { name: spec.name });
          });
        });
      });
    };
    return FormField.sketch({
      dom: renderFormFieldDom(),
      components: pLabel.toArray().concat([controlHWrapper()]),
      fieldBehaviours: derive$1([
        Disabling.config({
          disabled: () => !spec.enabled || providersBackstage.isDisabled(),
          onDisabled: (comp) => {
            FormField.getField(comp).each(Disabling.disable);
            memUrlPickerButton.getOpt(comp).each(Disabling.disable);
          },
          onEnabled: (comp) => {
            FormField.getField(comp).each(Disabling.enable);
            memUrlPickerButton.getOpt(comp).each(Disabling.enable);
          }
        }),
        receivingConfig(),
        config("url-input-events", [run$1(browseUrlEvent, openUrlPicker)])
      ])
    });
  };
  const renderAlertBanner = (spec, providersBackstage) => Container.sketch({
    dom: {
      tag: "div",
      attributes: { role: "alert" },
      classes: [
        "tox-notification",
        "tox-notification--in",
        `tox-notification--${spec.level}`
      ]
    },
    components: [
      {
        dom: {
          tag: "div",
          classes: ["tox-notification__icon"]
        },
        components: [Button.sketch({
          dom: {
            tag: "button",
            classes: [
              "tox-button",
              "tox-button--naked",
              "tox-button--icon"
            ],
            innerHtml: get$2(spec.icon, providersBackstage.icons),
            attributes: { title: providersBackstage.translate(spec.iconTooltip) }
          },
          action: (comp) => {
            emitWith(comp, formActionEvent, {
              name: "alert-banner",
              value: spec.url
            });
          },
          buttonBehaviours: derive$1([addFocusableBehaviour()])
        })]
      },
      {
        dom: {
          tag: "div",
          classes: ["tox-notification__body"],
          innerHtml: providersBackstage.translate(spec.text)
        }
      }
    ]
  });
  const set$1 = (element2, status) => {
    element2.dom.checked = status;
  };
  const get$1 = (element2) => element2.dom.checked;
  const renderCheckbox = (spec, providerBackstage, initialData) => {
    const toggleCheckboxHandler = (comp) => {
      comp.element.dom.click();
      return Optional.some(true);
    };
    const pField = FormField.parts.field({
      factory: { sketch: identity },
      dom: {
        tag: "input",
        classes: ["tox-checkbox__input"],
        attributes: { type: "checkbox" }
      },
      behaviours: derive$1([
        ComposingConfigs.self(),
        Disabling.config({ disabled: () => !spec.enabled || providerBackstage.isDisabled() }),
        Tabstopping.config({}),
        Focusing.config({}),
        RepresentingConfigs.withElement(initialData, get$1, set$1),
        Keying.config({
          mode: "special",
          onEnter: toggleCheckboxHandler,
          onSpace: toggleCheckboxHandler,
          stopSpaceKeyup: true
        }),
        config("checkbox-events", [run$1(change(), (component, _) => {
          emitWith(component, formChangeEvent, { name: spec.name });
        })])
      ])
    });
    const pLabel = FormField.parts.label({
      dom: {
        tag: "span",
        classes: ["tox-checkbox__label"]
      },
      components: [text$1(providerBackstage.translate(spec.label))],
      behaviours: derive$1([Unselecting.config({})])
    });
    const makeIcon = (className) => {
      const iconName = className === "checked" ? "selected" : "unselected";
      return render$3(iconName, {
        tag: "span",
        classes: [
          "tox-icon",
          "tox-checkbox-icon__" + className
        ]
      }, providerBackstage.icons);
    };
    const memIcons = record({
      dom: {
        tag: "div",
        classes: ["tox-checkbox__icons"]
      },
      components: [
        makeIcon("checked"),
        makeIcon("unchecked")
      ]
    });
    return FormField.sketch({
      dom: {
        tag: "label",
        classes: ["tox-checkbox"]
      },
      components: [
        pField,
        memIcons.asSpec(),
        pLabel
      ],
      fieldBehaviours: derive$1([
        Disabling.config({
          disabled: () => !spec.enabled || providerBackstage.isDisabled(),
          disableClass: "tox-checkbox--disabled",
          onDisabled: (comp) => {
            FormField.getField(comp).each(Disabling.disable);
          },
          onEnabled: (comp) => {
            FormField.getField(comp).each(Disabling.enable);
          }
        }),
        receivingConfig()
      ])
    });
  };
  const renderHtmlPanel = (spec) => {
    if (spec.presets === "presentation") {
      return Container.sketch({
        dom: {
          tag: "div",
          classes: ["tox-form__group"],
          innerHtml: spec.html
        }
      });
    } else {
      return Container.sketch({
        dom: {
          tag: "div",
          classes: ["tox-form__group"],
          innerHtml: spec.html,
          attributes: { role: "document" }
        },
        containerBehaviours: derive$1([
          Tabstopping.config({}),
          Focusing.config({})
        ])
      });
    }
  };
  const make$2 = (render2) => {
    return (parts2, spec, dialogData, backstage) => get$g(spec, "name").fold(() => render2(spec, backstage, Optional.none()), (fieldName) => parts2.field(fieldName, render2(spec, backstage, get$g(dialogData, fieldName))));
  };
  const makeIframe = (render2) => (parts2, spec, dialogData, backstage) => {
    const iframeSpec = deepMerge(spec, { source: "dynamic" });
    return make$2(render2)(parts2, iframeSpec, dialogData, backstage);
  };
  const factories = {
    bar: make$2((spec, backstage) => renderBar(spec, backstage.shared)),
    collection: make$2((spec, backstage, data) => renderCollection(spec, backstage.shared.providers, data)),
    alertbanner: make$2((spec, backstage) => renderAlertBanner(spec, backstage.shared.providers)),
    input: make$2((spec, backstage, data) => renderInput(spec, backstage.shared.providers, data)),
    textarea: make$2((spec, backstage, data) => renderTextarea(spec, backstage.shared.providers, data)),
    label: make$2((spec, backstage) => renderLabel$1(spec, backstage.shared)),
    iframe: makeIframe((spec, backstage, data) => renderIFrame(spec, backstage.shared.providers, data)),
    button: make$2((spec, backstage) => renderDialogButton(spec, backstage.shared.providers)),
    checkbox: make$2((spec, backstage, data) => renderCheckbox(spec, backstage.shared.providers, data)),
    colorinput: make$2((spec, backstage, data) => renderColorInput(spec, backstage.shared, backstage.colorinput, data)),
    colorpicker: make$2((spec, backstage, data) => renderColorPicker(spec, backstage.shared.providers, data)),
    dropzone: make$2((spec, backstage, data) => renderDropZone(spec, backstage.shared.providers, data)),
    grid: make$2((spec, backstage) => renderGrid(spec, backstage.shared)),
    listbox: make$2((spec, backstage, data) => renderListBox(spec, backstage, data)),
    selectbox: make$2((spec, backstage, data) => renderSelectBox(spec, backstage.shared.providers, data)),
    sizeinput: make$2((spec, backstage) => renderSizeInput(spec, backstage.shared.providers)),
    slider: make$2((spec, backstage, data) => renderSlider(spec, backstage.shared.providers, data)),
    urlinput: make$2((spec, backstage, data) => renderUrlInput(spec, backstage, backstage.urlinput, data)),
    customeditor: make$2(renderCustomEditor),
    htmlpanel: make$2(renderHtmlPanel),
    imagepreview: make$2((spec, _, data) => renderImagePreview(spec, data)),
    table: make$2((spec, backstage) => renderTable(spec, backstage.shared.providers)),
    panel: make$2((spec, backstage) => renderPanel(spec, backstage))
  };
  const noFormParts = {
    field: (_name, spec) => spec,
    record: constant$1([])
  };
  const interpretInForm = (parts2, spec, dialogData, oldBackstage) => {
    const newBackstage = deepMerge(oldBackstage, { shared: { interpreter: (childSpec) => interpretParts(parts2, childSpec, dialogData, newBackstage) } });
    return interpretParts(parts2, spec, dialogData, newBackstage);
  };
  const interpretParts = (parts2, spec, dialogData, backstage) => get$g(factories, spec.type).fold(() => {
    console.error(`Unknown factory type "${spec.type}", defaulting to container: `, spec);
    return spec;
  }, (factory2) => factory2(parts2, spec, dialogData, backstage));
  const interpretWithoutForm = (spec, dialogData, backstage) => interpretParts(noFormParts, spec, dialogData, backstage);
  const labelPrefix = "layout-inset";
  const westEdgeX = (anchor2) => anchor2.x;
  const middleX = (anchor2, element2) => anchor2.x + anchor2.width / 2 - element2.width / 2;
  const eastEdgeX = (anchor2, element2) => anchor2.x + anchor2.width - element2.width;
  const northY = (anchor2) => anchor2.y;
  const southY = (anchor2, element2) => anchor2.y + anchor2.height - element2.height;
  const centreY = (anchor2, element2) => anchor2.y + anchor2.height / 2 - element2.height / 2;
  const southwest = (anchor2, element2, bubbles) => nu$6(eastEdgeX(anchor2, element2), southY(anchor2, element2), bubbles.insetSouthwest(), northwest$3(), "southwest", boundsRestriction(anchor2, {
    right: 0,
    bottom: 3
  }), labelPrefix);
  const southeast = (anchor2, element2, bubbles) => nu$6(westEdgeX(anchor2), southY(anchor2, element2), bubbles.insetSoutheast(), northeast$3(), "southeast", boundsRestriction(anchor2, {
    left: 1,
    bottom: 3
  }), labelPrefix);
  const northwest = (anchor2, element2, bubbles) => nu$6(eastEdgeX(anchor2, element2), northY(anchor2), bubbles.insetNorthwest(), southwest$3(), "northwest", boundsRestriction(anchor2, {
    right: 0,
    top: 2
  }), labelPrefix);
  const northeast = (anchor2, element2, bubbles) => nu$6(westEdgeX(anchor2), northY(anchor2), bubbles.insetNortheast(), southeast$3(), "northeast", boundsRestriction(anchor2, {
    left: 1,
    top: 2
  }), labelPrefix);
  const north = (anchor2, element2, bubbles) => nu$6(middleX(anchor2, element2), northY(anchor2), bubbles.insetNorth(), south$3(), "north", boundsRestriction(anchor2, { top: 2 }), labelPrefix);
  const south = (anchor2, element2, bubbles) => nu$6(middleX(anchor2, element2), southY(anchor2, element2), bubbles.insetSouth(), north$3(), "south", boundsRestriction(anchor2, { bottom: 3 }), labelPrefix);
  const east = (anchor2, element2, bubbles) => nu$6(eastEdgeX(anchor2, element2), centreY(anchor2, element2), bubbles.insetEast(), west$3(), "east", boundsRestriction(anchor2, { right: 0 }), labelPrefix);
  const west = (anchor2, element2, bubbles) => nu$6(westEdgeX(anchor2), centreY(anchor2, element2), bubbles.insetWest(), east$3(), "west", boundsRestriction(anchor2, { left: 1 }), labelPrefix);
  const lookupPreserveLayout = (lastPlacement) => {
    switch (lastPlacement) {
      case "north":
        return north;
      case "northeast":
        return northeast;
      case "northwest":
        return northwest;
      case "south":
        return south;
      case "southeast":
        return southeast;
      case "southwest":
        return southwest;
      case "east":
        return east;
      case "west":
        return west;
    }
  };
  const preserve = (anchor2, element2, bubbles, placee, bounds2) => {
    const layout2 = getPlacement(placee).map(lookupPreserveLayout).getOr(north);
    return layout2(anchor2, element2, bubbles, placee, bounds2);
  };
  const lookupFlippedLayout = (lastPlacement) => {
    switch (lastPlacement) {
      case "north":
        return south;
      case "northeast":
        return southeast;
      case "northwest":
        return southwest;
      case "south":
        return north;
      case "southeast":
        return northeast;
      case "southwest":
        return northwest;
      case "east":
        return west;
      case "west":
        return east;
    }
  };
  const flip = (anchor2, element2, bubbles, placee, bounds2) => {
    const layout2 = getPlacement(placee).map(lookupFlippedLayout).getOr(north);
    return layout2(anchor2, element2, bubbles, placee, bounds2);
  };
  const bubbleAlignments$2 = {
    valignCentre: [],
    alignCentre: [],
    alignLeft: [],
    alignRight: [],
    right: [],
    left: [],
    bottom: [],
    top: []
  };
  const getInlineDialogAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
    const bubbleSize2 = 12;
    const overrides = { maxHeightFunction: expandable$1() };
    const editableAreaAnchor = () => ({
      type: "node",
      root: getContentContainer(contentAreaElement()),
      node: Optional.from(contentAreaElement()),
      bubble: nu$5(bubbleSize2, bubbleSize2, bubbleAlignments$2),
      layouts: {
        onRtl: () => [northeast],
        onLtr: () => [northwest]
      },
      overrides
    });
    const standardAnchor = () => ({
      type: "hotspot",
      hotspot: lazyAnchorbar(),
      bubble: nu$5(-bubbleSize2, bubbleSize2, bubbleAlignments$2),
      layouts: {
        onRtl: () => [southeast$2],
        onLtr: () => [southwest$2]
      },
      overrides
    });
    return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  };
  const getBannerAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
    const editableAreaAnchor = () => ({
      type: "node",
      root: getContentContainer(contentAreaElement()),
      node: Optional.from(contentAreaElement()),
      layouts: {
        onRtl: () => [north],
        onLtr: () => [north]
      }
    });
    const standardAnchor = () => ({
      type: "hotspot",
      hotspot: lazyAnchorbar(),
      layouts: {
        onRtl: () => [south$2],
        onLtr: () => [south$2]
      }
    });
    return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  };
  const getCursorAnchor = (editor, bodyElement) => () => ({
    type: "selection",
    root: bodyElement(),
    getSelection: () => {
      const rng = editor.selection.getRng();
      return Optional.some(SimSelection.range(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
    }
  });
  const getNodeAnchor$1 = (bodyElement) => (element2) => ({
    type: "node",
    root: bodyElement(),
    node: element2
  });
  const getAnchors = (editor, lazyAnchorbar, isToolbarTop) => {
    const useFixedToolbarContainer = useFixedContainer(editor);
    const bodyElement = () => SugarElement.fromDom(editor.getBody());
    const contentAreaElement = () => SugarElement.fromDom(editor.getContentAreaContainer());
    const lazyUseEditableAreaAnchor = () => useFixedToolbarContainer || !isToolbarTop();
    return {
      inlineDialog: getInlineDialogAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
      banner: getBannerAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
      cursor: getCursorAnchor(editor, bodyElement),
      node: getNodeAnchor$1(bodyElement)
    };
  };
  const colorPicker = (editor) => (callback, value2) => {
    const dialog = colorPickerDialog(editor);
    dialog(callback, value2);
  };
  const hasCustomColors = (editor) => () => hasCustomColors$1(editor);
  const getColors = (editor) => () => getColors$2(editor);
  const getColorCols = (editor) => () => getColorCols$1(editor);
  const ColorInputBackstage = (editor) => ({
    colorPicker: colorPicker(editor),
    hasCustomColors: hasCustomColors(editor),
    getColors: getColors(editor),
    getColorCols: getColorCols(editor)
  });
  const isDraggableModal = (editor) => () => isDraggableModal$1(editor);
  const DialogBackstage = (editor) => ({ isDraggableModal: isDraggableModal(editor) });
  const HeaderBackstage = (editor) => {
    const mode = Cell(isToolbarLocationBottom(editor) ? "bottom" : "top");
    return {
      isPositionedAtTop: () => mode.get() === "top",
      getDockingMode: mode.get,
      setDockingMode: mode.set
    };
  };
  const defaultStyleFormats = [
    {
      title: "Headings",
      items: [
        {
          title: "Heading 1",
          format: "h1"
        },
        {
          title: "Heading 2",
          format: "h2"
        },
        {
          title: "Heading 3",
          format: "h3"
        },
        {
          title: "Heading 4",
          format: "h4"
        },
        {
          title: "Heading 5",
          format: "h5"
        },
        {
          title: "Heading 6",
          format: "h6"
        }
      ]
    },
    {
      title: "Inline",
      items: [
        {
          title: "Bold",
          format: "bold"
        },
        {
          title: "Italic",
          format: "italic"
        },
        {
          title: "Underline",
          format: "underline"
        },
        {
          title: "Strikethrough",
          format: "strikethrough"
        },
        {
          title: "Superscript",
          format: "superscript"
        },
        {
          title: "Subscript",
          format: "subscript"
        },
        {
          title: "Code",
          format: "code"
        }
      ]
    },
    {
      title: "Blocks",
      items: [
        {
          title: "Paragraph",
          format: "p"
        },
        {
          title: "Blockquote",
          format: "blockquote"
        },
        {
          title: "Div",
          format: "div"
        },
        {
          title: "Pre",
          format: "pre"
        }
      ]
    },
    {
      title: "Align",
      items: [
        {
          title: "Left",
          format: "alignleft"
        },
        {
          title: "Center",
          format: "aligncenter"
        },
        {
          title: "Right",
          format: "alignright"
        },
        {
          title: "Justify",
          format: "alignjustify"
        }
      ]
    }
  ];
  const isNestedFormat = (format) => has$2(format, "items");
  const isBlockFormat = (format) => has$2(format, "block");
  const isInlineFormat = (format) => has$2(format, "inline");
  const isSelectorFormat = (format) => has$2(format, "selector");
  const mapFormats = (userFormats) => foldl(userFormats, (acc, fmt) => {
    if (isNestedFormat(fmt)) {
      const result = mapFormats(fmt.items);
      return {
        customFormats: acc.customFormats.concat(result.customFormats),
        formats: acc.formats.concat([{
          title: fmt.title,
          items: result.formats
        }])
      };
    } else if (isInlineFormat(fmt) || isBlockFormat(fmt) || isSelectorFormat(fmt)) {
      const formatName = isString(fmt.name) ? fmt.name : fmt.title.toLowerCase();
      const formatNameWithPrefix = `custom-${formatName}`;
      return {
        customFormats: acc.customFormats.concat([{
          name: formatNameWithPrefix,
          format: fmt
        }]),
        formats: acc.formats.concat([{
          title: fmt.title,
          format: formatNameWithPrefix,
          icon: fmt.icon
        }])
      };
    } else {
      return {
        ...acc,
        formats: acc.formats.concat(fmt)
      };
    }
  }, {
    customFormats: [],
    formats: []
  });
  const registerCustomFormats = (editor, userFormats) => {
    const result = mapFormats(userFormats);
    const registerFormats = (customFormats) => {
      each$1(customFormats, (fmt) => {
        if (!editor.formatter.has(fmt.name)) {
          editor.formatter.register(fmt.name, fmt.format);
        }
      });
    };
    if (editor.formatter) {
      registerFormats(result.customFormats);
    } else {
      editor.on("init", () => {
        registerFormats(result.customFormats);
      });
    }
    return result.formats;
  };
  const getStyleFormats = (editor) => getUserStyleFormats(editor).map((userFormats) => {
    const registeredUserFormats = registerCustomFormats(editor, userFormats);
    return shouldMergeStyleFormats(editor) ? defaultStyleFormats.concat(registeredUserFormats) : registeredUserFormats;
  }).getOr(defaultStyleFormats);
  const processBasic = (item2, isSelectedFor, getPreviewFor) => {
    const formatterSpec = {
      type: "formatter",
      isSelected: isSelectedFor(item2.format),
      getStylePreview: getPreviewFor(item2.format)
    };
    return deepMerge(item2, formatterSpec);
  };
  const register$a = (editor, formats, isSelectedFor, getPreviewFor) => {
    const enrichSupported = (item2) => processBasic(item2, isSelectedFor, getPreviewFor);
    const enrichMenu = (item2) => {
      const submenuSpec = { type: "submenu" };
      return deepMerge(item2, submenuSpec);
    };
    const enrichCustom = (item2) => {
      const formatName = isString(item2.name) ? item2.name : generate$6(item2.title);
      const formatNameWithPrefix = `custom-${formatName}`;
      const customSpec = {
        type: "formatter",
        format: formatNameWithPrefix,
        isSelected: isSelectedFor(formatNameWithPrefix),
        getStylePreview: getPreviewFor(formatNameWithPrefix)
      };
      const newItem = deepMerge(item2, customSpec);
      editor.formatter.register(formatName, newItem);
      return newItem;
    };
    const doEnrich = (items) => map$2(items, (item2) => {
      const keys$1 = keys(item2);
      if (hasNonNullableKey(item2, "items")) {
        const newItems = doEnrich(item2.items);
        return deepMerge(enrichMenu(item2), { getStyleItems: constant$1(newItems) });
      } else if (hasNonNullableKey(item2, "format")) {
        return enrichSupported(item2);
      } else if (keys$1.length === 1 && contains$2(keys$1, "title")) {
        return deepMerge(item2, { type: "separator" });
      } else {
        return enrichCustom(item2);
      }
    });
    return doEnrich(formats);
  };
  const init$8 = (editor) => {
    const isSelectedFor = (format) => () => editor.formatter.match(format);
    const getPreviewFor = (format) => () => {
      const fmt = editor.formatter.get(format);
      return fmt !== void 0 ? Optional.some({
        tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || "div" : "div",
        styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
      }) : Optional.none();
    };
    const flatten2 = (fmt) => {
      const subs2 = fmt.items;
      return subs2 !== void 0 && subs2.length > 0 ? bind$3(subs2, flatten2) : [fmt.format];
    };
    const settingsFormats = Cell([]);
    const settingsFlattenedFormats = Cell([]);
    const eventsFormats = Cell([]);
    const eventsFlattenedFormats = Cell([]);
    const replaceSettings = Cell(false);
    editor.on("PreInit", (_e) => {
      const formats = getStyleFormats(editor);
      const enriched = register$a(editor, formats, isSelectedFor, getPreviewFor);
      settingsFormats.set(enriched);
      settingsFlattenedFormats.set(bind$3(enriched, flatten2));
    });
    editor.on("addStyleModifications", (e) => {
      const modifications = register$a(editor, e.items, isSelectedFor, getPreviewFor);
      eventsFormats.set(modifications);
      replaceSettings.set(e.replace);
      eventsFlattenedFormats.set(bind$3(modifications, flatten2));
    });
    const getData2 = () => {
      const fromSettings = replaceSettings.get() ? [] : settingsFormats.get();
      const fromEvents = eventsFormats.get();
      return fromSettings.concat(fromEvents);
    };
    const getFlattenedKeys = () => {
      const fromSettings = replaceSettings.get() ? [] : settingsFlattenedFormats.get();
      const fromEvents = eventsFlattenedFormats.get();
      return fromSettings.concat(fromEvents);
    };
    return {
      getData: getData2,
      getFlattenedKeys
    };
  };
  const isElement = (node) => isNonNullable(node) && node.nodeType === 1;
  const trim = global$1.trim;
  const hasContentEditableState = (value2) => {
    return (node) => {
      if (isElement(node)) {
        if (node.contentEditable === value2) {
          return true;
        }
        if (node.getAttribute("data-mce-contenteditable") === value2) {
          return true;
        }
      }
      return false;
    };
  };
  const isContentEditableTrue = hasContentEditableState("true");
  const isContentEditableFalse = hasContentEditableState("false");
  const create = (type2, title2, url, level, attach2) => {
    return {
      type: type2,
      title: title2,
      url,
      level,
      attach: attach2
    };
  };
  const isChildOfContentEditableTrue = (node) => {
    while (node = node.parentNode) {
      const value2 = node.contentEditable;
      if (value2 && value2 !== "inherit") {
        return isContentEditableTrue(node);
      }
    }
    return false;
  };
  const select = (selector, root) => {
    return map$2(descendants(SugarElement.fromDom(root), selector), (element2) => {
      return element2.dom;
    });
  };
  const getElementText = (elm) => {
    return elm.innerText || elm.textContent;
  };
  const getOrGenerateId = (elm) => {
    return elm.id ? elm.id : generate$6("h");
  };
  const isAnchor = (elm) => {
    return elm && elm.nodeName === "A" && (elm.id || elm.name) !== void 0;
  };
  const isValidAnchor = (elm) => {
    return isAnchor(elm) && isEditable(elm);
  };
  const isHeader = (elm) => {
    return elm && /^(H[1-6])$/.test(elm.nodeName);
  };
  const isEditable = (elm) => {
    return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
  };
  const isValidHeader = (elm) => {
    return isHeader(elm) && isEditable(elm);
  };
  const getLevel = (elm) => {
    return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
  };
  const headerTarget = (elm) => {
    const headerId = getOrGenerateId(elm);
    const attach2 = () => {
      elm.id = headerId;
    };
    return create("header", getElementText(elm), "#" + headerId, getLevel(elm), attach2);
  };
  const anchorTarget = (elm) => {
    const anchorId = elm.id || elm.name;
    const anchorText = getElementText(elm);
    return create("anchor", anchorText ? anchorText : "#" + anchorId, "#" + anchorId, 0, noop);
  };
  const getHeaderTargets = (elms) => {
    return map$2(filter$2(elms, isValidHeader), headerTarget);
  };
  const getAnchorTargets = (elms) => {
    return map$2(filter$2(elms, isValidAnchor), anchorTarget);
  };
  const getTargetElements = (elm) => {
    const elms = select("h1,h2,h3,h4,h5,h6,a:not([href])", elm);
    return elms;
  };
  const hasTitle = (target) => {
    return trim(target.title).length > 0;
  };
  const find = (elm) => {
    const elms = getTargetElements(elm);
    return filter$2(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
  };
  const LinkTargets = { find };
  const STORAGE_KEY = "tinymce-url-history";
  const HISTORY_LENGTH = 5;
  const isHttpUrl = (url) => isString(url) && /^https?/.test(url);
  const isArrayOfUrl = (a) => isArray(a) && a.length <= HISTORY_LENGTH && forall(a, isHttpUrl);
  const isRecordOfUrlArray = (r2) => isObject(r2) && find$4(r2, (value2) => !isArrayOfUrl(value2)).isNone();
  const getAllHistory = () => {
    const unparsedHistory = global$4.getItem(STORAGE_KEY);
    if (unparsedHistory === null) {
      return {};
    }
    let history;
    try {
      history = JSON.parse(unparsedHistory);
    } catch (e) {
      if (e instanceof SyntaxError) {
        console.log("Local storage " + STORAGE_KEY + " was not valid JSON", e);
        return {};
      }
      throw e;
    }
    if (!isRecordOfUrlArray(history)) {
      console.log("Local storage " + STORAGE_KEY + " was not valid format", history);
      return {};
    }
    return history;
  };
  const setAllHistory = (history) => {
    if (!isRecordOfUrlArray(history)) {
      throw new Error("Bad format for history:\n" + JSON.stringify(history));
    }
    global$4.setItem(STORAGE_KEY, JSON.stringify(history));
  };
  const getHistory = (fileType) => {
    const history = getAllHistory();
    return get$g(history, fileType).getOr([]);
  };
  const addToHistory = (url, fileType) => {
    if (!isHttpUrl(url)) {
      return;
    }
    const history = getAllHistory();
    const items = get$g(history, fileType).getOr([]);
    const itemsWithoutUrl = filter$2(items, (item2) => item2 !== url);
    history[fileType] = [url].concat(itemsWithoutUrl).slice(0, HISTORY_LENGTH);
    setAllHistory(history);
  };
  const isTruthy = (value2) => !!value2;
  const makeMap = (value2) => map$1(global$1.makeMap(value2, /[, ]/), isTruthy);
  const getPicker = (editor) => Optional.from(getFilePickerCallback(editor));
  const getPickerTypes = (editor) => {
    const optFileTypes = Optional.from(getFilePickerTypes(editor)).filter(isTruthy).map(makeMap);
    return getPicker(editor).fold(never, (_picker) => optFileTypes.fold(always, (types2) => keys(types2).length > 0 ? types2 : false));
  };
  const getPickerSetting = (editor, filetype) => {
    const pickerTypes = getPickerTypes(editor);
    if (isBoolean(pickerTypes)) {
      return pickerTypes ? getPicker(editor) : Optional.none();
    } else {
      return pickerTypes[filetype] ? getPicker(editor) : Optional.none();
    }
  };
  const getUrlPicker = (editor, filetype) => getPickerSetting(editor, filetype).map((picker) => (entry) => Future.nu((completer) => {
    const handler = (value2, meta2) => {
      if (!isString(value2)) {
        throw new Error("Expected value to be string");
      }
      if (meta2 !== void 0 && !isObject(meta2)) {
        throw new Error("Expected meta to be a object");
      }
      const r2 = {
        value: value2,
        meta: meta2
      };
      completer(r2);
    };
    const meta = {
      filetype,
      fieldname: entry.fieldname,
      ...Optional.from(entry.meta).getOr({})
    };
    picker.call(editor, handler, entry.value, meta);
  }));
  const getTextSetting = (value2) => Optional.from(value2).filter(isString).getOrUndefined();
  const getLinkInformation = (editor) => {
    if (!useTypeaheadUrls(editor)) {
      return Optional.none();
    }
    return Optional.some({
      targets: LinkTargets.find(editor.getBody()),
      anchorTop: getTextSetting(getAnchorTop(editor)),
      anchorBottom: getTextSetting(getAnchorBottom(editor))
    });
  };
  const getValidationHandler = (editor) => Optional.from(getFilePickerValidatorHandler(editor));
  const UrlInputBackstage = (editor) => ({
    getHistory,
    addToHistory,
    getLinkInformation: () => getLinkInformation(editor),
    getValidationHandler: () => getValidationHandler(editor),
    getUrlPicker: (filetype) => getUrlPicker(editor, filetype)
  });
  const init$7 = (lazySink, editor, lazyAnchorbar) => {
    const contextMenuState = Cell(false);
    const toolbar = HeaderBackstage(editor);
    const backstage = {
      shared: {
        providers: {
          icons: () => editor.ui.registry.getAll().icons,
          menuItems: () => editor.ui.registry.getAll().menuItems,
          translate: global$8.translate,
          isDisabled: () => editor.mode.isReadOnly() || !editor.ui.isEnabled(),
          getOption: editor.options.get
        },
        interpreter: (s) => interpretWithoutForm(s, {}, backstage),
        anchors: getAnchors(editor, lazyAnchorbar, toolbar.isPositionedAtTop),
        header: toolbar,
        getSink: lazySink
      },
      urlinput: UrlInputBackstage(editor),
      styles: init$8(editor),
      colorinput: ColorInputBackstage(editor),
      dialog: DialogBackstage(editor),
      isContextMenuOpen: () => contextMenuState.get(),
      setContextMenuState: (state) => contextMenuState.set(state)
    };
    return backstage;
  };
  const setup$b = (editor, mothership, uiMothership) => {
    const broadcastEvent = (name2, evt) => {
      each$1([
        mothership,
        uiMothership
      ], (ship) => {
        ship.broadcastEvent(name2, evt);
      });
    };
    const broadcastOn = (channel, message) => {
      each$1([
        mothership,
        uiMothership
      ], (ship) => {
        ship.broadcastOn([channel], message);
      });
    };
    const fireDismissPopups = (evt) => broadcastOn(dismissPopups(), { target: evt.target });
    const doc = getDocument();
    const onTouchstart = bind(doc, "touchstart", fireDismissPopups);
    const onTouchmove = bind(doc, "touchmove", (evt) => broadcastEvent(documentTouchmove(), evt));
    const onTouchend = bind(doc, "touchend", (evt) => broadcastEvent(documentTouchend(), evt));
    const onMousedown = bind(doc, "mousedown", fireDismissPopups);
    const onMouseup = bind(doc, "mouseup", (evt) => {
      if (evt.raw.button === 0) {
        broadcastOn(mouseReleased(), { target: evt.target });
      }
    });
    const onContentClick = (raw) => broadcastOn(dismissPopups(), { target: SugarElement.fromDom(raw.target) });
    const onContentMouseup = (raw) => {
      if (raw.button === 0) {
        broadcastOn(mouseReleased(), { target: SugarElement.fromDom(raw.target) });
      }
    };
    const onContentMousedown = () => {
      each$1(editor.editorManager.get(), (loopEditor) => {
        if (editor !== loopEditor) {
          loopEditor.dispatch("DismissPopups", { relatedTarget: editor });
        }
      });
    };
    const onWindowScroll = (evt) => broadcastEvent(windowScroll(), fromRawEvent(evt));
    const onWindowResize = (evt) => {
      broadcastOn(repositionPopups(), {});
      broadcastEvent(windowResize(), fromRawEvent(evt));
    };
    const onEditorResize = () => broadcastOn(repositionPopups(), {});
    const onEditorProgress = (evt) => {
      if (evt.state) {
        broadcastOn(dismissPopups(), { target: SugarElement.fromDom(editor.getContainer()) });
      }
    };
    const onDismissPopups = (event) => {
      broadcastOn(dismissPopups(), { target: SugarElement.fromDom(event.relatedTarget.getContainer()) });
    };
    editor.on("PostRender", () => {
      editor.on("click", onContentClick);
      editor.on("tap", onContentClick);
      editor.on("mouseup", onContentMouseup);
      editor.on("mousedown", onContentMousedown);
      editor.on("ScrollWindow", onWindowScroll);
      editor.on("ResizeWindow", onWindowResize);
      editor.on("ResizeEditor", onEditorResize);
      editor.on("AfterProgressState", onEditorProgress);
      editor.on("DismissPopups", onDismissPopups);
    });
    editor.on("remove", () => {
      editor.off("click", onContentClick);
      editor.off("tap", onContentClick);
      editor.off("mouseup", onContentMouseup);
      editor.off("mousedown", onContentMousedown);
      editor.off("ScrollWindow", onWindowScroll);
      editor.off("ResizeWindow", onWindowResize);
      editor.off("ResizeEditor", onEditorResize);
      editor.off("AfterProgressState", onEditorProgress);
      editor.off("DismissPopups", onDismissPopups);
      onMousedown.unbind();
      onTouchstart.unbind();
      onTouchmove.unbind();
      onTouchend.unbind();
      onMouseup.unbind();
    });
    editor.on("detach", () => {
      detachSystem(mothership);
      detachSystem(uiMothership);
      mothership.destroy();
      uiMothership.destroy();
    });
  };
  const parts$a = AlloyParts;
  const partType = PartType;
  const schema$f = constant$1([
    defaulted("shell", false),
    required$1("makeItem"),
    defaulted("setupItem", noop),
    SketchBehaviours.field("listBehaviours", [Replacing])
  ]);
  const customListDetail = () => ({ behaviours: derive$1([Replacing.config({})]) });
  const itemsPart = optional({
    name: "items",
    overrides: customListDetail
  });
  const parts$9 = constant$1([itemsPart]);
  const name = constant$1("CustomList");
  const factory$d = (detail, components2, _spec, _external) => {
    const setItems = (list, items) => {
      getListContainer(list).fold(() => {
        console.error("Custom List was defined to not be a shell, but no item container was specified in components");
        throw new Error("Custom List was defined to not be a shell, but no item container was specified in components");
      }, (container) => {
        const itemComps = Replacing.contents(container);
        const numListsRequired = items.length;
        const numListsToAdd = numListsRequired - itemComps.length;
        const itemsToAdd = numListsToAdd > 0 ? range$2(numListsToAdd, () => detail.makeItem()) : [];
        const itemsToRemove = itemComps.slice(numListsRequired);
        each$1(itemsToRemove, (item2) => Replacing.remove(container, item2));
        each$1(itemsToAdd, (item2) => Replacing.append(container, item2));
        const builtLists = Replacing.contents(container);
        each$1(builtLists, (item2, i) => {
          detail.setupItem(list, item2, items[i], i);
        });
      });
    };
    const extra = detail.shell ? {
      behaviours: [Replacing.config({})],
      components: []
    } : {
      behaviours: [],
      components: components2
    };
    const getListContainer = (component) => detail.shell ? Optional.some(component) : getPart(component, detail, "items");
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: extra.components,
      behaviours: augment(detail.listBehaviours, extra.behaviours),
      apis: { setItems }
    };
  };
  const CustomList = composite({
    name: name(),
    configFields: schema$f(),
    partFields: parts$9(),
    factory: factory$d,
    apis: {
      setItems: (apis, list, items) => {
        apis.setItems(list, items);
      }
    }
  });
  const schema$e = constant$1([
    required$1("dom"),
    defaulted("shell", true),
    field("toolbarBehaviours", [Replacing])
  ]);
  const enhanceGroups = () => ({ behaviours: derive$1([Replacing.config({})]) });
  const parts$8 = constant$1([optional({
    name: "groups",
    overrides: enhanceGroups
  })]);
  const factory$c = (detail, components2, _spec, _externals) => {
    const setGroups2 = (toolbar, groups) => {
      getGroupContainer(toolbar).fold(() => {
        console.error("Toolbar was defined to not be a shell, but no groups container was specified in components");
        throw new Error("Toolbar was defined to not be a shell, but no groups container was specified in components");
      }, (container) => {
        Replacing.set(container, groups);
      });
    };
    const getGroupContainer = (component) => detail.shell ? Optional.some(component) : getPart(component, detail, "groups");
    const extra = detail.shell ? {
      behaviours: [Replacing.config({})],
      components: []
    } : {
      behaviours: [],
      components: components2
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: extra.components,
      behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
      apis: { setGroups: setGroups2 },
      domModification: { attributes: { role: "group" } }
    };
  };
  const Toolbar = composite({
    name: "Toolbar",
    configFields: schema$e(),
    partFields: parts$8(),
    factory: factory$c,
    apis: {
      setGroups: (apis, toolbar, groups) => {
        apis.setGroups(toolbar, groups);
      }
    }
  });
  const setup$a = noop;
  const isDocked$2 = never;
  const getBehaviours$1 = constant$1([]);
  var StaticHeader = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    setup: setup$a,
    isDocked: isDocked$2,
    getBehaviours: getBehaviours$1
  });
  const getOffsetParent = (element2) => {
    const isFixed = is$1(getRaw(element2, "position"), "fixed");
    const offsetParent$1 = isFixed ? Optional.none() : offsetParent(element2);
    return offsetParent$1.orThunk(() => {
      const marker = SugarElement.fromTag("span");
      return parent(element2).bind((parent2) => {
        append$2(parent2, marker);
        const offsetParent$12 = offsetParent(marker);
        remove$5(marker);
        return offsetParent$12;
      });
    });
  };
  const getOrigin = (element2) => getOffsetParent(element2).map(absolute$3).getOrThunk(() => SugarPosition(0, 0));
  const morphAdt = Adt.generate([
    { static: [] },
    { absolute: ["positionCss"] },
    { fixed: ["positionCss"] }
  ]);
  const appear = (component, contextualInfo) => {
    const elem = component.element;
    add$2(elem, contextualInfo.transitionClass);
    remove$2(elem, contextualInfo.fadeOutClass);
    add$2(elem, contextualInfo.fadeInClass);
    contextualInfo.onShow(component);
  };
  const disappear = (component, contextualInfo) => {
    const elem = component.element;
    add$2(elem, contextualInfo.transitionClass);
    remove$2(elem, contextualInfo.fadeInClass);
    add$2(elem, contextualInfo.fadeOutClass);
    contextualInfo.onHide(component);
  };
  const isPartiallyVisible = (box2, viewport2) => box2.y < viewport2.bottom && box2.bottom > viewport2.y;
  const isTopCompletelyVisible = (box2, viewport2) => box2.y >= viewport2.y;
  const isBottomCompletelyVisible = (box2, viewport2) => box2.bottom <= viewport2.bottom;
  const isVisibleForModes = (modes, box2, viewport2) => forall(modes, (mode) => {
    switch (mode) {
      case "bottom":
        return isBottomCompletelyVisible(box2, viewport2);
      case "top":
        return isTopCompletelyVisible(box2, viewport2);
    }
  });
  const getPrior = (elem, state) => state.getInitialPos().map((pos) => bounds(pos.bounds.x, pos.bounds.y, get$c(elem), get$d(elem)));
  const storePrior = (elem, box2, state) => {
    state.setInitialPos({
      style: getAllRaw(elem),
      position: get$e(elem, "position") || "static",
      bounds: box2
    });
  };
  const revertToOriginal = (elem, box2, state) => state.getInitialPos().bind((position2) => {
    state.clearInitialPos();
    switch (position2.position) {
      case "static":
        return Optional.some(morphAdt.static());
      case "absolute":
        const offsetBox = getOffsetParent(elem).map(box$1).getOrThunk(() => box$1(body()));
        return Optional.some(morphAdt.absolute(NuPositionCss("absolute", get$g(position2.style, "left").map((_left) => box2.x - offsetBox.x), get$g(position2.style, "top").map((_top) => box2.y - offsetBox.y), get$g(position2.style, "right").map((_right) => offsetBox.right - box2.right), get$g(position2.style, "bottom").map((_bottom) => offsetBox.bottom - box2.bottom))));
      default:
        return Optional.none();
    }
  });
  const morphToOriginal = (elem, viewport2, state) => getPrior(elem, state).filter((box2) => isVisibleForModes(state.getModes(), box2, viewport2)).bind((box2) => revertToOriginal(elem, box2, state));
  const morphToFixed = (elem, viewport2, state) => {
    const box2 = box$1(elem);
    if (!isVisibleForModes(state.getModes(), box2, viewport2)) {
      storePrior(elem, box2, state);
      const winBox = win();
      const left2 = box2.x - winBox.x;
      const top2 = viewport2.y - winBox.y;
      const bottom2 = winBox.bottom - viewport2.bottom;
      const isTop = box2.y <= viewport2.y;
      return Optional.some(morphAdt.fixed(NuPositionCss("fixed", Optional.some(left2), isTop ? Optional.some(top2) : Optional.none(), Optional.none(), !isTop ? Optional.some(bottom2) : Optional.none())));
    } else {
      return Optional.none();
    }
  };
  const getMorph = (component, viewport2, state) => {
    const elem = component.element;
    const isDocked2 = is$1(getRaw(elem, "position"), "fixed");
    return isDocked2 ? morphToOriginal(elem, viewport2, state) : morphToFixed(elem, viewport2, state);
  };
  const getMorphToOriginal = (component, state) => {
    const elem = component.element;
    return getPrior(elem, state).bind((box2) => revertToOriginal(elem, box2, state));
  };
  const morphToStatic = (component, config2, state) => {
    state.setDocked(false);
    each$1([
      "left",
      "right",
      "top",
      "bottom",
      "position"
    ], (prop) => remove$6(component.element, prop));
    config2.onUndocked(component);
  };
  const morphToCoord = (component, config2, state, position2) => {
    const isDocked2 = position2.position === "fixed";
    state.setDocked(isDocked2);
    applyPositionCss(component.element, position2);
    const method = isDocked2 ? config2.onDocked : config2.onUndocked;
    method(component);
  };
  const updateVisibility = (component, config2, state, viewport2, morphToDocked = false) => {
    config2.contextual.each((contextInfo) => {
      contextInfo.lazyContext(component).each((box2) => {
        const isVisible2 = isPartiallyVisible(box2, viewport2);
        if (isVisible2 !== state.isVisible()) {
          state.setVisible(isVisible2);
          if (morphToDocked && !isVisible2) {
            add$1(component.element, [contextInfo.fadeOutClass]);
            contextInfo.onHide(component);
          } else {
            const method = isVisible2 ? appear : disappear;
            method(component, contextInfo);
          }
        }
      });
    });
  };
  const refreshInternal = (component, config2, state) => {
    const viewport2 = config2.lazyViewport(component);
    const isDocked2 = state.isDocked();
    if (isDocked2) {
      updateVisibility(component, config2, state, viewport2);
    }
    getMorph(component, viewport2, state).each((morph) => {
      morph.fold(() => morphToStatic(component, config2, state), (position2) => morphToCoord(component, config2, state, position2), (position2) => {
        updateVisibility(component, config2, state, viewport2, true);
        morphToCoord(component, config2, state, position2);
      });
    });
  };
  const resetInternal = (component, config2, state) => {
    const elem = component.element;
    state.setDocked(false);
    getMorphToOriginal(component, state).each((morph) => {
      morph.fold(() => morphToStatic(component, config2, state), (position2) => morphToCoord(component, config2, state, position2), noop);
    });
    state.setVisible(true);
    config2.contextual.each((contextInfo) => {
      remove$1(elem, [
        contextInfo.fadeInClass,
        contextInfo.fadeOutClass,
        contextInfo.transitionClass
      ]);
      contextInfo.onShow(component);
    });
    refresh$4(component, config2, state);
  };
  const refresh$4 = (component, config2, state) => {
    if (component.getSystem().isConnected()) {
      refreshInternal(component, config2, state);
    }
  };
  const reset = (component, config2, state) => {
    if (state.isDocked()) {
      resetInternal(component, config2, state);
    }
  };
  const isDocked$1 = (component, config2, state) => state.isDocked();
  const setModes = (component, config2, state, modes) => state.setModes(modes);
  const getModes = (component, config2, state) => state.getModes();
  var DockingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    refresh: refresh$4,
    reset,
    isDocked: isDocked$1,
    getModes,
    setModes
  });
  const events$5 = (dockInfo, dockState) => derive$2([
    runOnSource(transitionend(), (component, simulatedEvent) => {
      dockInfo.contextual.each((contextInfo) => {
        if (has(component.element, contextInfo.transitionClass)) {
          remove$1(component.element, [
            contextInfo.transitionClass,
            contextInfo.fadeInClass
          ]);
          const notify = dockState.isVisible() ? contextInfo.onShown : contextInfo.onHidden;
          notify(component);
        }
        simulatedEvent.stop();
      });
    }),
    run$1(windowScroll(), (component, _) => {
      refresh$4(component, dockInfo, dockState);
    }),
    run$1(windowResize(), (component, _) => {
      reset(component, dockInfo, dockState);
    })
  ]);
  var ActiveDocking = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$5
  });
  var DockingSchema = [
    optionObjOf("contextual", [
      requiredString("fadeInClass"),
      requiredString("fadeOutClass"),
      requiredString("transitionClass"),
      requiredFunction("lazyContext"),
      onHandler("onShow"),
      onHandler("onShown"),
      onHandler("onHide"),
      onHandler("onHidden")
    ]),
    defaultedFunction("lazyViewport", win),
    defaultedArrayOf("modes", [
      "top",
      "bottom"
    ], string),
    onHandler("onDocked"),
    onHandler("onUndocked")
  ];
  const init$6 = (spec) => {
    const docked = Cell(false);
    const visible = Cell(true);
    const initialBounds = value$2();
    const modes = Cell(spec.modes);
    const readState = () => `docked:  ${docked.get()}, visible: ${visible.get()}, modes: ${modes.get().join(",")}`;
    return nu$8({
      isDocked: docked.get,
      setDocked: docked.set,
      getInitialPos: initialBounds.get,
      setInitialPos: initialBounds.set,
      clearInitialPos: initialBounds.clear,
      isVisible: visible.get,
      setVisible: visible.set,
      getModes: modes.get,
      setModes: modes.set,
      readState
    });
  };
  var DockingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$6
  });
  const Docking = create$3({
    fields: DockingSchema,
    name: "docking",
    active: ActiveDocking,
    apis: DockingApis,
    state: DockingState
  });
  const toolbarHeightChange = constant$1(generate$6("toolbar-height-change"));
  const visibility = {
    fadeInClass: "tox-editor-dock-fadein",
    fadeOutClass: "tox-editor-dock-fadeout",
    transitionClass: "tox-editor-dock-transition"
  };
  const editorStickyOnClass = "tox-tinymce--toolbar-sticky-on";
  const editorStickyOffClass = "tox-tinymce--toolbar-sticky-off";
  const scrollFromBehindHeader = (e, containerHeader) => {
    const doc = owner$4(containerHeader);
    const viewHeight = doc.dom.defaultView.innerHeight;
    const scrollPos = get$b(doc);
    const markerElement = SugarElement.fromDom(e.elm);
    const markerPos = absolute$2(markerElement);
    const markerHeight = get$d(markerElement);
    const markerTop = markerPos.y;
    const markerBottom = markerTop + markerHeight;
    const editorHeaderPos = absolute$3(containerHeader);
    const editorHeaderHeight = get$d(containerHeader);
    const editorHeaderTop = editorHeaderPos.top;
    const editorHeaderBottom = editorHeaderTop + editorHeaderHeight;
    const editorHeaderDockedAtTop = Math.abs(editorHeaderTop - scrollPos.top) < 2;
    const editorHeaderDockedAtBottom = Math.abs(editorHeaderBottom - (scrollPos.top + viewHeight)) < 2;
    if (editorHeaderDockedAtTop && markerTop < editorHeaderBottom) {
      to(scrollPos.left, markerTop - editorHeaderHeight, doc);
    } else if (editorHeaderDockedAtBottom && markerBottom > editorHeaderTop) {
      const y = markerTop - viewHeight + markerHeight + editorHeaderHeight;
      to(scrollPos.left, y, doc);
    }
  };
  const isDockedMode = (header, mode) => contains$2(Docking.getModes(header), mode);
  const updateIframeContentFlow = (header) => {
    const getOccupiedHeight = (elm2) => getOuter$2(elm2) + (parseInt(get$e(elm2, "margin-top"), 10) || 0) + (parseInt(get$e(elm2, "margin-bottom"), 10) || 0);
    const elm = header.element;
    parent(elm).each((parentElem) => {
      const padding = "padding-" + Docking.getModes(header)[0];
      if (Docking.isDocked(header)) {
        const parentWidth = get$c(parentElem);
        set$8(elm, "width", parentWidth + "px");
        set$8(parentElem, padding, getOccupiedHeight(elm) + "px");
      } else {
        remove$6(elm, "width");
        remove$6(parentElem, padding);
      }
    });
  };
  const updateSinkVisibility = (sinkElem, visible) => {
    if (visible) {
      remove$2(sinkElem, visibility.fadeOutClass);
      add$1(sinkElem, [
        visibility.transitionClass,
        visibility.fadeInClass
      ]);
    } else {
      remove$2(sinkElem, visibility.fadeInClass);
      add$1(sinkElem, [
        visibility.fadeOutClass,
        visibility.transitionClass
      ]);
    }
  };
  const updateEditorClasses = (editor, docked) => {
    const editorContainer = SugarElement.fromDom(editor.getContainer());
    if (docked) {
      add$2(editorContainer, editorStickyOnClass);
      remove$2(editorContainer, editorStickyOffClass);
    } else {
      add$2(editorContainer, editorStickyOffClass);
      remove$2(editorContainer, editorStickyOnClass);
    }
  };
  const restoreFocus = (headerElem, focusedElem) => {
    const ownerDoc = owner$4(focusedElem);
    active$1(ownerDoc).filter((activeElm) => !eq(focusedElem, activeElm)).filter((activeElm) => eq(activeElm, SugarElement.fromDom(ownerDoc.dom.body)) || contains(headerElem, activeElm)).each(() => focus$3(focusedElem));
  };
  const findFocusedElem = (rootElm, lazySink) => search(rootElm).orThunk(() => lazySink().toOptional().bind((sink) => search(sink.element)));
  const setup$9 = (editor, sharedBackstage, lazyHeader) => {
    if (!editor.inline) {
      if (!sharedBackstage.header.isPositionedAtTop()) {
        editor.on("ResizeEditor", () => {
          lazyHeader().each(Docking.reset);
        });
      }
      editor.on("ResizeWindow ResizeEditor", () => {
        lazyHeader().each(updateIframeContentFlow);
      });
      editor.on("SkinLoaded", () => {
        lazyHeader().each((comp) => {
          Docking.isDocked(comp) ? Docking.reset(comp) : Docking.refresh(comp);
        });
      });
      editor.on("FullscreenStateChanged", () => {
        lazyHeader().each(Docking.reset);
      });
    }
    editor.on("AfterScrollIntoView", (e) => {
      lazyHeader().each((header) => {
        Docking.refresh(header);
        const headerElem = header.element;
        if (isVisible(headerElem)) {
          scrollFromBehindHeader(e, headerElem);
        }
      });
    });
    editor.on("PostRender", () => {
      updateEditorClasses(editor, false);
    });
  };
  const isDocked = (lazyHeader) => lazyHeader().map(Docking.isDocked).getOr(false);
  const getIframeBehaviours = () => [Receiving.config({ channels: { [toolbarHeightChange()]: { onReceive: updateIframeContentFlow } } })];
  const getBehaviours = (editor, sharedBackstage) => {
    const focusedElm = value$2();
    const lazySink = sharedBackstage.getSink;
    const runOnSinkElement = (f) => {
      lazySink().each((sink) => f(sink.element));
    };
    const onDockingSwitch = (comp) => {
      if (!editor.inline) {
        updateIframeContentFlow(comp);
      }
      updateEditorClasses(editor, Docking.isDocked(comp));
      comp.getSystem().broadcastOn([repositionPopups()], {});
      lazySink().each((sink) => sink.getSystem().broadcastOn([repositionPopups()], {}));
    };
    const additionalBehaviours = editor.inline ? [] : getIframeBehaviours();
    return [
      Focusing.config({}),
      Docking.config({
        contextual: {
          lazyContext: (comp) => {
            const headerHeight = getOuter$2(comp.element);
            const container = editor.inline ? editor.getContentAreaContainer() : editor.getContainer();
            const box2 = box$1(SugarElement.fromDom(container));
            const boxHeight = box2.height - headerHeight;
            const topBound = box2.y + (isDockedMode(comp, "top") ? 0 : headerHeight);
            return Optional.some(bounds(box2.x, topBound, box2.width, boxHeight));
          },
          onShow: () => {
            runOnSinkElement((elem) => updateSinkVisibility(elem, true));
          },
          onShown: (comp) => {
            runOnSinkElement((elem) => remove$1(elem, [
              visibility.transitionClass,
              visibility.fadeInClass
            ]));
            focusedElm.get().each((elem) => {
              restoreFocus(comp.element, elem);
              focusedElm.clear();
            });
          },
          onHide: (comp) => {
            findFocusedElem(comp.element, lazySink).fold(focusedElm.clear, focusedElm.set);
            runOnSinkElement((elem) => updateSinkVisibility(elem, false));
          },
          onHidden: () => {
            runOnSinkElement((elem) => remove$1(elem, [visibility.transitionClass]));
          },
          ...visibility
        },
        lazyViewport: (comp) => {
          const win$1 = win();
          const offset2 = getStickyToolbarOffset(editor);
          const top2 = win$1.y + (isDockedMode(comp, "top") ? offset2 : 0);
          const height2 = win$1.height - (isDockedMode(comp, "bottom") ? offset2 : 0);
          return bounds(win$1.x, top2, win$1.width, height2);
        },
        modes: [sharedBackstage.header.getDockingMode()],
        onDocked: onDockingSwitch,
        onUndocked: onDockingSwitch
      }),
      ...additionalBehaviours
    ];
  };
  var StickyHeader = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    setup: setup$9,
    isDocked,
    getBehaviours
  });
  const renderHeader = (spec) => {
    const editor = spec.editor;
    const getBehaviours$22 = spec.sticky ? getBehaviours : getBehaviours$1;
    return {
      uid: spec.uid,
      dom: spec.dom,
      components: spec.components,
      behaviours: derive$1(getBehaviours$22(editor, spec.sharedBackstage))
    };
  };
  const groupToolbarButtonSchema = objOf([
    type,
    requiredOf("items", oneOf([
      arrOfObj([
        name$1,
        requiredArrayOf("items", string)
      ]),
      string
    ]))
  ].concat(baseToolbarButtonFields));
  const createGroupToolbarButton = (spec) => asRaw("GroupToolbarButton", groupToolbarButtonSchema, spec);
  const baseMenuButtonFields = [
    optionString("text"),
    optionString("tooltip"),
    optionString("icon"),
    requiredFunction("fetch"),
    defaultedFunction("onSetup", () => noop)
  ];
  const MenuButtonSchema = objOf([
    type,
    ...baseMenuButtonFields
  ]);
  const createMenuButton = (spec) => asRaw("menubutton", MenuButtonSchema, spec);
  const splitButtonSchema = objOf([
    type,
    optionalTooltip,
    optionalIcon,
    optionalText,
    optionalSelect,
    fetch$1,
    onSetup,
    defaultedStringEnum("presets", "normal", [
      "normal",
      "color",
      "listpreview"
    ]),
    defaultedColumns(1),
    onAction,
    onItemAction
  ]);
  const createSplitButton = (spec) => asRaw("SplitButton", splitButtonSchema, spec);
  const factory$b = (detail, spec) => {
    const setMenus = (comp, menus) => {
      const newMenus = map$2(menus, (m) => {
        const buttonSpec = {
          type: "menubutton",
          text: m.text,
          fetch: (callback) => {
            callback(m.getItems());
          }
        };
        const internal = createMenuButton(buttonSpec).mapError((errInfo) => formatError(errInfo)).getOrDie();
        return renderMenuButton(internal, "tox-mbtn", spec.backstage, Optional.some("menuitem"));
      });
      Replacing.set(comp, newMenus);
    };
    const apis = {
      focus: Keying.focusIn,
      setMenus
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: [],
      behaviours: derive$1([
        Replacing.config({}),
        config("menubar-events", [
          runOnAttached((component) => {
            detail.onSetup(component);
          }),
          run$1(mouseover(), (comp, se) => {
            descendant(comp.element, ".tox-mbtn--active").each((activeButton) => {
              closest$1(se.event.target, ".tox-mbtn").each((hoveredButton) => {
                if (!eq(activeButton, hoveredButton)) {
                  comp.getSystem().getByDom(activeButton).each((activeComp) => {
                    comp.getSystem().getByDom(hoveredButton).each((hoveredComp) => {
                      Dropdown.expand(hoveredComp);
                      Dropdown.close(activeComp);
                      Focusing.focus(hoveredComp);
                    });
                  });
                }
              });
            });
          }),
          run$1(focusShifted(), (comp, se) => {
            se.event.prevFocus.bind((prev) => comp.getSystem().getByDom(prev).toOptional()).each((prev) => {
              se.event.newFocus.bind((nu2) => comp.getSystem().getByDom(nu2).toOptional()).each((nu2) => {
                if (Dropdown.isOpen(prev)) {
                  Dropdown.expand(nu2);
                  Dropdown.close(prev);
                }
              });
            });
          })
        ]),
        Keying.config({
          mode: "flow",
          selector: ".tox-mbtn",
          onEscape: (comp) => {
            detail.onEscape(comp);
            return Optional.some(true);
          }
        }),
        Tabstopping.config({})
      ]),
      apis,
      domModification: { attributes: { role: "menubar" } }
    };
  };
  var SilverMenubar = single({
    factory: factory$b,
    name: "silver.Menubar",
    configFields: [
      required$1("dom"),
      required$1("uid"),
      required$1("onEscape"),
      required$1("backstage"),
      defaulted("onSetup", noop)
    ],
    apis: {
      focus: (apis, comp) => {
        apis.focus(comp);
      },
      setMenus: (apis, comp, menus) => {
        apis.setMenus(comp, menus);
      }
    }
  });
  const getAnimationRoot = (component, slideConfig) => slideConfig.getAnimationRoot.fold(() => component.element, (get2) => get2(component));
  const getDimensionProperty = (slideConfig) => slideConfig.dimension.property;
  const getDimension = (slideConfig, elem) => slideConfig.dimension.getDimension(elem);
  const disableTransitions = (component, slideConfig) => {
    const root = getAnimationRoot(component, slideConfig);
    remove$1(root, [
      slideConfig.shrinkingClass,
      slideConfig.growingClass
    ]);
  };
  const setShrunk = (component, slideConfig) => {
    remove$2(component.element, slideConfig.openClass);
    add$2(component.element, slideConfig.closedClass);
    set$8(component.element, getDimensionProperty(slideConfig), "0px");
    reflow(component.element);
  };
  const setGrown = (component, slideConfig) => {
    remove$2(component.element, slideConfig.closedClass);
    add$2(component.element, slideConfig.openClass);
    remove$6(component.element, getDimensionProperty(slideConfig));
  };
  const doImmediateShrink = (component, slideConfig, slideState, _calculatedSize) => {
    slideState.setCollapsed();
    set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
    disableTransitions(component, slideConfig);
    setShrunk(component, slideConfig);
    slideConfig.onStartShrink(component);
    slideConfig.onShrunk(component);
  };
  const doStartShrink = (component, slideConfig, slideState, calculatedSize) => {
    const size = calculatedSize.getOrThunk(() => getDimension(slideConfig, component.element));
    slideState.setCollapsed();
    set$8(component.element, getDimensionProperty(slideConfig), size);
    reflow(component.element);
    const root = getAnimationRoot(component, slideConfig);
    remove$2(root, slideConfig.growingClass);
    add$2(root, slideConfig.shrinkingClass);
    setShrunk(component, slideConfig);
    slideConfig.onStartShrink(component);
  };
  const doStartSmartShrink = (component, slideConfig, slideState) => {
    const size = getDimension(slideConfig, component.element);
    const shrinker = size === "0px" ? doImmediateShrink : doStartShrink;
    shrinker(component, slideConfig, slideState, Optional.some(size));
  };
  const doStartGrow = (component, slideConfig, slideState) => {
    const root = getAnimationRoot(component, slideConfig);
    const wasShrinking = has(root, slideConfig.shrinkingClass);
    const beforeSize = getDimension(slideConfig, component.element);
    setGrown(component, slideConfig);
    const fullSize = getDimension(slideConfig, component.element);
    const startPartialGrow = () => {
      set$8(component.element, getDimensionProperty(slideConfig), beforeSize);
      reflow(component.element);
    };
    const startCompleteGrow = () => {
      setShrunk(component, slideConfig);
    };
    const setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow;
    setStartSize();
    remove$2(root, slideConfig.shrinkingClass);
    add$2(root, slideConfig.growingClass);
    setGrown(component, slideConfig);
    set$8(component.element, getDimensionProperty(slideConfig), fullSize);
    slideState.setExpanded();
    slideConfig.onStartGrow(component);
  };
  const refresh$3 = (component, slideConfig, slideState) => {
    if (slideState.isExpanded()) {
      remove$6(component.element, getDimensionProperty(slideConfig));
      const fullSize = getDimension(slideConfig, component.element);
      set$8(component.element, getDimensionProperty(slideConfig), fullSize);
    }
  };
  const grow = (component, slideConfig, slideState) => {
    if (!slideState.isExpanded()) {
      doStartGrow(component, slideConfig, slideState);
    }
  };
  const shrink = (component, slideConfig, slideState) => {
    if (slideState.isExpanded()) {
      doStartSmartShrink(component, slideConfig, slideState);
    }
  };
  const immediateShrink = (component, slideConfig, slideState) => {
    if (slideState.isExpanded()) {
      doImmediateShrink(component, slideConfig, slideState);
    }
  };
  const hasGrown = (component, slideConfig, slideState) => slideState.isExpanded();
  const hasShrunk = (component, slideConfig, slideState) => slideState.isCollapsed();
  const isGrowing = (component, slideConfig, _slideState) => {
    const root = getAnimationRoot(component, slideConfig);
    return has(root, slideConfig.growingClass) === true;
  };
  const isShrinking = (component, slideConfig, _slideState) => {
    const root = getAnimationRoot(component, slideConfig);
    return has(root, slideConfig.shrinkingClass) === true;
  };
  const isTransitioning = (component, slideConfig, slideState) => isGrowing(component, slideConfig) || isShrinking(component, slideConfig);
  const toggleGrow = (component, slideConfig, slideState) => {
    const f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow;
    f(component, slideConfig, slideState);
  };
  const immediateGrow = (component, slideConfig, slideState) => {
    if (!slideState.isExpanded()) {
      setGrown(component, slideConfig);
      set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
      disableTransitions(component, slideConfig);
      slideState.setExpanded();
      slideConfig.onStartGrow(component);
      slideConfig.onGrown(component);
    }
  };
  var SlidingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    refresh: refresh$3,
    grow,
    shrink,
    immediateShrink,
    hasGrown,
    hasShrunk,
    isGrowing,
    isShrinking,
    isTransitioning,
    toggleGrow,
    disableTransitions,
    immediateGrow
  });
  const exhibit = (base2, slideConfig, _slideState) => {
    const expanded = slideConfig.expanded;
    return expanded ? nu$7({
      classes: [slideConfig.openClass],
      styles: {}
    }) : nu$7({
      classes: [slideConfig.closedClass],
      styles: wrap$1(slideConfig.dimension.property, "0px")
    });
  };
  const events$4 = (slideConfig, slideState) => derive$2([runOnSource(transitionend(), (component, simulatedEvent) => {
    const raw = simulatedEvent.event.raw;
    if (raw.propertyName === slideConfig.dimension.property) {
      disableTransitions(component, slideConfig);
      if (slideState.isExpanded()) {
        remove$6(component.element, slideConfig.dimension.property);
      }
      const notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk;
      notify(component);
    }
  })]);
  var ActiveSliding = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    exhibit,
    events: events$4
  });
  var SlidingSchema = [
    required$1("closedClass"),
    required$1("openClass"),
    required$1("shrinkingClass"),
    required$1("growingClass"),
    option$3("getAnimationRoot"),
    onHandler("onShrunk"),
    onHandler("onStartShrink"),
    onHandler("onGrown"),
    onHandler("onStartGrow"),
    defaulted("expanded", false),
    requiredOf("dimension", choose$1("property", {
      width: [
        output$1("property", "width"),
        output$1("getDimension", (elem) => get$c(elem) + "px")
      ],
      height: [
        output$1("property", "height"),
        output$1("getDimension", (elem) => get$d(elem) + "px")
      ]
    }))
  ];
  const init$5 = (spec) => {
    const state = Cell(spec.expanded);
    const readState = () => "expanded: " + state.get();
    return nu$8({
      isExpanded: () => state.get() === true,
      isCollapsed: () => state.get() === false,
      setCollapsed: curry(state.set, false),
      setExpanded: curry(state.set, true),
      readState
    });
  };
  var SlidingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$5
  });
  const Sliding = create$3({
    fields: SlidingSchema,
    name: "sliding",
    active: ActiveSliding,
    apis: SlidingApis,
    state: SlidingState
  });
  const owner = "container";
  const schema$d = [field("slotBehaviours", [])];
  const getPartName = (name2) => "<alloy.field." + name2 + ">";
  const sketch = (sSpec) => {
    const parts2 = (() => {
      const record2 = [];
      const slot = (name2, config2) => {
        record2.push(name2);
        return generateOne$1(owner, getPartName(name2), config2);
      };
      return {
        slot,
        record: constant$1(record2)
      };
    })();
    const spec = sSpec(parts2);
    const partNames = parts2.record();
    const fieldParts = map$2(partNames, (n) => required({
      name: n,
      pname: getPartName(n)
    }));
    return composite$1(owner, schema$d, fieldParts, make$1, spec);
  };
  const make$1 = (detail, components2) => {
    const getSlotNames = (_) => getAllPartNames(detail);
    const getSlot = (container, key) => getPart(container, detail, key);
    const onSlot = (f, def) => (container, key) => getPart(container, detail, key).map((slot) => f(slot, key)).getOr(def);
    const onSlots = (f) => (container, keys2) => {
      each$1(keys2, (key) => f(container, key));
    };
    const doShowing = (comp, _key) => get$f(comp.element, "aria-hidden") !== "true";
    const doShow = (comp, key) => {
      if (!doShowing(comp)) {
        const element2 = comp.element;
        remove$6(element2, "display");
        remove$7(element2, "aria-hidden");
        emitWith(comp, slotVisibility(), {
          name: key,
          visible: true
        });
      }
    };
    const doHide = (comp, key) => {
      if (doShowing(comp)) {
        const element2 = comp.element;
        set$8(element2, "display", "none");
        set$9(element2, "aria-hidden", "true");
        emitWith(comp, slotVisibility(), {
          name: key,
          visible: false
        });
      }
    };
    const isShowing = onSlot(doShowing, false);
    const hideSlot = onSlot(doHide);
    const hideSlots = onSlots(hideSlot);
    const hideAllSlots = (container) => hideSlots(container, getSlotNames());
    const showSlot = onSlot(doShow);
    const apis = {
      getSlotNames,
      getSlot,
      isShowing,
      hideSlot,
      hideAllSlots,
      showSlot
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: get$3(detail.slotBehaviours),
      apis
    };
  };
  const slotApis = map$1({
    getSlotNames: (apis, c) => apis.getSlotNames(c),
    getSlot: (apis, c, key) => apis.getSlot(c, key),
    isShowing: (apis, c, key) => apis.isShowing(c, key),
    hideSlot: (apis, c, key) => apis.hideSlot(c, key),
    hideAllSlots: (apis, c) => apis.hideAllSlots(c),
    showSlot: (apis, c, key) => apis.showSlot(c, key)
  }, (value2) => makeApi(value2));
  const SlotContainer = {
    ...slotApis,
    ...{ sketch }
  };
  const sidebarSchema = objOf([
    optionalIcon,
    optionalTooltip,
    defaultedFunction("onShow", noop),
    defaultedFunction("onHide", noop),
    onSetup
  ]);
  const createSidebar = (spec) => asRaw("sidebar", sidebarSchema, spec);
  const setup$8 = (editor) => {
    const { sidebars } = editor.ui.registry.getAll();
    each$1(keys(sidebars), (name2) => {
      const spec = sidebars[name2];
      const isActive = () => is$1(Optional.from(editor.queryCommandValue("ToggleSidebar")), name2);
      editor.ui.registry.addToggleButton(name2, {
        icon: spec.icon,
        tooltip: spec.tooltip,
        onAction: (buttonApi) => {
          editor.execCommand("ToggleSidebar", false, name2);
          buttonApi.setActive(isActive());
        },
        onSetup: (buttonApi) => {
          const handleToggle = () => buttonApi.setActive(isActive());
          editor.on("ToggleSidebar", handleToggle);
          return () => {
            editor.off("ToggleSidebar", handleToggle);
          };
        }
      });
    });
  };
  const getApi = (comp) => ({ element: () => comp.element.dom });
  const makePanels = (parts2, panelConfigs) => {
    const specs = map$2(keys(panelConfigs), (name2) => {
      const spec = panelConfigs[name2];
      const bridged = getOrDie(createSidebar(spec));
      return {
        name: name2,
        getApi,
        onSetup: bridged.onSetup,
        onShow: bridged.onShow,
        onHide: bridged.onHide
      };
    });
    return map$2(specs, (spec) => {
      const editorOffCell = Cell(noop);
      return parts2.slot(spec.name, {
        dom: {
          tag: "div",
          classes: ["tox-sidebar__pane"]
        },
        behaviours: SimpleBehaviours.unnamedEvents([
          onControlAttached(spec, editorOffCell),
          onControlDetached(spec, editorOffCell),
          run$1(slotVisibility(), (sidepanel, se) => {
            const data = se.event;
            const optSidePanelSpec = find$5(specs, (config2) => config2.name === data.name);
            optSidePanelSpec.each((sidePanelSpec) => {
              const handler = data.visible ? sidePanelSpec.onShow : sidePanelSpec.onHide;
              handler(sidePanelSpec.getApi(sidepanel));
            });
          })
        ])
      });
    });
  };
  const makeSidebar = (panelConfigs) => SlotContainer.sketch((parts2) => ({
    dom: {
      tag: "div",
      classes: ["tox-sidebar__pane-container"]
    },
    components: makePanels(parts2, panelConfigs),
    slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached((slotContainer) => SlotContainer.hideAllSlots(slotContainer))])
  }));
  const setSidebar = (sidebar, panelConfigs, showSidebar) => {
    const optSlider = Composing.getCurrent(sidebar);
    optSlider.each((slider) => {
      Replacing.set(slider, [makeSidebar(panelConfigs)]);
      const configKey = showSidebar === null || showSidebar === void 0 ? void 0 : showSidebar.toLowerCase();
      if (isString(showSidebar) && has$2(panelConfigs, configKey)) {
        Composing.getCurrent(slider).each((slotContainer) => {
          SlotContainer.showSlot(slotContainer, configKey);
          Sliding.immediateGrow(slider);
          remove$6(slider.element, "width");
        });
      }
    });
  };
  const toggleSidebar = (sidebar, name2) => {
    const optSlider = Composing.getCurrent(sidebar);
    optSlider.each((slider) => {
      const optSlotContainer = Composing.getCurrent(slider);
      optSlotContainer.each((slotContainer) => {
        if (Sliding.hasGrown(slider)) {
          if (SlotContainer.isShowing(slotContainer, name2)) {
            Sliding.shrink(slider);
          } else {
            SlotContainer.hideAllSlots(slotContainer);
            SlotContainer.showSlot(slotContainer, name2);
          }
        } else {
          SlotContainer.hideAllSlots(slotContainer);
          SlotContainer.showSlot(slotContainer, name2);
          Sliding.grow(slider);
        }
      });
    });
  };
  const whichSidebar = (sidebar) => {
    const optSlider = Composing.getCurrent(sidebar);
    return optSlider.bind((slider) => {
      const sidebarOpen = Sliding.isGrowing(slider) || Sliding.hasGrown(slider);
      if (sidebarOpen) {
        const optSlotContainer = Composing.getCurrent(slider);
        return optSlotContainer.bind((slotContainer) => find$5(SlotContainer.getSlotNames(slotContainer), (name2) => SlotContainer.isShowing(slotContainer, name2)));
      } else {
        return Optional.none();
      }
    });
  };
  const fixSize = generate$6("FixSizeEvent");
  const autoSize = generate$6("AutoSizeEvent");
  const renderSidebar = (spec) => ({
    uid: spec.uid,
    dom: {
      tag: "div",
      classes: ["tox-sidebar"],
      attributes: { role: "complementary" }
    },
    components: [{
      dom: {
        tag: "div",
        classes: ["tox-sidebar__slider"]
      },
      components: [],
      behaviours: derive$1([
        Tabstopping.config({}),
        Focusing.config({}),
        Sliding.config({
          dimension: { property: "width" },
          closedClass: "tox-sidebar--sliding-closed",
          openClass: "tox-sidebar--sliding-open",
          shrinkingClass: "tox-sidebar--sliding-shrinking",
          growingClass: "tox-sidebar--sliding-growing",
          onShrunk: (slider) => {
            const optSlotContainer = Composing.getCurrent(slider);
            optSlotContainer.each(SlotContainer.hideAllSlots);
            emit(slider, autoSize);
          },
          onGrown: (slider) => {
            emit(slider, autoSize);
          },
          onStartGrow: (slider) => {
            emitWith(slider, fixSize, { width: getRaw(slider.element, "width").getOr("") });
          },
          onStartShrink: (slider) => {
            emitWith(slider, fixSize, { width: get$c(slider.element) + "px" });
          }
        }),
        Replacing.config({}),
        Composing.config({
          find: (comp) => {
            const children2 = Replacing.contents(comp);
            return head(children2);
          }
        })
      ])
    }],
    behaviours: derive$1([
      ComposingConfigs.childAt(0),
      config("sidebar-sliding-events", [
        run$1(fixSize, (comp, se) => {
          set$8(comp.element, "width", se.event.width);
        }),
        run$1(autoSize, (comp, _se) => {
          remove$6(comp.element, "width");
        })
      ])
    ])
  });
  const block = (component, config2, state, getBusySpec2) => {
    set$9(component.element, "aria-busy", true);
    const root = config2.getRoot(component).getOr(component);
    const blockerBehaviours = derive$1([
      Keying.config({
        mode: "special",
        onTab: () => Optional.some(true),
        onShiftTab: () => Optional.some(true)
      }),
      Focusing.config({})
    ]);
    const blockSpec = getBusySpec2(root, blockerBehaviours);
    const blocker = root.getSystem().build(blockSpec);
    Replacing.append(root, premade(blocker));
    if (blocker.hasConfigured(Keying) && config2.focus) {
      Keying.focusIn(blocker);
    }
    if (!state.isBlocked()) {
      config2.onBlock(component);
    }
    state.blockWith(() => Replacing.remove(root, blocker));
  };
  const unblock = (component, config2, state) => {
    remove$7(component.element, "aria-busy");
    if (state.isBlocked()) {
      config2.onUnblock(component);
    }
    state.clear();
  };
  var BlockingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    block,
    unblock
  });
  var BlockingSchema = [
    defaultedFunction("getRoot", Optional.none),
    defaultedBoolean("focus", true),
    onHandler("onBlock"),
    onHandler("onUnblock")
  ];
  const init$4 = () => {
    const blocker = destroyable();
    const blockWith = (destroy) => {
      blocker.set({ destroy });
    };
    return nu$8({
      readState: blocker.isSet,
      blockWith,
      clear: blocker.clear,
      isBlocked: blocker.isSet
    });
  };
  var BlockingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$4
  });
  const Blocking = create$3({
    fields: BlockingSchema,
    name: "blocking",
    apis: BlockingApis,
    state: BlockingState
  });
  const getAttrs = (elem) => {
    const attributes = elem.dom.attributes !== void 0 ? elem.dom.attributes : [];
    return foldl(attributes, (b2, attr) => {
      if (attr.name === "class") {
        return b2;
      } else {
        return {
          ...b2,
          [attr.name]: attr.value
        };
      }
    }, {});
  };
  const getClasses = (elem) => Array.prototype.slice.call(elem.dom.classList, 0);
  const fromHtml = (html) => {
    const elem = SugarElement.fromHtml(html);
    const children$1 = children(elem);
    const attrs = getAttrs(elem);
    const classes2 = getClasses(elem);
    const contents2 = children$1.length === 0 ? {} : { innerHtml: get$9(elem) };
    return {
      tag: name$3(elem),
      classes: classes2,
      attributes: attrs,
      ...contents2
    };
  };
  const getBusySpec$1 = (providerBackstage) => (_root, _behaviours) => ({
    dom: {
      tag: "div",
      attributes: {
        "aria-label": providerBackstage.translate("Loading..."),
        "tabindex": "0"
      },
      classes: ["tox-throbber__busy-spinner"]
    },
    components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  });
  const focusBusyComponent = (throbber) => Composing.getCurrent(throbber).each((comp) => focus$3(comp.element));
  const toggleEditorTabIndex = (editor, state) => {
    const tabIndexAttr = "tabindex";
    const dataTabIndexAttr = `data-mce-${tabIndexAttr}`;
    Optional.from(editor.iframeElement).map(SugarElement.fromDom).each((iframe2) => {
      if (state) {
        getOpt(iframe2, tabIndexAttr).each((tabIndex) => set$9(iframe2, dataTabIndexAttr, tabIndex));
        set$9(iframe2, tabIndexAttr, -1);
      } else {
        remove$7(iframe2, tabIndexAttr);
        getOpt(iframe2, dataTabIndexAttr).each((tabIndex) => {
          set$9(iframe2, tabIndexAttr, tabIndex);
          remove$7(iframe2, dataTabIndexAttr);
        });
      }
    });
  };
  const toggleThrobber = (editor, comp, state, providerBackstage) => {
    const element2 = comp.element;
    toggleEditorTabIndex(editor, state);
    if (state) {
      Blocking.block(comp, getBusySpec$1(providerBackstage));
      remove$6(element2, "display");
      remove$7(element2, "aria-hidden");
      if (editor.hasFocus()) {
        focusBusyComponent(comp);
      }
    } else {
      const throbberFocus = Composing.getCurrent(comp).exists((busyComp) => hasFocus(busyComp.element));
      Blocking.unblock(comp);
      set$8(element2, "display", "none");
      set$9(element2, "aria-hidden", "true");
      if (throbberFocus) {
        editor.focus();
      }
    }
  };
  const renderThrobber = (spec) => ({
    uid: spec.uid,
    dom: {
      tag: "div",
      attributes: { "aria-hidden": "true" },
      classes: ["tox-throbber"],
      styles: { display: "none" }
    },
    behaviours: derive$1([
      Replacing.config({}),
      Blocking.config({ focus: false }),
      Composing.config({ find: (comp) => head(comp.components()) })
    ]),
    components: []
  });
  const isFocusEvent = (event) => event.type === "focusin";
  const isPasteBinTarget = (event) => {
    if (isFocusEvent(event)) {
      const node = event.composed ? head(event.composedPath()) : Optional.from(event.target);
      return node.map(SugarElement.fromDom).filter(isElement$1).exists((targetElm) => has(targetElm, "mce-pastebin"));
    } else {
      return false;
    }
  };
  const setup$7 = (editor, lazyThrobber, sharedBackstage) => {
    const throbberState = Cell(false);
    const timer = value$2();
    const stealFocus = (e) => {
      if (throbberState.get() && !isPasteBinTarget(e)) {
        e.preventDefault();
        focusBusyComponent(lazyThrobber());
        editor.editorManager.setActive(editor);
      }
    };
    if (!editor.inline) {
      editor.on("PreInit", () => {
        editor.dom.bind(editor.getWin(), "focusin", stealFocus);
        editor.on("BeforeExecCommand", (e) => {
          if (e.command.toLowerCase() === "mcefocus" && e.value !== true) {
            stealFocus(e);
          }
        });
      });
    }
    const toggle2 = (state) => {
      if (state !== throbberState.get()) {
        throbberState.set(state);
        toggleThrobber(editor, lazyThrobber(), state, sharedBackstage.providers);
        editor.dispatch("AfterProgressState", { state });
      }
    };
    editor.on("ProgressState", (e) => {
      timer.on(clearTimeout);
      if (isNumber(e.time)) {
        const timerId = global$9.setEditorTimeout(editor, () => toggle2(e.state), e.time);
        timer.set(timerId);
      } else {
        toggle2(e.state);
        timer.clear();
      }
    });
  };
  const generate$1 = (xs, f) => {
    const init2 = {
      len: 0,
      list: []
    };
    const r2 = foldl(xs, (b2, a) => {
      const value2 = f(a, b2.len);
      return value2.fold(constant$1(b2), (v) => ({
        len: v.finish,
        list: b2.list.concat([v])
      }));
    }, init2);
    return r2.list;
  };
  const output = (within, extra, withinWidth) => ({
    within,
    extra,
    withinWidth
  });
  const apportion = (units2, total, len) => {
    const parray = generate$1(units2, (unit, current) => {
      const width2 = len(unit);
      return Optional.some({
        element: unit,
        start: current,
        finish: current + width2,
        width: width2
      });
    });
    const within = filter$2(parray, (unit) => unit.finish <= total);
    const withinWidth = foldr(within, (acc, el) => acc + el.width, 0);
    const extra = parray.slice(within.length);
    return {
      within,
      extra,
      withinWidth
    };
  };
  const toUnit = (parray) => map$2(parray, (unit) => unit.element);
  const fitLast = (within, extra, withinWidth) => {
    const fits = toUnit(within.concat(extra));
    return output(fits, [], withinWidth);
  };
  const overflow = (within, extra, overflower, withinWidth) => {
    const fits = toUnit(within).concat([overflower]);
    return output(fits, toUnit(extra), withinWidth);
  };
  const fitAll = (within, extra, withinWidth) => output(toUnit(within), [], withinWidth);
  const tryFit = (total, units2, len) => {
    const divide = apportion(units2, total, len);
    return divide.extra.length === 0 ? Optional.some(divide) : Optional.none();
  };
  const partition = (total, units2, len, overflower) => {
    const divide = tryFit(total, units2, len).getOrThunk(() => apportion(units2, total - len(overflower), len));
    const within = divide.within;
    const extra = divide.extra;
    const withinWidth = divide.withinWidth;
    if (extra.length === 1 && extra[0].width <= len(overflower)) {
      return fitLast(within, extra, withinWidth);
    } else if (extra.length >= 1) {
      return overflow(within, extra, overflower, withinWidth);
    } else {
      return fitAll(within, extra, withinWidth);
    }
  };
  const setGroups$1 = (toolbar, storedGroups) => {
    const bGroups = map$2(storedGroups, (g) => premade(g));
    Toolbar.setGroups(toolbar, bGroups);
  };
  const findFocusedComp = (comps) => findMap(comps, (comp) => search(comp.element).bind((focusedElm) => comp.getSystem().getByDom(focusedElm).toOptional()));
  const refresh$2 = (toolbar, detail, setOverflow) => {
    const builtGroups = detail.builtGroups.get();
    if (builtGroups.length === 0) {
      return;
    }
    const primary2 = getPartOrDie(toolbar, detail, "primary");
    const overflowGroup = Coupling.getCoupled(toolbar, "overflowGroup");
    set$8(primary2.element, "visibility", "hidden");
    const groups = builtGroups.concat([overflowGroup]);
    const focusedComp = findFocusedComp(groups);
    setOverflow([]);
    setGroups$1(primary2, groups);
    const availableWidth = get$c(primary2.element);
    const overflows = partition(availableWidth, detail.builtGroups.get(), (comp) => get$c(comp.element), overflowGroup);
    if (overflows.extra.length === 0) {
      Replacing.remove(primary2, overflowGroup);
      setOverflow([]);
    } else {
      setGroups$1(primary2, overflows.within);
      setOverflow(overflows.extra);
    }
    remove$6(primary2.element, "visibility");
    reflow(primary2.element);
    focusedComp.each(Focusing.focus);
  };
  const schema$c = constant$1([
    field("splitToolbarBehaviours", [Coupling]),
    customField("builtGroups", () => Cell([]))
  ]);
  const schema$b = constant$1([
    markers$1(["overflowToggledClass"]),
    optionFunction("getOverflowBounds"),
    required$1("lazySink"),
    customField("overflowGroups", () => Cell([]))
  ].concat(schema$c()));
  const parts$7 = constant$1([
    required({
      factory: Toolbar,
      schema: schema$e(),
      name: "primary"
    }),
    external({
      schema: schema$e(),
      name: "overflow"
    }),
    external({ name: "overflow-button" }),
    external({ name: "overflow-group" })
  ]);
  const expandable = constant$1((element2, available) => {
    setMax(element2, Math.floor(available));
  });
  const schema$a = constant$1([
    markers$1(["toggledClass"]),
    required$1("lazySink"),
    requiredFunction("fetch"),
    optionFunction("getBounds"),
    optionObjOf("fireDismissalEventInstead", [defaulted("event", dismissRequested())]),
    schema$y()
  ]);
  const parts$6 = constant$1([
    external({
      name: "button",
      overrides: (detail) => ({
        dom: { attributes: { "aria-haspopup": "true" } },
        buttonBehaviours: derive$1([Toggling.config({
          toggleClass: detail.markers.toggledClass,
          aria: { mode: "expanded" },
          toggleOnExecute: false
        })])
      })
    }),
    external({
      factory: Toolbar,
      schema: schema$e(),
      name: "toolbar",
      overrides: (detail) => {
        return {
          toolbarBehaviours: derive$1([Keying.config({
            mode: "cyclic",
            onEscape: (comp) => {
              getPart(comp, detail, "button").each(Focusing.focus);
              return Optional.none();
            }
          })])
        };
      }
    })
  ]);
  const toggle = (button2, externals) => {
    const toolbarSandbox = Coupling.getCoupled(button2, "toolbarSandbox");
    if (Sandboxing.isOpen(toolbarSandbox)) {
      Sandboxing.close(toolbarSandbox);
    } else {
      Sandboxing.open(toolbarSandbox, externals.toolbar());
    }
  };
  const position = (button2, toolbar, detail, layouts2) => {
    const bounds2 = detail.getBounds.map((bounder) => bounder());
    const sink = detail.lazySink(button2).getOrDie();
    Positioning.positionWithinBounds(sink, toolbar, {
      anchor: {
        type: "hotspot",
        hotspot: button2,
        layouts: layouts2,
        overrides: { maxWidthFunction: expandable() }
      }
    }, bounds2);
  };
  const setGroups = (button2, toolbar, detail, layouts2, groups) => {
    Toolbar.setGroups(toolbar, groups);
    position(button2, toolbar, detail, layouts2);
    Toggling.on(button2);
  };
  const makeSandbox = (button2, spec, detail) => {
    const ariaControls = manager();
    const onOpen = (sandbox, toolbar) => {
      detail.fetch().get((groups) => {
        setGroups(button2, toolbar, detail, spec.layouts, groups);
        ariaControls.link(button2.element);
        Keying.focusIn(toolbar);
      });
    };
    const onClose = () => {
      Toggling.off(button2);
      Focusing.focus(button2);
      ariaControls.unlink(button2.element);
    };
    return {
      dom: {
        tag: "div",
        attributes: { id: ariaControls.id }
      },
      behaviours: derive$1([
        Keying.config({
          mode: "special",
          onEscape: (comp) => {
            Sandboxing.close(comp);
            return Optional.some(true);
          }
        }),
        Sandboxing.config({
          onOpen,
          onClose,
          isPartOf: (container, data, queryElem) => {
            return isPartOf$1(data, queryElem) || isPartOf$1(button2, queryElem);
          },
          getAttachPoint: () => {
            return detail.lazySink(button2).getOrDie();
          }
        }),
        Receiving.config({
          channels: {
            ...receivingChannel$1({
              isExtraPart: never,
              ...detail.fireDismissalEventInstead.map((fe) => ({ fireEventInstead: { event: fe.event } })).getOr({})
            }),
            ...receivingChannel({
              doReposition: () => {
                Sandboxing.getState(Coupling.getCoupled(button2, "toolbarSandbox")).each((toolbar) => {
                  position(button2, toolbar, detail, spec.layouts);
                });
              }
            })
          }
        })
      ])
    };
  };
  const factory$a = (detail, components2, spec, externals) => ({
    ...Button.sketch({
      ...externals.button(),
      action: (button2) => {
        toggle(button2, externals);
      },
      buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [Coupling.config({
        others: {
          toolbarSandbox: (button2) => {
            return makeSandbox(button2, spec, detail);
          }
        }
      })])
    }),
    apis: {
      setGroups: (button2, groups) => {
        Sandboxing.getState(Coupling.getCoupled(button2, "toolbarSandbox")).each((toolbar) => {
          setGroups(button2, toolbar, detail, spec.layouts, groups);
        });
      },
      reposition: (button2) => {
        Sandboxing.getState(Coupling.getCoupled(button2, "toolbarSandbox")).each((toolbar) => {
          position(button2, toolbar, detail, spec.layouts);
        });
      },
      toggle: (button2) => {
        toggle(button2, externals);
      },
      getToolbar: (button2) => {
        return Sandboxing.getState(Coupling.getCoupled(button2, "toolbarSandbox"));
      },
      isOpen: (button2) => {
        return Sandboxing.isOpen(Coupling.getCoupled(button2, "toolbarSandbox"));
      }
    }
  });
  const FloatingToolbarButton = composite({
    name: "FloatingToolbarButton",
    factory: factory$a,
    configFields: schema$a(),
    partFields: parts$6(),
    apis: {
      setGroups: (apis, button2, groups) => {
        apis.setGroups(button2, groups);
      },
      reposition: (apis, button2) => {
        apis.reposition(button2);
      },
      toggle: (apis, button2) => {
        apis.toggle(button2);
      },
      getToolbar: (apis, button2) => apis.getToolbar(button2),
      isOpen: (apis, button2) => apis.isOpen(button2)
    }
  });
  const schema$9 = constant$1([
    required$1("items"),
    markers$1(["itemSelector"]),
    field("tgroupBehaviours", [Keying])
  ]);
  const parts$5 = constant$1([group({
    name: "items",
    unit: "item"
  })]);
  const factory$9 = (detail, components2, _spec, _externals) => ({
    uid: detail.uid,
    dom: detail.dom,
    components: components2,
    behaviours: augment(detail.tgroupBehaviours, [Keying.config({
      mode: "flow",
      selector: detail.markers.itemSelector
    })]),
    domModification: { attributes: { role: "toolbar" } }
  });
  const ToolbarGroup = composite({
    name: "ToolbarGroup",
    configFields: schema$9(),
    partFields: parts$5(),
    factory: factory$9
  });
  const buildGroups = (comps) => map$2(comps, (g) => premade(g));
  const refresh$1 = (toolbar, memFloatingToolbarButton, detail) => {
    refresh$2(toolbar, detail, (overflowGroups) => {
      detail.overflowGroups.set(overflowGroups);
      memFloatingToolbarButton.getOpt(toolbar).each((floatingToolbarButton) => {
        FloatingToolbarButton.setGroups(floatingToolbarButton, buildGroups(overflowGroups));
      });
    });
  };
  const factory$8 = (detail, components2, spec, externals) => {
    const memFloatingToolbarButton = record(FloatingToolbarButton.sketch({
      fetch: () => Future.nu((resolve) => {
        resolve(buildGroups(detail.overflowGroups.get()));
      }),
      layouts: {
        onLtr: () => [
          southwest$2,
          southeast$2
        ],
        onRtl: () => [
          southeast$2,
          southwest$2
        ],
        onBottomLtr: () => [
          northwest$2,
          northeast$2
        ],
        onBottomRtl: () => [
          northeast$2,
          northwest$2
        ]
      },
      getBounds: spec.getOverflowBounds,
      lazySink: detail.lazySink,
      fireDismissalEventInstead: {},
      markers: { toggledClass: detail.markers.overflowToggledClass },
      parts: {
        button: externals["overflow-button"](),
        toolbar: externals.overflow()
      }
    }));
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: augment(detail.splitToolbarBehaviours, [Coupling.config({
        others: {
          overflowGroup: () => {
            return ToolbarGroup.sketch({
              ...externals["overflow-group"](),
              items: [memFloatingToolbarButton.asSpec()]
            });
          }
        }
      })]),
      apis: {
        setGroups: (toolbar, groups) => {
          detail.builtGroups.set(map$2(groups, toolbar.getSystem().build));
          refresh$1(toolbar, memFloatingToolbarButton, detail);
        },
        refresh: (toolbar) => refresh$1(toolbar, memFloatingToolbarButton, detail),
        toggle: (toolbar) => {
          memFloatingToolbarButton.getOpt(toolbar).each((floatingToolbarButton) => {
            FloatingToolbarButton.toggle(floatingToolbarButton);
          });
        },
        isOpen: (toolbar) => memFloatingToolbarButton.getOpt(toolbar).map(FloatingToolbarButton.isOpen).getOr(false),
        reposition: (toolbar) => {
          memFloatingToolbarButton.getOpt(toolbar).each((floatingToolbarButton) => {
            FloatingToolbarButton.reposition(floatingToolbarButton);
          });
        },
        getOverflow: (toolbar) => memFloatingToolbarButton.getOpt(toolbar).bind(FloatingToolbarButton.getToolbar)
      },
      domModification: { attributes: { role: "group" } }
    };
  };
  const SplitFloatingToolbar = composite({
    name: "SplitFloatingToolbar",
    configFields: schema$b(),
    partFields: parts$7(),
    factory: factory$8,
    apis: {
      setGroups: (apis, toolbar, groups) => {
        apis.setGroups(toolbar, groups);
      },
      refresh: (apis, toolbar) => {
        apis.refresh(toolbar);
      },
      reposition: (apis, toolbar) => {
        apis.reposition(toolbar);
      },
      toggle: (apis, toolbar) => {
        apis.toggle(toolbar);
      },
      isOpen: (apis, toolbar) => apis.isOpen(toolbar),
      getOverflow: (apis, toolbar) => apis.getOverflow(toolbar)
    }
  });
  const schema$8 = constant$1([
    markers$1([
      "closedClass",
      "openClass",
      "shrinkingClass",
      "growingClass",
      "overflowToggledClass"
    ]),
    onHandler("onOpened"),
    onHandler("onClosed")
  ].concat(schema$c()));
  const parts$4 = constant$1([
    required({
      factory: Toolbar,
      schema: schema$e(),
      name: "primary"
    }),
    required({
      factory: Toolbar,
      schema: schema$e(),
      name: "overflow",
      overrides: (detail) => {
        return {
          toolbarBehaviours: derive$1([
            Sliding.config({
              dimension: { property: "height" },
              closedClass: detail.markers.closedClass,
              openClass: detail.markers.openClass,
              shrinkingClass: detail.markers.shrinkingClass,
              growingClass: detail.markers.growingClass,
              onShrunk: (comp) => {
                getPart(comp, detail, "overflow-button").each((button2) => {
                  Toggling.off(button2);
                  Focusing.focus(button2);
                });
                detail.onClosed(comp);
              },
              onGrown: (comp) => {
                Keying.focusIn(comp);
                detail.onOpened(comp);
              },
              onStartGrow: (comp) => {
                getPart(comp, detail, "overflow-button").each(Toggling.on);
              }
            }),
            Keying.config({
              mode: "acyclic",
              onEscape: (comp) => {
                getPart(comp, detail, "overflow-button").each(Focusing.focus);
                return Optional.some(true);
              }
            })
          ])
        };
      }
    }),
    external({
      name: "overflow-button",
      overrides: (detail) => ({
        buttonBehaviours: derive$1([Toggling.config({
          toggleClass: detail.markers.overflowToggledClass,
          aria: { mode: "pressed" },
          toggleOnExecute: false
        })])
      })
    }),
    external({ name: "overflow-group" })
  ]);
  const isOpen = (toolbar, detail) => getPart(toolbar, detail, "overflow").map(Sliding.hasGrown).getOr(false);
  const toggleToolbar = (toolbar, detail) => {
    getPart(toolbar, detail, "overflow-button").bind(() => getPart(toolbar, detail, "overflow")).each((overf) => {
      refresh(toolbar, detail);
      Sliding.toggleGrow(overf);
    });
  };
  const refresh = (toolbar, detail) => {
    getPart(toolbar, detail, "overflow").each((overflow2) => {
      refresh$2(toolbar, detail, (groups) => {
        const builtGroups = map$2(groups, (g) => premade(g));
        Toolbar.setGroups(overflow2, builtGroups);
      });
      getPart(toolbar, detail, "overflow-button").each((button2) => {
        if (Sliding.hasGrown(overflow2)) {
          Toggling.on(button2);
        }
      });
      Sliding.refresh(overflow2);
    });
  };
  const factory$7 = (detail, components2, spec, externals) => {
    const toolbarToggleEvent = "alloy.toolbar.toggle";
    const doSetGroups = (toolbar, groups) => {
      const built = map$2(groups, toolbar.getSystem().build);
      detail.builtGroups.set(built);
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: augment(detail.splitToolbarBehaviours, [
        Coupling.config({
          others: {
            overflowGroup: (toolbar) => {
              return ToolbarGroup.sketch({
                ...externals["overflow-group"](),
                items: [Button.sketch({
                  ...externals["overflow-button"](),
                  action: (_button) => {
                    emit(toolbar, toolbarToggleEvent);
                  }
                })]
              });
            }
          }
        }),
        config("toolbar-toggle-events", [run$1(toolbarToggleEvent, (toolbar) => {
          toggleToolbar(toolbar, detail);
        })])
      ]),
      apis: {
        setGroups: (toolbar, groups) => {
          doSetGroups(toolbar, groups);
          refresh(toolbar, detail);
        },
        refresh: (toolbar) => refresh(toolbar, detail),
        toggle: (toolbar) => toggleToolbar(toolbar, detail),
        isOpen: (toolbar) => isOpen(toolbar, detail)
      },
      domModification: { attributes: { role: "group" } }
    };
  };
  const SplitSlidingToolbar = composite({
    name: "SplitSlidingToolbar",
    configFields: schema$8(),
    partFields: parts$4(),
    factory: factory$7,
    apis: {
      setGroups: (apis, toolbar, groups) => {
        apis.setGroups(toolbar, groups);
      },
      refresh: (apis, toolbar) => {
        apis.refresh(toolbar);
      },
      toggle: (apis, toolbar) => {
        apis.toggle(toolbar);
      },
      isOpen: (apis, toolbar) => apis.isOpen(toolbar)
    }
  });
  const renderToolbarGroupCommon = (toolbarGroup) => {
    const attributes = toolbarGroup.title.fold(() => ({}), (title2) => ({ attributes: { title: title2 } }));
    return {
      dom: {
        tag: "div",
        classes: ["tox-toolbar__group"],
        ...attributes
      },
      components: [ToolbarGroup.parts.items({})],
      items: toolbarGroup.items,
      markers: { itemSelector: "*:not(.tox-split-button) > .tox-tbtn:not([disabled]), .tox-split-button:not([disabled]), .tox-toolbar-nav-js:not([disabled])" },
      tgroupBehaviours: derive$1([
        Tabstopping.config({}),
        Focusing.config({})
      ])
    };
  };
  const renderToolbarGroup = (toolbarGroup) => ToolbarGroup.sketch(renderToolbarGroupCommon(toolbarGroup));
  const getToolbarbehaviours = (toolbarSpec, modeName) => {
    const onAttached = runOnAttached((component) => {
      const groups = map$2(toolbarSpec.initGroups, renderToolbarGroup);
      Toolbar.setGroups(component, groups);
    });
    return derive$1([
      DisablingConfigs.toolbarButton(toolbarSpec.providers.isDisabled),
      receivingConfig(),
      Keying.config({
        mode: modeName,
        onEscape: toolbarSpec.onEscape,
        selector: ".tox-toolbar__group"
      }),
      config("toolbar-events", [onAttached])
    ]);
  };
  const renderMoreToolbarCommon = (toolbarSpec) => {
    const modeName = toolbarSpec.cyclicKeying ? "cyclic" : "acyclic";
    return {
      uid: toolbarSpec.uid,
      dom: {
        tag: "div",
        classes: ["tox-toolbar-overlord"]
      },
      parts: {
        "overflow-group": renderToolbarGroupCommon({
          title: Optional.none(),
          items: []
        }),
        "overflow-button": renderIconButtonSpec({
          name: "more",
          icon: Optional.some("more-drawer"),
          enabled: true,
          tooltip: Optional.some("More..."),
          primary: false,
          buttonType: Optional.none(),
          borderless: false
        }, Optional.none(), toolbarSpec.providers)
      },
      splitToolbarBehaviours: getToolbarbehaviours(toolbarSpec, modeName)
    };
  };
  const renderFloatingMoreToolbar = (toolbarSpec) => {
    const baseSpec = renderMoreToolbarCommon(toolbarSpec);
    const overflowXOffset = 4;
    const primary2 = SplitFloatingToolbar.parts.primary({
      dom: {
        tag: "div",
        classes: ["tox-toolbar__primary"]
      }
    });
    return SplitFloatingToolbar.sketch({
      ...baseSpec,
      lazySink: toolbarSpec.getSink,
      getOverflowBounds: () => {
        const headerElem = toolbarSpec.moreDrawerData.lazyHeader().element;
        const headerBounds = absolute$2(headerElem);
        const docElem = documentElement(headerElem);
        const docBounds = absolute$2(docElem);
        const height2 = Math.max(docElem.dom.scrollHeight, docBounds.height);
        return bounds(headerBounds.x + overflowXOffset, docBounds.y, headerBounds.width - overflowXOffset * 2, height2);
      },
      parts: {
        ...baseSpec.parts,
        overflow: {
          dom: {
            tag: "div",
            classes: ["tox-toolbar__overflow"],
            attributes: toolbarSpec.attributes
          }
        }
      },
      components: [primary2],
      markers: { overflowToggledClass: "tox-tbtn--enabled" }
    });
  };
  const renderSlidingMoreToolbar = (toolbarSpec) => {
    const primary2 = SplitSlidingToolbar.parts.primary({
      dom: {
        tag: "div",
        classes: ["tox-toolbar__primary"]
      }
    });
    const overflow2 = SplitSlidingToolbar.parts.overflow({
      dom: {
        tag: "div",
        classes: ["tox-toolbar__overflow"]
      }
    });
    const baseSpec = renderMoreToolbarCommon(toolbarSpec);
    return SplitSlidingToolbar.sketch({
      ...baseSpec,
      components: [
        primary2,
        overflow2
      ],
      markers: {
        openClass: "tox-toolbar__overflow--open",
        closedClass: "tox-toolbar__overflow--closed",
        growingClass: "tox-toolbar__overflow--growing",
        shrinkingClass: "tox-toolbar__overflow--shrinking",
        overflowToggledClass: "tox-tbtn--enabled"
      },
      onOpened: (comp) => {
        comp.getSystem().broadcastOn([toolbarHeightChange()], { type: "opened" });
      },
      onClosed: (comp) => {
        comp.getSystem().broadcastOn([toolbarHeightChange()], { type: "closed" });
      }
    });
  };
  const renderToolbar = (toolbarSpec) => {
    const modeName = toolbarSpec.cyclicKeying ? "cyclic" : "acyclic";
    return Toolbar.sketch({
      uid: toolbarSpec.uid,
      dom: {
        tag: "div",
        classes: ["tox-toolbar"].concat(toolbarSpec.type === ToolbarMode$1.scrolling ? ["tox-toolbar--scrolling"] : [])
      },
      components: [Toolbar.parts.groups({})],
      toolbarBehaviours: getToolbarbehaviours(toolbarSpec, modeName)
    });
  };
  const factory$6 = (detail, components2, _spec) => {
    const apis = {
      getSocket: (comp) => {
        return parts$a.getPart(comp, detail, "socket");
      },
      setSidebar: (comp, panelConfigs, showSidebar) => {
        parts$a.getPart(comp, detail, "sidebar").each((sidebar) => setSidebar(sidebar, panelConfigs, showSidebar));
      },
      toggleSidebar: (comp, name2) => {
        parts$a.getPart(comp, detail, "sidebar").each((sidebar) => toggleSidebar(sidebar, name2));
      },
      whichSidebar: (comp) => {
        return parts$a.getPart(comp, detail, "sidebar").bind(whichSidebar).getOrNull();
      },
      getHeader: (comp) => {
        return parts$a.getPart(comp, detail, "header");
      },
      getToolbar: (comp) => {
        return parts$a.getPart(comp, detail, "toolbar");
      },
      setToolbar: (comp, groups) => {
        parts$a.getPart(comp, detail, "toolbar").each((toolbar) => {
          toolbar.getApis().setGroups(toolbar, groups);
        });
      },
      setToolbars: (comp, toolbars) => {
        parts$a.getPart(comp, detail, "multiple-toolbar").each((mToolbar) => {
          CustomList.setItems(mToolbar, toolbars);
        });
      },
      refreshToolbar: (comp) => {
        const toolbar = parts$a.getPart(comp, detail, "toolbar");
        toolbar.each((toolbar2) => toolbar2.getApis().refresh(toolbar2));
      },
      toggleToolbarDrawer: (comp) => {
        parts$a.getPart(comp, detail, "toolbar").each((toolbar) => {
          mapFrom(toolbar.getApis().toggle, (toggle2) => toggle2(toolbar));
        });
      },
      isToolbarDrawerToggled: (comp) => {
        return parts$a.getPart(comp, detail, "toolbar").bind((toolbar) => Optional.from(toolbar.getApis().isOpen).map((isOpen2) => isOpen2(toolbar))).getOr(false);
      },
      getThrobber: (comp) => {
        return parts$a.getPart(comp, detail, "throbber");
      },
      focusToolbar: (comp) => {
        const optToolbar = parts$a.getPart(comp, detail, "toolbar").orThunk(() => parts$a.getPart(comp, detail, "multiple-toolbar"));
        optToolbar.each((toolbar) => {
          Keying.focusIn(toolbar);
        });
      },
      setMenubar: (comp, menus) => {
        parts$a.getPart(comp, detail, "menubar").each((menubar) => {
          SilverMenubar.setMenus(menubar, menus);
        });
      },
      focusMenubar: (comp) => {
        parts$a.getPart(comp, detail, "menubar").each((menubar) => {
          SilverMenubar.focus(menubar);
        });
      }
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      apis,
      behaviours: detail.behaviours
    };
  };
  const partMenubar = partType.optional({
    factory: SilverMenubar,
    name: "menubar",
    schema: [required$1("backstage")]
  });
  const toolbarFactory = (spec) => {
    if (spec.type === ToolbarMode$1.sliding) {
      return renderSlidingMoreToolbar;
    } else if (spec.type === ToolbarMode$1.floating) {
      return renderFloatingMoreToolbar;
    } else {
      return renderToolbar;
    }
  };
  const partMultipleToolbar = partType.optional({
    factory: {
      sketch: (spec) => CustomList.sketch({
        uid: spec.uid,
        dom: spec.dom,
        listBehaviours: derive$1([Keying.config({
          mode: "acyclic",
          selector: ".tox-toolbar"
        })]),
        makeItem: () => renderToolbar({
          type: spec.type,
          uid: generate$6("multiple-toolbar-item"),
          cyclicKeying: false,
          initGroups: [],
          providers: spec.providers,
          onEscape: () => {
            spec.onEscape();
            return Optional.some(true);
          }
        }),
        setupItem: (_mToolbar, tc, data, _index) => {
          Toolbar.setGroups(tc, data);
        },
        shell: true
      })
    },
    name: "multiple-toolbar",
    schema: [
      required$1("dom"),
      required$1("onEscape")
    ]
  });
  const partToolbar = partType.optional({
    factory: {
      sketch: (spec) => {
        const renderer = toolbarFactory(spec);
        const toolbarSpec = {
          type: spec.type,
          uid: spec.uid,
          onEscape: () => {
            spec.onEscape();
            return Optional.some(true);
          },
          cyclicKeying: false,
          initGroups: [],
          getSink: spec.getSink,
          providers: spec.providers,
          moreDrawerData: {
            lazyToolbar: spec.lazyToolbar,
            lazyMoreButton: spec.lazyMoreButton,
            lazyHeader: spec.lazyHeader
          },
          attributes: spec.attributes
        };
        return renderer(toolbarSpec);
      }
    },
    name: "toolbar",
    schema: [
      required$1("dom"),
      required$1("onEscape"),
      required$1("getSink")
    ]
  });
  const partHeader = partType.optional({
    factory: { sketch: renderHeader },
    name: "header",
    schema: [required$1("dom")]
  });
  const partSocket = partType.optional({
    name: "socket",
    schema: [required$1("dom")]
  });
  const partSidebar = partType.optional({
    factory: { sketch: renderSidebar },
    name: "sidebar",
    schema: [required$1("dom")]
  });
  const partThrobber = partType.optional({
    factory: { sketch: renderThrobber },
    name: "throbber",
    schema: [required$1("dom")]
  });
  var OuterContainer = composite({
    name: "OuterContainer",
    factory: factory$6,
    configFields: [
      required$1("dom"),
      required$1("behaviours")
    ],
    partFields: [
      partHeader,
      partMenubar,
      partToolbar,
      partMultipleToolbar,
      partSocket,
      partSidebar,
      partThrobber
    ],
    apis: {
      getSocket: (apis, comp) => {
        return apis.getSocket(comp);
      },
      setSidebar: (apis, comp, panelConfigs, showSidebar) => {
        apis.setSidebar(comp, panelConfigs, showSidebar);
      },
      toggleSidebar: (apis, comp, name2) => {
        apis.toggleSidebar(comp, name2);
      },
      whichSidebar: (apis, comp) => {
        return apis.whichSidebar(comp);
      },
      getHeader: (apis, comp) => {
        return apis.getHeader(comp);
      },
      getToolbar: (apis, comp) => {
        return apis.getToolbar(comp);
      },
      setToolbar: (apis, comp, grps) => {
        const groups = map$2(grps, (grp) => {
          return renderToolbarGroup(grp);
        });
        apis.setToolbar(comp, groups);
      },
      setToolbars: (apis, comp, ts) => {
        const renderedToolbars = map$2(ts, (g) => map$2(g, renderToolbarGroup));
        apis.setToolbars(comp, renderedToolbars);
      },
      refreshToolbar: (apis, comp) => {
        return apis.refreshToolbar(comp);
      },
      toggleToolbarDrawer: (apis, comp) => {
        apis.toggleToolbarDrawer(comp);
      },
      isToolbarDrawerToggled: (apis, comp) => {
        return apis.isToolbarDrawerToggled(comp);
      },
      getThrobber: (apis, comp) => {
        return apis.getThrobber(comp);
      },
      setMenubar: (apis, comp, menus) => {
        apis.setMenubar(comp, menus);
      },
      focusMenubar: (apis, comp) => {
        apis.focusMenubar(comp);
      },
      focusToolbar: (apis, comp) => {
        apis.focusToolbar(comp);
      }
    }
  });
  const defaultMenubar = "file edit view insert format tools table help";
  const defaultMenus = {
    file: {
      title: "File",
      items: "newdocument restoredraft | preview | export print | deleteallconversations"
    },
    edit: {
      title: "Edit",
      items: "undo redo | cut copy paste pastetext | selectall | searchreplace"
    },
    view: {
      title: "View",
      items: "code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments"
    },
    insert: {
      title: "Insert",
      items: "image link media addcomment pageembed template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime"
    },
    format: {
      title: "Format",
      items: "bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat"
    },
    tools: {
      title: "Tools",
      items: "spellchecker spellcheckerlanguage | a11ycheck code wordcount"
    },
    table: {
      title: "Table",
      items: "inserttable | cell row column | advtablesort | tableprops deletetable"
    },
    help: {
      title: "Help",
      items: "help"
    }
  };
  const make = (menu2, registry, editor) => {
    const removedMenuItems = getRemovedMenuItems(editor).split(/[ ,]/);
    return {
      text: menu2.title,
      getItems: () => bind$3(menu2.items, (i) => {
        const itemName = i.toLowerCase();
        if (itemName.trim().length === 0) {
          return [];
        } else if (exists(removedMenuItems, (removedMenuItem) => removedMenuItem === itemName)) {
          return [];
        } else if (itemName === "separator" || itemName === "|") {
          return [{ type: "separator" }];
        } else if (registry.menuItems[itemName]) {
          return [registry.menuItems[itemName]];
        } else {
          return [];
        }
      })
    };
  };
  const parseItemsString = (items) => {
    if (typeof items === "string") {
      return items.split(" ");
    }
    return items;
  };
  const identifyMenus = (editor, registry) => {
    const rawMenuData = {
      ...defaultMenus,
      ...registry.menus
    };
    const userDefinedMenus = keys(registry.menus).length > 0;
    const menubar = registry.menubar === void 0 || registry.menubar === true ? parseItemsString(defaultMenubar) : parseItemsString(registry.menubar === false ? "" : registry.menubar);
    const validMenus = filter$2(menubar, (menuName) => {
      const isDefaultMenu = has$2(defaultMenus, menuName);
      if (userDefinedMenus) {
        return isDefaultMenu || get$g(registry.menus, menuName).exists((menu2) => has$2(menu2, "items"));
      } else {
        return isDefaultMenu;
      }
    });
    const menus = map$2(validMenus, (menuName) => {
      const menuData = rawMenuData[menuName];
      return make({
        title: menuData.title,
        items: parseItemsString(menuData.items)
      }, registry, editor);
    });
    return filter$2(menus, (menu2) => {
      const isNotSeparator = (item2) => item2.type !== "separator";
      return menu2.getItems().length > 0 && exists(menu2.getItems(), isNotSeparator);
    });
  };
  const fireSkinLoaded = (editor) => {
    const done = () => {
      editor._skinLoaded = true;
      fireSkinLoaded$1(editor);
    };
    return () => {
      if (editor.initialized) {
        done();
      } else {
        editor.on("init", done);
      }
    };
  };
  const fireSkinLoadError = (editor, err) => () => fireSkinLoadError$1(editor, { message: err });
  const loadStylesheet = (editor, stylesheetUrl, styleSheetLoader) => {
    editor.on("remove", () => styleSheetLoader.unload(stylesheetUrl));
    return styleSheetLoader.load(stylesheetUrl);
  };
  const loadUiSkins = (editor, skinUrl) => {
    const skinUiCss = skinUrl + "/skin.min.css";
    return loadStylesheet(editor, skinUiCss, editor.ui.styleSheetLoader);
  };
  const loadShadowDomUiSkins = (editor, skinUrl) => {
    const isInShadowRoot$1 = isInShadowRoot(SugarElement.fromDom(editor.getElement()));
    if (isInShadowRoot$1) {
      const shadowDomSkinCss = skinUrl + "/skin.shadowdom.min.css";
      return loadStylesheet(editor, shadowDomSkinCss, global$7.DOM.styleSheetLoader);
    } else {
      return Promise.resolve();
    }
  };
  const loadSkin = (isInline, editor) => {
    const skinUrl = getSkinUrl(editor);
    if (skinUrl) {
      editor.contentCSS.push(skinUrl + (isInline ? "/content.inline" : "/content") + ".min.css");
    }
    if (!isSkinDisabled(editor) && isString(skinUrl)) {
      Promise.all([
        loadUiSkins(editor, skinUrl),
        loadShadowDomUiSkins(editor, skinUrl)
      ]).then(fireSkinLoaded(editor), fireSkinLoadError(editor, "Skin could not be loaded"));
    } else {
      fireSkinLoaded(editor)();
    }
  };
  const iframe = curry(loadSkin, false);
  const inline = curry(loadSkin, true);
  const onSetupFormatToggle = (editor, name2) => (api2) => {
    const boundCallback = unbindable();
    const init2 = () => {
      api2.setActive(editor.formatter.match(name2));
      const binding = editor.formatter.formatChanged(name2, api2.setActive);
      boundCallback.set(binding);
    };
    editor.initialized ? init2() : editor.once("init", init2);
    return () => {
      editor.off("init", init2);
      boundCallback.clear();
    };
  };
  const onSetupEvent = (editor, event, f) => (api2) => {
    const handleEvent = () => f(api2);
    const init2 = () => {
      f(api2);
      editor.on(event, handleEvent);
    };
    editor.initialized ? init2() : editor.once("init", init2);
    return () => {
      editor.off("init", init2);
      editor.off(event, handleEvent);
    };
  };
  const onActionToggleFormat$1 = (editor) => (rawItem) => () => {
    editor.undoManager.transact(() => {
      editor.focus();
      editor.execCommand("mceToggleFormat", false, rawItem.format);
    });
  };
  const onActionExecCommand = (editor, command) => () => editor.execCommand(command);
  const generateSelectItems = (_editor, backstage, spec) => {
    const generateItem = (rawItem, response, invalid, value2) => {
      const translatedText = backstage.shared.providers.translate(rawItem.title);
      if (rawItem.type === "separator") {
        return Optional.some({
          type: "separator",
          text: translatedText
        });
      } else if (rawItem.type === "submenu") {
        const items = bind$3(rawItem.getStyleItems(), (si) => validate(si, response, value2));
        if (response === 0 && items.length <= 0) {
          return Optional.none();
        } else {
          return Optional.some({
            type: "nestedmenuitem",
            text: translatedText,
            enabled: items.length > 0,
            getSubmenuItems: () => bind$3(rawItem.getStyleItems(), (si) => validate(si, response, value2))
          });
        }
      } else {
        return Optional.some({
          type: "togglemenuitem",
          text: translatedText,
          icon: rawItem.icon,
          active: rawItem.isSelected(value2),
          enabled: !invalid,
          onAction: spec.onAction(rawItem),
          ...rawItem.getStylePreview().fold(() => ({}), (preview) => ({ meta: { style: preview } }))
        });
      }
    };
    const validate = (item2, response, value2) => {
      const invalid = item2.type === "formatter" && spec.isInvalid(item2);
      if (response === 0) {
        return invalid ? [] : generateItem(item2, response, false, value2).toArray();
      } else {
        return generateItem(item2, response, invalid, value2).toArray();
      }
    };
    const validateItems = (preItems) => {
      const value2 = spec.getCurrentValue();
      const response = spec.shouldHide ? 0 : 1;
      return bind$3(preItems, (item2) => validate(item2, response, value2));
    };
    const getFetch2 = (backstage2, getStyleItems) => (comp, callback) => {
      const preItems = getStyleItems();
      const items = validateItems(preItems);
      const menu2 = build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage2, false);
      callback(menu2);
    };
    return {
      validateItems,
      getFetch: getFetch2
    };
  };
  const createMenuItems = (editor, backstage, spec) => {
    const dataset2 = spec.dataset;
    const getStyleItems = dataset2.type === "basic" ? () => map$2(dataset2.data, (d) => processBasic(d, spec.isSelectedFor, spec.getPreviewFor)) : dataset2.getData;
    return {
      items: generateSelectItems(editor, backstage, spec),
      getStyleItems
    };
  };
  const createSelectButton = (editor, backstage, spec) => {
    const { items, getStyleItems } = createMenuItems(editor, backstage, spec);
    const getApi2 = (comp) => ({ getComponent: constant$1(comp) });
    const onSetup2 = onSetupEvent(editor, "NodeChange", (api2) => {
      const comp = api2.getComponent();
      spec.updateText(comp);
    });
    return renderCommonDropdown({
      text: spec.icon.isSome() ? Optional.none() : spec.text,
      icon: spec.icon,
      tooltip: Optional.from(spec.tooltip),
      role: Optional.none(),
      fetch: items.getFetch(backstage, getStyleItems),
      onSetup: onSetup2,
      getApi: getApi2,
      columns: 1,
      presets: "normal",
      classes: spec.icon.isSome() ? [] : ["bespoke"],
      dropdownBehaviours: []
    }, "tox-tbtn", backstage.shared);
  };
  const process = (rawFormats) => map$2(rawFormats, (item2) => {
    let title2 = item2, format = item2;
    const values2 = item2.split("=");
    if (values2.length > 1) {
      title2 = values2[0];
      format = values2[1];
    }
    return {
      title: title2,
      format
    };
  });
  const buildBasicStaticDataset = (data) => ({
    type: "basic",
    data
  });
  var Delimiter;
  (function(Delimiter2) {
    Delimiter2[Delimiter2["SemiColon"] = 0] = "SemiColon";
    Delimiter2[Delimiter2["Space"] = 1] = "Space";
  })(Delimiter || (Delimiter = {}));
  const split = (rawFormats, delimiter) => {
    if (delimiter === Delimiter.SemiColon) {
      return rawFormats.replace(/;$/, "").split(";");
    } else {
      return rawFormats.split(" ");
    }
  };
  const buildBasicSettingsDataset = (editor, settingName, delimiter) => {
    const rawFormats = editor.options.get(settingName);
    const data = process(split(rawFormats, delimiter));
    return {
      type: "basic",
      data
    };
  };
  const alignMenuItems = [
    {
      title: "Left",
      icon: "align-left",
      format: "alignleft",
      command: "JustifyLeft"
    },
    {
      title: "Center",
      icon: "align-center",
      format: "aligncenter",
      command: "JustifyCenter"
    },
    {
      title: "Right",
      icon: "align-right",
      format: "alignright",
      command: "JustifyRight"
    },
    {
      title: "Justify",
      icon: "align-justify",
      format: "alignjustify",
      command: "JustifyFull"
    }
  ];
  const getSpec$4 = (editor) => {
    const getMatchingValue = () => find$5(alignMenuItems, (item2) => editor.formatter.match(item2.format));
    const isSelectedFor = (format) => () => editor.formatter.match(format);
    const getPreviewFor = (_format) => Optional.none;
    const updateSelectMenuIcon = (comp) => {
      const match = getMatchingValue();
      const alignment = match.fold(constant$1("left"), (item2) => item2.title.toLowerCase());
      emitWith(comp, updateMenuIcon, { icon: `align-${alignment}` });
    };
    const dataset2 = buildBasicStaticDataset(alignMenuItems);
    const onAction2 = (rawItem) => () => find$5(alignMenuItems, (item2) => item2.format === rawItem.format).each((item2) => editor.execCommand(item2.command));
    return {
      tooltip: "Align",
      text: Optional.none(),
      icon: Optional.some("align-left"),
      isSelectedFor,
      getCurrentValue: Optional.none,
      getPreviewFor,
      onAction: onAction2,
      updateText: updateSelectMenuIcon,
      dataset: dataset2,
      shouldHide: false,
      isInvalid: (item2) => !editor.formatter.canApply(item2.format)
    };
  };
  const createAlignButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$4(editor));
  const createAlignMenu = (editor, backstage) => {
    const menuItems = createMenuItems(editor, backstage, getSpec$4(editor));
    editor.ui.registry.addNestedMenuItem("align", {
      text: backstage.shared.providers.translate("Align"),
      getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
    });
  };
  const findNearest = (editor, getStyles) => {
    const styles = getStyles();
    const formats = map$2(styles, (style) => style.format);
    return Optional.from(editor.formatter.closest(formats)).bind((fmt) => find$5(styles, (data) => data.format === fmt)).orThunk(() => someIf(editor.formatter.match("p"), {
      title: "Paragraph",
      format: "p"
    }));
  };
  const getSpec$3 = (editor) => {
    const fallbackFormat = "Paragraph";
    const isSelectedFor = (format) => () => editor.formatter.match(format);
    const getPreviewFor = (format) => () => {
      const fmt = editor.formatter.get(format);
      return Optional.some({
        tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || "div" : "div",
        styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
      });
    };
    const updateSelectMenuText = (comp) => {
      const detectedFormat = findNearest(editor, () => dataset2.data);
      const text2 = detectedFormat.fold(constant$1(fallbackFormat), (fmt) => fmt.title);
      emitWith(comp, updateMenuText, { text: text2 });
    };
    const dataset2 = buildBasicSettingsDataset(editor, "block_formats", Delimiter.SemiColon);
    return {
      tooltip: "Blocks",
      text: Optional.some(fallbackFormat),
      icon: Optional.none(),
      isSelectedFor,
      getCurrentValue: Optional.none,
      getPreviewFor,
      onAction: onActionToggleFormat$1(editor),
      updateText: updateSelectMenuText,
      dataset: dataset2,
      shouldHide: false,
      isInvalid: (item2) => !editor.formatter.canApply(item2.format)
    };
  };
  const createBlocksButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$3(editor));
  const createBlocksMenu = (editor, backstage) => {
    const menuItems = createMenuItems(editor, backstage, getSpec$3(editor));
    editor.ui.registry.addNestedMenuItem("blocks", {
      text: "Blocks",
      getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
    });
  };
  const systemStackFonts = [
    "-apple-system",
    "Segoe UI",
    "Roboto",
    "Helvetica Neue",
    "sans-serif"
  ];
  const splitFonts = (fontFamily) => {
    const fonts = fontFamily.split(/\s*,\s*/);
    return map$2(fonts, (font) => font.replace(/^['"]+|['"]+$/g, ""));
  };
  const isSystemFontStack = (fontFamily) => {
    const matchesSystemStack = () => {
      const fonts = splitFonts(fontFamily.toLowerCase());
      return forall(systemStackFonts, (font) => fonts.indexOf(font.toLowerCase()) > -1);
    };
    return fontFamily.indexOf("-apple-system") === 0 && matchesSystemStack();
  };
  const getSpec$2 = (editor) => {
    const systemFont = "System Font";
    const getMatchingValue = () => {
      const getFirstFont = (fontFamily2) => fontFamily2 ? splitFonts(fontFamily2)[0] : "";
      const fontFamily = editor.queryCommandValue("FontName");
      const items = dataset2.data;
      const font = fontFamily ? fontFamily.toLowerCase() : "";
      const matchOpt = find$5(items, (item2) => {
        const format = item2.format;
        return format.toLowerCase() === font || getFirstFont(format).toLowerCase() === getFirstFont(font).toLowerCase();
      }).orThunk(() => {
        return someIf(isSystemFontStack(font), {
          title: systemFont,
          format: font
        });
      });
      return {
        matchOpt,
        font: fontFamily
      };
    };
    const isSelectedFor = (item2) => (valueOpt) => valueOpt.exists((value2) => value2.format === item2);
    const getCurrentValue = () => {
      const { matchOpt } = getMatchingValue();
      return matchOpt;
    };
    const getPreviewFor = (item2) => () => Optional.some({
      tag: "div",
      styles: item2.indexOf("dings") === -1 ? { "font-family": item2 } : {}
    });
    const onAction2 = (rawItem) => () => {
      editor.undoManager.transact(() => {
        editor.focus();
        editor.execCommand("FontName", false, rawItem.format);
      });
    };
    const updateSelectMenuText = (comp) => {
      const { matchOpt, font } = getMatchingValue();
      const text2 = matchOpt.fold(constant$1(font), (item2) => item2.title);
      emitWith(comp, updateMenuText, { text: text2 });
    };
    const dataset2 = buildBasicSettingsDataset(editor, "font_family_formats", Delimiter.SemiColon);
    return {
      tooltip: "Fonts",
      text: Optional.some(systemFont),
      icon: Optional.none(),
      isSelectedFor,
      getCurrentValue,
      getPreviewFor,
      onAction: onAction2,
      updateText: updateSelectMenuText,
      dataset: dataset2,
      shouldHide: false,
      isInvalid: never
    };
  };
  const createFontFamilyButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$2(editor));
  const createFontFamilyMenu = (editor, backstage) => {
    const menuItems = createMenuItems(editor, backstage, getSpec$2(editor));
    editor.ui.registry.addNestedMenuItem("fontfamily", {
      text: backstage.shared.providers.translate("Fonts"),
      getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
    });
  };
  const legacyFontSizes = {
    "8pt": "1",
    "10pt": "2",
    "12pt": "3",
    "14pt": "4",
    "18pt": "5",
    "24pt": "6",
    "36pt": "7"
  };
  const keywordFontSizes = {
    "xx-small": "7pt",
    "x-small": "8pt",
    "small": "10pt",
    "medium": "12pt",
    "large": "14pt",
    "x-large": "18pt",
    "xx-large": "24pt"
  };
  const round = (number2, precision) => {
    const factor = Math.pow(10, precision);
    return Math.round(number2 * factor) / factor;
  };
  const toPt = (fontSize, precision) => {
    if (/[0-9.]+px$/.test(fontSize)) {
      return round(parseInt(fontSize, 10) * 72 / 96, precision || 0) + "pt";
    } else {
      return get$g(keywordFontSizes, fontSize).getOr(fontSize);
    }
  };
  const toLegacy = (fontSize) => get$g(legacyFontSizes, fontSize).getOr("");
  const getSpec$1 = (editor) => {
    const getMatchingValue = () => {
      let matchOpt = Optional.none();
      const items = dataset2.data;
      const fontSize = editor.queryCommandValue("FontSize");
      if (fontSize) {
        for (let precision = 3; matchOpt.isNone() && precision >= 0; precision--) {
          const pt = toPt(fontSize, precision);
          const legacy = toLegacy(pt);
          matchOpt = find$5(items, (item2) => item2.format === fontSize || item2.format === pt || item2.format === legacy);
        }
      }
      return {
        matchOpt,
        size: fontSize
      };
    };
    const isSelectedFor = (item2) => (valueOpt) => valueOpt.exists((value2) => value2.format === item2);
    const getCurrentValue = () => {
      const { matchOpt } = getMatchingValue();
      return matchOpt;
    };
    const getPreviewFor = constant$1(Optional.none);
    const onAction2 = (rawItem) => () => {
      editor.undoManager.transact(() => {
        editor.focus();
        editor.execCommand("FontSize", false, rawItem.format);
      });
    };
    const updateSelectMenuText = (comp) => {
      const { matchOpt, size } = getMatchingValue();
      const text2 = matchOpt.fold(constant$1(size), (match) => match.title);
      emitWith(comp, updateMenuText, { text: text2 });
    };
    const dataset2 = buildBasicSettingsDataset(editor, "font_size_formats", Delimiter.Space);
    return {
      tooltip: "Font sizes",
      text: Optional.some("12pt"),
      icon: Optional.none(),
      isSelectedFor,
      getPreviewFor,
      getCurrentValue,
      onAction: onAction2,
      updateText: updateSelectMenuText,
      dataset: dataset2,
      shouldHide: false,
      isInvalid: never
    };
  };
  const createFontSizeButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$1(editor));
  const createFontSizeMenu = (editor, backstage) => {
    const menuItems = createMenuItems(editor, backstage, getSpec$1(editor));
    editor.ui.registry.addNestedMenuItem("fontsize", {
      text: "Font sizes",
      getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
    });
  };
  const getSpec = (editor, dataset2) => {
    const fallbackFormat = "Paragraph";
    const isSelectedFor = (format) => () => editor.formatter.match(format);
    const getPreviewFor = (format) => () => {
      const fmt = editor.formatter.get(format);
      return fmt !== void 0 ? Optional.some({
        tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || "div" : "div",
        styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
      }) : Optional.none();
    };
    const updateSelectMenuText = (comp) => {
      const getFormatItems = (fmt) => {
        const subs2 = fmt.items;
        return subs2 !== void 0 && subs2.length > 0 ? bind$3(subs2, getFormatItems) : [{
          title: fmt.title,
          format: fmt.format
        }];
      };
      const flattenedItems = bind$3(getStyleFormats(editor), getFormatItems);
      const detectedFormat = findNearest(editor, constant$1(flattenedItems));
      const text2 = detectedFormat.fold(constant$1(fallbackFormat), (fmt) => fmt.title);
      emitWith(comp, updateMenuText, { text: text2 });
    };
    return {
      tooltip: "Formats",
      text: Optional.some(fallbackFormat),
      icon: Optional.none(),
      isSelectedFor,
      getCurrentValue: Optional.none,
      getPreviewFor,
      onAction: onActionToggleFormat$1(editor),
      updateText: updateSelectMenuText,
      shouldHide: shouldAutoHideStyleFormats(editor),
      isInvalid: (item2) => !editor.formatter.canApply(item2.format),
      dataset: dataset2
    };
  };
  const createStylesButton = (editor, backstage) => {
    const dataset2 = {
      type: "advanced",
      ...backstage.styles
    };
    return createSelectButton(editor, backstage, getSpec(editor, dataset2));
  };
  const createStylesMenu = (editor, backstage) => {
    const dataset2 = {
      type: "advanced",
      ...backstage.styles
    };
    const menuItems = createMenuItems(editor, backstage, getSpec(editor, dataset2));
    editor.ui.registry.addNestedMenuItem("styles", {
      text: "Formats",
      getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
    });
  };
  const events$3 = (reflectingConfig, reflectingState) => {
    const update = (component, data) => {
      reflectingConfig.updateState.each((updateState) => {
        const newState = updateState(component, data);
        reflectingState.set(newState);
      });
      reflectingConfig.renderComponents.each((renderComponents2) => {
        const newComponents = renderComponents2(data, reflectingState.get());
        const replacer = reflectingConfig.reuseDom ? withReuse : withoutReuse;
        replacer(component, newComponents);
      });
    };
    return derive$2([
      run$1(receive(), (component, message) => {
        const receivingData = message;
        if (!receivingData.universal) {
          const channel = reflectingConfig.channel;
          if (contains$2(receivingData.channels, channel)) {
            update(component, receivingData.data);
          }
        }
      }),
      runOnAttached((comp, _se) => {
        reflectingConfig.initialData.each((rawData) => {
          update(comp, rawData);
        });
      })
    ]);
  };
  var ActiveReflecting = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    events: events$3
  });
  const getState = (component, replaceConfig, reflectState) => reflectState;
  var ReflectingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    getState
  });
  var ReflectingSchema = [
    required$1("channel"),
    option$3("renderComponents"),
    option$3("updateState"),
    option$3("initialData"),
    defaultedBoolean("reuseDom", true)
  ];
  const init$3 = () => {
    const cell = Cell(Optional.none());
    const clear2 = () => cell.set(Optional.none());
    const readState = () => cell.get().getOr("none");
    return {
      readState,
      get: cell.get,
      set: cell.set,
      clear: clear2
    };
  };
  var ReflectingState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init: init$3
  });
  const Reflecting = create$3({
    fields: ReflectingSchema,
    name: "reflecting",
    active: ActiveReflecting,
    apis: ReflectingApis,
    state: ReflectingState
  });
  const schema$7 = constant$1([
    required$1("toggleClass"),
    required$1("fetch"),
    onStrictHandler("onExecute"),
    defaulted("getHotspot", Optional.some),
    defaulted("getAnchorOverrides", constant$1({})),
    schema$y(),
    onStrictHandler("onItemExecute"),
    option$3("lazySink"),
    required$1("dom"),
    onHandler("onOpen"),
    field("splitDropdownBehaviours", [
      Coupling,
      Keying,
      Focusing
    ]),
    defaulted("matchWidth", false),
    defaulted("useMinWidth", false),
    defaulted("eventOrder", {}),
    option$3("role")
  ].concat(sandboxFields()));
  const arrowPart = required({
    factory: Button,
    schema: [required$1("dom")],
    name: "arrow",
    defaults: () => {
      return { buttonBehaviours: derive$1([Focusing.revoke()]) };
    },
    overrides: (detail) => {
      return {
        dom: {
          tag: "span",
          attributes: { role: "presentation" }
        },
        action: (arrow) => {
          arrow.getSystem().getByUid(detail.uid).each(emitExecute);
        },
        buttonBehaviours: derive$1([Toggling.config({
          toggleOnExecute: false,
          toggleClass: detail.toggleClass
        })])
      };
    }
  });
  const buttonPart = required({
    factory: Button,
    schema: [required$1("dom")],
    name: "button",
    defaults: () => {
      return { buttonBehaviours: derive$1([Focusing.revoke()]) };
    },
    overrides: (detail) => {
      return {
        dom: {
          tag: "span",
          attributes: { role: "presentation" }
        },
        action: (btn) => {
          btn.getSystem().getByUid(detail.uid).each((splitDropdown) => {
            detail.onExecute(splitDropdown, btn);
          });
        }
      };
    }
  });
  const parts$3 = constant$1([
    arrowPart,
    buttonPart,
    optional({
      factory: {
        sketch: (spec) => {
          return {
            uid: spec.uid,
            dom: {
              tag: "span",
              styles: { display: "none" },
              attributes: { "aria-hidden": "true" },
              innerHtml: spec.text
            }
          };
        }
      },
      schema: [required$1("text")],
      name: "aria-descriptor"
    }),
    external({
      schema: [tieredMenuMarkers()],
      name: "menu",
      defaults: (detail) => {
        return {
          onExecute: (tmenu, item2) => {
            tmenu.getSystem().getByUid(detail.uid).each((splitDropdown) => {
              detail.onItemExecute(splitDropdown, tmenu, item2);
            });
          }
        };
      }
    }),
    partType$1()
  ]);
  const factory$5 = (detail, components2, spec, externals) => {
    const switchToMenu = (sandbox) => {
      Composing.getCurrent(sandbox).each((current) => {
        Highlighting.highlightFirst(current);
        Keying.focusIn(current);
      });
    };
    const action = (component) => {
      const onOpenSync = switchToMenu;
      togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
    };
    const openMenu = (comp) => {
      action(comp);
      return Optional.some(true);
    };
    const executeOnButton = (comp) => {
      const button2 = getPartOrDie(comp, detail, "button");
      emitExecute(button2);
      return Optional.some(true);
    };
    const buttonEvents = {
      ...derive$2([runOnAttached((component, _simulatedEvent) => {
        const ariaDescriptor = getPart(component, detail, "aria-descriptor");
        ariaDescriptor.each((descriptor) => {
          const descriptorId = generate$6("aria");
          set$9(descriptor.element, "id", descriptorId);
          set$9(component.element, "aria-describedby", descriptorId);
        });
      })]),
      ...events$a(Optional.some(action))
    };
    const apis = {
      repositionMenus: (comp) => {
        if (Toggling.isOn(comp)) {
          repositionMenus(comp);
        }
      }
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      apis,
      eventOrder: {
        ...detail.eventOrder,
        [execute$5()]: [
          "disabling",
          "toggling",
          "alloy.base.behaviour"
        ]
      },
      events: buttonEvents,
      behaviours: augment(detail.splitDropdownBehaviours, [
        Coupling.config({
          others: {
            sandbox: (hotspot) => {
              const arrow = getPartOrDie(hotspot, detail, "arrow");
              const extras = {
                onOpen: () => {
                  Toggling.on(arrow);
                  Toggling.on(hotspot);
                },
                onClose: () => {
                  Toggling.off(arrow);
                  Toggling.off(hotspot);
                }
              };
              return makeSandbox$1(detail, hotspot, extras);
            }
          }
        }),
        Keying.config({
          mode: "special",
          onSpace: executeOnButton,
          onEnter: executeOnButton,
          onDown: openMenu
        }),
        Focusing.config({}),
        Toggling.config({
          toggleOnExecute: false,
          aria: { mode: "expanded" }
        })
      ]),
      domModification: {
        attributes: {
          "role": detail.role.getOr("button"),
          "aria-haspopup": true
        }
      }
    };
  };
  const SplitDropdown = composite({
    name: "SplitDropdown",
    configFields: schema$7(),
    partFields: parts$3(),
    factory: factory$5,
    apis: { repositionMenus: (apis, comp) => apis.repositionMenus(comp) }
  });
  const getButtonApi = (component) => ({
    isEnabled: () => !Disabling.isDisabled(component),
    setEnabled: (state) => Disabling.set(component, !state)
  });
  const getToggleApi = (component) => ({
    setActive: (state) => {
      Toggling.set(component, state);
    },
    isActive: () => Toggling.isOn(component),
    isEnabled: () => !Disabling.isDisabled(component),
    setEnabled: (state) => Disabling.set(component, !state)
  });
  const getTooltipAttributes = (tooltip, providersBackstage) => tooltip.map((tooltip2) => ({
    "aria-label": providersBackstage.translate(tooltip2),
    "title": providersBackstage.translate(tooltip2)
  })).getOr({});
  const focusButtonEvent = generate$6("focus-button");
  const renderCommonStructure = (icon2, text2, tooltip, receiver, behaviours2, providersBackstage) => {
    return {
      dom: {
        tag: "button",
        classes: ["tox-tbtn"].concat(text2.isSome() ? ["tox-tbtn--select"] : []),
        attributes: getTooltipAttributes(tooltip, providersBackstage)
      },
      components: componentRenderPipeline([
        icon2.map((iconName) => renderIconFromPack(iconName, providersBackstage.icons)),
        text2.map((text3) => renderLabel(text3, "tox-tbtn", providersBackstage))
      ]),
      eventOrder: {
        [mousedown()]: [
          "focusing",
          "alloy.base.behaviour",
          "common-button-display-events"
        ]
      },
      buttonBehaviours: derive$1([
        DisablingConfigs.toolbarButton(providersBackstage.isDisabled),
        receivingConfig(),
        config("common-button-display-events", [run$1(mousedown(), (button2, se) => {
          se.event.prevent();
          emit(button2, focusButtonEvent);
        })])
      ].concat(receiver.map((r2) => Reflecting.config({
        channel: r2,
        initialData: {
          icon: icon2,
          text: text2
        },
        renderComponents: (data, _state) => componentRenderPipeline([
          data.icon.map((iconName) => renderIconFromPack(iconName, providersBackstage.icons)),
          data.text.map((text3) => renderLabel(text3, "tox-tbtn", providersBackstage))
        ])
      })).toArray()).concat(behaviours2.getOr([])))
    };
  };
  const renderFloatingToolbarButton = (spec, backstage, identifyButtons2, attributes) => {
    const sharedBackstage = backstage.shared;
    return FloatingToolbarButton.sketch({
      lazySink: sharedBackstage.getSink,
      fetch: () => Future.nu((resolve) => {
        resolve(map$2(identifyButtons2(spec.items), renderToolbarGroup));
      }),
      markers: { toggledClass: "tox-tbtn--enabled" },
      parts: {
        button: renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), sharedBackstage.providers),
        toolbar: {
          dom: {
            tag: "div",
            classes: ["tox-toolbar__overflow"],
            attributes
          }
        }
      }
    });
  };
  const renderCommonToolbarButton = (spec, specialisation, providersBackstage) => {
    const editorOffCell = Cell(noop);
    const structure = renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), providersBackstage);
    return Button.sketch({
      dom: structure.dom,
      components: structure.components,
      eventOrder: toolbarButtonEventOrder,
      buttonBehaviours: derive$1([
        config("toolbar-button-events", [
          onToolbarButtonExecute({
            onAction: spec.onAction,
            getApi: specialisation.getApi
          }),
          onControlAttached(specialisation, editorOffCell),
          onControlDetached(specialisation, editorOffCell)
        ]),
        DisablingConfigs.toolbarButton(() => !spec.enabled || providersBackstage.isDisabled()),
        receivingConfig()
      ].concat(specialisation.toolbarButtonBehaviours))
    });
  };
  const renderToolbarButton = (spec, providersBackstage) => renderToolbarButtonWith(spec, providersBackstage, []);
  const renderToolbarButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
    toolbarButtonBehaviours: [].concat(bonusEvents.length > 0 ? [config("toolbarButtonWith", bonusEvents)] : []),
    getApi: getButtonApi,
    onSetup: spec.onSetup
  }, providersBackstage);
  const renderToolbarToggleButton = (spec, providersBackstage) => renderToolbarToggleButtonWith(spec, providersBackstage, []);
  const renderToolbarToggleButtonWith = (spec, providersBackstage, bonusEvents) => deepMerge(renderCommonToolbarButton(spec, {
    toolbarButtonBehaviours: [
      Replacing.config({}),
      Toggling.config({
        toggleClass: "tox-tbtn--enabled",
        aria: { mode: "pressed" },
        toggleOnExecute: false
      })
    ].concat(bonusEvents.length > 0 ? [config("toolbarToggleButtonWith", bonusEvents)] : []),
    getApi: getToggleApi,
    onSetup: spec.onSetup
  }, providersBackstage));
  const fetchChoices = (getApi2, spec, providersBackstage) => (comp) => Future.nu((callback) => spec.fetch(callback)).map((items) => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6("menu-value"), items, (value2) => {
    spec.onItemAction(getApi2(comp), value2);
  }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), providersBackstage), {
    movement: deriveMenuMovement(spec.columns, spec.presets),
    menuBehaviours: SimpleBehaviours.unnamedEvents(spec.columns !== "auto" ? [] : [runOnAttached((comp2, _se) => {
      detectSize(comp2, 4, classForPreset(spec.presets)).each(({ numRows, numColumns }) => {
        Keying.setGridSize(comp2, numRows, numColumns);
      });
    })])
  }))));
  const renderSplitButton = (spec, sharedBackstage) => {
    const displayChannel = generate$6("channel-update-split-dropdown-display");
    const getApi2 = (comp) => ({
      isEnabled: () => !Disabling.isDisabled(comp),
      setEnabled: (state) => Disabling.set(comp, !state),
      setIconFill: (id, value2) => {
        descendant(comp.element, 'svg path[id="' + id + '"], rect[id="' + id + '"]').each((underlinePath) => {
          set$9(underlinePath, "fill", value2);
        });
      },
      setActive: (state) => {
        set$9(comp.element, "aria-pressed", state);
        descendant(comp.element, "span").each((button2) => {
          comp.getSystem().getByDom(button2).each((buttonComp) => Toggling.set(buttonComp, state));
        });
      },
      isActive: () => descendant(comp.element, "span").exists((button2) => comp.getSystem().getByDom(button2).exists(Toggling.isOn))
    });
    const editorOffCell = Cell(noop);
    const specialisation = {
      getApi: getApi2,
      onSetup: spec.onSetup
    };
    return SplitDropdown.sketch({
      dom: {
        tag: "div",
        classes: ["tox-split-button"],
        attributes: {
          "aria-pressed": false,
          ...getTooltipAttributes(spec.tooltip, sharedBackstage.providers)
        }
      },
      onExecute: (button2) => {
        spec.onAction(getApi2(button2));
      },
      onItemExecute: (_a, _b, _c) => {
      },
      splitDropdownBehaviours: derive$1([
        DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
        receivingConfig(),
        config("split-dropdown-events", [
          run$1(focusButtonEvent, Focusing.focus),
          onControlAttached(specialisation, editorOffCell),
          onControlDetached(specialisation, editorOffCell)
        ]),
        Unselecting.config({})
      ]),
      eventOrder: {
        [attachedToDom()]: [
          "alloy.base.behaviour",
          "split-dropdown-events"
        ]
      },
      toggleClass: "tox-tbtn--enabled",
      lazySink: sharedBackstage.getSink,
      fetch: fetchChoices(getApi2, spec, sharedBackstage.providers),
      parts: { menu: part(false, spec.columns, spec.presets) },
      components: [
        SplitDropdown.parts.button(renderCommonStructure(spec.icon, spec.text, Optional.none(), Optional.some(displayChannel), Optional.some([Toggling.config({
          toggleClass: "tox-tbtn--enabled",
          toggleOnExecute: false
        })]), sharedBackstage.providers)),
        SplitDropdown.parts.arrow({
          dom: {
            tag: "button",
            classes: [
              "tox-tbtn",
              "tox-split-button__chevron"
            ],
            innerHtml: get$2("chevron-down", sharedBackstage.providers.icons)
          },
          buttonBehaviours: derive$1([
            DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
            receivingConfig(),
            addFocusableBehaviour()
          ])
        }),
        SplitDropdown.parts["aria-descriptor"]({ text: sharedBackstage.providers.translate("To open the popup, press Shift+Enter") })
      ]
    });
  };
  const defaultToolbar = [
    {
      name: "history",
      items: [
        "undo",
        "redo"
      ]
    },
    {
      name: "styles",
      items: ["styles"]
    },
    {
      name: "formatting",
      items: [
        "bold",
        "italic"
      ]
    },
    {
      name: "alignment",
      items: [
        "alignleft",
        "aligncenter",
        "alignright",
        "alignjustify"
      ]
    },
    {
      name: "indentation",
      items: [
        "outdent",
        "indent"
      ]
    },
    {
      name: "permanent pen",
      items: ["permanentpen"]
    },
    {
      name: "comments",
      items: ["addcomment"]
    }
  ];
  const renderFromBridge = (bridgeBuilder, render2) => (spec, extras, editor) => {
    const internal = bridgeBuilder(spec).mapError((errInfo) => formatError(errInfo)).getOrDie();
    return render2(internal, extras, editor);
  };
  const types = {
    button: renderFromBridge(createToolbarButton, (s, extras) => renderToolbarButton(s, extras.backstage.shared.providers)),
    togglebutton: renderFromBridge(createToggleButton, (s, extras) => renderToolbarToggleButton(s, extras.backstage.shared.providers)),
    menubutton: renderFromBridge(createMenuButton, (s, extras) => renderMenuButton(s, "tox-tbtn", extras.backstage, Optional.none())),
    splitbutton: renderFromBridge(createSplitButton, (s, extras) => renderSplitButton(s, extras.backstage.shared)),
    grouptoolbarbutton: renderFromBridge(createGroupToolbarButton, (s, extras, editor) => {
      const buttons = editor.ui.registry.getAll().buttons;
      const identify = (toolbar) => identifyButtons(editor, {
        buttons,
        toolbar,
        allowToolbarGroups: false
      }, extras, Optional.none());
      const attributes = { [Attribute]: extras.backstage.shared.header.isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop };
      switch (getToolbarMode(editor)) {
        case ToolbarMode$1.floating:
          return renderFloatingToolbarButton(s, extras.backstage, identify, attributes);
        default:
          throw new Error("Toolbar groups are only supported when using floating toolbar mode");
      }
    }),
    styleSelectButton: (editor, extras) => createStylesButton(editor, extras.backstage),
    fontsizeSelectButton: (editor, extras) => createFontSizeButton(editor, extras.backstage),
    fontSelectButton: (editor, extras) => createFontFamilyButton(editor, extras.backstage),
    formatButton: (editor, extras) => createBlocksButton(editor, extras.backstage),
    alignMenuButton: (editor, extras) => createAlignButton(editor, extras.backstage)
  };
  const extractFrom = (spec, extras, editor) => get$g(types, spec.type).fold(() => {
    console.error("skipping button defined by", spec);
    return Optional.none();
  }, (render2) => Optional.some(render2(spec, extras, editor)));
  const bespokeButtons = {
    styles: types.styleSelectButton,
    fontsize: types.fontsizeSelectButton,
    fontfamily: types.fontSelectButton,
    blocks: types.formatButton,
    align: types.alignMenuButton
  };
  const removeUnusedDefaults = (buttons) => {
    const filteredItemGroups = map$2(defaultToolbar, (group2) => {
      const items = filter$2(group2.items, (subItem) => has$2(buttons, subItem) || has$2(bespokeButtons, subItem));
      return {
        name: group2.name,
        items
      };
    });
    return filter$2(filteredItemGroups, (group2) => group2.items.length > 0);
  };
  const convertStringToolbar = (strToolbar) => {
    const groupsStrings = strToolbar.split("|");
    return map$2(groupsStrings, (g) => ({ items: g.trim().split(" ") }));
  };
  const isToolbarGroupSettingArray = (toolbar) => isArrayOf(toolbar, (t2) => has$2(t2, "name") && has$2(t2, "items"));
  const createToolbar = (toolbarConfig) => {
    const toolbar = toolbarConfig.toolbar;
    const buttons = toolbarConfig.buttons;
    if (toolbar === false) {
      return [];
    } else if (toolbar === void 0 || toolbar === true) {
      return removeUnusedDefaults(buttons);
    } else if (isString(toolbar)) {
      return convertStringToolbar(toolbar);
    } else if (isToolbarGroupSettingArray(toolbar)) {
      return toolbar;
    } else {
      console.error("Toolbar type should be string, string[], boolean or ToolbarGroup[]");
      return [];
    }
  };
  const lookupButton = (editor, buttons, toolbarItem, allowToolbarGroups, extras, prefixes) => get$g(buttons, toolbarItem.toLowerCase()).orThunk(() => prefixes.bind((ps) => findMap(ps, (prefix2) => get$g(buttons, prefix2 + toolbarItem.toLowerCase())))).fold(() => get$g(bespokeButtons, toolbarItem.toLowerCase()).map((r2) => r2(editor, extras)).orThunk(() => Optional.none()), (spec) => {
    if (spec.type === "grouptoolbarbutton" && !allowToolbarGroups) {
      console.warn(`Ignoring the '${toolbarItem}' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`);
      return Optional.none();
    } else {
      return extractFrom(spec, extras, editor);
    }
  });
  const identifyButtons = (editor, toolbarConfig, extras, prefixes) => {
    const toolbarGroups = createToolbar(toolbarConfig);
    const groups = map$2(toolbarGroups, (group2) => {
      const items = bind$3(group2.items, (toolbarItem) => toolbarItem.trim().length === 0 ? [] : lookupButton(editor, toolbarConfig.buttons, toolbarItem, toolbarConfig.allowToolbarGroups, extras, prefixes).toArray());
      return {
        title: Optional.from(editor.translate(group2.name)),
        items
      };
    });
    return filter$2(groups, (group2) => group2.items.length > 0);
  };
  const setToolbar = (editor, uiComponents, rawUiConfig, backstage) => {
    const comp = uiComponents.outerContainer;
    const toolbarConfig = rawUiConfig.toolbar;
    const toolbarButtonsConfig = rawUiConfig.buttons;
    if (isArrayOf(toolbarConfig, isString)) {
      const toolbars = toolbarConfig.map((t2) => {
        const config2 = {
          toolbar: t2,
          buttons: toolbarButtonsConfig,
          allowToolbarGroups: rawUiConfig.allowToolbarGroups
        };
        return identifyButtons(editor, config2, { backstage }, Optional.none());
      });
      OuterContainer.setToolbars(comp, toolbars);
    } else {
      OuterContainer.setToolbar(comp, identifyButtons(editor, rawUiConfig, { backstage }, Optional.none()));
    }
  };
  const detection = detect$1();
  const isiOS12 = detection.os.isiOS() && detection.os.version.major <= 12;
  const setupEvents$1 = (editor, uiComponents) => {
    const dom2 = editor.dom;
    let contentWindow = editor.getWin();
    const initialDocEle = editor.getDoc().documentElement;
    const lastWindowDimensions = Cell(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
    const lastDocumentDimensions = Cell(SugarPosition(initialDocEle.offsetWidth, initialDocEle.offsetHeight));
    const resizeWindow = () => {
      const outer = lastWindowDimensions.get();
      if (outer.left !== contentWindow.innerWidth || outer.top !== contentWindow.innerHeight) {
        lastWindowDimensions.set(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
        fireResizeContent(editor);
      }
    };
    const resizeDocument = () => {
      const docEle = editor.getDoc().documentElement;
      const inner = lastDocumentDimensions.get();
      if (inner.left !== docEle.offsetWidth || inner.top !== docEle.offsetHeight) {
        lastDocumentDimensions.set(SugarPosition(docEle.offsetWidth, docEle.offsetHeight));
        fireResizeContent(editor);
      }
    };
    const scroll = (e) => fireScrollContent(editor, e);
    dom2.bind(contentWindow, "resize", resizeWindow);
    dom2.bind(contentWindow, "scroll", scroll);
    const elementLoad = capture(SugarElement.fromDom(editor.getBody()), "load", resizeDocument);
    const mothership = uiComponents.uiMothership.element;
    editor.on("hide", () => {
      set$8(mothership, "display", "none");
    });
    editor.on("show", () => {
      remove$6(mothership, "display");
    });
    editor.on("NodeChange", resizeDocument);
    editor.on("remove", () => {
      elementLoad.unbind();
      dom2.unbind(contentWindow, "resize", resizeWindow);
      dom2.unbind(contentWindow, "scroll", scroll);
      contentWindow = null;
    });
  };
  const render$1 = (editor, uiComponents, rawUiConfig, backstage, args) => {
    const lastToolbarWidth = Cell(0);
    const outerContainer = uiComponents.outerContainer;
    iframe(editor);
    const eTargetNode = SugarElement.fromDom(args.targetNode);
    const uiRoot = getContentContainer(getRootNode(eTargetNode));
    attachSystemAfter(eTargetNode, uiComponents.mothership);
    attachSystem(uiRoot, uiComponents.uiMothership);
    editor.on("PostRender", () => {
      setToolbar(editor, uiComponents, rawUiConfig, backstage);
      lastToolbarWidth.set(editor.getWin().innerWidth);
      OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
      OuterContainer.setSidebar(outerContainer, rawUiConfig.sidebar, getSidebarShow(editor));
      setupEvents$1(editor, uiComponents);
    });
    const socket = OuterContainer.getSocket(outerContainer).getOrDie("Could not find expected socket element");
    if (isiOS12) {
      setAll(socket.element, {
        "overflow": "scroll",
        "-webkit-overflow-scrolling": "touch"
      });
      const limit = first(() => {
        editor.dispatch("ScrollContent");
      }, 20);
      const unbinder = bind(socket.element, "scroll", limit.throttle);
      editor.on("remove", unbinder.unbind);
    }
    setupReadonlyModeSwitch(editor, uiComponents);
    editor.addCommand("ToggleSidebar", (_ui, value2) => {
      OuterContainer.toggleSidebar(outerContainer, value2);
      editor.dispatch("ToggleSidebar");
    });
    editor.addQueryValueHandler("ToggleSidebar", () => OuterContainer.whichSidebar(outerContainer));
    const toolbarMode = getToolbarMode(editor);
    const refreshDrawer = () => {
      OuterContainer.refreshToolbar(uiComponents.outerContainer);
    };
    if (toolbarMode === ToolbarMode$1.sliding || toolbarMode === ToolbarMode$1.floating) {
      editor.on("ResizeWindow ResizeEditor ResizeContent", () => {
        const width2 = editor.getWin().innerWidth;
        if (width2 !== lastToolbarWidth.get()) {
          refreshDrawer();
          lastToolbarWidth.set(width2);
        }
      });
    }
    const api2 = {
      setEnabled: (state) => {
        broadcastReadonly(uiComponents, !state);
      },
      isEnabled: () => !Disabling.isDisabled(outerContainer)
    };
    return {
      iframeContainer: socket.element.dom,
      editorContainer: outerContainer.element.dom,
      api: api2
    };
  };
  var Iframe = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    render: render$1
  });
  const parseToInt = (val) => {
    const re = /^[0-9\.]+(|px)$/i;
    if (re.test("" + val)) {
      return Optional.some(parseInt("" + val, 10));
    }
    return Optional.none();
  };
  const numToPx = (val) => isNumber(val) ? val + "px" : val;
  const calcCappedSize = (size, minSize, maxSize) => {
    const minOverride = minSize.filter((min2) => size < min2);
    const maxOverride = maxSize.filter((max2) => size > max2);
    return minOverride.or(maxOverride).getOr(size);
  };
  const getHeight = (editor) => {
    const baseHeight = getHeightOption(editor);
    const minHeight = getMinHeightOption(editor);
    const maxHeight = getMaxHeightOption(editor);
    return parseToInt(baseHeight).map((height2) => calcCappedSize(height2, minHeight, maxHeight));
  };
  const getHeightWithFallback = (editor) => {
    const height2 = getHeight(editor);
    return height2.getOr(getHeightOption(editor));
  };
  const getWidth = (editor) => {
    const baseWidth = getWidthOption(editor);
    const minWidth = getMinWidthOption(editor);
    const maxWidth = getMaxWidthOption(editor);
    return parseToInt(baseWidth).map((width2) => calcCappedSize(width2, minWidth, maxWidth));
  };
  const getWidthWithFallback = (editor) => {
    const width2 = getWidth(editor);
    return width2.getOr(getWidthOption(editor));
  };
  const { ToolbarLocation, ToolbarMode } = Options;
  const InlineHeader = (editor, targetElm, uiComponents, backstage, floatContainer) => {
    const { uiMothership, outerContainer } = uiComponents;
    const DOM = global$7.DOM;
    const useFixedToolbarContainer = useFixedContainer(editor);
    const isSticky = isStickyToolbar(editor);
    const editorMaxWidthOpt = getMaxWidthOption(editor).or(getWidth(editor));
    const headerBackstage = backstage.shared.header;
    const isPositionedAtTop = headerBackstage.isPositionedAtTop;
    const toolbarMode = getToolbarMode(editor);
    const isSplitToolbar = toolbarMode === ToolbarMode.sliding || toolbarMode === ToolbarMode.floating;
    const visible = Cell(false);
    const isVisible2 = () => visible.get() && !editor.removed;
    const calcToolbarOffset = (toolbar) => isSplitToolbar ? toolbar.fold(constant$1(0), (tbar) => tbar.components().length > 1 ? get$d(tbar.components()[1].element) : 0) : 0;
    const calcMode = (container) => {
      switch (getToolbarLocation(editor)) {
        case ToolbarLocation.auto:
          const toolbar = OuterContainer.getToolbar(outerContainer);
          const offset2 = calcToolbarOffset(toolbar);
          const toolbarHeight = get$d(container.element) - offset2;
          const targetBounds = box$1(targetElm);
          const roomAtTop = targetBounds.y > toolbarHeight;
          if (roomAtTop) {
            return "top";
          } else {
            const doc = documentElement(targetElm);
            const docHeight = Math.max(doc.dom.scrollHeight, get$d(doc));
            const roomAtBottom = targetBounds.bottom < docHeight - toolbarHeight;
            if (roomAtBottom) {
              return "bottom";
            } else {
              const winBounds = win();
              const isRoomAtBottomViewport = winBounds.bottom < targetBounds.bottom - toolbarHeight;
              return isRoomAtBottomViewport ? "bottom" : "top";
            }
          }
        case ToolbarLocation.bottom:
          return "bottom";
        case ToolbarLocation.top:
        default:
          return "top";
      }
    };
    const setupMode = (mode) => {
      const container = floatContainer.get();
      Docking.setModes(container, [mode]);
      headerBackstage.setDockingMode(mode);
      const verticalDir = isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop;
      set$9(container.element, Attribute, verticalDir);
    };
    const updateChromeWidth = () => {
      const maxWidth = editorMaxWidthOpt.getOrThunk(() => {
        const bodyMargin = parseToInt(get$e(body(), "margin-left")).getOr(0);
        return get$c(body()) - absolute$3(targetElm).left + bodyMargin;
      });
      set$8(floatContainer.get().element, "max-width", maxWidth + "px");
    };
    const updateChromePosition = () => {
      const toolbar = OuterContainer.getToolbar(outerContainer);
      const offset2 = calcToolbarOffset(toolbar);
      const targetBounds = box$1(targetElm);
      const top2 = isPositionedAtTop() ? Math.max(targetBounds.y - get$d(floatContainer.get().element) + offset2, 0) : targetBounds.bottom;
      setAll(outerContainer.element, {
        position: "absolute",
        top: Math.round(top2) + "px",
        left: Math.round(targetBounds.x) + "px"
      });
    };
    const repositionPopups$1 = () => {
      uiMothership.broadcastOn([repositionPopups()], {});
    };
    const updateChromeUi = (resetDocking = false) => {
      if (!isVisible2()) {
        return;
      }
      if (!useFixedToolbarContainer) {
        updateChromeWidth();
      }
      if (isSplitToolbar) {
        OuterContainer.refreshToolbar(outerContainer);
      }
      if (!useFixedToolbarContainer) {
        updateChromePosition();
      }
      if (isSticky) {
        const floatContainerComp = floatContainer.get();
        resetDocking ? Docking.reset(floatContainerComp) : Docking.refresh(floatContainerComp);
      }
      repositionPopups$1();
    };
    const updateMode = (updateUi = true) => {
      if (useFixedToolbarContainer || !isSticky || !isVisible2()) {
        return;
      }
      const currentMode = headerBackstage.getDockingMode();
      const newMode = calcMode(floatContainer.get());
      if (newMode !== currentMode) {
        setupMode(newMode);
        if (updateUi) {
          updateChromeUi(true);
        }
      }
    };
    const show2 = () => {
      visible.set(true);
      set$8(outerContainer.element, "display", "flex");
      DOM.addClass(editor.getBody(), "mce-edit-focus");
      remove$6(uiMothership.element, "display");
      updateMode(false);
      updateChromeUi();
    };
    const hide = () => {
      visible.set(false);
      if (uiComponents.outerContainer) {
        set$8(outerContainer.element, "display", "none");
        DOM.removeClass(editor.getBody(), "mce-edit-focus");
      }
      set$8(uiMothership.element, "display", "none");
    };
    return {
      isVisible: isVisible2,
      isPositionedAtTop,
      show: show2,
      hide,
      update: updateChromeUi,
      updateMode,
      repositionPopups: repositionPopups$1
    };
  };
  const getTargetPosAndBounds = (targetElm, isToolbarTop) => {
    const bounds2 = box$1(targetElm);
    return {
      pos: isToolbarTop ? bounds2.y : bounds2.bottom,
      bounds: bounds2
    };
  };
  const setupEvents = (editor, targetElm, ui, toolbarPersist) => {
    const prevPosAndBounds = Cell(getTargetPosAndBounds(targetElm, ui.isPositionedAtTop()));
    const resizeContent = (e) => {
      const { pos, bounds: bounds2 } = getTargetPosAndBounds(targetElm, ui.isPositionedAtTop());
      const {
        pos: prevPos,
        bounds: prevBounds
      } = prevPosAndBounds.get();
      const hasResized = bounds2.height !== prevBounds.height || bounds2.width !== prevBounds.width;
      prevPosAndBounds.set({
        pos,
        bounds: bounds2
      });
      if (hasResized) {
        fireResizeContent(editor, e);
      }
      if (ui.isVisible()) {
        if (prevPos !== pos) {
          ui.update(true);
        } else if (hasResized) {
          ui.updateMode();
          ui.repositionPopups();
        }
      }
    };
    if (!toolbarPersist) {
      editor.on("activate", ui.show);
      editor.on("deactivate", ui.hide);
    }
    editor.on("SkinLoaded ResizeWindow", () => ui.update(true));
    editor.on("NodeChange keydown", (e) => {
      requestAnimationFrame(() => resizeContent(e));
    });
    editor.on("ScrollWindow", () => ui.updateMode());
    const elementLoad = unbindable();
    elementLoad.set(capture(SugarElement.fromDom(editor.getBody()), "load", resizeContent));
    editor.on("remove", () => {
      elementLoad.clear();
    });
  };
  const render = (editor, uiComponents, rawUiConfig, backstage, args) => {
    const { mothership, uiMothership, outerContainer } = uiComponents;
    const floatContainer = Cell(null);
    const targetElm = SugarElement.fromDom(args.targetNode);
    const ui = InlineHeader(editor, targetElm, uiComponents, backstage, floatContainer);
    const toolbarPersist = isToolbarPersist(editor);
    inline(editor);
    const render2 = () => {
      if (floatContainer.get()) {
        ui.show();
        return;
      }
      floatContainer.set(OuterContainer.getHeader(outerContainer).getOrDie());
      const uiContainer = getUiContainer(editor);
      attachSystem(uiContainer, mothership);
      attachSystem(uiContainer, uiMothership);
      setToolbar(editor, uiComponents, rawUiConfig, backstage);
      OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
      ui.show();
      setupEvents(editor, targetElm, ui, toolbarPersist);
      editor.nodeChanged();
    };
    editor.on("show", render2);
    editor.on("hide", ui.hide);
    if (!toolbarPersist) {
      editor.on("focus", render2);
      editor.on("blur", ui.hide);
    }
    editor.on("init", () => {
      if (editor.hasFocus() || toolbarPersist) {
        render2();
      }
    });
    setupReadonlyModeSwitch(editor, uiComponents);
    const api2 = {
      show: () => {
        render2();
      },
      hide: () => {
        ui.hide();
      },
      setEnabled: (state) => {
        broadcastReadonly(uiComponents, !state);
      },
      isEnabled: () => !Disabling.isDisabled(outerContainer)
    };
    return {
      editorContainer: outerContainer.element.dom,
      api: api2
    };
  };
  var Inline = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    render
  });
  const showContextToolbarEvent = "contexttoolbar-show";
  const hideContextToolbarEvent = "contexttoolbar-hide";
  const getFormApi = (input2) => ({
    hide: () => emit(input2, sandboxClose()),
    getValue: () => Representing.getValue(input2)
  });
  const runOnExecute = (memInput, original2) => run$1(internalToolbarButtonExecute, (comp, se) => {
    const input2 = memInput.get(comp);
    const formApi = getFormApi(input2);
    original2.onAction(formApi, se.event.buttonApi);
  });
  const renderContextButton = (memInput, button2, extras) => {
    const { primary: primary2, ...rest } = button2.original;
    const bridged = getOrDie(createToolbarButton({
      ...rest,
      type: "button",
      onAction: noop
    }));
    return renderToolbarButtonWith(bridged, extras.backstage.shared.providers, [runOnExecute(memInput, button2)]);
  };
  const renderContextToggleButton = (memInput, button2, extras) => {
    const { primary: primary2, ...rest } = button2.original;
    const bridged = getOrDie(createToggleButton({
      ...rest,
      type: "togglebutton",
      onAction: noop
    }));
    return renderToolbarToggleButtonWith(bridged, extras.backstage.shared.providers, [runOnExecute(memInput, button2)]);
  };
  const generateOne = (memInput, button2, providersBackstage) => {
    const extras = { backstage: { shared: { providers: providersBackstage } } };
    if (button2.type === "contextformtogglebutton") {
      return renderContextToggleButton(memInput, button2, extras);
    } else {
      return renderContextButton(memInput, button2, extras);
    }
  };
  const generate = (memInput, buttons, providersBackstage) => {
    const mementos = map$2(buttons, (button2) => record(generateOne(memInput, button2, providersBackstage)));
    const asSpecs = () => map$2(mementos, (mem) => mem.asSpec());
    const findPrimary = (compInSystem) => findMap(buttons, (button2, i) => {
      if (button2.primary) {
        return Optional.from(mementos[i]).bind((mem) => mem.getOpt(compInSystem)).filter(not(Disabling.isDisabled));
      } else {
        return Optional.none();
      }
    });
    return {
      asSpecs,
      findPrimary
    };
  };
  const buildInitGroups = (ctx, providers) => {
    const inputAttributes = ctx.label.fold(() => ({}), (label2) => ({ "aria-label": label2 }));
    const memInput = record(Input.sketch({
      inputClasses: [
        "tox-toolbar-textfield",
        "tox-toolbar-nav-js"
      ],
      data: ctx.initValue(),
      inputAttributes,
      selectOnFocus: true,
      inputBehaviours: derive$1([Keying.config({
        mode: "special",
        onEnter: (input2) => commands.findPrimary(input2).map((primary2) => {
          emitExecute(primary2);
          return true;
        }),
        onLeft: (comp, se) => {
          se.cut();
          return Optional.none();
        },
        onRight: (comp, se) => {
          se.cut();
          return Optional.none();
        }
      })])
    }));
    const commands = generate(memInput, ctx.commands, providers);
    return [
      {
        title: Optional.none(),
        items: [memInput.asSpec()]
      },
      {
        title: Optional.none(),
        items: commands.asSpecs()
      }
    ];
  };
  const renderContextForm = (toolbarType, ctx, providers) => renderToolbar({
    type: toolbarType,
    uid: generate$6("context-toolbar"),
    initGroups: buildInitGroups(ctx, providers),
    onEscape: Optional.none,
    cyclicKeying: true,
    providers
  });
  const ContextForm = {
    renderContextForm,
    buildInitGroups
  };
  const isVerticalOverlap = (a, b2, threshold = 0.01) => b2.bottom - a.y >= threshold && a.bottom - b2.y >= threshold;
  const getRangeRect = (rng) => {
    const rect2 = rng.getBoundingClientRect();
    if (rect2.height <= 0 && rect2.width <= 0) {
      const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset).element;
      const elm = isText(leaf$1) ? parent(leaf$1) : Optional.some(leaf$1);
      return elm.filter(isElement$1).map((e) => e.dom.getBoundingClientRect()).getOr(rect2);
    } else {
      return rect2;
    }
  };
  const getSelectionBounds = (editor) => {
    const rng = editor.selection.getRng();
    const rect2 = getRangeRect(rng);
    if (editor.inline) {
      const scroll = get$b();
      return bounds(scroll.left + rect2.left, scroll.top + rect2.top, rect2.width, rect2.height);
    } else {
      const bodyPos = absolute$2(SugarElement.fromDom(editor.getBody()));
      return bounds(bodyPos.x + rect2.left, bodyPos.y + rect2.top, rect2.width, rect2.height);
    }
  };
  const getAnchorElementBounds = (editor, lastElement) => lastElement.filter(inBody).map(absolute$2).getOrThunk(() => getSelectionBounds(editor));
  const getHorizontalBounds = (contentAreaBox, viewportBounds, margin) => {
    const x = Math.max(contentAreaBox.x + margin, viewportBounds.x);
    const right2 = Math.min(contentAreaBox.right - margin, viewportBounds.right);
    return {
      x,
      width: right2 - x
    };
  };
  const getVerticalBounds = (editor, contentAreaBox, viewportBounds, isToolbarLocationTop, toolbarType, margin) => {
    const container = SugarElement.fromDom(editor.getContainer());
    const header = descendant(container, ".tox-editor-header").getOr(container);
    const headerBox = box$1(header);
    const isToolbarBelowContentArea = headerBox.y >= contentAreaBox.bottom;
    const isToolbarAbove = isToolbarLocationTop && !isToolbarBelowContentArea;
    if (editor.inline && isToolbarAbove) {
      return {
        y: Math.max(headerBox.bottom + margin, viewportBounds.y),
        bottom: viewportBounds.bottom
      };
    }
    if (editor.inline && !isToolbarAbove) {
      return {
        y: viewportBounds.y,
        bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
      };
    }
    const containerBounds = toolbarType === "line" ? box$1(container) : contentAreaBox;
    if (isToolbarAbove) {
      return {
        y: Math.max(headerBox.bottom + margin, viewportBounds.y),
        bottom: Math.min(containerBounds.bottom - margin, viewportBounds.bottom)
      };
    }
    return {
      y: Math.max(containerBounds.y + margin, viewportBounds.y),
      bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
    };
  };
  const getContextToolbarBounds = (editor, sharedBackstage, toolbarType, margin = 0) => {
    const viewportBounds = getBounds$3(window);
    const contentAreaBox = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
    const toolbarOrMenubarEnabled = isMenubarEnabled(editor) || isToolbarEnabled(editor) || isMultipleToolbars(editor);
    const { x, width: width2 } = getHorizontalBounds(contentAreaBox, viewportBounds, margin);
    if (editor.inline && !toolbarOrMenubarEnabled) {
      return bounds(x, viewportBounds.y, width2, viewportBounds.height);
    } else {
      const isToolbarTop = sharedBackstage.header.isPositionedAtTop();
      const { y, bottom: bottom2 } = getVerticalBounds(editor, contentAreaBox, viewportBounds, isToolbarTop, toolbarType, margin);
      return bounds(x, y, width2, bottom2 - y);
    }
  };
  const bubbleSize$1 = 12;
  const bubbleAlignments$1 = {
    valignCentre: [],
    alignCentre: [],
    alignLeft: ["tox-pop--align-left"],
    alignRight: ["tox-pop--align-right"],
    right: ["tox-pop--right"],
    left: ["tox-pop--left"],
    bottom: ["tox-pop--bottom"],
    top: ["tox-pop--top"],
    inset: ["tox-pop--inset"]
  };
  const anchorOverrides = {
    maxHeightFunction: expandable$1(),
    maxWidthFunction: expandable()
  };
  const isEntireElementSelected = (editor, elem) => {
    const rng = editor.selection.getRng();
    const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset);
    return rng.startContainer === rng.endContainer && rng.startOffset === rng.endOffset - 1 && eq(leaf$1.element, elem);
  };
  const preservePosition = (elem, position2, f) => {
    const currentPosition = getRaw(elem, "position");
    set$8(elem, "position", position2);
    const result = f(elem);
    currentPosition.each((pos) => set$8(elem, "position", pos));
    return result;
  };
  const shouldUseInsetLayouts = (position2) => position2 === "node";
  const determineInsetLayout = (editor, contextbar, elem, data, bounds2) => {
    const selectionBounds = getSelectionBounds(editor);
    const isSameAnchorElement = data.lastElement().exists((prev) => eq(elem, prev));
    if (isEntireElementSelected(editor, elem)) {
      return isSameAnchorElement ? preserve : north;
    } else if (isSameAnchorElement) {
      return preservePosition(contextbar, data.getMode(), () => {
        const isOverlapping = isVerticalOverlap(selectionBounds, box$1(contextbar));
        return isOverlapping && !data.isReposition() ? flip : preserve;
      });
    } else {
      const yBounds = data.getMode() === "fixed" ? bounds2.y + get$b().top : bounds2.y;
      const contextbarHeight = get$d(contextbar) + bubbleSize$1;
      return yBounds + contextbarHeight <= selectionBounds.y ? north : south;
    }
  };
  const getAnchorSpec$2 = (editor, mobile, data, position2) => {
    const smartInsetLayout = (elem) => (anchor2, element2, bubbles, placee, bounds2) => {
      const layout2 = determineInsetLayout(editor, placee, elem, data, bounds2);
      const newAnchor = {
        ...anchor2,
        y: bounds2.y,
        height: bounds2.height
      };
      return {
        ...layout2(newAnchor, element2, bubbles, placee, bounds2),
        alwaysFit: true
      };
    };
    const getInsetLayouts = (elem) => shouldUseInsetLayouts(position2) ? [smartInsetLayout(elem)] : [];
    const desktopAnchorSpecLayouts = {
      onLtr: (elem) => [
        north$2,
        south$2,
        northeast$2,
        southeast$2,
        northwest$2,
        southwest$2
      ].concat(getInsetLayouts(elem)),
      onRtl: (elem) => [
        north$2,
        south$2,
        northwest$2,
        southwest$2,
        northeast$2,
        southeast$2
      ].concat(getInsetLayouts(elem))
    };
    const mobileAnchorSpecLayouts = {
      onLtr: (elem) => [
        south$2,
        southeast$2,
        southwest$2,
        northeast$2,
        northwest$2,
        north$2
      ].concat(getInsetLayouts(elem)),
      onRtl: (elem) => [
        south$2,
        southwest$2,
        southeast$2,
        northwest$2,
        northeast$2,
        north$2
      ].concat(getInsetLayouts(elem))
    };
    return mobile ? mobileAnchorSpecLayouts : desktopAnchorSpecLayouts;
  };
  const getAnchorLayout = (editor, position2, isTouch2, data) => {
    if (position2 === "line") {
      return {
        bubble: nu$5(bubbleSize$1, 0, bubbleAlignments$1),
        layouts: {
          onLtr: () => [east$2],
          onRtl: () => [west$2]
        },
        overrides: anchorOverrides
      };
    } else {
      return {
        bubble: nu$5(0, bubbleSize$1, bubbleAlignments$1, 1 / bubbleSize$1),
        layouts: getAnchorSpec$2(editor, isTouch2, data, position2),
        overrides: anchorOverrides
      };
    }
  };
  const matchTargetWith = (elem, candidates) => {
    const ctxs = filter$2(candidates, (toolbarApi) => toolbarApi.predicate(elem.dom));
    const { pass, fail } = partition$3(ctxs, (t2) => t2.type === "contexttoolbar");
    return {
      contextToolbars: pass,
      contextForms: fail
    };
  };
  const filterByPositionForStartNode = (toolbars) => {
    if (toolbars.length <= 1) {
      return toolbars;
    } else {
      const doesPositionExist = (value2) => exists(toolbars, (t2) => t2.position === value2);
      const filterToolbarsByPosition = (value2) => filter$2(toolbars, (t2) => t2.position === value2);
      const hasSelectionToolbars = doesPositionExist("selection");
      const hasNodeToolbars = doesPositionExist("node");
      if (hasSelectionToolbars || hasNodeToolbars) {
        if (hasNodeToolbars && hasSelectionToolbars) {
          const nodeToolbars = filterToolbarsByPosition("node");
          const selectionToolbars = map$2(filterToolbarsByPosition("selection"), (t2) => ({
            ...t2,
            position: "node"
          }));
          return nodeToolbars.concat(selectionToolbars);
        } else {
          return hasSelectionToolbars ? filterToolbarsByPosition("selection") : filterToolbarsByPosition("node");
        }
      } else {
        return filterToolbarsByPosition("line");
      }
    }
  };
  const filterByPositionForAncestorNode = (toolbars) => {
    if (toolbars.length <= 1) {
      return toolbars;
    } else {
      const findPosition = (value2) => find$5(toolbars, (t2) => t2.position === value2);
      const basePosition = findPosition("selection").orThunk(() => findPosition("node")).orThunk(() => findPosition("line")).map((t2) => t2.position);
      return basePosition.fold(() => [], (pos) => filter$2(toolbars, (t2) => t2.position === pos));
    }
  };
  const matchStartNode = (elem, nodeCandidates, editorCandidates) => {
    const nodeMatches = matchTargetWith(elem, nodeCandidates);
    if (nodeMatches.contextForms.length > 0) {
      return Optional.some({
        elem,
        toolbars: [nodeMatches.contextForms[0]]
      });
    } else {
      const editorMatches = matchTargetWith(elem, editorCandidates);
      if (editorMatches.contextForms.length > 0) {
        return Optional.some({
          elem,
          toolbars: [editorMatches.contextForms[0]]
        });
      } else if (nodeMatches.contextToolbars.length > 0 || editorMatches.contextToolbars.length > 0) {
        const toolbars = filterByPositionForStartNode(nodeMatches.contextToolbars.concat(editorMatches.contextToolbars));
        return Optional.some({
          elem,
          toolbars
        });
      } else {
        return Optional.none();
      }
    }
  };
  const matchAncestor = (isRoot, startNode, scopes) => {
    if (isRoot(startNode)) {
      return Optional.none();
    } else {
      return ancestor$2(startNode, (ancestorElem) => {
        if (isElement$1(ancestorElem)) {
          const { contextToolbars, contextForms } = matchTargetWith(ancestorElem, scopes.inNodeScope);
          const toolbars = contextForms.length > 0 ? contextForms : filterByPositionForAncestorNode(contextToolbars);
          return toolbars.length > 0 ? Optional.some({
            elem: ancestorElem,
            toolbars
          }) : Optional.none();
        } else {
          return Optional.none();
        }
      }, isRoot);
    }
  };
  const lookup$1 = (scopes, editor) => {
    const rootElem = SugarElement.fromDom(editor.getBody());
    const isRoot = (elem) => eq(elem, rootElem);
    const isOutsideRoot = (startNode2) => !isRoot(startNode2) && !contains(rootElem, startNode2);
    const startNode = SugarElement.fromDom(editor.selection.getNode());
    if (isOutsideRoot(startNode)) {
      return Optional.none();
    }
    return matchStartNode(startNode, scopes.inNodeScope, scopes.inEditorScope).orThunk(() => matchAncestor(isRoot, startNode, scopes));
  };
  const categorise = (contextToolbars, navigate) => {
    const forms = {};
    const inNodeScope = [];
    const inEditorScope = [];
    const formNavigators = {};
    const lookupTable = {};
    const registerForm = (key, toolbarSpec) => {
      const contextForm = getOrDie(createContextForm(toolbarSpec));
      forms[key] = contextForm;
      contextForm.launch.map((launch) => {
        formNavigators["form:" + key] = {
          ...toolbarSpec.launch,
          type: launch.type === "contextformtogglebutton" ? "togglebutton" : "button",
          onAction: () => {
            navigate(contextForm);
          }
        };
      });
      if (contextForm.scope === "editor") {
        inEditorScope.push(contextForm);
      } else {
        inNodeScope.push(contextForm);
      }
      lookupTable[key] = contextForm;
    };
    const registerToolbar = (key, toolbarSpec) => {
      createContextToolbar(toolbarSpec).each((contextToolbar) => {
        if (toolbarSpec.scope === "editor") {
          inEditorScope.push(contextToolbar);
        } else {
          inNodeScope.push(contextToolbar);
        }
        lookupTable[key] = contextToolbar;
      });
    };
    const keys$1 = keys(contextToolbars);
    each$1(keys$1, (key) => {
      const toolbarApi = contextToolbars[key];
      if (toolbarApi.type === "contextform") {
        registerForm(key, toolbarApi);
      } else if (toolbarApi.type === "contexttoolbar") {
        registerToolbar(key, toolbarApi);
      }
    });
    return {
      forms,
      inNodeScope,
      inEditorScope,
      lookupTable,
      formNavigators
    };
  };
  const forwardSlideEvent = generate$6("forward-slide");
  const backSlideEvent = generate$6("backward-slide");
  const changeSlideEvent = generate$6("change-slide-event");
  const resizingClass = "tox-pop--resizing";
  const renderContextToolbar = (spec) => {
    const stack = Cell([]);
    return InlineView.sketch({
      dom: {
        tag: "div",
        classes: ["tox-pop"]
      },
      fireDismissalEventInstead: { event: "doNotDismissYet" },
      onShow: (comp) => {
        stack.set([]);
        InlineView.getContent(comp).each((c) => {
          remove$6(c.element, "visibility");
        });
        remove$2(comp.element, resizingClass);
        remove$6(comp.element, "width");
      },
      inlineBehaviours: derive$1([
        config("context-toolbar-events", [
          runOnSource(transitionend(), (comp, se) => {
            if (se.event.raw.propertyName === "width") {
              remove$2(comp.element, resizingClass);
              remove$6(comp.element, "width");
            }
          }),
          run$1(changeSlideEvent, (comp, se) => {
            const elem = comp.element;
            remove$6(elem, "width");
            const currentWidth = get$c(elem);
            InlineView.setContent(comp, se.event.contents);
            add$2(elem, resizingClass);
            const newWidth = get$c(elem);
            set$8(elem, "width", currentWidth + "px");
            InlineView.getContent(comp).each((newContents) => {
              se.event.focus.bind((f) => {
                focus$3(f);
                return search(elem);
              }).orThunk(() => {
                Keying.focusIn(newContents);
                return active$1(getRootNode(elem));
              });
            });
            setTimeout(() => {
              set$8(comp.element, "width", newWidth + "px");
            }, 0);
          }),
          run$1(forwardSlideEvent, (comp, se) => {
            InlineView.getContent(comp).each((oldContents) => {
              stack.set(stack.get().concat([{
                bar: oldContents,
                focus: active$1(getRootNode(comp.element))
              }]));
            });
            emitWith(comp, changeSlideEvent, {
              contents: se.event.forwardContents,
              focus: Optional.none()
            });
          }),
          run$1(backSlideEvent, (comp, _se) => {
            last$1(stack.get()).each((last2) => {
              stack.set(stack.get().slice(0, stack.get().length - 1));
              emitWith(comp, changeSlideEvent, {
                contents: premade(last2.bar),
                focus: last2.focus
              });
            });
          })
        ]),
        Keying.config({
          mode: "special",
          onEscape: (comp) => last$1(stack.get()).fold(() => spec.onEscape(), (_) => {
            emit(comp, backSlideEvent);
            return Optional.some(true);
          })
        })
      ]),
      lazySink: () => Result.value(spec.sink)
    });
  };
  const transitionClass = "tox-pop--transition";
  const register$9 = (editor, registryContextToolbars, sink, extras) => {
    const backstage = extras.backstage;
    const sharedBackstage = backstage.shared;
    const isTouch2 = detect$1().deviceType.isTouch;
    const lastElement = value$2();
    const lastTrigger = value$2();
    const lastContextPosition = value$2();
    const contextbar = build$1(renderContextToolbar({
      sink,
      onEscape: () => {
        editor.focus();
        return Optional.some(true);
      }
    }));
    const getBounds2 = () => {
      const position2 = lastContextPosition.get().getOr("node");
      const margin = shouldUseInsetLayouts(position2) ? 1 : 0;
      return getContextToolbarBounds(editor, sharedBackstage, position2, margin);
    };
    const canLaunchToolbar = () => {
      return !editor.removed && !(isTouch2() && backstage.isContextMenuOpen());
    };
    const isSameLaunchElement = (elem) => is$1(lift2(elem, lastElement.get(), eq), true);
    const shouldContextToolbarHide = () => {
      if (!canLaunchToolbar()) {
        return true;
      } else {
        const contextToolbarBounds = getBounds2();
        const anchorBounds = is$1(lastContextPosition.get(), "node") ? getAnchorElementBounds(editor, lastElement.get()) : getSelectionBounds(editor);
        return contextToolbarBounds.height <= 0 || !isVerticalOverlap(anchorBounds, contextToolbarBounds);
      }
    };
    const close2 = () => {
      lastElement.clear();
      lastTrigger.clear();
      lastContextPosition.clear();
      InlineView.hide(contextbar);
    };
    const hideOrRepositionIfNecessary = () => {
      if (InlineView.isOpen(contextbar)) {
        const contextBarEle = contextbar.element;
        remove$6(contextBarEle, "display");
        if (shouldContextToolbarHide()) {
          set$8(contextBarEle, "display", "none");
        } else {
          lastTrigger.set(0);
          InlineView.reposition(contextbar);
        }
      }
    };
    const wrapInPopDialog = (toolbarSpec) => ({
      dom: {
        tag: "div",
        classes: ["tox-pop__dialog"]
      },
      components: [toolbarSpec],
      behaviours: derive$1([
        Keying.config({ mode: "acyclic" }),
        config("pop-dialog-wrap-events", [
          runOnAttached((comp) => {
            editor.shortcuts.add("ctrl+F9", "focus statusbar", () => Keying.focusIn(comp));
          }),
          runOnDetached((_comp) => {
            editor.shortcuts.remove("ctrl+F9");
          })
        ])
      ])
    });
    const getScopes = cached(() => categorise(registryContextToolbars, (toolbarApi) => {
      const alloySpec = buildToolbar([toolbarApi]);
      emitWith(contextbar, forwardSlideEvent, { forwardContents: wrapInPopDialog(alloySpec) });
    }));
    const buildContextToolbarGroups = (allButtons, ctx) => identifyButtons(editor, {
      buttons: allButtons,
      toolbar: ctx.items,
      allowToolbarGroups: false
    }, extras, Optional.some(["form:"]));
    const buildContextFormGroups = (ctx, providers) => ContextForm.buildInitGroups(ctx, providers);
    const buildToolbar = (toolbars) => {
      const { buttons } = editor.ui.registry.getAll();
      const scopes = getScopes();
      const allButtons = {
        ...buttons,
        ...scopes.formNavigators
      };
      const toolbarType = getToolbarMode(editor) === ToolbarMode$1.scrolling ? ToolbarMode$1.scrolling : ToolbarMode$1.default;
      const initGroups = flatten(map$2(toolbars, (ctx) => ctx.type === "contexttoolbar" ? buildContextToolbarGroups(allButtons, ctx) : buildContextFormGroups(ctx, sharedBackstage.providers)));
      return renderToolbar({
        type: toolbarType,
        uid: generate$6("context-toolbar"),
        initGroups,
        onEscape: Optional.none,
        cyclicKeying: true,
        providers: sharedBackstage.providers
      });
    };
    const getAnchor2 = (position2, element2) => {
      const anchorage = position2 === "node" ? sharedBackstage.anchors.node(element2) : sharedBackstage.anchors.cursor();
      const anchorLayout = getAnchorLayout(editor, position2, isTouch2(), {
        lastElement: lastElement.get,
        isReposition: () => is$1(lastTrigger.get(), 0),
        getMode: () => Positioning.getMode(sink)
      });
      return deepMerge(anchorage, anchorLayout);
    };
    const launchContext = (toolbarApi, elem) => {
      launchContextToolbar.cancel();
      if (!canLaunchToolbar()) {
        return;
      }
      const toolbarSpec = buildToolbar(toolbarApi);
      const position2 = toolbarApi[0].position;
      const anchor2 = getAnchor2(position2, elem);
      lastContextPosition.set(position2);
      lastTrigger.set(1);
      const contextBarEle = contextbar.element;
      remove$6(contextBarEle, "display");
      if (!isSameLaunchElement(elem)) {
        remove$2(contextBarEle, transitionClass);
        Positioning.reset(sink, contextbar);
      }
      InlineView.showWithinBounds(contextbar, wrapInPopDialog(toolbarSpec), {
        anchor: anchor2,
        transition: {
          classes: [transitionClass],
          mode: "placement"
        }
      }, () => Optional.some(getBounds2()));
      elem.fold(lastElement.clear, lastElement.set);
      if (shouldContextToolbarHide()) {
        set$8(contextBarEle, "display", "none");
      }
    };
    const launchContextToolbar = last(() => {
      if (!editor.hasFocus() || editor.removed) {
        return;
      }
      if (has(contextbar.element, transitionClass)) {
        launchContextToolbar.throttle();
      } else {
        const scopes = getScopes();
        lookup$1(scopes, editor).fold(close2, (info) => {
          launchContext(info.toolbars, Optional.some(info.elem));
        });
      }
    }, 17);
    editor.on("init", () => {
      editor.on("remove", close2);
      editor.on("ScrollContent ScrollWindow ObjectResized ResizeEditor longpress", hideOrRepositionIfNecessary);
      editor.on("click keyup focus SetContent", launchContextToolbar.throttle);
      editor.on(hideContextToolbarEvent, close2);
      editor.on(showContextToolbarEvent, (e) => {
        const scopes = getScopes();
        get$g(scopes.lookupTable, e.toolbarKey).each((ctx) => {
          launchContext([ctx], someIf(e.target !== editor, e.target));
          InlineView.getContent(contextbar).each(Keying.focusIn);
        });
      });
      editor.on("focusout", (_e) => {
        global$9.setEditorTimeout(editor, () => {
          if (search(sink.element).isNone() && search(contextbar.element).isNone()) {
            close2();
          }
        }, 0);
      });
      editor.on("SwitchMode", () => {
        if (editor.mode.isReadOnly()) {
          close2();
        }
      });
      editor.on("AfterProgressState", (event) => {
        if (event.state) {
          close2();
        } else if (editor.hasFocus()) {
          launchContextToolbar.throttle();
        }
      });
      editor.on("NodeChange", (_e) => {
        search(contextbar.element).fold(launchContextToolbar.throttle, noop);
      });
    });
  };
  const register$8 = (editor) => {
    const alignToolbarButtons = [
      {
        name: "alignleft",
        text: "Align left",
        cmd: "JustifyLeft",
        icon: "align-left"
      },
      {
        name: "aligncenter",
        text: "Align center",
        cmd: "JustifyCenter",
        icon: "align-center"
      },
      {
        name: "alignright",
        text: "Align right",
        cmd: "JustifyRight",
        icon: "align-right"
      },
      {
        name: "alignjustify",
        text: "Justify",
        cmd: "JustifyFull",
        icon: "align-justify"
      }
    ];
    each$1(alignToolbarButtons, (item2) => {
      editor.ui.registry.addToggleButton(item2.name, {
        tooltip: item2.text,
        icon: item2.icon,
        onAction: onActionExecCommand(editor, item2.cmd),
        onSetup: onSetupFormatToggle(editor, item2.name)
      });
    });
    editor.ui.registry.addButton("alignnone", {
      tooltip: "No alignment",
      icon: "align-none",
      onAction: onActionExecCommand(editor, "JustifyNone")
    });
  };
  const units = {
    unsupportedLength: [
      "em",
      "ex",
      "cap",
      "ch",
      "ic",
      "rem",
      "lh",
      "rlh",
      "vw",
      "vh",
      "vi",
      "vb",
      "vmin",
      "vmax",
      "cm",
      "mm",
      "Q",
      "in",
      "pc",
      "pt",
      "px"
    ],
    fixed: [
      "px",
      "pt"
    ],
    relative: ["%"],
    empty: [""]
  };
  const pattern = (() => {
    const decimalDigits = "[0-9]+";
    const signedInteger = "[+-]?" + decimalDigits;
    const exponentPart = "[eE]" + signedInteger;
    const dot = "\\.";
    const opt = (input2) => `(?:${input2})?`;
    const unsignedDecimalLiteral = [
      "Infinity",
      decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
      dot + decimalDigits + opt(exponentPart),
      decimalDigits + opt(exponentPart)
    ].join("|");
    const float = `[+-]?(?:${unsignedDecimalLiteral})`;
    return new RegExp(`^(${float})(.*)$`);
  })();
  const isUnit = (unit, accepted) => exists(accepted, (acc) => exists(units[acc], (check) => unit === check));
  const parse = (input2, accepted) => {
    const match = Optional.from(pattern.exec(input2));
    return match.bind((array) => {
      const value2 = Number(array[1]);
      const unitRaw = array[2];
      if (isUnit(unitRaw, accepted)) {
        return Optional.some({
          value: value2,
          unit: unitRaw
        });
      } else {
        return Optional.none();
      }
    });
  };
  const normalise = (input2, accepted) => parse(input2, accepted).map(({ value: value2, unit }) => value2 + unit);
  const registerController = (editor, spec) => {
    const getMenuItems = () => {
      const options = spec.getOptions(editor);
      const initial = spec.getCurrent(editor).map(spec.hash);
      const current = value$2();
      return map$2(options, (value2) => ({
        type: "togglemenuitem",
        text: spec.display(value2),
        onSetup: (api2) => {
          const setActive = (active2) => {
            if (active2) {
              current.on((oldApi) => oldApi.setActive(false));
              current.set(api2);
            }
            api2.setActive(active2);
          };
          setActive(is$1(initial, spec.hash(value2)));
          const unbindWatcher = spec.watcher(editor, value2, setActive);
          return () => {
            current.clear();
            unbindWatcher();
          };
        },
        onAction: () => spec.setCurrent(editor, value2)
      }));
    };
    editor.ui.registry.addMenuButton(spec.name, {
      tooltip: spec.text,
      icon: spec.icon,
      fetch: (callback) => callback(getMenuItems()),
      onSetup: spec.onToolbarSetup
    });
    editor.ui.registry.addNestedMenuItem(spec.name, {
      type: "nestedmenuitem",
      text: spec.text,
      getSubmenuItems: getMenuItems,
      onSetup: spec.onMenuSetup
    });
  };
  const lineHeightSpec = {
    name: "lineheight",
    text: "Line height",
    icon: "line-height",
    getOptions: getLineHeightFormats,
    hash: (input2) => normalise(input2, [
      "fixed",
      "relative",
      "empty"
    ]).getOr(input2),
    display: identity,
    watcher: (editor, value2, callback) => editor.formatter.formatChanged("lineheight", callback, false, { value: value2 }).unbind,
    getCurrent: (editor) => Optional.from(editor.queryCommandValue("LineHeight")),
    setCurrent: (editor, value2) => editor.execCommand("LineHeight", false, value2)
  };
  const languageSpec = (editor) => {
    const settingsOpt = Optional.from(getContentLanguages(editor));
    return settingsOpt.map((settings) => ({
      name: "language",
      text: "Language",
      icon: "language",
      getOptions: constant$1(settings),
      hash: (input2) => isUndefined(input2.customCode) ? input2.code : `${input2.code}/${input2.customCode}`,
      display: (input2) => input2.title,
      watcher: (editor2, value2, callback) => editor2.formatter.formatChanged("lang", callback, false, {
        value: value2.code,
        customValue: value2.customCode
      }).unbind,
      getCurrent: (editor2) => {
        const node = SugarElement.fromDom(editor2.selection.getNode());
        return closest$4(node, (n) => Optional.some(n).filter(isElement$1).bind((ele) => {
          const codeOpt = getOpt(ele, "lang");
          return codeOpt.map((code) => {
            const customCode = getOpt(ele, "data-mce-lang").getOrUndefined();
            return {
              code,
              customCode,
              title: ""
            };
          });
        }));
      },
      setCurrent: (editor2, lang) => editor2.execCommand("Lang", false, lang),
      onToolbarSetup: (api2) => {
        const unbinder = unbindable();
        api2.setActive(editor.formatter.match("lang", {}, void 0, true));
        unbinder.set(editor.formatter.formatChanged("lang", api2.setActive, true));
        return unbinder.clear;
      }
    }));
  };
  const register$7 = (editor) => {
    registerController(editor, lineHeightSpec);
    languageSpec(editor).each((spec) => registerController(editor, spec));
  };
  const register$6 = (editor, backstage) => {
    createAlignMenu(editor, backstage);
    createFontFamilyMenu(editor, backstage);
    createStylesMenu(editor, backstage);
    createBlocksMenu(editor, backstage);
    createFontSizeMenu(editor, backstage);
  };
  const onSetupOutdentState = (editor) => onSetupEvent(editor, "NodeChange", (api2) => {
    api2.setEnabled(editor.queryCommandState("outdent"));
  });
  const registerButtons$2 = (editor) => {
    editor.ui.registry.addButton("outdent", {
      tooltip: "Decrease indent",
      icon: "outdent",
      onSetup: onSetupOutdentState(editor),
      onAction: onActionExecCommand(editor, "outdent")
    });
    editor.ui.registry.addButton("indent", {
      tooltip: "Increase indent",
      icon: "indent",
      onAction: onActionExecCommand(editor, "indent")
    });
  };
  const register$5 = (editor) => {
    registerButtons$2(editor);
  };
  const makeSetupHandler = (editor, pasteAsText) => (api2) => {
    api2.setActive(pasteAsText.get());
    const pastePlainTextToggleHandler = (e) => {
      pasteAsText.set(e.state);
      api2.setActive(e.state);
    };
    editor.on("PastePlainTextToggle", pastePlainTextToggleHandler);
    return () => editor.off("PastePlainTextToggle", pastePlainTextToggleHandler);
  };
  const register$4 = (editor) => {
    const pasteAsText = Cell(getPasteAsText(editor));
    const onAction2 = () => editor.execCommand("mceTogglePlainTextPaste");
    editor.ui.registry.addToggleButton("pastetext", {
      active: false,
      icon: "paste-text",
      tooltip: "Paste as text",
      onAction: onAction2,
      onSetup: makeSetupHandler(editor, pasteAsText)
    });
    editor.ui.registry.addToggleMenuItem("pastetext", {
      text: "Paste as text",
      icon: "paste-text",
      onAction: onAction2,
      onSetup: makeSetupHandler(editor, pasteAsText)
    });
  };
  const onActionToggleFormat = (editor, fmt) => () => {
    editor.execCommand("mceToggleFormat", false, fmt);
  };
  const registerFormatButtons = (editor) => {
    global$1.each([
      {
        name: "bold",
        text: "Bold",
        icon: "bold"
      },
      {
        name: "italic",
        text: "Italic",
        icon: "italic"
      },
      {
        name: "underline",
        text: "Underline",
        icon: "underline"
      },
      {
        name: "strikethrough",
        text: "Strikethrough",
        icon: "strike-through"
      },
      {
        name: "subscript",
        text: "Subscript",
        icon: "subscript"
      },
      {
        name: "superscript",
        text: "Superscript",
        icon: "superscript"
      }
    ], (btn, _idx) => {
      editor.ui.registry.addToggleButton(btn.name, {
        tooltip: btn.text,
        icon: btn.icon,
        onSetup: onSetupFormatToggle(editor, btn.name),
        onAction: onActionToggleFormat(editor, btn.name)
      });
    });
    for (let i = 1; i <= 6; i++) {
      const name2 = "h" + i;
      editor.ui.registry.addToggleButton(name2, {
        text: name2.toUpperCase(),
        tooltip: "Heading " + i,
        onSetup: onSetupFormatToggle(editor, name2),
        onAction: onActionToggleFormat(editor, name2)
      });
    }
  };
  const registerCommandButtons = (editor) => {
    global$1.each([
      {
        name: "cut",
        text: "Cut",
        action: "Cut",
        icon: "cut"
      },
      {
        name: "copy",
        text: "Copy",
        action: "Copy",
        icon: "copy"
      },
      {
        name: "paste",
        text: "Paste",
        action: "Paste",
        icon: "paste"
      },
      {
        name: "help",
        text: "Help",
        action: "mceHelp",
        icon: "help"
      },
      {
        name: "selectall",
        text: "Select all",
        action: "SelectAll",
        icon: "select-all"
      },
      {
        name: "newdocument",
        text: "New document",
        action: "mceNewDocument",
        icon: "new-document"
      },
      {
        name: "removeformat",
        text: "Clear formatting",
        action: "RemoveFormat",
        icon: "remove-formatting"
      },
      {
        name: "remove",
        text: "Remove",
        action: "Delete",
        icon: "remove"
      },
      {
        name: "print",
        text: "Print",
        action: "mcePrint",
        icon: "print"
      },
      {
        name: "hr",
        text: "Horizontal line",
        action: "InsertHorizontalRule",
        icon: "horizontal-rule"
      }
    ], (btn) => {
      editor.ui.registry.addButton(btn.name, {
        tooltip: btn.text,
        icon: btn.icon,
        onAction: onActionExecCommand(editor, btn.action)
      });
    });
  };
  const registerCommandToggleButtons = (editor) => {
    global$1.each([{
      name: "blockquote",
      text: "Blockquote",
      action: "mceBlockQuote",
      icon: "quote"
    }], (btn) => {
      editor.ui.registry.addToggleButton(btn.name, {
        tooltip: btn.text,
        icon: btn.icon,
        onAction: onActionExecCommand(editor, btn.action),
        onSetup: onSetupFormatToggle(editor, btn.name)
      });
    });
  };
  const registerButtons$1 = (editor) => {
    registerFormatButtons(editor);
    registerCommandButtons(editor);
    registerCommandToggleButtons(editor);
  };
  const registerMenuItems$2 = (editor) => {
    global$1.each([
      {
        name: "bold",
        text: "Bold",
        action: "Bold",
        icon: "bold",
        shortcut: "Meta+B"
      },
      {
        name: "italic",
        text: "Italic",
        action: "Italic",
        icon: "italic",
        shortcut: "Meta+I"
      },
      {
        name: "underline",
        text: "Underline",
        action: "Underline",
        icon: "underline",
        shortcut: "Meta+U"
      },
      {
        name: "strikethrough",
        text: "Strikethrough",
        action: "Strikethrough",
        icon: "strike-through"
      },
      {
        name: "subscript",
        text: "Subscript",
        action: "Subscript",
        icon: "subscript"
      },
      {
        name: "superscript",
        text: "Superscript",
        action: "Superscript",
        icon: "superscript"
      },
      {
        name: "removeformat",
        text: "Clear formatting",
        action: "RemoveFormat",
        icon: "remove-formatting"
      },
      {
        name: "newdocument",
        text: "New document",
        action: "mceNewDocument",
        icon: "new-document"
      },
      {
        name: "cut",
        text: "Cut",
        action: "Cut",
        icon: "cut",
        shortcut: "Meta+X"
      },
      {
        name: "copy",
        text: "Copy",
        action: "Copy",
        icon: "copy",
        shortcut: "Meta+C"
      },
      {
        name: "paste",
        text: "Paste",
        action: "Paste",
        icon: "paste",
        shortcut: "Meta+V"
      },
      {
        name: "selectall",
        text: "Select all",
        action: "SelectAll",
        icon: "select-all",
        shortcut: "Meta+A"
      },
      {
        name: "print",
        text: "Print...",
        action: "mcePrint",
        icon: "print",
        shortcut: "Meta+P"
      },
      {
        name: "hr",
        text: "Horizontal line",
        action: "InsertHorizontalRule",
        icon: "horizontal-rule"
      }
    ], (menuitem) => {
      editor.ui.registry.addMenuItem(menuitem.name, {
        text: menuitem.text,
        icon: menuitem.icon,
        shortcut: menuitem.shortcut,
        onAction: onActionExecCommand(editor, menuitem.action)
      });
    });
    editor.ui.registry.addMenuItem("codeformat", {
      text: "Code",
      icon: "sourcecode",
      onAction: onActionToggleFormat(editor, "code")
    });
  };
  const register$3 = (editor) => {
    registerButtons$1(editor);
    registerMenuItems$2(editor);
  };
  const onSetupUndoRedoState = (editor, type2) => onSetupEvent(editor, "Undo Redo AddUndo TypingUndo ClearUndos SwitchMode", (api2) => {
    api2.setEnabled(!editor.mode.isReadOnly() && editor.undoManager[type2]());
  });
  const registerMenuItems$1 = (editor) => {
    editor.ui.registry.addMenuItem("undo", {
      text: "Undo",
      icon: "undo",
      shortcut: "Meta+Z",
      onSetup: onSetupUndoRedoState(editor, "hasUndo"),
      onAction: onActionExecCommand(editor, "undo")
    });
    editor.ui.registry.addMenuItem("redo", {
      text: "Redo",
      icon: "redo",
      shortcut: "Meta+Y",
      onSetup: onSetupUndoRedoState(editor, "hasRedo"),
      onAction: onActionExecCommand(editor, "redo")
    });
  };
  const registerButtons = (editor) => {
    editor.ui.registry.addButton("undo", {
      tooltip: "Undo",
      icon: "undo",
      enabled: false,
      onSetup: onSetupUndoRedoState(editor, "hasUndo"),
      onAction: onActionExecCommand(editor, "undo")
    });
    editor.ui.registry.addButton("redo", {
      tooltip: "Redo",
      icon: "redo",
      enabled: false,
      onSetup: onSetupUndoRedoState(editor, "hasRedo"),
      onAction: onActionExecCommand(editor, "redo")
    });
  };
  const register$2 = (editor) => {
    registerMenuItems$1(editor);
    registerButtons(editor);
  };
  const onSetupVisualAidState = (editor) => onSetupEvent(editor, "VisualAid", (api2) => {
    api2.setActive(editor.hasVisual);
  });
  const registerMenuItems = (editor) => {
    editor.ui.registry.addToggleMenuItem("visualaid", {
      text: "Visual aids",
      onSetup: onSetupVisualAidState(editor),
      onAction: onActionExecCommand(editor, "mceToggleVisualAid")
    });
  };
  const registerToolbarButton = (editor) => {
    editor.ui.registry.addButton("visualaid", {
      tooltip: "Visual aids",
      text: "Visual aids",
      onAction: onActionExecCommand(editor, "mceToggleVisualAid")
    });
  };
  const register$1 = (editor) => {
    registerToolbarButton(editor);
    registerMenuItems(editor);
  };
  const setup$6 = (editor, backstage) => {
    register$8(editor);
    register$3(editor);
    register$6(editor, backstage);
    register$2(editor);
    register$c(editor);
    register$1(editor);
    register$5(editor);
    register$7(editor);
    register$4(editor);
  };
  const patchPipeConfig = (config2) => isString(config2) ? config2.split(/[ ,]/) : config2;
  const option = (name2) => (editor) => editor.options.get(name2);
  const register = (editor) => {
    const registerOption = editor.options.register;
    registerOption("contextmenu_avoid_overlap", {
      processor: "string",
      default: ""
    });
    registerOption("contextmenu_never_use_native", {
      processor: "boolean",
      default: false
    });
    registerOption("contextmenu", {
      processor: (value2) => {
        if (value2 === false) {
          return {
            value: [],
            valid: true
          };
        } else if (isString(value2) || isArrayOf(value2, isString)) {
          return {
            value: patchPipeConfig(value2),
            valid: true
          };
        } else {
          return {
            valid: false,
            message: "Must be false or a string."
          };
        }
      },
      default: "link linkchecker image editimage table spellchecker configurepermanentpen"
    });
  };
  const shouldNeverUseNative = option("contextmenu_never_use_native");
  const getAvoidOverlapSelector = option("contextmenu_avoid_overlap");
  const isContextMenuDisabled = (editor) => getContextMenu(editor).length === 0;
  const getContextMenu = (editor) => {
    const contextMenus = editor.ui.registry.getAll().contextMenus;
    const contextMenu = editor.options.get("contextmenu");
    if (editor.options.isSet("contextmenu")) {
      return contextMenu;
    } else {
      return filter$2(contextMenu, (item2) => has$2(contextMenus, item2));
    }
  };
  const nu = (x, y) => ({
    type: "makeshift",
    x,
    y
  });
  const transpose = (pos, dx, dy) => {
    return nu(pos.x + dx, pos.y + dy);
  };
  const isTouchEvent = (e) => e.type === "longpress" || e.type.indexOf("touch") === 0;
  const fromPageXY = (e) => {
    if (isTouchEvent(e)) {
      const touch2 = e.touches[0];
      return nu(touch2.pageX, touch2.pageY);
    } else {
      return nu(e.pageX, e.pageY);
    }
  };
  const fromClientXY = (e) => {
    if (isTouchEvent(e)) {
      const touch2 = e.touches[0];
      return nu(touch2.clientX, touch2.clientY);
    } else {
      return nu(e.clientX, e.clientY);
    }
  };
  const transposeContentAreaContainer = (element2, pos) => {
    const containerPos = global$7.DOM.getPos(element2);
    return transpose(pos, containerPos.x, containerPos.y);
  };
  const getPointAnchor = (editor, e) => {
    if (e.type === "contextmenu" || e.type === "longpress") {
      if (editor.inline) {
        return fromPageXY(e);
      } else {
        return transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e));
      }
    } else {
      return getSelectionAnchor(editor);
    }
  };
  const getSelectionAnchor = (editor) => {
    return {
      type: "selection",
      root: SugarElement.fromDom(editor.selection.getNode())
    };
  };
  const getNodeAnchor = (editor) => ({
    type: "node",
    node: Optional.some(SugarElement.fromDom(editor.selection.getNode())),
    root: SugarElement.fromDom(editor.getBody())
  });
  const getAnchorSpec$1 = (editor, e, anchorType) => {
    switch (anchorType) {
      case "node":
        return getNodeAnchor(editor);
      case "point":
        return getPointAnchor(editor, e);
      case "selection":
        return getSelectionAnchor(editor);
    }
  };
  const initAndShow$1 = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
    const items = buildMenu();
    const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
    build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false).map((menuData) => {
      e.preventDefault();
      InlineView.showMenuAt(contextmenu, { anchor: anchorSpec }, {
        menu: { markers: markers("normal") },
        data: menuData
      });
    });
  };
  const layouts = {
    onLtr: () => [
      south$2,
      southeast$2,
      southwest$2,
      northeast$2,
      northwest$2,
      north$2,
      north,
      south,
      northeast,
      southeast,
      northwest,
      southwest
    ],
    onRtl: () => [
      south$2,
      southwest$2,
      southeast$2,
      northwest$2,
      northeast$2,
      north$2,
      north,
      south,
      northwest,
      southwest,
      northeast,
      southeast
    ]
  };
  const bubbleSize = 12;
  const bubbleAlignments = {
    valignCentre: [],
    alignCentre: [],
    alignLeft: ["tox-pop--align-left"],
    alignRight: ["tox-pop--align-right"],
    right: ["tox-pop--right"],
    left: ["tox-pop--left"],
    bottom: ["tox-pop--bottom"],
    top: ["tox-pop--top"]
  };
  const isTouchWithinSelection = (editor, e) => {
    const selection = editor.selection;
    if (selection.isCollapsed() || e.touches.length < 1) {
      return false;
    } else {
      const touch2 = e.touches[0];
      const rng = selection.getRng();
      const rngRectOpt = getFirstRect(editor.getWin(), SimSelection.domRange(rng));
      return rngRectOpt.exists((rngRect) => rngRect.left <= touch2.clientX && rngRect.right >= touch2.clientX && rngRect.top <= touch2.clientY && rngRect.bottom >= touch2.clientY);
    }
  };
  const setupiOSOverrides = (editor) => {
    const originalSelection = editor.selection.getRng();
    const selectionReset = () => {
      global$9.setEditorTimeout(editor, () => {
        editor.selection.setRng(originalSelection);
      }, 10);
      unbindEventListeners();
    };
    editor.once("touchend", selectionReset);
    const preventMousedown = (e) => {
      e.preventDefault();
      e.stopImmediatePropagation();
    };
    editor.on("mousedown", preventMousedown, true);
    const clearSelectionReset = () => unbindEventListeners();
    editor.once("longpresscancel", clearSelectionReset);
    const unbindEventListeners = () => {
      editor.off("touchend", selectionReset);
      editor.off("longpresscancel", clearSelectionReset);
      editor.off("mousedown", preventMousedown);
    };
  };
  const getAnchorSpec = (editor, e, anchorType) => {
    const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
    const bubbleYOffset = anchorType === "point" ? bubbleSize : 0;
    return {
      bubble: nu$5(0, bubbleYOffset, bubbleAlignments),
      layouts,
      overrides: {
        maxWidthFunction: expandable(),
        maxHeightFunction: expandable$1()
      },
      ...anchorSpec
    };
  };
  const show = (editor, e, items, backstage, contextmenu, anchorType, highlightImmediately) => {
    const anchorSpec = getAnchorSpec(editor, e, anchorType);
    build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, true).map((menuData) => {
      e.preventDefault();
      InlineView.showMenuWithinBounds(contextmenu, { anchor: anchorSpec }, {
        menu: {
          markers: markers("normal"),
          highlightImmediately
        },
        data: menuData,
        type: "horizontal"
      }, () => Optional.some(getContextToolbarBounds(editor, backstage.shared, anchorType === "node" ? "node" : "selection")));
      editor.dispatch(hideContextToolbarEvent);
    });
  };
  const initAndShow = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
    const detection2 = detect$1();
    const isiOS = detection2.os.isiOS();
    const isMacOS = detection2.os.isMacOS();
    const isAndroid = detection2.os.isAndroid();
    const isTouch2 = detection2.deviceType.isTouch();
    const shouldHighlightImmediately = () => !(isAndroid || isiOS || isMacOS && isTouch2);
    const open2 = () => {
      const items = buildMenu();
      show(editor, e, items, backstage, contextmenu, anchorType, shouldHighlightImmediately());
    };
    if ((isMacOS || isiOS) && anchorType !== "node") {
      const openiOS = () => {
        setupiOSOverrides(editor);
        open2();
      };
      if (isTouchWithinSelection(editor, e)) {
        openiOS();
      } else {
        editor.once("selectionchange", openiOS);
        editor.once("touchend", () => editor.off("selectionchange", openiOS));
      }
    } else {
      open2();
    }
  };
  const isSeparator = (item2) => isString(item2) ? item2 === "|" : item2.type === "separator";
  const separator = { type: "separator" };
  const makeContextItem = (item2) => {
    const commonMenuItem = (item3) => ({
      text: item3.text,
      icon: item3.icon,
      enabled: item3.enabled,
      shortcut: item3.shortcut
    });
    if (isString(item2)) {
      return item2;
    } else {
      switch (item2.type) {
        case "separator":
          return separator;
        case "submenu":
          return {
            type: "nestedmenuitem",
            ...commonMenuItem(item2),
            getSubmenuItems: () => {
              const items = item2.getSubmenuItems();
              if (isString(items)) {
                return items;
              } else {
                return map$2(items, makeContextItem);
              }
            }
          };
        default:
          return {
            type: "menuitem",
            ...commonMenuItem(item2),
            onAction: noarg(item2.onAction)
          };
      }
    }
  };
  const addContextMenuGroup = (xs, groupItems) => {
    if (groupItems.length === 0) {
      return xs;
    }
    const lastMenuItem = last$1(xs).filter((item2) => !isSeparator(item2));
    const before2 = lastMenuItem.fold(() => [], (_) => [separator]);
    return xs.concat(before2).concat(groupItems).concat([separator]);
  };
  const generateContextMenu = (contextMenus, menuConfig, selectedElement) => {
    const sections = foldl(menuConfig, (acc, name2) => {
      return get$g(contextMenus, name2.toLowerCase()).map((menu2) => {
        const items = menu2.update(selectedElement);
        if (isString(items)) {
          return addContextMenuGroup(acc, items.split(" "));
        } else if (items.length > 0) {
          const allItems = map$2(items, makeContextItem);
          return addContextMenuGroup(acc, allItems);
        } else {
          return acc;
        }
      }).getOrThunk(() => acc.concat([name2]));
    }, []);
    if (sections.length > 0 && isSeparator(sections[sections.length - 1])) {
      sections.pop();
    }
    return sections;
  };
  const isNativeOverrideKeyEvent = (editor, e) => e.ctrlKey && !shouldNeverUseNative(editor);
  const isTriggeredByKeyboard = (editor, e) => e.type !== "longpress" && (e.button !== 2 || e.target === editor.getBody() && e.pointerType === "");
  const getSelectedElement = (editor, e) => isTriggeredByKeyboard(editor, e) ? editor.selection.getStart(true) : e.target;
  const getAnchorType = (editor, e) => {
    const selector = getAvoidOverlapSelector(editor);
    const anchorType = isTriggeredByKeyboard(editor, e) ? "selection" : "point";
    if (isNotEmpty(selector)) {
      const target = getSelectedElement(editor, e);
      const selectorExists = closest(SugarElement.fromDom(target), selector);
      return selectorExists ? "node" : anchorType;
    } else {
      return anchorType;
    }
  };
  const setup$5 = (editor, lazySink, backstage) => {
    const detection2 = detect$1();
    const isTouch2 = detection2.deviceType.isTouch;
    const contextmenu = build$1(InlineView.sketch({
      dom: { tag: "div" },
      lazySink,
      onEscape: () => editor.focus(),
      onShow: () => backstage.setContextMenuState(true),
      onHide: () => backstage.setContextMenuState(false),
      fireDismissalEventInstead: {},
      inlineBehaviours: derive$1([config("dismissContextMenu", [run$1(dismissRequested(), (comp, _se) => {
        Sandboxing.close(comp);
        editor.focus();
      })])])
    }));
    const hideContextMenu = (_e) => InlineView.hide(contextmenu);
    const showContextMenu = (e) => {
      if (shouldNeverUseNative(editor)) {
        e.preventDefault();
      }
      if (isNativeOverrideKeyEvent(editor, e) || isContextMenuDisabled(editor)) {
        return;
      }
      const anchorType = getAnchorType(editor, e);
      const buildMenu = () => {
        const selectedElement = getSelectedElement(editor, e);
        const registry = editor.ui.registry.getAll();
        const menuConfig = getContextMenu(editor);
        return generateContextMenu(registry.contextMenus, menuConfig, selectedElement);
      };
      const initAndShow$2 = isTouch2() ? initAndShow : initAndShow$1;
      initAndShow$2(editor, e, buildMenu, backstage, contextmenu, anchorType);
    };
    editor.on("init", () => {
      const hideEvents = "ResizeEditor ScrollContent ScrollWindow longpresscancel" + (isTouch2() ? "" : " ResizeWindow");
      editor.on(hideEvents, hideContextMenu);
      editor.on("longpress contextmenu", showContextMenu);
    });
  };
  const adt = Adt.generate([
    {
      offset: [
        "x",
        "y"
      ]
    },
    {
      absolute: [
        "x",
        "y"
      ]
    },
    {
      fixed: [
        "x",
        "y"
      ]
    }
  ]);
  const subtract = (change2) => (point2) => point2.translate(-change2.left, -change2.top);
  const add = (change2) => (point2) => point2.translate(change2.left, change2.top);
  const transform = (changes) => (x, y) => foldl(changes, (rest, f) => f(rest), SugarPosition(x, y));
  const asFixed = (coord, scroll, origin) => coord.fold(transform([
    add(origin),
    subtract(scroll)
  ]), transform([subtract(scroll)]), transform([]));
  const asAbsolute = (coord, scroll, origin) => coord.fold(transform([add(origin)]), transform([]), transform([add(scroll)]));
  const asOffset = (coord, scroll, origin) => coord.fold(transform([]), transform([subtract(origin)]), transform([
    add(scroll),
    subtract(origin)
  ]));
  const withinRange = (coord1, coord2, xRange2, yRange2, scroll, origin) => {
    const a1 = asAbsolute(coord1, scroll, origin);
    const a2 = asAbsolute(coord2, scroll, origin);
    return Math.abs(a1.left - a2.left) <= xRange2 && Math.abs(a1.top - a2.top) <= yRange2;
  };
  const getDeltas = (coord1, coord2, xRange2, yRange2, scroll, origin) => {
    const a1 = asAbsolute(coord1, scroll, origin);
    const a2 = asAbsolute(coord2, scroll, origin);
    const left2 = Math.abs(a1.left - a2.left);
    const top2 = Math.abs(a1.top - a2.top);
    return SugarPosition(left2, top2);
  };
  const toStyles = (coord, scroll, origin) => {
    const stylesOpt = coord.fold((x, y) => ({
      position: Optional.some("absolute"),
      left: Optional.some(x + "px"),
      top: Optional.some(y + "px")
    }), (x, y) => ({
      position: Optional.some("absolute"),
      left: Optional.some(x - origin.left + "px"),
      top: Optional.some(y - origin.top + "px")
    }), (x, y) => ({
      position: Optional.some("fixed"),
      left: Optional.some(x + "px"),
      top: Optional.some(y + "px")
    }));
    return {
      right: Optional.none(),
      bottom: Optional.none(),
      ...stylesOpt
    };
  };
  const translate = (coord, deltaX, deltaY) => coord.fold((x, y) => offset(x + deltaX, y + deltaY), (x, y) => absolute(x + deltaX, y + deltaY), (x, y) => fixed(x + deltaX, y + deltaY));
  const absorb = (partialCoord, originalCoord, scroll, origin) => {
    const absorbOne = (stencil, nu2) => (optX, optY) => {
      const original2 = stencil(originalCoord, scroll, origin);
      return nu2(optX.getOr(original2.left), optY.getOr(original2.top));
    };
    return partialCoord.fold(absorbOne(asOffset, offset), absorbOne(asAbsolute, absolute), absorbOne(asFixed, fixed));
  };
  const offset = adt.offset;
  const absolute = adt.absolute;
  const fixed = adt.fixed;
  const parseAttrToInt = (element2, name2) => {
    const value2 = get$f(element2, name2);
    return isUndefined(value2) ? NaN : parseInt(value2, 10);
  };
  const get = (component, snapsInfo) => {
    const element2 = component.element;
    const x = parseAttrToInt(element2, snapsInfo.leftAttr);
    const y = parseAttrToInt(element2, snapsInfo.topAttr);
    return isNaN(x) || isNaN(y) ? Optional.none() : Optional.some(SugarPosition(x, y));
  };
  const set = (component, snapsInfo, pt) => {
    const element2 = component.element;
    set$9(element2, snapsInfo.leftAttr, pt.left + "px");
    set$9(element2, snapsInfo.topAttr, pt.top + "px");
  };
  const clear = (component, snapsInfo) => {
    const element2 = component.element;
    remove$7(element2, snapsInfo.leftAttr);
    remove$7(element2, snapsInfo.topAttr);
  };
  const getCoords = (component, snapInfo, coord, delta) => get(component, snapInfo).fold(() => coord, (fixed$12) => fixed(fixed$12.left + delta.left, fixed$12.top + delta.top));
  const moveOrSnap = (component, snapInfo, coord, delta, scroll, origin) => {
    const newCoord = getCoords(component, snapInfo, coord, delta);
    const snap2 = snapInfo.mustSnap ? findClosestSnap(component, snapInfo, newCoord, scroll, origin) : findSnap(component, snapInfo, newCoord, scroll, origin);
    const fixedCoord = asFixed(newCoord, scroll, origin);
    set(component, snapInfo, fixedCoord);
    return snap2.fold(() => ({
      coord: fixed(fixedCoord.left, fixedCoord.top),
      extra: Optional.none()
    }), (spanned) => ({
      coord: spanned.output,
      extra: spanned.extra
    }));
  };
  const stopDrag = (component, snapInfo) => {
    clear(component, snapInfo);
  };
  const findMatchingSnap = (snaps, newCoord, scroll, origin) => findMap(snaps, (snap2) => {
    const sensor = snap2.sensor;
    const inRange = withinRange(newCoord, sensor, snap2.range.left, snap2.range.top, scroll, origin);
    return inRange ? Optional.some({
      output: absorb(snap2.output, newCoord, scroll, origin),
      extra: snap2.extra
    }) : Optional.none();
  });
  const findClosestSnap = (component, snapInfo, newCoord, scroll, origin) => {
    const snaps = snapInfo.getSnapPoints(component);
    const matchSnap = findMatchingSnap(snaps, newCoord, scroll, origin);
    return matchSnap.orThunk(() => {
      const bestSnap = foldl(snaps, (acc, snap2) => {
        const sensor = snap2.sensor;
        const deltas = getDeltas(newCoord, sensor, snap2.range.left, snap2.range.top, scroll, origin);
        return acc.deltas.fold(() => ({
          deltas: Optional.some(deltas),
          snap: Optional.some(snap2)
        }), (bestDeltas) => {
          const currAvg = (deltas.left + deltas.top) / 2;
          const bestAvg = (bestDeltas.left + bestDeltas.top) / 2;
          if (currAvg <= bestAvg) {
            return {
              deltas: Optional.some(deltas),
              snap: Optional.some(snap2)
            };
          } else {
            return acc;
          }
        });
      }, {
        deltas: Optional.none(),
        snap: Optional.none()
      });
      return bestSnap.snap.map((snap2) => ({
        output: absorb(snap2.output, newCoord, scroll, origin),
        extra: snap2.extra
      }));
    });
  };
  const findSnap = (component, snapInfo, newCoord, scroll, origin) => {
    const snaps = snapInfo.getSnapPoints(component);
    return findMatchingSnap(snaps, newCoord, scroll, origin);
  };
  const snapTo$1 = (snap2, scroll, origin) => ({
    coord: absorb(snap2.output, snap2.output, scroll, origin),
    extra: snap2.extra
  });
  const snapTo = (component, dragConfig, _state, snap2) => {
    const target = dragConfig.getTarget(component.element);
    if (dragConfig.repositionTarget) {
      const doc = owner$4(component.element);
      const scroll = get$b(doc);
      const origin = getOrigin(target);
      const snapPin = snapTo$1(snap2, scroll, origin);
      const styles = toStyles(snapPin.coord, scroll, origin);
      setOptions(target, styles);
    }
  };
  var DraggingApis = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    snapTo
  });
  const initialAttribute = "data-initial-z-index";
  const resetZIndex = (blocker) => {
    parent(blocker.element).filter(isElement$1).each((root) => {
      getOpt(root, initialAttribute).fold(() => remove$6(root, "z-index"), (zIndex) => set$8(root, "z-index", zIndex));
      remove$7(root, initialAttribute);
    });
  };
  const changeZIndex = (blocker) => {
    parent(blocker.element).filter(isElement$1).each((root) => {
      getRaw(root, "z-index").each((zindex) => {
        set$9(root, initialAttribute, zindex);
      });
      set$8(root, "z-index", get$e(blocker.element, "z-index"));
    });
  };
  const instigate = (anyComponent, blocker) => {
    anyComponent.getSystem().addToGui(blocker);
    changeZIndex(blocker);
  };
  const discard = (blocker) => {
    resetZIndex(blocker);
    blocker.getSystem().removeFromGui(blocker);
  };
  const createComponent = (component, blockerClass, blockerEvents) => component.getSystem().build(Container.sketch({
    dom: {
      styles: {
        "left": "0px",
        "top": "0px",
        "width": "100%",
        "height": "100%",
        "position": "fixed",
        "z-index": "1000000000000000"
      },
      classes: [blockerClass]
    },
    events: blockerEvents
  }));
  var SnapSchema = optionObjOf("snaps", [
    required$1("getSnapPoints"),
    onHandler("onSensor"),
    required$1("leftAttr"),
    required$1("topAttr"),
    defaulted("lazyViewport", win),
    defaulted("mustSnap", false)
  ]);
  const schema$6 = [
    defaulted("useFixed", never),
    required$1("blockerClass"),
    defaulted("getTarget", identity),
    defaulted("onDrag", noop),
    defaulted("repositionTarget", true),
    defaulted("onDrop", noop),
    defaultedFunction("getBounds", win),
    SnapSchema
  ];
  const getCurrentCoord = (target) => lift3(getRaw(target, "left"), getRaw(target, "top"), getRaw(target, "position"), (left2, top2, position2) => {
    const nu2 = position2 === "fixed" ? fixed : offset;
    return nu2(parseInt(left2, 10), parseInt(top2, 10));
  }).getOrThunk(() => {
    const location = absolute$3(target);
    return absolute(location.left, location.top);
  });
  const clampCoords = (component, coords, scroll, origin, startData) => {
    const bounds2 = startData.bounds;
    const absoluteCoord = asAbsolute(coords, scroll, origin);
    const newX = clamp(absoluteCoord.left, bounds2.x, bounds2.x + bounds2.width - startData.width);
    const newY = clamp(absoluteCoord.top, bounds2.y, bounds2.y + bounds2.height - startData.height);
    const newCoords = absolute(newX, newY);
    return coords.fold(() => {
      const offset$1 = asOffset(newCoords, scroll, origin);
      return offset(offset$1.left, offset$1.top);
    }, constant$1(newCoords), () => {
      const fixed$12 = asFixed(newCoords, scroll, origin);
      return fixed(fixed$12.left, fixed$12.top);
    });
  };
  const calcNewCoord = (component, optSnaps, currentCoord, scroll, origin, delta, startData) => {
    const newCoord = optSnaps.fold(() => {
      const translated = translate(currentCoord, delta.left, delta.top);
      const fixedCoord = asFixed(translated, scroll, origin);
      return fixed(fixedCoord.left, fixedCoord.top);
    }, (snapInfo) => {
      const snapping = moveOrSnap(component, snapInfo, currentCoord, delta, scroll, origin);
      snapping.extra.each((extra) => {
        snapInfo.onSensor(component, extra);
      });
      return snapping.coord;
    });
    return clampCoords(component, newCoord, scroll, origin, startData);
  };
  const dragBy = (component, dragConfig, startData, delta) => {
    const target = dragConfig.getTarget(component.element);
    if (dragConfig.repositionTarget) {
      const doc = owner$4(component.element);
      const scroll = get$b(doc);
      const origin = getOrigin(target);
      const currentCoord = getCurrentCoord(target);
      const newCoord = calcNewCoord(component, dragConfig.snaps, currentCoord, scroll, origin, delta, startData);
      const styles = toStyles(newCoord, scroll, origin);
      setOptions(target, styles);
    }
    dragConfig.onDrag(component, target, delta);
  };
  const calcStartData = (dragConfig, comp) => ({
    bounds: dragConfig.getBounds(),
    height: getOuter$2(comp.element),
    width: getOuter$1(comp.element)
  });
  const move = (component, dragConfig, dragState, dragMode, event) => {
    const delta = dragState.update(dragMode, event);
    const dragStartData = dragState.getStartData().getOrThunk(() => calcStartData(dragConfig, component));
    delta.each((dlt) => {
      dragBy(component, dragConfig, dragStartData, dlt);
    });
  };
  const stop = (component, blocker, dragConfig, dragState) => {
    blocker.each(discard);
    dragConfig.snaps.each((snapInfo) => {
      stopDrag(component, snapInfo);
    });
    const target = dragConfig.getTarget(component.element);
    dragState.reset();
    dragConfig.onDrop(component, target);
  };
  const handlers = (events2) => (dragConfig, dragState) => {
    const updateStartState = (comp) => {
      dragState.setStartData(calcStartData(dragConfig, comp));
    };
    return derive$2([
      run$1(windowScroll(), (comp) => {
        dragState.getStartData().each(() => updateStartState(comp));
      }),
      ...events2(dragConfig, dragState, updateStartState)
    ]);
  };
  const init$2 = (dragApi) => derive$2([
    run$1(mousedown(), dragApi.forceDrop),
    run$1(mouseup(), dragApi.drop),
    run$1(mousemove(), (comp, simulatedEvent) => {
      dragApi.move(simulatedEvent.event);
    }),
    run$1(mouseout(), dragApi.delayDrop)
  ]);
  const getData$1 = (event) => Optional.from(SugarPosition(event.x, event.y));
  const getDelta$1 = (old, nu2) => SugarPosition(nu2.left - old.left, nu2.top - old.top);
  var MouseData = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    getData: getData$1,
    getDelta: getDelta$1
  });
  const events$2 = (dragConfig, dragState, updateStartState) => [run$1(mousedown(), (component, simulatedEvent) => {
    const raw = simulatedEvent.event.raw;
    if (raw.button !== 0) {
      return;
    }
    simulatedEvent.stop();
    const stop$1 = () => stop(component, Optional.some(blocker), dragConfig, dragState);
    const delayDrop = DelayedFunction(stop$1, 200);
    const dragApi = {
      drop: stop$1,
      delayDrop: delayDrop.schedule,
      forceDrop: stop$1,
      move: (event) => {
        delayDrop.cancel();
        move(component, dragConfig, dragState, MouseData, event);
      }
    };
    const blocker = createComponent(component, dragConfig.blockerClass, init$2(dragApi));
    const start = () => {
      updateStartState(component);
      instigate(component, blocker);
    };
    start();
  })];
  const schema$5 = [
    ...schema$6,
    output$1("dragger", { handlers: handlers(events$2) })
  ];
  const init$1 = (dragApi) => derive$2([
    run$1(touchstart(), dragApi.forceDrop),
    run$1(touchend(), dragApi.drop),
    run$1(touchcancel(), dragApi.drop),
    run$1(touchmove(), (comp, simulatedEvent) => {
      dragApi.move(simulatedEvent.event);
    })
  ]);
  const getDataFrom = (touches) => {
    const touch2 = touches[0];
    return Optional.some(SugarPosition(touch2.clientX, touch2.clientY));
  };
  const getData = (event) => {
    const raw = event.raw;
    const touches = raw.touches;
    return touches.length === 1 ? getDataFrom(touches) : Optional.none();
  };
  const getDelta = (old, nu2) => SugarPosition(nu2.left - old.left, nu2.top - old.top);
  var TouchData = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    getData,
    getDelta
  });
  const events$1 = (dragConfig, dragState, updateStartState) => {
    const blockerSingleton = value$2();
    const stopBlocking = (component) => {
      stop(component, blockerSingleton.get(), dragConfig, dragState);
      blockerSingleton.clear();
    };
    return [
      run$1(touchstart(), (component, simulatedEvent) => {
        simulatedEvent.stop();
        const stop2 = () => stopBlocking(component);
        const dragApi = {
          drop: stop2,
          delayDrop: noop,
          forceDrop: stop2,
          move: (event) => {
            move(component, dragConfig, dragState, TouchData, event);
          }
        };
        const blocker = createComponent(component, dragConfig.blockerClass, init$1(dragApi));
        blockerSingleton.set(blocker);
        const start = () => {
          updateStartState(component);
          instigate(component, blocker);
        };
        start();
      }),
      run$1(touchmove(), (component, simulatedEvent) => {
        simulatedEvent.stop();
        move(component, dragConfig, dragState, TouchData, simulatedEvent.event);
      }),
      run$1(touchend(), (component, simulatedEvent) => {
        simulatedEvent.stop();
        stopBlocking(component);
      }),
      run$1(touchcancel(), stopBlocking)
    ];
  };
  const schema$4 = [
    ...schema$6,
    output$1("dragger", { handlers: handlers(events$1) })
  ];
  const events = (dragConfig, dragState, updateStartState) => [
    ...events$2(dragConfig, dragState, updateStartState),
    ...events$1(dragConfig, dragState, updateStartState)
  ];
  const schema$3 = [
    ...schema$6,
    output$1("dragger", { handlers: handlers(events) })
  ];
  const mouse = schema$5;
  const touch = schema$4;
  const mouseOrTouch = schema$3;
  var DraggingBranches = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    mouse,
    touch,
    mouseOrTouch
  });
  const init = () => {
    let previous = Optional.none();
    let startData = Optional.none();
    const reset2 = () => {
      previous = Optional.none();
      startData = Optional.none();
    };
    const calculateDelta = (mode, nu2) => {
      const result = previous.map((old) => mode.getDelta(old, nu2));
      previous = Optional.some(nu2);
      return result;
    };
    const update = (mode, dragEvent) => mode.getData(dragEvent).bind((nuData) => calculateDelta(mode, nuData));
    const setStartData = (data) => {
      startData = Optional.some(data);
    };
    const getStartData = () => startData;
    const readState = constant$1({});
    return nu$8({
      readState,
      reset: reset2,
      update,
      getStartData,
      setStartData
    });
  };
  var DragState = /* @__PURE__ */ Object.freeze({
    __proto__: null,
    init
  });
  const Dragging = createModes({
    branchKey: "mode",
    branches: DraggingBranches,
    name: "dragging",
    active: {
      events: (dragConfig, dragState) => {
        const dragger = dragConfig.dragger;
        return dragger.handlers(dragConfig, dragState);
      }
    },
    extra: {
      snap: (sConfig) => ({
        sensor: sConfig.sensor,
        range: sConfig.range,
        output: sConfig.output,
        extra: Optional.from(sConfig.extra)
      })
    },
    state: DragState,
    apis: DraggingApis
  });
  const snapWidth = 40;
  const snapOffset = snapWidth / 2;
  const calcSnap = (selectorOpt, td, x, y, width2, height2) => selectorOpt.fold(() => Dragging.snap({
    sensor: absolute(x - snapOffset, y - snapOffset),
    range: SugarPosition(width2, height2),
    output: absolute(Optional.some(x), Optional.some(y)),
    extra: { td }
  }), (selectorHandle) => {
    const sensorLeft = x - snapOffset;
    const sensorTop = y - snapOffset;
    const sensorWidth = snapWidth;
    const sensorHeight = snapWidth;
    const rect2 = selectorHandle.element.dom.getBoundingClientRect();
    return Dragging.snap({
      sensor: absolute(sensorLeft, sensorTop),
      range: SugarPosition(sensorWidth, sensorHeight),
      output: absolute(Optional.some(x - rect2.width / 2), Optional.some(y - rect2.height / 2)),
      extra: { td }
    });
  });
  const getSnapsConfig = (getSnapPoints, cell, onChange) => {
    const isSameCell = (cellOpt, td) => cellOpt.exists((currentTd) => eq(currentTd, td));
    return {
      getSnapPoints,
      leftAttr: "data-drag-left",
      topAttr: "data-drag-top",
      onSensor: (component, extra) => {
        const td = extra.td;
        if (!isSameCell(cell.get(), td)) {
          cell.set(td);
          onChange(td);
        }
      },
      mustSnap: true
    };
  };
  const createSelector = (snaps) => record(Button.sketch({
    dom: {
      tag: "div",
      classes: ["tox-selector"]
    },
    buttonBehaviours: derive$1([
      Dragging.config({
        mode: "mouseOrTouch",
        blockerClass: "blocker",
        snaps
      }),
      Unselecting.config({})
    ]),
    eventOrder: {
      mousedown: [
        "dragging",
        "alloy.base.behaviour"
      ],
      touchstart: [
        "dragging",
        "alloy.base.behaviour"
      ]
    }
  }));
  const setup$4 = (editor, sink) => {
    const tlTds = Cell([]);
    const brTds = Cell([]);
    const isVisible2 = Cell(false);
    const startCell = value$2();
    const finishCell = value$2();
    const getTopLeftSnap = (td) => {
      const box2 = absolute$2(td);
      return calcSnap(memTopLeft.getOpt(sink), td, box2.x, box2.y, box2.width, box2.height);
    };
    const getTopLeftSnaps = () => map$2(tlTds.get(), (td) => getTopLeftSnap(td));
    const getBottomRightSnap = (td) => {
      const box2 = absolute$2(td);
      return calcSnap(memBottomRight.getOpt(sink), td, box2.right, box2.bottom, box2.width, box2.height);
    };
    const getBottomRightSnaps = () => map$2(brTds.get(), (td) => getBottomRightSnap(td));
    const topLeftSnaps = getSnapsConfig(getTopLeftSnaps, startCell, (start) => {
      finishCell.get().each((finish) => {
        editor.dispatch("TableSelectorChange", {
          start,
          finish
        });
      });
    });
    const bottomRightSnaps = getSnapsConfig(getBottomRightSnaps, finishCell, (finish) => {
      startCell.get().each((start) => {
        editor.dispatch("TableSelectorChange", {
          start,
          finish
        });
      });
    });
    const memTopLeft = createSelector(topLeftSnaps);
    const memBottomRight = createSelector(bottomRightSnaps);
    const topLeft = build$1(memTopLeft.asSpec());
    const bottomRight = build$1(memBottomRight.asSpec());
    const showOrHideHandle = (selector, cell, isAbove, isBelow) => {
      const cellRect = cell.dom.getBoundingClientRect();
      remove$6(selector.element, "display");
      const viewportHeight = defaultView(SugarElement.fromDom(editor.getBody())).dom.innerHeight;
      const aboveViewport = isAbove(cellRect);
      const belowViewport = isBelow(cellRect, viewportHeight);
      if (aboveViewport || belowViewport) {
        set$8(selector.element, "display", "none");
      }
    };
    const snapTo2 = (selector, cell, getSnapConfig, pos) => {
      const snap2 = getSnapConfig(cell);
      Dragging.snapTo(selector, snap2);
      const isAbove = (rect2) => rect2[pos] < 0;
      const isBelow = (rect2, viewportHeight) => rect2[pos] > viewportHeight;
      showOrHideHandle(selector, cell, isAbove, isBelow);
    };
    const snapTopLeft = (cell) => snapTo2(topLeft, cell, getTopLeftSnap, "top");
    const snapLastTopLeft = () => startCell.get().each(snapTopLeft);
    const snapBottomRight = (cell) => snapTo2(bottomRight, cell, getBottomRightSnap, "bottom");
    const snapLastBottomRight = () => finishCell.get().each(snapBottomRight);
    if (detect$1().deviceType.isTouch()) {
      editor.on("TableSelectionChange", (e) => {
        if (!isVisible2.get()) {
          attach(sink, topLeft);
          attach(sink, bottomRight);
          isVisible2.set(true);
        }
        startCell.set(e.start);
        finishCell.set(e.finish);
        e.otherCells.each((otherCells) => {
          tlTds.set(otherCells.upOrLeftCells);
          brTds.set(otherCells.downOrRightCells);
          snapTopLeft(e.start);
          snapBottomRight(e.finish);
        });
      });
      editor.on("ResizeEditor ResizeWindow ScrollContent", () => {
        snapLastTopLeft();
        snapLastBottomRight();
      });
      editor.on("TableSelectionClear", () => {
        if (isVisible2.get()) {
          detach(topLeft);
          detach(bottomRight);
          isVisible2.set(false);
        }
        startCell.clear();
        finishCell.clear();
      });
    }
  };
  var Logo = '<svg width="50px" height="16px" viewBox="0 0 50 16" xmlns="http://www.w3.org/2000/svg">\n  <path fill-rule="evenodd" clip-rule="evenodd" d="M10.143 0c2.608.015 5.186 2.178 5.186 5.331 0 0 .077 3.812-.084 4.87-.361 2.41-2.164 4.074-4.65 4.496-1.453.284-2.523.49-3.212.623-.373.071-.634.122-.785.152-.184.038-.997.145-1.35.145-2.732 0-5.21-2.04-5.248-5.33 0 0 0-3.514.03-4.442.093-2.4 1.758-4.342 4.926-4.963 0 0 3.875-.752 4.036-.782.368-.07.775-.1 1.15-.1Zm1.826 2.8L5.83 3.989v2.393l-2.455.475v5.968l6.137-1.189V9.243l2.456-.476V2.8ZM5.83 6.382l3.682-.713v3.574l-3.682.713V6.382Zm27.173-1.64-.084-1.066h-2.226v9.132h2.456V7.743c-.008-1.151.998-2.064 2.149-2.072 1.15-.008 1.987.92 1.995 2.072v5.065h2.455V7.359c-.015-2.18-1.657-3.929-3.837-3.913a3.993 3.993 0 0 0-2.908 1.296Zm-6.3-4.266L29.16 0v2.387l-2.456.475V.476Zm0 3.2v9.132h2.456V3.676h-2.456Zm18.179 11.787L49.11 3.676H46.58l-1.612 4.527-.46 1.382-.384-1.382-1.611-4.527H39.98l3.3 9.132L42.15 16l2.732-.537ZM22.867 9.738c0 .752.568 1.075.921 1.075.353 0 .668-.047.998-.154l.537 1.765c-.23.154-.92.537-2.225.537-1.305 0-2.655-.997-2.686-2.686a136.877 136.877 0 0 1 0-4.374H18.8V3.676h1.612v-1.98l2.455-.476v2.456h2.302V5.9h-2.302v3.837Z"/>\n</svg>\n';
  const isHidden = (elm) => elm.nodeName === "BR" || !!elm.getAttribute("data-mce-bogus") || elm.getAttribute("data-mce-type") === "bookmark";
  const renderElementPath = (editor, settings, providersBackstage) => {
    var _a;
    const delimiter = (_a = settings.delimiter) !== null && _a !== void 0 ? _a : "\u203A";
    const renderElement = (name2, element2, index2) => Button.sketch({
      dom: {
        tag: "div",
        classes: ["tox-statusbar__path-item"],
        attributes: {
          "data-index": index2,
          "aria-level": index2 + 1
        }
      },
      components: [text$1(name2)],
      action: (_btn) => {
        editor.focus();
        editor.selection.select(element2);
        editor.nodeChanged();
      },
      buttonBehaviours: derive$1([
        DisablingConfigs.button(providersBackstage.isDisabled),
        receivingConfig()
      ])
    });
    const renderDivider = () => ({
      dom: {
        tag: "div",
        classes: ["tox-statusbar__path-divider"],
        attributes: { "aria-hidden": true }
      },
      components: [text$1(` ${delimiter} `)]
    });
    const renderPathData = (data) => foldl(data, (acc, path2, index2) => {
      const element2 = renderElement(path2.name, path2.element, index2);
      if (index2 === 0) {
        return acc.concat([element2]);
      } else {
        return acc.concat([
          renderDivider(),
          element2
        ]);
      }
    }, []);
    const updatePath = (parents) => {
      const newPath = [];
      let i = parents.length;
      while (i-- > 0) {
        const parent2 = parents[i];
        if (parent2.nodeType === 1 && !isHidden(parent2)) {
          const args = editor.dispatch("ResolveName", {
            name: parent2.nodeName.toLowerCase(),
            target: parent2
          });
          if (!args.isDefaultPrevented()) {
            newPath.push({
              name: args.name,
              element: parent2
            });
          }
          if (args.isPropagationStopped()) {
            break;
          }
        }
      }
      return newPath;
    };
    return {
      dom: {
        tag: "div",
        classes: ["tox-statusbar__path"],
        attributes: { role: "navigation" }
      },
      behaviours: derive$1([
        Keying.config({
          mode: "flow",
          selector: "div[role=button]"
        }),
        Disabling.config({ disabled: providersBackstage.isDisabled }),
        receivingConfig(),
        Tabstopping.config({}),
        Replacing.config({}),
        config("elementPathEvents", [runOnAttached((comp, _e) => {
          editor.shortcuts.add("alt+F11", "focus statusbar elementpath", () => Keying.focusIn(comp));
          editor.on("NodeChange", (e) => {
            const newPath = updatePath(e.parents);
            const newChildren = newPath.length > 0 ? renderPathData(newPath) : [];
            Replacing.set(comp, newChildren);
          });
        })])
      ]),
      components: []
    };
  };
  var ResizeTypes;
  (function(ResizeTypes2) {
    ResizeTypes2[ResizeTypes2["None"] = 0] = "None";
    ResizeTypes2[ResizeTypes2["Both"] = 1] = "Both";
    ResizeTypes2[ResizeTypes2["Vertical"] = 2] = "Vertical";
  })(ResizeTypes || (ResizeTypes = {}));
  const getDimensions = (editor, deltas, resizeType, originalHeight, originalWidth) => {
    const dimensions = {};
    dimensions.height = calcCappedSize(originalHeight + deltas.top, getMinHeightOption(editor), getMaxHeightOption(editor));
    if (resizeType === ResizeTypes.Both) {
      dimensions.width = calcCappedSize(originalWidth + deltas.left, getMinWidthOption(editor), getMaxWidthOption(editor));
    }
    return dimensions;
  };
  const resize = (editor, deltas, resizeType) => {
    const container = SugarElement.fromDom(editor.getContainer());
    const dimensions = getDimensions(editor, deltas, resizeType, get$d(container), get$c(container));
    each(dimensions, (val, dim) => set$8(container, dim, numToPx(val)));
    fireResizeEditor(editor);
  };
  const getResizeType = (editor) => {
    const resize2 = getResize(editor);
    if (resize2 === false) {
      return ResizeTypes.None;
    } else if (resize2 === "both") {
      return ResizeTypes.Both;
    } else {
      return ResizeTypes.Vertical;
    }
  };
  const keyboardHandler = (editor, resizeType, x, y) => {
    const scale = 20;
    const delta = SugarPosition(x * scale, y * scale);
    resize(editor, delta, resizeType);
    return Optional.some(true);
  };
  const renderResizeHandler = (editor, providersBackstage) => {
    const resizeType = getResizeType(editor);
    if (resizeType === ResizeTypes.None) {
      return Optional.none();
    }
    return Optional.some(render$3("resize-handle", {
      tag: "div",
      classes: ["tox-statusbar__resize-handle"],
      attributes: { title: providersBackstage.translate("Resize") },
      behaviours: [
        Dragging.config({
          mode: "mouse",
          repositionTarget: false,
          onDrag: (_comp, _target, delta) => resize(editor, delta, resizeType),
          blockerClass: "tox-blocker"
        }),
        Keying.config({
          mode: "special",
          onLeft: () => keyboardHandler(editor, resizeType, -1, 0),
          onRight: () => keyboardHandler(editor, resizeType, 1, 0),
          onUp: () => keyboardHandler(editor, resizeType, 0, -1),
          onDown: () => keyboardHandler(editor, resizeType, 0, 1)
        }),
        Tabstopping.config({}),
        Focusing.config({})
      ]
    }, providersBackstage.icons));
  };
  const renderWordCount = (editor, providersBackstage) => {
    const replaceCountText = (comp, count, mode) => Replacing.set(comp, [text$1(providersBackstage.translate([
      "{0} " + mode,
      count[mode]
    ]))]);
    return Button.sketch({
      dom: {
        tag: "button",
        classes: ["tox-statusbar__wordcount"]
      },
      components: [],
      buttonBehaviours: derive$1([
        DisablingConfigs.button(providersBackstage.isDisabled),
        receivingConfig(),
        Tabstopping.config({}),
        Replacing.config({}),
        Representing.config({
          store: {
            mode: "memory",
            initialValue: {
              mode: "words",
              count: {
                words: 0,
                characters: 0
              }
            }
          }
        }),
        config("wordcount-events", [
          runOnExecute$1((comp) => {
            const currentVal = Representing.getValue(comp);
            const newMode = currentVal.mode === "words" ? "characters" : "words";
            Representing.setValue(comp, {
              mode: newMode,
              count: currentVal.count
            });
            replaceCountText(comp, currentVal.count, newMode);
          }),
          runOnAttached((comp) => {
            editor.on("wordCountUpdate", (e) => {
              const { mode } = Representing.getValue(comp);
              Representing.setValue(comp, {
                mode,
                count: e.wordCount
              });
              replaceCountText(comp, e.wordCount, mode);
            });
          })
        ])
      ]),
      eventOrder: {
        [execute$5()]: [
          "disabling",
          "alloy.base.behaviour",
          "wordcount-events"
        ]
      }
    });
  };
  const renderStatusbar = (editor, providersBackstage) => {
    const renderBranding = () => {
      return {
        dom: {
          tag: "span",
          classes: ["tox-statusbar__branding"]
        },
        components: [{
          dom: {
            tag: "a",
            attributes: {
              "href": "https://www.tiny.cloud/powered-by-tiny?utm_campaign=editor_referral&utm_medium=poweredby&utm_source=tinymce&utm_content=v6",
              "rel": "noopener",
              "target": "_blank",
              "aria-label": global$8.translate([
                "Powered by {0}",
                "Tiny"
              ])
            },
            innerHtml: Logo.trim()
          },
          behaviours: derive$1([Focusing.config({})])
        }]
      };
    };
    const getTextComponents = () => {
      const components2 = [];
      if (useElementPath(editor)) {
        components2.push(renderElementPath(editor, {}, providersBackstage));
      }
      if (editor.hasPlugin("wordcount")) {
        components2.push(renderWordCount(editor, providersBackstage));
      }
      if (useBranding(editor)) {
        components2.push(renderBranding());
      }
      if (components2.length > 0) {
        return [{
          dom: {
            tag: "div",
            classes: ["tox-statusbar__text-container"]
          },
          components: components2
        }];
      }
      return [];
    };
    const getComponents = () => {
      const components2 = getTextComponents();
      const resizeHandler = renderResizeHandler(editor, providersBackstage);
      return components2.concat(resizeHandler.toArray());
    };
    return {
      dom: {
        tag: "div",
        classes: ["tox-statusbar"]
      },
      components: getComponents()
    };
  };
  const getLazyMothership = (singleton2) => singleton2.get().getOrDie("UI has not been rendered");
  const setup$3 = (editor) => {
    const isInline = editor.inline;
    const mode = isInline ? Inline : Iframe;
    const header = isStickyToolbar(editor) ? StickyHeader : StaticHeader;
    const lazySink = value$2();
    const lazyOuterContainer = value$2();
    const lazyMothership = value$2();
    const lazyUiMothership = value$2();
    const platform2 = detect$1();
    const isTouch2 = platform2.deviceType.isTouch();
    const touchPlatformClass = "tox-platform-touch";
    const deviceClasses = isTouch2 ? [touchPlatformClass] : [];
    const isToolbarBottom = isToolbarLocationBottom(editor);
    const toolbarMode = getToolbarMode(editor);
    const memAnchorBar = record({
      dom: {
        tag: "div",
        classes: ["tox-anchorbar"]
      }
    });
    const lazyHeader = () => lazyOuterContainer.get().bind(OuterContainer.getHeader);
    const lazySinkResult = () => Result.fromOption(lazySink.get(), "UI has not been rendered");
    const lazyAnchorBar = () => lazyOuterContainer.get().bind((container) => memAnchorBar.getOpt(container)).getOrDie("Could not find a anchor bar element");
    const lazyToolbar = () => lazyOuterContainer.get().bind((container) => OuterContainer.getToolbar(container)).getOrDie("Could not find more toolbar element");
    const lazyThrobber = () => lazyOuterContainer.get().bind((container) => OuterContainer.getThrobber(container)).getOrDie("Could not find throbber element");
    const backstage = init$7(lazySinkResult, editor, lazyAnchorBar);
    const makeHeaderPart = () => {
      const verticalDirAttributes = { attributes: { [Attribute]: isToolbarBottom ? AttributeValue.BottomToTop : AttributeValue.TopToBottom } };
      const partMenubar2 = OuterContainer.parts.menubar({
        dom: {
          tag: "div",
          classes: ["tox-menubar"]
        },
        backstage,
        onEscape: () => {
          editor.focus();
        }
      });
      const partToolbar2 = OuterContainer.parts.toolbar({
        dom: {
          tag: "div",
          classes: ["tox-toolbar"]
        },
        getSink: lazySinkResult,
        providers: backstage.shared.providers,
        onEscape: () => {
          editor.focus();
        },
        type: toolbarMode,
        lazyToolbar,
        lazyHeader: () => lazyHeader().getOrDie("Could not find header element"),
        ...verticalDirAttributes
      });
      const partMultipleToolbar2 = OuterContainer.parts["multiple-toolbar"]({
        dom: {
          tag: "div",
          classes: ["tox-toolbar-overlord"]
        },
        providers: backstage.shared.providers,
        onEscape: () => {
          editor.focus();
        },
        type: toolbarMode
      });
      const hasMultipleToolbar = isMultipleToolbars(editor);
      const hasToolbar = isToolbarEnabled(editor);
      const hasMenubar = isMenubarEnabled(editor);
      const getPartToolbar = () => {
        if (hasMultipleToolbar) {
          return [partMultipleToolbar2];
        } else if (hasToolbar) {
          return [partToolbar2];
        } else {
          return [];
        }
      };
      return OuterContainer.parts.header({
        dom: {
          tag: "div",
          classes: ["tox-editor-header"],
          ...verticalDirAttributes
        },
        components: flatten([
          hasMenubar ? [partMenubar2] : [],
          getPartToolbar(),
          useFixedContainer(editor) ? [] : [memAnchorBar.asSpec()]
        ]),
        sticky: isStickyToolbar(editor),
        editor,
        sharedBackstage: backstage.shared
      });
    };
    const makeSidebarDefinition = () => {
      const partSocket2 = OuterContainer.parts.socket({
        dom: {
          tag: "div",
          classes: ["tox-edit-area"]
        }
      });
      const partSidebar2 = OuterContainer.parts.sidebar({
        dom: {
          tag: "div",
          classes: ["tox-sidebar"]
        }
      });
      return {
        dom: {
          tag: "div",
          classes: ["tox-sidebar-wrap"]
        },
        components: [
          partSocket2,
          partSidebar2
        ]
      };
    };
    const renderSink = () => {
      const uiContainer = getUiContainer(editor);
      const isGridUiContainer = eq(body(), uiContainer) && get$e(uiContainer, "display") === "grid";
      const sinkSpec = {
        dom: {
          tag: "div",
          classes: [
            "tox",
            "tox-silver-sink",
            "tox-tinymce-aux"
          ].concat(deviceClasses),
          attributes: { ...global$8.isRtl() ? { dir: "rtl" } : {} }
        },
        behaviours: derive$1([Positioning.config({ useFixed: () => header.isDocked(lazyHeader) })])
      };
      const reactiveWidthSpec = {
        dom: { styles: { width: document.body.clientWidth + "px" } },
        events: derive$2([run$1(windowResize(), (comp) => {
          set$8(comp.element, "width", document.body.clientWidth + "px");
        })])
      };
      const sink = build$1(deepMerge(sinkSpec, isGridUiContainer ? reactiveWidthSpec : {}));
      const uiMothership = takeover(sink);
      lazySink.set(sink);
      lazyUiMothership.set(uiMothership);
      return {
        sink,
        uiMothership
      };
    };
    const renderContainer2 = () => {
      const partHeader2 = makeHeaderPart();
      const sidebarContainer = makeSidebarDefinition();
      const partThrobber2 = OuterContainer.parts.throbber({
        dom: {
          tag: "div",
          classes: ["tox-throbber"]
        },
        backstage
      });
      const statusbar = useStatusBar(editor) && !isInline ? Optional.some(renderStatusbar(editor, backstage.shared.providers)) : Optional.none();
      const editorComponents = flatten([
        isToolbarBottom ? [] : [partHeader2],
        isInline ? [] : [sidebarContainer],
        isToolbarBottom ? [partHeader2] : []
      ]);
      const editorContainer = {
        dom: {
          tag: "div",
          classes: ["tox-editor-container"]
        },
        components: editorComponents
      };
      const containerComponents = flatten([
        [editorContainer],
        isInline ? [] : statusbar.toArray(),
        [partThrobber2]
      ]);
      const isHidden2 = isDistractionFree(editor);
      const attributes = {
        role: "application",
        ...global$8.isRtl() ? { dir: "rtl" } : {},
        ...isHidden2 ? { "aria-hidden": "true" } : {}
      };
      const outerContainer = build$1(OuterContainer.sketch({
        dom: {
          tag: "div",
          classes: [
            "tox",
            "tox-tinymce"
          ].concat(isInline ? ["tox-tinymce-inline"] : []).concat(isToolbarBottom ? ["tox-tinymce--toolbar-bottom"] : []).concat(deviceClasses),
          styles: {
            visibility: "hidden",
            ...isHidden2 ? {
              opacity: "0",
              border: "0"
            } : {}
          },
          attributes
        },
        components: containerComponents,
        behaviours: derive$1([
          receivingConfig(),
          Disabling.config({ disableClass: "tox-tinymce--disabled" }),
          Keying.config({
            mode: "cyclic",
            selector: ".tox-menubar, .tox-toolbar, .tox-toolbar__primary, .tox-toolbar__overflow--open, .tox-sidebar__overflow--open, .tox-statusbar__path, .tox-statusbar__wordcount, .tox-statusbar__branding a, .tox-statusbar__resize-handle"
          })
        ])
      }));
      const mothership = takeover(outerContainer);
      lazyOuterContainer.set(outerContainer);
      lazyMothership.set(mothership);
      return {
        mothership,
        outerContainer
      };
    };
    const setEditorSize = (outerContainer) => {
      const parsedHeight = numToPx(getHeightWithFallback(editor));
      const parsedWidth = numToPx(getWidthWithFallback(editor));
      if (!editor.inline) {
        if (isValidValue("div", "width", parsedWidth)) {
          set$8(outerContainer.element, "width", parsedWidth);
        }
        if (isValidValue("div", "height", parsedHeight)) {
          set$8(outerContainer.element, "height", parsedHeight);
        } else {
          set$8(outerContainer.element, "height", "400px");
        }
      }
      return parsedHeight;
    };
    const setupShortcutsAndCommands = (outerContainer) => {
      editor.addShortcut("alt+F9", "focus menubar", () => {
        OuterContainer.focusMenubar(outerContainer);
      });
      editor.addShortcut("alt+F10", "focus toolbar", () => {
        OuterContainer.focusToolbar(outerContainer);
      });
      editor.addCommand("ToggleToolbarDrawer", () => {
        OuterContainer.toggleToolbarDrawer(outerContainer);
      });
      editor.addQueryStateHandler("ToggleToolbarDrawer", () => OuterContainer.isToolbarDrawerToggled(outerContainer));
    };
    const renderUI = () => {
      const { mothership, outerContainer } = renderContainer2();
      const { uiMothership, sink } = renderSink();
      map$1(getToolbarGroups(editor), (toolbarGroupButtonConfig, name2) => {
        editor.ui.registry.addGroupToolbarButton(name2, toolbarGroupButtonConfig);
      });
      const { buttons, menuItems, contextToolbars, sidebars } = editor.ui.registry.getAll();
      const toolbarOpt = getMultipleToolbarsOption(editor);
      const rawUiConfig = {
        menuItems,
        menus: getMenus(editor),
        menubar: getMenubar(editor),
        toolbar: toolbarOpt.getOrThunk(() => getToolbar(editor)),
        allowToolbarGroups: toolbarMode === ToolbarMode$1.floating,
        buttons,
        sidebar: sidebars
      };
      setupShortcutsAndCommands(outerContainer);
      setup$b(editor, mothership, uiMothership);
      header.setup(editor, backstage.shared, lazyHeader);
      setup$6(editor, backstage);
      setup$5(editor, lazySinkResult, backstage);
      setup$8(editor);
      setup$7(editor, lazyThrobber, backstage.shared);
      register$9(editor, contextToolbars, sink, { backstage });
      setup$4(editor, sink);
      const elm = editor.getElement();
      const height2 = setEditorSize(outerContainer);
      const uiComponents = {
        mothership,
        uiMothership,
        outerContainer,
        sink
      };
      const args = {
        targetNode: elm,
        height: height2
      };
      return mode.render(editor, uiComponents, rawUiConfig, backstage, args);
    };
    const getMothership = () => getLazyMothership(lazyMothership);
    const getUiMothership = () => getLazyMothership(lazyUiMothership);
    return {
      getMothership,
      getUiMothership,
      backstage,
      renderUI
    };
  };
  const describedBy = (describedElement, describeElement) => {
    const describeId = Optional.from(get$f(describedElement, "id")).fold(() => {
      const id = generate$6("dialog-describe");
      set$9(describeElement, "id", id);
      return id;
    }, identity);
    set$9(describedElement, "aria-describedby", describeId);
  };
  const labelledBy = (labelledElement, labelElement) => {
    const labelId = getOpt(labelledElement, "id").fold(() => {
      const id = generate$6("dialog-label");
      set$9(labelElement, "id", id);
      return id;
    }, identity);
    set$9(labelledElement, "aria-labelledby", labelId);
  };
  const schema$2 = constant$1([
    required$1("lazySink"),
    option$3("dragBlockClass"),
    defaultedFunction("getBounds", win),
    defaulted("useTabstopAt", always),
    defaulted("eventOrder", {}),
    field("modalBehaviours", [Keying]),
    onKeyboardHandler("onExecute"),
    onStrictKeyboardHandler("onEscape")
  ]);
  const basic = { sketch: identity };
  const parts$2 = constant$1([
    optional({
      name: "draghandle",
      overrides: (detail, spec) => {
        return {
          behaviours: derive$1([Dragging.config({
            mode: "mouse",
            getTarget: (handle2) => {
              return ancestor(handle2, '[role="dialog"]').getOr(handle2);
            },
            blockerClass: detail.dragBlockClass.getOrDie(new Error("The drag blocker class was not specified for a dialog with a drag handle: \n" + JSON.stringify(spec, null, 2)).message),
            getBounds: detail.getDragBounds
          })])
        };
      }
    }),
    required({
      schema: [required$1("dom")],
      name: "title"
    }),
    required({
      factory: basic,
      schema: [required$1("dom")],
      name: "close"
    }),
    required({
      factory: basic,
      schema: [required$1("dom")],
      name: "body"
    }),
    optional({
      factory: basic,
      schema: [required$1("dom")],
      name: "footer"
    }),
    external({
      factory: {
        sketch: (spec, detail) => ({
          ...spec,
          dom: detail.dom,
          components: detail.components
        })
      },
      schema: [
        defaulted("dom", {
          tag: "div",
          styles: {
            position: "fixed",
            left: "0px",
            top: "0px",
            right: "0px",
            bottom: "0px"
          }
        }),
        defaulted("components", [])
      ],
      name: "blocker"
    })
  ]);
  const factory$4 = (detail, components2, spec, externals) => {
    const dialogComp = value$2();
    const showDialog = (dialog) => {
      dialogComp.set(dialog);
      const sink = detail.lazySink(dialog).getOrDie();
      const externalBlocker = externals.blocker();
      const blocker = sink.getSystem().build({
        ...externalBlocker,
        components: externalBlocker.components.concat([premade(dialog)]),
        behaviours: derive$1([
          Focusing.config({}),
          config("dialog-blocker-events", [runOnSource(focusin(), () => {
            Keying.focusIn(dialog);
          })])
        ])
      });
      attach(sink, blocker);
      Keying.focusIn(dialog);
    };
    const hideDialog = (dialog) => {
      dialogComp.clear();
      parent(dialog.element).each((blockerDom) => {
        dialog.getSystem().getByDom(blockerDom).each((blocker) => {
          detach(blocker);
        });
      });
    };
    const getDialogBody = (dialog) => getPartOrDie(dialog, detail, "body");
    const getDialogFooter = (dialog) => getPartOrDie(dialog, detail, "footer");
    const setBusy = (dialog, getBusySpec2) => {
      Blocking.block(dialog, getBusySpec2);
    };
    const setIdle = (dialog) => {
      Blocking.unblock(dialog);
    };
    const modalEventsId = generate$6("modal-events");
    const eventOrder = {
      ...detail.eventOrder,
      [attachedToDom()]: [modalEventsId].concat(detail.eventOrder["alloy.system.attached"] || [])
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      apis: {
        show: showDialog,
        hide: hideDialog,
        getBody: getDialogBody,
        getFooter: getDialogFooter,
        setIdle,
        setBusy
      },
      eventOrder,
      domModification: {
        attributes: {
          "role": "dialog",
          "aria-modal": "true"
        }
      },
      behaviours: augment(detail.modalBehaviours, [
        Replacing.config({}),
        Keying.config({
          mode: "cyclic",
          onEnter: detail.onExecute,
          onEscape: detail.onEscape,
          useTabstopAt: detail.useTabstopAt
        }),
        Blocking.config({ getRoot: dialogComp.get }),
        config(modalEventsId, [runOnAttached((c) => {
          labelledBy(c.element, getPartOrDie(c, detail, "title").element);
          describedBy(c.element, getPartOrDie(c, detail, "body").element);
        })])
      ])
    };
  };
  const ModalDialog = composite({
    name: "ModalDialog",
    configFields: schema$2(),
    partFields: parts$2(),
    factory: factory$4,
    apis: {
      show: (apis, dialog) => {
        apis.show(dialog);
      },
      hide: (apis, dialog) => {
        apis.hide(dialog);
      },
      getBody: (apis, dialog) => apis.getBody(dialog),
      getFooter: (apis, dialog) => apis.getFooter(dialog),
      setBusy: (apis, dialog, getBusySpec2) => {
        apis.setBusy(dialog, getBusySpec2);
      },
      setIdle: (apis, dialog) => {
        apis.setIdle(dialog);
      }
    }
  });
  const dialogToggleMenuItemSchema = objOf([
    type,
    name$1
  ].concat(commonMenuItemFields));
  const dialogToggleMenuItemDataProcessor = boolean;
  const baseFooterButtonFields = [
    generatedName("button"),
    optionalIcon,
    defaultedStringEnum("align", "end", [
      "start",
      "end"
    ]),
    primary,
    enabled,
    optionStringEnum("buttonType", [
      "primary",
      "secondary"
    ])
  ];
  const dialogFooterButtonFields = [
    ...baseFooterButtonFields,
    text
  ];
  const normalFooterButtonFields = [
    requiredStringEnum("type", [
      "submit",
      "cancel",
      "custom"
    ]),
    ...dialogFooterButtonFields
  ];
  const menuFooterButtonFields = [
    requiredStringEnum("type", ["menu"]),
    optionalText,
    optionalTooltip,
    optionalIcon,
    requiredArrayOf("items", dialogToggleMenuItemSchema),
    ...baseFooterButtonFields
  ];
  const dialogFooterButtonSchema = choose$1("type", {
    submit: normalFooterButtonFields,
    cancel: normalFooterButtonFields,
    custom: normalFooterButtonFields,
    menu: menuFooterButtonFields
  });
  const alertBannerFields = [
    type,
    text,
    requiredStringEnum("level", [
      "info",
      "warn",
      "error",
      "success"
    ]),
    icon,
    defaulted("url", "")
  ];
  const alertBannerSchema = objOf(alertBannerFields);
  const createBarFields = (itemsField) => [
    type,
    itemsField
  ];
  const buttonFields = [
    type,
    text,
    enabled,
    generatedName("button"),
    optionalIcon,
    borderless,
    optionStringEnum("buttonType", [
      "primary",
      "secondary",
      "toolbar"
    ]),
    primary
  ];
  const buttonSchema = objOf(buttonFields);
  const formComponentFields = [
    type,
    name$1
  ];
  const formComponentWithLabelFields = formComponentFields.concat([optionalLabel]);
  const checkboxFields = formComponentFields.concat([
    label,
    enabled
  ]);
  const checkboxSchema = objOf(checkboxFields);
  const checkboxDataProcessor = boolean;
  const collectionFields = formComponentWithLabelFields.concat([defaultedColumns("auto")]);
  const collectionSchema = objOf(collectionFields);
  const collectionDataProcessor = arrOfObj([
    value$1,
    text,
    icon
  ]);
  const colorInputFields = formComponentWithLabelFields;
  const colorInputSchema = objOf(colorInputFields);
  const colorInputDataProcessor = string;
  const colorPickerFields = formComponentWithLabelFields;
  const colorPickerSchema = objOf(colorPickerFields);
  const colorPickerDataProcessor = string;
  const customEditorFields = formComponentFields.concat([
    defaultedString("tag", "textarea"),
    requiredString("scriptId"),
    requiredString("scriptUrl"),
    defaultedPostMsg("settings", void 0)
  ]);
  const customEditorFieldsOld = formComponentFields.concat([
    defaultedString("tag", "textarea"),
    requiredFunction("init")
  ]);
  const customEditorSchema = valueOf((v) => asRaw("customeditor.old", objOfOnly(customEditorFieldsOld), v).orThunk(() => asRaw("customeditor.new", objOfOnly(customEditorFields), v)));
  const customEditorDataProcessor = string;
  const dropZoneFields = formComponentWithLabelFields;
  const dropZoneSchema = objOf(dropZoneFields);
  const dropZoneDataProcessor = arrOfVal();
  const createGridFields = (itemsField) => [
    type,
    requiredNumber("columns"),
    itemsField
  ];
  const htmlPanelFields = [
    type,
    requiredString("html"),
    defaultedStringEnum("presets", "presentation", [
      "presentation",
      "document"
    ])
  ];
  const htmlPanelSchema = objOf(htmlPanelFields);
  const iframeFields = formComponentWithLabelFields.concat([
    defaultedBoolean("sandboxed", true),
    defaultedBoolean("transparent", true)
  ]);
  const iframeSchema = objOf(iframeFields);
  const iframeDataProcessor = string;
  const imagePreviewSchema = objOf(formComponentFields.concat([optionString("height")]));
  const imagePreviewDataProcessor = objOf([
    requiredString("url"),
    optionNumber("zoom"),
    optionNumber("cachedWidth"),
    optionNumber("cachedHeight")
  ]);
  const inputFields = formComponentWithLabelFields.concat([
    optionString("inputMode"),
    optionString("placeholder"),
    defaultedBoolean("maximized", false),
    enabled
  ]);
  const inputSchema = objOf(inputFields);
  const inputDataProcessor = string;
  const createLabelFields = (itemsField) => [
    type,
    label,
    itemsField
  ];
  const listBoxSingleItemFields = [
    text,
    value$1
  ];
  const listBoxNestedItemFields = [
    text,
    requiredArrayOf("items", thunkOf("items", () => listBoxItemSchema))
  ];
  const listBoxItemSchema = oneOf([
    objOf(listBoxSingleItemFields),
    objOf(listBoxNestedItemFields)
  ]);
  const listBoxFields = formComponentWithLabelFields.concat([
    requiredArrayOf("items", listBoxItemSchema),
    enabled
  ]);
  const listBoxSchema = objOf(listBoxFields);
  const listBoxDataProcessor = string;
  const selectBoxFields = formComponentWithLabelFields.concat([
    requiredArrayOfObj("items", [
      text,
      value$1
    ]),
    defaultedNumber("size", 1),
    enabled
  ]);
  const selectBoxSchema = objOf(selectBoxFields);
  const selectBoxDataProcessor = string;
  const sizeInputFields = formComponentWithLabelFields.concat([
    defaultedBoolean("constrain", true),
    enabled
  ]);
  const sizeInputSchema = objOf(sizeInputFields);
  const sizeInputDataProcessor = objOf([
    requiredString("width"),
    requiredString("height")
  ]);
  const sliderFields = formComponentFields.concat([
    label,
    defaultedNumber("min", 0),
    defaultedNumber("max", 0)
  ]);
  const sliderSchema = objOf(sliderFields);
  const sliderInputDataProcessor = number;
  const tableFields = [
    type,
    requiredArrayOf("header", string),
    requiredArrayOf("cells", arrOf(string))
  ];
  const tableSchema = objOf(tableFields);
  const textAreaFields = formComponentWithLabelFields.concat([
    optionString("placeholder"),
    defaultedBoolean("maximized", false),
    enabled
  ]);
  const textAreaSchema = objOf(textAreaFields);
  const textAreaDataProcessor = string;
  const urlInputFields = formComponentWithLabelFields.concat([
    defaultedStringEnum("filetype", "file", [
      "image",
      "media",
      "file"
    ]),
    enabled
  ]);
  const urlInputSchema = objOf(urlInputFields);
  const urlInputDataProcessor = objOf([
    value$1,
    defaultedMeta
  ]);
  const createItemsField = (name2) => field$1("items", "items", required$2(), arrOf(valueOf((v) => asRaw(`Checking item of ${name2}`, itemSchema, v).fold((sErr) => Result.error(formatError(sErr)), (passValue) => Result.value(passValue)))));
  const itemSchema = valueThunk(() => choose$2("type", {
    alertbanner: alertBannerSchema,
    bar: objOf(createBarFields(createItemsField("bar"))),
    button: buttonSchema,
    checkbox: checkboxSchema,
    colorinput: colorInputSchema,
    colorpicker: colorPickerSchema,
    dropzone: dropZoneSchema,
    grid: objOf(createGridFields(createItemsField("grid"))),
    iframe: iframeSchema,
    input: inputSchema,
    listbox: listBoxSchema,
    selectbox: selectBoxSchema,
    sizeinput: sizeInputSchema,
    slider: sliderSchema,
    textarea: textAreaSchema,
    urlinput: urlInputSchema,
    customeditor: customEditorSchema,
    htmlpanel: htmlPanelSchema,
    imagepreview: imagePreviewSchema,
    collection: collectionSchema,
    label: objOf(createLabelFields(createItemsField("label"))),
    table: tableSchema,
    panel: panelSchema
  }));
  const panelFields = [
    type,
    defaulted("classes", []),
    requiredArrayOf("items", itemSchema)
  ];
  const panelSchema = objOf(panelFields);
  const tabFields = [
    generatedName("tab"),
    title,
    requiredArrayOf("items", itemSchema)
  ];
  const tabPanelFields = [
    type,
    requiredArrayOfObj("tabs", tabFields)
  ];
  const tabPanelSchema = objOf(tabPanelFields);
  const dialogButtonFields = dialogFooterButtonFields;
  const dialogButtonSchema = dialogFooterButtonSchema;
  const dialogSchema = objOf([
    requiredString("title"),
    requiredOf("body", choose$2("type", {
      panel: panelSchema,
      tabpanel: tabPanelSchema
    })),
    defaultedString("size", "normal"),
    requiredArrayOf("buttons", dialogButtonSchema),
    defaulted("initialData", {}),
    defaultedFunction("onAction", noop),
    defaultedFunction("onChange", noop),
    defaultedFunction("onSubmit", noop),
    defaultedFunction("onClose", noop),
    defaultedFunction("onCancel", noop),
    defaultedFunction("onTabChange", noop)
  ]);
  const createDialog = (spec) => asRaw("dialog", dialogSchema, spec);
  const urlDialogButtonSchema = objOf([
    requiredStringEnum("type", [
      "cancel",
      "custom"
    ]),
    ...dialogButtonFields
  ]);
  const urlDialogSchema = objOf([
    requiredString("title"),
    requiredString("url"),
    optionNumber("height"),
    optionNumber("width"),
    optionArrayOf("buttons", urlDialogButtonSchema),
    defaultedFunction("onAction", noop),
    defaultedFunction("onCancel", noop),
    defaultedFunction("onClose", noop),
    defaultedFunction("onMessage", noop)
  ]);
  const createUrlDialog = (spec) => asRaw("dialog", urlDialogSchema, spec);
  const getAllObjects = (obj) => {
    if (isObject(obj)) {
      return [obj].concat(bind$3(values(obj), getAllObjects));
    } else if (isArray(obj)) {
      return bind$3(obj, getAllObjects);
    } else {
      return [];
    }
  };
  const isNamedItem = (obj) => isString(obj.type) && isString(obj.name);
  const dataProcessors = {
    checkbox: checkboxDataProcessor,
    colorinput: colorInputDataProcessor,
    colorpicker: colorPickerDataProcessor,
    dropzone: dropZoneDataProcessor,
    input: inputDataProcessor,
    iframe: iframeDataProcessor,
    imagepreview: imagePreviewDataProcessor,
    selectbox: selectBoxDataProcessor,
    sizeinput: sizeInputDataProcessor,
    slider: sliderInputDataProcessor,
    listbox: listBoxDataProcessor,
    size: sizeInputDataProcessor,
    textarea: textAreaDataProcessor,
    urlinput: urlInputDataProcessor,
    customeditor: customEditorDataProcessor,
    collection: collectionDataProcessor,
    togglemenuitem: dialogToggleMenuItemDataProcessor
  };
  const getDataProcessor = (item2) => Optional.from(dataProcessors[item2.type]);
  const getNamedItems = (structure) => filter$2(getAllObjects(structure), isNamedItem);
  const createDataValidator = (structure) => {
    const namedItems = getNamedItems(structure);
    const fields = bind$3(namedItems, (item2) => getDataProcessor(item2).fold(() => [], (schema2) => [requiredOf(item2.name, schema2)]));
    return objOf(fields);
  };
  const extract = (structure) => {
    const internalDialog = getOrDie(createDialog(structure));
    const dataValidator = createDataValidator(structure);
    const initialData = structure.initialData;
    return {
      internalDialog,
      dataValidator,
      initialData
    };
  };
  const DialogManager = {
    open: (factory2, structure) => {
      const extraction = extract(structure);
      return factory2(extraction.internalDialog, extraction.initialData, extraction.dataValidator);
    },
    openUrl: (factory2, structure) => {
      const internalDialog = getOrDie(createUrlDialog(structure));
      return factory2(internalDialog);
    },
    redial: (structure) => extract(structure)
  };
  const toValidValues = (values2) => {
    const errors = [];
    const result = {};
    each(values2, (value2, name2) => {
      value2.fold(() => {
        errors.push(name2);
      }, (v) => {
        result[name2] = v;
      });
    });
    return errors.length > 0 ? Result.error(errors) : Result.value(result);
  };
  const renderBodyPanel = (spec, dialogData, backstage) => {
    const memForm = record(Form.sketch((parts2) => ({
      dom: {
        tag: "div",
        classes: ["tox-form"].concat(spec.classes)
      },
      components: map$2(spec.items, (item2) => interpretInForm(parts2, item2, dialogData, backstage))
    })));
    return {
      dom: {
        tag: "div",
        classes: ["tox-dialog__body"]
      },
      components: [{
        dom: {
          tag: "div",
          classes: ["tox-dialog__body-content"]
        },
        components: [memForm.asSpec()]
      }],
      behaviours: derive$1([
        Keying.config({
          mode: "acyclic",
          useTabstopAt: not(isPseudoStop)
        }),
        ComposingConfigs.memento(memForm),
        RepresentingConfigs.memento(memForm, {
          postprocess: (formValue) => toValidValues(formValue).fold((err) => {
            console.error(err);
            return {};
          }, identity)
        })
      ])
    };
  };
  const factory$3 = (detail, _spec) => ({
    uid: detail.uid,
    dom: detail.dom,
    components: detail.components,
    events: events$a(detail.action),
    behaviours: augment(detail.tabButtonBehaviours, [
      Focusing.config({}),
      Keying.config({
        mode: "execution",
        useSpace: true,
        useEnter: true
      }),
      Representing.config({
        store: {
          mode: "memory",
          initialValue: detail.value
        }
      })
    ]),
    domModification: detail.domModification
  });
  const TabButton = single({
    name: "TabButton",
    configFields: [
      defaulted("uid", void 0),
      required$1("value"),
      field$1("dom", "dom", mergeWithThunk(() => ({
        attributes: {
          "role": "tab",
          "id": generate$6("aria"),
          "aria-selected": "false"
        }
      })), anyValue()),
      option$3("action"),
      defaulted("domModification", {}),
      field("tabButtonBehaviours", [
        Focusing,
        Keying,
        Representing
      ]),
      required$1("view")
    ],
    factory: factory$3
  });
  const schema$1 = constant$1([
    required$1("tabs"),
    required$1("dom"),
    defaulted("clickToDismiss", false),
    field("tabbarBehaviours", [
      Highlighting,
      Keying
    ]),
    markers$1([
      "tabClass",
      "selectedClass"
    ])
  ]);
  const tabsPart = group({
    factory: TabButton,
    name: "tabs",
    unit: "tab",
    overrides: (barDetail) => {
      const dismissTab$1 = (tabbar, button2) => {
        Highlighting.dehighlight(tabbar, button2);
        emitWith(tabbar, dismissTab(), {
          tabbar,
          button: button2
        });
      };
      const changeTab$1 = (tabbar, button2) => {
        Highlighting.highlight(tabbar, button2);
        emitWith(tabbar, changeTab(), {
          tabbar,
          button: button2
        });
      };
      return {
        action: (button2) => {
          const tabbar = button2.getSystem().getByUid(barDetail.uid).getOrDie();
          const activeButton = Highlighting.isHighlighted(tabbar, button2);
          const response = (() => {
            if (activeButton && barDetail.clickToDismiss) {
              return dismissTab$1;
            } else if (!activeButton) {
              return changeTab$1;
            } else {
              return noop;
            }
          })();
          response(tabbar, button2);
        },
        domModification: { classes: [barDetail.markers.tabClass] }
      };
    }
  });
  const parts$1 = constant$1([tabsPart]);
  const factory$2 = (detail, components2, _spec, _externals) => ({
    "uid": detail.uid,
    "dom": detail.dom,
    components: components2,
    "debug.sketcher": "Tabbar",
    "domModification": { attributes: { role: "tablist" } },
    "behaviours": augment(detail.tabbarBehaviours, [
      Highlighting.config({
        highlightClass: detail.markers.selectedClass,
        itemClass: detail.markers.tabClass,
        onHighlight: (tabbar, tab) => {
          set$9(tab.element, "aria-selected", "true");
        },
        onDehighlight: (tabbar, tab) => {
          set$9(tab.element, "aria-selected", "false");
        }
      }),
      Keying.config({
        mode: "flow",
        getInitial: (tabbar) => {
          return Highlighting.getHighlighted(tabbar).map((tab) => tab.element);
        },
        selector: "." + detail.markers.tabClass,
        executeOnMove: true
      })
    ])
  });
  const Tabbar = composite({
    name: "Tabbar",
    configFields: schema$1(),
    partFields: parts$1(),
    factory: factory$2
  });
  const factory$1 = (detail, _spec) => ({
    uid: detail.uid,
    dom: detail.dom,
    behaviours: augment(detail.tabviewBehaviours, [Replacing.config({})]),
    domModification: { attributes: { role: "tabpanel" } }
  });
  const Tabview = single({
    name: "Tabview",
    configFields: [field("tabviewBehaviours", [Replacing])],
    factory: factory$1
  });
  const schema = constant$1([
    defaulted("selectFirst", true),
    onHandler("onChangeTab"),
    onHandler("onDismissTab"),
    defaulted("tabs", []),
    field("tabSectionBehaviours", [])
  ]);
  const barPart = required({
    factory: Tabbar,
    schema: [
      required$1("dom"),
      requiredObjOf("markers", [
        required$1("tabClass"),
        required$1("selectedClass")
      ])
    ],
    name: "tabbar",
    defaults: (detail) => {
      return { tabs: detail.tabs };
    }
  });
  const viewPart = required({
    factory: Tabview,
    name: "tabview"
  });
  const parts = constant$1([
    barPart,
    viewPart
  ]);
  const factory = (detail, components2, _spec, _externals) => {
    const changeTab$1 = (button2) => {
      const tabValue = Representing.getValue(button2);
      getPart(button2, detail, "tabview").each((tabview) => {
        const tabWithValue = find$5(detail.tabs, (t2) => t2.value === tabValue);
        tabWithValue.each((tabData) => {
          const panel = tabData.view();
          getOpt(button2.element, "id").each((id) => {
            set$9(tabview.element, "aria-labelledby", id);
          });
          Replacing.set(tabview, panel);
          detail.onChangeTab(tabview, button2, panel);
        });
      });
    };
    const changeTabBy = (section, byPred) => {
      getPart(section, detail, "tabbar").each((tabbar) => {
        byPred(tabbar).each(emitExecute);
      });
    };
    return {
      uid: detail.uid,
      dom: detail.dom,
      components: components2,
      behaviours: get$3(detail.tabSectionBehaviours),
      events: derive$2(flatten([
        detail.selectFirst ? [runOnAttached((section, _simulatedEvent) => {
          changeTabBy(section, Highlighting.getFirst);
        })] : [],
        [
          run$1(changeTab(), (section, simulatedEvent) => {
            const button2 = simulatedEvent.event.button;
            changeTab$1(button2);
          }),
          run$1(dismissTab(), (section, simulatedEvent) => {
            const button2 = simulatedEvent.event.button;
            detail.onDismissTab(section, button2);
          })
        ]
      ])),
      apis: {
        getViewItems: (section) => {
          return getPart(section, detail, "tabview").map((tabview) => Replacing.contents(tabview)).getOr([]);
        },
        showTab: (section, tabKey) => {
          const getTabIfNotActive = (tabbar) => {
            const candidates = Highlighting.getCandidates(tabbar);
            const optTab = find$5(candidates, (c) => Representing.getValue(c) === tabKey);
            return optTab.filter((tab) => !Highlighting.isHighlighted(tabbar, tab));
          };
          changeTabBy(section, getTabIfNotActive);
        }
      }
    };
  };
  const TabSection = composite({
    name: "TabSection",
    configFields: schema(),
    partFields: parts(),
    factory,
    apis: {
      getViewItems: (apis, component) => apis.getViewItems(component),
      showTab: (apis, component, tabKey) => {
        apis.showTab(component, tabKey);
      }
    }
  });
  const measureHeights = (allTabs, tabview, tabviewComp) => map$2(allTabs, (_tab, i) => {
    Replacing.set(tabviewComp, allTabs[i].view());
    const rect2 = tabview.dom.getBoundingClientRect();
    Replacing.set(tabviewComp, []);
    return rect2.height;
  });
  const getMaxHeight = (heights) => head(sort(heights, (a, b2) => {
    if (a > b2) {
      return -1;
    } else if (a < b2) {
      return 1;
    } else {
      return 0;
    }
  }));
  const getMaxTabviewHeight = (dialog, tabview, tablist) => {
    const documentElement$1 = documentElement(dialog).dom;
    const rootElm = ancestor(dialog, ".tox-dialog-wrap").getOr(dialog);
    const isFixed = get$e(rootElm, "position") === "fixed";
    let maxHeight;
    if (isFixed) {
      maxHeight = Math.max(documentElement$1.clientHeight, window.innerHeight);
    } else {
      maxHeight = Math.max(documentElement$1.offsetHeight, documentElement$1.scrollHeight);
    }
    const tabviewHeight = get$d(tabview);
    const isTabListBeside = tabview.dom.offsetLeft >= tablist.dom.offsetLeft + get$c(tablist);
    const currentTabHeight = isTabListBeside ? Math.max(get$d(tablist), tabviewHeight) : tabviewHeight;
    const dialogTopMargin = parseInt(get$e(dialog, "margin-top"), 10) || 0;
    const dialogBottomMargin = parseInt(get$e(dialog, "margin-bottom"), 10) || 0;
    const dialogHeight = get$d(dialog) + dialogTopMargin + dialogBottomMargin;
    const chromeHeight = dialogHeight - currentTabHeight;
    return maxHeight - chromeHeight;
  };
  const showTab = (allTabs, comp) => {
    head(allTabs).each((tab) => TabSection.showTab(comp, tab.value));
  };
  const setTabviewHeight = (tabview, height2) => {
    set$8(tabview, "height", height2 + "px");
    set$8(tabview, "flex-basis", height2 + "px");
  };
  const updateTabviewHeight = (dialogBody, tabview, maxTabHeight) => {
    ancestor(dialogBody, '[role="dialog"]').each((dialog) => {
      descendant(dialog, '[role="tablist"]').each((tablist) => {
        maxTabHeight.get().map((height2) => {
          set$8(tabview, "height", "0");
          set$8(tabview, "flex-basis", "0");
          return Math.min(height2, getMaxTabviewHeight(dialog, tabview, tablist));
        }).each((height2) => {
          setTabviewHeight(tabview, height2);
        });
      });
    });
  };
  const getTabview = (dialog) => descendant(dialog, '[role="tabpanel"]');
  const setMode = (allTabs) => {
    const smartTabHeight = (() => {
      const maxTabHeight = value$2();
      const extraEvents = [
        runOnAttached((comp) => {
          const dialog = comp.element;
          getTabview(dialog).each((tabview) => {
            set$8(tabview, "visibility", "hidden");
            comp.getSystem().getByDom(tabview).toOptional().each((tabviewComp) => {
              const heights = measureHeights(allTabs, tabview, tabviewComp);
              const maxTabHeightOpt = getMaxHeight(heights);
              maxTabHeightOpt.fold(maxTabHeight.clear, maxTabHeight.set);
            });
            updateTabviewHeight(dialog, tabview, maxTabHeight);
            remove$6(tabview, "visibility");
            showTab(allTabs, comp);
            requestAnimationFrame(() => {
              updateTabviewHeight(dialog, tabview, maxTabHeight);
            });
          });
        }),
        run$1(windowResize(), (comp) => {
          const dialog = comp.element;
          getTabview(dialog).each((tabview) => {
            updateTabviewHeight(dialog, tabview, maxTabHeight);
          });
        }),
        run$1(formResizeEvent, (comp, _se) => {
          const dialog = comp.element;
          getTabview(dialog).each((tabview) => {
            const oldFocus = active$1(getRootNode(tabview));
            set$8(tabview, "visibility", "hidden");
            const oldHeight = getRaw(tabview, "height").map((h2) => parseInt(h2, 10));
            remove$6(tabview, "height");
            remove$6(tabview, "flex-basis");
            const newHeight = tabview.dom.getBoundingClientRect().height;
            const hasGrown2 = oldHeight.forall((h2) => newHeight > h2);
            if (hasGrown2) {
              maxTabHeight.set(newHeight);
              updateTabviewHeight(dialog, tabview, maxTabHeight);
            } else {
              oldHeight.each((h2) => {
                setTabviewHeight(tabview, h2);
              });
            }
            remove$6(tabview, "visibility");
            oldFocus.each(focus$3);
          });
        })
      ];
      const selectFirst = false;
      return {
        extraEvents,
        selectFirst
      };
    })();
    const naiveTabHeight = (() => {
      const extraEvents = [];
      const selectFirst = true;
      return {
        extraEvents,
        selectFirst
      };
    })();
    return {
      smartTabHeight,
      naiveTabHeight
    };
  };
  const SendDataToSectionChannel = "send-data-to-section";
  const SendDataToViewChannel = "send-data-to-view";
  const renderTabPanel = (spec, dialogData, backstage) => {
    const storedValue = Cell({});
    const updateDataWithForm = (form) => {
      const formData = Representing.getValue(form);
      const validData = toValidValues(formData).getOr({});
      const currentData = storedValue.get();
      const newData = deepMerge(currentData, validData);
      storedValue.set(newData);
    };
    const setDataOnForm = (form) => {
      const tabData = storedValue.get();
      Representing.setValue(form, tabData);
    };
    const oldTab = Cell(null);
    const allTabs = map$2(spec.tabs, (tab) => {
      return {
        value: tab.name,
        dom: {
          tag: "div",
          classes: ["tox-dialog__body-nav-item"]
        },
        components: [text$1(backstage.shared.providers.translate(tab.title))],
        view: () => {
          return [Form.sketch((parts2) => ({
            dom: {
              tag: "div",
              classes: ["tox-form"]
            },
            components: map$2(tab.items, (item2) => interpretInForm(parts2, item2, dialogData, backstage)),
            formBehaviours: derive$1([
              Keying.config({
                mode: "acyclic",
                useTabstopAt: not(isPseudoStop)
              }),
              config("TabView.form.events", [
                runOnAttached(setDataOnForm),
                runOnDetached(updateDataWithForm)
              ]),
              Receiving.config({
                channels: wrapAll([
                  {
                    key: SendDataToSectionChannel,
                    value: { onReceive: updateDataWithForm }
                  },
                  {
                    key: SendDataToViewChannel,
                    value: { onReceive: setDataOnForm }
                  }
                ])
              })
            ])
          }))];
        }
      };
    });
    const tabMode = setMode(allTabs).smartTabHeight;
    return TabSection.sketch({
      dom: {
        tag: "div",
        classes: ["tox-dialog__body"]
      },
      onChangeTab: (section, button2, _viewItems) => {
        const name2 = Representing.getValue(button2);
        emitWith(section, formTabChangeEvent, {
          name: name2,
          oldName: oldTab.get()
        });
        oldTab.set(name2);
      },
      tabs: allTabs,
      components: [
        TabSection.parts.tabbar({
          dom: {
            tag: "div",
            classes: ["tox-dialog__body-nav"]
          },
          components: [Tabbar.parts.tabs({})],
          markers: {
            tabClass: "tox-tab",
            selectedClass: "tox-dialog__body-nav-item--active"
          },
          tabbarBehaviours: derive$1([Tabstopping.config({})])
        }),
        TabSection.parts.tabview({
          dom: {
            tag: "div",
            classes: ["tox-dialog__body-content"]
          }
        })
      ],
      selectFirst: tabMode.selectFirst,
      tabSectionBehaviours: derive$1([
        config("tabpanel", tabMode.extraEvents),
        Keying.config({ mode: "acyclic" }),
        Composing.config({ find: (comp) => head(TabSection.getViewItems(comp)) }),
        RepresentingConfigs.withComp(Optional.none(), (tsection) => {
          tsection.getSystem().broadcastOn([SendDataToSectionChannel], {});
          return storedValue.get();
        }, (tsection, value2) => {
          storedValue.set(value2);
          tsection.getSystem().broadcastOn([SendDataToViewChannel], {});
        })
      ])
    });
  };
  const dialogChannel = generate$6("update-dialog");
  const titleChannel = generate$6("update-title");
  const bodyChannel = generate$6("update-body");
  const footerChannel = generate$6("update-footer");
  const bodySendMessageChannel = generate$6("body-send-message");
  const renderBody = (spec, dialogId, contentId, backstage, ariaAttrs) => {
    const renderComponents2 = (incoming) => {
      const body2 = incoming.body;
      switch (body2.type) {
        case "tabpanel": {
          return [renderTabPanel(body2, incoming.initialData, backstage)];
        }
        default: {
          return [renderBodyPanel(body2, incoming.initialData, backstage)];
        }
      }
    };
    const updateState = (_comp, incoming) => Optional.some({ isTabPanel: () => incoming.body.type === "tabpanel" });
    const ariaAttributes = { "aria-live": "polite" };
    return {
      dom: {
        tag: "div",
        classes: ["tox-dialog__content-js"],
        attributes: {
          ...contentId.map((x) => ({ id: x })).getOr({}),
          ...ariaAttrs ? ariaAttributes : {}
        }
      },
      components: [],
      behaviours: derive$1([
        ComposingConfigs.childAt(0),
        Reflecting.config({
          channel: `${bodyChannel}-${dialogId}`,
          updateState,
          renderComponents: renderComponents2,
          initialData: spec
        })
      ])
    };
  };
  const renderInlineBody = (spec, dialogId, contentId, backstage, ariaAttrs) => renderBody(spec, dialogId, Optional.some(contentId), backstage, ariaAttrs);
  const renderModalBody = (spec, dialogId, backstage) => {
    const bodySpec = renderBody(spec, dialogId, Optional.none(), backstage, false);
    return ModalDialog.parts.body(bodySpec);
  };
  const renderIframeBody = (spec) => {
    const bodySpec = {
      dom: {
        tag: "div",
        classes: ["tox-dialog__content-js"]
      },
      components: [{
        dom: {
          tag: "div",
          classes: ["tox-dialog__body-iframe"]
        },
        components: [craft({
          dom: {
            tag: "iframe",
            attributes: { src: spec.url }
          },
          behaviours: derive$1([
            Tabstopping.config({}),
            Focusing.config({})
          ])
        })]
      }],
      behaviours: derive$1([Keying.config({
        mode: "acyclic",
        useTabstopAt: not(isPseudoStop)
      })])
    };
    return ModalDialog.parts.body(bodySpec);
  };
  const isTouch = global$5.deviceType.isTouch();
  const hiddenHeader = (title2, close2) => ({
    dom: {
      tag: "div",
      styles: { display: "none" },
      classes: ["tox-dialog__header"]
    },
    components: [
      title2,
      close2
    ]
  });
  const pClose = (onClose, providersBackstage) => ModalDialog.parts.close(Button.sketch({
    dom: {
      tag: "button",
      classes: [
        "tox-button",
        "tox-button--icon",
        "tox-button--naked"
      ],
      attributes: {
        "type": "button",
        "aria-label": providersBackstage.translate("Close")
      }
    },
    action: onClose,
    buttonBehaviours: derive$1([Tabstopping.config({})])
  }));
  const pUntitled = () => ModalDialog.parts.title({
    dom: {
      tag: "div",
      classes: ["tox-dialog__title"],
      innerHtml: "",
      styles: { display: "none" }
    }
  });
  const pBodyMessage = (message, providersBackstage) => ModalDialog.parts.body({
    dom: {
      tag: "div",
      classes: ["tox-dialog__body"]
    },
    components: [{
      dom: {
        tag: "div",
        classes: ["tox-dialog__body-content"]
      },
      components: [{ dom: fromHtml(`<p>${providersBackstage.translate(message)}</p>`) }]
    }]
  });
  const pFooter = (buttons) => ModalDialog.parts.footer({
    dom: {
      tag: "div",
      classes: ["tox-dialog__footer"]
    },
    components: buttons
  });
  const pFooterGroup = (startButtons, endButtons) => [
    Container.sketch({
      dom: {
        tag: "div",
        classes: ["tox-dialog__footer-start"]
      },
      components: startButtons
    }),
    Container.sketch({
      dom: {
        tag: "div",
        classes: ["tox-dialog__footer-end"]
      },
      components: endButtons
    })
  ];
  const renderDialog$1 = (spec) => {
    const dialogClass = "tox-dialog";
    const blockerClass = dialogClass + "-wrap";
    const blockerBackdropClass = blockerClass + "__backdrop";
    const scrollLockClass = dialogClass + "__disable-scroll";
    return ModalDialog.sketch({
      lazySink: spec.lazySink,
      onEscape: (comp) => {
        spec.onEscape(comp);
        return Optional.some(true);
      },
      useTabstopAt: (elem) => !isPseudoStop(elem),
      dom: {
        tag: "div",
        classes: [dialogClass].concat(spec.extraClasses),
        styles: {
          position: "relative",
          ...spec.extraStyles
        }
      },
      components: [
        spec.header,
        spec.body,
        ...spec.footer.toArray()
      ],
      parts: {
        blocker: {
          dom: fromHtml(`<div class="${blockerClass}"></div>`),
          components: [{
            dom: {
              tag: "div",
              classes: isTouch ? [
                blockerBackdropClass,
                blockerBackdropClass + "--opaque"
              ] : [blockerBackdropClass]
            }
          }]
        }
      },
      dragBlockClass: blockerClass,
      modalBehaviours: derive$1([
        Focusing.config({}),
        config("dialog-events", spec.dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
          Keying.focusIn(comp);
        })])),
        config("scroll-lock", [
          runOnAttached(() => {
            add$2(body(), scrollLockClass);
          }),
          runOnDetached(() => {
            remove$2(body(), scrollLockClass);
          })
        ]),
        ...spec.extraBehaviours
      ]),
      eventOrder: {
        [execute$5()]: ["dialog-events"],
        [attachedToDom()]: [
          "scroll-lock",
          "dialog-events",
          "alloy.base.behaviour"
        ],
        [detachedFromDom()]: [
          "alloy.base.behaviour",
          "dialog-events",
          "scroll-lock"
        ],
        ...spec.eventOrder
      }
    });
  };
  const renderClose = (providersBackstage) => Button.sketch({
    dom: {
      tag: "button",
      classes: [
        "tox-button",
        "tox-button--icon",
        "tox-button--naked"
      ],
      attributes: {
        "type": "button",
        "aria-label": providersBackstage.translate("Close"),
        "title": providersBackstage.translate("Close")
      }
    },
    components: [render$3("close", {
      tag: "div",
      classes: ["tox-icon"]
    }, providersBackstage.icons)],
    action: (comp) => {
      emit(comp, formCancelEvent);
    }
  });
  const renderTitle = (spec, dialogId, titleId, providersBackstage) => {
    const renderComponents2 = (data) => [text$1(providersBackstage.translate(data.title))];
    return {
      dom: {
        tag: "div",
        classes: ["tox-dialog__title"],
        attributes: { ...titleId.map((x) => ({ id: x })).getOr({}) }
      },
      components: [],
      behaviours: derive$1([Reflecting.config({
        channel: `${titleChannel}-${dialogId}`,
        initialData: spec,
        renderComponents: renderComponents2
      })])
    };
  };
  const renderDragHandle = () => ({ dom: fromHtml('<div class="tox-dialog__draghandle"></div>') });
  const renderInlineHeader = (spec, dialogId, titleId, providersBackstage) => Container.sketch({
    dom: fromHtml('<div class="tox-dialog__header"></div>'),
    components: [
      renderTitle(spec, dialogId, Optional.some(titleId), providersBackstage),
      renderDragHandle(),
      renderClose(providersBackstage)
    ],
    containerBehaviours: derive$1([Dragging.config({
      mode: "mouse",
      blockerClass: "blocker",
      getTarget: (handle2) => {
        return closest$1(handle2, '[role="dialog"]').getOrDie();
      },
      snaps: {
        getSnapPoints: () => [],
        leftAttr: "data-drag-left",
        topAttr: "data-drag-top"
      }
    })])
  });
  const renderModalHeader = (spec, dialogId, providersBackstage) => {
    const pTitle = ModalDialog.parts.title(renderTitle(spec, dialogId, Optional.none(), providersBackstage));
    const pHandle = ModalDialog.parts.draghandle(renderDragHandle());
    const pClose2 = ModalDialog.parts.close(renderClose(providersBackstage));
    const components2 = [pTitle].concat(spec.draggable ? [pHandle] : []).concat([pClose2]);
    return Container.sketch({
      dom: fromHtml('<div class="tox-dialog__header"></div>'),
      components: components2
    });
  };
  const getHeader = (title2, dialogId, backstage) => renderModalHeader({
    title: backstage.shared.providers.translate(title2),
    draggable: backstage.dialog.isDraggableModal()
  }, dialogId, backstage.shared.providers);
  const getBusySpec = (message, bs, providers) => ({
    dom: {
      tag: "div",
      classes: ["tox-dialog__busy-spinner"],
      attributes: { "aria-label": providers.translate(message) },
      styles: {
        left: "0px",
        right: "0px",
        bottom: "0px",
        top: "0px",
        position: "absolute"
      }
    },
    behaviours: bs,
    components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  });
  const getEventExtras = (lazyDialog, providers, extra) => ({
    onClose: () => extra.closeWindow(),
    onBlock: (blockEvent) => {
      ModalDialog.setBusy(lazyDialog(), (_comp, bs) => getBusySpec(blockEvent.message, bs, providers));
    },
    onUnblock: () => {
      ModalDialog.setIdle(lazyDialog());
    }
  });
  const renderModalDialog = (spec, initialData, dialogEvents, backstage) => {
    const updateState = (_comp, incoming) => Optional.some(incoming);
    return build$1(renderDialog$1({
      ...spec,
      lazySink: backstage.shared.getSink,
      extraBehaviours: [
        Reflecting.config({
          channel: `${dialogChannel}-${spec.id}`,
          updateState,
          initialData
        }),
        RepresentingConfigs.memory({}),
        ...spec.extraBehaviours
      ],
      onEscape: (comp) => {
        emit(comp, formCancelEvent);
      },
      dialogEvents,
      eventOrder: {
        [receive()]: [
          Reflecting.name(),
          Receiving.name()
        ],
        [attachedToDom()]: [
          "scroll-lock",
          Reflecting.name(),
          "messages",
          "dialog-events",
          "alloy.base.behaviour"
        ],
        [detachedFromDom()]: [
          "alloy.base.behaviour",
          "dialog-events",
          "messages",
          Reflecting.name(),
          "scroll-lock"
        ]
      }
    }));
  };
  const mapMenuButtons = (buttons) => {
    const mapItems = (button2) => {
      const items = map$2(button2.items, (item2) => {
        const cell = Cell(false);
        return {
          ...item2,
          storage: cell
        };
      });
      return {
        ...button2,
        items
      };
    };
    return map$2(buttons, (button2) => {
      if (button2.type === "menu") {
        return mapItems(button2);
      }
      return button2;
    });
  };
  const extractCellsToObject = (buttons) => foldl(buttons, (acc, button2) => {
    if (button2.type === "menu") {
      const menuButton = button2;
      return foldl(menuButton.items, (innerAcc, item2) => {
        innerAcc[item2.name] = item2.storage;
        return innerAcc;
      }, acc);
    }
    return acc;
  }, {});
  const initCommonEvents = (fireApiEvent, extras) => [
    runWithTarget(focusin(), onFocus),
    fireApiEvent(formCloseEvent, (_api, spec) => {
      extras.onClose();
      spec.onClose();
    }),
    fireApiEvent(formCancelEvent, (api2, spec, _event, self2) => {
      spec.onCancel(api2);
      emit(self2, formCloseEvent);
    }),
    run$1(formUnblockEvent, (_c, _se) => extras.onUnblock()),
    run$1(formBlockEvent, (_c, se) => extras.onBlock(se.event))
  ];
  const initUrlDialog = (getInstanceApi, extras) => {
    const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
      withSpec(c, (spec, _c) => {
        f(getInstanceApi(), spec, se.event, c);
      });
    });
    const withSpec = (c, f) => {
      Reflecting.getState(c).get().each((currentDialog) => {
        f(currentDialog, c);
      });
    };
    return [
      ...initCommonEvents(fireApiEvent, extras),
      fireApiEvent(formActionEvent, (api2, spec, event) => {
        spec.onAction(api2, { name: event.name });
      })
    ];
  };
  const initDialog = (getInstanceApi, extras, getSink2) => {
    const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
      withSpec(c, (spec, _c) => {
        f(getInstanceApi(), spec, se.event, c);
      });
    });
    const withSpec = (c, f) => {
      Reflecting.getState(c).get().each((currentDialogInit) => {
        f(currentDialogInit.internalDialog, c);
      });
    };
    return [
      ...initCommonEvents(fireApiEvent, extras),
      fireApiEvent(formSubmitEvent, (api2, spec) => spec.onSubmit(api2)),
      fireApiEvent(formChangeEvent, (api2, spec, event) => {
        spec.onChange(api2, { name: event.name });
      }),
      fireApiEvent(formActionEvent, (api2, spec, event, component) => {
        const focusIn2 = () => Keying.focusIn(component);
        const isDisabled2 = (focused) => has$1(focused, "disabled") || getOpt(focused, "aria-disabled").exists((val) => val === "true");
        const rootNode = getRootNode(component.element);
        const current = active$1(rootNode);
        spec.onAction(api2, {
          name: event.name,
          value: event.value
        });
        active$1(rootNode).fold(focusIn2, (focused) => {
          if (isDisabled2(focused)) {
            focusIn2();
          } else if (current.exists((cur) => contains(focused, cur) && isDisabled2(cur))) {
            focusIn2();
          } else {
            getSink2().toOptional().filter((sink) => !contains(sink.element, focused)).each(focusIn2);
          }
        });
      }),
      fireApiEvent(formTabChangeEvent, (api2, spec, event) => {
        spec.onTabChange(api2, {
          newTabName: event.name,
          oldTabName: event.oldName
        });
      }),
      runOnDetached((component) => {
        const api2 = getInstanceApi();
        Representing.setValue(component, api2.getData());
      })
    ];
  };
  const SilverDialogEvents = {
    initUrlDialog,
    initDialog
  };
  const makeButton = (button2, backstage) => renderFooterButton(button2, button2.type, backstage);
  const lookup = (compInSystem, footerButtons, buttonName) => find$5(footerButtons, (button2) => button2.name === buttonName).bind((memButton) => memButton.memento.getOpt(compInSystem));
  const renderComponents = (_data, state) => {
    const footerButtons = state.map((s) => s.footerButtons).getOr([]);
    const buttonGroups = partition$3(footerButtons, (button2) => button2.align === "start");
    const makeGroup = (edge2, buttons) => Container.sketch({
      dom: {
        tag: "div",
        classes: [`tox-dialog__footer-${edge2}`]
      },
      components: map$2(buttons, (button2) => button2.memento.asSpec())
    });
    const startButtons = makeGroup("start", buttonGroups.pass);
    const endButtons = makeGroup("end", buttonGroups.fail);
    return [
      startButtons,
      endButtons
    ];
  };
  const renderFooter = (initSpec, dialogId, backstage) => {
    const updateState = (comp, data) => {
      const footerButtons = map$2(data.buttons, (button2) => {
        const memButton = record(makeButton(button2, backstage));
        return {
          name: button2.name,
          align: button2.align,
          memento: memButton
        };
      });
      const lookupByName = (buttonName) => lookup(comp, footerButtons, buttonName);
      return Optional.some({
        lookupByName,
        footerButtons
      });
    };
    return {
      dom: fromHtml('<div class="tox-dialog__footer"></div>'),
      components: [],
      behaviours: derive$1([Reflecting.config({
        channel: `${footerChannel}-${dialogId}`,
        initialData: initSpec,
        updateState,
        renderComponents
      })])
    };
  };
  const renderInlineFooter = (initSpec, dialogId, backstage) => renderFooter(initSpec, dialogId, backstage);
  const renderModalFooter = (initSpec, dialogId, backstage) => ModalDialog.parts.footer(renderFooter(initSpec, dialogId, backstage));
  const getCompByName = (access, name2) => {
    const root = access.getRoot();
    if (root.getSystem().isConnected()) {
      const form = Composing.getCurrent(access.getFormWrapper()).getOr(access.getFormWrapper());
      return Form.getField(form, name2).orThunk(() => {
        const footer = access.getFooter();
        const footerState = Reflecting.getState(footer).get();
        return footerState.bind((f) => f.lookupByName(name2));
      });
    } else {
      return Optional.none();
    }
  };
  const validateData$1 = (access, data) => {
    const root = access.getRoot();
    return Reflecting.getState(root).get().map((dialogState) => getOrDie(asRaw("data", dialogState.dataValidator, data))).getOr(data);
  };
  const getDialogApi = (access, doRedial, menuItemStates) => {
    const withRoot = (f) => {
      const root = access.getRoot();
      if (root.getSystem().isConnected()) {
        f(root);
      }
    };
    const getData2 = () => {
      const root = access.getRoot();
      const valueComp = root.getSystem().isConnected() ? access.getFormWrapper() : root;
      const representedValues = Representing.getValue(valueComp);
      const menuItemCurrentState = map$1(menuItemStates, (cell) => cell.get());
      return {
        ...representedValues,
        ...menuItemCurrentState
      };
    };
    const setData = (newData) => {
      withRoot((_) => {
        const prevData = instanceApi.getData();
        const mergedData = deepMerge(prevData, newData);
        const newInternalData = validateData$1(access, mergedData);
        const form = access.getFormWrapper();
        Representing.setValue(form, newInternalData);
        each(menuItemStates, (v, k) => {
          if (has$2(mergedData, k)) {
            v.set(mergedData[k]);
          }
        });
      });
    };
    const setEnabled = (name2, state) => {
      getCompByName(access, name2).each(state ? Disabling.enable : Disabling.disable);
    };
    const focus2 = (name2) => {
      getCompByName(access, name2).each(Focusing.focus);
    };
    const block2 = (message) => {
      if (!isString(message)) {
        throw new Error("The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument");
      }
      withRoot((root) => {
        emitWith(root, formBlockEvent, { message });
      });
    };
    const unblock2 = () => {
      withRoot((root) => {
        emit(root, formUnblockEvent);
      });
    };
    const showTab2 = (name2) => {
      withRoot((_) => {
        const body2 = access.getBody();
        const bodyState = Reflecting.getState(body2);
        if (bodyState.get().exists((b2) => b2.isTabPanel())) {
          Composing.getCurrent(body2).each((tabSection) => {
            TabSection.showTab(tabSection, name2);
          });
        }
      });
    };
    const redial = (d) => {
      withRoot((root) => {
        const id = access.getId();
        const dialogInit = doRedial(d);
        root.getSystem().broadcastOn([`${dialogChannel}-${id}`], dialogInit);
        root.getSystem().broadcastOn([`${titleChannel}-${id}`], dialogInit.internalDialog);
        root.getSystem().broadcastOn([`${bodyChannel}-${id}`], dialogInit.internalDialog);
        root.getSystem().broadcastOn([`${footerChannel}-${id}`], dialogInit.internalDialog);
        instanceApi.setData(dialogInit.initialData);
      });
    };
    const close2 = () => {
      withRoot((root) => {
        emit(root, formCloseEvent);
      });
    };
    const instanceApi = {
      getData: getData2,
      setData,
      setEnabled,
      focus: focus2,
      block: block2,
      unblock: unblock2,
      showTab: showTab2,
      redial,
      close: close2
    };
    return instanceApi;
  };
  const getDialogSizeClasses = (size) => {
    switch (size) {
      case "large":
        return ["tox-dialog--width-lg"];
      case "medium":
        return ["tox-dialog--width-md"];
      default:
        return [];
    }
  };
  const renderDialog = (dialogInit, extra, backstage) => {
    const dialogId = generate$6("dialog");
    const internalDialog = dialogInit.internalDialog;
    const header = getHeader(internalDialog.title, dialogId, backstage);
    const body2 = renderModalBody({
      body: internalDialog.body,
      initialData: internalDialog.initialData
    }, dialogId, backstage);
    const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
    const objOfCells = extractCellsToObject(storagedMenuButtons);
    const footer = renderModalFooter({ buttons: storagedMenuButtons }, dialogId, backstage);
    const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra), backstage.shared.getSink);
    const dialogSize = getDialogSizeClasses(internalDialog.size);
    const spec = {
      id: dialogId,
      header,
      body: body2,
      footer: Optional.some(footer),
      extraClasses: dialogSize,
      extraBehaviours: [],
      extraStyles: {}
    };
    const dialog = renderModalDialog(spec, dialogInit, dialogEvents, backstage);
    const modalAccess = (() => {
      const getForm = () => {
        const outerForm = ModalDialog.getBody(dialog);
        return Composing.getCurrent(outerForm).getOr(outerForm);
      };
      return {
        getId: constant$1(dialogId),
        getRoot: constant$1(dialog),
        getBody: () => ModalDialog.getBody(dialog),
        getFooter: () => ModalDialog.getFooter(dialog),
        getFormWrapper: getForm
      };
    })();
    const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
    return {
      dialog,
      instanceApi
    };
  };
  const renderInlineDialog = (dialogInit, extra, backstage, ariaAttrs) => {
    const dialogId = generate$6("dialog");
    const dialogLabelId = generate$6("dialog-label");
    const dialogContentId = generate$6("dialog-content");
    const internalDialog = dialogInit.internalDialog;
    const updateState = (_comp, incoming) => Optional.some(incoming);
    const memHeader = record(renderInlineHeader({
      title: internalDialog.title,
      draggable: true
    }, dialogId, dialogLabelId, backstage.shared.providers));
    const memBody = record(renderInlineBody({
      body: internalDialog.body,
      initialData: internalDialog.initialData
    }, dialogId, dialogContentId, backstage, ariaAttrs));
    const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
    const objOfCells = extractCellsToObject(storagedMenuButtons);
    const memFooter = record(renderInlineFooter({ buttons: storagedMenuButtons }, dialogId, backstage));
    const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, {
      onBlock: (event) => {
        Blocking.block(dialog, (_comp, bs) => getBusySpec(event.message, bs, backstage.shared.providers));
      },
      onUnblock: () => {
        Blocking.unblock(dialog);
      },
      onClose: () => extra.closeWindow()
    }, backstage.shared.getSink);
    const dialog = build$1({
      dom: {
        tag: "div",
        classes: [
          "tox-dialog",
          "tox-dialog-inline"
        ],
        attributes: {
          role: "dialog",
          ["aria-labelledby"]: dialogLabelId,
          ["aria-describedby"]: dialogContentId
        }
      },
      eventOrder: {
        [receive()]: [
          Reflecting.name(),
          Receiving.name()
        ],
        [execute$5()]: ["execute-on-form"],
        [attachedToDom()]: [
          "reflecting",
          "execute-on-form"
        ]
      },
      behaviours: derive$1([
        Keying.config({
          mode: "cyclic",
          onEscape: (c) => {
            emit(c, formCloseEvent);
            return Optional.some(true);
          },
          useTabstopAt: (elem) => !isPseudoStop(elem) && (name$3(elem) !== "button" || get$f(elem, "disabled") !== "disabled")
        }),
        Reflecting.config({
          channel: `${dialogChannel}-${dialogId}`,
          updateState,
          initialData: dialogInit
        }),
        Focusing.config({}),
        config("execute-on-form", dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
          Keying.focusIn(comp);
        })])),
        Blocking.config({ getRoot: () => Optional.some(dialog) }),
        Replacing.config({}),
        RepresentingConfigs.memory({})
      ]),
      components: [
        memHeader.asSpec(),
        memBody.asSpec(),
        memFooter.asSpec()
      ]
    });
    const instanceApi = getDialogApi({
      getId: constant$1(dialogId),
      getRoot: constant$1(dialog),
      getFooter: () => memFooter.get(dialog),
      getBody: () => memBody.get(dialog),
      getFormWrapper: () => {
        const body2 = memBody.get(dialog);
        return Composing.getCurrent(body2).getOr(body2);
      }
    }, extra.redial, objOfCells);
    return {
      dialog,
      instanceApi
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.util.URI");
  const getUrlDialogApi = (root) => {
    const withRoot = (f) => {
      if (root.getSystem().isConnected()) {
        f(root);
      }
    };
    const block2 = (message) => {
      if (!isString(message)) {
        throw new Error("The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument");
      }
      withRoot((root2) => {
        emitWith(root2, formBlockEvent, { message });
      });
    };
    const unblock2 = () => {
      withRoot((root2) => {
        emit(root2, formUnblockEvent);
      });
    };
    const close2 = () => {
      withRoot((root2) => {
        emit(root2, formCloseEvent);
      });
    };
    const sendMessage = (data) => {
      withRoot((root2) => {
        root2.getSystem().broadcastOn([bodySendMessageChannel], data);
      });
    };
    return {
      block: block2,
      unblock: unblock2,
      close: close2,
      sendMessage
    };
  };
  const SUPPORTED_MESSAGE_ACTIONS = [
    "insertContent",
    "setContent",
    "execCommand",
    "close",
    "block",
    "unblock"
  ];
  const isSupportedMessage = (data) => isObject(data) && SUPPORTED_MESSAGE_ACTIONS.indexOf(data.mceAction) !== -1;
  const isCustomMessage = (data) => !isSupportedMessage(data) && isObject(data) && has$2(data, "mceAction");
  const handleMessage = (editor, api2, data) => {
    switch (data.mceAction) {
      case "insertContent":
        editor.insertContent(data.content);
        break;
      case "setContent":
        editor.setContent(data.content);
        break;
      case "execCommand":
        const ui = isBoolean(data.ui) ? data.ui : false;
        editor.execCommand(data.cmd, ui, data.value);
        break;
      case "close":
        api2.close();
        break;
      case "block":
        api2.block(data.message);
        break;
      case "unblock":
        api2.unblock();
        break;
    }
  };
  const renderUrlDialog = (internalDialog, extra, editor, backstage) => {
    const dialogId = generate$6("dialog");
    const header = getHeader(internalDialog.title, dialogId, backstage);
    const body2 = renderIframeBody(internalDialog);
    const footer = internalDialog.buttons.bind((buttons) => {
      if (buttons.length === 0) {
        return Optional.none();
      } else {
        return Optional.some(renderModalFooter({ buttons }, dialogId, backstage));
      }
    });
    const dialogEvents = SilverDialogEvents.initUrlDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra));
    const styles = {
      ...internalDialog.height.fold(() => ({}), (height2) => ({
        "height": height2 + "px",
        "max-height": height2 + "px"
      })),
      ...internalDialog.width.fold(() => ({}), (width2) => ({
        "width": width2 + "px",
        "max-width": width2 + "px"
      }))
    };
    const classes2 = internalDialog.width.isNone() && internalDialog.height.isNone() ? ["tox-dialog--width-lg"] : [];
    const iframeUri = new global2(internalDialog.url, { base_uri: new global2(window.location.href) });
    const iframeDomain = `${iframeUri.protocol}://${iframeUri.host}${iframeUri.port ? ":" + iframeUri.port : ""}`;
    const messageHandlerUnbinder = unbindable();
    const extraBehaviours = [
      config("messages", [
        runOnAttached(() => {
          const unbind2 = bind(SugarElement.fromDom(window), "message", (e) => {
            if (iframeUri.isSameOrigin(new global2(e.raw.origin))) {
              const data = e.raw.data;
              if (isSupportedMessage(data)) {
                handleMessage(editor, instanceApi, data);
              } else if (isCustomMessage(data)) {
                internalDialog.onMessage(instanceApi, data);
              }
            }
          });
          messageHandlerUnbinder.set(unbind2);
        }),
        runOnDetached(messageHandlerUnbinder.clear)
      ]),
      Receiving.config({
        channels: {
          [bodySendMessageChannel]: {
            onReceive: (comp, data) => {
              descendant(comp.element, "iframe").each((iframeEle) => {
                const iframeWin = iframeEle.dom.contentWindow;
                iframeWin.postMessage(data, iframeDomain);
              });
            }
          }
        }
      })
    ];
    const spec = {
      id: dialogId,
      header,
      body: body2,
      footer,
      extraClasses: classes2,
      extraBehaviours,
      extraStyles: styles
    };
    const dialog = renderModalDialog(spec, internalDialog, dialogEvents, backstage);
    const instanceApi = getUrlDialogApi(dialog);
    return {
      dialog,
      instanceApi
    };
  };
  const setup$2 = (extras) => {
    const sharedBackstage = extras.backstage.shared;
    const open2 = (message, callback) => {
      const closeDialog = () => {
        ModalDialog.hide(alertDialog);
        callback();
      };
      const memFooterClose = record(renderFooterButton({
        name: "close-alert",
        text: "OK",
        primary: true,
        buttonType: Optional.some("primary"),
        align: "end",
        enabled: true,
        icon: Optional.none()
      }, "cancel", extras.backstage));
      const titleSpec = pUntitled();
      const closeSpec = pClose(closeDialog, sharedBackstage.providers);
      const alertDialog = build$1(renderDialog$1({
        lazySink: () => sharedBackstage.getSink(),
        header: hiddenHeader(titleSpec, closeSpec),
        body: pBodyMessage(message, sharedBackstage.providers),
        footer: Optional.some(pFooter(pFooterGroup([], [memFooterClose.asSpec()]))),
        onEscape: closeDialog,
        extraClasses: ["tox-alert-dialog"],
        extraBehaviours: [],
        extraStyles: {},
        dialogEvents: [run$1(formCancelEvent, closeDialog)],
        eventOrder: {}
      }));
      ModalDialog.show(alertDialog);
      const footerCloseButton = memFooterClose.get(alertDialog);
      Focusing.focus(footerCloseButton);
    };
    return { open: open2 };
  };
  const setup$1 = (extras) => {
    const sharedBackstage = extras.backstage.shared;
    const open2 = (message, callback) => {
      const closeDialog = (state) => {
        ModalDialog.hide(confirmDialog);
        callback(state);
      };
      const memFooterYes = record(renderFooterButton({
        name: "yes",
        text: "Yes",
        primary: true,
        buttonType: Optional.some("primary"),
        align: "end",
        enabled: true,
        icon: Optional.none()
      }, "submit", extras.backstage));
      const footerNo = renderFooterButton({
        name: "no",
        text: "No",
        primary: false,
        buttonType: Optional.some("secondary"),
        align: "end",
        enabled: true,
        icon: Optional.none()
      }, "cancel", extras.backstage);
      const titleSpec = pUntitled();
      const closeSpec = pClose(() => closeDialog(false), sharedBackstage.providers);
      const confirmDialog = build$1(renderDialog$1({
        lazySink: () => sharedBackstage.getSink(),
        header: hiddenHeader(titleSpec, closeSpec),
        body: pBodyMessage(message, sharedBackstage.providers),
        footer: Optional.some(pFooter(pFooterGroup([], [
          footerNo,
          memFooterYes.asSpec()
        ]))),
        onEscape: () => closeDialog(false),
        extraClasses: ["tox-confirm-dialog"],
        extraBehaviours: [],
        extraStyles: {},
        dialogEvents: [
          run$1(formCancelEvent, () => closeDialog(false)),
          run$1(formSubmitEvent, () => closeDialog(true))
        ],
        eventOrder: {}
      }));
      ModalDialog.show(confirmDialog);
      const footerYesButton = memFooterYes.get(confirmDialog);
      Focusing.focus(footerYesButton);
    };
    return { open: open2 };
  };
  const validateData = (data, validator) => getOrDie(asRaw("data", validator, data));
  const isAlertOrConfirmDialog = (target) => closest(target, ".tox-alert-dialog") || closest(target, ".tox-confirm-dialog");
  const inlineAdditionalBehaviours = (editor, isStickyToolbar2, isToolbarLocationTop) => {
    if (isStickyToolbar2 && isToolbarLocationTop) {
      return [];
    } else {
      return [Docking.config({
        contextual: {
          lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
          fadeInClass: "tox-dialog-dock-fadein",
          fadeOutClass: "tox-dialog-dock-fadeout",
          transitionClass: "tox-dialog-dock-transition"
        },
        modes: ["top"]
      })];
    }
  };
  const setup = (extras) => {
    const backstage = extras.backstage;
    const editor = extras.editor;
    const isStickyToolbar$1 = isStickyToolbar(editor);
    const alertDialog = setup$2(extras);
    const confirmDialog = setup$1(extras);
    const open2 = (config2, params, closeWindow) => {
      if (params !== void 0 && params.inline === "toolbar") {
        return openInlineDialog(config2, backstage.shared.anchors.inlineDialog(), closeWindow, params.ariaAttrs);
      } else if (params !== void 0 && params.inline === "cursor") {
        return openInlineDialog(config2, backstage.shared.anchors.cursor(), closeWindow, params.ariaAttrs);
      } else {
        return openModalDialog(config2, closeWindow);
      }
    };
    const openUrl = (config2, closeWindow) => openModalUrlDialog(config2, closeWindow);
    const openModalUrlDialog = (config2, closeWindow) => {
      const factory2 = (contents2) => {
        const dialog = renderUrlDialog(contents2, {
          closeWindow: () => {
            ModalDialog.hide(dialog.dialog);
            closeWindow(dialog.instanceApi);
          }
        }, editor, backstage);
        ModalDialog.show(dialog.dialog);
        return dialog.instanceApi;
      };
      return DialogManager.openUrl(factory2, config2);
    };
    const openModalDialog = (config2, closeWindow) => {
      const factory2 = (contents2, internalInitialData, dataValidator) => {
        const initialData = internalInitialData;
        const dialogInit = {
          dataValidator,
          initialData,
          internalDialog: contents2
        };
        const dialog = renderDialog(dialogInit, {
          redial: DialogManager.redial,
          closeWindow: () => {
            ModalDialog.hide(dialog.dialog);
            closeWindow(dialog.instanceApi);
          }
        }, backstage);
        ModalDialog.show(dialog.dialog);
        dialog.instanceApi.setData(initialData);
        return dialog.instanceApi;
      };
      return DialogManager.open(factory2, config2);
    };
    const openInlineDialog = (config$1, anchor2, closeWindow, ariaAttrs) => {
      const factory2 = (contents2, internalInitialData, dataValidator) => {
        const initialData = validateData(internalInitialData, dataValidator);
        const inlineDialog = value$2();
        const isToolbarLocationTop = backstage.shared.header.isPositionedAtTop();
        const dialogInit = {
          dataValidator,
          initialData,
          internalDialog: contents2
        };
        const refreshDocking = () => inlineDialog.on((dialog) => {
          InlineView.reposition(dialog);
          Docking.refresh(dialog);
        });
        const dialogUi = renderInlineDialog(dialogInit, {
          redial: DialogManager.redial,
          closeWindow: () => {
            inlineDialog.on(InlineView.hide);
            editor.off("ResizeEditor", refreshDocking);
            inlineDialog.clear();
            closeWindow(dialogUi.instanceApi);
          }
        }, backstage, ariaAttrs);
        const inlineDialogComp = build$1(InlineView.sketch({
          lazySink: backstage.shared.getSink,
          dom: {
            tag: "div",
            classes: []
          },
          fireDismissalEventInstead: {},
          ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
          inlineBehaviours: derive$1([
            config("window-manager-inline-events", [run$1(dismissRequested(), (_comp, _se) => {
              emit(dialogUi.dialog, formCancelEvent);
            })]),
            ...inlineAdditionalBehaviours(editor, isStickyToolbar$1, isToolbarLocationTop)
          ]),
          isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
        }));
        inlineDialog.set(inlineDialogComp);
        InlineView.showWithin(inlineDialogComp, premade(dialogUi.dialog), { anchor: anchor2 }, Optional.some(body()));
        if (!isStickyToolbar$1 || !isToolbarLocationTop) {
          Docking.refresh(inlineDialogComp);
          editor.on("ResizeEditor", refreshDocking);
        }
        dialogUi.instanceApi.setData(initialData);
        Keying.focusIn(dialogUi.dialog);
        return dialogUi.instanceApi;
      };
      return DialogManager.open(factory2, config$1);
    };
    const confirm = (message, callback) => {
      confirmDialog.open(message, (state) => {
        callback(state);
      });
    };
    const alert = (message, callback) => {
      alertDialog.open(message, () => {
        callback();
      });
    };
    const close2 = (instanceApi) => {
      instanceApi.close();
    };
    return {
      open: open2,
      openUrl,
      alert,
      close: close2,
      confirm
    };
  };
  const registerOptions = (editor) => {
    register$e(editor);
    register$d(editor);
    register(editor);
  };
  var Theme = () => {
    global$a.add("silver", (editor) => {
      registerOptions(editor);
      const { getUiMothership, backstage, renderUI } = setup$3(editor);
      Autocompleter.register(editor, backstage.shared);
      const windowMgr = setup({
        editor,
        backstage
      });
      return {
        renderUI,
        getWindowManagerImpl: constant$1(windowMgr),
        getNotificationManagerImpl: () => NotificationManagerImpl(editor, { backstage }, getUiMothership())
      };
    });
  };
  Theme();
})();
(function() {
  var global$4 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const getPrototypeOf = Object.getPrototypeOf;
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const isSimpleType = (type) => (value) => typeof value === type;
  const eq = (t) => (a) => t === a;
  const is = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf(o) === proto);
  const isString = isType("string");
  const isObject = isType("object");
  const isPlainObject = (value) => is(value, Object);
  const isArray = isType("array");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const isArrayOf = (value, pred) => {
    if (isArray(value)) {
      for (let i = 0, len = value.length; i < len; ++i) {
        if (!pred(value[i])) {
          return false;
        }
      }
      return true;
    }
    return false;
  };
  const noop = () => {
  };
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = (r) => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r = {};
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r;
  };
  const filter = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== void 0 && obj[key] !== null;
  const nativePush = Array.prototype.push;
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const get = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get(xs, 0);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r = f(arr[i], i);
      if (r.isSome()) {
        return r;
      }
    }
    return Optional.none();
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const rawSet = (dom, key, value) => {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key, value + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value) => {
    rawSet(element.dom, key, value);
  };
  const remove = (element, key) => {
    element.dom.removeAttribute(key);
  };
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  var global$3 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");
  var global$2 = tinymce.util.Tools.resolve("tinymce.util.URI");
  const isNotEmpty = (s) => s.length > 0;
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("image_dimensions", {
      processor: "boolean",
      default: true
    });
    registerOption("image_advtab", {
      processor: "boolean",
      default: false
    });
    registerOption("image_uploadtab", {
      processor: "boolean",
      default: true
    });
    registerOption("image_prepend_url", {
      processor: "string",
      default: ""
    });
    registerOption("image_class_list", { processor: "object[]" });
    registerOption("image_description", {
      processor: "boolean",
      default: true
    });
    registerOption("image_title", {
      processor: "boolean",
      default: false
    });
    registerOption("image_caption", {
      processor: "boolean",
      default: false
    });
    registerOption("image_list", {
      processor: (value) => {
        const valid = value === false || isString(value) || isArrayOf(value, isObject) || isFunction(value);
        return valid ? {
          value,
          valid
        } : {
          valid: false,
          message: "Must be false, a string, an array or a function."
        };
      },
      default: false
    });
  };
  const hasDimensions = option("image_dimensions");
  const hasAdvTab = option("image_advtab");
  const hasUploadTab = option("image_uploadtab");
  const getPrependUrl = option("image_prepend_url");
  const getClassList = option("image_class_list");
  const hasDescription = option("image_description");
  const hasImageTitle = option("image_title");
  const hasImageCaption = option("image_caption");
  const getImageList = option("image_list");
  const showAccessibilityOptions = option("a11y_advanced_options");
  const isAutomaticUploadsEnabled = option("automatic_uploads");
  const hasUploadUrl = (editor) => isNotEmpty(editor.options.get("images_upload_url"));
  const hasUploadHandler = (editor) => isNonNullable(editor.options.get("images_upload_handler"));
  const parseIntAndGetMax = (val1, val2) => Math.max(parseInt(val1, 10), parseInt(val2, 10));
  const getImageSize = (url) => new Promise((callback) => {
    const img = document.createElement("img");
    const done = (dimensions) => {
      img.onload = img.onerror = null;
      if (img.parentNode) {
        img.parentNode.removeChild(img);
      }
      callback(dimensions);
    };
    img.onload = () => {
      const width = parseIntAndGetMax(img.width, img.clientWidth);
      const height = parseIntAndGetMax(img.height, img.clientHeight);
      const dimensions = {
        width,
        height
      };
      done(Promise.resolve(dimensions));
    };
    img.onerror = () => {
      done(Promise.reject(`Failed to get image dimensions for: ${url}`));
    };
    const style = img.style;
    style.visibility = "hidden";
    style.position = "fixed";
    style.bottom = style.left = "0px";
    style.width = style.height = "auto";
    document.body.appendChild(img);
    img.src = url;
  });
  const removePixelSuffix = (value) => {
    if (value) {
      value = value.replace(/px$/, "");
    }
    return value;
  };
  const addPixelSuffix = (value) => {
    if (value.length > 0 && /^[0-9]+$/.test(value)) {
      value += "px";
    }
    return value;
  };
  const mergeMargins = (css) => {
    if (css.margin) {
      const splitMargin = String(css.margin).split(" ");
      switch (splitMargin.length) {
        case 1:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[0];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[0];
          css["margin-left"] = css["margin-left"] || splitMargin[0];
          break;
        case 2:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[0];
          css["margin-left"] = css["margin-left"] || splitMargin[1];
          break;
        case 3:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[2];
          css["margin-left"] = css["margin-left"] || splitMargin[1];
          break;
        case 4:
          css["margin-top"] = css["margin-top"] || splitMargin[0];
          css["margin-right"] = css["margin-right"] || splitMargin[1];
          css["margin-bottom"] = css["margin-bottom"] || splitMargin[2];
          css["margin-left"] = css["margin-left"] || splitMargin[3];
      }
      delete css.margin;
    }
    return css;
  };
  const createImageList = (editor, callback) => {
    const imageList = getImageList(editor);
    if (isString(imageList)) {
      fetch(imageList).then((res) => {
        if (res.ok) {
          res.json().then(callback);
        }
      });
    } else if (isFunction(imageList)) {
      imageList(callback);
    } else {
      callback(imageList);
    }
  };
  const waitLoadImage = (editor, data, imgElm) => {
    const selectImage = () => {
      imgElm.onload = imgElm.onerror = null;
      if (editor.selection) {
        editor.selection.select(imgElm);
        editor.nodeChanged();
      }
    };
    imgElm.onload = () => {
      if (!data.width && !data.height && hasDimensions(editor)) {
        editor.dom.setAttribs(imgElm, {
          width: String(imgElm.clientWidth),
          height: String(imgElm.clientHeight)
        });
      }
      selectImage();
    };
    imgElm.onerror = selectImage;
  };
  const blobToDataUri = (blob) => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      resolve(reader.result);
    };
    reader.onerror = () => {
      reject(reader.error.message);
    };
    reader.readAsDataURL(blob);
  });
  const isPlaceholderImage = (imgElm) => imgElm.nodeName === "IMG" && (imgElm.hasAttribute("data-mce-object") || imgElm.hasAttribute("data-mce-placeholder"));
  const isSafeImageUrl = (editor, src) => {
    const getOption = editor.options.get;
    return global$2.isDomSafe(src, "img", {
      allow_html_data_urls: getOption("allow_html_data_urls"),
      allow_script_urls: getOption("allow_script_urls"),
      allow_svg_data_urls: getOption("allow_svg_data_urls")
    });
  };
  const DOM = global$3.DOM;
  const getHspace = (image) => {
    if (image.style.marginLeft && image.style.marginRight && image.style.marginLeft === image.style.marginRight) {
      return removePixelSuffix(image.style.marginLeft);
    } else {
      return "";
    }
  };
  const getVspace = (image) => {
    if (image.style.marginTop && image.style.marginBottom && image.style.marginTop === image.style.marginBottom) {
      return removePixelSuffix(image.style.marginTop);
    } else {
      return "";
    }
  };
  const getBorder = (image) => {
    if (image.style.borderWidth) {
      return removePixelSuffix(image.style.borderWidth);
    } else {
      return "";
    }
  };
  const getAttrib = (image, name) => {
    if (image.hasAttribute(name)) {
      return image.getAttribute(name);
    } else {
      return "";
    }
  };
  const getStyle = (image, name) => image.style[name] ? image.style[name] : "";
  const hasCaption = (image) => image.parentNode !== null && image.parentNode.nodeName === "FIGURE";
  const updateAttrib = (image, name, value) => {
    if (value === "") {
      image.removeAttribute(name);
    } else {
      image.setAttribute(name, value);
    }
  };
  const wrapInFigure = (image) => {
    const figureElm = DOM.create("figure", { class: "image" });
    DOM.insertAfter(figureElm, image);
    figureElm.appendChild(image);
    figureElm.appendChild(DOM.create("figcaption", { contentEditable: "true" }, "Caption"));
    figureElm.contentEditable = "false";
  };
  const removeFigure = (image) => {
    const figureElm = image.parentNode;
    DOM.insertAfter(image, figureElm);
    DOM.remove(figureElm);
  };
  const toggleCaption = (image) => {
    if (hasCaption(image)) {
      removeFigure(image);
    } else {
      wrapInFigure(image);
    }
  };
  const normalizeStyle = (image, normalizeCss2) => {
    const attrValue = image.getAttribute("style");
    const value = normalizeCss2(attrValue !== null ? attrValue : "");
    if (value.length > 0) {
      image.setAttribute("style", value);
      image.setAttribute("data-mce-style", value);
    } else {
      image.removeAttribute("style");
    }
  };
  const setSize = (name, normalizeCss2) => (image, name2, value) => {
    if (image.style[name2]) {
      image.style[name2] = addPixelSuffix(value);
      normalizeStyle(image, normalizeCss2);
    } else {
      updateAttrib(image, name2, value);
    }
  };
  const getSize = (image, name) => {
    if (image.style[name]) {
      return removePixelSuffix(image.style[name]);
    } else {
      return getAttrib(image, name);
    }
  };
  const setHspace = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.marginLeft = pxValue;
    image.style.marginRight = pxValue;
  };
  const setVspace = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.marginTop = pxValue;
    image.style.marginBottom = pxValue;
  };
  const setBorder = (image, value) => {
    const pxValue = addPixelSuffix(value);
    image.style.borderWidth = pxValue;
  };
  const setBorderStyle = (image, value) => {
    image.style.borderStyle = value;
  };
  const getBorderStyle = (image) => getStyle(image, "borderStyle");
  const isFigure = (elm) => elm.nodeName === "FIGURE";
  const isImage = (elm) => elm.nodeName === "IMG";
  const getIsDecorative = (image) => DOM.getAttrib(image, "alt").length === 0 && DOM.getAttrib(image, "role") === "presentation";
  const getAlt = (image) => {
    if (getIsDecorative(image)) {
      return "";
    } else {
      return getAttrib(image, "alt");
    }
  };
  const defaultData = () => ({
    src: "",
    alt: "",
    title: "",
    width: "",
    height: "",
    class: "",
    style: "",
    caption: false,
    hspace: "",
    vspace: "",
    border: "",
    borderStyle: "",
    isDecorative: false
  });
  const getStyleValue = (normalizeCss2, data) => {
    const image = document.createElement("img");
    updateAttrib(image, "style", data.style);
    if (getHspace(image) || data.hspace !== "") {
      setHspace(image, data.hspace);
    }
    if (getVspace(image) || data.vspace !== "") {
      setVspace(image, data.vspace);
    }
    if (getBorder(image) || data.border !== "") {
      setBorder(image, data.border);
    }
    if (getBorderStyle(image) || data.borderStyle !== "") {
      setBorderStyle(image, data.borderStyle);
    }
    return normalizeCss2(image.getAttribute("style"));
  };
  const create = (normalizeCss2, data) => {
    const image = document.createElement("img");
    write(normalizeCss2, {
      ...data,
      caption: false
    }, image);
    setAlt(image, data.alt, data.isDecorative);
    if (data.caption) {
      const figure = DOM.create("figure", { class: "image" });
      figure.appendChild(image);
      figure.appendChild(DOM.create("figcaption", { contentEditable: "true" }, "Caption"));
      figure.contentEditable = "false";
      return figure;
    } else {
      return image;
    }
  };
  const read = (normalizeCss2, image) => ({
    src: getAttrib(image, "src"),
    alt: getAlt(image),
    title: getAttrib(image, "title"),
    width: getSize(image, "width"),
    height: getSize(image, "height"),
    class: getAttrib(image, "class"),
    style: normalizeCss2(getAttrib(image, "style")),
    caption: hasCaption(image),
    hspace: getHspace(image),
    vspace: getVspace(image),
    border: getBorder(image),
    borderStyle: getStyle(image, "borderStyle"),
    isDecorative: getIsDecorative(image)
  });
  const updateProp = (image, oldData, newData, name, set2) => {
    if (newData[name] !== oldData[name]) {
      set2(image, name, newData[name]);
    }
  };
  const setAlt = (image, alt, isDecorative) => {
    if (isDecorative) {
      DOM.setAttrib(image, "role", "presentation");
      const sugarImage = SugarElement.fromDom(image);
      set(sugarImage, "alt", "");
    } else {
      if (isNull(alt)) {
        const sugarImage = SugarElement.fromDom(image);
        remove(sugarImage, "alt");
      } else {
        const sugarImage = SugarElement.fromDom(image);
        set(sugarImage, "alt", alt);
      }
      if (DOM.getAttrib(image, "role") === "presentation") {
        DOM.setAttrib(image, "role", "");
      }
    }
  };
  const updateAlt = (image, oldData, newData) => {
    if (newData.alt !== oldData.alt || newData.isDecorative !== oldData.isDecorative) {
      setAlt(image, newData.alt, newData.isDecorative);
    }
  };
  const normalized = (set2, normalizeCss2) => (image, name, value) => {
    set2(image, value);
    normalizeStyle(image, normalizeCss2);
  };
  const write = (normalizeCss2, newData, image) => {
    const oldData = read(normalizeCss2, image);
    updateProp(image, oldData, newData, "caption", (image2, _name, _value) => toggleCaption(image2));
    updateProp(image, oldData, newData, "src", updateAttrib);
    updateProp(image, oldData, newData, "title", updateAttrib);
    updateProp(image, oldData, newData, "width", setSize("width", normalizeCss2));
    updateProp(image, oldData, newData, "height", setSize("height", normalizeCss2));
    updateProp(image, oldData, newData, "class", updateAttrib);
    updateProp(image, oldData, newData, "style", normalized((image2, value) => updateAttrib(image2, "style", value), normalizeCss2));
    updateProp(image, oldData, newData, "hspace", normalized(setHspace, normalizeCss2));
    updateProp(image, oldData, newData, "vspace", normalized(setVspace, normalizeCss2));
    updateProp(image, oldData, newData, "border", normalized(setBorder, normalizeCss2));
    updateProp(image, oldData, newData, "borderStyle", normalized(setBorderStyle, normalizeCss2));
    updateAlt(image, oldData, newData);
  };
  const normalizeCss$1 = (editor, cssText) => {
    const css = editor.dom.styles.parse(cssText);
    const mergedCss = mergeMargins(css);
    const compressed = editor.dom.styles.parse(editor.dom.styles.serialize(mergedCss));
    return editor.dom.styles.serialize(compressed);
  };
  const getSelectedImage = (editor) => {
    const imgElm = editor.selection.getNode();
    const figureElm = editor.dom.getParent(imgElm, "figure.image");
    if (figureElm) {
      return editor.dom.select("img", figureElm)[0];
    }
    if (imgElm && (imgElm.nodeName !== "IMG" || isPlaceholderImage(imgElm))) {
      return null;
    }
    return imgElm;
  };
  const splitTextBlock = (editor, figure) => {
    const dom = editor.dom;
    const textBlockElements = filter(editor.schema.getTextBlockElements(), (_, parentElm) => !editor.schema.isValidChild(parentElm, "figure"));
    const textBlock = dom.getParent(figure.parentNode, (node) => hasNonNullableKey(textBlockElements, node.nodeName), editor.getBody());
    if (textBlock) {
      return dom.split(textBlock, figure);
    } else {
      return figure;
    }
  };
  const readImageDataFromSelection = (editor) => {
    const image = getSelectedImage(editor);
    return image ? read((css) => normalizeCss$1(editor, css), image) : defaultData();
  };
  const insertImageAtCaret = (editor, data) => {
    const elm = create((css) => normalizeCss$1(editor, css), data);
    editor.dom.setAttrib(elm, "data-mce-id", "__mcenew");
    editor.focus();
    editor.selection.setContent(elm.outerHTML);
    const insertedElm = editor.dom.select('*[data-mce-id="__mcenew"]')[0];
    editor.dom.setAttrib(insertedElm, "data-mce-id", null);
    if (isFigure(insertedElm)) {
      const figure = splitTextBlock(editor, insertedElm);
      editor.selection.select(figure);
    } else {
      editor.selection.select(insertedElm);
    }
  };
  const syncSrcAttr = (editor, image) => {
    editor.dom.setAttrib(image, "src", image.getAttribute("src"));
  };
  const deleteImage = (editor, image) => {
    if (image) {
      const elm = editor.dom.is(image.parentNode, "figure.image") ? image.parentNode : image;
      editor.dom.remove(elm);
      editor.focus();
      editor.nodeChanged();
      if (editor.dom.isEmpty(editor.getBody())) {
        editor.setContent("");
        editor.selection.setCursorLocation();
      }
    }
  };
  const writeImageDataToSelection = (editor, data) => {
    const image = getSelectedImage(editor);
    write((css) => normalizeCss$1(editor, css), data, image);
    syncSrcAttr(editor, image);
    if (isFigure(image.parentNode)) {
      const figure = image.parentNode;
      splitTextBlock(editor, figure);
      editor.selection.select(image.parentNode);
    } else {
      editor.selection.select(image);
      waitLoadImage(editor, data, image);
    }
  };
  const sanitizeImageData = (editor, data) => {
    const src = data.src;
    return {
      ...data,
      src: isSafeImageUrl(editor, src) ? src : ""
    };
  };
  const insertOrUpdateImage = (editor, partialData) => {
    const image = getSelectedImage(editor);
    if (image) {
      const selectedImageData = read((css) => normalizeCss$1(editor, css), image);
      const data = {
        ...selectedImageData,
        ...partialData
      };
      const sanitizedData = sanitizeImageData(editor, data);
      if (data.src) {
        writeImageDataToSelection(editor, sanitizedData);
      } else {
        deleteImage(editor, image);
      }
    } else if (partialData.src) {
      insertImageAtCaret(editor, {
        ...defaultData(),
        ...partialData
      });
    }
  };
  const deep = (old, nu) => {
    const bothObjects = isPlainObject(old) && isPlainObject(nu);
    return bothObjects ? deepMerge(old, nu) : nu;
  };
  const baseMerge = (merger) => {
    return (...objects) => {
      if (objects.length === 0) {
        throw new Error(`Can't merge zero objects`);
      }
      const ret = {};
      for (let j = 0; j < objects.length; j++) {
        const curObject = objects[j];
        for (const key in curObject) {
          if (has(curObject, key)) {
            ret[key] = merger(ret[key], curObject[key]);
          }
        }
      }
      return ret;
    };
  };
  const deepMerge = baseMerge(deep);
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.ImageUploader");
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const getValue = (item) => isString(item.value) ? item.value : "";
  const getText = (item) => {
    if (isString(item.text)) {
      return item.text;
    } else if (isString(item.title)) {
      return item.title;
    } else {
      return "";
    }
  };
  const sanitizeList = (list, extractValue) => {
    const out = [];
    global2.each(list, (item) => {
      const text = getText(item);
      if (item.menu !== void 0) {
        const items = sanitizeList(item.menu, extractValue);
        out.push({
          text,
          items
        });
      } else {
        const value = extractValue(item);
        out.push({
          text,
          value
        });
      }
    });
    return out;
  };
  const sanitizer = (extractor = getValue) => (list) => {
    if (list) {
      return Optional.from(list).map((list2) => sanitizeList(list2, extractor));
    } else {
      return Optional.none();
    }
  };
  const sanitize = (list) => sanitizer(getValue)(list);
  const isGroup = (item) => has(item, "items");
  const findEntryDelegate = (list, value) => findMap(list, (item) => {
    if (isGroup(item)) {
      return findEntryDelegate(item.items, value);
    } else if (item.value === value) {
      return Optional.some(item);
    } else {
      return Optional.none();
    }
  });
  const findEntry = (optList, value) => optList.bind((list) => findEntryDelegate(list, value));
  const ListUtils = {
    sanitizer,
    sanitize,
    findEntry
  };
  const makeTab$2 = (_info) => ({
    title: "Advanced",
    name: "advanced",
    items: [{
      type: "grid",
      columns: 2,
      items: [
        {
          type: "input",
          label: "Vertical space",
          name: "vspace",
          inputMode: "numeric"
        },
        {
          type: "input",
          label: "Horizontal space",
          name: "hspace",
          inputMode: "numeric"
        },
        {
          type: "input",
          label: "Border width",
          name: "border",
          inputMode: "numeric"
        },
        {
          type: "listbox",
          name: "borderstyle",
          label: "Border style",
          items: [
            {
              text: "Select...",
              value: ""
            },
            {
              text: "Solid",
              value: "solid"
            },
            {
              text: "Dotted",
              value: "dotted"
            },
            {
              text: "Dashed",
              value: "dashed"
            },
            {
              text: "Double",
              value: "double"
            },
            {
              text: "Groove",
              value: "groove"
            },
            {
              text: "Ridge",
              value: "ridge"
            },
            {
              text: "Inset",
              value: "inset"
            },
            {
              text: "Outset",
              value: "outset"
            },
            {
              text: "None",
              value: "none"
            },
            {
              text: "Hidden",
              value: "hidden"
            }
          ]
        }
      ]
    }]
  });
  const AdvTab = { makeTab: makeTab$2 };
  const collect = (editor) => {
    const urlListSanitizer = ListUtils.sanitizer((item) => editor.convertURL(item.value || item.url, "src"));
    const futureImageList = new Promise((completer) => {
      createImageList(editor, (imageList) => {
        completer(urlListSanitizer(imageList).map((items) => flatten([
          [{
            text: "None",
            value: ""
          }],
          items
        ])));
      });
    });
    const classList = ListUtils.sanitize(getClassList(editor));
    const hasAdvTab$1 = hasAdvTab(editor);
    const hasUploadTab$1 = hasUploadTab(editor);
    const hasUploadUrl$1 = hasUploadUrl(editor);
    const hasUploadHandler$1 = hasUploadHandler(editor);
    const image = readImageDataFromSelection(editor);
    const hasDescription$1 = hasDescription(editor);
    const hasImageTitle$1 = hasImageTitle(editor);
    const hasDimensions$1 = hasDimensions(editor);
    const hasImageCaption$1 = hasImageCaption(editor);
    const hasAccessibilityOptions = showAccessibilityOptions(editor);
    const automaticUploads = isAutomaticUploadsEnabled(editor);
    const prependURL = Optional.some(getPrependUrl(editor)).filter((preUrl) => isString(preUrl) && preUrl.length > 0);
    return futureImageList.then((imageList) => ({
      image,
      imageList,
      classList,
      hasAdvTab: hasAdvTab$1,
      hasUploadTab: hasUploadTab$1,
      hasUploadUrl: hasUploadUrl$1,
      hasUploadHandler: hasUploadHandler$1,
      hasDescription: hasDescription$1,
      hasImageTitle: hasImageTitle$1,
      hasDimensions: hasDimensions$1,
      hasImageCaption: hasImageCaption$1,
      prependURL,
      hasAccessibilityOptions,
      automaticUploads
    }));
  };
  const makeItems = (info) => {
    const imageUrl = {
      name: "src",
      type: "urlinput",
      filetype: "image",
      label: "Source"
    };
    const imageList = info.imageList.map((items) => ({
      name: "images",
      type: "listbox",
      label: "Image list",
      items
    }));
    const imageDescription = {
      name: "alt",
      type: "input",
      label: "Alternative description",
      enabled: !(info.hasAccessibilityOptions && info.image.isDecorative)
    };
    const imageTitle = {
      name: "title",
      type: "input",
      label: "Image title"
    };
    const imageDimensions = {
      name: "dimensions",
      type: "sizeinput"
    };
    const isDecorative = {
      type: "label",
      label: "Accessibility",
      items: [{
        name: "isDecorative",
        type: "checkbox",
        label: "Image is decorative"
      }]
    };
    const classList = info.classList.map((items) => ({
      name: "classes",
      type: "listbox",
      label: "Class",
      items
    }));
    const caption = {
      type: "label",
      label: "Caption",
      items: [{
        type: "checkbox",
        name: "caption",
        label: "Show caption"
      }]
    };
    const getDialogContainerType = (useColumns) => useColumns ? {
      type: "grid",
      columns: 2
    } : { type: "panel" };
    return flatten([
      [imageUrl],
      imageList.toArray(),
      info.hasAccessibilityOptions && info.hasDescription ? [isDecorative] : [],
      info.hasDescription ? [imageDescription] : [],
      info.hasImageTitle ? [imageTitle] : [],
      info.hasDimensions ? [imageDimensions] : [],
      [{
        ...getDialogContainerType(info.classList.isSome() && info.hasImageCaption),
        items: flatten([
          classList.toArray(),
          info.hasImageCaption ? [caption] : []
        ])
      }]
    ]);
  };
  const makeTab$1 = (info) => ({
    title: "General",
    name: "general",
    items: makeItems(info)
  });
  const MainTab = {
    makeTab: makeTab$1,
    makeItems
  };
  const makeTab = (_info) => {
    const items = [{
      type: "dropzone",
      name: "fileinput"
    }];
    return {
      title: "Upload",
      name: "upload",
      items
    };
  };
  const UploadTab = { makeTab };
  const createState2 = (info) => ({
    prevImage: ListUtils.findEntry(info.imageList, info.image.src),
    prevAlt: info.image.alt,
    open: true
  });
  const fromImageData = (image) => ({
    src: {
      value: image.src,
      meta: {}
    },
    images: image.src,
    alt: image.alt,
    title: image.title,
    dimensions: {
      width: image.width,
      height: image.height
    },
    classes: image.class,
    caption: image.caption,
    style: image.style,
    vspace: image.vspace,
    border: image.border,
    hspace: image.hspace,
    borderstyle: image.borderStyle,
    fileinput: [],
    isDecorative: image.isDecorative
  });
  const toImageData = (data, removeEmptyAlt) => ({
    src: data.src.value,
    alt: data.alt.length === 0 && removeEmptyAlt ? null : data.alt,
    title: data.title,
    width: data.dimensions.width,
    height: data.dimensions.height,
    class: data.classes,
    style: data.style,
    caption: data.caption,
    hspace: data.hspace,
    vspace: data.vspace,
    border: data.border,
    borderStyle: data.borderstyle,
    isDecorative: data.isDecorative
  });
  const addPrependUrl2 = (info, srcURL) => {
    if (!/^(?:[a-zA-Z]+:)?\/\//.test(srcURL)) {
      return info.prependURL.bind((prependUrl) => {
        if (srcURL.substring(0, prependUrl.length) !== prependUrl) {
          return Optional.some(prependUrl + srcURL);
        }
        return Optional.none();
      });
    }
    return Optional.none();
  };
  const addPrependUrl = (info, api) => {
    const data = api.getData();
    addPrependUrl2(info, data.src.value).each((srcURL) => {
      api.setData({
        src: {
          value: srcURL,
          meta: data.src.meta
        }
      });
    });
  };
  const formFillFromMeta2 = (info, data, meta) => {
    if (info.hasDescription && isString(meta.alt)) {
      data.alt = meta.alt;
    }
    if (info.hasAccessibilityOptions) {
      data.isDecorative = meta.isDecorative || data.isDecorative || false;
    }
    if (info.hasImageTitle && isString(meta.title)) {
      data.title = meta.title;
    }
    if (info.hasDimensions) {
      if (isString(meta.width)) {
        data.dimensions.width = meta.width;
      }
      if (isString(meta.height)) {
        data.dimensions.height = meta.height;
      }
    }
    if (isString(meta.class)) {
      ListUtils.findEntry(info.classList, meta.class).each((entry) => {
        data.classes = entry.value;
      });
    }
    if (info.hasImageCaption) {
      if (isBoolean(meta.caption)) {
        data.caption = meta.caption;
      }
    }
    if (info.hasAdvTab) {
      if (isString(meta.style)) {
        data.style = meta.style;
      }
      if (isString(meta.vspace)) {
        data.vspace = meta.vspace;
      }
      if (isString(meta.border)) {
        data.border = meta.border;
      }
      if (isString(meta.hspace)) {
        data.hspace = meta.hspace;
      }
      if (isString(meta.borderstyle)) {
        data.borderstyle = meta.borderstyle;
      }
    }
  };
  const formFillFromMeta = (info, api) => {
    const data = api.getData();
    const meta = data.src.meta;
    if (meta !== void 0) {
      const newData = deepMerge({}, data);
      formFillFromMeta2(info, newData, meta);
      api.setData(newData);
    }
  };
  const calculateImageSize = (helpers, info, state, api) => {
    const data = api.getData();
    const url = data.src.value;
    const meta = data.src.meta || {};
    if (!meta.width && !meta.height && info.hasDimensions) {
      if (isNotEmpty(url)) {
        helpers.imageSize(url).then((size) => {
          if (state.open) {
            api.setData({ dimensions: size });
          }
        }).catch((e) => console.error(e));
      } else {
        api.setData({
          dimensions: {
            width: "",
            height: ""
          }
        });
      }
    }
  };
  const updateImagesDropdown = (info, state, api) => {
    const data = api.getData();
    const image = ListUtils.findEntry(info.imageList, data.src.value);
    state.prevImage = image;
    api.setData({ images: image.map((entry) => entry.value).getOr("") });
  };
  const changeSrc = (helpers, info, state, api) => {
    addPrependUrl(info, api);
    formFillFromMeta(info, api);
    calculateImageSize(helpers, info, state, api);
    updateImagesDropdown(info, state, api);
  };
  const changeImages = (helpers, info, state, api) => {
    const data = api.getData();
    const image = ListUtils.findEntry(info.imageList, data.images);
    image.each((img) => {
      const updateAlt2 = data.alt === "" || state.prevImage.map((image2) => image2.text === data.alt).getOr(false);
      if (updateAlt2) {
        if (img.value === "") {
          api.setData({
            src: img,
            alt: state.prevAlt
          });
        } else {
          api.setData({
            src: img,
            alt: img.text
          });
        }
      } else {
        api.setData({ src: img });
      }
    });
    state.prevImage = image;
    changeSrc(helpers, info, state, api);
  };
  const changeFileInput = (helpers, info, state, api) => {
    const data = api.getData();
    api.block("Uploading image");
    head(data.fileinput).fold(() => {
      api.unblock();
    }, (file) => {
      const blobUri = URL.createObjectURL(file);
      const finalize = () => {
        api.unblock();
        URL.revokeObjectURL(blobUri);
      };
      const updateSrcAndSwitchTab = (url) => {
        api.setData({
          src: {
            value: url,
            meta: {}
          }
        });
        api.showTab("general");
        changeSrc(helpers, info, state, api);
      };
      blobToDataUri(file).then((dataUrl) => {
        const blobInfo = helpers.createBlobCache(file, blobUri, dataUrl);
        if (info.automaticUploads) {
          helpers.uploadImage(blobInfo).then((result) => {
            updateSrcAndSwitchTab(result.url);
            finalize();
          }).catch((err) => {
            finalize();
            helpers.alertErr(err);
          });
        } else {
          helpers.addToBlobCache(blobInfo);
          updateSrcAndSwitchTab(blobInfo.blobUri());
          api.unblock();
        }
      });
    });
  };
  const changeHandler = (helpers, info, state) => (api, evt) => {
    if (evt.name === "src") {
      changeSrc(helpers, info, state, api);
    } else if (evt.name === "images") {
      changeImages(helpers, info, state, api);
    } else if (evt.name === "alt") {
      state.prevAlt = api.getData().alt;
    } else if (evt.name === "fileinput") {
      changeFileInput(helpers, info, state, api);
    } else if (evt.name === "isDecorative") {
      api.setEnabled("alt", !api.getData().isDecorative);
    }
  };
  const closeHandler = (state) => () => {
    state.open = false;
  };
  const makeDialogBody = (info) => {
    if (info.hasAdvTab || info.hasUploadUrl || info.hasUploadHandler) {
      const tabPanel = {
        type: "tabpanel",
        tabs: flatten([
          [MainTab.makeTab(info)],
          info.hasAdvTab ? [AdvTab.makeTab(info)] : [],
          info.hasUploadTab && (info.hasUploadUrl || info.hasUploadHandler) ? [UploadTab.makeTab(info)] : []
        ])
      };
      return tabPanel;
    } else {
      const panel = {
        type: "panel",
        items: MainTab.makeItems(info)
      };
      return panel;
    }
  };
  const submitHandler = (editor, info, helpers) => (api) => {
    const data = deepMerge(fromImageData(info.image), api.getData());
    const finalData = {
      ...data,
      style: getStyleValue(helpers.normalizeCss, toImageData(data, false))
    };
    editor.execCommand("mceUpdateImage", false, toImageData(finalData, info.hasAccessibilityOptions));
    editor.editorUpload.uploadImagesAuto();
    api.close();
  };
  const imageSize = (editor) => (url) => {
    if (!isSafeImageUrl(editor, url)) {
      return Promise.resolve({
        width: "",
        height: ""
      });
    } else {
      return getImageSize(editor.documentBaseURI.toAbsolute(url)).then((dimensions) => ({
        width: String(dimensions.width),
        height: String(dimensions.height)
      }));
    }
  };
  const createBlobCache = (editor) => (file, blobUri, dataUrl) => editor.editorUpload.blobCache.create({
    blob: file,
    blobUri,
    name: file.name ? file.name.replace(/\.[^\.]+$/, "") : null,
    filename: file.name,
    base64: dataUrl.split(",")[1]
  });
  const addToBlobCache = (editor) => (blobInfo) => {
    editor.editorUpload.blobCache.add(blobInfo);
  };
  const alertErr = (editor) => (message) => {
    editor.windowManager.alert(message);
  };
  const normalizeCss = (editor) => (cssText) => normalizeCss$1(editor, cssText);
  const parseStyle = (editor) => (cssText) => editor.dom.parseStyle(cssText);
  const serializeStyle = (editor) => (stylesArg, name) => editor.dom.serializeStyle(stylesArg, name);
  const uploadImage = (editor) => (blobInfo) => global$1(editor).upload([blobInfo], false).then((results) => {
    if (results.length === 0) {
      return Promise.reject("Failed to upload image");
    } else if (results[0].status === false) {
      return Promise.reject(results[0].error.message);
    } else {
      return results[0];
    }
  });
  const Dialog = (editor) => {
    const helpers = {
      imageSize: imageSize(editor),
      addToBlobCache: addToBlobCache(editor),
      createBlobCache: createBlobCache(editor),
      alertErr: alertErr(editor),
      normalizeCss: normalizeCss(editor),
      parseStyle: parseStyle(editor),
      serializeStyle: serializeStyle(editor),
      uploadImage: uploadImage(editor)
    };
    const open = () => {
      collect(editor).then((info) => {
        const state = createState2(info);
        return {
          title: "Insert/Edit Image",
          size: "normal",
          body: makeDialogBody(info),
          buttons: [
            {
              type: "cancel",
              name: "cancel",
              text: "Cancel"
            },
            {
              type: "submit",
              name: "save",
              text: "Save",
              primary: true
            }
          ],
          initialData: fromImageData(info.image),
          onSubmit: submitHandler(editor, info, helpers),
          onChange: changeHandler(helpers, info, state),
          onClose: closeHandler(state)
        };
      }).then(editor.windowManager.open);
    };
    return { open };
  };
  const register$1 = (editor) => {
    editor.addCommand("mceImage", Dialog(editor).open);
    editor.addCommand("mceUpdateImage", (_ui, data) => {
      editor.undoManager.transact(() => insertOrUpdateImage(editor, data));
    });
  };
  const hasImageClass = (node) => {
    const className = node.attr("class");
    return className && /\bimage\b/.test(className);
  };
  const toggleContentEditableState = (state) => (nodes) => {
    let i = nodes.length;
    const toggleContentEditable = (node) => {
      node.attr("contenteditable", state ? "true" : null);
    };
    while (i--) {
      const node = nodes[i];
      if (hasImageClass(node)) {
        node.attr("contenteditable", state ? "false" : null);
        global2.each(node.getAll("figcaption"), toggleContentEditable);
      }
    }
  };
  const setup = (editor) => {
    editor.on("PreInit", () => {
      editor.parser.addNodeFilter("figure", toggleContentEditableState(true));
      editor.serializer.addNodeFilter("figure", toggleContentEditableState(false));
    });
  };
  const register = (editor) => {
    editor.ui.registry.addToggleButton("image", {
      icon: "image",
      tooltip: "Insert/edit image",
      onAction: Dialog(editor).open,
      onSetup: (buttonApi) => {
        buttonApi.setActive(isNonNullable(getSelectedImage(editor)));
        return editor.selection.selectorChangedWithUnbind("img:not([data-mce-object]):not([data-mce-placeholder]),figure.image", buttonApi.setActive).unbind;
      }
    });
    editor.ui.registry.addMenuItem("image", {
      icon: "image",
      text: "Image...",
      onAction: Dialog(editor).open
    });
    editor.ui.registry.addContextMenu("image", { update: (element) => isFigure(element) || isImage(element) && !isPlaceholderImage(element) ? ["image"] : [] });
  };
  var Plugin = () => {
    global$4.add("image", (editor) => {
      register$2(editor);
      setup(editor);
      register(editor);
      register$1(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$6 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const isString = isType("string");
  const isObject = isType("object");
  const isArray = isType("array");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativePush = Array.prototype.push;
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const Cell = (initial) => {
    let value = initial;
    const get2 = () => {
      return value;
    };
    const set = (v) => {
      value = v;
    };
    return {
      get: get2,
      set
    };
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const get$1 = (obj, key) => {
    return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("audio_template_callback", { processor: "function" });
    registerOption("video_template_callback", { processor: "function" });
    registerOption("iframe_template_callback", { processor: "function" });
    registerOption("media_live_embeds", {
      processor: "boolean",
      default: true
    });
    registerOption("media_filter_html", {
      processor: "boolean",
      default: true
    });
    registerOption("media_url_resolver", { processor: "function" });
    registerOption("media_alt_source", {
      processor: "boolean",
      default: true
    });
    registerOption("media_poster", {
      processor: "boolean",
      default: true
    });
    registerOption("media_dimensions", {
      processor: "boolean",
      default: true
    });
  };
  const getAudioTemplateCallback = option("audio_template_callback");
  const getVideoTemplateCallback = option("video_template_callback");
  const getIframeTemplateCallback = option("iframe_template_callback");
  const hasLiveEmbeds = option("media_live_embeds");
  const shouldFilterHtml = option("media_filter_html");
  const getUrlResolver = option("media_url_resolver");
  const hasAltSource = option("media_alt_source");
  const hasPoster = option("media_poster");
  const hasDimensions = option("media_dimensions");
  var global$5 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  var global$4 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");
  var global$3 = tinymce.util.Tools.resolve("tinymce.html.DomParser");
  const DOM$1 = global$4.DOM;
  const trimPx = (value) => value.replace(/px$/, "");
  const getEphoxEmbedData = (node) => {
    const style = node.attr("style");
    const styles = style ? DOM$1.parseStyle(style) : {};
    return {
      type: "ephox-embed-iri",
      source: node.attr("data-ephox-embed-iri"),
      altsource: "",
      poster: "",
      width: get$1(styles, "max-width").map(trimPx).getOr(""),
      height: get$1(styles, "max-height").map(trimPx).getOr("")
    };
  };
  const htmlToData = (html, schema) => {
    let data = {};
    const parser = global$3({
      validate: false,
      forced_root_block: false
    }, schema);
    const rootNode = parser.parse(html);
    for (let node = rootNode; node; node = node.walk()) {
      if (node.type === 1) {
        const name = node.name;
        if (node.attr("data-ephox-embed-iri")) {
          data = getEphoxEmbedData(node);
          break;
        } else {
          if (!data.source && name === "param") {
            data.source = node.attr("movie");
          }
          if (name === "iframe" || name === "object" || name === "embed" || name === "video" || name === "audio") {
            if (!data.type) {
              data.type = name;
            }
            data = global$5.extend(node.attributes.map, data);
          }
          if (name === "script") {
            data = {
              type: "script",
              source: node.attr("src")
            };
          }
          if (name === "source") {
            if (!data.source) {
              data.source = node.attr("src");
            } else if (!data.altsource) {
              data.altsource = node.attr("src");
            }
          }
          if (name === "img" && !data.poster) {
            data.poster = node.attr("src");
          }
        }
      }
    }
    data.source = data.source || data.src || data.data;
    data.altsource = data.altsource || "";
    data.poster = data.poster || "";
    return data;
  };
  const guess = (url) => {
    const mimes = {
      mp3: "audio/mpeg",
      m4a: "audio/x-m4a",
      wav: "audio/wav",
      mp4: "video/mp4",
      webm: "video/webm",
      ogg: "video/ogg",
      swf: "application/x-shockwave-flash"
    };
    const fileEnd = url.toLowerCase().split(".").pop();
    const mime = mimes[fileEnd];
    return mime ? mime : "";
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.html.Node");
  var global$1 = tinymce.util.Tools.resolve("tinymce.html.Serializer");
  const Parser = (schema, settings = {}) => global$3({
    forced_root_block: false,
    validate: false,
    allow_conditional_comments: true,
    ...settings
  }, schema);
  const DOM = global$4.DOM;
  const addPx = (value) => /^[0-9.]+$/.test(value) ? value + "px" : value;
  const updateEphoxEmbed = (data, node) => {
    const style = node.attr("style");
    const styleMap = style ? DOM.parseStyle(style) : {};
    styleMap["max-width"] = addPx(data.width);
    styleMap["max-height"] = addPx(data.height);
    node.attr("style", DOM.serializeStyle(styleMap));
  };
  const sources = [
    "source",
    "altsource"
  ];
  const updateHtml = (html, data, updateAll, schema) => {
    let numSources = 0;
    let sourceCount = 0;
    const parser = Parser(schema);
    parser.addNodeFilter("source", (nodes) => numSources = nodes.length);
    const rootNode = parser.parse(html);
    for (let node = rootNode; node; node = node.walk()) {
      if (node.type === 1) {
        const name = node.name;
        if (node.attr("data-ephox-embed-iri")) {
          updateEphoxEmbed(data, node);
          break;
        } else {
          switch (name) {
            case "video":
            case "object":
            case "embed":
            case "img":
            case "iframe":
              if (data.height !== void 0 && data.width !== void 0) {
                node.attr("width", data.width);
                node.attr("height", data.height);
              }
              break;
          }
          if (updateAll) {
            switch (name) {
              case "video":
                node.attr("poster", data.poster);
                node.attr("src", null);
                for (let index2 = numSources; index2 < 2; index2++) {
                  if (data[sources[index2]]) {
                    const source = new global$2("source", 1);
                    source.attr("src", data[sources[index2]]);
                    source.attr("type", data[sources[index2] + "mime"] || null);
                    node.append(source);
                  }
                }
                break;
              case "iframe":
                node.attr("src", data.source);
                break;
              case "object":
                const hasImage = node.getAll("img").length > 0;
                if (data.poster && !hasImage) {
                  node.attr("src", data.poster);
                  const img = new global$2("img", 1);
                  img.attr("src", data.poster);
                  img.attr("width", data.width);
                  img.attr("height", data.height);
                  node.append(img);
                }
                break;
              case "source":
                if (sourceCount < 2) {
                  node.attr("src", data[sources[sourceCount]]);
                  node.attr("type", data[sources[sourceCount] + "mime"] || null);
                  if (!data[sources[sourceCount]]) {
                    node.remove();
                    continue;
                  }
                }
                sourceCount++;
                break;
              case "img":
                if (!data.poster) {
                  node.remove();
                }
                break;
            }
          }
        }
      }
    }
    return global$1({}, schema).serialize(rootNode);
  };
  const urlPatterns = [
    {
      regex: /youtu\.be\/([\w\-_\?&=.]+)/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$1",
      allowFullscreen: true
    },
    {
      regex: /youtube\.com(.+)v=([^&]+)(&([a-z0-9&=\-_]+))?/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$2?$4",
      allowFullscreen: true
    },
    {
      regex: /youtube.com\/embed\/([a-z0-9\?&=\-_]+)/i,
      type: "iframe",
      w: 560,
      h: 314,
      url: "www.youtube.com/embed/$1",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/([0-9]+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",
      allowFullscreen: true
    },
    {
      regex: /vimeo\.com\/(.*)\/([0-9]+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: "player.vimeo.com/video/$2?title=0&amp;byline=0",
      allowFullscreen: true
    },
    {
      regex: /maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,
      type: "iframe",
      w: 425,
      h: 350,
      url: 'maps.google.com/maps/ms?msid=$2&output=embed"',
      allowFullscreen: false
    },
    {
      regex: /dailymotion\.com\/video\/([^_]+)/,
      type: "iframe",
      w: 480,
      h: 270,
      url: "www.dailymotion.com/embed/video/$1",
      allowFullscreen: true
    },
    {
      regex: /dai\.ly\/([^_]+)/,
      type: "iframe",
      w: 480,
      h: 270,
      url: "www.dailymotion.com/embed/video/$1",
      allowFullscreen: true
    }
  ];
  const getProtocol = (url) => {
    const protocolMatches = url.match(/^(https?:\/\/|www\.)(.+)$/i);
    if (protocolMatches && protocolMatches.length > 1) {
      return protocolMatches[1] === "www." ? "https://" : protocolMatches[1];
    } else {
      return "https://";
    }
  };
  const getUrl = (pattern, url) => {
    const protocol = getProtocol(url);
    const match = pattern.regex.exec(url);
    let newUrl = protocol + pattern.url;
    for (let i = 0; i < match.length; i++) {
      newUrl = newUrl.replace("$" + i, () => match[i] ? match[i] : "");
    }
    return newUrl.replace(/\?$/, "");
  };
  const matchPattern = (url) => {
    const patterns = urlPatterns.filter((pattern) => pattern.regex.test(url));
    if (patterns.length > 0) {
      return global$5.extend({}, patterns[0], { url: getUrl(patterns[0], url) });
    } else {
      return null;
    }
  };
  const getIframeHtml = (data, iframeTemplateCallback) => {
    if (iframeTemplateCallback) {
      return iframeTemplateCallback(data);
    } else {
      const allowFullscreen = data.allowfullscreen ? ' allowFullscreen="1"' : "";
      return '<iframe src="' + data.source + '" width="' + data.width + '" height="' + data.height + '"' + allowFullscreen + "></iframe>";
    }
  };
  const getFlashHtml = (data) => {
    let html = '<object data="' + data.source + '" width="' + data.width + '" height="' + data.height + '" type="application/x-shockwave-flash">';
    if (data.poster) {
      html += '<img src="' + data.poster + '" width="' + data.width + '" height="' + data.height + '" />';
    }
    html += "</object>";
    return html;
  };
  const getAudioHtml = (data, audioTemplateCallback) => {
    if (audioTemplateCallback) {
      return audioTemplateCallback(data);
    } else {
      return '<audio controls="controls" src="' + data.source + '">' + (data.altsource ? '\n<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : "") + " />\n" : "") + "</audio>";
    }
  };
  const getVideoHtml = (data, videoTemplateCallback) => {
    if (videoTemplateCallback) {
      return videoTemplateCallback(data);
    } else {
      return '<video width="' + data.width + '" height="' + data.height + '"' + (data.poster ? ' poster="' + data.poster + '"' : "") + ' controls="controls">\n<source src="' + data.source + '"' + (data.sourcemime ? ' type="' + data.sourcemime + '"' : "") + " />\n" + (data.altsource ? '<source src="' + data.altsource + '"' + (data.altsourcemime ? ' type="' + data.altsourcemime + '"' : "") + " />\n" : "") + "</video>";
    }
  };
  const getScriptHtml = (data) => {
    return '<script src="' + data.source + '"><\/script>';
  };
  const dataToHtml = (editor, dataIn) => {
    const data = global$5.extend({}, dataIn);
    if (!data.source) {
      global$5.extend(data, htmlToData(data.embed, editor.schema));
      if (!data.source) {
        return "";
      }
    }
    if (!data.altsource) {
      data.altsource = "";
    }
    if (!data.poster) {
      data.poster = "";
    }
    data.source = editor.convertURL(data.source, "source");
    data.altsource = editor.convertURL(data.altsource, "source");
    data.sourcemime = guess(data.source);
    data.altsourcemime = guess(data.altsource);
    data.poster = editor.convertURL(data.poster, "poster");
    const pattern = matchPattern(data.source);
    if (pattern) {
      data.source = pattern.url;
      data.type = pattern.type;
      data.allowfullscreen = pattern.allowFullscreen;
      data.width = data.width || String(pattern.w);
      data.height = data.height || String(pattern.h);
    }
    if (data.embed) {
      return updateHtml(data.embed, data, true, editor.schema);
    } else {
      const audioTemplateCallback = getAudioTemplateCallback(editor);
      const videoTemplateCallback = getVideoTemplateCallback(editor);
      const iframeTemplateCallback = getIframeTemplateCallback(editor);
      data.width = data.width || "300";
      data.height = data.height || "150";
      global$5.each(data, (value, key) => {
        data[key] = editor.dom.encode("" + value);
      });
      if (data.type === "iframe") {
        return getIframeHtml(data, iframeTemplateCallback);
      } else if (data.sourcemime === "application/x-shockwave-flash") {
        return getFlashHtml(data);
      } else if (data.sourcemime.indexOf("audio") !== -1) {
        return getAudioHtml(data, audioTemplateCallback);
      } else if (data.type === "script") {
        return getScriptHtml(data);
      } else {
        return getVideoHtml(data, videoTemplateCallback);
      }
    }
  };
  const isMediaElement = (element) => element.hasAttribute("data-mce-object") || element.hasAttribute("data-ephox-embed-iri");
  const setup$2 = (editor) => {
    editor.on("click keyup touchend", () => {
      const selectedNode = editor.selection.getNode();
      if (selectedNode && editor.dom.hasClass(selectedNode, "mce-preview-object")) {
        if (editor.dom.getAttrib(selectedNode, "data-mce-selected")) {
          selectedNode.setAttribute("data-mce-selected", "2");
        }
      }
    });
    editor.on("ObjectSelected", (e) => {
      const objectType = e.target.getAttribute("data-mce-object");
      if (objectType === "script") {
        e.preventDefault();
      }
    });
    editor.on("ObjectResized", (e) => {
      const target = e.target;
      if (target.getAttribute("data-mce-object")) {
        let html = target.getAttribute("data-mce-html");
        if (html) {
          html = unescape(html);
          target.setAttribute("data-mce-html", escape(updateHtml(html, {
            width: String(e.width),
            height: String(e.height)
          }, false, editor.schema)));
        }
      }
    });
  };
  const cache = {};
  const embedPromise = (data, dataToHtml2, handler) => {
    return new Promise((res, rej) => {
      const wrappedResolve = (response) => {
        if (response.html) {
          cache[data.source] = response;
        }
        return res({
          url: data.source,
          html: response.html ? response.html : dataToHtml2(data)
        });
      };
      if (cache[data.source]) {
        wrappedResolve(cache[data.source]);
      } else {
        handler({ url: data.source }, wrappedResolve, rej);
      }
    });
  };
  const defaultPromise = (data, dataToHtml2) => Promise.resolve({
    html: dataToHtml2(data),
    url: data.source
  });
  const loadedData = (editor) => (data) => dataToHtml(editor, data);
  const getEmbedHtml = (editor, data) => {
    const embedHandler = getUrlResolver(editor);
    return embedHandler ? embedPromise(data, loadedData(editor), embedHandler) : defaultPromise(data, loadedData(editor));
  };
  const isCached = (url) => has(cache, url);
  const extractMeta = (sourceInput, data) => get$1(data, sourceInput).bind((mainData) => get$1(mainData, "meta"));
  const getValue = (data, metaData, sourceInput) => (prop) => {
    const getFromData = () => get$1(data, prop);
    const getFromMetaData = () => get$1(metaData, prop);
    const getNonEmptyValue = (c) => get$1(c, "value").bind((v) => v.length > 0 ? Optional.some(v) : Optional.none());
    const getFromValueFirst = () => getFromData().bind((child) => isObject(child) ? getNonEmptyValue(child).orThunk(getFromMetaData) : getFromMetaData().orThunk(() => Optional.from(child)));
    const getFromMetaFirst = () => getFromMetaData().orThunk(() => getFromData().bind((child) => isObject(child) ? getNonEmptyValue(child) : Optional.from(child)));
    return { [prop]: (prop === sourceInput ? getFromValueFirst() : getFromMetaFirst()).getOr("") };
  };
  const getDimensions = (data, metaData) => {
    const dimensions = {};
    get$1(data, "dimensions").each((dims) => {
      each$1([
        "width",
        "height"
      ], (prop) => {
        get$1(metaData, prop).orThunk(() => get$1(dims, prop)).each((value) => dimensions[prop] = value);
      });
    });
    return dimensions;
  };
  const unwrap = (data, sourceInput) => {
    const metaData = sourceInput ? extractMeta(sourceInput, data).getOr({}) : {};
    const get2 = getValue(data, metaData, sourceInput);
    return {
      ...get2("source"),
      ...get2("altsource"),
      ...get2("poster"),
      ...get2("embed"),
      ...getDimensions(data, metaData)
    };
  };
  const wrap = (data) => {
    const wrapped = {
      ...data,
      source: { value: get$1(data, "source").getOr("") },
      altsource: { value: get$1(data, "altsource").getOr("") },
      poster: { value: get$1(data, "poster").getOr("") }
    };
    each$1([
      "width",
      "height"
    ], (prop) => {
      get$1(data, prop).each((value) => {
        const dimensions = wrapped.dimensions || {};
        dimensions[prop] = value;
        wrapped.dimensions = dimensions;
      });
    });
    return wrapped;
  };
  const handleError = (editor) => (error) => {
    const errorMessage = error && error.msg ? "Media embed handler error: " + error.msg : "Media embed handler threw unknown error.";
    editor.notificationManager.open({
      type: "error",
      text: errorMessage
    });
  };
  const getEditorData = (editor) => {
    const element = editor.selection.getNode();
    const snippet = isMediaElement(element) ? editor.serializer.serialize(element, { selection: true }) : "";
    return {
      embed: snippet,
      ...htmlToData(snippet, editor.schema)
    };
  };
  const addEmbedHtml = (api, editor) => (response) => {
    if (isString(response.url) && response.url.trim().length > 0) {
      const html = response.html;
      const snippetData = htmlToData(html, editor.schema);
      const nuData = {
        ...snippetData,
        source: response.url,
        embed: html
      };
      api.setData(wrap(nuData));
    }
  };
  const selectPlaceholder = (editor, beforeObjects) => {
    const afterObjects = editor.dom.select("*[data-mce-object]");
    for (let i = 0; i < beforeObjects.length; i++) {
      for (let y = afterObjects.length - 1; y >= 0; y--) {
        if (beforeObjects[i] === afterObjects[y]) {
          afterObjects.splice(y, 1);
        }
      }
    }
    editor.selection.select(afterObjects[0]);
  };
  const handleInsert = (editor, html) => {
    const beforeObjects = editor.dom.select("*[data-mce-object]");
    editor.insertContent(html);
    selectPlaceholder(editor, beforeObjects);
    editor.nodeChanged();
  };
  const submitForm = (prevData, newData, editor) => {
    newData.embed = updateHtml(newData.embed, newData, false, editor.schema);
    if (newData.embed && (prevData.source === newData.source || isCached(newData.source))) {
      handleInsert(editor, newData.embed);
    } else {
      getEmbedHtml(editor, newData).then((response) => {
        handleInsert(editor, response.html);
      }).catch(handleError(editor));
    }
  };
  const showDialog = (editor) => {
    const editorData = getEditorData(editor);
    const currentData = Cell(editorData);
    const initialData = wrap(editorData);
    const handleSource = (prevData, api) => {
      const serviceData = unwrap(api.getData(), "source");
      if (prevData.source !== serviceData.source) {
        addEmbedHtml(win, editor)({
          url: serviceData.source,
          html: ""
        });
        getEmbedHtml(editor, serviceData).then(addEmbedHtml(win, editor)).catch(handleError(editor));
      }
    };
    const handleEmbed = (api) => {
      const data = unwrap(api.getData());
      const dataFromEmbed = htmlToData(data.embed, editor.schema);
      api.setData(wrap(dataFromEmbed));
    };
    const handleUpdate = (api, sourceInput) => {
      const data = unwrap(api.getData(), sourceInput);
      const embed = dataToHtml(editor, data);
      api.setData(wrap({
        ...data,
        embed
      }));
    };
    const mediaInput = [{
      name: "source",
      type: "urlinput",
      filetype: "media",
      label: "Source"
    }];
    const sizeInput = !hasDimensions(editor) ? [] : [{
      type: "sizeinput",
      name: "dimensions",
      label: "Constrain proportions",
      constrain: true
    }];
    const generalTab = {
      title: "General",
      name: "general",
      items: flatten([
        mediaInput,
        sizeInput
      ])
    };
    const embedTextarea = {
      type: "textarea",
      name: "embed",
      label: "Paste your embed code below:"
    };
    const embedTab = {
      title: "Embed",
      items: [embedTextarea]
    };
    const advancedFormItems = [];
    if (hasAltSource(editor)) {
      advancedFormItems.push({
        name: "altsource",
        type: "urlinput",
        filetype: "media",
        label: "Alternative source URL"
      });
    }
    if (hasPoster(editor)) {
      advancedFormItems.push({
        name: "poster",
        type: "urlinput",
        filetype: "image",
        label: "Media poster (Image URL)"
      });
    }
    const advancedTab = {
      title: "Advanced",
      name: "advanced",
      items: advancedFormItems
    };
    const tabs = [
      generalTab,
      embedTab
    ];
    if (advancedFormItems.length > 0) {
      tabs.push(advancedTab);
    }
    const body = {
      type: "tabpanel",
      tabs
    };
    const win = editor.windowManager.open({
      title: "Insert/Edit Media",
      size: "normal",
      body,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      onSubmit: (api) => {
        const serviceData = unwrap(api.getData());
        submitForm(currentData.get(), serviceData, editor);
        api.close();
      },
      onChange: (api, detail) => {
        switch (detail.name) {
          case "source":
            handleSource(currentData.get(), api);
            break;
          case "embed":
            handleEmbed(api);
            break;
          case "dimensions":
          case "altsource":
          case "poster":
            handleUpdate(api, detail.name);
            break;
        }
        currentData.set(unwrap(api.getData()));
      },
      initialData
    });
  };
  const get = (editor) => {
    const showDialog$1 = () => {
      showDialog(editor);
    };
    return { showDialog: showDialog$1 };
  };
  const register$1 = (editor) => {
    const showDialog$1 = () => {
      showDialog(editor);
    };
    editor.addCommand("mceMedia", showDialog$1);
  };
  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.Env");
  const isLiveEmbedNode = (node) => {
    const name = node.name;
    return name === "iframe" || name === "video" || name === "audio";
  };
  const getDimension = (node, styles, dimension, defaultValue = null) => {
    const value = node.attr(dimension);
    if (isNonNullable(value)) {
      return value;
    } else if (!has(styles, dimension)) {
      return defaultValue;
    } else {
      return null;
    }
  };
  const setDimensions = (node, previewNode, styles) => {
    const useDefaults = previewNode.name === "img" || node.name === "video";
    const defaultWidth = useDefaults ? "300" : null;
    const fallbackHeight = node.name === "audio" ? "30" : "150";
    const defaultHeight = useDefaults ? fallbackHeight : null;
    previewNode.attr({
      width: getDimension(node, styles, "width", defaultWidth),
      height: getDimension(node, styles, "height", defaultHeight)
    });
  };
  const appendNodeContent = (editor, nodeName, previewNode, html) => {
    const newNode = Parser(editor.schema).parse(html, { context: nodeName });
    while (newNode.firstChild) {
      previewNode.append(newNode.firstChild);
    }
  };
  const createPlaceholderNode = (editor, node) => {
    const name = node.name;
    const placeHolder = new global$2("img", 1);
    retainAttributesAndInnerHtml(editor, node, placeHolder);
    setDimensions(node, placeHolder, {});
    placeHolder.attr({
      "style": node.attr("style"),
      "src": global2.transparentSrc,
      "data-mce-object": name,
      "class": "mce-object mce-object-" + name
    });
    return placeHolder;
  };
  const createPreviewNode = (editor, node) => {
    const name = node.name;
    const previewWrapper = new global$2("span", 1);
    previewWrapper.attr({
      "contentEditable": "false",
      "style": node.attr("style"),
      "data-mce-object": name,
      "class": "mce-preview-object mce-object-" + name
    });
    retainAttributesAndInnerHtml(editor, node, previewWrapper);
    const styles = editor.dom.parseStyle(node.attr("style"));
    const previewNode = new global$2(name, 1);
    setDimensions(node, previewNode, styles);
    previewNode.attr({
      src: node.attr("src"),
      style: node.attr("style"),
      class: node.attr("class")
    });
    if (name === "iframe") {
      previewNode.attr({
        allowfullscreen: node.attr("allowfullscreen"),
        frameborder: "0"
      });
    } else {
      const attrs = [
        "controls",
        "crossorigin",
        "currentTime",
        "loop",
        "muted",
        "poster",
        "preload"
      ];
      each$1(attrs, (attrName) => {
        previewNode.attr(attrName, node.attr(attrName));
      });
      const sanitizedHtml = previewWrapper.attr("data-mce-html");
      if (isNonNullable(sanitizedHtml)) {
        appendNodeContent(editor, name, previewNode, unescape(sanitizedHtml));
      }
    }
    const shimNode = new global$2("span", 1);
    shimNode.attr("class", "mce-shim");
    previewWrapper.append(previewNode);
    previewWrapper.append(shimNode);
    return previewWrapper;
  };
  const retainAttributesAndInnerHtml = (editor, sourceNode, targetNode) => {
    const attribs = sourceNode.attributes;
    let ai = attribs.length;
    while (ai--) {
      const attrName = attribs[ai].name;
      let attrValue = attribs[ai].value;
      if (attrName !== "width" && attrName !== "height" && attrName !== "style" && !startsWith(attrName, "data-mce-")) {
        if (attrName === "data" || attrName === "src") {
          attrValue = editor.convertURL(attrValue, attrName);
        }
        targetNode.attr("data-mce-p-" + attrName, attrValue);
      }
    }
    const serializer = global$1({ inner: true }, editor.schema);
    const tempNode = new global$2("div", 1);
    each$1(sourceNode.children(), (child) => tempNode.append(child));
    const innerHtml = serializer.serialize(tempNode);
    if (innerHtml) {
      targetNode.attr("data-mce-html", escape(innerHtml));
      targetNode.empty();
    }
  };
  const isPageEmbedWrapper = (node) => {
    const nodeClass = node.attr("class");
    return nodeClass && /\btiny-pageembed\b/.test(nodeClass);
  };
  const isWithinEmbedWrapper = (node) => {
    while (node = node.parent) {
      if (node.attr("data-ephox-embed-iri") || isPageEmbedWrapper(node)) {
        return true;
      }
    }
    return false;
  };
  const placeHolderConverter = (editor) => (nodes) => {
    let i = nodes.length;
    let node;
    while (i--) {
      node = nodes[i];
      if (!node.parent) {
        continue;
      }
      if (node.parent.attr("data-mce-object")) {
        continue;
      }
      if (isLiveEmbedNode(node) && hasLiveEmbeds(editor)) {
        if (!isWithinEmbedWrapper(node)) {
          node.replace(createPreviewNode(editor, node));
        }
      } else {
        if (!isWithinEmbedWrapper(node)) {
          node.replace(createPlaceholderNode(editor, node));
        }
      }
    }
  };
  const parseAndSanitize = (editor, context, html) => {
    const validate = shouldFilterHtml(editor);
    return Parser(editor.schema, { validate }).parse(html, { context });
  };
  const setup$1 = (editor) => {
    editor.on("PreInit", () => {
      const { schema, serializer, parser } = editor;
      const boolAttrs = schema.getBoolAttrs();
      each$1("webkitallowfullscreen mozallowfullscreen".split(" "), (name) => {
        boolAttrs[name] = {};
      });
      each({ embed: ["wmode"] }, (attrs, name) => {
        const rule = schema.getElementRule(name);
        each$1(attrs, (attr) => {
          rule.attributes[attr] = {};
          rule.attributesOrder.push(attr);
        });
      });
      parser.addNodeFilter("iframe,video,audio,object,embed,script", placeHolderConverter(editor));
      serializer.addAttributeFilter("data-mce-object", (nodes, name) => {
        let i = nodes.length;
        while (i--) {
          const node = nodes[i];
          if (!node.parent) {
            continue;
          }
          const realElmName = node.attr(name);
          const realElm = new global$2(realElmName, 1);
          if (realElmName !== "audio" && realElmName !== "script") {
            const className = node.attr("class");
            if (className && className.indexOf("mce-preview-object") !== -1) {
              realElm.attr({
                width: node.firstChild.attr("width"),
                height: node.firstChild.attr("height")
              });
            } else {
              realElm.attr({
                width: node.attr("width"),
                height: node.attr("height")
              });
            }
          }
          realElm.attr({ style: node.attr("style") });
          const attribs = node.attributes;
          let ai = attribs.length;
          while (ai--) {
            const attrName = attribs[ai].name;
            if (attrName.indexOf("data-mce-p-") === 0) {
              realElm.attr(attrName.substr(11), attribs[ai].value);
            }
          }
          if (realElmName === "script") {
            realElm.attr("type", "text/javascript");
          }
          const innerHtml = node.attr("data-mce-html");
          if (innerHtml) {
            const fragment = parseAndSanitize(editor, realElmName, unescape(innerHtml));
            each$1(fragment.children(), (child) => realElm.append(child));
          }
          node.replace(realElm);
        }
      });
    });
    editor.on("SetContent", () => {
      const dom = editor.dom;
      each$1(dom.select("span.mce-preview-object"), (elm) => {
        if (dom.select("span.mce-shim", elm).length === 0) {
          dom.add(elm, "span", { class: "mce-shim" });
        }
      });
    });
  };
  const setup = (editor) => {
    editor.on("ResolveName", (e) => {
      let name;
      if (e.target.nodeType === 1 && (name = e.target.getAttribute("data-mce-object"))) {
        e.name = name;
      }
    });
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mceMedia");
    editor.ui.registry.addToggleButton("media", {
      tooltip: "Insert/edit media",
      icon: "embed",
      onAction,
      onSetup: (buttonApi) => {
        const selection = editor.selection;
        buttonApi.setActive(isMediaElement(selection.getNode()));
        return selection.selectorChangedWithUnbind("img[data-mce-object],span[data-mce-object],div[data-ephox-embed-iri]", buttonApi.setActive).unbind;
      }
    });
    editor.ui.registry.addMenuItem("media", {
      icon: "embed",
      text: "Media...",
      onAction
    });
  };
  var Plugin = () => {
    global$6.add("media", (editor) => {
      register$2(editor);
      register$1(editor);
      register(editor);
      setup(editor);
      setup$1(editor);
      setup$2(editor);
      return get(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$3 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value) => typeOf(value) === type2;
  const isSimpleType = (type2) => (value) => typeof value === type2;
  const eq$1 = (t) => (a) => t === a;
  const isString = isType$1("string");
  const isArray = isType$1("array");
  const isBoolean = isSimpleType("boolean");
  const isUndefined = eq$1(void 0);
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const noop = () => {
  };
  const compose1 = (fbc, fab) => (a) => fbc(fab(a));
  const constant = (value) => {
    return () => {
      return value;
    };
  };
  const identity = (x) => {
    return x;
  };
  const tripleEquals = (a, b) => {
    return a === b;
  };
  function curry(fn, ...initialArgs) {
    return (...restArgs) => {
      const all2 = initialArgs.concat(restArgs);
      return fn.apply(null, all2);
    };
  }
  const never = constant(false);
  const always = constant(true);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each$1 = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = (r) => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r = {};
    each$1(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r;
  };
  const filter$1 = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const mapToArray = (obj, f) => {
    const r = [];
    each$1(obj, (value, name2) => {
      r.push(f(value, name2));
    });
    return r;
  };
  const values = (obj) => {
    return mapToArray(obj, identity);
  };
  const size = (obj) => {
    return keys(obj).length;
  };
  const get$4 = (obj, key2) => {
    return has(obj, key2) ? Optional.from(obj[key2]) : Optional.none();
  };
  const has = (obj, key2) => hasOwnProperty.call(obj, key2);
  const hasNonNullableKey = (obj, key2) => has(obj, key2) && obj[key2] !== void 0 && obj[key2] !== null;
  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains = (xs, x) => rawIndexOf(xs, x) > -1;
  const exists = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return true;
      }
    }
    return false;
  };
  const range = (num, f) => {
    const r = [];
    for (let i = 0; i < num; i++) {
      r.push(f(i));
    }
    return r;
  };
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const eachr = (xs, f) => {
    for (let i = xs.length - 1; i >= 0; i--) {
      const x = xs[i];
      f(x, i);
    }
  };
  const partition = (xs, pred) => {
    const pass = [];
    const fail = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      const arr = pred(x, i) ? pass : fail;
      arr.push(x);
    }
    return {
      pass,
      fail
    };
  };
  const filter = (xs, pred) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r.push(x);
      }
    }
    return r;
  };
  const foldr = (xs, f, acc) => {
    eachr(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const foldl = (xs, f, acc) => {
    each(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const flatten$1 = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten$1(map(xs, f));
  const forall = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; ++i) {
      const x = xs[i];
      if (pred(x, i) !== true) {
        return false;
      }
    }
    return true;
  };
  const mapToObject = (xs, f) => {
    const r = {};
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      r[String(x)] = f(x, i);
    }
    return r;
  };
  const get$3 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get$3(xs, 0);
  const last = (xs) => get$3(xs, xs.length - 1);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r = f(arr[i], i);
      if (r.isSome()) {
        return r;
      }
    }
    return Optional.none();
  };
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom$1(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom$1(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom$1(node);
  };
  const fromDom$1 = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom: fromDom$1,
    fromPoint
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const COMMENT = 8;
  const DOCUMENT = 9;
  const DOCUMENT_FRAGMENT = 11;
  const ELEMENT = 1;
  const TEXT = 3;
  const name = (element) => {
    const r = element.dom.nodeName;
    return r.toLowerCase();
  };
  const type = (element) => element.dom.nodeType;
  const isType = (t) => (element) => type(element) === t;
  const isComment = (element) => type(element) === COMMENT || name(element) === "#comment";
  const isElement = isType(ELEMENT);
  const isText = isType(TEXT);
  const isDocument = isType(DOCUMENT);
  const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  const isTag = (tag) => (e) => isElement(e) && name(e) === tag;
  const is$2 = (element, selector) => {
    const dom = element.dom;
    if (dom.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  const bypassSelector = (dom) => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  const all$1 = (selector, scope) => {
    const base = scope === void 0 ? document : scope.dom;
    return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  };
  const one = (selector, scope) => {
    const base = scope === void 0 ? document : scope.dom;
    return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
  };
  const eq = (e1, e2) => e1.dom === e2.dom;
  const is$1 = is$2;
  const owner = (element) => SugarElement.fromDom(element.dom.ownerDocument);
  const documentOrOwner = (dos) => isDocument(dos) ? dos : owner(dos);
  const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  const parents = (element, isRoot) => {
    const stop = isFunction(isRoot) ? isRoot : never;
    let dom = element.dom;
    const ret = [];
    while (dom.parentNode !== null && dom.parentNode !== void 0) {
      const rawParent = dom.parentNode;
      const p = SugarElement.fromDom(rawParent);
      ret.push(p);
      if (stop(p) === true) {
        break;
      } else {
        dom = rawParent;
      }
    }
    return ret;
  };
  const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
  const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  const children$3 = (element) => map(element.dom.childNodes, SugarElement.fromDom);
  const child$3 = (element, index2) => {
    const cs = element.dom.childNodes;
    return Optional.from(cs[index2]).map(SugarElement.fromDom);
  };
  const firstChild = (element) => child$3(element, 0);
  const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  const getRootNode = supported ? (e) => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  const getShadowRoot = (e) => {
    const r = getRootNode(e);
    return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  };
  const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
  const inBody = (element) => {
    const dom = isText(element) ? element.dom.parentNode : element.dom;
    if (dom === void 0 || dom === null || dom.ownerDocument === null) {
      return false;
    }
    const doc = dom.ownerDocument;
    return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  };
  const children$2 = (scope, predicate) => filter(children$3(scope), predicate);
  const descendants$1 = (scope, predicate) => {
    let result = [];
    each(children$3(scope), (x) => {
      if (predicate(x)) {
        result = result.concat([x]);
      }
      result = result.concat(descendants$1(x, predicate));
    });
    return result;
  };
  const children$1 = (scope, selector) => children$2(scope, (e) => is$2(e, selector));
  const descendants = (scope, selector) => all$1(selector, scope);
  var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot) => {
    if (is2(scope, a)) {
      return Optional.some(scope);
    } else if (isFunction(isRoot) && isRoot(scope)) {
      return Optional.none();
    } else {
      return ancestor2(scope, a, isRoot);
    }
  };
  const ancestor$1 = (scope, predicate, isRoot) => {
    let element = scope.dom;
    const stop = isFunction(isRoot) ? isRoot : never;
    while (element.parentNode) {
      element = element.parentNode;
      const el = SugarElement.fromDom(element);
      if (predicate(el)) {
        return Optional.some(el);
      } else if (stop(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const child$2 = (scope, predicate) => {
    const pred = (node) => predicate(SugarElement.fromDom(node));
    const result = find(scope.dom.childNodes, pred);
    return result.map(SugarElement.fromDom);
  };
  const ancestor = (scope, selector, isRoot) => ancestor$1(scope, (e) => is$2(e, selector), isRoot);
  const child$1 = (scope, selector) => child$2(scope, (e) => is$2(e, selector));
  const descendant = (scope, selector) => one(selector, scope);
  const closest = (scope, selector, isRoot) => {
    const is2 = (element, selector2) => is$2(element, selector2);
    return ClosestOrAncestor(is2, ancestor, scope, selector, isRoot);
  };
  const rawSet = (dom, key2, value) => {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key2, value + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key2, ":: Value ", value, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set$2 = (element, key2, value) => {
    rawSet(element.dom, key2, value);
  };
  const setAll = (element, attrs) => {
    const dom = element.dom;
    each$1(attrs, (v, k) => {
      rawSet(dom, k, v);
    });
  };
  const get$2 = (element, key2) => {
    const v = element.dom.getAttribute(key2);
    return v === null ? void 0 : v;
  };
  const getOpt = (element, key2) => Optional.from(get$2(element, key2));
  const remove$2 = (element, key2) => {
    element.dom.removeAttribute(key2);
  };
  const clone = (element) => foldl(element.dom.attributes, (acc, attr) => {
    acc[attr.name] = attr.value;
    return acc;
  }, {});
  const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
  const cat = (arr) => {
    const r = [];
    const push = (x) => {
      r.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r;
  };
  const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  const flatten = (oot) => oot.bind(identity);
  const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  const removeFromStart = (str, numChars) => {
    return str.substring(numChars);
  };
  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const removeLeading = (str, prefix) => {
    return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  };
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };
  const blank = (r) => (s) => s.replace(r, "");
  const trim = blank(/^\s+|\s+$/g);
  const isNotEmpty = (s) => s.length > 0;
  const isEmpty = (s) => !isNotEmpty(s);
  const toFloat = (value) => {
    const num = parseFloat(value);
    return isNaN(num) ? Optional.none() : Optional.some(num);
  };
  const isSupported = (dom) => dom.style !== void 0 && isFunction(dom.style.getPropertyValue);
  const internalSet = (dom, property, value) => {
    if (!isString(value)) {
      console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value, ":: Element ", dom);
      throw new Error("CSS value must be a string: " + value);
    }
    if (isSupported(dom)) {
      dom.style.setProperty(property, value);
    }
  };
  const internalRemove = (dom, property) => {
    if (isSupported(dom)) {
      dom.style.removeProperty(property);
    }
  };
  const set$1 = (element, property, value) => {
    const dom = element.dom;
    internalSet(dom, property, value);
  };
  const get$1 = (element, property) => {
    const dom = element.dom;
    const styles = window.getComputedStyle(dom);
    const r = styles.getPropertyValue(property);
    return r === "" && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  };
  const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : "";
  const getRaw = (element, property) => {
    const dom = element.dom;
    const raw = getUnsafeProperty(dom, property);
    return Optional.from(raw).filter((r) => r.length > 0);
  };
  const remove$1 = (element, property) => {
    const dom = element.dom;
    internalRemove(dom, property);
    if (is(getOpt(element, "style").map(trim), "")) {
      remove$2(element, "style");
    }
  };
  const getAttrValue = (cell2, name2, fallback = 0) => getOpt(cell2, name2).map((value) => parseInt(value, 10)).getOr(fallback);
  const firstLayer = (scope, selector) => {
    return filterFirstLayer(scope, selector, always);
  };
  const filterFirstLayer = (scope, selector, predicate) => {
    return bind(children$3(scope), (x) => {
      if (is$2(x, selector)) {
        return predicate(x) ? [x] : [];
      } else {
        return filterFirstLayer(x, selector, predicate);
      }
    });
  };
  const validSectionList = [
    "tfoot",
    "thead",
    "tbody",
    "colgroup"
  ];
  const isValidSection = (parentName) => contains(validSectionList, parentName);
  const grid = (rows2, columns2) => ({
    rows: rows2,
    columns: columns2
  });
  const detail = (element, rowspan, colspan) => ({
    element,
    rowspan,
    colspan
  });
  const extended = (element, rowspan, colspan, row, column, isLocked) => ({
    element,
    rowspan,
    colspan,
    row,
    column,
    isLocked
  });
  const rowdetail = (element, cells2, section) => ({
    element,
    cells: cells2,
    section
  });
  const bounds = (startRow, startCol, finishRow, finishCol) => ({
    startRow,
    startCol,
    finishRow,
    finishCol
  });
  const columnext = (element, colspan, column) => ({
    element,
    colspan,
    column
  });
  const colgroup = (element, columns2) => ({
    element,
    columns: columns2
  });
  const lookup = (tags, element, isRoot = never) => {
    if (isRoot(element)) {
      return Optional.none();
    }
    if (contains(tags, name(element))) {
      return Optional.some(element);
    }
    const isRootOrUpperTable = (elm) => is$2(elm, "table") || isRoot(elm);
    return ancestor(element, tags.join(","), isRootOrUpperTable);
  };
  const cell = (element, isRoot) => lookup([
    "td",
    "th"
  ], element, isRoot);
  const cells = (ancestor2) => firstLayer(ancestor2, "th,td");
  const columns = (ancestor2) => {
    if (is$2(ancestor2, "colgroup")) {
      return children$1(ancestor2, "col");
    } else {
      return bind(columnGroups(ancestor2), (columnGroup) => children$1(columnGroup, "col"));
    }
  };
  const table = (element, isRoot) => closest(element, "table", isRoot);
  const rows = (ancestor2) => firstLayer(ancestor2, "tr");
  const columnGroups = (ancestor2) => table(ancestor2).fold(constant([]), (table2) => children$1(table2, "colgroup"));
  const fromRowsOrColGroups = (elems, getSection) => map(elems, (row) => {
    if (name(row) === "colgroup") {
      const cells2 = map(columns(row), (column) => {
        const colspan = getAttrValue(column, "span", 1);
        return detail(column, 1, colspan);
      });
      return rowdetail(row, cells2, "colgroup");
    } else {
      const cells$1 = map(cells(row), (cell2) => {
        const rowspan = getAttrValue(cell2, "rowspan", 1);
        const colspan = getAttrValue(cell2, "colspan", 1);
        return detail(cell2, rowspan, colspan);
      });
      return rowdetail(row, cells$1, getSection(row));
    }
  });
  const getParentSection = (group) => parent(group).map((parent2) => {
    const parentName = name(parent2);
    return isValidSection(parentName) ? parentName : "tbody";
  }).getOr("tbody");
  const fromTable$1 = (table2) => {
    const rows$1 = rows(table2);
    const columnGroups$1 = columnGroups(table2);
    const elems = [
      ...columnGroups$1,
      ...rows$1
    ];
    return fromRowsOrColGroups(elems, getParentSection);
  };
  const LOCKED_COL_ATTR = "data-snooker-locked-cols";
  const getLockedColumnsFromTable = (table2) => getOpt(table2, LOCKED_COL_ATTR).bind((lockedColStr) => Optional.from(lockedColStr.match(/\d+/g))).map((lockedCols) => mapToObject(lockedCols, always));
  const key = (row, column) => {
    return row + "," + column;
  };
  const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]);
  const findItem = (warehouse, item, comparator) => {
    const filtered = filterItems(warehouse, (detail2) => {
      return comparator(item, detail2.element);
    });
    return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none();
  };
  const filterItems = (warehouse, predicate) => {
    const all2 = bind(warehouse.all, (r) => {
      return r.cells;
    });
    return filter(all2, predicate);
  };
  const generateColumns = (rowData) => {
    const columnsGroup = {};
    let index2 = 0;
    each(rowData.cells, (column) => {
      const colspan = column.colspan;
      range(colspan, (columnIndex) => {
        const colIndex = index2 + columnIndex;
        columnsGroup[colIndex] = columnext(column.element, colspan, colIndex);
      });
      index2 += colspan;
    });
    return columnsGroup;
  };
  const generate$1 = (list) => {
    const access = {};
    const cells2 = [];
    const tableOpt = head(list).map((rowData) => rowData.element).bind(table);
    const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({});
    let maxRows = 0;
    let maxColumns = 0;
    let rowCount = 0;
    const {
      pass: colgroupRows,
      fail: rows2
    } = partition(list, (rowData) => rowData.section === "colgroup");
    each(rows2, (rowData) => {
      const currentRow = [];
      each(rowData.cells, (rowCell) => {
        let start = 0;
        while (access[key(rowCount, start)] !== void 0) {
          start++;
        }
        const isLocked = hasNonNullableKey(lockedColumns, start.toString());
        const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked);
        for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) {
          for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) {
            const rowPosition = rowCount + occupiedRowPosition;
            const columnPosition = start + occupiedColumnPosition;
            const newpos = key(rowPosition, columnPosition);
            access[newpos] = current;
            maxColumns = Math.max(maxColumns, columnPosition + 1);
          }
        }
        currentRow.push(current);
      });
      maxRows++;
      cells2.push(rowdetail(rowData.element, currentRow, rowData.section));
      rowCount++;
    });
    const { columns: columns2, colgroups } = last(colgroupRows).map((rowData) => {
      const columns3 = generateColumns(rowData);
      const colgroup$1 = colgroup(rowData.element, values(columns3));
      return {
        colgroups: [colgroup$1],
        columns: columns3
      };
    }).getOrThunk(() => ({
      colgroups: [],
      columns: {}
    }));
    const grid$1 = grid(maxRows, maxColumns);
    return {
      grid: grid$1,
      access,
      all: cells2,
      columns: columns2,
      colgroups
    };
  };
  const fromTable = (table2) => {
    const list = fromTable$1(table2);
    return generate$1(list);
  };
  const justCells = (warehouse) => bind(warehouse.all, (w) => w.cells);
  const justColumns = (warehouse) => values(warehouse.columns);
  const hasColumns = (warehouse) => keys(warehouse.columns).length > 0;
  const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]);
  const Warehouse = {
    fromTable,
    generate: generate$1,
    getAt,
    findItem,
    filterItems,
    justCells,
    justColumns,
    hasColumns,
    getColumnAt
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const getTDTHOverallStyle = (dom, elm, name2) => {
    const cells2 = dom.select("td,th", elm);
    let firstChildStyle;
    const checkChildren = (firstChildStyle2, elms) => {
      for (let i = 0; i < elms.length; i++) {
        const currentStyle = dom.getStyle(elms[i], name2);
        if (typeof firstChildStyle2 === "undefined") {
          firstChildStyle2 = currentStyle;
        }
        if (firstChildStyle2 !== currentStyle) {
          return "";
        }
      }
      return firstChildStyle2;
    };
    return checkChildren(firstChildStyle, cells2);
  };
  const setAlign = (editor, elm, name2) => {
    global$2.each("left center right".split(" "), (align) => {
      if (align !== name2) {
        editor.formatter.remove("align" + align, {}, elm);
      }
    });
    if (name2) {
      editor.formatter.apply("align" + name2, {}, elm);
    }
  };
  const setVAlign = (editor, elm, name2) => {
    global$2.each("top middle bottom".split(" "), (align) => {
      if (align !== name2) {
        editor.formatter.remove("valign" + align, {}, elm);
      }
    });
    if (name2) {
      editor.formatter.apply("valign" + name2, {}, elm);
    }
  };
  const fireTableModified = (editor, table2, data) => {
    editor.dispatch("TableModified", {
      ...data,
      table: table2
    });
  };
  const toNumber = (px, fallback) => toFloat(px).getOr(fallback);
  const getProp = (element, name2, fallback) => toNumber(get$1(element, name2), fallback);
  const calcContentBoxSize = (element, size2, upper, lower) => {
    const paddingUpper = getProp(element, `padding-${upper}`, 0);
    const paddingLower = getProp(element, `padding-${lower}`, 0);
    const borderUpper = getProp(element, `border-${upper}-width`, 0);
    const borderLower = getProp(element, `border-${lower}-width`, 0);
    return size2 - paddingUpper - paddingLower - borderUpper - borderLower;
  };
  const getCalculatedWidth = (element, boxSizing) => {
    const dom = element.dom;
    const width = dom.getBoundingClientRect().width || dom.offsetWidth;
    return boxSizing === "border-box" ? width : calcContentBoxSize(element, width, "left", "right");
  };
  const getInnerWidth = (element) => getCalculatedWidth(element, "content-box");
  const getInner = getInnerWidth;
  var global$1 = tinymce.util.Tools.resolve("tinymce.Env");
  const defaultTableToolbar = "tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol";
  const defaultCellBorderWidths = range(5, (i) => {
    const size2 = `${i + 1}px`;
    return {
      title: size2,
      value: size2
    };
  });
  const defaultCellBorderStyles = map([
    "Solid",
    "Dotted",
    "Dashed",
    "Double",
    "Groove",
    "Ridge",
    "Inset",
    "Outset",
    "None",
    "Hidden"
  ], (type2) => {
    return {
      title: type2,
      value: type2.toLowerCase()
    };
  });
  const defaultWidth = "100%";
  const getPixelForcedWidth = (editor) => {
    var _a;
    const dom = editor.dom;
    const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody();
    return getInner(SugarElement.fromDom(parentBlock)) + "px";
  };
  const determineDefaultStyles = (editor, defaultStyles) => {
    if (isResponsiveForced(editor) || !shouldStyleWithCss(editor)) {
      return defaultStyles;
    } else if (isPixelsForced(editor)) {
      return {
        ...defaultStyles,
        width: getPixelForcedWidth(editor)
      };
    } else {
      return {
        ...defaultStyles,
        width: defaultWidth
      };
    }
  };
  const determineDefaultAttributes = (editor, defaultAttributes) => {
    if (isResponsiveForced(editor) || shouldStyleWithCss(editor)) {
      return defaultAttributes;
    } else if (isPixelsForced(editor)) {
      return {
        ...defaultAttributes,
        width: getPixelForcedWidth(editor)
      };
    } else {
      return {
        ...defaultAttributes,
        width: defaultWidth
      };
    }
  };
  const option = (name2) => (editor) => editor.options.get(name2);
  const register = (editor) => {
    const registerOption = editor.options.register;
    registerOption("table_border_widths", {
      processor: "object[]",
      default: defaultCellBorderWidths
    });
    registerOption("table_border_styles", {
      processor: "object[]",
      default: defaultCellBorderStyles
    });
    registerOption("table_cell_advtab", {
      processor: "boolean",
      default: true
    });
    registerOption("table_row_advtab", {
      processor: "boolean",
      default: true
    });
    registerOption("table_advtab", {
      processor: "boolean",
      default: true
    });
    registerOption("table_appearance_options", {
      processor: "boolean",
      default: true
    });
    registerOption("table_grid", {
      processor: "boolean",
      default: !global$1.deviceType.isTouch()
    });
    registerOption("table_cell_class_list", {
      processor: "object[]",
      default: []
    });
    registerOption("table_row_class_list", {
      processor: "object[]",
      default: []
    });
    registerOption("table_class_list", {
      processor: "object[]",
      default: []
    });
    registerOption("table_toolbar", {
      processor: "string",
      default: defaultTableToolbar
    });
    registerOption("table_background_color_map", {
      processor: "object[]",
      default: []
    });
    registerOption("table_border_color_map", {
      processor: "object[]",
      default: []
    });
  };
  const getTableSizingMode = option("table_sizing_mode");
  const getTableBorderWidths = option("table_border_widths");
  const getTableBorderStyles = option("table_border_styles");
  const hasAdvancedCellTab = option("table_cell_advtab");
  const hasAdvancedRowTab = option("table_row_advtab");
  const hasAdvancedTableTab = option("table_advtab");
  const hasAppearanceOptions = option("table_appearance_options");
  const hasTableGrid = option("table_grid");
  const shouldStyleWithCss = option("table_style_by_css");
  const getCellClassList = option("table_cell_class_list");
  const getRowClassList = option("table_row_class_list");
  const getTableClassList = option("table_class_list");
  const getToolbar = option("table_toolbar");
  const getTableBackgroundColorMap = option("table_background_color_map");
  const getTableBorderColorMap = option("table_border_color_map");
  const isPixelsForced = (editor) => getTableSizingMode(editor) === "fixed";
  const isResponsiveForced = (editor) => getTableSizingMode(editor) === "responsive";
  const getDefaultStyles = (editor) => {
    const options = editor.options;
    const defaultStyles = options.get("table_default_styles");
    return options.isSet("table_default_styles") ? defaultStyles : determineDefaultStyles(editor, defaultStyles);
  };
  const getDefaultAttributes = (editor) => {
    const options = editor.options;
    const defaultAttributes = options.get("table_default_attributes");
    return options.isSet("table_default_attributes") ? defaultAttributes : determineDefaultAttributes(editor, defaultAttributes);
  };
  const getNodeName = (elm) => elm.nodeName.toLowerCase();
  const getBody = (editor) => SugarElement.fromDom(editor.getBody());
  const getIsRoot = (editor) => (element) => eq(element, getBody(editor));
  const removePxSuffix = (size2) => size2 ? size2.replace(/px$/, "") : "";
  const addPxSuffix = (size2) => /^\d+(\.\d+)?$/.test(size2) ? size2 + "px" : size2;
  const getSelectionStart = (editor) => SugarElement.fromDom(editor.selection.getStart());
  const getSelectionEnd = (editor) => SugarElement.fromDom(editor.selection.getEnd());
  const isWithin = (bounds2, detail2) => {
    return detail2.column >= bounds2.startCol && detail2.column + detail2.colspan - 1 <= bounds2.finishCol && detail2.row >= bounds2.startRow && detail2.row + detail2.rowspan - 1 <= bounds2.finishRow;
  };
  const isRectangular = (warehouse, bounds2) => {
    let isRect = true;
    const detailIsWithin = curry(isWithin, bounds2);
    for (let i = bounds2.startRow; i <= bounds2.finishRow; i++) {
      for (let j = bounds2.startCol; j <= bounds2.finishCol; j++) {
        isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin);
      }
    }
    return isRect ? Optional.some(bounds2) : Optional.none();
  };
  const getBounds = (detailA, detailB) => {
    return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1));
  };
  const getAnyBox = (warehouse, startCell, finishCell) => {
    const startCoords = Warehouse.findItem(warehouse, startCell, eq);
    const finishCoords = Warehouse.findItem(warehouse, finishCell, eq);
    return startCoords.bind((sc) => {
      return finishCoords.map((fc) => {
        return getBounds(sc, fc);
      });
    });
  };
  const getBox$1 = (warehouse, startCell, finishCell) => {
    return getAnyBox(warehouse, startCell, finishCell).bind((bounds2) => {
      return isRectangular(warehouse, bounds2);
    });
  };
  const getBox = (table2, first, last2) => {
    const warehouse = getWarehouse(table2);
    return getBox$1(warehouse, first, last2);
  };
  const getWarehouse = Warehouse.fromTable;
  const before = (marker, element) => {
    const parent$1 = parent(marker);
    parent$1.each((v) => {
      v.dom.insertBefore(element.dom, marker.dom);
    });
  };
  const after$1 = (marker, element) => {
    const sibling = nextSibling(marker);
    sibling.fold(() => {
      const parent$1 = parent(marker);
      parent$1.each((v) => {
        append$1(v, element);
      });
    }, (v) => {
      before(v, element);
    });
  };
  const prepend = (parent2, element) => {
    const firstChild$1 = firstChild(parent2);
    firstChild$1.fold(() => {
      append$1(parent2, element);
    }, (v) => {
      parent2.dom.insertBefore(element.dom, v.dom);
    });
  };
  const append$1 = (parent2, element) => {
    parent2.dom.appendChild(element.dom);
  };
  const wrap = (element, wrapper) => {
    before(element, wrapper);
    append$1(wrapper, element);
  };
  const after = (marker, elements) => {
    each(elements, (x, i) => {
      const e = i === 0 ? marker : elements[i - 1];
      after$1(e, x);
    });
  };
  const append = (parent2, elements) => {
    each(elements, (x) => {
      append$1(parent2, x);
    });
  };
  const remove = (element) => {
    const dom = element.dom;
    if (dom.parentNode !== null) {
      dom.parentNode.removeChild(dom);
    }
  };
  const unwrap = (wrapper) => {
    const children2 = children$3(wrapper);
    if (children2.length > 0) {
      after(wrapper, children2);
    }
    remove(wrapper);
  };
  const NodeValue = (is2, name2) => {
    const get2 = (element) => {
      if (!is2(element)) {
        throw new Error("Can only get " + name2 + " value of a " + name2 + " node");
      }
      return getOption(element).getOr("");
    };
    const getOption = (element) => is2(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
    const set2 = (element, value) => {
      if (!is2(element)) {
        throw new Error("Can only set raw " + name2 + " value of a " + name2 + " node");
      }
      element.dom.nodeValue = value;
    };
    return {
      get: get2,
      getOption,
      set: set2
    };
  };
  const api = NodeValue(isText, "text");
  const get = (element) => api.get(element);
  const set = (element, value) => api.set(element, value);
  var TagBoundaries = [
    "body",
    "p",
    "div",
    "article",
    "aside",
    "figcaption",
    "figure",
    "footer",
    "header",
    "nav",
    "section",
    "ol",
    "ul",
    "li",
    "table",
    "thead",
    "tbody",
    "tfoot",
    "caption",
    "tr",
    "td",
    "th",
    "h1",
    "h2",
    "h3",
    "h4",
    "h5",
    "h6",
    "blockquote",
    "pre",
    "address"
  ];
  var DomUniverse = () => {
    const clone$1 = (element) => {
      return SugarElement.fromDom(element.dom.cloneNode(false));
    };
    const document2 = (element) => documentOrOwner(element).dom;
    const isBoundary = (element) => {
      if (!isElement(element)) {
        return false;
      }
      if (name(element) === "body") {
        return true;
      }
      return contains(TagBoundaries, name(element));
    };
    const isEmptyTag = (element) => {
      if (!isElement(element)) {
        return false;
      }
      return contains([
        "br",
        "img",
        "hr",
        "input"
      ], name(element));
    };
    const isNonEditable = (element) => isElement(element) && get$2(element, "contenteditable") === "false";
    const comparePosition = (element, other) => {
      return element.dom.compareDocumentPosition(other.dom);
    };
    const copyAttributesTo = (source, destination) => {
      const as = clone(source);
      setAll(destination, as);
    };
    const isSpecial = (element) => {
      const tag = name(element);
      return contains([
        "script",
        "noscript",
        "iframe",
        "noframes",
        "noembed",
        "title",
        "style",
        "textarea",
        "xmp"
      ], tag);
    };
    const getLanguage = (element) => isElement(element) ? getOpt(element, "lang") : Optional.none();
    return {
      up: constant({
        selector: ancestor,
        closest,
        predicate: ancestor$1,
        all: parents
      }),
      down: constant({
        selector: descendants,
        predicate: descendants$1
      }),
      styles: constant({
        get: get$1,
        getRaw,
        set: set$1,
        remove: remove$1
      }),
      attrs: constant({
        get: get$2,
        set: set$2,
        remove: remove$2,
        copyTo: copyAttributesTo
      }),
      insert: constant({
        before,
        after: after$1,
        afterAll: after,
        append: append$1,
        appendAll: append,
        prepend,
        wrap
      }),
      remove: constant({
        unwrap,
        remove
      }),
      create: constant({
        nu: SugarElement.fromTag,
        clone: clone$1,
        text: SugarElement.fromText
      }),
      query: constant({
        comparePosition,
        prevSibling,
        nextSibling
      }),
      property: constant({
        children: children$3,
        name,
        parent,
        document: document2,
        isText,
        isComment,
        isElement,
        isSpecial,
        getLanguage,
        getText: get,
        setText: set,
        isBoundary,
        isEmptyTag,
        isNonEditable
      }),
      eq,
      is: is$1
    };
  };
  const all = (universe2, look, elements, f) => {
    const head2 = elements[0];
    const tail = elements.slice(1);
    return f(universe2, look, head2, tail);
  };
  const oneAll = (universe2, look, elements) => {
    return elements.length > 0 ? all(universe2, look, elements, unsafeOne) : Optional.none();
  };
  const unsafeOne = (universe2, look, head2, tail) => {
    const start = look(universe2, head2);
    return foldr(tail, (b, a) => {
      const current = look(universe2, a);
      return commonElement(universe2, b, current);
    }, start);
  };
  const commonElement = (universe2, start, end) => {
    return start.bind((s) => {
      return end.filter(curry(universe2.eq, s));
    });
  };
  const sharedOne$1 = oneAll;
  const universe = DomUniverse();
  const sharedOne = (look, elements) => {
    return sharedOne$1(universe, (_universe, element) => {
      return look(element);
    }, elements);
  };
  const lookupTable = (container) => {
    return ancestor(container, "table");
  };
  const retrieve$1 = (container, selector) => {
    const sels = descendants(container, selector);
    return sels.length > 0 ? Optional.some(sels) : Optional.none();
  };
  const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => {
    return descendant(container, firstSelectedSelector).bind((first) => {
      return descendant(container, lastSelectedSelector).bind((last2) => {
        return sharedOne(lookupTable, [
          first,
          last2
        ]).map((table2) => {
          return {
            first,
            last: last2,
            table: table2
          };
        });
      });
    });
  };
  const retrieve = (container, selector) => {
    return retrieve$1(container, selector);
  };
  const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => {
    return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind((edges) => {
      const isRoot = (ancestor2) => {
        return eq(container, ancestor2);
      };
      const sectionSelector = "thead,tfoot,tbody,table";
      const firstAncestor = ancestor(edges.first, sectionSelector, isRoot);
      const lastAncestor = ancestor(edges.last, sectionSelector, isRoot);
      return firstAncestor.bind((fA) => {
        return lastAncestor.bind((lA) => {
          return eq(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none();
        });
      });
    });
  };
  const fromDom = (nodes) => map(nodes, SugarElement.fromDom);
  const strSelected = "data-mce-selected";
  const strSelectedSelector = "td[" + strSelected + "],th[" + strSelected + "]";
  const strFirstSelected = "data-mce-first-selected";
  const strFirstSelectedSelector = "td[" + strFirstSelected + "],th[" + strFirstSelected + "]";
  const strLastSelected = "data-mce-last-selected";
  const strLastSelectedSelector = "td[" + strLastSelected + "],th[" + strLastSelected + "]";
  const ephemera = {
    selected: strSelected,
    selectedSelector: strSelectedSelector,
    firstSelected: strFirstSelected,
    firstSelectedSelector: strFirstSelectedSelector,
    lastSelected: strLastSelected,
    lastSelectedSelector: strLastSelectedSelector
  };
  const getSelectionCellFallback = (element) => table(element).bind((table2) => retrieve(table2, ephemera.firstSelectedSelector)).fold(constant(element), (cells2) => cells2[0]);
  const getSelectionFromSelector = (selector) => (initCell, isRoot) => {
    const cellName = name(initCell);
    const cell2 = cellName === "col" || cellName === "colgroup" ? getSelectionCellFallback(initCell) : initCell;
    return closest(cell2, selector, isRoot);
  };
  const getSelectionCellOrCaption = getSelectionFromSelector("th,td,caption");
  const getSelectionCell = getSelectionFromSelector("th,td");
  const getCellsFromSelection = (editor) => fromDom(editor.model.table.getSelectedCells());
  const getRowsFromSelection = (selected, selector) => {
    const cellOpt = getSelectionCell(selected);
    const rowsOpt = cellOpt.bind((cell2) => table(cell2)).map((table2) => rows(table2));
    return lift2(cellOpt, rowsOpt, (cell2, rows2) => filter(rows2, (row) => exists(fromDom(row.dom.cells), (rowCell) => get$2(rowCell, selector) === "1" || eq(rowCell, cell2)))).getOr([]);
  };
  const verticalAlignValues = [
    {
      text: "None",
      value: ""
    },
    {
      text: "Top",
      value: "top"
    },
    {
      text: "Middle",
      value: "middle"
    },
    {
      text: "Bottom",
      value: "bottom"
    }
  ];
  const hexColour = (value) => ({ value });
  const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  const isHexString = (hex) => shorthandRegex.test(hex) || longformRegex.test(hex);
  const normalizeHex = (hex) => removeLeading(hex, "#").toUpperCase();
  const fromString$1 = (hex) => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
  const toHex = (component) => {
    const hex = component.toString(16);
    return (hex.length === 1 ? "0" + hex : hex).toUpperCase();
  };
  const fromRgba = (rgbaColour2) => {
    const value = toHex(rgbaColour2.red) + toHex(rgbaColour2.green) + toHex(rgbaColour2.blue);
    return hexColour(value);
  };
  const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  const rgbaColour = (red, green, blue, alpha) => ({
    red,
    green,
    blue,
    alpha
  });
  const fromStringValues = (red, green, blue, alpha) => {
    const r = parseInt(red, 10);
    const g = parseInt(green, 10);
    const b = parseInt(blue, 10);
    const a = parseFloat(alpha);
    return rgbaColour(r, g, b, a);
  };
  const fromString = (rgbaString) => {
    if (rgbaString === "transparent") {
      return Optional.some(rgbaColour(0, 0, 0, 0));
    }
    const rgbMatch = rgbRegex.exec(rgbaString);
    if (rgbMatch !== null) {
      return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], "1"));
    }
    const rgbaMatch = rgbaRegex.exec(rgbaString);
    if (rgbaMatch !== null) {
      return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
    }
    return Optional.none();
  };
  const anyToHex = (color) => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
    const canvas = document.createElement("canvas");
    canvas.height = 1;
    canvas.width = 1;
    const canvasContext = canvas.getContext("2d");
    canvasContext.clearRect(0, 0, canvas.width, canvas.height);
    canvasContext.fillStyle = "#FFFFFF";
    canvasContext.fillStyle = color;
    canvasContext.fillRect(0, 0, 1, 1);
    const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
    const r = rgba[0];
    const g = rgba[1];
    const b = rgba[2];
    const a = rgba[3];
    return fromRgba(rgbaColour(r, g, b, a));
  });
  const rgbaToHexString = (color) => fromString(color).map(fromRgba).map((h2) => "#" + h2.value).getOr(color);
  const Cell = (initial) => {
    let value = initial;
    const get2 = () => {
      return value;
    };
    const set2 = (v) => {
      value = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get2 = () => subject.get();
    const set2 = (s) => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear,
      isSet,
      get: get2,
      set: set2
    };
  };
  const unbindable = () => singleton((s) => s.unbind());
  const onSetupToggle = (editor, formatName, formatValue) => {
    return (api2) => {
      const boundCallback = unbindable();
      const isNone = isEmpty(formatValue);
      const init = () => {
        const selectedCells = getCellsFromSelection(editor);
        const checkNode = (cell2) => editor.formatter.match(formatName, { value: formatValue }, cell2.dom, isNone);
        if (isNone) {
          api2.setActive(!exists(selectedCells, checkNode));
          boundCallback.set(editor.formatter.formatChanged(formatName, (match) => api2.setActive(!match), true));
        } else {
          api2.setActive(forall(selectedCells, checkNode));
          boundCallback.set(editor.formatter.formatChanged(formatName, api2.setActive, false, { value: formatValue }));
        }
      };
      editor.initialized ? init() : editor.on("init", init);
      return boundCallback.clear;
    };
  };
  const isListGroup = (item) => hasNonNullableKey(item, "menu");
  const buildListItems = (items) => map(items, (item) => {
    const text = item.text || item.title;
    if (isListGroup(item)) {
      return {
        text,
        items: buildListItems(item.menu)
      };
    } else {
      return {
        text,
        value: item.value
      };
    }
  });
  const buildMenuItems = (editor, items, format, onAction) => map(items, (item) => {
    const text = item.text || item.title;
    if (isListGroup(item)) {
      return {
        type: "nestedmenuitem",
        text,
        getSubmenuItems: () => buildMenuItems(editor, item.menu, format, onAction)
      };
    } else {
      return {
        text,
        type: "togglemenuitem",
        onAction: () => onAction(item.value),
        onSetup: onSetupToggle(editor, format, item.value)
      };
    }
  });
  const applyTableCellStyle = (editor, style) => (value) => {
    editor.execCommand("mceTableApplyCellStyle", false, { [style]: value });
  };
  const filterNoneItem = (list) => bind(list, (item) => {
    if (isListGroup(item)) {
      return [{
        ...item,
        menu: filterNoneItem(item.menu)
      }];
    } else {
      return isNotEmpty(item.value) ? [item] : [];
    }
  });
  const generateMenuItemsCallback = (editor, items, format, onAction) => (callback) => callback(buildMenuItems(editor, items, format, onAction));
  const buildColorMenu = (editor, colorList, style) => {
    const colorMap = map(colorList, (entry) => ({
      text: entry.title,
      value: "#" + anyToHex(entry.value).value,
      type: "choiceitem"
    }));
    return [{
      type: "fancymenuitem",
      fancytype: "colorswatch",
      initData: {
        colors: colorMap.length > 0 ? colorMap : void 0,
        allowCustomColors: false
      },
      onAction: (data) => {
        const value = data.value === "remove" ? "" : data.value;
        editor.execCommand("mceTableApplyCellStyle", false, { [style]: value });
      }
    }];
  };
  const changeRowHeader = (editor) => () => {
    const currentType = editor.queryCommandValue("mceTableRowType");
    const newType = currentType === "header" ? "body" : "header";
    editor.execCommand("mceTableRowType", false, { type: newType });
  };
  const changeColumnHeader = (editor) => () => {
    const currentType = editor.queryCommandValue("mceTableColType");
    const newType = currentType === "th" ? "td" : "th";
    editor.execCommand("mceTableColType", false, { type: newType });
  };
  const getClassList$1 = (editor) => {
    const classes = buildListItems(getCellClassList(editor));
    if (classes.length > 0) {
      return Optional.some({
        name: "class",
        type: "listbox",
        label: "Class",
        items: classes
      });
    }
    return Optional.none();
  };
  const children = [
    {
      name: "width",
      type: "input",
      label: "Width"
    },
    {
      name: "height",
      type: "input",
      label: "Height"
    },
    {
      name: "celltype",
      type: "listbox",
      label: "Cell type",
      items: [
        {
          text: "Cell",
          value: "td"
        },
        {
          text: "Header cell",
          value: "th"
        }
      ]
    },
    {
      name: "scope",
      type: "listbox",
      label: "Scope",
      items: [
        {
          text: "None",
          value: ""
        },
        {
          text: "Row",
          value: "row"
        },
        {
          text: "Column",
          value: "col"
        },
        {
          text: "Row group",
          value: "rowgroup"
        },
        {
          text: "Column group",
          value: "colgroup"
        }
      ]
    },
    {
      name: "halign",
      type: "listbox",
      label: "Horizontal align",
      items: [
        {
          text: "None",
          value: ""
        },
        {
          text: "Left",
          value: "left"
        },
        {
          text: "Center",
          value: "center"
        },
        {
          text: "Right",
          value: "right"
        }
      ]
    },
    {
      name: "valign",
      type: "listbox",
      label: "Vertical align",
      items: verticalAlignValues
    }
  ];
  const getItems$2 = (editor) => children.concat(getClassList$1(editor).toArray());
  const getAdvancedTab = (editor, dialogName) => {
    const emptyBorderStyle = [{
      text: "Select...",
      value: ""
    }];
    const advTabItems = [
      {
        name: "borderstyle",
        type: "listbox",
        label: "Border style",
        items: emptyBorderStyle.concat(buildListItems(getTableBorderStyles(editor)))
      },
      {
        name: "bordercolor",
        type: "colorinput",
        label: "Border color"
      },
      {
        name: "backgroundcolor",
        type: "colorinput",
        label: "Background color"
      }
    ];
    const borderWidth = {
      name: "borderwidth",
      type: "input",
      label: "Border width"
    };
    const items = dialogName === "cell" ? [borderWidth].concat(advTabItems) : advTabItems;
    return {
      title: "Advanced",
      name: "advanced",
      items
    };
  };
  const normal = (editor, element) => {
    const dom = editor.dom;
    const setAttrib = (attr, value) => {
      dom.setAttrib(element, attr, value);
    };
    const setStyle = (prop, value) => {
      dom.setStyle(element, prop, value);
    };
    const setFormat = (formatName, value) => {
      if (value === "") {
        editor.formatter.remove(formatName, { value: null }, element, true);
      } else {
        editor.formatter.apply(formatName, { value }, element);
      }
    };
    return {
      setAttrib,
      setStyle,
      setFormat
    };
  };
  const DomModifier = { normal };
  const isHeaderCell = isTag("th");
  const getRowHeaderType = (isHeaderRow, isHeaderCells) => {
    if (isHeaderRow && isHeaderCells) {
      return "sectionCells";
    } else if (isHeaderRow) {
      return "section";
    } else {
      return "cells";
    }
  };
  const getRowType$1 = (row) => {
    const isHeaderRow = row.section === "thead";
    const isHeaderCells = is(findCommonCellType(row.cells), "th");
    if (row.section === "tfoot") {
      return { type: "footer" };
    } else if (isHeaderRow || isHeaderCells) {
      return {
        type: "header",
        subType: getRowHeaderType(isHeaderRow, isHeaderCells)
      };
    } else {
      return { type: "body" };
    }
  };
  const findCommonCellType = (cells2) => {
    const headerCells = filter(cells2, (cell2) => isHeaderCell(cell2.element));
    if (headerCells.length === 0) {
      return Optional.some("td");
    } else if (headerCells.length === cells2.length) {
      return Optional.some("th");
    } else {
      return Optional.none();
    }
  };
  const findCommonRowType = (rows2) => {
    const rowTypes = map(rows2, (row) => getRowType$1(row).type);
    const hasHeader = contains(rowTypes, "header");
    const hasFooter = contains(rowTypes, "footer");
    if (!hasHeader && !hasFooter) {
      return Optional.some("body");
    } else {
      const hasBody = contains(rowTypes, "body");
      if (hasHeader && !hasBody && !hasFooter) {
        return Optional.some("header");
      } else if (!hasHeader && !hasBody && hasFooter) {
        return Optional.some("footer");
      } else {
        return Optional.none();
      }
    }
  };
  const cached = (f) => {
    let called = false;
    let r;
    return (...args) => {
      if (!called) {
        called = true;
        r = f.apply(null, args);
      }
      return r;
    };
  };
  const findInWarehouse = (warehouse, element) => findMap(warehouse.all, (r) => find(r.cells, (e) => eq(element, e.element)));
  const extractCells = (warehouse, target, predicate) => {
    const details = map(target.selection, (cell$1) => {
      return cell(cell$1).bind((lc) => findInWarehouse(warehouse, lc)).filter(predicate);
    });
    const cells2 = cat(details);
    return someIf(cells2.length > 0, cells2);
  };
  const onMergable = (_warehouse, target) => target.mergable;
  const onUnmergable = (_warehouse, target) => target.unmergable;
  const onCells = (warehouse, target) => extractCells(warehouse, target, always);
  const isUnlockedTableCell = (warehouse, cell2) => findInWarehouse(warehouse, cell2).exists((detail2) => !detail2.isLocked);
  const allUnlocked = (warehouse, cells2) => forall(cells2, (cell2) => isUnlockedTableCell(warehouse, cell2));
  const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter((mergeable) => allUnlocked(warehouse, mergeable.cells));
  const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter((cells2) => allUnlocked(warehouse, cells2));
  const generate = (cases) => {
    if (!isArray(cases)) {
      throw new Error("cases must be an array");
    }
    if (cases.length === 0) {
      throw new Error("there must be at least one case");
    }
    const constructors = [];
    const adt2 = {};
    each(cases, (acase, count) => {
      const keys$1 = keys(acase);
      if (keys$1.length !== 1) {
        throw new Error("one and only one name per case");
      }
      const key2 = keys$1[0];
      const value = acase[key2];
      if (adt2[key2] !== void 0) {
        throw new Error("duplicate key detected:" + key2);
      } else if (key2 === "cata") {
        throw new Error("cannot have a case named cata (sorry)");
      } else if (!isArray(value)) {
        throw new Error("case arguments must be an array");
      }
      constructors.push(key2);
      adt2[key2] = (...args) => {
        const argLength = args.length;
        if (argLength !== value.length) {
          throw new Error("Wrong number of arguments to case " + key2 + ". Expected " + value.length + " (" + value + "), got " + argLength);
        }
        const match = (branches) => {
          const branchKeys = keys(branches);
          if (constructors.length !== branchKeys.length) {
            throw new Error("Wrong number of arguments to match. Expected: " + constructors.join(",") + "\nActual: " + branchKeys.join(","));
          }
          const allReqd = forall(constructors, (reqKey) => {
            return contains(branchKeys, reqKey);
          });
          if (!allReqd) {
            throw new Error("Not all branches were specified when using match. Specified: " + branchKeys.join(", ") + "\nRequired: " + constructors.join(", "));
          }
          return branches[key2].apply(null, args);
        };
        return {
          fold: (...foldArgs) => {
            if (foldArgs.length !== cases.length) {
              throw new Error("Wrong number of arguments to fold. Expected " + cases.length + ", got " + foldArgs.length);
            }
            const target = foldArgs[count];
            return target.apply(null, args);
          },
          match,
          log: (label) => {
            console.log(label, {
              constructors,
              constructor: key2,
              params: args
            });
          }
        };
      };
    });
    return adt2;
  };
  const Adt = { generate };
  const adt = Adt.generate([
    { none: [] },
    { only: ["index"] },
    {
      left: [
        "index",
        "next"
      ]
    },
    {
      middle: [
        "prev",
        "index",
        "next"
      ]
    },
    {
      right: [
        "prev",
        "index"
      ]
    }
  ]);
  ({ ...adt });
  const opGetRowsType = (table2, target) => {
    const house = Warehouse.fromTable(table2);
    const details = onCells(house, target);
    return details.bind((selectedCells) => {
      const lastSelectedCell = selectedCells[selectedCells.length - 1];
      const minRowRange = selectedCells[0].row;
      const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan;
      const selectedRows = house.all.slice(minRowRange, maxRowRange);
      return findCommonRowType(selectedRows);
    }).getOr("");
  };
  const getRowsType = opGetRowsType;
  const rgbToHex = (value) => startsWith(value, "rgb") ? rgbaToHexString(value) : value;
  const extractAdvancedStyles = (elm) => {
    const element = SugarElement.fromDom(elm);
    return {
      borderwidth: getRaw(element, "border-width").getOr(""),
      borderstyle: getRaw(element, "border-style").getOr(""),
      bordercolor: getRaw(element, "border-color").map(rgbToHex).getOr(""),
      backgroundcolor: getRaw(element, "background-color").map(rgbToHex).getOr("")
    };
  };
  const getSharedValues = (data) => {
    const baseData = data[0];
    const comparisonData = data.slice(1);
    each(comparisonData, (items) => {
      each(keys(baseData), (key2) => {
        each$1(items, (itemValue, itemKey) => {
          const comparisonValue = baseData[key2];
          if (comparisonValue !== "" && key2 === itemKey) {
            if (comparisonValue !== itemValue) {
              baseData[key2] = "";
            }
          }
        });
      });
    });
    return baseData;
  };
  const getAlignment = (formats, formatName, editor, elm) => find(formats, (name2) => !isUndefined(editor.formatter.matchNode(elm, formatName + name2))).getOr("");
  const getHAlignment = curry(getAlignment, [
    "left",
    "center",
    "right"
  ], "align");
  const getVAlignment = curry(getAlignment, [
    "top",
    "middle",
    "bottom"
  ], "valign");
  const extractDataFromSettings = (editor, hasAdvTableTab) => {
    const style = getDefaultStyles(editor);
    const attrs = getDefaultAttributes(editor);
    const extractAdvancedStyleData = () => ({
      borderstyle: get$4(style, "border-style").getOr(""),
      bordercolor: rgbToHex(get$4(style, "border-color").getOr("")),
      backgroundcolor: rgbToHex(get$4(style, "background-color").getOr(""))
    });
    const defaultData = {
      height: "",
      width: "100%",
      cellspacing: "",
      cellpadding: "",
      caption: false,
      class: "",
      align: "",
      border: ""
    };
    const getBorder = () => {
      const borderWidth = style["border-width"];
      if (shouldStyleWithCss(editor) && borderWidth) {
        return { border: borderWidth };
      }
      return get$4(attrs, "border").fold(() => ({}), (border) => ({ border }));
    };
    const advStyle = hasAdvTableTab ? extractAdvancedStyleData() : {};
    const getCellPaddingCellSpacing = () => {
      const spacing = get$4(style, "border-spacing").or(get$4(attrs, "cellspacing")).fold(() => ({}), (cellspacing) => ({ cellspacing }));
      const padding = get$4(style, "border-padding").or(get$4(attrs, "cellpadding")).fold(() => ({}), (cellpadding) => ({ cellpadding }));
      return {
        ...spacing,
        ...padding
      };
    };
    const data = {
      ...defaultData,
      ...style,
      ...attrs,
      ...advStyle,
      ...getBorder(),
      ...getCellPaddingCellSpacing()
    };
    return data;
  };
  const getRowType = (elm) => table(SugarElement.fromDom(elm)).map((table2) => {
    const target = { selection: fromDom(elm.cells) };
    return getRowsType(table2, target);
  }).getOr("");
  const extractDataFromTableElement = (editor, elm, hasAdvTableTab) => {
    const getBorder = (dom2, elm2) => {
      const optBorderWidth = getRaw(SugarElement.fromDom(elm2), "border-width");
      if (shouldStyleWithCss(editor) && optBorderWidth.isSome()) {
        return optBorderWidth.getOr("");
      }
      return dom2.getAttrib(elm2, "border") || getTDTHOverallStyle(editor.dom, elm2, "border-width") || getTDTHOverallStyle(editor.dom, elm2, "border");
    };
    const dom = editor.dom;
    const cellspacing = shouldStyleWithCss(editor) ? dom.getStyle(elm, "border-spacing") || dom.getAttrib(elm, "cellspacing") : dom.getAttrib(elm, "cellspacing") || dom.getStyle(elm, "border-spacing");
    const cellpadding = shouldStyleWithCss(editor) ? getTDTHOverallStyle(dom, elm, "padding") || dom.getAttrib(elm, "cellpadding") : dom.getAttrib(elm, "cellpadding") || getTDTHOverallStyle(dom, elm, "padding");
    return {
      width: dom.getStyle(elm, "width") || dom.getAttrib(elm, "width"),
      height: dom.getStyle(elm, "height") || dom.getAttrib(elm, "height"),
      cellspacing,
      cellpadding,
      border: getBorder(dom, elm),
      caption: !!dom.select("caption", elm)[0],
      class: dom.getAttrib(elm, "class", ""),
      align: getHAlignment(editor, elm),
      ...hasAdvTableTab ? extractAdvancedStyles(elm) : {}
    };
  };
  const extractDataFromRowElement = (editor, elm, hasAdvancedRowTab2) => {
    const dom = editor.dom;
    return {
      height: dom.getStyle(elm, "height") || dom.getAttrib(elm, "height"),
      class: dom.getAttrib(elm, "class", ""),
      type: getRowType(elm),
      align: getHAlignment(editor, elm),
      ...hasAdvancedRowTab2 ? extractAdvancedStyles(elm) : {}
    };
  };
  const extractDataFromCellElement = (editor, cell2, hasAdvancedCellTab2, column) => {
    const dom = editor.dom;
    const colElm = column.getOr(cell2);
    const getStyle = (element, style) => dom.getStyle(element, style) || dom.getAttrib(element, style);
    return {
      width: getStyle(colElm, "width"),
      height: getStyle(cell2, "height"),
      scope: dom.getAttrib(cell2, "scope"),
      celltype: getNodeName(cell2),
      class: dom.getAttrib(cell2, "class", ""),
      halign: getHAlignment(editor, cell2),
      valign: getVAlignment(editor, cell2),
      ...hasAdvancedCellTab2 ? extractAdvancedStyles(cell2) : {}
    };
  };
  const getSelectedCells = (table2, cells2) => {
    const warehouse = Warehouse.fromTable(table2);
    const allCells = Warehouse.justCells(warehouse);
    const filtered = filter(allCells, (cellA) => exists(cells2, (cellB) => eq(cellA.element, cellB)));
    return map(filtered, (cell2) => ({
      element: cell2.element.dom,
      column: Warehouse.getColumnAt(warehouse, cell2.column).map((col) => col.element.dom)
    }));
  };
  const updateSimpleProps$1 = (modifier, colModifier, data, shouldUpdate) => {
    if (shouldUpdate("scope")) {
      modifier.setAttrib("scope", data.scope);
    }
    if (shouldUpdate("class")) {
      modifier.setAttrib("class", data.class);
    }
    if (shouldUpdate("height")) {
      modifier.setStyle("height", addPxSuffix(data.height));
    }
    if (shouldUpdate("width")) {
      colModifier.setStyle("width", addPxSuffix(data.width));
    }
  };
  const updateAdvancedProps$1 = (modifier, data, shouldUpdate) => {
    if (shouldUpdate("backgroundcolor")) {
      modifier.setFormat("tablecellbackgroundcolor", data.backgroundcolor);
    }
    if (shouldUpdate("bordercolor")) {
      modifier.setFormat("tablecellbordercolor", data.bordercolor);
    }
    if (shouldUpdate("borderstyle")) {
      modifier.setFormat("tablecellborderstyle", data.borderstyle);
    }
    if (shouldUpdate("borderwidth")) {
      modifier.setFormat("tablecellborderwidth", addPxSuffix(data.borderwidth));
    }
  };
  const applyStyleData$1 = (editor, cells2, data, wasChanged) => {
    const isSingleCell = cells2.length === 1;
    each(cells2, (item) => {
      const cellElm = item.element;
      const shouldOverrideCurrentValue = isSingleCell ? always : wasChanged;
      const modifier = DomModifier.normal(editor, cellElm);
      const colModifier = item.column.map((col) => DomModifier.normal(editor, col)).getOr(modifier);
      updateSimpleProps$1(modifier, colModifier, data, shouldOverrideCurrentValue);
      if (hasAdvancedCellTab(editor)) {
        updateAdvancedProps$1(modifier, data, shouldOverrideCurrentValue);
      }
      if (wasChanged("halign")) {
        setAlign(editor, cellElm, data.halign);
      }
      if (wasChanged("valign")) {
        setVAlign(editor, cellElm, data.valign);
      }
    });
  };
  const applyStructureData$1 = (editor, data) => {
    editor.execCommand("mceTableCellType", false, {
      type: data.celltype,
      no_events: true
    });
  };
  const applyCellData = (editor, cells2, oldData, data) => {
    const modifiedData = filter$1(data, (value, key2) => oldData[key2] !== value);
    if (size(modifiedData) > 0 && cells2.length >= 1) {
      table(cells2[0]).each((table2) => {
        const selectedCells = getSelectedCells(table2, cells2);
        const styleModified = size(filter$1(modifiedData, (_value, key2) => key2 !== "scope" && key2 !== "celltype")) > 0;
        const structureModified = has(modifiedData, "celltype");
        if (styleModified || has(modifiedData, "scope")) {
          applyStyleData$1(editor, selectedCells, data, curry(has, modifiedData));
        }
        if (structureModified) {
          applyStructureData$1(editor, data);
        }
        fireTableModified(editor, table2.dom, {
          structure: structureModified,
          style: styleModified
        });
      });
    }
  };
  const onSubmitCellForm = (editor, cells2, oldData, api2) => {
    const data = api2.getData();
    api2.close();
    editor.undoManager.transact(() => {
      applyCellData(editor, cells2, oldData, data);
      editor.focus();
    });
  };
  const getData$1 = (editor, cells2) => {
    const cellsData = table(cells2[0]).map((table2) => map(getSelectedCells(table2, cells2), (item) => extractDataFromCellElement(editor, item.element, hasAdvancedCellTab(editor), item.column)));
    return getSharedValues(cellsData.getOrDie());
  };
  const open$2 = (editor) => {
    const cells2 = getCellsFromSelection(editor);
    if (cells2.length === 0) {
      return;
    }
    const data = getData$1(editor, cells2);
    const dialogTabPanel = {
      type: "tabpanel",
      tabs: [
        {
          title: "General",
          name: "general",
          items: getItems$2(editor)
        },
        getAdvancedTab(editor, "cell")
      ]
    };
    const dialogPanel = {
      type: "panel",
      items: [{
        type: "grid",
        columns: 2,
        items: getItems$2(editor)
      }]
    };
    editor.windowManager.open({
      title: "Cell Properties",
      size: "normal",
      body: hasAdvancedCellTab(editor) ? dialogTabPanel : dialogPanel,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData: data,
      onSubmit: curry(onSubmitCellForm, editor, cells2, data)
    });
  };
  const getClassList = (editor) => {
    const classes = buildListItems(getRowClassList(editor));
    if (classes.length > 0) {
      return Optional.some({
        name: "class",
        type: "listbox",
        label: "Class",
        items: classes
      });
    }
    return Optional.none();
  };
  const formChildren = [
    {
      type: "listbox",
      name: "type",
      label: "Row type",
      items: [
        {
          text: "Header",
          value: "header"
        },
        {
          text: "Body",
          value: "body"
        },
        {
          text: "Footer",
          value: "footer"
        }
      ]
    },
    {
      type: "listbox",
      name: "align",
      label: "Alignment",
      items: [
        {
          text: "None",
          value: ""
        },
        {
          text: "Left",
          value: "left"
        },
        {
          text: "Center",
          value: "center"
        },
        {
          text: "Right",
          value: "right"
        }
      ]
    },
    {
      label: "Height",
      name: "height",
      type: "input"
    }
  ];
  const getItems$1 = (editor) => formChildren.concat(getClassList(editor).toArray());
  const updateSimpleProps = (modifier, data, shouldUpdate) => {
    if (shouldUpdate("class")) {
      modifier.setAttrib("class", data.class);
    }
    if (shouldUpdate("height")) {
      modifier.setStyle("height", addPxSuffix(data.height));
    }
  };
  const updateAdvancedProps = (modifier, data, shouldUpdate) => {
    if (shouldUpdate("backgroundcolor")) {
      modifier.setStyle("background-color", data.backgroundcolor);
    }
    if (shouldUpdate("bordercolor")) {
      modifier.setStyle("border-color", data.bordercolor);
    }
    if (shouldUpdate("borderstyle")) {
      modifier.setStyle("border-style", data.borderstyle);
    }
  };
  const applyStyleData = (editor, rows2, data, wasChanged) => {
    const isSingleRow = rows2.length === 1;
    const shouldOverrideCurrentValue = isSingleRow ? always : wasChanged;
    each(rows2, (rowElm) => {
      const modifier = DomModifier.normal(editor, rowElm);
      updateSimpleProps(modifier, data, shouldOverrideCurrentValue);
      if (hasAdvancedRowTab(editor)) {
        updateAdvancedProps(modifier, data, shouldOverrideCurrentValue);
      }
      if (wasChanged("align")) {
        setAlign(editor, rowElm, data.align);
      }
    });
  };
  const applyStructureData = (editor, data) => {
    editor.execCommand("mceTableRowType", false, {
      type: data.type,
      no_events: true
    });
  };
  const applyRowData = (editor, rows2, oldData, data) => {
    const modifiedData = filter$1(data, (value, key2) => oldData[key2] !== value);
    if (size(modifiedData) > 0) {
      const typeModified = has(modifiedData, "type");
      const styleModified = typeModified ? size(modifiedData) > 1 : true;
      if (styleModified) {
        applyStyleData(editor, rows2, data, curry(has, modifiedData));
      }
      if (typeModified) {
        applyStructureData(editor, data);
      }
      table(SugarElement.fromDom(rows2[0])).each((table2) => fireTableModified(editor, table2.dom, {
        structure: typeModified,
        style: styleModified
      }));
    }
  };
  const onSubmitRowForm = (editor, rows2, oldData, api2) => {
    const data = api2.getData();
    api2.close();
    editor.undoManager.transact(() => {
      applyRowData(editor, rows2, oldData, data);
      editor.focus();
    });
  };
  const open$1 = (editor) => {
    const rows2 = getRowsFromSelection(getSelectionStart(editor), ephemera.selected);
    if (rows2.length === 0) {
      return;
    }
    const rowsData = map(rows2, (rowElm) => extractDataFromRowElement(editor, rowElm.dom, hasAdvancedRowTab(editor)));
    const data = getSharedValues(rowsData);
    const dialogTabPanel = {
      type: "tabpanel",
      tabs: [
        {
          title: "General",
          name: "general",
          items: getItems$1(editor)
        },
        getAdvancedTab(editor, "row")
      ]
    };
    const dialogPanel = {
      type: "panel",
      items: [{
        type: "grid",
        columns: 2,
        items: getItems$1(editor)
      }]
    };
    editor.windowManager.open({
      title: "Row Properties",
      size: "normal",
      body: hasAdvancedRowTab(editor) ? dialogTabPanel : dialogPanel,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData: data,
      onSubmit: curry(onSubmitRowForm, editor, map(rows2, (r) => r.dom), data)
    });
  };
  const getItems = (editor, classes, insertNewTable) => {
    const rowColCountItems = !insertNewTable ? [] : [
      {
        type: "input",
        name: "cols",
        label: "Cols",
        inputMode: "numeric"
      },
      {
        type: "input",
        name: "rows",
        label: "Rows",
        inputMode: "numeric"
      }
    ];
    const alwaysItems = [
      {
        type: "input",
        name: "width",
        label: "Width"
      },
      {
        type: "input",
        name: "height",
        label: "Height"
      }
    ];
    const appearanceItems = hasAppearanceOptions(editor) ? [
      {
        type: "input",
        name: "cellspacing",
        label: "Cell spacing",
        inputMode: "numeric"
      },
      {
        type: "input",
        name: "cellpadding",
        label: "Cell padding",
        inputMode: "numeric"
      },
      {
        type: "input",
        name: "border",
        label: "Border width"
      },
      {
        type: "label",
        label: "Caption",
        items: [{
          type: "checkbox",
          name: "caption",
          label: "Show caption"
        }]
      }
    ] : [];
    const alignmentItem = [{
      type: "listbox",
      name: "align",
      label: "Alignment",
      items: [
        {
          text: "None",
          value: ""
        },
        {
          text: "Left",
          value: "left"
        },
        {
          text: "Center",
          value: "center"
        },
        {
          text: "Right",
          value: "right"
        }
      ]
    }];
    const classListItem = classes.length > 0 ? [{
      type: "listbox",
      name: "class",
      label: "Class",
      items: classes
    }] : [];
    return rowColCountItems.concat(alwaysItems).concat(appearanceItems).concat(alignmentItem).concat(classListItem);
  };
  const styleTDTH = (dom, elm, name2, value) => {
    if (elm.tagName === "TD" || elm.tagName === "TH") {
      if (isString(name2)) {
        dom.setStyle(elm, name2, value);
      } else {
        dom.setStyles(elm, name2);
      }
    } else {
      if (elm.children) {
        for (let i = 0; i < elm.children.length; i++) {
          styleTDTH(dom, elm.children[i], name2, value);
        }
      }
    }
  };
  const applyDataToElement = (editor, tableElm, data) => {
    const dom = editor.dom;
    const attrs = {};
    const styles = {};
    attrs.class = data.class;
    styles.height = addPxSuffix(data.height);
    if (shouldStyleWithCss(editor)) {
      styles.width = addPxSuffix(data.width);
    } else if (dom.getAttrib(tableElm, "width")) {
      attrs.width = removePxSuffix(data.width);
    }
    if (shouldStyleWithCss(editor)) {
      styles["border-width"] = addPxSuffix(data.border);
      styles["border-spacing"] = addPxSuffix(data.cellspacing);
    } else {
      attrs.border = data.border;
      attrs.cellpadding = data.cellpadding;
      attrs.cellspacing = data.cellspacing;
    }
    if (shouldStyleWithCss(editor) && tableElm.children) {
      for (let i = 0; i < tableElm.children.length; i++) {
        styleTDTH(dom, tableElm.children[i], {
          "border-width": addPxSuffix(data.border),
          "padding": addPxSuffix(data.cellpadding)
        });
        if (hasAdvancedTableTab(editor)) {
          styleTDTH(dom, tableElm.children[i], { "border-color": data.bordercolor });
        }
      }
    }
    if (hasAdvancedTableTab(editor)) {
      styles["background-color"] = data.backgroundcolor;
      styles["border-color"] = data.bordercolor;
      styles["border-style"] = data.borderstyle;
    }
    attrs.style = dom.serializeStyle({
      ...getDefaultStyles(editor),
      ...styles
    });
    dom.setAttribs(tableElm, {
      ...getDefaultAttributes(editor),
      ...attrs
    });
  };
  const onSubmitTableForm = (editor, tableElm, oldData, api2) => {
    const dom = editor.dom;
    const data = api2.getData();
    const modifiedData = filter$1(data, (value, key2) => oldData[key2] !== value);
    api2.close();
    if (data.class === "") {
      delete data.class;
    }
    editor.undoManager.transact(() => {
      if (!tableElm) {
        const cols = parseInt(data.cols, 10) || 1;
        const rows2 = parseInt(data.rows, 10) || 1;
        editor.execCommand("mceInsertTable", false, {
          rows: rows2,
          columns: cols
        });
        tableElm = getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).bind((cell2) => table(cell2, getIsRoot(editor))).map((table2) => table2.dom).getOrUndefined();
      }
      if (size(modifiedData) > 0) {
        applyDataToElement(editor, tableElm, data);
        const captionElm = dom.select("caption", tableElm)[0];
        if (captionElm && !data.caption || !captionElm && data.caption) {
          editor.execCommand("mceTableToggleCaption");
        }
        setAlign(editor, tableElm, data.align);
      }
      editor.focus();
      editor.addVisual();
      if (size(modifiedData) > 0) {
        const captionModified = has(modifiedData, "caption");
        const styleModified = captionModified ? size(modifiedData) > 1 : true;
        fireTableModified(editor, tableElm, {
          structure: captionModified,
          style: styleModified
        });
      }
    });
  };
  const open = (editor, insertNewTable) => {
    const dom = editor.dom;
    let tableElm;
    let data = extractDataFromSettings(editor, hasAdvancedTableTab(editor));
    if (insertNewTable === false) {
      tableElm = dom.getParent(editor.selection.getStart(), "table", editor.getBody());
      if (tableElm) {
        data = extractDataFromTableElement(editor, tableElm, hasAdvancedTableTab(editor));
      } else {
        if (hasAdvancedTableTab(editor)) {
          data.borderstyle = "";
          data.bordercolor = "";
          data.backgroundcolor = "";
        }
      }
    } else {
      data.cols = "1";
      data.rows = "1";
      if (hasAdvancedTableTab(editor)) {
        data.borderstyle = "";
        data.bordercolor = "";
        data.backgroundcolor = "";
      }
    }
    const classes = buildListItems(getTableClassList(editor));
    if (classes.length > 0) {
      if (data.class) {
        data.class = data.class.replace(/\s*mce\-item\-table\s*/g, "");
      }
    }
    const generalPanel = {
      type: "grid",
      columns: 2,
      items: getItems(editor, classes, insertNewTable)
    };
    const nonAdvancedForm = () => ({
      type: "panel",
      items: [generalPanel]
    });
    const advancedForm = () => ({
      type: "tabpanel",
      tabs: [
        {
          title: "General",
          name: "general",
          items: [generalPanel]
        },
        getAdvancedTab(editor, "table")
      ]
    });
    const dialogBody = hasAdvancedTableTab(editor) ? advancedForm() : nonAdvancedForm();
    editor.windowManager.open({
      title: "Table Properties",
      size: "normal",
      body: dialogBody,
      onSubmit: curry(onSubmitTableForm, editor, tableElm, data),
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData: data
    });
  };
  const registerCommands = (editor) => {
    each$1({
      mceTableProps: curry(open, editor, false),
      mceTableRowProps: curry(open$1, editor),
      mceTableCellProps: curry(open$2, editor)
    }, (func, name2) => editor.addCommand(name2, () => func()));
    editor.addCommand("mceInsertTableDialog", (_ui) => {
      open(editor, true);
    });
  };
  const child = (scope, selector) => child$1(scope, selector).isSome();
  const selection = identity;
  const unmergable = (selectedCells) => {
    const hasSpan = (elem, type2) => getOpt(elem, type2).exists((span) => parseInt(span, 10) > 1);
    const hasRowOrColSpan = (elem) => hasSpan(elem, "rowspan") || hasSpan(elem, "colspan");
    return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none();
  };
  const mergable = (table2, selectedCells, ephemera2) => {
    if (selectedCells.length <= 1) {
      return Optional.none();
    } else {
      return retrieveBox(table2, ephemera2.firstSelectedSelector, ephemera2.lastSelectedSelector).map((bounds2) => ({
        bounds: bounds2,
        cells: selectedCells
      }));
    }
  };
  const noMenu = (cell2) => ({
    element: cell2,
    mergable: Optional.none(),
    unmergable: Optional.none(),
    selection: [cell2]
  });
  const forMenu = (selectedCells, table2, cell2) => ({
    element: cell2,
    mergable: mergable(table2, selectedCells, ephemera),
    unmergable: unmergable(selectedCells),
    selection: selection(selectedCells)
  });
  const getSelectionTargets = (editor) => {
    const targets = Cell(Optional.none());
    const changeHandlers = Cell([]);
    let selectionDetails = Optional.none();
    const isCaption = isTag("caption");
    const isDisabledForSelection = (key2) => selectionDetails.forall((details) => !details[key2]);
    const getStart = () => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor));
    const getEnd = () => getSelectionCellOrCaption(getSelectionEnd(editor), getIsRoot(editor));
    const findTargets = () => getStart().bind((startCellOrCaption) => flatten(lift2(table(startCellOrCaption), getEnd().bind(table), (startTable, endTable) => {
      if (eq(startTable, endTable)) {
        if (isCaption(startCellOrCaption)) {
          return Optional.some(noMenu(startCellOrCaption));
        } else {
          return Optional.some(forMenu(getCellsFromSelection(editor), startTable, startCellOrCaption));
        }
      }
      return Optional.none();
    })));
    const getExtractedDetails = (targets2) => {
      const tableOpt = table(targets2.element);
      return tableOpt.map((table2) => {
        const warehouse = Warehouse.fromTable(table2);
        const selectedCells = onCells(warehouse, targets2).getOr([]);
        const locked = foldl(selectedCells, (acc, cell2) => {
          if (cell2.isLocked) {
            acc.onAny = true;
            if (cell2.column === 0) {
              acc.onFirst = true;
            } else if (cell2.column + cell2.colspan >= warehouse.grid.columns) {
              acc.onLast = true;
            }
          }
          return acc;
        }, {
          onAny: false,
          onFirst: false,
          onLast: false
        });
        return {
          mergeable: onUnlockedMergable(warehouse, targets2).isSome(),
          unmergeable: onUnlockedUnmergable(warehouse, targets2).isSome(),
          locked
        };
      });
    };
    const resetTargets = () => {
      targets.set(cached(findTargets)());
      selectionDetails = targets.get().bind(getExtractedDetails);
      each(changeHandlers.get(), (handler) => handler());
    };
    const setupHandler = (handler) => {
      handler();
      changeHandlers.set(changeHandlers.get().concat([handler]));
      return () => {
        changeHandlers.set(filter(changeHandlers.get(), (h2) => h2 !== handler));
      };
    };
    const onSetup = (api2, isDisabled) => setupHandler(() => targets.get().fold(() => {
      api2.setEnabled(false);
    }, (targets2) => {
      api2.setEnabled(!isDisabled(targets2));
    }));
    const onSetupWithToggle = (api2, isDisabled, isActive) => setupHandler(() => targets.get().fold(() => {
      api2.setEnabled(false);
      api2.setActive(false);
    }, (targets2) => {
      api2.setEnabled(!isDisabled(targets2));
      api2.setActive(isActive(targets2));
    }));
    const isDisabledFromLocked = (lockedDisable) => selectionDetails.exists((details) => details.locked[lockedDisable]);
    const onSetupTable = (api2) => onSetup(api2, (_) => false);
    const onSetupCellOrRow = (api2) => onSetup(api2, (targets2) => isCaption(targets2.element));
    const onSetupColumn = (lockedDisable) => (api2) => onSetup(api2, (targets2) => isCaption(targets2.element) || isDisabledFromLocked(lockedDisable));
    const onSetupPasteable = (getClipboardData) => (api2) => onSetup(api2, (targets2) => isCaption(targets2.element) || getClipboardData().isNone());
    const onSetupPasteableColumn = (getClipboardData, lockedDisable) => (api2) => onSetup(api2, (targets2) => isCaption(targets2.element) || getClipboardData().isNone() || isDisabledFromLocked(lockedDisable));
    const onSetupMergeable = (api2) => onSetup(api2, (_targets) => isDisabledForSelection("mergeable"));
    const onSetupUnmergeable = (api2) => onSetup(api2, (_targets) => isDisabledForSelection("unmergeable"));
    const onSetupTableWithCaption = (api2) => {
      return onSetupWithToggle(api2, never, (targets2) => {
        const tableOpt = table(targets2.element, getIsRoot(editor));
        return tableOpt.exists((table2) => child(table2, "caption"));
      });
    };
    const onSetupTableHeaders = (command, headerType) => (api2) => {
      return onSetupWithToggle(api2, (targets2) => isCaption(targets2.element), () => editor.queryCommandValue(command) === headerType);
    };
    const onSetupTableRowHeaders = onSetupTableHeaders("mceTableRowType", "header");
    const onSetupTableColumnHeaders = onSetupTableHeaders("mceTableColType", "th");
    editor.on("NodeChange ExecCommand TableSelectorChange", resetTargets);
    return {
      onSetupTable,
      onSetupCellOrRow,
      onSetupColumn,
      onSetupPasteable,
      onSetupPasteableColumn,
      onSetupMergeable,
      onSetupUnmergeable,
      resetTargets,
      onSetupTableWithCaption,
      onSetupTableRowHeaders,
      onSetupTableColumnHeaders,
      targets: targets.get
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.FakeClipboard");
  const tableTypeBase = "x-tinymce/dom-table-";
  const tableTypeRow = tableTypeBase + "rows";
  const tableTypeColumn = tableTypeBase + "columns";
  const getData = (type2) => {
    var _a;
    const items = (_a = global2.read()) !== null && _a !== void 0 ? _a : [];
    return findMap(items, (item) => Optional.from(item.getType(type2)));
  };
  const getRows = () => getData(tableTypeRow);
  const getColumns = () => getData(tableTypeColumn);
  const addButtons = (editor, selectionTargets) => {
    editor.ui.registry.addMenuButton("table", {
      tooltip: "Table",
      icon: "table",
      fetch: (callback) => callback("inserttable | cell row column | advtablesort | tableprops deletetable")
    });
    const cmd = (command) => () => editor.execCommand(command);
    const addButtonIfRegistered = (name2, spec) => {
      if (editor.queryCommandSupported(spec.command)) {
        editor.ui.registry.addButton(name2, {
          ...spec,
          onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
        });
      }
    };
    const addToggleButtonIfRegistered = (name2, spec) => {
      if (editor.queryCommandSupported(spec.command)) {
        editor.ui.registry.addToggleButton(name2, {
          ...spec,
          onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
        });
      }
    };
    addButtonIfRegistered("tableprops", {
      tooltip: "Table properties",
      command: "mceTableProps",
      icon: "table",
      onSetup: selectionTargets.onSetupTable
    });
    addButtonIfRegistered("tabledelete", {
      tooltip: "Delete table",
      command: "mceTableDelete",
      icon: "table-delete-table",
      onSetup: selectionTargets.onSetupTable
    });
    addButtonIfRegistered("tablecellprops", {
      tooltip: "Cell properties",
      command: "mceTableCellProps",
      icon: "table-cell-properties",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tablemergecells", {
      tooltip: "Merge cells",
      command: "mceTableMergeCells",
      icon: "table-merge-cells",
      onSetup: selectionTargets.onSetupMergeable
    });
    addButtonIfRegistered("tablesplitcells", {
      tooltip: "Split cell",
      command: "mceTableSplitCells",
      icon: "table-split-cells",
      onSetup: selectionTargets.onSetupUnmergeable
    });
    addButtonIfRegistered("tableinsertrowbefore", {
      tooltip: "Insert row before",
      command: "mceTableInsertRowBefore",
      icon: "table-insert-row-above",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tableinsertrowafter", {
      tooltip: "Insert row after",
      command: "mceTableInsertRowAfter",
      icon: "table-insert-row-after",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tabledeleterow", {
      tooltip: "Delete row",
      command: "mceTableDeleteRow",
      icon: "table-delete-row",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tablerowprops", {
      tooltip: "Row properties",
      command: "mceTableRowProps",
      icon: "table-row-properties",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tableinsertcolbefore", {
      tooltip: "Insert column before",
      command: "mceTableInsertColBefore",
      icon: "table-insert-column-before",
      onSetup: selectionTargets.onSetupColumn("onFirst")
    });
    addButtonIfRegistered("tableinsertcolafter", {
      tooltip: "Insert column after",
      command: "mceTableInsertColAfter",
      icon: "table-insert-column-after",
      onSetup: selectionTargets.onSetupColumn("onLast")
    });
    addButtonIfRegistered("tabledeletecol", {
      tooltip: "Delete column",
      command: "mceTableDeleteCol",
      icon: "table-delete-column",
      onSetup: selectionTargets.onSetupColumn("onAny")
    });
    addButtonIfRegistered("tablecutrow", {
      tooltip: "Cut row",
      command: "mceTableCutRow",
      icon: "cut-row",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tablecopyrow", {
      tooltip: "Copy row",
      command: "mceTableCopyRow",
      icon: "duplicate-row",
      onSetup: selectionTargets.onSetupCellOrRow
    });
    addButtonIfRegistered("tablepasterowbefore", {
      tooltip: "Paste row before",
      command: "mceTablePasteRowBefore",
      icon: "paste-row-before",
      onSetup: selectionTargets.onSetupPasteable(getRows)
    });
    addButtonIfRegistered("tablepasterowafter", {
      tooltip: "Paste row after",
      command: "mceTablePasteRowAfter",
      icon: "paste-row-after",
      onSetup: selectionTargets.onSetupPasteable(getRows)
    });
    addButtonIfRegistered("tablecutcol", {
      tooltip: "Cut column",
      command: "mceTableCutCol",
      icon: "cut-column",
      onSetup: selectionTargets.onSetupColumn("onAny")
    });
    addButtonIfRegistered("tablecopycol", {
      tooltip: "Copy column",
      command: "mceTableCopyCol",
      icon: "duplicate-column",
      onSetup: selectionTargets.onSetupColumn("onAny")
    });
    addButtonIfRegistered("tablepastecolbefore", {
      tooltip: "Paste column before",
      command: "mceTablePasteColBefore",
      icon: "paste-column-before",
      onSetup: selectionTargets.onSetupPasteableColumn(getColumns, "onFirst")
    });
    addButtonIfRegistered("tablepastecolafter", {
      tooltip: "Paste column after",
      command: "mceTablePasteColAfter",
      icon: "paste-column-after",
      onSetup: selectionTargets.onSetupPasteableColumn(getColumns, "onLast")
    });
    addButtonIfRegistered("tableinsertdialog", {
      tooltip: "Insert table",
      command: "mceInsertTableDialog",
      icon: "table"
    });
    const tableClassList = filterNoneItem(getTableClassList(editor));
    if (tableClassList.length !== 0 && editor.queryCommandSupported("mceTableToggleClass")) {
      editor.ui.registry.addMenuButton("tableclass", {
        icon: "table-classes",
        tooltip: "Table styles",
        fetch: generateMenuItemsCallback(editor, tableClassList, "tableclass", (value) => editor.execCommand("mceTableToggleClass", false, value)),
        onSetup: selectionTargets.onSetupTable
      });
    }
    const tableCellClassList = filterNoneItem(getCellClassList(editor));
    if (tableCellClassList.length !== 0 && editor.queryCommandSupported("mceTableCellToggleClass")) {
      editor.ui.registry.addMenuButton("tablecellclass", {
        icon: "table-cell-classes",
        tooltip: "Cell styles",
        fetch: generateMenuItemsCallback(editor, tableCellClassList, "tablecellclass", (value) => editor.execCommand("mceTableCellToggleClass", false, value)),
        onSetup: selectionTargets.onSetupCellOrRow
      });
    }
    if (editor.queryCommandSupported("mceTableApplyCellStyle")) {
      editor.ui.registry.addMenuButton("tablecellvalign", {
        icon: "vertical-align",
        tooltip: "Vertical align",
        fetch: generateMenuItemsCallback(editor, verticalAlignValues, "tablecellverticalalign", applyTableCellStyle(editor, "vertical-align")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addMenuButton("tablecellborderwidth", {
        icon: "border-width",
        tooltip: "Border width",
        fetch: generateMenuItemsCallback(editor, getTableBorderWidths(editor), "tablecellborderwidth", applyTableCellStyle(editor, "border-width")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addMenuButton("tablecellborderstyle", {
        icon: "border-style",
        tooltip: "Border style",
        fetch: generateMenuItemsCallback(editor, getTableBorderStyles(editor), "tablecellborderstyle", applyTableCellStyle(editor, "border-style")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addMenuButton("tablecellbackgroundcolor", {
        icon: "cell-background-color",
        tooltip: "Background color",
        fetch: (callback) => callback(buildColorMenu(editor, getTableBackgroundColorMap(editor), "background-color")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addMenuButton("tablecellbordercolor", {
        icon: "cell-border-color",
        tooltip: "Border color",
        fetch: (callback) => callback(buildColorMenu(editor, getTableBorderColorMap(editor), "border-color")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
    }
    addToggleButtonIfRegistered("tablecaption", {
      tooltip: "Table caption",
      icon: "table-caption",
      command: "mceTableToggleCaption",
      onSetup: selectionTargets.onSetupTableWithCaption
    });
    addToggleButtonIfRegistered("tablerowheader", {
      tooltip: "Row header",
      icon: "table-top-header",
      command: "mceTableRowType",
      onAction: changeRowHeader(editor),
      onSetup: selectionTargets.onSetupTableRowHeaders
    });
    addToggleButtonIfRegistered("tablecolheader", {
      tooltip: "Column header",
      icon: "table-left-header",
      command: "mceTableColType",
      onAction: changeColumnHeader(editor),
      onSetup: selectionTargets.onSetupTableColumnHeaders
    });
  };
  const addToolbars = (editor) => {
    const isTable = (table2) => editor.dom.is(table2, "table") && editor.getBody().contains(table2);
    const toolbar = getToolbar(editor);
    if (toolbar.length > 0) {
      editor.ui.registry.addContextToolbar("table", {
        predicate: isTable,
        items: toolbar,
        scope: "node",
        position: "node"
      });
    }
  };
  const addMenuItems = (editor, selectionTargets) => {
    const cmd = (command) => () => editor.execCommand(command);
    const addMenuIfRegistered = (name2, spec) => {
      if (editor.queryCommandSupported(spec.command)) {
        editor.ui.registry.addMenuItem(name2, {
          ...spec,
          onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
        });
        return true;
      } else {
        return false;
      }
    };
    const addToggleMenuIfRegistered = (name2, spec) => {
      if (editor.queryCommandSupported(spec.command)) {
        editor.ui.registry.addToggleMenuItem(name2, {
          ...spec,
          onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
        });
      }
    };
    const insertTableAction = (data) => {
      editor.execCommand("mceInsertTable", false, {
        rows: data.numRows,
        columns: data.numColumns
      });
    };
    const hasRowMenuItems = [
      addMenuIfRegistered("tableinsertrowbefore", {
        text: "Insert row before",
        icon: "table-insert-row-above",
        command: "mceTableInsertRowBefore",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tableinsertrowafter", {
        text: "Insert row after",
        icon: "table-insert-row-after",
        command: "mceTableInsertRowAfter",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tabledeleterow", {
        text: "Delete row",
        icon: "table-delete-row",
        command: "mceTableDeleteRow",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tablerowprops", {
        text: "Row properties",
        icon: "table-row-properties",
        command: "mceTableRowProps",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tablecutrow", {
        text: "Cut row",
        icon: "cut-row",
        command: "mceTableCutRow",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tablecopyrow", {
        text: "Copy row",
        icon: "duplicate-row",
        command: "mceTableCopyRow",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tablepasterowbefore", {
        text: "Paste row before",
        icon: "paste-row-before",
        command: "mceTablePasteRowBefore",
        onSetup: selectionTargets.onSetupPasteable(getRows)
      }),
      addMenuIfRegistered("tablepasterowafter", {
        text: "Paste row after",
        icon: "paste-row-after",
        command: "mceTablePasteRowAfter",
        onSetup: selectionTargets.onSetupPasteable(getRows)
      })
    ];
    const hasColumnMenuItems = [
      addMenuIfRegistered("tableinsertcolumnbefore", {
        text: "Insert column before",
        icon: "table-insert-column-before",
        command: "mceTableInsertColBefore",
        onSetup: selectionTargets.onSetupColumn("onFirst")
      }),
      addMenuIfRegistered("tableinsertcolumnafter", {
        text: "Insert column after",
        icon: "table-insert-column-after",
        command: "mceTableInsertColAfter",
        onSetup: selectionTargets.onSetupColumn("onLast")
      }),
      addMenuIfRegistered("tabledeletecolumn", {
        text: "Delete column",
        icon: "table-delete-column",
        command: "mceTableDeleteCol",
        onSetup: selectionTargets.onSetupColumn("onAny")
      }),
      addMenuIfRegistered("tablecutcolumn", {
        text: "Cut column",
        icon: "cut-column",
        command: "mceTableCutCol",
        onSetup: selectionTargets.onSetupColumn("onAny")
      }),
      addMenuIfRegistered("tablecopycolumn", {
        text: "Copy column",
        icon: "duplicate-column",
        command: "mceTableCopyCol",
        onSetup: selectionTargets.onSetupColumn("onAny")
      }),
      addMenuIfRegistered("tablepastecolumnbefore", {
        text: "Paste column before",
        icon: "paste-column-before",
        command: "mceTablePasteColBefore",
        onSetup: selectionTargets.onSetupPasteableColumn(getColumns, "onFirst")
      }),
      addMenuIfRegistered("tablepastecolumnafter", {
        text: "Paste column after",
        icon: "paste-column-after",
        command: "mceTablePasteColAfter",
        onSetup: selectionTargets.onSetupPasteableColumn(getColumns, "onLast")
      })
    ];
    const hasCellMenuItems = [
      addMenuIfRegistered("tablecellprops", {
        text: "Cell properties",
        icon: "table-cell-properties",
        command: "mceTableCellProps",
        onSetup: selectionTargets.onSetupCellOrRow
      }),
      addMenuIfRegistered("tablemergecells", {
        text: "Merge cells",
        icon: "table-merge-cells",
        command: "mceTableMergeCells",
        onSetup: selectionTargets.onSetupMergeable
      }),
      addMenuIfRegistered("tablesplitcells", {
        text: "Split cell",
        icon: "table-split-cells",
        command: "mceTableSplitCells",
        onSetup: selectionTargets.onSetupUnmergeable
      })
    ];
    if (!hasTableGrid(editor)) {
      editor.ui.registry.addMenuItem("inserttable", {
        text: "Table",
        icon: "table",
        onAction: cmd("mceInsertTableDialog")
      });
    } else {
      editor.ui.registry.addNestedMenuItem("inserttable", {
        text: "Table",
        icon: "table",
        getSubmenuItems: () => [{
          type: "fancymenuitem",
          fancytype: "inserttable",
          onAction: insertTableAction
        }]
      });
    }
    editor.ui.registry.addMenuItem("inserttabledialog", {
      text: "Insert table",
      icon: "table",
      onAction: cmd("mceInsertTableDialog")
    });
    addMenuIfRegistered("tableprops", {
      text: "Table properties",
      onSetup: selectionTargets.onSetupTable,
      command: "mceTableProps"
    });
    addMenuIfRegistered("deletetable", {
      text: "Delete table",
      icon: "table-delete-table",
      onSetup: selectionTargets.onSetupTable,
      command: "mceTableDelete"
    });
    if (contains(hasRowMenuItems, true)) {
      editor.ui.registry.addNestedMenuItem("row", {
        type: "nestedmenuitem",
        text: "Row",
        getSubmenuItems: constant("tableinsertrowbefore tableinsertrowafter tabledeleterow tablerowprops | tablecutrow tablecopyrow tablepasterowbefore tablepasterowafter")
      });
    }
    if (contains(hasColumnMenuItems, true)) {
      editor.ui.registry.addNestedMenuItem("column", {
        type: "nestedmenuitem",
        text: "Column",
        getSubmenuItems: constant("tableinsertcolumnbefore tableinsertcolumnafter tabledeletecolumn | tablecutcolumn tablecopycolumn tablepastecolumnbefore tablepastecolumnafter")
      });
    }
    if (contains(hasCellMenuItems, true)) {
      editor.ui.registry.addNestedMenuItem("cell", {
        type: "nestedmenuitem",
        text: "Cell",
        getSubmenuItems: constant("tablecellprops tablemergecells tablesplitcells")
      });
    }
    editor.ui.registry.addContextMenu("table", {
      update: () => {
        selectionTargets.resetTargets();
        return selectionTargets.targets().fold(constant(""), (targets) => {
          if (name(targets.element) === "caption") {
            return "tableprops deletetable";
          } else {
            return "cell row column | advtablesort | tableprops deletetable";
          }
        });
      }
    });
    const tableClassList = filterNoneItem(getTableClassList(editor));
    if (tableClassList.length !== 0 && editor.queryCommandSupported("mceTableToggleClass")) {
      editor.ui.registry.addNestedMenuItem("tableclass", {
        icon: "table-classes",
        text: "Table styles",
        getSubmenuItems: () => buildMenuItems(editor, tableClassList, "tableclass", (value) => editor.execCommand("mceTableToggleClass", false, value)),
        onSetup: selectionTargets.onSetupTable
      });
    }
    const tableCellClassList = filterNoneItem(getCellClassList(editor));
    if (tableCellClassList.length !== 0 && editor.queryCommandSupported("mceTableCellToggleClass")) {
      editor.ui.registry.addNestedMenuItem("tablecellclass", {
        icon: "table-cell-classes",
        text: "Cell styles",
        getSubmenuItems: () => buildMenuItems(editor, tableCellClassList, "tablecellclass", (value) => editor.execCommand("mceTableCellToggleClass", false, value)),
        onSetup: selectionTargets.onSetupCellOrRow
      });
    }
    if (editor.queryCommandSupported("mceTableApplyCellStyle")) {
      editor.ui.registry.addNestedMenuItem("tablecellvalign", {
        icon: "vertical-align",
        text: "Vertical align",
        getSubmenuItems: () => buildMenuItems(editor, verticalAlignValues, "tablecellverticalalign", applyTableCellStyle(editor, "vertical-align")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addNestedMenuItem("tablecellborderwidth", {
        icon: "border-width",
        text: "Border width",
        getSubmenuItems: () => buildMenuItems(editor, getTableBorderWidths(editor), "tablecellborderwidth", applyTableCellStyle(editor, "border-width")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addNestedMenuItem("tablecellborderstyle", {
        icon: "border-style",
        text: "Border style",
        getSubmenuItems: () => buildMenuItems(editor, getTableBorderStyles(editor), "tablecellborderstyle", applyTableCellStyle(editor, "border-style")),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addNestedMenuItem("tablecellbackgroundcolor", {
        icon: "cell-background-color",
        text: "Background color",
        getSubmenuItems: () => buildColorMenu(editor, getTableBackgroundColorMap(editor), "background-color"),
        onSetup: selectionTargets.onSetupCellOrRow
      });
      editor.ui.registry.addNestedMenuItem("tablecellbordercolor", {
        icon: "cell-border-color",
        text: "Border color",
        getSubmenuItems: () => buildColorMenu(editor, getTableBorderColorMap(editor), "border-color"),
        onSetup: selectionTargets.onSetupCellOrRow
      });
    }
    addToggleMenuIfRegistered("tablecaption", {
      icon: "table-caption",
      text: "Table caption",
      command: "mceTableToggleCaption",
      onSetup: selectionTargets.onSetupTableWithCaption
    });
    addToggleMenuIfRegistered("tablerowheader", {
      text: "Row header",
      icon: "table-top-header",
      command: "mceTableRowType",
      onAction: changeRowHeader(editor),
      onSetup: selectionTargets.onSetupTableRowHeaders
    });
    addToggleMenuIfRegistered("tablecolheader", {
      text: "Column header",
      icon: "table-left-header",
      command: "mceTableColType",
      onAction: changeColumnHeader(editor),
      onSetup: selectionTargets.onSetupTableRowHeaders
    });
  };
  const Plugin = (editor) => {
    const selectionTargets = getSelectionTargets(editor);
    register(editor);
    registerCommands(editor);
    addMenuItems(editor, selectionTargets);
    addButtons(editor, selectionTargets);
    addToolbars(editor);
  };
  var Plugin$1 = () => {
    global$3.add("table", Plugin);
  };
  Plugin$1();
})();
(function() {
  var global$5 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const isSimpleType = (type) => (value) => typeof value === type;
  const eq = (t) => (a) => t === a;
  const isString = isType("string");
  const isObject = isType("object");
  const isArray = isType("array");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isArrayOf = (value, pred) => {
    if (isArray(value)) {
      for (let i = 0, len = value.length; i < len; ++i) {
        if (!pred(value[i])) {
          return false;
        }
      }
      return true;
    }
    return false;
  };
  const noop = () => {
  };
  const tripleEquals = (a, b) => {
    return a === b;
  };
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains = (xs, x) => rawIndexOf(xs, x) > -1;
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const foldl = (xs, f, acc) => {
    each$1(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten(map(xs, f));
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r = f(arr[i], i);
      if (r.isSome()) {
        return r;
      }
    }
    return Optional.none();
  };
  const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
  const cat = (arr) => {
    const r = [];
    const push = (x) => {
      r.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r;
  };
  const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("link_assume_external_targets", {
      processor: (value) => {
        const valid = isString(value) || isBoolean(value);
        if (valid) {
          if (value === true) {
            return {
              value: 1,
              valid
            };
          } else if (value === "http" || value === "https") {
            return {
              value,
              valid
            };
          } else {
            return {
              value: 0,
              valid
            };
          }
        } else {
          return {
            valid: false,
            message: "Must be a string or a boolean."
          };
        }
      },
      default: false
    });
    registerOption("link_context_toolbar", {
      processor: "boolean",
      default: false
    });
    registerOption("link_list", { processor: (value) => isString(value) || isFunction(value) || isArrayOf(value, isObject) });
    registerOption("link_default_target", { processor: "string" });
    registerOption("link_default_protocol", {
      processor: "string",
      default: "https"
    });
    registerOption("link_target_list", {
      processor: (value) => isBoolean(value) || isArrayOf(value, isObject),
      default: true
    });
    registerOption("link_rel_list", {
      processor: "object[]",
      default: []
    });
    registerOption("link_class_list", {
      processor: "object[]",
      default: []
    });
    registerOption("link_title", {
      processor: "boolean",
      default: true
    });
    registerOption("allow_unsafe_link_target", {
      processor: "boolean",
      default: false
    });
    registerOption("link_quicklink", {
      processor: "boolean",
      default: false
    });
  };
  const assumeExternalTargets = option("link_assume_external_targets");
  const hasContextToolbar = option("link_context_toolbar");
  const getLinkList = option("link_list");
  const getDefaultLinkTarget = option("link_default_target");
  const getDefaultLinkProtocol = option("link_default_protocol");
  const getTargetList = option("link_target_list");
  const getRelList = option("link_rel_list");
  const getLinkClassList = option("link_class_list");
  const shouldShowLinkTitle = option("link_title");
  const allowUnsafeLinkTarget = option("allow_unsafe_link_target");
  const useQuickLink = option("link_quicklink");
  var global$4 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const getValue = (item) => isString(item.value) ? item.value : "";
  const getText = (item) => {
    if (isString(item.text)) {
      return item.text;
    } else if (isString(item.title)) {
      return item.title;
    } else {
      return "";
    }
  };
  const sanitizeList = (list, extractValue) => {
    const out = [];
    global$4.each(list, (item) => {
      const text = getText(item);
      if (item.menu !== void 0) {
        const items = sanitizeList(item.menu, extractValue);
        out.push({
          text,
          items
        });
      } else {
        const value = extractValue(item);
        out.push({
          text,
          value
        });
      }
    });
    return out;
  };
  const sanitizeWith = (extracter = getValue) => (list) => Optional.from(list).map((list2) => sanitizeList(list2, extracter));
  const sanitize = (list) => sanitizeWith(getValue)(list);
  const createUi = (name, label) => (items) => ({
    name,
    type: "listbox",
    label,
    items
  });
  const ListOptions = {
    sanitize,
    sanitizeWith,
    createUi,
    getValue
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = (r) => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r = {};
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r;
  };
  const filter = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== void 0 && obj[key] !== null;
  var global$3 = tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");
  var global$2 = tinymce.util.Tools.resolve("tinymce.util.URI");
  const isAnchor = (elm) => elm && elm.nodeName.toLowerCase() === "a";
  const isLink = (elm) => isAnchor(elm) && !!getHref(elm);
  const collectNodesInRange = (rng, predicate) => {
    if (rng.collapsed) {
      return [];
    } else {
      const contents = rng.cloneContents();
      const walker = new global$3(contents.firstChild, contents);
      const elements = [];
      let current = contents.firstChild;
      do {
        if (predicate(current)) {
          elements.push(current);
        }
      } while (current = walker.next());
      return elements;
    }
  };
  const hasProtocol = (url) => /^\w+:/i.test(url);
  const getHref = (elm) => {
    const href = elm.getAttribute("data-mce-href");
    return href ? href : elm.getAttribute("href");
  };
  const applyRelTargetRules = (rel, isUnsafe) => {
    const rules = ["noopener"];
    const rels = rel ? rel.split(/\s+/) : [];
    const toString = (rels2) => global$4.trim(rels2.sort().join(" "));
    const addTargetRules = (rels2) => {
      rels2 = removeTargetRules(rels2);
      return rels2.length > 0 ? rels2.concat(rules) : rules;
    };
    const removeTargetRules = (rels2) => rels2.filter((val) => global$4.inArray(rules, val) === -1);
    const newRels = isUnsafe ? addTargetRules(rels) : removeTargetRules(rels);
    return newRels.length > 0 ? toString(newRels) : "";
  };
  const trimCaretContainers = (text) => text.replace(/\uFEFF/g, "");
  const getAnchorElement = (editor, selectedElm) => {
    selectedElm = selectedElm || editor.selection.getNode();
    if (isImageFigure(selectedElm)) {
      return editor.dom.select("a[href]", selectedElm)[0];
    } else {
      return editor.dom.getParent(selectedElm, "a[href]");
    }
  };
  const getAnchorText = (selection, anchorElm) => {
    const text = anchorElm ? anchorElm.innerText || anchorElm.textContent : selection.getContent({ format: "text" });
    return trimCaretContainers(text);
  };
  const hasLinks = (elements) => global$4.grep(elements, isLink).length > 0;
  const hasLinksInSelection = (rng) => collectNodesInRange(rng, isLink).length > 0;
  const isOnlyTextSelected = (editor) => {
    const inlineTextElements = editor.schema.getTextInlineElements();
    const isElement = (elm) => elm.nodeType === 1 && !isAnchor(elm) && !has(inlineTextElements, elm.nodeName.toLowerCase());
    const elements = collectNodesInRange(editor.selection.getRng(), isElement);
    return elements.length === 0;
  };
  const isImageFigure = (elm) => elm && elm.nodeName === "FIGURE" && /\bimage\b/i.test(elm.className);
  const getLinkAttrs = (data) => {
    const attrs = [
      "title",
      "rel",
      "class",
      "target"
    ];
    return foldl(attrs, (acc, key) => {
      data[key].each((value) => {
        acc[key] = value.length > 0 ? value : null;
      });
      return acc;
    }, { href: data.href });
  };
  const handleExternalTargets = (href, assumeExternalTargets2) => {
    if ((assumeExternalTargets2 === "http" || assumeExternalTargets2 === "https") && !hasProtocol(href)) {
      return assumeExternalTargets2 + "://" + href;
    }
    return href;
  };
  const applyLinkOverrides = (editor, linkAttrs) => {
    const newLinkAttrs = { ...linkAttrs };
    if (getRelList(editor).length === 0 && !allowUnsafeLinkTarget(editor)) {
      const newRel = applyRelTargetRules(newLinkAttrs.rel, newLinkAttrs.target === "_blank");
      newLinkAttrs.rel = newRel ? newRel : null;
    }
    if (Optional.from(newLinkAttrs.target).isNone() && getTargetList(editor) === false) {
      newLinkAttrs.target = getDefaultLinkTarget(editor);
    }
    newLinkAttrs.href = handleExternalTargets(newLinkAttrs.href, assumeExternalTargets(editor));
    return newLinkAttrs;
  };
  const updateLink = (editor, anchorElm, text, linkAttrs) => {
    text.each((text2) => {
      if (has(anchorElm, "innerText")) {
        anchorElm.innerText = text2;
      } else {
        anchorElm.textContent = text2;
      }
    });
    editor.dom.setAttribs(anchorElm, linkAttrs);
    editor.selection.select(anchorElm);
  };
  const createLink = (editor, selectedElm, text, linkAttrs) => {
    if (isImageFigure(selectedElm)) {
      linkImageFigure(editor, selectedElm, linkAttrs);
    } else {
      text.fold(() => {
        editor.execCommand("mceInsertLink", false, linkAttrs);
      }, (text2) => {
        editor.insertContent(editor.dom.createHTML("a", linkAttrs, editor.dom.encode(text2)));
      });
    }
  };
  const linkDomMutation = (editor, attachState, data) => {
    const selectedElm = editor.selection.getNode();
    const anchorElm = getAnchorElement(editor, selectedElm);
    const linkAttrs = applyLinkOverrides(editor, getLinkAttrs(data));
    editor.undoManager.transact(() => {
      if (data.href === attachState.href) {
        attachState.attach();
      }
      if (anchorElm) {
        editor.focus();
        updateLink(editor, anchorElm, data.text, linkAttrs);
      } else {
        createLink(editor, selectedElm, data.text, linkAttrs);
      }
    });
  };
  const unlinkSelection = (editor) => {
    const dom = editor.dom, selection = editor.selection;
    const bookmark = selection.getBookmark();
    const rng = selection.getRng().cloneRange();
    const startAnchorElm = dom.getParent(rng.startContainer, "a[href]", editor.getBody());
    const endAnchorElm = dom.getParent(rng.endContainer, "a[href]", editor.getBody());
    if (startAnchorElm) {
      rng.setStartBefore(startAnchorElm);
    }
    if (endAnchorElm) {
      rng.setEndAfter(endAnchorElm);
    }
    selection.setRng(rng);
    editor.execCommand("unlink");
    selection.moveToBookmark(bookmark);
  };
  const unlinkDomMutation = (editor) => {
    editor.undoManager.transact(() => {
      const node = editor.selection.getNode();
      if (isImageFigure(node)) {
        unlinkImageFigure(editor, node);
      } else {
        unlinkSelection(editor);
      }
      editor.focus();
    });
  };
  const unwrapOptions = (data) => {
    const {
      class: cls,
      href,
      rel,
      target,
      text,
      title
    } = data;
    return filter({
      class: cls.getOrNull(),
      href,
      rel: rel.getOrNull(),
      target: target.getOrNull(),
      text: text.getOrNull(),
      title: title.getOrNull()
    }, (v, _k) => isNull(v) === false);
  };
  const sanitizeData = (editor, data) => {
    const getOption = editor.options.get;
    const uriOptions = {
      allow_html_data_urls: getOption("allow_html_data_urls"),
      allow_script_urls: getOption("allow_script_urls"),
      allow_svg_data_urls: getOption("allow_svg_data_urls")
    };
    const href = data.href;
    return {
      ...data,
      href: global$2.isDomSafe(href, "a", uriOptions) ? href : ""
    };
  };
  const link = (editor, attachState, data) => {
    const sanitizedData = sanitizeData(editor, data);
    editor.hasPlugin("rtc", true) ? editor.execCommand("createlink", false, unwrapOptions(sanitizedData)) : linkDomMutation(editor, attachState, sanitizedData);
  };
  const unlink = (editor) => {
    editor.hasPlugin("rtc", true) ? editor.execCommand("unlink") : unlinkDomMutation(editor);
  };
  const unlinkImageFigure = (editor, fig) => {
    const img = editor.dom.select("img", fig)[0];
    if (img) {
      const a = editor.dom.getParents(img, "a[href]", fig)[0];
      if (a) {
        a.parentNode.insertBefore(img, a);
        editor.dom.remove(a);
      }
    }
  };
  const linkImageFigure = (editor, fig, attrs) => {
    const img = editor.dom.select("img", fig)[0];
    if (img) {
      const a = editor.dom.create("a", attrs);
      img.parentNode.insertBefore(a, img);
      a.appendChild(img);
    }
  };
  const isListGroup = (item) => hasNonNullableKey(item, "items");
  const findTextByValue = (value, catalog) => findMap(catalog, (item) => {
    if (isListGroup(item)) {
      return findTextByValue(value, item.items);
    } else {
      return someIf(item.value === value, item);
    }
  });
  const getDelta = (persistentText, fieldName, catalog, data) => {
    const value = data[fieldName];
    const hasPersistentText = persistentText.length > 0;
    return value !== void 0 ? findTextByValue(value, catalog).map((i) => ({
      url: {
        value: i.value,
        meta: {
          text: hasPersistentText ? persistentText : i.text,
          attach: noop
        }
      },
      text: hasPersistentText ? persistentText : i.text
    })) : Optional.none();
  };
  const findCatalog = (catalogs, fieldName) => {
    if (fieldName === "link") {
      return catalogs.link;
    } else if (fieldName === "anchor") {
      return catalogs.anchor;
    } else {
      return Optional.none();
    }
  };
  const init = (initialData, linkCatalog) => {
    const persistentData = {
      text: initialData.text,
      title: initialData.title
    };
    const getTitleFromUrlChange = (url) => someIf(persistentData.title.length <= 0, Optional.from(url.meta.title).getOr(""));
    const getTextFromUrlChange = (url) => someIf(persistentData.text.length <= 0, Optional.from(url.meta.text).getOr(url.value));
    const onUrlChange = (data) => {
      const text = getTextFromUrlChange(data.url);
      const title = getTitleFromUrlChange(data.url);
      if (text.isSome() || title.isSome()) {
        return Optional.some({
          ...text.map((text2) => ({ text: text2 })).getOr({}),
          ...title.map((title2) => ({ title: title2 })).getOr({})
        });
      } else {
        return Optional.none();
      }
    };
    const onCatalogChange = (data, change) => {
      const catalog = findCatalog(linkCatalog, change.name).getOr([]);
      return getDelta(persistentData.text, change.name, catalog, data);
    };
    const onChange = (getData, change) => {
      const name = change.name;
      if (name === "url") {
        return onUrlChange(getData());
      } else if (contains([
        "anchor",
        "link"
      ], name)) {
        return onCatalogChange(getData(), change);
      } else if (name === "text" || name === "title") {
        persistentData[name] = getData()[name];
        return Optional.none();
      } else {
        return Optional.none();
      }
    };
    return { onChange };
  };
  const DialogChanges = {
    init,
    getDelta
  };
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Delay");
  const delayedConfirm = (editor, message, callback) => {
    const rng = editor.selection.getRng();
    global$1.setEditorTimeout(editor, () => {
      editor.windowManager.confirm(message, (state) => {
        editor.selection.setRng(rng);
        callback(state);
      });
    });
  };
  const tryEmailTransform = (data) => {
    const url = data.href;
    const suggestMailTo = url.indexOf("@") > 0 && url.indexOf("/") === -1 && url.indexOf("mailto:") === -1;
    return suggestMailTo ? Optional.some({
      message: "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",
      preprocess: (oldData) => ({
        ...oldData,
        href: "mailto:" + url
      })
    }) : Optional.none();
  };
  const tryProtocolTransform = (assumeExternalTargets2, defaultLinkProtocol) => (data) => {
    const url = data.href;
    const suggestProtocol = assumeExternalTargets2 === 1 && !hasProtocol(url) || assumeExternalTargets2 === 0 && /^\s*www(\.|\d\.)/i.test(url);
    return suggestProtocol ? Optional.some({
      message: `The URL you entered seems to be an external link. Do you want to add the required ${defaultLinkProtocol}:// prefix?`,
      preprocess: (oldData) => ({
        ...oldData,
        href: defaultLinkProtocol + "://" + url
      })
    }) : Optional.none();
  };
  const preprocess = (editor, data) => findMap([
    tryEmailTransform,
    tryProtocolTransform(assumeExternalTargets(editor), getDefaultLinkProtocol(editor))
  ], (f) => f(data)).fold(() => Promise.resolve(data), (transform) => new Promise((callback) => {
    delayedConfirm(editor, transform.message, (state) => {
      callback(state ? transform.preprocess(data) : data);
    });
  }));
  const DialogConfirms = { preprocess };
  const getAnchors = (editor) => {
    const anchorNodes = editor.dom.select("a:not([href])");
    const anchors = bind(anchorNodes, (anchor) => {
      const id = anchor.name || anchor.id;
      return id ? [{
        text: id,
        value: "#" + id
      }] : [];
    });
    return anchors.length > 0 ? Optional.some([{
      text: "None",
      value: ""
    }].concat(anchors)) : Optional.none();
  };
  const AnchorListOptions = { getAnchors };
  const getClasses = (editor) => {
    const list = getLinkClassList(editor);
    if (list.length > 0) {
      return ListOptions.sanitize(list);
    }
    return Optional.none();
  };
  const ClassListOptions = { getClasses };
  const parseJson = (text) => {
    try {
      return Optional.some(JSON.parse(text));
    } catch (err) {
      return Optional.none();
    }
  };
  const getLinks = (editor) => {
    const extractor = (item) => editor.convertURL(item.value || item.url, "href");
    const linkList = getLinkList(editor);
    return new Promise((resolve) => {
      if (isString(linkList)) {
        fetch(linkList).then((res) => res.ok ? res.text().then(parseJson) : Promise.reject()).then(resolve, () => resolve(Optional.none()));
      } else if (isFunction(linkList)) {
        linkList((output) => resolve(Optional.some(output)));
      } else {
        resolve(Optional.from(linkList));
      }
    }).then((optItems) => optItems.bind(ListOptions.sanitizeWith(extractor)).map((items) => {
      if (items.length > 0) {
        const noneItem = [{
          text: "None",
          value: ""
        }];
        return noneItem.concat(items);
      } else {
        return items;
      }
    }));
  };
  const LinkListOptions = { getLinks };
  const getRels = (editor, initialTarget) => {
    const list = getRelList(editor);
    if (list.length > 0) {
      const isTargetBlank = is(initialTarget, "_blank");
      const enforceSafe = allowUnsafeLinkTarget(editor) === false;
      const safeRelExtractor = (item) => applyRelTargetRules(ListOptions.getValue(item), isTargetBlank);
      const sanitizer = enforceSafe ? ListOptions.sanitizeWith(safeRelExtractor) : ListOptions.sanitize;
      return sanitizer(list);
    }
    return Optional.none();
  };
  const RelOptions = { getRels };
  const fallbacks = [
    {
      text: "Current window",
      value: ""
    },
    {
      text: "New window",
      value: "_blank"
    }
  ];
  const getTargets = (editor) => {
    const list = getTargetList(editor);
    if (isArray(list)) {
      return ListOptions.sanitize(list).orThunk(() => Optional.some(fallbacks));
    } else if (list === false) {
      return Optional.none();
    }
    return Optional.some(fallbacks);
  };
  const TargetOptions = { getTargets };
  const nonEmptyAttr = (dom, elem, name) => {
    const val = dom.getAttrib(elem, name);
    return val !== null && val.length > 0 ? Optional.some(val) : Optional.none();
  };
  const extractFromAnchor = (editor, anchor) => {
    const dom = editor.dom;
    const onlyText = isOnlyTextSelected(editor);
    const text = onlyText ? Optional.some(getAnchorText(editor.selection, anchor)) : Optional.none();
    const url = anchor ? Optional.some(dom.getAttrib(anchor, "href")) : Optional.none();
    const target = anchor ? Optional.from(dom.getAttrib(anchor, "target")) : Optional.none();
    const rel = nonEmptyAttr(dom, anchor, "rel");
    const linkClass = nonEmptyAttr(dom, anchor, "class");
    const title = nonEmptyAttr(dom, anchor, "title");
    return {
      url,
      text,
      title,
      target,
      rel,
      linkClass
    };
  };
  const collect = (editor, linkNode) => LinkListOptions.getLinks(editor).then((links) => {
    const anchor = extractFromAnchor(editor, linkNode);
    return {
      anchor,
      catalogs: {
        targets: TargetOptions.getTargets(editor),
        rels: RelOptions.getRels(editor, anchor.target),
        classes: ClassListOptions.getClasses(editor),
        anchor: AnchorListOptions.getAnchors(editor),
        link: links
      },
      optNode: Optional.from(linkNode),
      flags: { titleEnabled: shouldShowLinkTitle(editor) }
    };
  });
  const DialogInfo = { collect };
  const handleSubmit = (editor, info) => (api) => {
    const data = api.getData();
    if (!data.url.value) {
      unlink(editor);
      api.close();
      return;
    }
    const getChangedValue = (key) => Optional.from(data[key]).filter((value) => !is(info.anchor[key], value));
    const changedData = {
      href: data.url.value,
      text: getChangedValue("text"),
      target: getChangedValue("target"),
      rel: getChangedValue("rel"),
      class: getChangedValue("linkClass"),
      title: getChangedValue("title")
    };
    const attachState = {
      href: data.url.value,
      attach: data.url.meta !== void 0 && data.url.meta.attach ? data.url.meta.attach : noop
    };
    DialogConfirms.preprocess(editor, changedData).then((pData) => {
      link(editor, attachState, pData);
    });
    api.close();
  };
  const collectData = (editor) => {
    const anchorNode = getAnchorElement(editor);
    return DialogInfo.collect(editor, anchorNode);
  };
  const getInitialData = (info, defaultTarget) => {
    const anchor = info.anchor;
    const url = anchor.url.getOr("");
    return {
      url: {
        value: url,
        meta: { original: { value: url } }
      },
      text: anchor.text.getOr(""),
      title: anchor.title.getOr(""),
      anchor: url,
      link: url,
      rel: anchor.rel.getOr(""),
      target: anchor.target.or(defaultTarget).getOr(""),
      linkClass: anchor.linkClass.getOr("")
    };
  };
  const makeDialog = (settings, onSubmit, editor) => {
    const urlInput = [{
      name: "url",
      type: "urlinput",
      filetype: "file",
      label: "URL"
    }];
    const displayText = settings.anchor.text.map(() => ({
      name: "text",
      type: "input",
      label: "Text to display"
    })).toArray();
    const titleText = settings.flags.titleEnabled ? [{
      name: "title",
      type: "input",
      label: "Title"
    }] : [];
    const defaultTarget = Optional.from(getDefaultLinkTarget(editor));
    const initialData = getInitialData(settings, defaultTarget);
    const catalogs = settings.catalogs;
    const dialogDelta = DialogChanges.init(initialData, catalogs);
    const body = {
      type: "panel",
      items: flatten([
        urlInput,
        displayText,
        titleText,
        cat([
          catalogs.anchor.map(ListOptions.createUi("anchor", "Anchors")),
          catalogs.rels.map(ListOptions.createUi("rel", "Rel")),
          catalogs.targets.map(ListOptions.createUi("target", "Open link in...")),
          catalogs.link.map(ListOptions.createUi("link", "Link list")),
          catalogs.classes.map(ListOptions.createUi("linkClass", "Class"))
        ])
      ])
    };
    return {
      title: "Insert/Edit Link",
      size: "normal",
      body,
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData,
      onChange: (api, { name }) => {
        dialogDelta.onChange(api.getData, { name }).each((newData) => {
          api.setData(newData);
        });
      },
      onSubmit
    };
  };
  const open$1 = (editor) => {
    const data = collectData(editor);
    data.then((info) => {
      const onSubmit = handleSubmit(editor, info);
      return makeDialog(info, onSubmit, editor);
    }).then((spec) => {
      editor.windowManager.open(spec);
    });
  };
  const register = (editor) => {
    editor.addCommand("mceLink", (_ui, value) => {
      if ((value === null || value === void 0 ? void 0 : value.dialog) === true || !useQuickLink(editor)) {
        open$1(editor);
      } else {
        editor.dispatch("contexttoolbar-show", { toolbarKey: "quicklink" });
      }
    });
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.util.VK");
  const appendClickRemove = (link2, evt) => {
    document.body.appendChild(link2);
    link2.dispatchEvent(evt);
    document.body.removeChild(link2);
  };
  const open = (url) => {
    const link2 = document.createElement("a");
    link2.target = "_blank";
    link2.href = url;
    link2.rel = "noreferrer noopener";
    const evt = document.createEvent("MouseEvents");
    evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    appendClickRemove(link2, evt);
  };
  const getLink = (editor, elm) => editor.dom.getParent(elm, "a[href]");
  const getSelectedLink = (editor) => getLink(editor, editor.selection.getStart());
  const hasOnlyAltModifier = (e) => {
    return e.altKey === true && e.shiftKey === false && e.ctrlKey === false && e.metaKey === false;
  };
  const gotoLink = (editor, a) => {
    if (a) {
      const href = getHref(a);
      if (/^#/.test(href)) {
        const targetEl = editor.dom.select(href);
        if (targetEl.length) {
          editor.selection.scrollIntoView(targetEl[0], true);
        }
      } else {
        open(a.href);
      }
    }
  };
  const openDialog = (editor) => () => {
    editor.execCommand("mceLink", false, { dialog: true });
  };
  const gotoSelectedLink = (editor) => () => {
    gotoLink(editor, getSelectedLink(editor));
  };
  const setupGotoLinks = (editor) => {
    editor.on("click", (e) => {
      const link2 = getLink(editor, e.target);
      if (link2 && global2.metaKeyPressed(e)) {
        e.preventDefault();
        gotoLink(editor, link2);
      }
    });
    editor.on("keydown", (e) => {
      if (!e.isDefaultPrevented() && e.keyCode === 13 && hasOnlyAltModifier(e)) {
        const link2 = getSelectedLink(editor);
        if (link2) {
          e.preventDefault();
          gotoLink(editor, link2);
        }
      }
    });
  };
  const toggleState = (editor, toggler) => {
    editor.on("NodeChange", toggler);
    return () => editor.off("NodeChange", toggler);
  };
  const toggleActiveState = (editor) => (api) => {
    const updateState = () => api.setActive(!editor.mode.isReadOnly() && getAnchorElement(editor, editor.selection.getNode()) !== null);
    updateState();
    return toggleState(editor, updateState);
  };
  const toggleEnabledState = (editor) => (api) => {
    const updateState = () => api.setEnabled(getAnchorElement(editor, editor.selection.getNode()) !== null);
    updateState();
    return toggleState(editor, updateState);
  };
  const toggleUnlinkState = (editor) => (api) => {
    const hasLinks$1 = (parents2) => hasLinks(parents2) || hasLinksInSelection(editor.selection.getRng());
    const parents = editor.dom.getParents(editor.selection.getStart());
    api.setEnabled(hasLinks$1(parents));
    return toggleState(editor, (e) => api.setEnabled(hasLinks$1(e.parents)));
  };
  const setup = (editor) => {
    editor.addShortcut("Meta+K", "", () => {
      editor.execCommand("mceLink");
    });
  };
  const setupButtons = (editor) => {
    editor.ui.registry.addToggleButton("link", {
      icon: "link",
      tooltip: "Insert/edit link",
      onAction: openDialog(editor),
      onSetup: toggleActiveState(editor)
    });
    editor.ui.registry.addButton("openlink", {
      icon: "new-tab",
      tooltip: "Open link",
      onAction: gotoSelectedLink(editor),
      onSetup: toggleEnabledState(editor)
    });
    editor.ui.registry.addButton("unlink", {
      icon: "unlink",
      tooltip: "Remove link",
      onAction: () => unlink(editor),
      onSetup: toggleUnlinkState(editor)
    });
  };
  const setupMenuItems = (editor) => {
    editor.ui.registry.addMenuItem("openlink", {
      text: "Open link",
      icon: "new-tab",
      onAction: gotoSelectedLink(editor),
      onSetup: toggleEnabledState(editor)
    });
    editor.ui.registry.addMenuItem("link", {
      icon: "link",
      text: "Link...",
      shortcut: "Meta+K",
      onAction: openDialog(editor)
    });
    editor.ui.registry.addMenuItem("unlink", {
      icon: "unlink",
      text: "Remove link",
      onAction: () => unlink(editor),
      onSetup: toggleUnlinkState(editor)
    });
  };
  const setupContextMenu = (editor) => {
    const inLink = "link unlink openlink";
    const noLink = "link";
    editor.ui.registry.addContextMenu("link", { update: (element) => hasLinks(editor.dom.getParents(element, "a")) ? inLink : noLink });
  };
  const setupContextToolbars = (editor) => {
    const collapseSelectionToEnd = (editor2) => {
      editor2.selection.collapse(false);
    };
    const onSetupLink = (buttonApi) => {
      const node = editor.selection.getNode();
      buttonApi.setEnabled(getAnchorElement(editor, node) !== null);
      return noop;
    };
    const getLinkText = (value) => {
      const anchor = getAnchorElement(editor);
      const onlyText = isOnlyTextSelected(editor);
      if (!anchor && onlyText) {
        const text = getAnchorText(editor.selection, anchor);
        return Optional.some(text.length > 0 ? text : value);
      } else {
        return Optional.none();
      }
    };
    editor.ui.registry.addContextForm("quicklink", {
      launch: {
        type: "contextformtogglebutton",
        icon: "link",
        tooltip: "Link",
        onSetup: toggleActiveState(editor)
      },
      label: "Link",
      predicate: (node) => !!getAnchorElement(editor, node) && hasContextToolbar(editor),
      initValue: () => {
        const elm = getAnchorElement(editor);
        return !!elm ? getHref(elm) : "";
      },
      commands: [
        {
          type: "contextformtogglebutton",
          icon: "link",
          tooltip: "Link",
          primary: true,
          onSetup: (buttonApi) => {
            const node = editor.selection.getNode();
            buttonApi.setActive(!!getAnchorElement(editor, node));
            return toggleActiveState(editor)(buttonApi);
          },
          onAction: (formApi) => {
            const value = formApi.getValue();
            const text = getLinkText(value);
            const attachState = {
              href: value,
              attach: noop
            };
            link(editor, attachState, {
              href: value,
              text,
              title: Optional.none(),
              rel: Optional.none(),
              target: Optional.none(),
              class: Optional.none()
            });
            collapseSelectionToEnd(editor);
            formApi.hide();
          }
        },
        {
          type: "contextformbutton",
          icon: "unlink",
          tooltip: "Remove link",
          onSetup: onSetupLink,
          onAction: (formApi) => {
            unlink(editor);
            formApi.hide();
          }
        },
        {
          type: "contextformbutton",
          icon: "new-tab",
          tooltip: "Open link",
          onSetup: onSetupLink,
          onAction: (formApi) => {
            gotoSelectedLink(editor)();
            formApi.hide();
          }
        }
      ]
    });
  };
  var Plugin = () => {
    global$5.add("link", (editor) => {
      register$1(editor);
      setupButtons(editor);
      setupMenuItems(editor);
      setupContextMenu(editor);
      setupContextToolbars(editor);
      setupGotoLinks(editor);
      register(editor);
      setup(editor);
    });
  };
  Plugin();
})();
(function() {
  var global2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const setContent = (editor, html) => {
    editor.focus();
    editor.undoManager.transact(() => {
      editor.setContent(html);
    });
    editor.selection.setCursorLocation();
    editor.nodeChanged();
  };
  const getContent = (editor) => {
    return editor.getContent({ source_view: true });
  };
  const open = (editor) => {
    const editorContent = getContent(editor);
    editor.windowManager.open({
      title: "Source Code",
      size: "large",
      body: {
        type: "panel",
        items: [{
          type: "textarea",
          name: "code"
        }]
      },
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData: { code: editorContent },
      onSubmit: (api) => {
        setContent(editor, api.getData().code);
        api.close();
      }
    });
  };
  const register$1 = (editor) => {
    editor.addCommand("mceCodeEditor", () => {
      open(editor);
    });
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mceCodeEditor");
    editor.ui.registry.addButton("code", {
      icon: "sourcecode",
      tooltip: "Source code",
      onAction
    });
    editor.ui.registry.addMenuItem("code", {
      icon: "sourcecode",
      text: "Source code",
      onAction
    });
  };
  var Plugin = () => {
    global2.add("code", (editor) => {
      register$1(editor);
      register(editor);
      return {};
    });
  };
  Plugin();
})();
(function() {
  var global$6 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value) => typeOf(value) === type2;
  const isSimpleType = (type2) => (value) => typeof value === type2;
  const isString = isType$1("string");
  const isObject = isType$1("object");
  const isArray = isType$1("array");
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const noop = () => {
  };
  const constant = (value) => {
    return () => {
      return value;
    };
  };
  const tripleEquals = (a, b) => {
    return a === b;
  };
  const not = (f) => (t) => !f(t);
  const never = constant(false);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativeSlice = Array.prototype.slice;
  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains$1 = (xs, x) => rawIndexOf(xs, x) > -1;
  const exists = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return true;
      }
    }
    return false;
  };
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const filter$1 = (xs, pred) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r.push(x);
      }
    }
    return r;
  };
  const groupBy = (xs, f) => {
    if (xs.length === 0) {
      return [];
    } else {
      let wasType = f(xs[0]);
      const r = [];
      let group = [];
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        const type2 = f(x);
        if (type2 !== wasType) {
          r.push(group);
          group = [];
        }
        wasType = type2;
        group.push(x);
      }
      if (group.length !== 0) {
        r.push(group);
      }
      return r;
    }
  };
  const foldl = (xs, f, acc) => {
    each$1(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten(map(xs, f));
  const reverse = (xs) => {
    const r = nativeSlice.call(xs, 0);
    r.reverse();
    return r;
  };
  const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get$1(xs, 0);
  const last = (xs) => get$1(xs, xs.length - 1);
  const unique2 = (xs, comparator) => {
    const r = [];
    const isDuplicated = isFunction(comparator) ? (x) => exists(r, (i) => comparator(i, x)) : (x) => contains$1(r, x);
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (!isDuplicated(x)) {
        r.push(x);
      }
    }
    return r;
  };
  const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left) => comparator(left, rhs));
  const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
  const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  const ELEMENT = 1;
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  const is$1 = (element, selector) => {
    const dom = element.dom;
    if (dom.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  const eq = (e1, e2) => e1.dom === e2.dom;
  const contains = (e1, e2) => {
    const d1 = e1.dom;
    const d2 = e2.dom;
    return d1 === d2 ? false : d1.contains(d2);
  };
  const is = is$1;
  var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot) => {
    if (is2(scope, a)) {
      return Optional.some(scope);
    } else if (isFunction(isRoot) && isRoot(scope)) {
      return Optional.none();
    } else {
      return ancestor2(scope, a, isRoot);
    }
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const name = (element) => {
    const r = element.dom.nodeName;
    return r.toLowerCase();
  };
  const type = (element) => element.dom.nodeType;
  const isType = (t) => (element) => type(element) === t;
  const isElement = isType(ELEMENT);
  const isTag = (tag) => (e) => isElement(e) && name(e) === tag;
  const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  const children = (element) => map(element.dom.childNodes, SugarElement.fromDom);
  const child = (element, index2) => {
    const cs = element.dom.childNodes;
    return Optional.from(cs[index2]).map(SugarElement.fromDom);
  };
  const firstChild = (element) => child(element, 0);
  const lastChild = (element) => child(element, element.dom.childNodes.length - 1);
  const ancestor = (scope, predicate, isRoot) => {
    let element = scope.dom;
    const stop = isFunction(isRoot) ? isRoot : never;
    while (element.parentNode) {
      element = element.parentNode;
      const el = SugarElement.fromDom(element);
      if (predicate(el)) {
        return Optional.some(el);
      } else if (stop(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const closest = (scope, predicate, isRoot) => {
    const is2 = (s, test) => test(s);
    return ClosestOrAncestor(is2, ancestor, scope, predicate, isRoot);
  };
  const before$1 = (marker, element) => {
    const parent$1 = parent(marker);
    parent$1.each((v) => {
      v.dom.insertBefore(element.dom, marker.dom);
    });
  };
  const after = (marker, element) => {
    const sibling = nextSibling(marker);
    sibling.fold(() => {
      const parent$1 = parent(marker);
      parent$1.each((v) => {
        append$1(v, element);
      });
    }, (v) => {
      before$1(v, element);
    });
  };
  const append$1 = (parent2, element) => {
    parent2.dom.appendChild(element.dom);
  };
  const before = (marker, elements) => {
    each$1(elements, (x) => {
      before$1(marker, x);
    });
  };
  const append = (parent2, elements) => {
    each$1(elements, (x) => {
      append$1(parent2, x);
    });
  };
  const empty = (element) => {
    element.dom.textContent = "";
    each$1(children(element), (rogue) => {
      remove(rogue);
    });
  };
  const remove = (element) => {
    const dom = element.dom;
    if (dom.parentNode !== null) {
      dom.parentNode.removeChild(dom);
    }
  };
  var global$5 = tinymce.util.Tools.resolve("tinymce.dom.RangeUtils");
  var global$4 = tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");
  var global$3 = tinymce.util.Tools.resolve("tinymce.util.VK");
  const keys = Object.keys;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const objAcc = (r) => (x, i) => {
    r[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r = {};
    each(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r;
  };
  const filter = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const rawSet = (dom, key, value) => {
    if (isString(value) || isBoolean(value) || isNumber(value)) {
      dom.setAttribute(key, value + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const setAll = (element, attrs) => {
    const dom = element.dom;
    each(attrs, (v, k) => {
      rawSet(dom, k, v);
    });
  };
  const clone$1 = (element) => foldl(element.dom.attributes, (acc, attr) => {
    acc[attr.name] = attr.value;
    return acc;
  }, {});
  const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  const deep = (original) => clone(original, true);
  const shallowAs = (original, tag) => {
    const nu = SugarElement.fromTag(tag);
    const attributes = clone$1(original);
    setAll(nu, attributes);
    return nu;
  };
  const mutate = (original, tag) => {
    const nu = shallowAs(original, tag);
    after(original, nu);
    const children$1 = children(original);
    append(nu, children$1);
    remove(original);
    return nu;
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const matchNodeName = (name2) => (node) => node && node.nodeName.toLowerCase() === name2;
  const matchNodeNames = (regex) => (node) => node && regex.test(node.nodeName);
  const isTextNode = (node) => node && node.nodeType === 3;
  const isListNode = matchNodeNames(/^(OL|UL|DL)$/);
  const isOlUlNode = matchNodeNames(/^(OL|UL)$/);
  const isOlNode = matchNodeName("ol");
  const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
  const isDlItemNode = matchNodeNames(/^(DT|DD)$/);
  const isTableCellNode = matchNodeNames(/^(TH|TD)$/);
  const isBr = matchNodeName("br");
  const isFirstChild = (node) => node.parentNode.firstChild === node;
  const isTextBlock = (editor, node) => node && !!editor.schema.getTextBlockElements()[node.nodeName];
  const isBlock = (node, blockElements) => node && node.nodeName in blockElements;
  const isBogusBr = (dom, node) => {
    if (!isBr(node)) {
      return false;
    }
    return dom.isBlock(node.nextSibling) && !isBr(node.previousSibling);
  };
  const isEmpty$1 = (dom, elm, keepBookmarks) => {
    const empty2 = dom.isEmpty(elm);
    if (keepBookmarks && dom.select("span[data-mce-type=bookmark]", elm).length > 0) {
      return false;
    }
    return empty2;
  };
  const isChildOfBody = (dom, elm) => dom.isChildOf(elm, dom.getRoot());
  const option = (name2) => (editor) => editor.options.get(name2);
  const register$3 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("lists_indent_on_tab", {
      processor: "boolean",
      default: true
    });
  };
  const shouldIndentOnTab = option("lists_indent_on_tab");
  const getForcedRootBlock = option("forced_root_block");
  const getForcedRootBlockAttrs = option("forced_root_block_attrs");
  const createTextBlock = (editor, contentNode) => {
    const dom = editor.dom;
    const blockElements = editor.schema.getBlockElements();
    const fragment = dom.createFragment();
    const blockName = getForcedRootBlock(editor);
    const blockAttrs = getForcedRootBlockAttrs(editor);
    let node, textBlock, hasContentNode;
    textBlock = dom.create(blockName, blockAttrs);
    if (!isBlock(contentNode.firstChild, blockElements)) {
      fragment.appendChild(textBlock);
    }
    while (node = contentNode.firstChild) {
      const nodeName = node.nodeName;
      if (!hasContentNode && (nodeName !== "SPAN" || node.getAttribute("data-mce-type") !== "bookmark")) {
        hasContentNode = true;
      }
      if (isBlock(node, blockElements)) {
        fragment.appendChild(node);
        textBlock = null;
      } else {
        if (!textBlock) {
          textBlock = dom.create(blockName, blockAttrs);
          fragment.appendChild(textBlock);
        }
        textBlock.appendChild(node);
      }
    }
    if (!hasContentNode) {
      textBlock.appendChild(dom.create("br", { "data-mce-bogus": "1" }));
    }
    return fragment;
  };
  const DOM$2 = global$2.DOM;
  const splitList = (editor, list, li) => {
    const removeAndKeepBookmarks = (targetNode) => {
      global$1.each(bookmarks, (node) => {
        targetNode.parentNode.insertBefore(node, li.parentNode);
      });
      DOM$2.remove(targetNode);
    };
    const bookmarks = DOM$2.select('span[data-mce-type="bookmark"]', list);
    const newBlock = createTextBlock(editor, li);
    const tmpRng = DOM$2.createRng();
    tmpRng.setStartAfter(li);
    tmpRng.setEndAfter(list);
    const fragment = tmpRng.extractContents();
    for (let node = fragment.firstChild; node; node = node.firstChild) {
      if (node.nodeName === "LI" && editor.dom.isEmpty(node)) {
        DOM$2.remove(node);
        break;
      }
    }
    if (!editor.dom.isEmpty(fragment)) {
      DOM$2.insertAfter(fragment, list);
    }
    DOM$2.insertAfter(newBlock, list);
    if (isEmpty$1(editor.dom, li.parentNode)) {
      removeAndKeepBookmarks(li.parentNode);
    }
    DOM$2.remove(li);
    if (isEmpty$1(editor.dom, list)) {
      DOM$2.remove(list);
    }
  };
  const isDescriptionDetail = isTag("dd");
  const isDescriptionTerm = isTag("dt");
  const outdentDlItem = (editor, item) => {
    if (isDescriptionDetail(item)) {
      mutate(item, "dt");
    } else if (isDescriptionTerm(item)) {
      parent(item).each((dl) => splitList(editor, dl.dom, item.dom));
    }
  };
  const indentDlItem = (item) => {
    if (isDescriptionTerm(item)) {
      mutate(item, "dd");
    }
  };
  const dlIndentation = (editor, indentation, dlItems) => {
    if (indentation === "Indent") {
      each$1(dlItems, indentDlItem);
    } else {
      each$1(dlItems, (item) => outdentDlItem(editor, item));
    }
  };
  const getNormalizedPoint = (container, offset) => {
    if (isTextNode(container)) {
      return {
        container,
        offset
      };
    }
    const node = global$5.getNode(container, offset);
    if (isTextNode(node)) {
      return {
        container: node,
        offset: offset >= container.childNodes.length ? node.data.length : 0
      };
    } else if (node.previousSibling && isTextNode(node.previousSibling)) {
      return {
        container: node.previousSibling,
        offset: node.previousSibling.data.length
      };
    } else if (node.nextSibling && isTextNode(node.nextSibling)) {
      return {
        container: node.nextSibling,
        offset: 0
      };
    }
    return {
      container,
      offset
    };
  };
  const normalizeRange = (rng) => {
    const outRng = rng.cloneRange();
    const rangeStart = getNormalizedPoint(rng.startContainer, rng.startOffset);
    outRng.setStart(rangeStart.container, rangeStart.offset);
    const rangeEnd = getNormalizedPoint(rng.endContainer, rng.endOffset);
    outRng.setEnd(rangeEnd.container, rangeEnd.offset);
    return outRng;
  };
  const listNames = [
    "OL",
    "UL",
    "DL"
  ];
  const listSelector = listNames.join(",");
  const getParentList = (editor, node) => {
    const selectionStart = node || editor.selection.getStart(true);
    return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
  };
  const isParentListSelected = (parentList, selectedBlocks) => parentList && selectedBlocks.length === 1 && selectedBlocks[0] === parentList;
  const findSubLists = (parentList) => filter$1(parentList.querySelectorAll(listSelector), isListNode);
  const getSelectedSubLists = (editor) => {
    const parentList = getParentList(editor);
    const selectedBlocks = editor.selection.getSelectedBlocks();
    if (isParentListSelected(parentList, selectedBlocks)) {
      return findSubLists(parentList);
    } else {
      return filter$1(selectedBlocks, (elm) => {
        return isListNode(elm) && parentList !== elm;
      });
    }
  };
  const findParentListItemsNodes = (editor, elms) => {
    const listItemsElms = global$1.map(elms, (elm) => {
      const parentLi = editor.dom.getParent(elm, "li,dd,dt", getClosestListHost(editor, elm));
      return parentLi ? parentLi : elm;
    });
    return unique2(listItemsElms);
  };
  const getSelectedListItems = (editor) => {
    const selectedBlocks = editor.selection.getSelectedBlocks();
    return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
  };
  const getSelectedDlItems = (editor) => filter$1(getSelectedListItems(editor), isDlItemNode);
  const getClosestEditingHost = (editor, elm) => {
    const parentTableCell = editor.dom.getParents(elm, "TD,TH");
    return parentTableCell.length > 0 ? parentTableCell[0] : editor.getBody();
  };
  const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, (listName) => schema.isValidChild(node.nodeName, listName));
  const getClosestListHost = (editor, elm) => {
    const parentBlocks = editor.dom.getParents(elm, editor.dom.isBlock);
    const parentBlock = find(parentBlocks, (elm2) => isListHost(editor.schema, elm2));
    return parentBlock.getOr(editor.getBody());
  };
  const findLastParentListNode = (editor, elm) => {
    const parentLists = editor.dom.getParents(elm, "ol,ul", getClosestListHost(editor, elm));
    return last(parentLists);
  };
  const getSelectedLists = (editor) => {
    const firstList = findLastParentListNode(editor, editor.selection.getStart());
    const subsequentLists = filter$1(editor.selection.getSelectedBlocks(), isOlUlNode);
    return firstList.toArray().concat(subsequentLists);
  };
  const getSelectedListRoots = (editor) => {
    const selectedLists = getSelectedLists(editor);
    return getUniqueListRoots(editor, selectedLists);
  };
  const getUniqueListRoots = (editor, lists) => {
    const listRoots = map(lists, (list) => findLastParentListNode(editor, list).getOr(list));
    return unique2(listRoots);
  };
  const fromElements = (elements, scope) => {
    const doc = scope || document;
    const fragment = doc.createDocumentFragment();
    each$1(elements, (element) => {
      fragment.appendChild(element.dom);
    });
    return SugarElement.fromDom(fragment);
  };
  const fireListEvent = (editor, action, element) => editor.dispatch("ListMutation", {
    action,
    element
  });
  const blank = (r) => (s) => s.replace(r, "");
  const trim = blank(/^\s+|\s+$/g);
  const isNotEmpty = (s) => s.length > 0;
  const isEmpty = (s) => !isNotEmpty(s);
  const isSupported = (dom) => dom.style !== void 0 && isFunction(dom.style.getPropertyValue);
  const internalSet = (dom, property, value) => {
    if (!isString(value)) {
      console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value, ":: Element ", dom);
      throw new Error("CSS value must be a string: " + value);
    }
    if (isSupported(dom)) {
      dom.style.setProperty(property, value);
    }
  };
  const set = (element, property, value) => {
    const dom = element.dom;
    internalSet(dom, property, value);
  };
  const joinSegment = (parent2, child2) => {
    append$1(parent2.item, child2.list);
  };
  const joinSegments = (segments) => {
    for (let i = 1; i < segments.length; i++) {
      joinSegment(segments[i - 1], segments[i]);
    }
  };
  const appendSegments = (head$1, tail) => {
    lift2(last(head$1), head(tail), joinSegment);
  };
  const createSegment = (scope, listType) => {
    const segment = {
      list: SugarElement.fromTag(listType, scope),
      item: SugarElement.fromTag("li", scope)
    };
    append$1(segment.list, segment.item);
    return segment;
  };
  const createSegments = (scope, entry, size) => {
    const segments = [];
    for (let i = 0; i < size; i++) {
      segments.push(createSegment(scope, entry.listType));
    }
    return segments;
  };
  const populateSegments = (segments, entry) => {
    for (let i = 0; i < segments.length - 1; i++) {
      set(segments[i].item, "list-style-type", "none");
    }
    last(segments).each((segment) => {
      setAll(segment.list, entry.listAttributes);
      setAll(segment.item, entry.itemAttributes);
      append(segment.item, entry.content);
    });
  };
  const normalizeSegment = (segment, entry) => {
    if (name(segment.list) !== entry.listType) {
      segment.list = mutate(segment.list, entry.listType);
    }
    setAll(segment.list, entry.listAttributes);
  };
  const createItem = (scope, attr, content) => {
    const item = SugarElement.fromTag("li", scope);
    setAll(item, attr);
    append(item, content);
    return item;
  };
  const appendItem = (segment, item) => {
    append$1(segment.list, item);
    segment.item = item;
  };
  const writeShallow = (scope, cast, entry) => {
    const newCast = cast.slice(0, entry.depth);
    last(newCast).each((segment) => {
      const item = createItem(scope, entry.itemAttributes, entry.content);
      appendItem(segment, item);
      normalizeSegment(segment, entry);
    });
    return newCast;
  };
  const writeDeep = (scope, cast, entry) => {
    const segments = createSegments(scope, entry, entry.depth - cast.length);
    joinSegments(segments);
    populateSegments(segments, entry);
    appendSegments(cast, segments);
    return cast.concat(segments);
  };
  const composeList = (scope, entries) => {
    const cast = foldl(entries, (cast2, entry) => {
      return entry.depth > cast2.length ? writeDeep(scope, cast2, entry) : writeShallow(scope, cast2, entry);
    }, []);
    return head(cast).map((segment) => segment.list);
  };
  const isList = (el) => is(el, "OL,UL");
  const hasFirstChildList = (el) => firstChild(el).exists(isList);
  const hasLastChildList = (el) => lastChild(el).exists(isList);
  const isIndented = (entry) => entry.depth > 0;
  const isSelected = (entry) => entry.isSelected;
  const cloneItemContent = (li) => {
    const children$1 = children(li);
    const content = hasLastChildList(li) ? children$1.slice(0, -1) : children$1;
    return map(content, deep);
  };
  const createEntry = (li, depth, isSelected2) => parent(li).filter(isElement).map((list) => ({
    depth,
    dirty: false,
    isSelected: isSelected2,
    content: cloneItemContent(li),
    itemAttributes: clone$1(li),
    listAttributes: clone$1(list),
    listType: name(list)
  }));
  const indentEntry = (indentation, entry) => {
    switch (indentation) {
      case "Indent":
        entry.depth++;
        break;
      case "Outdent":
        entry.depth--;
        break;
      case "Flatten":
        entry.depth = 0;
    }
    entry.dirty = true;
  };
  const cloneListProperties = (target, source) => {
    target.listType = source.listType;
    target.listAttributes = { ...source.listAttributes };
  };
  const cleanListProperties = (entry) => {
    entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== "start");
  };
  const closestSiblingEntry = (entries, start) => {
    const depth = entries[start].depth;
    const matches = (entry) => entry.depth === depth && !entry.dirty;
    const until = (entry) => entry.depth < depth;
    return findUntil(reverse(entries.slice(0, start)), matches, until).orThunk(() => findUntil(entries.slice(start + 1), matches, until));
  };
  const normalizeEntries = (entries) => {
    each$1(entries, (entry, i) => {
      closestSiblingEntry(entries, i).fold(() => {
        if (entry.dirty) {
          cleanListProperties(entry);
        }
      }, (matchingEntry) => cloneListProperties(entry, matchingEntry));
    });
    return entries;
  };
  const Cell = (initial) => {
    let value = initial;
    const get2 = () => {
      return value;
    };
    const set2 = (v) => {
      value = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => {
    itemSelection.each((selection) => {
      if (eq(selection.start, item)) {
        selectionState.set(true);
      }
    });
    const currentItemEntry = createEntry(item, depth, selectionState.get());
    itemSelection.each((selection) => {
      if (eq(selection.end, item)) {
        selectionState.set(false);
      }
    });
    const childListEntries = lastChild(item).filter(isList).map((list) => parseList(depth, itemSelection, selectionState, list)).getOr([]);
    return currentItemEntry.toArray().concat(childListEntries);
  }, (list) => parseList(depth, itemSelection, selectionState, list));
  const parseList = (depth, itemSelection, selectionState, list) => bind(children(list), (element) => {
    const parser = isList(element) ? parseList : parseItem;
    const newDepth = depth + 1;
    return parser(newDepth, itemSelection, selectionState, element);
  });
  const parseLists = (lists, itemSelection) => {
    const selectionState = Cell(false);
    const initialDepth = 0;
    return map(lists, (list) => ({
      sourceList: list,
      entries: parseList(initialDepth, itemSelection, selectionState, list)
    }));
  };
  const outdentedComposer = (editor, entries) => {
    const normalizedEntries = normalizeEntries(entries);
    return map(normalizedEntries, (entry) => {
      const content = fromElements(entry.content);
      return SugarElement.fromDom(createTextBlock(editor, content.dom));
    });
  };
  const indentedComposer = (editor, entries) => {
    const normalizedEntries = normalizeEntries(entries);
    return composeList(editor.contentDocument, normalizedEntries).toArray();
  };
  const composeEntries = (editor, entries) => bind(groupBy(entries, isIndented), (entries2) => {
    const groupIsIndented = head(entries2).exists(isIndented);
    return groupIsIndented ? indentedComposer(editor, entries2) : outdentedComposer(editor, entries2);
  });
  const indentSelectedEntries = (entries, indentation) => {
    each$1(filter$1(entries, isSelected), (entry) => indentEntry(indentation, entry));
  };
  const getItemSelection = (editor) => {
    const selectedListItems = map(getSelectedListItems(editor), SugarElement.fromDom);
    return lift2(find(selectedListItems, not(hasFirstChildList)), find(reverse(selectedListItems), not(hasFirstChildList)), (start, end) => ({
      start,
      end
    }));
  };
  const listIndentation = (editor, lists, indentation) => {
    const entrySets = parseLists(lists, getItemSelection(editor));
    each$1(entrySets, (entrySet) => {
      indentSelectedEntries(entrySet.entries, indentation);
      const composedLists = composeEntries(editor, entrySet.entries);
      each$1(composedLists, (composedList) => {
        fireListEvent(editor, indentation === "Indent" ? "IndentList" : "OutdentList", composedList.dom);
      });
      before(entrySet.sourceList, composedLists);
      remove(entrySet.sourceList);
    });
  };
  const selectionIndentation = (editor, indentation) => {
    const lists = map(getSelectedListRoots(editor), SugarElement.fromDom);
    const dlItems = map(getSelectedDlItems(editor), SugarElement.fromDom);
    let isHandled = false;
    if (lists.length || dlItems.length) {
      const bookmark = editor.selection.getBookmark();
      listIndentation(editor, lists, indentation);
      dlIndentation(editor, indentation, dlItems);
      editor.selection.moveToBookmark(bookmark);
      editor.selection.setRng(normalizeRange(editor.selection.getRng()));
      editor.nodeChanged();
      isHandled = true;
    }
    return isHandled;
  };
  const indentListSelection = (editor) => selectionIndentation(editor, "Indent");
  const outdentListSelection = (editor) => selectionIndentation(editor, "Outdent");
  const flattenListSelection = (editor) => selectionIndentation(editor, "Flatten");
  var global2 = tinymce.util.Tools.resolve("tinymce.dom.BookmarkManager");
  const DOM$1 = global$2.DOM;
  const createBookmark = (rng) => {
    const bookmark = {};
    const setupEndPoint = (start) => {
      let container = rng[start ? "startContainer" : "endContainer"];
      let offset = rng[start ? "startOffset" : "endOffset"];
      if (container.nodeType === 1) {
        const offsetNode = DOM$1.create("span", { "data-mce-type": "bookmark" });
        if (container.hasChildNodes()) {
          offset = Math.min(offset, container.childNodes.length - 1);
          if (start) {
            container.insertBefore(offsetNode, container.childNodes[offset]);
          } else {
            DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
          }
        } else {
          container.appendChild(offsetNode);
        }
        container = offsetNode;
        offset = 0;
      }
      bookmark[start ? "startContainer" : "endContainer"] = container;
      bookmark[start ? "startOffset" : "endOffset"] = offset;
    };
    setupEndPoint(true);
    if (!rng.collapsed) {
      setupEndPoint();
    }
    return bookmark;
  };
  const resolveBookmark = (bookmark) => {
    const restoreEndPoint = (start) => {
      let node;
      const nodeIndex = (container2) => {
        let node2 = container2.parentNode.firstChild, idx = 0;
        while (node2) {
          if (node2 === container2) {
            return idx;
          }
          if (node2.nodeType !== 1 || node2.getAttribute("data-mce-type") !== "bookmark") {
            idx++;
          }
          node2 = node2.nextSibling;
        }
        return -1;
      };
      let container = node = bookmark[start ? "startContainer" : "endContainer"];
      let offset = bookmark[start ? "startOffset" : "endOffset"];
      if (!container) {
        return;
      }
      if (container.nodeType === 1) {
        offset = nodeIndex(container);
        container = container.parentNode;
        DOM$1.remove(node);
        if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
          container.appendChild(DOM$1.create("br"));
        }
      }
      bookmark[start ? "startContainer" : "endContainer"] = container;
      bookmark[start ? "startOffset" : "endOffset"] = offset;
    };
    restoreEndPoint(true);
    restoreEndPoint();
    const rng = DOM$1.createRng();
    rng.setStart(bookmark.startContainer, bookmark.startOffset);
    if (bookmark.endContainer) {
      rng.setEnd(bookmark.endContainer, bookmark.endOffset);
    }
    return normalizeRange(rng);
  };
  const listToggleActionFromListName = (listName) => {
    switch (listName) {
      case "UL":
        return "ToggleUlList";
      case "OL":
        return "ToggleOlList";
      case "DL":
        return "ToggleDLList";
    }
  };
  const isCustomList = (list) => /\btox\-/.test(list.className);
  const listState = (editor, listName, activate) => {
    const nodeChangeHandler = (e) => {
      const inList = findUntil(e.parents, isListNode, isTableCellNode).filter((list) => list.nodeName === listName && !isCustomList(list)).isSome();
      activate(inList);
    };
    const parents = editor.dom.getParents(editor.selection.getNode());
    nodeChangeHandler({ parents });
    editor.on("NodeChange", nodeChangeHandler);
    return () => editor.off("NodeChange", nodeChangeHandler);
  };
  const updateListStyle = (dom, el, detail) => {
    const type2 = detail["list-style-type"] ? detail["list-style-type"] : null;
    dom.setStyle(el, "list-style-type", type2);
  };
  const setAttribs = (elm, attrs) => {
    global$1.each(attrs, (value, key) => {
      elm.setAttribute(key, value);
    });
  };
  const updateListAttrs = (dom, el, detail) => {
    setAttribs(el, detail["list-attributes"]);
    global$1.each(dom.select("li", el), (li) => {
      setAttribs(li, detail["list-item-attributes"]);
    });
  };
  const updateListWithDetails = (dom, el, detail) => {
    updateListStyle(dom, el, detail);
    updateListAttrs(dom, el, detail);
  };
  const removeStyles = (dom, element, styles) => {
    global$1.each(styles, (style) => dom.setStyle(element, style, ""));
  };
  const getEndPointNode = (editor, rng, start, root) => {
    let container = rng[start ? "startContainer" : "endContainer"];
    const offset = rng[start ? "startOffset" : "endOffset"];
    if (container.nodeType === 1) {
      container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
    }
    if (!start && isBr(container.nextSibling)) {
      container = container.nextSibling;
    }
    while (container.parentNode !== root) {
      if (isTextBlock(editor, container)) {
        return container;
      }
      if (/^(TD|TH)$/.test(container.parentNode.nodeName)) {
        return container;
      }
      container = container.parentNode;
    }
    return container;
  };
  const getSelectedTextBlocks = (editor, rng, root) => {
    const textBlocks = [];
    const dom = editor.dom;
    const startNode = getEndPointNode(editor, rng, true, root);
    const endNode = getEndPointNode(editor, rng, false, root);
    let block;
    const siblings = [];
    for (let node = startNode; node; node = node.nextSibling) {
      siblings.push(node);
      if (node === endNode) {
        break;
      }
    }
    global$1.each(siblings, (node) => {
      if (isTextBlock(editor, node)) {
        textBlocks.push(node);
        block = null;
        return;
      }
      if (dom.isBlock(node) || isBr(node)) {
        if (isBr(node)) {
          dom.remove(node);
        }
        block = null;
        return;
      }
      const nextSibling2 = node.nextSibling;
      if (global2.isBookmarkNode(node)) {
        if (isListNode(nextSibling2) || isTextBlock(editor, nextSibling2) || !nextSibling2 && node.parentNode === root) {
          block = null;
          return;
        }
      }
      if (!block) {
        block = dom.create("p");
        node.parentNode.insertBefore(block, node);
        textBlocks.push(block);
      }
      block.appendChild(node);
    });
    return textBlocks;
  };
  const hasCompatibleStyle = (dom, sib, detail) => {
    const sibStyle = dom.getStyle(sib, "list-style-type");
    let detailStyle = detail ? detail["list-style-type"] : "";
    detailStyle = detailStyle === null ? "" : detailStyle;
    return sibStyle === detailStyle;
  };
  const applyList = (editor, listName, detail) => {
    const rng = editor.selection.getRng();
    let listItemName = "LI";
    const root = getClosestListHost(editor, editor.selection.getStart(true));
    const dom = editor.dom;
    if (dom.getContentEditable(editor.selection.getNode()) === "false") {
      return;
    }
    listName = listName.toUpperCase();
    if (listName === "DL") {
      listItemName = "DT";
    }
    const bookmark = createBookmark(rng);
    const selectedTextBlocks = getSelectedTextBlocks(editor, rng, root);
    global$1.each(selectedTextBlocks, (block) => {
      let listBlock;
      const sibling = block.previousSibling;
      const parent2 = block.parentNode;
      if (!isListItemNode(parent2)) {
        if (sibling && isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(dom, sibling, detail)) {
          listBlock = sibling;
          block = dom.rename(block, listItemName);
          sibling.appendChild(block);
        } else {
          listBlock = dom.create(listName);
          block.parentNode.insertBefore(listBlock, block);
          listBlock.appendChild(block);
          block = dom.rename(block, listItemName);
        }
        removeStyles(dom, block, [
          "margin",
          "margin-right",
          "margin-bottom",
          "margin-left",
          "margin-top",
          "padding",
          "padding-right",
          "padding-bottom",
          "padding-left",
          "padding-top"
        ]);
        updateListWithDetails(dom, listBlock, detail);
        mergeWithAdjacentLists(editor.dom, listBlock);
      }
    });
    editor.selection.setRng(resolveBookmark(bookmark));
  };
  const isValidLists = (list1, list2) => {
    return list1 && list2 && isListNode(list1) && list1.nodeName === list2.nodeName;
  };
  const hasSameListStyle = (dom, list1, list2) => {
    const targetStyle = dom.getStyle(list1, "list-style-type", true);
    const style = dom.getStyle(list2, "list-style-type", true);
    return targetStyle === style;
  };
  const hasSameClasses = (elm1, elm2) => {
    return elm1.className === elm2.className;
  };
  const shouldMerge = (dom, list1, list2) => {
    return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
  };
  const mergeWithAdjacentLists = (dom, listBlock) => {
    let sibling, node;
    sibling = listBlock.nextSibling;
    if (shouldMerge(dom, listBlock, sibling)) {
      while (node = sibling.firstChild) {
        listBlock.appendChild(node);
      }
      dom.remove(sibling);
    }
    sibling = listBlock.previousSibling;
    if (shouldMerge(dom, listBlock, sibling)) {
      while (node = sibling.lastChild) {
        listBlock.insertBefore(node, listBlock.firstChild);
      }
      dom.remove(sibling);
    }
  };
  const updateList$1 = (editor, list, listName, detail) => {
    if (list.nodeName !== listName) {
      const newList = editor.dom.rename(list, listName);
      updateListWithDetails(editor.dom, newList, detail);
      fireListEvent(editor, listToggleActionFromListName(listName), newList);
    } else {
      updateListWithDetails(editor.dom, list, detail);
      fireListEvent(editor, listToggleActionFromListName(listName), list);
    }
  };
  const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
    const parentIsList = isListNode(parentList);
    if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail)) {
      flattenListSelection(editor);
    } else {
      applyList(editor, listName, detail);
      const bookmark = createBookmark(editor.selection.getRng());
      const allLists = parentIsList ? [
        parentList,
        ...lists
      ] : lists;
      global$1.each(allLists, (elm) => {
        updateList$1(editor, elm, listName, detail);
      });
      editor.selection.setRng(resolveBookmark(bookmark));
    }
  };
  const hasListStyleDetail = (detail) => {
    return "list-style-type" in detail;
  };
  const toggleSingleList = (editor, parentList, listName, detail) => {
    if (parentList === editor.getBody()) {
      return;
    }
    if (parentList) {
      if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
        flattenListSelection(editor);
      } else {
        const bookmark = createBookmark(editor.selection.getRng());
        updateListWithDetails(editor.dom, parentList, detail);
        const newList = editor.dom.rename(parentList, listName);
        mergeWithAdjacentLists(editor.dom, newList);
        editor.selection.setRng(resolveBookmark(bookmark));
        applyList(editor, listName, detail);
        fireListEvent(editor, listToggleActionFromListName(listName), newList);
      }
    } else {
      applyList(editor, listName, detail);
      fireListEvent(editor, listToggleActionFromListName(listName), parentList);
    }
  };
  const toggleList = (editor, listName, _detail) => {
    const parentList = getParentList(editor);
    const selectedSubLists = getSelectedSubLists(editor);
    const detail = isObject(_detail) ? _detail : {};
    if (selectedSubLists.length > 0) {
      toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
    } else {
      toggleSingleList(editor, parentList, listName, detail);
    }
  };
  const DOM = global$2.DOM;
  const normalizeList = (dom, list) => {
    const parentNode = list.parentNode;
    if (parentNode.nodeName === "LI" && parentNode.firstChild === list) {
      const sibling = parentNode.previousSibling;
      if (sibling && sibling.nodeName === "LI") {
        sibling.appendChild(list);
        if (isEmpty$1(dom, parentNode)) {
          DOM.remove(parentNode);
        }
      } else {
        DOM.setStyle(parentNode, "listStyleType", "none");
      }
    }
    if (isListNode(parentNode)) {
      const sibling = parentNode.previousSibling;
      if (sibling && sibling.nodeName === "LI") {
        sibling.appendChild(list);
      }
    }
  };
  const normalizeLists = (dom, element) => {
    const lists = global$1.grep(dom.select("ol,ul", element));
    global$1.each(lists, (list) => {
      normalizeList(dom, list);
    });
  };
  const findNextCaretContainer = (editor, rng, isForward, root) => {
    let node = rng.startContainer;
    const offset = rng.startOffset;
    if (isTextNode(node) && (isForward ? offset < node.data.length : offset > 0)) {
      return node;
    }
    const nonEmptyBlocks = editor.schema.getNonEmptyElements();
    if (node.nodeType === 1) {
      node = global$5.getNode(node, offset);
    }
    const walker = new global$4(node, root);
    if (isForward) {
      if (isBogusBr(editor.dom, node)) {
        walker.next();
      }
    }
    const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
    while (node = walkFn()) {
      if (node.nodeName === "LI" && !node.hasChildNodes()) {
        return node;
      }
      if (nonEmptyBlocks[node.nodeName]) {
        return node;
      }
      if (isTextNode(node) && node.data.length > 0) {
        return node;
      }
    }
  };
  const hasOnlyOneBlockChild = (dom, elm) => {
    const childNodes = elm.childNodes;
    return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
  };
  const unwrapSingleBlockChild = (dom, elm) => {
    if (hasOnlyOneBlockChild(dom, elm)) {
      dom.remove(elm.firstChild, true);
    }
  };
  const moveChildren = (dom, fromElm, toElm) => {
    let node;
    const targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
    unwrapSingleBlockChild(dom, fromElm);
    if (!isEmpty$1(dom, fromElm, true)) {
      while (node = fromElm.firstChild) {
        targetElm.appendChild(node);
      }
    }
  };
  const mergeLiElements = (dom, fromElm, toElm) => {
    let listNode;
    const ul = fromElm.parentNode;
    if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
      return;
    }
    if (isListNode(toElm.lastChild)) {
      listNode = toElm.lastChild;
    }
    if (ul === toElm.lastChild) {
      if (isBr(ul.previousSibling)) {
        dom.remove(ul.previousSibling);
      }
    }
    const node = toElm.lastChild;
    if (node && isBr(node) && fromElm.hasChildNodes()) {
      dom.remove(node);
    }
    if (isEmpty$1(dom, toElm, true)) {
      empty(SugarElement.fromDom(toElm));
    }
    moveChildren(dom, fromElm, toElm);
    if (listNode) {
      toElm.appendChild(listNode);
    }
    const contains$12 = contains(SugarElement.fromDom(toElm), SugarElement.fromDom(fromElm));
    const nestedLists = contains$12 ? dom.getParents(fromElm, isListNode, toElm) : [];
    dom.remove(fromElm);
    each$1(nestedLists, (list) => {
      if (isEmpty$1(dom, list) && list !== dom.getRoot()) {
        dom.remove(list);
      }
    });
  };
  const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
    empty(SugarElement.fromDom(toLi));
    mergeLiElements(editor.dom, fromLi, toLi);
    editor.selection.setCursorLocation(toLi, 0);
  };
  const mergeForward = (editor, rng, fromLi, toLi) => {
    const dom = editor.dom;
    if (dom.isEmpty(toLi)) {
      mergeIntoEmptyLi(editor, fromLi, toLi);
    } else {
      const bookmark = createBookmark(rng);
      mergeLiElements(dom, fromLi, toLi);
      editor.selection.setRng(resolveBookmark(bookmark));
    }
  };
  const mergeBackward = (editor, rng, fromLi, toLi) => {
    const bookmark = createBookmark(rng);
    mergeLiElements(editor.dom, fromLi, toLi);
    const resolvedBookmark = resolveBookmark(bookmark);
    editor.selection.setRng(resolvedBookmark);
  };
  const backspaceDeleteFromListToListCaret = (editor, isForward) => {
    const dom = editor.dom, selection = editor.selection;
    const selectionStartElm = selection.getStart();
    const root = getClosestEditingHost(editor, selectionStartElm);
    const li = dom.getParent(selection.getStart(), "LI", root);
    if (li) {
      const ul = li.parentNode;
      if (ul === editor.getBody() && isEmpty$1(dom, ul)) {
        return true;
      }
      const rng = normalizeRange(selection.getRng());
      const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), "LI", root);
      if (otherLi && otherLi !== li) {
        editor.undoManager.transact(() => {
          if (isForward) {
            mergeForward(editor, rng, otherLi, li);
          } else {
            if (isFirstChild(li)) {
              outdentListSelection(editor);
            } else {
              mergeBackward(editor, rng, li, otherLi);
            }
          }
        });
        return true;
      } else if (!otherLi) {
        if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
          editor.undoManager.transact(() => {
            flattenListSelection(editor);
          });
          return true;
        }
      }
    }
    return false;
  };
  const removeBlock = (dom, block, root) => {
    const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
    dom.remove(block);
    if (parentBlock && dom.isEmpty(parentBlock)) {
      dom.remove(parentBlock);
    }
  };
  const backspaceDeleteIntoListCaret = (editor, isForward) => {
    const dom = editor.dom;
    const selectionStartElm = editor.selection.getStart();
    const root = getClosestEditingHost(editor, selectionStartElm);
    const block = dom.getParent(selectionStartElm, dom.isBlock, root);
    if (block && dom.isEmpty(block)) {
      const rng = normalizeRange(editor.selection.getRng());
      const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), "LI", root);
      if (otherLi) {
        const findValidElement = (element) => contains$1([
          "td",
          "th",
          "caption"
        ], name(element));
        const findRoot = (node) => node.dom === root;
        const otherLiCell = closest(SugarElement.fromDom(otherLi), findValidElement, findRoot);
        const caretCell = closest(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
        if (!equals(otherLiCell, caretCell, eq)) {
          return false;
        }
        editor.undoManager.transact(() => {
          removeBlock(dom, block, root);
          mergeWithAdjacentLists(dom, otherLi.parentNode);
          editor.selection.select(otherLi, true);
          editor.selection.collapse(isForward);
        });
        return true;
      }
    }
    return false;
  };
  const backspaceDeleteCaret = (editor, isForward) => {
    return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
  };
  const hasListSelection = (editor) => {
    const selectionStartElm = editor.selection.getStart();
    const root = getClosestEditingHost(editor, selectionStartElm);
    const startListParent = editor.dom.getParent(selectionStartElm, "LI,DT,DD", root);
    return startListParent || getSelectedListItems(editor).length > 0;
  };
  const backspaceDeleteRange = (editor) => {
    if (hasListSelection(editor)) {
      editor.undoManager.transact(() => {
        editor.execCommand("Delete");
        normalizeLists(editor.dom, editor.getBody());
      });
      return true;
    }
    return false;
  };
  const backspaceDelete = (editor, isForward) => {
    return editor.selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor);
  };
  const setup$1 = (editor) => {
    editor.on("ExecCommand", (e) => {
      const cmd = e.command.toLowerCase();
      if ((cmd === "delete" || cmd === "forwarddelete") && hasListSelection(editor)) {
        normalizeLists(editor.dom, editor.getBody());
      }
    });
    editor.on("keydown", (e) => {
      if (e.keyCode === global$3.BACKSPACE) {
        if (backspaceDelete(editor, false)) {
          e.preventDefault();
        }
      } else if (e.keyCode === global$3.DELETE) {
        if (backspaceDelete(editor, true)) {
          e.preventDefault();
        }
      }
    });
  };
  const get = (editor) => ({
    backspaceDelete: (isForward) => {
      backspaceDelete(editor, isForward);
    }
  });
  const updateList = (editor, update) => {
    const parentList = getParentList(editor);
    editor.undoManager.transact(() => {
      if (isObject(update.styles)) {
        editor.dom.setStyles(parentList, update.styles);
      }
      if (isObject(update.attrs)) {
        each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
      }
    });
  };
  const parseAlphabeticBase26 = (str) => {
    const chars = reverse(trim(str).split(""));
    const values = map(chars, (char, i) => {
      const charValue = char.toUpperCase().charCodeAt(0) - "A".charCodeAt(0) + 1;
      return Math.pow(26, i) * charValue;
    });
    return foldl(values, (sum, v) => sum + v, 0);
  };
  const composeAlphabeticBase26 = (value) => {
    value--;
    if (value < 0) {
      return "";
    } else {
      const remainder = value % 26;
      const quotient = Math.floor(value / 26);
      const rest = composeAlphabeticBase26(quotient);
      const char = String.fromCharCode("A".charCodeAt(0) + remainder);
      return rest + char;
    }
  };
  const isUppercase = (str) => /^[A-Z]+$/.test(str);
  const isLowercase = (str) => /^[a-z]+$/.test(str);
  const isNumeric = (str) => /^[0-9]+$/.test(str);
  const deduceListType = (start) => {
    if (isNumeric(start)) {
      return 2;
    } else if (isUppercase(start)) {
      return 0;
    } else if (isLowercase(start)) {
      return 1;
    } else if (isEmpty(start)) {
      return 3;
    } else {
      return 4;
    }
  };
  const parseStartValue = (start) => {
    switch (deduceListType(start)) {
      case 2:
        return Optional.some({
          listStyleType: Optional.none(),
          start
        });
      case 0:
        return Optional.some({
          listStyleType: Optional.some("upper-alpha"),
          start: parseAlphabeticBase26(start).toString()
        });
      case 1:
        return Optional.some({
          listStyleType: Optional.some("lower-alpha"),
          start: parseAlphabeticBase26(start).toString()
        });
      case 3:
        return Optional.some({
          listStyleType: Optional.none(),
          start: ""
        });
      case 4:
        return Optional.none();
    }
  };
  const parseDetail = (detail) => {
    const start = parseInt(detail.start, 10);
    if (is$2(detail.listStyleType, "upper-alpha")) {
      return composeAlphabeticBase26(start);
    } else if (is$2(detail.listStyleType, "lower-alpha")) {
      return composeAlphabeticBase26(start).toLowerCase();
    } else {
      return detail.start;
    }
  };
  const open = (editor) => {
    const currentList = getParentList(editor);
    if (!isOlNode(currentList)) {
      return;
    }
    editor.windowManager.open({
      title: "List Properties",
      body: {
        type: "panel",
        items: [{
          type: "input",
          name: "start",
          label: "Start list at number",
          inputMode: "numeric"
        }]
      },
      initialData: {
        start: parseDetail({
          start: editor.dom.getAttrib(currentList, "start", "1"),
          listStyleType: Optional.some(editor.dom.getStyle(currentList, "list-style-type"))
        })
      },
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      onSubmit: (api) => {
        const data = api.getData();
        parseStartValue(data.start).each((detail) => {
          editor.execCommand("mceListUpdate", false, {
            attrs: { start: detail.start === "1" ? "" : detail.start },
            styles: { "list-style-type": detail.listStyleType.getOr("") }
          });
        });
        api.close();
      }
    });
  };
  const queryListCommandState = (editor, listName) => () => {
    const parentList = getParentList(editor);
    return parentList && parentList.nodeName === listName;
  };
  const registerDialog = (editor) => {
    editor.addCommand("mceListProps", () => {
      open(editor);
    });
  };
  const register$2 = (editor) => {
    editor.on("BeforeExecCommand", (e) => {
      const cmd = e.command.toLowerCase();
      if (cmd === "indent") {
        indentListSelection(editor);
      } else if (cmd === "outdent") {
        outdentListSelection(editor);
      }
    });
    editor.addCommand("InsertUnorderedList", (ui, detail) => {
      toggleList(editor, "UL", detail);
    });
    editor.addCommand("InsertOrderedList", (ui, detail) => {
      toggleList(editor, "OL", detail);
    });
    editor.addCommand("InsertDefinitionList", (ui, detail) => {
      toggleList(editor, "DL", detail);
    });
    editor.addCommand("RemoveList", () => {
      flattenListSelection(editor);
    });
    registerDialog(editor);
    editor.addCommand("mceListUpdate", (ui, detail) => {
      if (isObject(detail)) {
        updateList(editor, detail);
      }
    });
    editor.addQueryStateHandler("InsertUnorderedList", queryListCommandState(editor, "UL"));
    editor.addQueryStateHandler("InsertOrderedList", queryListCommandState(editor, "OL"));
    editor.addQueryStateHandler("InsertDefinitionList", queryListCommandState(editor, "DL"));
  };
  const setupTabKey = (editor) => {
    editor.on("keydown", (e) => {
      if (e.keyCode !== global$3.TAB || global$3.metaKeyPressed(e)) {
        return;
      }
      editor.undoManager.transact(() => {
        if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
          e.preventDefault();
        }
      });
    });
  };
  const setup = (editor) => {
    if (shouldIndentOnTab(editor)) {
      setupTabKey(editor);
    }
    setup$1(editor);
  };
  const register$1 = (editor) => {
    const exec = (command) => () => editor.execCommand(command);
    if (!editor.hasPlugin("advlist")) {
      editor.ui.registry.addToggleButton("numlist", {
        icon: "ordered-list",
        active: false,
        tooltip: "Numbered list",
        onAction: exec("InsertOrderedList"),
        onSetup: (api) => listState(editor, "OL", api.setActive)
      });
      editor.ui.registry.addToggleButton("bullist", {
        icon: "unordered-list",
        active: false,
        tooltip: "Bullet list",
        onAction: exec("InsertUnorderedList"),
        onSetup: (api) => listState(editor, "UL", api.setActive)
      });
    }
  };
  const register = (editor) => {
    const listProperties = {
      text: "List properties...",
      icon: "ordered-list",
      onAction: () => editor.execCommand("mceListProps"),
      onSetup: (api) => listState(editor, "OL", api.setEnabled)
    };
    editor.ui.registry.addMenuItem("listprops", listProperties);
    editor.ui.registry.addContextMenu("lists", {
      update: (node) => {
        const parentList = getParentList(editor, node);
        return isOlNode(parentList) ? ["listprops"] : [];
      }
    });
  };
  var Plugin = () => {
    global$6.add("lists", (editor) => {
      register$3(editor);
      if (editor.hasPlugin("rtc", true) === false) {
        setup(editor);
        register$2(editor);
      } else {
        registerDialog(editor);
      }
      register$1(editor);
      register(editor);
      return get(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const applyListFormat = (editor, listName, styleValue) => {
    const cmd = listName === "UL" ? "InsertUnorderedList" : "InsertOrderedList";
    editor.execCommand(cmd, false, styleValue === false ? null : { "list-style-type": styleValue });
  };
  const register$2 = (editor) => {
    editor.addCommand("ApplyUnorderedListStyle", (ui, value) => {
      applyListFormat(editor, "UL", value["list-style-type"]);
    });
    editor.addCommand("ApplyOrderedListStyle", (ui, value) => {
      applyListFormat(editor, "OL", value["list-style-type"]);
    });
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("advlist_number_styles", {
      processor: "string[]",
      default: "default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")
    });
    registerOption("advlist_bullet_styles", {
      processor: "string[]",
      default: "default,circle,square".split(",")
    });
  };
  const getNumberStyles = option("advlist_number_styles");
  const getBulletStyles = option("advlist_bullet_styles");
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const isChildOfBody = (editor, elm) => {
    return editor.dom.isChildOf(elm, editor.getBody());
  };
  const isTableCellNode = (node) => {
    return node && /^(TH|TD)$/.test(node.nodeName);
  };
  const isListNode = (editor) => (node) => {
    return node && /^(OL|UL|DL)$/.test(node.nodeName) && isChildOfBody(editor, node);
  };
  const getSelectedStyleType = (editor) => {
    const listElm = editor.dom.getParent(editor.selection.getNode(), "ol,ul");
    const style = editor.dom.getStyle(listElm, "listStyleType");
    return Optional.from(style);
  };
  const findIndex = (list, predicate) => {
    for (let index2 = 0; index2 < list.length; index2++) {
      const element = list[index2];
      if (predicate(element)) {
        return index2;
      }
    }
    return -1;
  };
  const styleValueToText = (styleValue) => {
    return styleValue.replace(/\-/g, " ").replace(/\b\w/g, (chr) => {
      return chr.toUpperCase();
    });
  };
  const isWithinList = (editor, e, nodeName) => {
    const tableCellIndex = findIndex(e.parents, isTableCellNode);
    const parents = tableCellIndex !== -1 ? e.parents.slice(0, tableCellIndex) : e.parents;
    const lists = global2.grep(parents, isListNode(editor));
    return lists.length > 0 && lists[0].nodeName === nodeName;
  };
  const makeSetupHandler = (editor, nodeName) => (api) => {
    const nodeChangeHandler = (e) => {
      api.setActive(isWithinList(editor, e, nodeName));
    };
    editor.on("NodeChange", nodeChangeHandler);
    return () => editor.off("NodeChange", nodeChangeHandler);
  };
  const addSplitButton = (editor, id, tooltip, cmd, nodeName, styles) => {
    editor.ui.registry.addSplitButton(id, {
      tooltip,
      icon: nodeName === "OL" ? "ordered-list" : "unordered-list",
      presets: "listpreview",
      columns: 3,
      fetch: (callback) => {
        const items = global2.map(styles, (styleValue) => {
          const iconStyle = nodeName === "OL" ? "num" : "bull";
          const iconName = styleValue === "disc" || styleValue === "decimal" ? "default" : styleValue;
          const itemValue = styleValue === "default" ? "" : styleValue;
          const displayText = styleValueToText(styleValue);
          return {
            type: "choiceitem",
            value: itemValue,
            icon: "list-" + iconStyle + "-" + iconName,
            text: displayText
          };
        });
        callback(items);
      },
      onAction: () => editor.execCommand(cmd),
      onItemAction: (_splitButtonApi, value) => {
        applyListFormat(editor, nodeName, value);
      },
      select: (value) => {
        const listStyleType = getSelectedStyleType(editor);
        return listStyleType.map((listStyle) => value === listStyle).getOr(false);
      },
      onSetup: makeSetupHandler(editor, nodeName)
    });
  };
  const addButton = (editor, id, tooltip, cmd, nodeName, _styles) => {
    editor.ui.registry.addToggleButton(id, {
      active: false,
      tooltip,
      icon: nodeName === "OL" ? "ordered-list" : "unordered-list",
      onSetup: makeSetupHandler(editor, nodeName),
      onAction: () => editor.execCommand(cmd)
    });
  };
  const addControl = (editor, id, tooltip, cmd, nodeName, styles) => {
    if (styles.length > 1) {
      addSplitButton(editor, id, tooltip, cmd, nodeName, styles);
    } else {
      addButton(editor, id, tooltip, cmd, nodeName);
    }
  };
  const register = (editor) => {
    addControl(editor, "numlist", "Numbered list", "InsertOrderedList", "OL", getNumberStyles(editor));
    addControl(editor, "bullist", "Bullet list", "InsertUnorderedList", "UL", getBulletStyles(editor));
  };
  var Plugin = () => {
    global$1.add("advlist", (editor) => {
      if (editor.hasPlugin("lists")) {
        register$1(editor);
        register(editor);
        register$2(editor);
      } else {
        console.error("Please use the Lists plugin together with the Advanced List plugin.");
      }
    });
  };
  Plugin();
})();
(function() {
  const Cell = (initial) => {
    let value2 = initial;
    const get2 = () => {
      return value2;
    };
    const set2 = (v) => {
      value2 = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const get$5 = (fullscreenState) => ({ isFullscreen: () => fullscreenState.get() !== null });
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
  const isSimpleType = (type2) => (value2) => typeof value2 === type2;
  const eq$1 = (t) => (a) => t === a;
  const isString = isType$1("string");
  const isArray = isType$1("array");
  const isNull = eq$1(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const noop = () => {
  };
  const compose = (fa, fb) => {
    return (...args) => {
      return fa(fb.apply(null, args));
    };
  };
  const compose1 = (fbc, fab) => (a) => fbc(fab(a));
  const constant = (value2) => {
    return () => {
      return value2;
    };
  };
  function curry(fn, ...initialArgs) {
    return (...restArgs) => {
      const all2 = initialArgs.concat(restArgs);
      return fn.apply(null, all2);
    };
  }
  const never = constant(false);
  const always = constant(true);
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder2) {
      if (this.tag) {
        return binder2(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get2 = () => subject.get();
    const set2 = (s) => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear,
      isSet,
      get: get2,
      set: set2
    };
  };
  const unbindable = () => singleton((s) => s.unbind());
  const value = () => {
    const subject = singleton(noop);
    const on = (f) => subject.get().each(f);
    return {
      ...subject,
      on
    };
  };
  const first = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      if (isNull(timer)) {
        timer = setTimeout(() => {
          timer = null;
          fn.apply(null, args);
        }, rate);
      }
    };
    return {
      cancel,
      throttle
    };
  };
  const nativePush = Array.prototype.push;
  const map = (xs, f) => {
    const len = xs.length;
    const r2 = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r2[i] = f(x, i);
    }
    return r2;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const filter$1 = (xs, pred) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r2.push(x);
      }
    }
    return r2;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find$1 = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const flatten = (xs) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r2, xs[i]);
    }
    return r2;
  };
  const bind$3 = (xs, f) => flatten(map(xs, f));
  const get$4 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get$4(xs, 0);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r2 = f(arr[i], i);
      if (r2.isSome()) {
        return r2;
      }
    }
    return Optional.none();
  };
  const keys = Object.keys;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const contains = (str, substr) => {
    return str.indexOf(substr) !== -1;
  };
  const isSupported$1 = (dom) => dom.style !== void 0 && isFunction(dom.style.getPropertyValue);
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const DOCUMENT = 9;
  const DOCUMENT_FRAGMENT = 11;
  const ELEMENT = 1;
  const TEXT = 3;
  const type = (element) => element.dom.nodeType;
  const isType = (t) => (element) => type(element) === t;
  const isElement = isType(ELEMENT);
  const isText = isType(TEXT);
  const isDocument = isType(DOCUMENT);
  const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  const is = (element, selector) => {
    const dom = element.dom;
    if (dom.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  const bypassSelector = (dom) => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  const all$1 = (selector, scope) => {
    const base = scope === void 0 ? document : scope.dom;
    return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  };
  const eq = (e1, e2) => e1.dom === e2.dom;
  const owner = (element) => SugarElement.fromDom(element.dom.ownerDocument);
  const documentOrOwner = (dos) => isDocument(dos) ? dos : owner(dos);
  const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  const parents = (element, isRoot) => {
    const stop = isFunction(isRoot) ? isRoot : never;
    let dom = element.dom;
    const ret = [];
    while (dom.parentNode !== null && dom.parentNode !== void 0) {
      const rawParent = dom.parentNode;
      const p = SugarElement.fromDom(rawParent);
      ret.push(p);
      if (stop(p) === true) {
        break;
      } else {
        dom = rawParent;
      }
    }
    return ret;
  };
  const siblings$2 = (element) => {
    const filterSelf = (elements) => filter$1(elements, (x) => !eq(element, x));
    return parent(element).map(children).map(filterSelf).getOr([]);
  };
  const children = (element) => map(element.dom.childNodes, SugarElement.fromDom);
  const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  const isSupported = constant(supported);
  const getRootNode = supported ? (e) => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  const getShadowRoot = (e) => {
    const r2 = getRootNode(e);
    return isShadowRoot(r2) ? Optional.some(r2) : Optional.none();
  };
  const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
  const getOriginalEventTarget = (event) => {
    if (isSupported() && isNonNullable(event.target)) {
      const el = SugarElement.fromDom(event.target);
      if (isElement(el) && isOpenShadowHost(el)) {
        if (event.composed && event.composedPath) {
          const composedPath = event.composedPath();
          if (composedPath) {
            return head(composedPath);
          }
        }
      }
    }
    return Optional.from(event.target);
  };
  const isOpenShadowHost = (element) => isNonNullable(element.dom.shadowRoot);
  const inBody = (element) => {
    const dom = isText(element) ? element.dom.parentNode : element.dom;
    if (dom === void 0 || dom === null || dom.ownerDocument === null) {
      return false;
    }
    const doc = dom.ownerDocument;
    return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  };
  const getBody = (doc) => {
    const b = doc.dom.body;
    if (b === null || b === void 0) {
      throw new Error("Body is not available yet");
    }
    return SugarElement.fromDom(b);
  };
  const rawSet = (dom, key, value2) => {
    if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
      dom.setAttribute(key, value2 + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value2, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value2) => {
    rawSet(element.dom, key, value2);
  };
  const get$3 = (element, key) => {
    const v = element.dom.getAttribute(key);
    return v === null ? void 0 : v;
  };
  const remove = (element, key) => {
    element.dom.removeAttribute(key);
  };
  const internalSet = (dom, property, value2) => {
    if (!isString(value2)) {
      console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value2, ":: Element ", dom);
      throw new Error("CSS value must be a string: " + value2);
    }
    if (isSupported$1(dom)) {
      dom.style.setProperty(property, value2);
    }
  };
  const setAll = (element, css) => {
    const dom = element.dom;
    each(css, (v, k) => {
      internalSet(dom, k, v);
    });
  };
  const get$2 = (element, property) => {
    const dom = element.dom;
    const styles = window.getComputedStyle(dom);
    const r2 = styles.getPropertyValue(property);
    return r2 === "" && !inBody(element) ? getUnsafeProperty(dom, property) : r2;
  };
  const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : "";
  const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
    target,
    x,
    y,
    stop,
    prevent,
    kill,
    raw
  });
  const fromRawEvent = (rawEvent) => {
    const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
    const stop = () => rawEvent.stopPropagation();
    const prevent = () => rawEvent.preventDefault();
    const kill = compose(prevent, stop);
    return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  };
  const handle = (filter2, handler) => (rawEvent) => {
    if (filter2(rawEvent)) {
      handler(fromRawEvent(rawEvent));
    }
  };
  const binder = (element, event, filter2, handler, useCapture) => {
    const wrapped = handle(filter2, handler);
    element.dom.addEventListener(event, wrapped, useCapture);
    return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  };
  const bind$2 = (element, event, filter2, handler) => binder(element, event, filter2, handler, false);
  const unbind = (element, event, handler, useCapture) => {
    element.dom.removeEventListener(event, handler, useCapture);
  };
  const filter = always;
  const bind$1 = (element, event, handler) => bind$2(element, event, filter, handler);
  const cached = (f) => {
    let called = false;
    let r2;
    return (...args) => {
      if (!called) {
        called = true;
        r2 = f.apply(null, args);
      }
      return r2;
    };
  };
  const DeviceType = (os, browser, userAgent, mediaMatch2) => {
    const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
    const isiPhone = os.isiOS() && !isiPad;
    const isMobile = os.isiOS() || os.isAndroid();
    const isTouch = isMobile || mediaMatch2("(pointer:coarse)");
    const isTablet = isiPad || !isiPhone && isMobile && mediaMatch2("(min-device-width:768px)");
    const isPhone = isiPhone || isMobile && !isTablet;
    const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
    const isDesktop = !isPhone && !isTablet && !iOSwebview;
    return {
      isiPad: constant(isiPad),
      isiPhone: constant(isiPhone),
      isTablet: constant(isTablet),
      isPhone: constant(isPhone),
      isTouch: constant(isTouch),
      isAndroid: os.isAndroid,
      isiOS: os.isiOS,
      isWebView: constant(iOSwebview),
      isDesktop: constant(isDesktop)
    };
  };
  const firstMatch = (regexes, s) => {
    for (let i = 0; i < regexes.length; i++) {
      const x = regexes[i];
      if (x.test(s)) {
        return x;
      }
    }
    return void 0;
  };
  const find = (regexes, agent) => {
    const r2 = firstMatch(regexes, agent);
    if (!r2) {
      return {
        major: 0,
        minor: 0
      };
    }
    const group = (i) => {
      return Number(agent.replace(r2, "$" + i));
    };
    return nu$2(group(1), group(2));
  };
  const detect$3 = (versionRegexes, agent) => {
    const cleanedAgent = String(agent).toLowerCase();
    if (versionRegexes.length === 0) {
      return unknown$2();
    }
    return find(versionRegexes, cleanedAgent);
  };
  const unknown$2 = () => {
    return nu$2(0, 0);
  };
  const nu$2 = (major, minor) => {
    return {
      major,
      minor
    };
  };
  const Version = {
    nu: nu$2,
    detect: detect$3,
    unknown: unknown$2
  };
  const detectBrowser$1 = (browsers2, userAgentData) => {
    return findMap(userAgentData.brands, (uaBrand) => {
      const lcBrand = uaBrand.brand.toLowerCase();
      return find$1(browsers2, (browser) => {
        var _a;
        return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
      }).map((info) => ({
        current: info.name,
        version: Version.nu(parseInt(uaBrand.version, 10), 0)
      }));
    });
  };
  const detect$2 = (candidates, userAgent) => {
    const agent = String(userAgent).toLowerCase();
    return find$1(candidates, (candidate) => {
      return candidate.search(agent);
    });
  };
  const detectBrowser = (browsers2, userAgent) => {
    return detect$2(browsers2, userAgent).map((browser) => {
      const version = Version.detect(browser.versionRegexes, userAgent);
      return {
        current: browser.name,
        version
      };
    });
  };
  const detectOs = (oses2, userAgent) => {
    return detect$2(oses2, userAgent).map((os) => {
      const version = Version.detect(os.versionRegexes, userAgent);
      return {
        current: os.name,
        version
      };
    });
  };
  const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  const checkContains = (target) => {
    return (uastring) => {
      return contains(uastring, target);
    };
  };
  const browsers = [
    {
      name: "Edge",
      versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
      search: (uastring) => {
        return contains(uastring, "edge/") && contains(uastring, "chrome") && contains(uastring, "safari") && contains(uastring, "applewebkit");
      }
    },
    {
      name: "Chromium",
      brand: "Chromium",
      versionRegexes: [
        /.*?chrome\/([0-9]+)\.([0-9]+).*/,
        normalVersionRegex
      ],
      search: (uastring) => {
        return contains(uastring, "chrome") && !contains(uastring, "chromeframe");
      }
    },
    {
      name: "IE",
      versionRegexes: [
        /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
        /.*?rv:([0-9]+)\.([0-9]+).*/
      ],
      search: (uastring) => {
        return contains(uastring, "msie") || contains(uastring, "trident");
      }
    },
    {
      name: "Opera",
      versionRegexes: [
        normalVersionRegex,
        /.*?opera\/([0-9]+)\.([0-9]+).*/
      ],
      search: checkContains("opera")
    },
    {
      name: "Firefox",
      versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
      search: checkContains("firefox")
    },
    {
      name: "Safari",
      versionRegexes: [
        normalVersionRegex,
        /.*?cpu os ([0-9]+)_([0-9]+).*/
      ],
      search: (uastring) => {
        return (contains(uastring, "safari") || contains(uastring, "mobile/")) && contains(uastring, "applewebkit");
      }
    }
  ];
  const oses = [
    {
      name: "Windows",
      search: checkContains("win"),
      versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "iOS",
      search: (uastring) => {
        return contains(uastring, "iphone") || contains(uastring, "ipad");
      },
      versionRegexes: [
        /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
        /.*cpu os ([0-9]+)_([0-9]+).*/,
        /.*cpu iphone os ([0-9]+)_([0-9]+).*/
      ]
    },
    {
      name: "Android",
      search: checkContains("android"),
      versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "macOS",
      search: checkContains("mac os x"),
      versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
    },
    {
      name: "Linux",
      search: checkContains("linux"),
      versionRegexes: []
    },
    {
      name: "Solaris",
      search: checkContains("sunos"),
      versionRegexes: []
    },
    {
      name: "FreeBSD",
      search: checkContains("freebsd"),
      versionRegexes: []
    },
    {
      name: "ChromeOS",
      search: checkContains("cros"),
      versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
    }
  ];
  const PlatformInfo = {
    browsers: constant(browsers),
    oses: constant(oses)
  };
  const edge = "Edge";
  const chromium = "Chromium";
  const ie = "IE";
  const opera = "Opera";
  const firefox = "Firefox";
  const safari = "Safari";
  const unknown$1 = () => {
    return nu$1({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu$1 = (info) => {
    const current = info.current;
    const version = info.version;
    const isBrowser = (name) => () => current === name;
    return {
      current,
      version,
      isEdge: isBrowser(edge),
      isChromium: isBrowser(chromium),
      isIE: isBrowser(ie),
      isOpera: isBrowser(opera),
      isFirefox: isBrowser(firefox),
      isSafari: isBrowser(safari)
    };
  };
  const Browser = {
    unknown: unknown$1,
    nu: nu$1,
    edge: constant(edge),
    chromium: constant(chromium),
    ie: constant(ie),
    opera: constant(opera),
    firefox: constant(firefox),
    safari: constant(safari)
  };
  const windows = "Windows";
  const ios = "iOS";
  const android = "Android";
  const linux = "Linux";
  const macos = "macOS";
  const solaris = "Solaris";
  const freebsd = "FreeBSD";
  const chromeos = "ChromeOS";
  const unknown = () => {
    return nu({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu = (info) => {
    const current = info.current;
    const version = info.version;
    const isOS = (name) => () => current === name;
    return {
      current,
      version,
      isWindows: isOS(windows),
      isiOS: isOS(ios),
      isAndroid: isOS(android),
      isMacOS: isOS(macos),
      isLinux: isOS(linux),
      isSolaris: isOS(solaris),
      isFreeBSD: isOS(freebsd),
      isChromeOS: isOS(chromeos)
    };
  };
  const OperatingSystem = {
    unknown,
    nu,
    windows: constant(windows),
    ios: constant(ios),
    android: constant(android),
    linux: constant(linux),
    macos: constant(macos),
    solaris: constant(solaris),
    freebsd: constant(freebsd),
    chromeos: constant(chromeos)
  };
  const detect$1 = (userAgent, userAgentDataOpt, mediaMatch2) => {
    const browsers2 = PlatformInfo.browsers();
    const oses2 = PlatformInfo.oses();
    const browser = userAgentDataOpt.bind((userAgentData) => detectBrowser$1(browsers2, userAgentData)).orThunk(() => detectBrowser(browsers2, userAgent)).fold(Browser.unknown, Browser.nu);
    const os = detectOs(oses2, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
    const deviceType = DeviceType(os, browser, userAgent, mediaMatch2);
    return {
      browser,
      os,
      deviceType
    };
  };
  const PlatformDetection = { detect: detect$1 };
  const mediaMatch = (query) => window.matchMedia(query).matches;
  let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  const detect = () => platform();
  const r = (left, top) => {
    const translate = (x, y) => r(left + x, top + y);
    return {
      left,
      top,
      translate
    };
  };
  const SugarPosition = r;
  const get$1 = (_DOC) => {
    const doc = _DOC !== void 0 ? _DOC.dom : document;
    const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
    const y = doc.body.scrollTop || doc.documentElement.scrollTop;
    return SugarPosition(x, y);
  };
  const get = (_win) => {
    const win = _win === void 0 ? window : _win;
    if (detect().browser.isFirefox()) {
      return Optional.none();
    } else {
      return Optional.from(win.visualViewport);
    }
  };
  const bounds = (x, y, width, height) => ({
    x,
    y,
    width,
    height,
    right: x + width,
    bottom: y + height
  });
  const getBounds = (_win) => {
    const win = _win === void 0 ? window : _win;
    const doc = win.document;
    const scroll = get$1(SugarElement.fromDom(doc));
    return get(win).fold(() => {
      const html = win.document.documentElement;
      const width = html.clientWidth;
      const height = html.clientHeight;
      return bounds(scroll.left, scroll.top, width, height);
    }, (visualViewport) => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  };
  const bind = (name, callback, _win) => get(_win).map((visualViewport) => {
    const handler = (e) => callback(fromRawEvent(e));
    visualViewport.addEventListener(name, handler);
    return { unbind: () => visualViewport.removeEventListener(name, handler) };
  }).getOrThunk(() => ({ unbind: noop }));
  var global$1 = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils");
  var global2 = tinymce.util.Tools.resolve("tinymce.Env");
  const fireFullscreenStateChanged = (editor, state) => {
    editor.dispatch("FullscreenStateChanged", { state });
    editor.dispatch("ResizeEditor");
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("fullscreen_native", {
      processor: "boolean",
      default: false
    });
  };
  const getFullscreenNative = option("fullscreen_native");
  const getFullscreenRoot = (editor) => {
    const elem = SugarElement.fromDom(editor.getElement());
    return getShadowRoot(elem).map(getShadowHost).getOrThunk(() => getBody(owner(elem)));
  };
  const getFullscreenElement = (root) => {
    if (root.fullscreenElement !== void 0) {
      return root.fullscreenElement;
    } else if (root.msFullscreenElement !== void 0) {
      return root.msFullscreenElement;
    } else if (root.webkitFullscreenElement !== void 0) {
      return root.webkitFullscreenElement;
    } else {
      return null;
    }
  };
  const getFullscreenchangeEventName = () => {
    if (document.fullscreenElement !== void 0) {
      return "fullscreenchange";
    } else if (document.msFullscreenElement !== void 0) {
      return "MSFullscreenChange";
    } else if (document.webkitFullscreenElement !== void 0) {
      return "webkitfullscreenchange";
    } else {
      return "fullscreenchange";
    }
  };
  const requestFullscreen = (sugarElem) => {
    const elem = sugarElem.dom;
    if (elem.requestFullscreen) {
      elem.requestFullscreen();
    } else if (elem.msRequestFullscreen) {
      elem.msRequestFullscreen();
    } else if (elem.webkitRequestFullScreen) {
      elem.webkitRequestFullScreen();
    }
  };
  const exitFullscreen = (sugarDoc) => {
    const doc = sugarDoc.dom;
    if (doc.exitFullscreen) {
      doc.exitFullscreen();
    } else if (doc.msExitFullscreen) {
      doc.msExitFullscreen();
    } else if (doc.webkitCancelFullScreen) {
      doc.webkitCancelFullScreen();
    }
  };
  const isFullscreenElement = (elem) => elem.dom === getFullscreenElement(owner(elem).dom);
  const ancestors$1 = (scope, predicate, isRoot) => filter$1(parents(scope, isRoot), predicate);
  const siblings$1 = (scope, predicate) => filter$1(siblings$2(scope), predicate);
  const all = (selector) => all$1(selector);
  const ancestors = (scope, selector, isRoot) => ancestors$1(scope, (e) => is(e, selector), isRoot);
  const siblings = (scope, selector) => siblings$1(scope, (e) => is(e, selector));
  const attr = "data-ephox-mobile-fullscreen-style";
  const siblingStyles = "display:none!important;";
  const ancestorPosition = "position:absolute!important;";
  const ancestorStyles = "top:0!important;left:0!important;margin:0!important;padding:0!important;width:100%!important;height:100%!important;overflow:visible!important;";
  const bgFallback = "background-color:rgb(255,255,255)!important;";
  const isAndroid = global2.os.isAndroid();
  const matchColor = (editorBody) => {
    const color = get$2(editorBody, "background-color");
    return color !== void 0 && color !== "" ? "background-color:" + color + "!important" : bgFallback;
  };
  const clobberStyles = (dom, container, editorBody) => {
    const gatherSiblings = (element) => {
      return siblings(element, "*:not(.tox-silver-sink)");
    };
    const clobber = (clobberStyle) => (element) => {
      const styles = get$3(element, "style");
      const backup = styles === void 0 ? "no-styles" : styles.trim();
      if (backup === clobberStyle) {
        return;
      } else {
        set(element, attr, backup);
        setAll(element, dom.parseStyle(clobberStyle));
      }
    };
    const ancestors$12 = ancestors(container, "*");
    const siblings$12 = bind$3(ancestors$12, gatherSiblings);
    const bgColor = matchColor(editorBody);
    each$1(siblings$12, clobber(siblingStyles));
    each$1(ancestors$12, clobber(ancestorPosition + ancestorStyles + bgColor));
    const containerStyles = isAndroid === true ? "" : ancestorPosition;
    clobber(containerStyles + ancestorStyles + bgColor)(container);
  };
  const restoreStyles = (dom) => {
    const clobberedEls = all("[" + attr + "]");
    each$1(clobberedEls, (element) => {
      const restore = get$3(element, attr);
      if (restore !== "no-styles") {
        setAll(element, dom.parseStyle(restore));
      } else {
        remove(element, "style");
      }
      remove(element, attr);
    });
  };
  const DOM = global$1.DOM;
  const getScrollPos = () => getBounds(window);
  const setScrollPos = (pos) => window.scrollTo(pos.x, pos.y);
  const viewportUpdate = get().fold(() => ({
    bind: noop,
    unbind: noop
  }), (visualViewport) => {
    const editorContainer = value();
    const resizeBinder = unbindable();
    const scrollBinder = unbindable();
    const refreshScroll = () => {
      document.body.scrollTop = 0;
      document.documentElement.scrollTop = 0;
    };
    const refreshVisualViewport = () => {
      window.requestAnimationFrame(() => {
        editorContainer.on((container) => setAll(container, {
          top: visualViewport.offsetTop + "px",
          left: visualViewport.offsetLeft + "px",
          height: visualViewport.height + "px",
          width: visualViewport.width + "px"
        }));
      });
    };
    const update = first(() => {
      refreshScroll();
      refreshVisualViewport();
    }, 50);
    const bind$12 = (element) => {
      editorContainer.set(element);
      update.throttle();
      resizeBinder.set(bind("resize", update.throttle));
      scrollBinder.set(bind("scroll", update.throttle));
    };
    const unbind2 = () => {
      editorContainer.on(() => {
        resizeBinder.clear();
        scrollBinder.clear();
      });
      editorContainer.clear();
    };
    return {
      bind: bind$12,
      unbind: unbind2
    };
  });
  const toggleFullscreen = (editor, fullscreenState) => {
    const body = document.body;
    const documentElement = document.documentElement;
    const editorContainer = editor.getContainer();
    const editorContainerS = SugarElement.fromDom(editorContainer);
    const fullscreenRoot = getFullscreenRoot(editor);
    const fullscreenInfo = fullscreenState.get();
    const editorBody = SugarElement.fromDom(editor.getBody());
    const isTouch = global2.deviceType.isTouch();
    const editorContainerStyle = editorContainer.style;
    const iframe = editor.iframeElement;
    const iframeStyle = iframe.style;
    const handleClasses = (handler) => {
      handler(body, "tox-fullscreen");
      handler(documentElement, "tox-fullscreen");
      handler(editorContainer, "tox-fullscreen");
      getShadowRoot(editorContainerS).map((root) => getShadowHost(root).dom).each((host) => {
        handler(host, "tox-fullscreen");
        handler(host, "tox-shadowhost");
      });
    };
    const cleanup = () => {
      if (isTouch) {
        restoreStyles(editor.dom);
      }
      handleClasses(DOM.removeClass);
      viewportUpdate.unbind();
      Optional.from(fullscreenState.get()).each((info) => info.fullscreenChangeHandler.unbind());
    };
    if (!fullscreenInfo) {
      const fullscreenChangeHandler = bind$1(owner(fullscreenRoot), getFullscreenchangeEventName(), (_evt) => {
        if (getFullscreenNative(editor)) {
          if (!isFullscreenElement(fullscreenRoot) && fullscreenState.get() !== null) {
            toggleFullscreen(editor, fullscreenState);
          }
        }
      });
      const newFullScreenInfo = {
        scrollPos: getScrollPos(),
        containerWidth: editorContainerStyle.width,
        containerHeight: editorContainerStyle.height,
        containerTop: editorContainerStyle.top,
        containerLeft: editorContainerStyle.left,
        iframeWidth: iframeStyle.width,
        iframeHeight: iframeStyle.height,
        fullscreenChangeHandler
      };
      if (isTouch) {
        clobberStyles(editor.dom, editorContainerS, editorBody);
      }
      iframeStyle.width = iframeStyle.height = "100%";
      editorContainerStyle.width = editorContainerStyle.height = "";
      handleClasses(DOM.addClass);
      viewportUpdate.bind(editorContainerS);
      editor.on("remove", cleanup);
      fullscreenState.set(newFullScreenInfo);
      if (getFullscreenNative(editor)) {
        requestFullscreen(fullscreenRoot);
      }
      fireFullscreenStateChanged(editor, true);
    } else {
      fullscreenInfo.fullscreenChangeHandler.unbind();
      if (getFullscreenNative(editor) && isFullscreenElement(fullscreenRoot)) {
        exitFullscreen(owner(fullscreenRoot));
      }
      iframeStyle.width = fullscreenInfo.iframeWidth;
      iframeStyle.height = fullscreenInfo.iframeHeight;
      editorContainerStyle.width = fullscreenInfo.containerWidth;
      editorContainerStyle.height = fullscreenInfo.containerHeight;
      editorContainerStyle.top = fullscreenInfo.containerTop;
      editorContainerStyle.left = fullscreenInfo.containerLeft;
      cleanup();
      setScrollPos(fullscreenInfo.scrollPos);
      fullscreenState.set(null);
      fireFullscreenStateChanged(editor, false);
      editor.off("remove", cleanup);
    }
  };
  const register$1 = (editor, fullscreenState) => {
    editor.addCommand("mceFullScreen", () => {
      toggleFullscreen(editor, fullscreenState);
    });
  };
  const makeSetupHandler = (editor, fullscreenState) => (api) => {
    api.setActive(fullscreenState.get() !== null);
    const editorEventCallback = (e) => api.setActive(e.state);
    editor.on("FullscreenStateChanged", editorEventCallback);
    return () => editor.off("FullscreenStateChanged", editorEventCallback);
  };
  const register = (editor, fullscreenState) => {
    const onAction = () => editor.execCommand("mceFullScreen");
    editor.ui.registry.addToggleMenuItem("fullscreen", {
      text: "Fullscreen",
      icon: "fullscreen",
      shortcut: "Meta+Shift+F",
      onAction,
      onSetup: makeSetupHandler(editor, fullscreenState)
    });
    editor.ui.registry.addToggleButton("fullscreen", {
      tooltip: "Fullscreen",
      icon: "fullscreen",
      onAction,
      onSetup: makeSetupHandler(editor, fullscreenState)
    });
  };
  var Plugin = () => {
    global$2.add("fullscreen", (editor) => {
      const fullscreenState = Cell(null);
      if (editor.inline) {
        return get$5(fullscreenState);
      }
      register$2(editor);
      register$1(editor, fullscreenState);
      register(editor, fullscreenState);
      editor.addShortcut("Meta+Shift+F", "", "mceFullScreen");
      return get$5(fullscreenState);
    });
  };
  Plugin();
})();
(function() {
  const Cell = (initial) => {
    let value = initial;
    const get2 = () => {
      return value;
    };
    const set = (v) => {
      value = v;
    };
    return {
      get: get2,
      set
    };
  };
  var global$3 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const get$1 = (customTabs) => {
    const addTab = (spec) => {
      const currentCustomTabs = customTabs.get();
      currentCustomTabs[spec.name] = spec;
      customTabs.set(currentCustomTabs);
    };
    return { addTab };
  };
  const register$2 = (editor, dialogOpener) => {
    editor.addCommand("mceHelp", dialogOpener);
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("help_tabs", { processor: "array" });
  };
  const getHelpTabs = option("help_tabs");
  const getForcedPlugins = option("forced_plugins");
  const register = (editor, dialogOpener) => {
    editor.ui.registry.addButton("help", {
      icon: "help",
      tooltip: "Help",
      onAction: dialogOpener
    });
    editor.ui.registry.addMenuItem("help", {
      text: "Help",
      icon: "help",
      shortcut: "Alt+0",
      onAction: dialogOpener
    });
  };
  const eq = (t) => (a) => t === a;
  const isUndefined = eq(void 0);
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const constant = (value) => {
    return () => {
      return value;
    };
  };
  const never = constant(false);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativeIndexOf = Array.prototype.indexOf;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains = (xs, x) => rawIndexOf(xs, x) > -1;
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const filter = (xs, pred) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r.push(x);
      }
    }
    return r;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const get = (obj, key) => {
    return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const cat = (arr) => {
    const r = [];
    const push = (x) => {
      r.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r;
  };
  const description = `<h1>Editor UI keyboard navigation</h1>

<h2>Activating keyboard navigation</h2>

<p>The sections of the outer UI of the editor - the menubar, toolbar, sidebar and footer - are all keyboard navigable. As such, there are multiple ways to activate keyboard navigation:</p>
<ul>
  <li>Focus the menubar: Alt + F9 (Windows) or &#x2325;F9 (MacOS)</li>
  <li>Focus the toolbar: Alt + F10 (Windows) or &#x2325;F10 (MacOS)</li>
  <li>Focus the footer: Alt + F11 (Windows) or &#x2325;F11 (MacOS)</li>
</ul>

<p>Focusing the menubar or toolbar will start keyboard navigation at the first item in the menubar or toolbar, which will be highlighted with a gray background. Focusing the footer will start keyboard navigation at the first item in the element path, which will be highlighted with an underline. </p>

<h2>Moving between UI sections</h2>

<p>When keyboard navigation is active, pressing tab will move the focus to the next major section of the UI, where applicable. These sections are:</p>
<ul>
  <li>the menubar</li>
  <li>each group of the toolbar </li>
  <li>the sidebar</li>
  <li>the element path in the footer </li>
  <li>the wordcount toggle button in the footer </li>
  <li>the branding link in the footer </li>
  <li>the editor resize handle in the footer</li>
</ul>

<p>Pressing shift + tab will move backwards through the same sections, except when moving from the footer to the toolbar. Focusing the element path then pressing shift + tab will move focus to the first toolbar group, not the last.</p>

<h2>Moving within UI sections</h2>

<p>Keyboard navigation within UI sections can usually be achieved using the left and right arrow keys. This includes:</p>
<ul>
  <li>moving between menus in the menubar</li>
  <li>moving between buttons in a toolbar group</li>
  <li>moving between items in the element path</li>
</ul>

<p>In all these UI sections, keyboard navigation will cycle within the section. For example, focusing the last button in a toolbar group then pressing right arrow will move focus to the first item in the same toolbar group. </p>

<h1>Executing buttons</h1>

<p>To execute a button, navigate the selection to the desired button and hit space or enter.</p>

<h1>Opening, navigating and closing menus</h1>

<p>When focusing a menubar button or a toolbar button with a menu, pressing space, enter or down arrow will open the menu. When the menu opens the first item will be selected. To move up or down the menu, press the up or down arrow key respectively. This is the same for submenus, which can also be opened and closed using the left and right arrow keys.</p>

<p>To close any active menu, hit the escape key. When a menu is closed the selection will be restored to its previous selection. This also works for closing submenus.</p>

<h1>Context toolbars and menus</h1>

<p>To focus an open context toolbar such as the table context toolbar, press Ctrl + F9 (Windows) or &#x2303;F9 (MacOS).</p>

<p>Context toolbar navigation is the same as toolbar navigation, and context menu navigation is the same as standard menu navigation.</p>

<h1>Dialog navigation</h1>

<p>There are two types of dialog UIs in TinyMCE: tabbed dialogs and non-tabbed dialogs.</p>

<p>When a non-tabbed dialog is opened, the first interactive component in the dialog will be focused. Users can navigate between interactive components by pressing tab. This includes any footer buttons. Navigation will cycle back to the first dialog component if tab is pressed while focusing the last component in the dialog. Pressing shift + tab will navigate backwards.</p>

<p>When a tabbed dialog is opened, the first button in the tab menu is focused. Pressing tab will navigate to the first interactive component in that tab, and will cycle through the tab\u2019s components, the footer buttons, then back to the tab button. To switch to another tab, focus the tab button for the current tab, then use the arrow keys to cycle through the tab buttons.</p>`;
  const tab$3 = () => {
    const body = {
      type: "htmlpanel",
      presets: "document",
      html: description
    };
    return {
      name: "keyboardnav",
      title: "Keyboard Navigation",
      items: [body]
    };
  };
  var global$2 = tinymce.util.Tools.resolve("tinymce.Env");
  const convertText = (source) => {
    const isMac = global$2.os.isMacOS() || global$2.os.isiOS();
    const mac = {
      alt: "&#x2325;",
      ctrl: "&#x2303;",
      shift: "&#x21E7;",
      meta: "&#x2318;",
      access: "&#x2303;&#x2325;"
    };
    const other = {
      meta: "Ctrl ",
      access: "Shift + Alt "
    };
    const replace = isMac ? mac : other;
    const shortcut = source.split("+");
    const updated = map(shortcut, (segment) => {
      const search = segment.toLowerCase().trim();
      return has(replace, search) ? replace[search] : segment;
    });
    return isMac ? updated.join("").replace(/\s/, "") : updated.join("+");
  };
  const shortcuts = [
    {
      shortcuts: ["Meta + B"],
      action: "Bold"
    },
    {
      shortcuts: ["Meta + I"],
      action: "Italic"
    },
    {
      shortcuts: ["Meta + U"],
      action: "Underline"
    },
    {
      shortcuts: ["Meta + A"],
      action: "Select all"
    },
    {
      shortcuts: [
        "Meta + Y",
        "Meta + Shift + Z"
      ],
      action: "Redo"
    },
    {
      shortcuts: ["Meta + Z"],
      action: "Undo"
    },
    {
      shortcuts: ["Access + 1"],
      action: "Heading 1"
    },
    {
      shortcuts: ["Access + 2"],
      action: "Heading 2"
    },
    {
      shortcuts: ["Access + 3"],
      action: "Heading 3"
    },
    {
      shortcuts: ["Access + 4"],
      action: "Heading 4"
    },
    {
      shortcuts: ["Access + 5"],
      action: "Heading 5"
    },
    {
      shortcuts: ["Access + 6"],
      action: "Heading 6"
    },
    {
      shortcuts: ["Access + 7"],
      action: "Paragraph"
    },
    {
      shortcuts: ["Access + 8"],
      action: "Div"
    },
    {
      shortcuts: ["Access + 9"],
      action: "Address"
    },
    {
      shortcuts: ["Alt + 0"],
      action: "Open help dialog"
    },
    {
      shortcuts: ["Alt + F9"],
      action: "Focus to menubar"
    },
    {
      shortcuts: ["Alt + F10"],
      action: "Focus to toolbar"
    },
    {
      shortcuts: ["Alt + F11"],
      action: "Focus to element path"
    },
    {
      shortcuts: ["Ctrl + F9"],
      action: "Focus to contextual toolbar"
    },
    {
      shortcuts: ["Shift + Enter"],
      action: "Open popup menu for split buttons"
    },
    {
      shortcuts: ["Meta + K"],
      action: "Insert link (if link plugin activated)"
    },
    {
      shortcuts: ["Meta + S"],
      action: "Save (if save plugin activated)"
    },
    {
      shortcuts: ["Meta + F"],
      action: "Find (if searchreplace plugin activated)"
    },
    {
      shortcuts: ["Meta + Shift + F"],
      action: "Switch to or from fullscreen mode"
    }
  ];
  const tab$2 = () => {
    const shortcutList = map(shortcuts, (shortcut) => {
      const shortcutText = map(shortcut.shortcuts, convertText).join(" or ");
      return [
        shortcut.action,
        shortcutText
      ];
    });
    const tablePanel = {
      type: "table",
      header: [
        "Action",
        "Shortcut"
      ],
      cells: shortcutList
    };
    return {
      name: "shortcuts",
      title: "Handy Shortcuts",
      items: [tablePanel]
    };
  };
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.I18n");
  const urls = map([
    {
      key: "advlist",
      name: "Advanced List"
    },
    {
      key: "anchor",
      name: "Anchor"
    },
    {
      key: "autolink",
      name: "Autolink"
    },
    {
      key: "autoresize",
      name: "Autoresize"
    },
    {
      key: "autosave",
      name: "Autosave"
    },
    {
      key: "charmap",
      name: "Character Map"
    },
    {
      key: "code",
      name: "Code"
    },
    {
      key: "codesample",
      name: "Code Sample"
    },
    {
      key: "colorpicker",
      name: "Color Picker"
    },
    {
      key: "directionality",
      name: "Directionality"
    },
    {
      key: "emoticons",
      name: "Emoticons"
    },
    {
      key: "fullscreen",
      name: "Full Screen"
    },
    {
      key: "help",
      name: "Help"
    },
    {
      key: "image",
      name: "Image"
    },
    {
      key: "importcss",
      name: "Import CSS"
    },
    {
      key: "insertdatetime",
      name: "Insert Date/Time"
    },
    {
      key: "link",
      name: "Link"
    },
    {
      key: "lists",
      name: "Lists"
    },
    {
      key: "media",
      name: "Media"
    },
    {
      key: "nonbreaking",
      name: "Nonbreaking"
    },
    {
      key: "pagebreak",
      name: "Page Break"
    },
    {
      key: "preview",
      name: "Preview"
    },
    {
      key: "quickbars",
      name: "Quick Toolbars"
    },
    {
      key: "save",
      name: "Save"
    },
    {
      key: "searchreplace",
      name: "Search and Replace"
    },
    {
      key: "table",
      name: "Table"
    },
    {
      key: "template",
      name: "Template"
    },
    {
      key: "textcolor",
      name: "Text Color"
    },
    {
      key: "visualblocks",
      name: "Visual Blocks"
    },
    {
      key: "visualchars",
      name: "Visual Characters"
    },
    {
      key: "wordcount",
      name: "Word Count"
    },
    {
      key: "a11ychecker",
      name: "Accessibility Checker",
      type: "premium"
    },
    {
      key: "advcode",
      name: "Advanced Code Editor",
      type: "premium"
    },
    {
      key: "advtable",
      name: "Advanced Tables",
      type: "premium"
    },
    {
      key: "autocorrect",
      name: "Autocorrect",
      type: "premium"
    },
    {
      key: "casechange",
      name: "Case Change",
      type: "premium"
    },
    {
      key: "checklist",
      name: "Checklist",
      type: "premium"
    },
    {
      key: "editimage",
      name: "Enhanced Image Editing",
      type: "premium"
    },
    {
      key: "mediaembed",
      name: "Enhanced Media Embed",
      type: "premium",
      slug: "introduction-to-mediaembed"
    },
    {
      key: "export",
      name: "Export",
      type: "premium"
    },
    {
      key: "formatpainter",
      name: "Format Painter",
      type: "premium"
    },
    {
      key: "linkchecker",
      name: "Link Checker",
      type: "premium"
    },
    {
      key: "mentions",
      name: "Mentions",
      type: "premium"
    },
    {
      key: "pageembed",
      name: "Page Embed",
      type: "premium"
    },
    {
      key: "permanentpen",
      name: "Permanent Pen",
      type: "premium"
    },
    {
      key: "powerpaste",
      name: "PowerPaste",
      type: "premium",
      slug: "introduction-to-powerpaste"
    },
    {
      key: "rtc",
      name: "Real-Time Collaboration",
      type: "premium",
      slug: "rtc-introduction"
    },
    {
      key: "tinymcespellchecker",
      name: "Spell Checker Pro",
      type: "premium",
      slug: "introduction-to-tiny-spellchecker"
    },
    {
      key: "tinycomments",
      name: "Tiny Comments",
      type: "premium",
      slug: "introduction-to-tiny-comments"
    },
    {
      key: "tinydrive",
      name: "Tiny Drive",
      type: "premium",
      slug: "tinydrive-introduction"
    },
    {
      key: "tableofcontents",
      name: "Table of Contents",
      type: "premium"
    }
  ], (item) => ({
    ...item,
    type: item.type || "opensource",
    slug: item.slug || item.key
  }));
  const tab$1 = (editor) => {
    const availablePlugins = () => {
      const premiumPlugins = filter(urls, ({ key, type }) => {
        return key !== "autocorrect" && type === "premium";
      });
      const premiumPluginList = map(premiumPlugins, (plugin) => "<li>" + global$1.translate(plugin.name) + "</li>").join("");
      return '<div data-mce-tabstop="1" tabindex="-1"><p><b>' + global$1.translate("Premium plugins:") + "</b></p><ul>" + premiumPluginList + '<li class="tox-help__more-link" "><a href="https://www.tiny.cloud/pricing/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" rel="noopener" target="_blank">' + global$1.translate("Learn more...") + "</a></li></ul></div>";
    };
    const makeLink = (p) => `<a href="${p.url}" target="_blank" rel="noopener">${p.name}</a>`;
    const maybeUrlize = (editor2, key) => find(urls, (x) => {
      return x.key === key;
    }).fold(() => {
      const getMetadata = editor2.plugins[key].getMetadata;
      return typeof getMetadata === "function" ? makeLink(getMetadata()) : key;
    }, (x) => {
      const name = x.type === "premium" ? `${x.name}*` : x.name;
      return makeLink({
        name,
        url: `https://www.tiny.cloud/docs/tinymce/6/${x.slug}/`
      });
    });
    const getPluginKeys = (editor2) => {
      const keys$1 = keys(editor2.plugins);
      const forcedPlugins = getForcedPlugins(editor2);
      return isUndefined(forcedPlugins) ? keys$1 : filter(keys$1, (k) => !contains(forcedPlugins, k));
    };
    const pluginLister = (editor2) => {
      const pluginKeys = getPluginKeys(editor2);
      const pluginLis = map(pluginKeys, (key) => {
        return "<li>" + maybeUrlize(editor2, key) + "</li>";
      });
      const count = pluginLis.length;
      const pluginsString = pluginLis.join("");
      const html = "<p><b>" + global$1.translate([
        "Plugins installed ({0}):",
        count
      ]) + "</b></p><ul>" + pluginsString + "</ul>";
      return html;
    };
    const installedPlugins = (editor2) => {
      if (editor2 == null) {
        return "";
      }
      return '<div data-mce-tabstop="1" tabindex="-1">' + pluginLister(editor2) + "</div>";
    };
    const htmlPanel = {
      type: "htmlpanel",
      presets: "document",
      html: [
        installedPlugins(editor),
        availablePlugins()
      ].join("")
    };
    return {
      name: "plugins",
      title: "Plugins",
      items: [htmlPanel]
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.EditorManager");
  const tab = () => {
    const getVersion = (major, minor) => major.indexOf("@") === 0 ? "X.X.X" : major + "." + minor;
    const version = getVersion(global2.majorVersion, global2.minorVersion);
    const changeLogLink = '<a href="https://www.tiny.cloud/docs/tinymce/6/changelog/?utm_campaign=editor_referral&utm_medium=help_dialog&utm_source=tinymce" rel="noopener" target="_blank">TinyMCE ' + version + "</a>";
    const htmlPanel = {
      type: "htmlpanel",
      html: "<p>" + global$1.translate([
        "You are using {0}",
        changeLogLink
      ]) + "</p>",
      presets: "document"
    };
    return {
      name: "versions",
      title: "Version",
      items: [htmlPanel]
    };
  };
  const parseHelpTabsSetting = (tabsFromSettings, tabs) => {
    const newTabs = {};
    const names = map(tabsFromSettings, (t) => {
      if (typeof t === "string") {
        if (has(tabs, t)) {
          newTabs[t] = tabs[t];
        }
        return t;
      } else {
        newTabs[t.name] = t;
        return t.name;
      }
    });
    return {
      tabs: newTabs,
      names
    };
  };
  const getNamesFromTabs = (tabs) => {
    const names = keys(tabs);
    const idx = names.indexOf("versions");
    if (idx !== -1) {
      names.splice(idx, 1);
      names.push("versions");
    }
    return {
      tabs,
      names
    };
  };
  const parseCustomTabs = (editor, customTabs) => {
    const shortcuts2 = tab$2();
    const nav = tab$3();
    const plugins = tab$1(editor);
    const versions = tab();
    const tabs = {
      [shortcuts2.name]: shortcuts2,
      [nav.name]: nav,
      [plugins.name]: plugins,
      [versions.name]: versions,
      ...customTabs.get()
    };
    return Optional.from(getHelpTabs(editor)).fold(() => getNamesFromTabs(tabs), (tabsFromSettings) => parseHelpTabsSetting(tabsFromSettings, tabs));
  };
  const init = (editor, customTabs) => () => {
    const { tabs, names } = parseCustomTabs(editor, customTabs);
    const foundTabs = map(names, (name) => get(tabs, name));
    const dialogTabs = cat(foundTabs);
    const body = {
      type: "tabpanel",
      tabs: dialogTabs
    };
    editor.windowManager.open({
      title: "Help",
      size: "medium",
      body,
      buttons: [{
        type: "cancel",
        name: "close",
        text: "Close",
        primary: true
      }],
      initialData: {}
    });
  };
  var Plugin = () => {
    global$3.add("help", (editor) => {
      const customTabs = Cell({});
      const api = get$1(customTabs);
      register$1(editor);
      const dialogOpener = init(editor, customTabs);
      register(editor, dialogOpener);
      register$2(editor, dialogOpener);
      editor.shortcuts.add("Alt+0", "Open help dialog", "mceHelp");
      return api;
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const fireInsertCustomChar = (editor, chr) => {
    return editor.dispatch("insertCustomChar", { chr });
  };
  const insertChar = (editor, chr) => {
    const evtChr = fireInsertCustomChar(editor, chr).chr;
    editor.execCommand("mceInsertContent", false, evtChr);
  };
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const isSimpleType = (type) => (value) => typeof value === type;
  const eq = (t) => (a) => t === a;
  const isArray$1 = isType("array");
  const isNull = eq(null);
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const constant = (value) => {
    return () => {
      return value;
    };
  };
  const never = constant(false);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativePush = Array.prototype.push;
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray$1(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten(map(xs, f));
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    const charMapProcessor = (value) => isFunction(value) || isArray$1(value);
    registerOption("charmap", { processor: charMapProcessor });
    registerOption("charmap_append", { processor: charMapProcessor });
  };
  const getCharMap$1 = option("charmap");
  const getCharMapAppend = option("charmap_append");
  const isArray = global2.isArray;
  const UserDefined = "User Defined";
  const getDefaultCharMap = () => {
    return [
      {
        name: "Currency",
        characters: [
          [
            36,
            "dollar sign"
          ],
          [
            162,
            "cent sign"
          ],
          [
            8364,
            "euro sign"
          ],
          [
            163,
            "pound sign"
          ],
          [
            165,
            "yen sign"
          ],
          [
            164,
            "currency sign"
          ],
          [
            8352,
            "euro-currency sign"
          ],
          [
            8353,
            "colon sign"
          ],
          [
            8354,
            "cruzeiro sign"
          ],
          [
            8355,
            "french franc sign"
          ],
          [
            8356,
            "lira sign"
          ],
          [
            8357,
            "mill sign"
          ],
          [
            8358,
            "naira sign"
          ],
          [
            8359,
            "peseta sign"
          ],
          [
            8360,
            "rupee sign"
          ],
          [
            8361,
            "won sign"
          ],
          [
            8362,
            "new sheqel sign"
          ],
          [
            8363,
            "dong sign"
          ],
          [
            8365,
            "kip sign"
          ],
          [
            8366,
            "tugrik sign"
          ],
          [
            8367,
            "drachma sign"
          ],
          [
            8368,
            "german penny symbol"
          ],
          [
            8369,
            "peso sign"
          ],
          [
            8370,
            "guarani sign"
          ],
          [
            8371,
            "austral sign"
          ],
          [
            8372,
            "hryvnia sign"
          ],
          [
            8373,
            "cedi sign"
          ],
          [
            8374,
            "livre tournois sign"
          ],
          [
            8375,
            "spesmilo sign"
          ],
          [
            8376,
            "tenge sign"
          ],
          [
            8377,
            "indian rupee sign"
          ],
          [
            8378,
            "turkish lira sign"
          ],
          [
            8379,
            "nordic mark sign"
          ],
          [
            8380,
            "manat sign"
          ],
          [
            8381,
            "ruble sign"
          ],
          [
            20870,
            "yen character"
          ],
          [
            20803,
            "yuan character"
          ],
          [
            22291,
            "yuan character, in hong kong and taiwan"
          ],
          [
            22278,
            "yen/yuan character variant one"
          ]
        ]
      },
      {
        name: "Text",
        characters: [
          [
            169,
            "copyright sign"
          ],
          [
            174,
            "registered sign"
          ],
          [
            8482,
            "trade mark sign"
          ],
          [
            8240,
            "per mille sign"
          ],
          [
            181,
            "micro sign"
          ],
          [
            183,
            "middle dot"
          ],
          [
            8226,
            "bullet"
          ],
          [
            8230,
            "three dot leader"
          ],
          [
            8242,
            "minutes / feet"
          ],
          [
            8243,
            "seconds / inches"
          ],
          [
            167,
            "section sign"
          ],
          [
            182,
            "paragraph sign"
          ],
          [
            223,
            "sharp s / ess-zed"
          ]
        ]
      },
      {
        name: "Quotations",
        characters: [
          [
            8249,
            "single left-pointing angle quotation mark"
          ],
          [
            8250,
            "single right-pointing angle quotation mark"
          ],
          [
            171,
            "left pointing guillemet"
          ],
          [
            187,
            "right pointing guillemet"
          ],
          [
            8216,
            "left single quotation mark"
          ],
          [
            8217,
            "right single quotation mark"
          ],
          [
            8220,
            "left double quotation mark"
          ],
          [
            8221,
            "right double quotation mark"
          ],
          [
            8218,
            "single low-9 quotation mark"
          ],
          [
            8222,
            "double low-9 quotation mark"
          ],
          [
            60,
            "less-than sign"
          ],
          [
            62,
            "greater-than sign"
          ],
          [
            8804,
            "less-than or equal to"
          ],
          [
            8805,
            "greater-than or equal to"
          ],
          [
            8211,
            "en dash"
          ],
          [
            8212,
            "em dash"
          ],
          [
            175,
            "macron"
          ],
          [
            8254,
            "overline"
          ],
          [
            164,
            "currency sign"
          ],
          [
            166,
            "broken bar"
          ],
          [
            168,
            "diaeresis"
          ],
          [
            161,
            "inverted exclamation mark"
          ],
          [
            191,
            "turned question mark"
          ],
          [
            710,
            "circumflex accent"
          ],
          [
            732,
            "small tilde"
          ],
          [
            176,
            "degree sign"
          ],
          [
            8722,
            "minus sign"
          ],
          [
            177,
            "plus-minus sign"
          ],
          [
            247,
            "division sign"
          ],
          [
            8260,
            "fraction slash"
          ],
          [
            215,
            "multiplication sign"
          ],
          [
            185,
            "superscript one"
          ],
          [
            178,
            "superscript two"
          ],
          [
            179,
            "superscript three"
          ],
          [
            188,
            "fraction one quarter"
          ],
          [
            189,
            "fraction one half"
          ],
          [
            190,
            "fraction three quarters"
          ]
        ]
      },
      {
        name: "Mathematical",
        characters: [
          [
            402,
            "function / florin"
          ],
          [
            8747,
            "integral"
          ],
          [
            8721,
            "n-ary sumation"
          ],
          [
            8734,
            "infinity"
          ],
          [
            8730,
            "square root"
          ],
          [
            8764,
            "similar to"
          ],
          [
            8773,
            "approximately equal to"
          ],
          [
            8776,
            "almost equal to"
          ],
          [
            8800,
            "not equal to"
          ],
          [
            8801,
            "identical to"
          ],
          [
            8712,
            "element of"
          ],
          [
            8713,
            "not an element of"
          ],
          [
            8715,
            "contains as member"
          ],
          [
            8719,
            "n-ary product"
          ],
          [
            8743,
            "logical and"
          ],
          [
            8744,
            "logical or"
          ],
          [
            172,
            "not sign"
          ],
          [
            8745,
            "intersection"
          ],
          [
            8746,
            "union"
          ],
          [
            8706,
            "partial differential"
          ],
          [
            8704,
            "for all"
          ],
          [
            8707,
            "there exists"
          ],
          [
            8709,
            "diameter"
          ],
          [
            8711,
            "backward difference"
          ],
          [
            8727,
            "asterisk operator"
          ],
          [
            8733,
            "proportional to"
          ],
          [
            8736,
            "angle"
          ]
        ]
      },
      {
        name: "Extended Latin",
        characters: [
          [
            192,
            "A - grave"
          ],
          [
            193,
            "A - acute"
          ],
          [
            194,
            "A - circumflex"
          ],
          [
            195,
            "A - tilde"
          ],
          [
            196,
            "A - diaeresis"
          ],
          [
            197,
            "A - ring above"
          ],
          [
            256,
            "A - macron"
          ],
          [
            198,
            "ligature AE"
          ],
          [
            199,
            "C - cedilla"
          ],
          [
            200,
            "E - grave"
          ],
          [
            201,
            "E - acute"
          ],
          [
            202,
            "E - circumflex"
          ],
          [
            203,
            "E - diaeresis"
          ],
          [
            274,
            "E - macron"
          ],
          [
            204,
            "I - grave"
          ],
          [
            205,
            "I - acute"
          ],
          [
            206,
            "I - circumflex"
          ],
          [
            207,
            "I - diaeresis"
          ],
          [
            298,
            "I - macron"
          ],
          [
            208,
            "ETH"
          ],
          [
            209,
            "N - tilde"
          ],
          [
            210,
            "O - grave"
          ],
          [
            211,
            "O - acute"
          ],
          [
            212,
            "O - circumflex"
          ],
          [
            213,
            "O - tilde"
          ],
          [
            214,
            "O - diaeresis"
          ],
          [
            216,
            "O - slash"
          ],
          [
            332,
            "O - macron"
          ],
          [
            338,
            "ligature OE"
          ],
          [
            352,
            "S - caron"
          ],
          [
            217,
            "U - grave"
          ],
          [
            218,
            "U - acute"
          ],
          [
            219,
            "U - circumflex"
          ],
          [
            220,
            "U - diaeresis"
          ],
          [
            362,
            "U - macron"
          ],
          [
            221,
            "Y - acute"
          ],
          [
            376,
            "Y - diaeresis"
          ],
          [
            562,
            "Y - macron"
          ],
          [
            222,
            "THORN"
          ],
          [
            224,
            "a - grave"
          ],
          [
            225,
            "a - acute"
          ],
          [
            226,
            "a - circumflex"
          ],
          [
            227,
            "a - tilde"
          ],
          [
            228,
            "a - diaeresis"
          ],
          [
            229,
            "a - ring above"
          ],
          [
            257,
            "a - macron"
          ],
          [
            230,
            "ligature ae"
          ],
          [
            231,
            "c - cedilla"
          ],
          [
            232,
            "e - grave"
          ],
          [
            233,
            "e - acute"
          ],
          [
            234,
            "e - circumflex"
          ],
          [
            235,
            "e - diaeresis"
          ],
          [
            275,
            "e - macron"
          ],
          [
            236,
            "i - grave"
          ],
          [
            237,
            "i - acute"
          ],
          [
            238,
            "i - circumflex"
          ],
          [
            239,
            "i - diaeresis"
          ],
          [
            299,
            "i - macron"
          ],
          [
            240,
            "eth"
          ],
          [
            241,
            "n - tilde"
          ],
          [
            242,
            "o - grave"
          ],
          [
            243,
            "o - acute"
          ],
          [
            244,
            "o - circumflex"
          ],
          [
            245,
            "o - tilde"
          ],
          [
            246,
            "o - diaeresis"
          ],
          [
            248,
            "o slash"
          ],
          [
            333,
            "o macron"
          ],
          [
            339,
            "ligature oe"
          ],
          [
            353,
            "s - caron"
          ],
          [
            249,
            "u - grave"
          ],
          [
            250,
            "u - acute"
          ],
          [
            251,
            "u - circumflex"
          ],
          [
            252,
            "u - diaeresis"
          ],
          [
            363,
            "u - macron"
          ],
          [
            253,
            "y - acute"
          ],
          [
            254,
            "thorn"
          ],
          [
            255,
            "y - diaeresis"
          ],
          [
            563,
            "y - macron"
          ],
          [
            913,
            "Alpha"
          ],
          [
            914,
            "Beta"
          ],
          [
            915,
            "Gamma"
          ],
          [
            916,
            "Delta"
          ],
          [
            917,
            "Epsilon"
          ],
          [
            918,
            "Zeta"
          ],
          [
            919,
            "Eta"
          ],
          [
            920,
            "Theta"
          ],
          [
            921,
            "Iota"
          ],
          [
            922,
            "Kappa"
          ],
          [
            923,
            "Lambda"
          ],
          [
            924,
            "Mu"
          ],
          [
            925,
            "Nu"
          ],
          [
            926,
            "Xi"
          ],
          [
            927,
            "Omicron"
          ],
          [
            928,
            "Pi"
          ],
          [
            929,
            "Rho"
          ],
          [
            931,
            "Sigma"
          ],
          [
            932,
            "Tau"
          ],
          [
            933,
            "Upsilon"
          ],
          [
            934,
            "Phi"
          ],
          [
            935,
            "Chi"
          ],
          [
            936,
            "Psi"
          ],
          [
            937,
            "Omega"
          ],
          [
            945,
            "alpha"
          ],
          [
            946,
            "beta"
          ],
          [
            947,
            "gamma"
          ],
          [
            948,
            "delta"
          ],
          [
            949,
            "epsilon"
          ],
          [
            950,
            "zeta"
          ],
          [
            951,
            "eta"
          ],
          [
            952,
            "theta"
          ],
          [
            953,
            "iota"
          ],
          [
            954,
            "kappa"
          ],
          [
            955,
            "lambda"
          ],
          [
            956,
            "mu"
          ],
          [
            957,
            "nu"
          ],
          [
            958,
            "xi"
          ],
          [
            959,
            "omicron"
          ],
          [
            960,
            "pi"
          ],
          [
            961,
            "rho"
          ],
          [
            962,
            "final sigma"
          ],
          [
            963,
            "sigma"
          ],
          [
            964,
            "tau"
          ],
          [
            965,
            "upsilon"
          ],
          [
            966,
            "phi"
          ],
          [
            967,
            "chi"
          ],
          [
            968,
            "psi"
          ],
          [
            969,
            "omega"
          ]
        ]
      },
      {
        name: "Symbols",
        characters: [
          [
            8501,
            "alef symbol"
          ],
          [
            982,
            "pi symbol"
          ],
          [
            8476,
            "real part symbol"
          ],
          [
            978,
            "upsilon - hook symbol"
          ],
          [
            8472,
            "Weierstrass p"
          ],
          [
            8465,
            "imaginary part"
          ]
        ]
      },
      {
        name: "Arrows",
        characters: [
          [
            8592,
            "leftwards arrow"
          ],
          [
            8593,
            "upwards arrow"
          ],
          [
            8594,
            "rightwards arrow"
          ],
          [
            8595,
            "downwards arrow"
          ],
          [
            8596,
            "left right arrow"
          ],
          [
            8629,
            "carriage return"
          ],
          [
            8656,
            "leftwards double arrow"
          ],
          [
            8657,
            "upwards double arrow"
          ],
          [
            8658,
            "rightwards double arrow"
          ],
          [
            8659,
            "downwards double arrow"
          ],
          [
            8660,
            "left right double arrow"
          ],
          [
            8756,
            "therefore"
          ],
          [
            8834,
            "subset of"
          ],
          [
            8835,
            "superset of"
          ],
          [
            8836,
            "not a subset of"
          ],
          [
            8838,
            "subset of or equal to"
          ],
          [
            8839,
            "superset of or equal to"
          ],
          [
            8853,
            "circled plus"
          ],
          [
            8855,
            "circled times"
          ],
          [
            8869,
            "perpendicular"
          ],
          [
            8901,
            "dot operator"
          ],
          [
            8968,
            "left ceiling"
          ],
          [
            8969,
            "right ceiling"
          ],
          [
            8970,
            "left floor"
          ],
          [
            8971,
            "right floor"
          ],
          [
            9001,
            "left-pointing angle bracket"
          ],
          [
            9002,
            "right-pointing angle bracket"
          ],
          [
            9674,
            "lozenge"
          ],
          [
            9824,
            "black spade suit"
          ],
          [
            9827,
            "black club suit"
          ],
          [
            9829,
            "black heart suit"
          ],
          [
            9830,
            "black diamond suit"
          ],
          [
            8194,
            "en space"
          ],
          [
            8195,
            "em space"
          ],
          [
            8201,
            "thin space"
          ],
          [
            8204,
            "zero width non-joiner"
          ],
          [
            8205,
            "zero width joiner"
          ],
          [
            8206,
            "left-to-right mark"
          ],
          [
            8207,
            "right-to-left mark"
          ]
        ]
      }
    ];
  };
  const charmapFilter = (charmap) => {
    return global2.grep(charmap, (item) => {
      return isArray(item) && item.length === 2;
    });
  };
  const getCharsFromOption = (optionValue) => {
    if (isArray(optionValue)) {
      return charmapFilter(optionValue);
    }
    if (typeof optionValue === "function") {
      return optionValue();
    }
    return [];
  };
  const extendCharMap = (editor, charmap) => {
    const userCharMap = getCharMap$1(editor);
    if (userCharMap) {
      charmap = [{
        name: UserDefined,
        characters: getCharsFromOption(userCharMap)
      }];
    }
    const userCharMapAppend = getCharMapAppend(editor);
    if (userCharMapAppend) {
      const userDefinedGroup = global2.grep(charmap, (cg) => cg.name === UserDefined);
      if (userDefinedGroup.length) {
        userDefinedGroup[0].characters = [].concat(userDefinedGroup[0].characters).concat(getCharsFromOption(userCharMapAppend));
        return charmap;
      }
      return charmap.concat({
        name: UserDefined,
        characters: getCharsFromOption(userCharMapAppend)
      });
    }
    return charmap;
  };
  const getCharMap = (editor) => {
    const groups = extendCharMap(editor, getDefaultCharMap());
    return groups.length > 1 ? [{
      name: "All",
      characters: bind(groups, (g) => g.characters)
    }].concat(groups) : groups;
  };
  const get = (editor) => {
    const getCharMap$12 = () => {
      return getCharMap(editor);
    };
    const insertChar$1 = (chr) => {
      insertChar(editor, chr);
    };
    return {
      getCharMap: getCharMap$12,
      insertChar: insertChar$1
    };
  };
  const Cell = (initial) => {
    let value = initial;
    const get2 = () => {
      return value;
    };
    const set = (v) => {
      value = v;
    };
    return {
      get: get2,
      set
    };
  };
  const last = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      cancel();
      timer = setTimeout(() => {
        timer = null;
        fn.apply(null, args);
      }, rate);
    };
    return {
      cancel,
      throttle
    };
  };
  const contains = (str, substr) => {
    return str.indexOf(substr) !== -1;
  };
  const fromCodePoint = String.fromCodePoint;
  const charMatches = (charCode, name, lowerCasePattern) => {
    if (contains(fromCodePoint(charCode).toLowerCase(), lowerCasePattern)) {
      return true;
    } else {
      return contains(name.toLowerCase(), lowerCasePattern) || contains(name.toLowerCase().replace(/\s+/g, ""), lowerCasePattern);
    }
  };
  const scan = (group, pattern) => {
    const matches = [];
    const lowerCasePattern = pattern.toLowerCase();
    each(group.characters, (g) => {
      if (charMatches(g[0], g[1], lowerCasePattern)) {
        matches.push(g);
      }
    });
    return map(matches, (m) => ({
      text: m[1],
      value: fromCodePoint(m[0]),
      icon: fromCodePoint(m[0])
    }));
  };
  const patternName = "pattern";
  const open = (editor, charMap) => {
    const makeGroupItems = () => [
      {
        label: "Search",
        type: "input",
        name: patternName
      },
      {
        type: "collection",
        name: "results"
      }
    ];
    const makeTabs = () => map(charMap, (charGroup) => ({
      title: charGroup.name,
      name: charGroup.name,
      items: makeGroupItems()
    }));
    const makePanel = () => ({
      type: "panel",
      items: makeGroupItems()
    });
    const makeTabPanel = () => ({
      type: "tabpanel",
      tabs: makeTabs()
    });
    const currentTab = charMap.length === 1 ? Cell(UserDefined) : Cell("All");
    const scanAndSet = (dialogApi2, pattern) => {
      find(charMap, (group) => group.name === currentTab.get()).each((f) => {
        const items = scan(f, pattern);
        dialogApi2.setData({ results: items });
      });
    };
    const SEARCH_DELAY = 40;
    const updateFilter = last((dialogApi2) => {
      const pattern = dialogApi2.getData().pattern;
      scanAndSet(dialogApi2, pattern);
    }, SEARCH_DELAY);
    const body = charMap.length === 1 ? makePanel() : makeTabPanel();
    const initialData = {
      pattern: "",
      results: scan(charMap[0], "")
    };
    const bridgeSpec = {
      title: "Special Character",
      size: "normal",
      body,
      buttons: [{
        type: "cancel",
        name: "close",
        text: "Close",
        primary: true
      }],
      initialData,
      onAction: (api, details) => {
        if (details.name === "results") {
          insertChar(editor, details.value);
          api.close();
        }
      },
      onTabChange: (dialogApi2, details) => {
        currentTab.set(details.newTabName);
        updateFilter.throttle(dialogApi2);
      },
      onChange: (dialogApi2, changeData) => {
        if (changeData.name === patternName) {
          updateFilter.throttle(dialogApi2);
        }
      }
    };
    const dialogApi = editor.windowManager.open(bridgeSpec);
    dialogApi.focus(patternName);
  };
  const register$1 = (editor, charMap) => {
    editor.addCommand("mceShowCharmap", () => {
      open(editor, charMap);
    });
  };
  const init = (editor, all) => {
    editor.ui.registry.addAutocompleter("charmap", {
      ch: ":",
      columns: "auto",
      minChars: 2,
      fetch: (pattern, _maxResults) => new Promise((resolve, _reject) => {
        resolve(scan(all, pattern));
      }),
      onAction: (autocompleteApi, rng, value) => {
        editor.selection.setRng(rng);
        editor.insertContent(value);
        autocompleteApi.hide();
      }
    });
  };
  const register = (editor) => {
    editor.ui.registry.addButton("charmap", {
      icon: "insert-character",
      tooltip: "Special character",
      onAction: () => editor.execCommand("mceShowCharmap")
    });
    editor.ui.registry.addMenuItem("charmap", {
      icon: "insert-character",
      text: "Special character...",
      onAction: () => editor.execCommand("mceShowCharmap")
    });
  };
  var Plugin = () => {
    global$1.add("charmap", (editor) => {
      register$2(editor);
      const charMap = getCharMap(editor);
      register$1(editor, charMap);
      register(editor);
      init(editor, charMap[0]);
      return get(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  var global$1 = tinymce.util.Tools.resolve("tinymce.Env");
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const option = (name) => (editor) => editor.options.get(name);
  const getContentStyle = option("content_style");
  const shouldUseContentCssCors = option("content_css_cors");
  const getBodyClass = option("body_class");
  const getBodyId = option("body_id");
  const getPreviewHtml = (editor) => {
    var _a;
    let headHtml = "";
    const encode = editor.dom.encode;
    const contentStyle = (_a = getContentStyle(editor)) !== null && _a !== void 0 ? _a : "";
    headHtml += '<base href="' + encode(editor.documentBaseURI.getURI()) + '">';
    const cors = shouldUseContentCssCors(editor) ? ' crossorigin="anonymous"' : "";
    global2.each(editor.contentCSS, (url) => {
      headHtml += '<link type="text/css" rel="stylesheet" href="' + encode(editor.documentBaseURI.toAbsolute(url)) + '"' + cors + ">";
    });
    if (contentStyle) {
      headHtml += '<style type="text/css">' + contentStyle + "</style>";
    }
    const bodyId = getBodyId(editor);
    const bodyClass = getBodyClass(editor);
    const isMetaKeyPressed = global$1.os.isMacOS() || global$1.os.isiOS() ? "e.metaKey" : "e.ctrlKey && !e.altKey";
    const preventClicksOnLinksScript = '<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !(' + isMetaKeyPressed + ")) {e.preventDefault();}}}, false);<\/script> ";
    const directionality = editor.getBody().dir;
    const dirAttr = directionality ? ' dir="' + encode(directionality) + '"' : "";
    const previewHtml = "<!DOCTYPE html><html><head>" + headHtml + '</head><body id="' + encode(bodyId) + '" class="mce-content-body ' + encode(bodyClass) + '"' + dirAttr + ">" + editor.getContent() + preventClicksOnLinksScript + "</body></html>";
    return previewHtml;
  };
  const open = (editor) => {
    const content = getPreviewHtml(editor);
    const dataApi = editor.windowManager.open({
      title: "Preview",
      size: "large",
      body: {
        type: "panel",
        items: [{
          name: "preview",
          type: "iframe",
          sandboxed: true,
          transparent: false
        }]
      },
      buttons: [{
        type: "cancel",
        name: "close",
        text: "Close",
        primary: true
      }],
      initialData: { preview: content }
    });
    dataApi.focus("close");
  };
  const register$1 = (editor) => {
    editor.addCommand("mcePreview", () => {
      open(editor);
    });
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mcePreview");
    editor.ui.registry.addButton("preview", {
      icon: "preview",
      tooltip: "Preview",
      onAction
    });
    editor.ui.registry.addMenuItem("preview", {
      icon: "preview",
      text: "Preview",
      onAction
    });
  };
  var Plugin = () => {
    global$2.add("preview", (editor) => {
      register$1(editor);
      register(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  var global$1 = tinymce.util.Tools.resolve("tinymce.dom.RangeUtils");
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("allow_html_in_named_anchor", {
      processor: "boolean",
      default: false
    });
  };
  const allowHtmlInNamedAnchor = option("allow_html_in_named_anchor");
  const namedAnchorSelector = "a:not([href])";
  const isEmptyString = (str) => !str;
  const getIdFromAnchor = (elm) => {
    const id = elm.getAttribute("id") || elm.getAttribute("name");
    return id || "";
  };
  const isAnchor = (elm) => elm && elm.nodeName.toLowerCase() === "a";
  const isNamedAnchor = (elm) => isAnchor(elm) && !elm.getAttribute("href") && getIdFromAnchor(elm) !== "";
  const isEmptyNamedAnchor = (elm) => isNamedAnchor(elm) && !elm.firstChild;
  const removeEmptyNamedAnchorsInSelection = (editor) => {
    const dom = editor.dom;
    global$1(dom).walk(editor.selection.getRng(), (nodes) => {
      global2.each(nodes, (node) => {
        if (isEmptyNamedAnchor(node)) {
          dom.remove(node, false);
        }
      });
    });
  };
  const isValidId = (id) => /^[A-Za-z][A-Za-z0-9\-:._]*$/.test(id);
  const getNamedAnchor = (editor) => editor.dom.getParent(editor.selection.getStart(), namedAnchorSelector);
  const getId = (editor) => {
    const anchor = getNamedAnchor(editor);
    if (anchor) {
      return getIdFromAnchor(anchor);
    } else {
      return "";
    }
  };
  const createAnchor = (editor, id) => {
    editor.undoManager.transact(() => {
      if (!allowHtmlInNamedAnchor(editor)) {
        editor.selection.collapse(true);
      }
      if (editor.selection.isCollapsed()) {
        editor.insertContent(editor.dom.createHTML("a", { id }));
      } else {
        removeEmptyNamedAnchorsInSelection(editor);
        editor.formatter.remove("namedAnchor", null, null, true);
        editor.formatter.apply("namedAnchor", { value: id });
        editor.addVisual();
      }
    });
  };
  const updateAnchor = (editor, id, anchorElement) => {
    anchorElement.removeAttribute("name");
    anchorElement.id = id;
    editor.addVisual();
    editor.undoManager.add();
  };
  const insert = (editor, id) => {
    const anchor = getNamedAnchor(editor);
    if (anchor) {
      updateAnchor(editor, id, anchor);
    } else {
      createAnchor(editor, id);
    }
    editor.focus();
  };
  const insertAnchor = (editor, newId) => {
    if (!isValidId(newId)) {
      editor.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.");
      return false;
    } else {
      insert(editor, newId);
      return true;
    }
  };
  const open = (editor) => {
    const currentId = getId(editor);
    editor.windowManager.open({
      title: "Anchor",
      size: "normal",
      body: {
        type: "panel",
        items: [{
          name: "id",
          type: "input",
          label: "ID",
          placeholder: "example"
        }]
      },
      buttons: [
        {
          type: "cancel",
          name: "cancel",
          text: "Cancel"
        },
        {
          type: "submit",
          name: "save",
          text: "Save",
          primary: true
        }
      ],
      initialData: { id: currentId },
      onSubmit: (api) => {
        if (insertAnchor(editor, api.getData().id)) {
          api.close();
        }
      }
    });
  };
  const register$1 = (editor) => {
    editor.addCommand("mceAnchor", () => {
      open(editor);
    });
  };
  const isNamedAnchorNode = (node) => node && isEmptyString(node.attr("href")) && !isEmptyString(node.attr("id") || node.attr("name"));
  const isEmptyNamedAnchorNode = (node) => isNamedAnchorNode(node) && !node.firstChild;
  const setContentEditable = (state) => (nodes) => {
    for (let i = 0; i < nodes.length; i++) {
      const node = nodes[i];
      if (isEmptyNamedAnchorNode(node)) {
        node.attr("contenteditable", state);
      }
    }
  };
  const setup = (editor) => {
    editor.on("PreInit", () => {
      editor.parser.addNodeFilter("a", setContentEditable("false"));
      editor.serializer.addNodeFilter("a", setContentEditable(null));
    });
  };
  const registerFormats = (editor) => {
    editor.formatter.register("namedAnchor", {
      inline: "a",
      selector: namedAnchorSelector,
      remove: "all",
      split: true,
      deep: true,
      attributes: { id: "%value" },
      onmatch: (node, _fmt, _itemName) => {
        return isNamedAnchor(node);
      }
    });
  };
  const register = (editor) => {
    editor.ui.registry.addToggleButton("anchor", {
      icon: "bookmark",
      tooltip: "Anchor",
      onAction: () => editor.execCommand("mceAnchor"),
      onSetup: (buttonApi) => editor.selection.selectorChangedWithUnbind("a:not([href])", buttonApi.setActive).unbind
    });
    editor.ui.registry.addMenuItem("anchor", {
      icon: "bookmark",
      text: "Anchor...",
      onAction: () => editor.execCommand("mceAnchor")
    });
  };
  var Plugin = () => {
    global$2.add("anchor", (editor) => {
      register$2(editor);
      setup(editor);
      register$1(editor);
      register(editor);
      editor.on("PreInit", () => {
        registerFormats(editor);
      });
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  var global2 = tinymce.util.Tools.resolve("tinymce.Env");
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("pagebreak_separator", {
      processor: "string",
      default: "<!-- pagebreak -->"
    });
    registerOption("pagebreak_split_block", {
      processor: "boolean",
      default: false
    });
  };
  const getSeparatorHtml = option("pagebreak_separator");
  const shouldSplitBlock = option("pagebreak_split_block");
  const pageBreakClass = "mce-pagebreak";
  const getPlaceholderHtml = (shouldSplitBlock2) => {
    const html = `<img src="${global2.transparentSrc}" class="${pageBreakClass}" data-mce-resize="false" data-mce-placeholder />`;
    return shouldSplitBlock2 ? `<p>${html}</p>` : html;
  };
  const setup$1 = (editor) => {
    const separatorHtml = getSeparatorHtml(editor);
    const shouldSplitBlock$1 = () => shouldSplitBlock(editor);
    const pageBreakSeparatorRegExp = new RegExp(separatorHtml.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g, (a) => {
      return "\\" + a;
    }), "gi");
    editor.on("BeforeSetContent", (e) => {
      e.content = e.content.replace(pageBreakSeparatorRegExp, getPlaceholderHtml(shouldSplitBlock$1()));
    });
    editor.on("PreInit", () => {
      editor.serializer.addNodeFilter("img", (nodes) => {
        let i = nodes.length, node, className;
        while (i--) {
          node = nodes[i];
          className = node.attr("class");
          if (className && className.indexOf(pageBreakClass) !== -1) {
            const parentNode = node.parent;
            if (editor.schema.getBlockElements()[parentNode.name] && shouldSplitBlock$1()) {
              parentNode.type = 3;
              parentNode.value = separatorHtml;
              parentNode.raw = true;
              node.remove();
              continue;
            }
            node.type = 3;
            node.value = separatorHtml;
            node.raw = true;
          }
        }
      });
    });
  };
  const register$1 = (editor) => {
    editor.addCommand("mcePageBreak", () => {
      editor.insertContent(getPlaceholderHtml(shouldSplitBlock(editor)));
    });
  };
  const setup = (editor) => {
    editor.on("ResolveName", (e) => {
      if (e.target.nodeName === "IMG" && editor.dom.hasClass(e.target, pageBreakClass)) {
        e.name = "pagebreak";
      }
    });
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mcePageBreak");
    editor.ui.registry.addButton("pagebreak", {
      icon: "page-break",
      tooltip: "Page break",
      onAction
    });
    editor.ui.registry.addMenuItem("pagebreak", {
      text: "Page break",
      icon: "page-break",
      onAction
    });
  };
  var Plugin = () => {
    global$1.add("pagebreak", (editor) => {
      register$2(editor);
      register$1(editor);
      register(editor);
      setup$1(editor);
      setup(editor);
    });
  };
  Plugin();
})();
(function() {
  const Cell = (initial) => {
    let value2 = initial;
    const get2 = () => {
      return value2;
    };
    const set2 = (v) => {
      value2 = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  var global$3 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
  const isSimpleType = (type2) => (value2) => typeof value2 === type2;
  const isString = isType$1("string");
  const isArray = isType$1("array");
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isNumber = isSimpleType("number");
  const noop = () => {
  };
  const constant = (value2) => {
    return () => {
      return value2;
    };
  };
  const always = constant(true);
  const punctuationStr = "[!-#%-*,-\\/:;?@\\[-\\]_{}\xA1\xAB\xB7\xBB\xBF;\xB7\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1361-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u3008\u3009\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30\u2E31\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]";
  const punctuation$1 = constant(punctuationStr);
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const punctuation = punctuation$1;
  var global$2 = tinymce.util.Tools.resolve("tinymce.Env");
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const nativeSlice = Array.prototype.slice;
  const nativePush = Array.prototype.push;
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const eachr = (xs, f) => {
    for (let i = xs.length - 1; i >= 0; i--) {
      const x = xs[i];
      f(x, i);
    }
  };
  const groupBy = (xs, f) => {
    if (xs.length === 0) {
      return [];
    } else {
      let wasType = f(xs[0]);
      const r = [];
      let group = [];
      for (let i = 0, len = xs.length; i < len; i++) {
        const x = xs[i];
        const type2 = f(x);
        if (type2 !== wasType) {
          r.push(group);
          group = [];
        }
        wasType = type2;
        group.push(x);
      }
      if (group.length !== 0) {
        r.push(group);
      }
      return r;
    }
  };
  const foldl = (xs, f, acc) => {
    each(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const flatten = (xs) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r, xs[i]);
    }
    return r;
  };
  const bind = (xs, f) => flatten(map(xs, f));
  const sort = (xs, comparator) => {
    const copy = nativeSlice.call(xs, 0);
    copy.sort(comparator);
    return copy;
  };
  const hasOwnProperty = Object.hasOwnProperty;
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  typeof window !== "undefined" ? window : Function("return this;")();
  const DOCUMENT = 9;
  const DOCUMENT_FRAGMENT = 11;
  const ELEMENT = 1;
  const TEXT = 3;
  const type = (element) => element.dom.nodeType;
  const isType = (t) => (element) => type(element) === t;
  const isText$1 = isType(TEXT);
  const rawSet = (dom, key, value2) => {
    if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
      dom.setAttribute(key, value2 + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value2, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value2) => {
    rawSet(element.dom, key, value2);
  };
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  const bypassSelector = (dom) => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  const all = (selector, scope) => {
    const base = scope === void 0 ? document : scope.dom;
    return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  };
  const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  const children = (element) => map(element.dom.childNodes, SugarElement.fromDom);
  const spot = (element, offset) => ({
    element,
    offset
  });
  const leaf = (element, offset) => {
    const cs = children(element);
    return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
  };
  const before = (marker, element) => {
    const parent$1 = parent(marker);
    parent$1.each((v) => {
      v.dom.insertBefore(element.dom, marker.dom);
    });
  };
  const append = (parent2, element) => {
    parent2.dom.appendChild(element.dom);
  };
  const wrap = (element, wrapper) => {
    before(element, wrapper);
    append(wrapper, element);
  };
  const NodeValue = (is, name) => {
    const get2 = (element) => {
      if (!is(element)) {
        throw new Error("Can only get " + name + " value of a " + name + " node");
      }
      return getOption(element).getOr("");
    };
    const getOption = (element) => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
    const set2 = (element, value2) => {
      if (!is(element)) {
        throw new Error("Can only set raw " + name + " value of a " + name + " node");
      }
      element.dom.nodeValue = value2;
    };
    return {
      get: get2,
      getOption,
      set: set2
    };
  };
  const api = NodeValue(isText$1, "text");
  const get$1 = (element) => api.get(element);
  const compareDocumentPosition = (a, b, match) => {
    return (a.compareDocumentPosition(b) & match) !== 0;
  };
  const documentPositionPreceding = (a, b) => {
    return compareDocumentPosition(a, b, Node.DOCUMENT_POSITION_PRECEDING);
  };
  const descendants = (scope, selector) => all(selector, scope);
  var global2 = tinymce.util.Tools.resolve("tinymce.dom.TreeWalker");
  const isSimpleBoundary = (dom, node) => dom.isBlock(node) || has(dom.schema.getVoidElements(), node.nodeName);
  const isContentEditableFalse = (dom, node) => dom.getContentEditable(node) === "false";
  const isContentEditableTrueInCef = (dom, node) => dom.getContentEditable(node) === "true" && dom.getContentEditableParent(node.parentNode) === "false";
  const isHidden = (dom, node) => !dom.isBlock(node) && has(dom.schema.getWhitespaceElements(), node.nodeName);
  const isBoundary = (dom, node) => isSimpleBoundary(dom, node) || isContentEditableFalse(dom, node) || isHidden(dom, node) || isContentEditableTrueInCef(dom, node);
  const isText = (node) => node.nodeType === 3;
  const nuSection = () => ({
    sOffset: 0,
    fOffset: 0,
    elements: []
  });
  const toLeaf = (node, offset) => leaf(SugarElement.fromDom(node), offset);
  const walk = (dom, walkerFn, startNode, callbacks, endNode, skipStart = true) => {
    let next2 = skipStart ? walkerFn(false) : startNode;
    while (next2) {
      const isCefNode = isContentEditableFalse(dom, next2);
      if (isCefNode || isHidden(dom, next2)) {
        const stopWalking = isCefNode ? callbacks.cef(next2) : callbacks.boundary(next2);
        if (stopWalking) {
          break;
        } else {
          next2 = walkerFn(true);
          continue;
        }
      } else if (isSimpleBoundary(dom, next2)) {
        if (callbacks.boundary(next2)) {
          break;
        }
      } else if (isText(next2)) {
        callbacks.text(next2);
      }
      if (next2 === endNode) {
        break;
      } else {
        next2 = walkerFn(false);
      }
    }
  };
  const collectTextToBoundary = (dom, section, node, rootNode, forwards) => {
    if (isBoundary(dom, node)) {
      return;
    }
    const rootBlock = dom.getParent(rootNode, dom.isBlock);
    const walker = new global2(node, rootBlock);
    const walkerFn = forwards ? walker.next.bind(walker) : walker.prev.bind(walker);
    walk(dom, walkerFn, node, {
      boundary: always,
      cef: always,
      text: (next2) => {
        if (forwards) {
          section.fOffset += next2.length;
        } else {
          section.sOffset += next2.length;
        }
        section.elements.push(SugarElement.fromDom(next2));
      }
    });
  };
  const collect = (dom, rootNode, startNode, endNode, callbacks, skipStart = true) => {
    const walker = new global2(startNode, rootNode);
    const sections = [];
    let current = nuSection();
    collectTextToBoundary(dom, current, startNode, rootNode, false);
    const finishSection = () => {
      if (current.elements.length > 0) {
        sections.push(current);
        current = nuSection();
      }
      return false;
    };
    walk(dom, walker.next.bind(walker), startNode, {
      boundary: finishSection,
      cef: (node) => {
        finishSection();
        if (callbacks) {
          sections.push(...callbacks.cef(node));
        }
        return false;
      },
      text: (next2) => {
        current.elements.push(SugarElement.fromDom(next2));
        if (callbacks) {
          callbacks.text(next2, current);
        }
      }
    }, endNode, skipStart);
    if (endNode) {
      collectTextToBoundary(dom, current, endNode, rootNode, true);
    }
    finishSection();
    return sections;
  };
  const collectRangeSections = (dom, rng) => {
    const start = toLeaf(rng.startContainer, rng.startOffset);
    const startNode = start.element.dom;
    const end = toLeaf(rng.endContainer, rng.endOffset);
    const endNode = end.element.dom;
    return collect(dom, rng.commonAncestorContainer, startNode, endNode, {
      text: (node, section) => {
        if (node === endNode) {
          section.fOffset += node.length - end.offset;
        } else if (node === startNode) {
          section.sOffset += start.offset;
        }
      },
      cef: (node) => {
        const sections = bind(descendants(SugarElement.fromDom(node), "*[contenteditable=true]"), (e) => {
          const ceTrueNode = e.dom;
          return collect(dom, ceTrueNode, ceTrueNode);
        });
        return sort(sections, (a, b) => documentPositionPreceding(a.elements[0].dom, b.elements[0].dom) ? 1 : -1);
      }
    }, false);
  };
  const fromRng = (dom, rng) => rng.collapsed ? [] : collectRangeSections(dom, rng);
  const fromNode = (dom, node) => {
    const rng = dom.createRng();
    rng.selectNode(node);
    return fromRng(dom, rng);
  };
  const fromNodes = (dom, nodes) => bind(nodes, (node) => fromNode(dom, node));
  const find$2 = (text, pattern, start = 0, finish = text.length) => {
    const regex = pattern.regex;
    regex.lastIndex = start;
    const results = [];
    let match;
    while (match = regex.exec(text)) {
      const matchedText = match[pattern.matchIndex];
      const matchStart = match.index + match[0].indexOf(matchedText);
      const matchFinish = matchStart + matchedText.length;
      if (matchFinish > finish) {
        break;
      }
      results.push({
        start: matchStart,
        finish: matchFinish
      });
      regex.lastIndex = matchFinish;
    }
    return results;
  };
  const extract = (elements, matches) => {
    const nodePositions = foldl(elements, (acc, element) => {
      const content = get$1(element);
      const start = acc.last;
      const finish = start + content.length;
      const positions = bind(matches, (match, matchIdx) => {
        if (match.start < finish && match.finish > start) {
          return [{
            element,
            start: Math.max(start, match.start) - start,
            finish: Math.min(finish, match.finish) - start,
            matchId: matchIdx
          }];
        } else {
          return [];
        }
      });
      return {
        results: acc.results.concat(positions),
        last: finish
      };
    }, {
      results: [],
      last: 0
    }).results;
    return groupBy(nodePositions, (position) => position.matchId);
  };
  const find$1 = (pattern, sections) => bind(sections, (section) => {
    const elements = section.elements;
    const content = map(elements, get$1).join("");
    const positions = find$2(content, pattern, section.sOffset, content.length - section.fOffset);
    return extract(elements, positions);
  });
  const mark = (matches, replacementNode) => {
    eachr(matches, (match, idx) => {
      eachr(match, (pos) => {
        const wrapper = SugarElement.fromDom(replacementNode.cloneNode(false));
        set(wrapper, "data-mce-index", idx);
        const textNode = pos.element.dom;
        if (textNode.length === pos.finish && pos.start === 0) {
          wrap(pos.element, wrapper);
        } else {
          if (textNode.length !== pos.finish) {
            textNode.splitText(pos.finish);
          }
          const matchNode = textNode.splitText(pos.start);
          wrap(SugarElement.fromDom(matchNode), wrapper);
        }
      });
    });
  };
  const findAndMark = (dom, pattern, node, replacementNode) => {
    const textSections = fromNode(dom, node);
    const matches = find$1(pattern, textSections);
    mark(matches, replacementNode);
    return matches.length;
  };
  const findAndMarkInSelection = (dom, pattern, selection, replacementNode) => {
    const bookmark = selection.getBookmark();
    const nodes = dom.select("td[data-mce-selected],th[data-mce-selected]");
    const textSections = nodes.length > 0 ? fromNodes(dom, nodes) : fromRng(dom, selection.getRng());
    const matches = find$1(pattern, textSections);
    mark(matches, replacementNode);
    selection.moveToBookmark(bookmark);
    return matches.length;
  };
  const getElmIndex = (elm) => {
    const value2 = elm.getAttribute("data-mce-index");
    if (typeof value2 === "number") {
      return "" + value2;
    }
    return value2;
  };
  const markAllMatches = (editor, currentSearchState, pattern, inSelection) => {
    const marker = editor.dom.create("span", { "data-mce-bogus": 1 });
    marker.className = "mce-match-marker";
    const node = editor.getBody();
    done(editor, currentSearchState, false);
    if (inSelection) {
      return findAndMarkInSelection(editor.dom, pattern, editor.selection, marker);
    } else {
      return findAndMark(editor.dom, pattern, node, marker);
    }
  };
  const unwrap = (node) => {
    const parentNode = node.parentNode;
    if (node.firstChild) {
      parentNode.insertBefore(node.firstChild, node);
    }
    node.parentNode.removeChild(node);
  };
  const findSpansByIndex = (editor, index2) => {
    const spans = [];
    const nodes = global$1.toArray(editor.getBody().getElementsByTagName("span"));
    if (nodes.length) {
      for (let i = 0; i < nodes.length; i++) {
        const nodeIndex = getElmIndex(nodes[i]);
        if (nodeIndex === null || !nodeIndex.length) {
          continue;
        }
        if (nodeIndex === index2.toString()) {
          spans.push(nodes[i]);
        }
      }
    }
    return spans;
  };
  const moveSelection = (editor, currentSearchState, forward) => {
    const searchState = currentSearchState.get();
    let testIndex = searchState.index;
    const dom = editor.dom;
    forward = forward !== false;
    if (forward) {
      if (testIndex + 1 === searchState.count) {
        testIndex = 0;
      } else {
        testIndex++;
      }
    } else {
      if (testIndex - 1 === -1) {
        testIndex = searchState.count - 1;
      } else {
        testIndex--;
      }
    }
    dom.removeClass(findSpansByIndex(editor, searchState.index), "mce-match-marker-selected");
    const spans = findSpansByIndex(editor, testIndex);
    if (spans.length) {
      dom.addClass(findSpansByIndex(editor, testIndex), "mce-match-marker-selected");
      editor.selection.scrollIntoView(spans[0]);
      return testIndex;
    }
    return -1;
  };
  const removeNode = (dom, node) => {
    const parent2 = node.parentNode;
    dom.remove(node);
    if (dom.isEmpty(parent2)) {
      dom.remove(parent2);
    }
  };
  const escapeSearchText = (text, wholeWord) => {
    const escapedText = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&").replace(/\s/g, "[^\\S\\r\\n\\uFEFF]");
    const wordRegex = "(" + escapedText + ")";
    return wholeWord ? `(?:^|\\s|${punctuation()})` + wordRegex + `(?=$|\\s|${punctuation()})` : wordRegex;
  };
  const find = (editor, currentSearchState, text, matchCase, wholeWord, inSelection) => {
    const selection = editor.selection;
    const escapedText = escapeSearchText(text, wholeWord);
    const isForwardSelection = selection.isForward();
    const pattern = {
      regex: new RegExp(escapedText, matchCase ? "g" : "gi"),
      matchIndex: 1
    };
    const count = markAllMatches(editor, currentSearchState, pattern, inSelection);
    if (global$2.browser.isSafari()) {
      selection.setRng(selection.getRng(), isForwardSelection);
    }
    if (count) {
      const newIndex = moveSelection(editor, currentSearchState, true);
      currentSearchState.set({
        index: newIndex,
        count,
        text,
        matchCase,
        wholeWord,
        inSelection
      });
    }
    return count;
  };
  const next = (editor, currentSearchState) => {
    const index2 = moveSelection(editor, currentSearchState, true);
    currentSearchState.set({
      ...currentSearchState.get(),
      index: index2
    });
  };
  const prev = (editor, currentSearchState) => {
    const index2 = moveSelection(editor, currentSearchState, false);
    currentSearchState.set({
      ...currentSearchState.get(),
      index: index2
    });
  };
  const isMatchSpan = (node) => {
    const matchIndex = getElmIndex(node);
    return matchIndex !== null && matchIndex.length > 0;
  };
  const replace = (editor, currentSearchState, text, forward, all2) => {
    const searchState = currentSearchState.get();
    const currentIndex = searchState.index;
    let currentMatchIndex, nextIndex = currentIndex;
    forward = forward !== false;
    const node = editor.getBody();
    const nodes = global$1.grep(global$1.toArray(node.getElementsByTagName("span")), isMatchSpan);
    for (let i = 0; i < nodes.length; i++) {
      const nodeIndex = getElmIndex(nodes[i]);
      let matchIndex = currentMatchIndex = parseInt(nodeIndex, 10);
      if (all2 || matchIndex === searchState.index) {
        if (text.length) {
          nodes[i].firstChild.nodeValue = text;
          unwrap(nodes[i]);
        } else {
          removeNode(editor.dom, nodes[i]);
        }
        while (nodes[++i]) {
          matchIndex = parseInt(getElmIndex(nodes[i]), 10);
          if (matchIndex === currentMatchIndex) {
            removeNode(editor.dom, nodes[i]);
          } else {
            i--;
            break;
          }
        }
        if (forward) {
          nextIndex--;
        }
      } else if (currentMatchIndex > currentIndex) {
        nodes[i].setAttribute("data-mce-index", String(currentMatchIndex - 1));
      }
    }
    currentSearchState.set({
      ...searchState,
      count: all2 ? 0 : searchState.count - 1,
      index: nextIndex
    });
    if (forward) {
      next(editor, currentSearchState);
    } else {
      prev(editor, currentSearchState);
    }
    return !all2 && currentSearchState.get().count > 0;
  };
  const done = (editor, currentSearchState, keepEditorSelection) => {
    let startContainer, endContainer;
    const searchState = currentSearchState.get();
    const nodes = global$1.toArray(editor.getBody().getElementsByTagName("span"));
    for (let i = 0; i < nodes.length; i++) {
      const nodeIndex = getElmIndex(nodes[i]);
      if (nodeIndex !== null && nodeIndex.length) {
        if (nodeIndex === searchState.index.toString()) {
          if (!startContainer) {
            startContainer = nodes[i].firstChild;
          }
          endContainer = nodes[i].firstChild;
        }
        unwrap(nodes[i]);
      }
    }
    currentSearchState.set({
      ...searchState,
      index: -1,
      count: 0,
      text: ""
    });
    if (startContainer && endContainer) {
      const rng = editor.dom.createRng();
      rng.setStart(startContainer, 0);
      rng.setEnd(endContainer, endContainer.data.length);
      if (keepEditorSelection !== false) {
        editor.selection.setRng(rng);
      }
      return rng;
    }
  };
  const hasNext = (editor, currentSearchState) => currentSearchState.get().count > 1;
  const hasPrev = (editor, currentSearchState) => currentSearchState.get().count > 1;
  const get = (editor, currentState) => {
    const done$1 = (keepEditorSelection) => {
      return done(editor, currentState, keepEditorSelection);
    };
    const find$12 = (text, matchCase, wholeWord, inSelection = false) => {
      return find(editor, currentState, text, matchCase, wholeWord, inSelection);
    };
    const next$1 = () => {
      return next(editor, currentState);
    };
    const prev$1 = () => {
      return prev(editor, currentState);
    };
    const replace$1 = (text, forward, all2) => {
      return replace(editor, currentState, text, forward, all2);
    };
    return {
      done: done$1,
      find: find$12,
      next: next$1,
      prev: prev$1,
      replace: replace$1
    };
  };
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get2 = () => subject.get();
    const set2 = (s) => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear,
      isSet,
      get: get2,
      set: set2
    };
  };
  const value = () => {
    const subject = singleton(noop);
    const on = (f) => subject.get().each(f);
    return {
      ...subject,
      on
    };
  };
  const open = (editor, currentSearchState) => {
    const dialogApi = value();
    editor.undoManager.add();
    const selectedText = global$1.trim(editor.selection.getContent({ format: "text" }));
    const updateButtonStates = (api2) => {
      api2.setEnabled("next", hasNext(editor, currentSearchState));
      api2.setEnabled("prev", hasPrev(editor, currentSearchState));
    };
    const updateSearchState = (api2) => {
      const data = api2.getData();
      const current = currentSearchState.get();
      currentSearchState.set({
        ...current,
        matchCase: data.matchcase,
        wholeWord: data.wholewords,
        inSelection: data.inselection
      });
    };
    const disableAll = (api2, disable) => {
      const buttons = [
        "replace",
        "replaceall",
        "prev",
        "next"
      ];
      const toggle = (name) => api2.setEnabled(name, !disable);
      each(buttons, toggle);
    };
    const notFoundAlert = (api2) => {
      editor.windowManager.alert("Could not find the specified string.", () => {
        api2.focus("findtext");
      });
    };
    const focusButtonIfRequired = (api2, name) => {
      if (global$2.browser.isSafari() && global$2.deviceType.isTouch() && (name === "find" || name === "replace" || name === "replaceall")) {
        api2.focus(name);
      }
    };
    const reset = (api2) => {
      done(editor, currentSearchState, false);
      disableAll(api2, true);
      updateButtonStates(api2);
    };
    const doFind = (api2) => {
      const data = api2.getData();
      const last = currentSearchState.get();
      if (!data.findtext.length) {
        reset(api2);
        return;
      }
      if (last.text === data.findtext && last.matchCase === data.matchcase && last.wholeWord === data.wholewords) {
        next(editor, currentSearchState);
      } else {
        const count = find(editor, currentSearchState, data.findtext, data.matchcase, data.wholewords, data.inselection);
        if (count <= 0) {
          notFoundAlert(api2);
        }
        disableAll(api2, count === 0);
      }
      updateButtonStates(api2);
    };
    const initialState = currentSearchState.get();
    const initialData = {
      findtext: selectedText,
      replacetext: "",
      wholewords: initialState.wholeWord,
      matchcase: initialState.matchCase,
      inselection: initialState.inSelection
    };
    const spec = {
      title: "Find and Replace",
      size: "normal",
      body: {
        type: "panel",
        items: [
          {
            type: "bar",
            items: [
              {
                type: "input",
                name: "findtext",
                placeholder: "Find",
                maximized: true,
                inputMode: "search"
              },
              {
                type: "button",
                name: "prev",
                text: "Previous",
                icon: "action-prev",
                enabled: false,
                borderless: true
              },
              {
                type: "button",
                name: "next",
                text: "Next",
                icon: "action-next",
                enabled: false,
                borderless: true
              }
            ]
          },
          {
            type: "input",
            name: "replacetext",
            placeholder: "Replace with",
            inputMode: "search"
          }
        ]
      },
      buttons: [
        {
          type: "menu",
          name: "options",
          icon: "preferences",
          tooltip: "Preferences",
          align: "start",
          items: [
            {
              type: "togglemenuitem",
              name: "matchcase",
              text: "Match case"
            },
            {
              type: "togglemenuitem",
              name: "wholewords",
              text: "Find whole words only"
            },
            {
              type: "togglemenuitem",
              name: "inselection",
              text: "Find in selection"
            }
          ]
        },
        {
          type: "custom",
          name: "find",
          text: "Find",
          primary: true
        },
        {
          type: "custom",
          name: "replace",
          text: "Replace",
          enabled: false
        },
        {
          type: "custom",
          name: "replaceall",
          text: "Replace all",
          enabled: false
        }
      ],
      initialData,
      onChange: (api2, details) => {
        if (details.name === "findtext" && currentSearchState.get().count > 0) {
          reset(api2);
        }
      },
      onAction: (api2, details) => {
        const data = api2.getData();
        switch (details.name) {
          case "find":
            doFind(api2);
            break;
          case "replace":
            if (!replace(editor, currentSearchState, data.replacetext)) {
              reset(api2);
            } else {
              updateButtonStates(api2);
            }
            break;
          case "replaceall":
            replace(editor, currentSearchState, data.replacetext, true, true);
            reset(api2);
            break;
          case "prev":
            prev(editor, currentSearchState);
            updateButtonStates(api2);
            break;
          case "next":
            next(editor, currentSearchState);
            updateButtonStates(api2);
            break;
          case "matchcase":
          case "wholewords":
          case "inselection":
            updateSearchState(api2);
            reset(api2);
            break;
        }
        focusButtonIfRequired(api2, details.name);
      },
      onSubmit: (api2) => {
        doFind(api2);
        focusButtonIfRequired(api2, "find");
      },
      onClose: () => {
        editor.focus();
        done(editor, currentSearchState);
        editor.undoManager.add();
      }
    };
    dialogApi.set(editor.windowManager.open(spec, { inline: "toolbar" }));
  };
  const register$1 = (editor, currentSearchState) => {
    editor.addCommand("SearchReplace", () => {
      open(editor, currentSearchState);
    });
  };
  const showDialog = (editor, currentSearchState) => () => {
    open(editor, currentSearchState);
  };
  const register = (editor, currentSearchState) => {
    editor.ui.registry.addMenuItem("searchreplace", {
      text: "Find and replace...",
      shortcut: "Meta+F",
      onAction: showDialog(editor, currentSearchState),
      icon: "search"
    });
    editor.ui.registry.addButton("searchreplace", {
      tooltip: "Find and replace",
      onAction: showDialog(editor, currentSearchState),
      icon: "search"
    });
    editor.shortcuts.add("Meta+F", "", showDialog(editor, currentSearchState));
  };
  var Plugin = () => {
    global$3.add("searchreplace", (editor) => {
      const currentSearchState = Cell({
        index: -1,
        count: 0,
        text: "",
        matchCase: false,
        wholeWord: false,
        inSelection: false
      });
      register$1(editor, currentSearchState);
      register(editor, currentSearchState);
      return get(editor, currentSearchState);
    });
  };
  Plugin();
})();
(function() {
  const Cell = (initial) => {
    let value = initial;
    const get = () => {
      return value;
    };
    const set = (v) => {
      value = v;
    };
    return {
      get,
      set
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const fireVisualBlocks = (editor, state) => {
    editor.dispatch("VisualBlocks", { state });
  };
  const toggleVisualBlocks = (editor, pluginUrl, enabledState) => {
    const dom = editor.dom;
    dom.toggleClass(editor.getBody(), "mce-visualblocks");
    enabledState.set(!enabledState.get());
    fireVisualBlocks(editor, enabledState.get());
  };
  const register$2 = (editor, pluginUrl, enabledState) => {
    editor.addCommand("mceVisualBlocks", () => {
      toggleVisualBlocks(editor, pluginUrl, enabledState);
    });
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("visualblocks_default_state", {
      processor: "boolean",
      default: false
    });
  };
  const isEnabledByDefault = option("visualblocks_default_state");
  const setup = (editor, pluginUrl, enabledState) => {
    editor.on("PreviewFormats AfterPreviewFormats", (e) => {
      if (enabledState.get()) {
        editor.dom.toggleClass(editor.getBody(), "mce-visualblocks", e.type === "afterpreviewformats");
      }
    });
    editor.on("init", () => {
      if (isEnabledByDefault(editor)) {
        toggleVisualBlocks(editor, pluginUrl, enabledState);
      }
    });
  };
  const toggleActiveState = (editor, enabledState) => (api) => {
    api.setActive(enabledState.get());
    const editorEventCallback = (e) => api.setActive(e.state);
    editor.on("VisualBlocks", editorEventCallback);
    return () => editor.off("VisualBlocks", editorEventCallback);
  };
  const register = (editor, enabledState) => {
    const onAction = () => editor.execCommand("mceVisualBlocks");
    editor.ui.registry.addToggleButton("visualblocks", {
      icon: "visualblocks",
      tooltip: "Show blocks",
      onAction,
      onSetup: toggleActiveState(editor, enabledState)
    });
    editor.ui.registry.addToggleMenuItem("visualblocks", {
      text: "Show blocks",
      icon: "visualblocks",
      onAction,
      onSetup: toggleActiveState(editor, enabledState)
    });
  };
  var Plugin = () => {
    global2.add("visualblocks", (editor, pluginUrl) => {
      register$1(editor);
      const enabledState = Cell(false);
      register$2(editor, pluginUrl, enabledState);
      register(editor, enabledState);
      setup(editor, pluginUrl, enabledState);
    });
  };
  Plugin();
})();
(function() {
  const Cell = (initial) => {
    let value2 = initial;
    const get2 = () => {
      return value2;
    };
    const set2 = (v) => {
      value2 = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const get$2 = (toggleState) => {
    const isEnabled = () => {
      return toggleState.get();
    };
    return { isEnabled };
  };
  const fireVisualChars = (editor, state) => {
    return editor.dispatch("VisualChars", { state });
  };
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
  const isSimpleType = (type2) => (value2) => typeof value2 === type2;
  const eq = (t) => (a) => t === a;
  const isString = isType$1("string");
  const isNull = eq(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isNumber = isSimpleType("number");
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const map = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const filter = (xs, pred) => {
    const r = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r.push(x);
      }
    }
    return r;
  };
  const keys = Object.keys;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const TEXT = 3;
  const type = (element) => element.dom.nodeType;
  const value = (element) => element.dom.nodeValue;
  const isType = (t) => (element) => type(element) === t;
  const isText = isType(TEXT);
  const rawSet = (dom, key, value2) => {
    if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
      dom.setAttribute(key, value2 + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key, ":: Value ", value2, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set = (element, key, value2) => {
    rawSet(element.dom, key, value2);
  };
  const get$1 = (element, key) => {
    const v = element.dom.getAttribute(key);
    return v === null ? void 0 : v;
  };
  const remove$3 = (element, key) => {
    element.dom.removeAttribute(key);
  };
  const read = (element, attr) => {
    const value2 = get$1(element, attr);
    return value2 === void 0 || value2 === "" ? [] : value2.split(" ");
  };
  const add$2 = (element, attr, id) => {
    const old = read(element, attr);
    const nu = old.concat([id]);
    set(element, attr, nu.join(" "));
    return true;
  };
  const remove$2 = (element, attr, id) => {
    const nu = filter(read(element, attr), (v) => v !== id);
    if (nu.length > 0) {
      set(element, attr, nu.join(" "));
    } else {
      remove$3(element, attr);
    }
    return false;
  };
  const supports = (element) => element.dom.classList !== void 0;
  const get = (element) => read(element, "class");
  const add$1 = (element, clazz) => add$2(element, "class", clazz);
  const remove$1 = (element, clazz) => remove$2(element, "class", clazz);
  const add = (element, clazz) => {
    if (supports(element)) {
      element.dom.classList.add(clazz);
    } else {
      add$1(element, clazz);
    }
  };
  const cleanClass = (element) => {
    const classList = supports(element) ? element.dom.classList : get(element);
    if (classList.length === 0) {
      remove$3(element, "class");
    }
  };
  const remove = (element, clazz) => {
    if (supports(element)) {
      const classList = element.dom.classList;
      classList.remove(clazz);
    } else {
      remove$1(element, clazz);
    }
    cleanClass(element);
  };
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  const charMap = {
    "\xA0": "nbsp",
    "\xAD": "shy"
  };
  const charMapToRegExp = (charMap2, global3) => {
    let regExp2 = "";
    each(charMap2, (_value, key) => {
      regExp2 += key;
    });
    return new RegExp("[" + regExp2 + "]", global3 ? "g" : "");
  };
  const charMapToSelector = (charMap2) => {
    let selector2 = "";
    each(charMap2, (value2) => {
      if (selector2) {
        selector2 += ",";
      }
      selector2 += "span.mce-" + value2;
    });
    return selector2;
  };
  const regExp = charMapToRegExp(charMap);
  const regExpGlobal = charMapToRegExp(charMap, true);
  const selector = charMapToSelector(charMap);
  const nbspClass = "mce-nbsp";
  const wrapCharWithSpan = (value2) => '<span data-mce-bogus="1" class="mce-' + charMap[value2] + '">' + value2 + "</span>";
  const isMatch = (n) => {
    const value$1 = value(n);
    return isText(n) && value$1 !== void 0 && regExp.test(value$1);
  };
  const filterDescendants = (scope, predicate) => {
    let result = [];
    const dom = scope.dom;
    const children = map(dom.childNodes, SugarElement.fromDom);
    each$1(children, (x) => {
      if (predicate(x)) {
        result = result.concat([x]);
      }
      result = result.concat(filterDescendants(x, predicate));
    });
    return result;
  };
  const findParentElm = (elm, rootElm) => {
    while (elm.parentNode) {
      if (elm.parentNode === rootElm) {
        return elm;
      }
      elm = elm.parentNode;
    }
  };
  const replaceWithSpans = (text) => text.replace(regExpGlobal, wrapCharWithSpan);
  const isWrappedNbsp = (node) => node.nodeName.toLowerCase() === "span" && node.classList.contains("mce-nbsp-wrap");
  const show = (editor, rootElm) => {
    const nodeList = filterDescendants(SugarElement.fromDom(rootElm), isMatch);
    each$1(nodeList, (n) => {
      const parent = n.dom.parentNode;
      if (isWrappedNbsp(parent)) {
        add(SugarElement.fromDom(parent), nbspClass);
      } else {
        const withSpans = replaceWithSpans(editor.dom.encode(value(n)));
        const div = editor.dom.create("div", null, withSpans);
        let node;
        while (node = div.lastChild) {
          editor.dom.insertAfter(node, n.dom);
        }
        editor.dom.remove(n.dom);
      }
    });
  };
  const hide = (editor, rootElm) => {
    const nodeList = editor.dom.select(selector, rootElm);
    each$1(nodeList, (node) => {
      if (isWrappedNbsp(node)) {
        remove(SugarElement.fromDom(node), nbspClass);
      } else {
        editor.dom.remove(node, true);
      }
    });
  };
  const toggle = (editor) => {
    const body = editor.getBody();
    const bookmark = editor.selection.getBookmark();
    let parentNode = findParentElm(editor.selection.getNode(), body);
    parentNode = parentNode !== void 0 ? parentNode : body;
    hide(editor, parentNode);
    show(editor, parentNode);
    editor.selection.moveToBookmark(bookmark);
  };
  const applyVisualChars = (editor, toggleState) => {
    fireVisualChars(editor, toggleState.get());
    const body = editor.getBody();
    if (toggleState.get() === true) {
      show(editor, body);
    } else {
      hide(editor, body);
    }
  };
  const toggleVisualChars = (editor, toggleState) => {
    toggleState.set(!toggleState.get());
    const bookmark = editor.selection.getBookmark();
    applyVisualChars(editor, toggleState);
    editor.selection.moveToBookmark(bookmark);
  };
  const register$2 = (editor, toggleState) => {
    editor.addCommand("mceVisualChars", () => {
      toggleVisualChars(editor, toggleState);
    });
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("visualchars_default_state", {
      processor: "boolean",
      default: false
    });
  };
  const isEnabledByDefault = option("visualchars_default_state");
  const setup$1 = (editor, toggleState) => {
    editor.on("init", () => {
      applyVisualChars(editor, toggleState);
    });
  };
  const first = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      if (isNull(timer)) {
        timer = setTimeout(() => {
          timer = null;
          fn.apply(null, args);
        }, rate);
      }
    };
    return {
      cancel,
      throttle
    };
  };
  const setup = (editor, toggleState) => {
    const debouncedToggle = first(() => {
      toggle(editor);
    }, 300);
    editor.on("keydown", (e) => {
      if (toggleState.get() === true) {
        e.keyCode === 13 ? toggle(editor) : debouncedToggle.throttle();
      }
    });
    editor.on("remove", debouncedToggle.cancel);
  };
  const toggleActiveState = (editor, enabledStated) => (api) => {
    api.setActive(enabledStated.get());
    const editorEventCallback = (e) => api.setActive(e.state);
    editor.on("VisualChars", editorEventCallback);
    return () => editor.off("VisualChars", editorEventCallback);
  };
  const register = (editor, toggleState) => {
    const onAction = () => editor.execCommand("mceVisualChars");
    editor.ui.registry.addToggleButton("visualchars", {
      tooltip: "Show invisible characters",
      icon: "visualchars",
      onAction,
      onSetup: toggleActiveState(editor, toggleState)
    });
    editor.ui.registry.addToggleMenuItem("visualchars", {
      text: "Show invisible characters",
      icon: "visualchars",
      onAction,
      onSetup: toggleActiveState(editor, toggleState)
    });
  };
  var Plugin = () => {
    global2.add("visualchars", (editor) => {
      register$1(editor);
      const toggleState = Cell(isEnabledByDefault(editor));
      register$2(editor, toggleState);
      register(editor, toggleState);
      setup(editor, toggleState);
      setup$1(editor, toggleState);
      return get$2(toggleState);
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("insertdatetime_dateformat", {
      processor: "string",
      default: editor.translate("%Y-%m-%d")
    });
    registerOption("insertdatetime_timeformat", {
      processor: "string",
      default: editor.translate("%H:%M:%S")
    });
    registerOption("insertdatetime_formats", {
      processor: "string[]",
      default: [
        "%H:%M:%S",
        "%Y-%m-%d",
        "%I:%M:%S %p",
        "%D"
      ]
    });
    registerOption("insertdatetime_element", {
      processor: "boolean",
      default: false
    });
  };
  const getDateFormat = option("insertdatetime_dateformat");
  const getTimeFormat = option("insertdatetime_timeformat");
  const getFormats = option("insertdatetime_formats");
  const shouldInsertTimeElement = option("insertdatetime_element");
  const getDefaultDateTime = (editor) => {
    const formats = getFormats(editor);
    return formats.length > 0 ? formats[0] : getTimeFormat(editor);
  };
  const daysShort = "Sun Mon Tue Wed Thu Fri Sat Sun".split(" ");
  const daysLong = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" ");
  const monthsShort = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");
  const monthsLong = "January February March April May June July August September October November December".split(" ");
  const addZeros = (value, len) => {
    value = "" + value;
    if (value.length < len) {
      for (let i = 0; i < len - value.length; i++) {
        value = "0" + value;
      }
    }
    return value;
  };
  const getDateTime = (editor, fmt, date = new Date()) => {
    fmt = fmt.replace("%D", "%m/%d/%Y");
    fmt = fmt.replace("%r", "%I:%M:%S %p");
    fmt = fmt.replace("%Y", "" + date.getFullYear());
    fmt = fmt.replace("%y", "" + date.getYear());
    fmt = fmt.replace("%m", addZeros(date.getMonth() + 1, 2));
    fmt = fmt.replace("%d", addZeros(date.getDate(), 2));
    fmt = fmt.replace("%H", "" + addZeros(date.getHours(), 2));
    fmt = fmt.replace("%M", "" + addZeros(date.getMinutes(), 2));
    fmt = fmt.replace("%S", "" + addZeros(date.getSeconds(), 2));
    fmt = fmt.replace("%I", "" + ((date.getHours() + 11) % 12 + 1));
    fmt = fmt.replace("%p", date.getHours() < 12 ? "AM" : "PM");
    fmt = fmt.replace("%B", "" + editor.translate(monthsLong[date.getMonth()]));
    fmt = fmt.replace("%b", "" + editor.translate(monthsShort[date.getMonth()]));
    fmt = fmt.replace("%A", "" + editor.translate(daysLong[date.getDay()]));
    fmt = fmt.replace("%a", "" + editor.translate(daysShort[date.getDay()]));
    fmt = fmt.replace("%%", "%");
    return fmt;
  };
  const updateElement = (editor, timeElm, computerTime, userTime) => {
    const newTimeElm = editor.dom.create("time", { datetime: computerTime }, userTime);
    timeElm.parentNode.insertBefore(newTimeElm, timeElm);
    editor.dom.remove(timeElm);
    editor.selection.select(newTimeElm, true);
    editor.selection.collapse(false);
  };
  const insertDateTime = (editor, format) => {
    if (shouldInsertTimeElement(editor)) {
      const userTime = getDateTime(editor, format);
      let computerTime;
      if (/%[HMSIp]/.test(format)) {
        computerTime = getDateTime(editor, "%Y-%m-%dT%H:%M");
      } else {
        computerTime = getDateTime(editor, "%Y-%m-%d");
      }
      const timeElm = editor.dom.getParent(editor.selection.getStart(), "time");
      if (timeElm) {
        updateElement(editor, timeElm, computerTime, userTime);
      } else {
        editor.insertContent('<time datetime="' + computerTime + '">' + userTime + "</time>");
      }
    } else {
      editor.insertContent(getDateTime(editor, format));
    }
  };
  const register$1 = (editor) => {
    editor.addCommand("mceInsertDate", (_ui, value) => {
      insertDateTime(editor, value !== null && value !== void 0 ? value : getDateFormat(editor));
    });
    editor.addCommand("mceInsertTime", (_ui, value) => {
      insertDateTime(editor, value !== null && value !== void 0 ? value : getTimeFormat(editor));
    });
  };
  const Cell = (initial) => {
    let value = initial;
    const get = () => {
      return value;
    };
    const set = (v) => {
      value = v;
    };
    return {
      get,
      set
    };
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const register = (editor) => {
    const formats = getFormats(editor);
    const defaultFormat = Cell(getDefaultDateTime(editor));
    const insertDateTime2 = (format) => editor.execCommand("mceInsertDate", false, format);
    editor.ui.registry.addSplitButton("insertdatetime", {
      icon: "insert-time",
      tooltip: "Insert date/time",
      select: (value) => value === defaultFormat.get(),
      fetch: (done) => {
        done(global2.map(formats, (format) => ({
          type: "choiceitem",
          text: getDateTime(editor, format),
          value: format
        })));
      },
      onAction: (_api) => {
        insertDateTime2(defaultFormat.get());
      },
      onItemAction: (_api, value) => {
        defaultFormat.set(value);
        insertDateTime2(value);
      }
    });
    const makeMenuItemHandler = (format) => () => {
      defaultFormat.set(format);
      insertDateTime2(format);
    };
    editor.ui.registry.addNestedMenuItem("insertdatetime", {
      icon: "insert-time",
      text: "Date/time",
      getSubmenuItems: () => global2.map(formats, (format) => ({
        type: "menuitem",
        text: getDateTime(editor, format),
        onAction: makeMenuItemHandler(format)
      }))
    });
  };
  var Plugin = () => {
    global$1.add("insertdatetime", (editor) => {
      register$2(editor);
      register$1(editor);
      register(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const isSimpleType = (type) => (value) => typeof value === type;
  const isBoolean = isSimpleType("boolean");
  const isNumber = isSimpleType("number");
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor) => {
    const registerOption = editor.options.register;
    registerOption("nonbreaking_force_tab", {
      processor: (value) => {
        if (isBoolean(value)) {
          return {
            value: value ? 3 : 0,
            valid: true
          };
        } else if (isNumber(value)) {
          return {
            value,
            valid: true
          };
        } else {
          return {
            valid: false,
            message: "Must be a boolean or number."
          };
        }
      },
      default: false
    });
    registerOption("nonbreaking_wrap", {
      processor: "boolean",
      default: true
    });
  };
  const getKeyboardSpaces = option("nonbreaking_force_tab");
  const wrapNbsps = option("nonbreaking_wrap");
  const stringRepeat = (string, repeats) => {
    let str = "";
    for (let index2 = 0; index2 < repeats; index2++) {
      str += string;
    }
    return str;
  };
  const isVisualCharsEnabled = (editor) => editor.plugins.visualchars ? editor.plugins.visualchars.isEnabled() : false;
  const insertNbsp = (editor, times) => {
    const classes = () => isVisualCharsEnabled(editor) ? "mce-nbsp-wrap mce-nbsp" : "mce-nbsp-wrap";
    const nbspSpan = () => `<span class="${classes()}" contenteditable="false">${stringRepeat("&nbsp;", times)}</span>`;
    const shouldWrap = wrapNbsps(editor);
    const html = shouldWrap || editor.plugins.visualchars ? nbspSpan() : stringRepeat("&nbsp;", times);
    editor.undoManager.transact(() => editor.insertContent(html));
  };
  const register$1 = (editor) => {
    editor.addCommand("mceNonBreaking", () => {
      insertNbsp(editor, 1);
    });
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.util.VK");
  const setup = (editor) => {
    const spaces = getKeyboardSpaces(editor);
    if (spaces > 0) {
      editor.on("keydown", (e) => {
        if (e.keyCode === global2.TAB && !e.isDefaultPrevented()) {
          if (e.shiftKey) {
            return;
          }
          e.preventDefault();
          e.stopImmediatePropagation();
          insertNbsp(editor, spaces);
        }
      });
    }
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mceNonBreaking");
    editor.ui.registry.addButton("nonbreaking", {
      icon: "non-breaking",
      tooltip: "Nonbreaking space",
      onAction
    });
    editor.ui.registry.addMenuItem("nonbreaking", {
      icon: "non-breaking",
      text: "Nonbreaking space",
      onAction
    });
  };
  var Plugin = () => {
    global$1.add("nonbreaking", (editor) => {
      register$2(editor);
      register$1(editor);
      register(editor);
      setup(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$4 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const eq = (t) => (a) => t === a;
  const isString = isType("string");
  const isUndefined = eq(void 0);
  var global$3 = tinymce.util.Tools.resolve("tinymce.util.Delay");
  var global$2 = tinymce.util.Tools.resolve("tinymce.util.LocalStorage");
  var global$1 = tinymce.util.Tools.resolve("tinymce.util.Tools");
  const fireRestoreDraft = (editor) => editor.dispatch("RestoreDraft");
  const fireStoreDraft = (editor) => editor.dispatch("StoreDraft");
  const fireRemoveDraft = (editor) => editor.dispatch("RemoveDraft");
  const parse = (timeString) => {
    const multiples = {
      s: 1e3,
      m: 6e4
    };
    const parsedTime = /^(\d+)([ms]?)$/.exec(timeString);
    return (parsedTime[2] ? multiples[parsedTime[2]] : 1) * parseInt(timeString, 10);
  };
  const option = (name) => (editor) => editor.options.get(name);
  const register$1 = (editor) => {
    const registerOption = editor.options.register;
    const timeProcessor = (value) => {
      const valid = isString(value);
      if (valid) {
        return {
          value: parse(value),
          valid
        };
      } else {
        return {
          valid: false,
          message: "Must be a string."
        };
      }
    };
    registerOption("autosave_ask_before_unload", {
      processor: "boolean",
      default: true
    });
    registerOption("autosave_prefix", {
      processor: "string",
      default: "tinymce-autosave-{path}{query}{hash}-{id}-"
    });
    registerOption("autosave_restore_when_empty", {
      processor: "boolean",
      default: false
    });
    registerOption("autosave_interval", {
      processor: timeProcessor,
      default: "30s"
    });
    registerOption("autosave_retention", {
      processor: timeProcessor,
      default: "20m"
    });
  };
  const shouldAskBeforeUnload = option("autosave_ask_before_unload");
  const shouldRestoreWhenEmpty = option("autosave_restore_when_empty");
  const getAutoSaveInterval = option("autosave_interval");
  const getAutoSaveRetention = option("autosave_retention");
  const getAutoSavePrefix = (editor) => {
    const location = document.location;
    return editor.options.get("autosave_prefix").replace(/{path}/g, location.pathname).replace(/{query}/g, location.search).replace(/{hash}/g, location.hash).replace(/{id}/g, editor.id);
  };
  const isEmpty = (editor, html) => {
    if (isUndefined(html)) {
      return editor.dom.isEmpty(editor.getBody());
    } else {
      const trimmedHtml = global$1.trim(html);
      if (trimmedHtml === "") {
        return true;
      } else {
        const fragment = new DOMParser().parseFromString(trimmedHtml, "text/html");
        return editor.dom.isEmpty(fragment);
      }
    }
  };
  const hasDraft = (editor) => {
    const time = parseInt(global$2.getItem(getAutoSavePrefix(editor) + "time"), 10) || 0;
    if (new Date().getTime() - time > getAutoSaveRetention(editor)) {
      removeDraft(editor, false);
      return false;
    }
    return true;
  };
  const removeDraft = (editor, fire) => {
    const prefix = getAutoSavePrefix(editor);
    global$2.removeItem(prefix + "draft");
    global$2.removeItem(prefix + "time");
    if (fire !== false) {
      fireRemoveDraft(editor);
    }
  };
  const storeDraft = (editor) => {
    const prefix = getAutoSavePrefix(editor);
    if (!isEmpty(editor) && editor.isDirty()) {
      global$2.setItem(prefix + "draft", editor.getContent({
        format: "raw",
        no_events: true
      }));
      global$2.setItem(prefix + "time", new Date().getTime().toString());
      fireStoreDraft(editor);
    }
  };
  const restoreDraft = (editor) => {
    const prefix = getAutoSavePrefix(editor);
    if (hasDraft(editor)) {
      editor.setContent(global$2.getItem(prefix + "draft"), { format: "raw" });
      fireRestoreDraft(editor);
    }
  };
  const startStoreDraft = (editor) => {
    const interval = getAutoSaveInterval(editor);
    global$3.setEditorInterval(editor, () => {
      storeDraft(editor);
    }, interval);
  };
  const restoreLastDraft = (editor) => {
    editor.undoManager.transact(() => {
      restoreDraft(editor);
      removeDraft(editor);
    });
    editor.focus();
  };
  const get = (editor) => ({
    hasDraft: () => hasDraft(editor),
    storeDraft: () => storeDraft(editor),
    restoreDraft: () => restoreDraft(editor),
    removeDraft: (fire) => removeDraft(editor, fire),
    isEmpty: (html) => isEmpty(editor, html)
  });
  var global2 = tinymce.util.Tools.resolve("tinymce.EditorManager");
  const setup = (editor) => {
    editor.editorManager.on("BeforeUnload", (e) => {
      let msg;
      global$1.each(global2.get(), (editor2) => {
        if (editor2.plugins.autosave) {
          editor2.plugins.autosave.storeDraft();
        }
        if (!msg && editor2.isDirty() && shouldAskBeforeUnload(editor2)) {
          msg = editor2.translate("You have unsaved changes are you sure you want to navigate away?");
        }
      });
      if (msg) {
        e.preventDefault();
        e.returnValue = msg;
      }
    });
  };
  const makeSetupHandler = (editor) => (api) => {
    api.setEnabled(hasDraft(editor));
    const editorEventCallback = () => api.setEnabled(hasDraft(editor));
    editor.on("StoreDraft RestoreDraft RemoveDraft", editorEventCallback);
    return () => editor.off("StoreDraft RestoreDraft RemoveDraft", editorEventCallback);
  };
  const register = (editor) => {
    startStoreDraft(editor);
    editor.ui.registry.addButton("restoredraft", {
      tooltip: "Restore last draft",
      icon: "restore-draft",
      onAction: () => {
        restoreLastDraft(editor);
      },
      onSetup: makeSetupHandler(editor)
    });
    editor.ui.registry.addMenuItem("restoredraft", {
      text: "Restore last draft",
      icon: "restore-draft",
      onAction: () => {
        restoreLastDraft(editor);
      },
      onSetup: makeSetupHandler(editor)
    });
  };
  var Plugin = () => {
    global$4.add("autosave", (editor) => {
      register$1(editor);
      setup(editor);
      register(editor);
      editor.on("init", () => {
        if (shouldRestoreWhenEmpty(editor) && editor.dom.isEmpty(editor.getBody())) {
          restoreDraft(editor);
        }
      });
      return get(editor);
    });
  };
  Plugin();
})();
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const eq = (t) => (a) => t === a;
  const isNull = eq(null);
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const noop = () => {
  };
  const constant = (value2) => {
    return () => {
      return value2;
    };
  };
  const never = constant(false);
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const exists = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return true;
      }
    }
    return false;
  };
  const map$1 = (xs, f) => {
    const len = xs.length;
    const r = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r[i] = f(x, i);
    }
    return r;
  };
  const each$1 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const Cell = (initial) => {
    let value2 = initial;
    const get = () => {
      return value2;
    };
    const set = (v) => {
      value2 = v;
    };
    return {
      get,
      set
    };
  };
  const last = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      cancel();
      timer = setTimeout(() => {
        timer = null;
        fn.apply(null, args);
      }, rate);
    };
    return {
      cancel,
      throttle
    };
  };
  const insertEmoticon = (editor, ch) => {
    editor.insertContent(ch);
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const map = (obj, f) => {
    return tupleMap(obj, (x, i) => ({
      k: i,
      v: f(x, i)
    }));
  };
  const tupleMap = (obj, f) => {
    const r = {};
    each(obj, (x, i) => {
      const tuple = f(x, i);
      r[tuple.k] = tuple.v;
    });
    return r;
  };
  const has = (obj, key) => hasOwnProperty.call(obj, key);
  const shallow = (old, nu) => {
    return nu;
  };
  const baseMerge = (merger) => {
    return (...objects) => {
      if (objects.length === 0) {
        throw new Error(`Can't merge zero objects`);
      }
      const ret = {};
      for (let j = 0; j < objects.length; j++) {
        const curObject = objects[j];
        for (const key in curObject) {
          if (has(curObject, key)) {
            ret[key] = merger(ret[key], curObject[key]);
          }
        }
      }
      return ret;
    };
  };
  const merge = baseMerge(shallow);
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get = () => subject.get();
    const set = (s) => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear,
      isSet,
      get,
      set
    };
  };
  const value = () => {
    const subject = singleton(noop);
    const on = (f) => subject.get().each(f);
    return {
      ...subject,
      on
    };
  };
  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const contains = (str, substr) => {
    return str.indexOf(substr) !== -1;
  };
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.Resource");
  const DEFAULT_ID = "tinymce.plugins.emoticons";
  const option = (name) => (editor) => editor.options.get(name);
  const register$2 = (editor, pluginUrl) => {
    const registerOption = editor.options.register;
    registerOption("emoticons_database", {
      processor: "string",
      default: "emojis"
    });
    registerOption("emoticons_database_url", {
      processor: "string",
      default: `${pluginUrl}/js/${getEmojiDatabase(editor)}${editor.suffix}.js`
    });
    registerOption("emoticons_database_id", {
      processor: "string",
      default: DEFAULT_ID
    });
    registerOption("emoticons_append", {
      processor: "object",
      default: {}
    });
    registerOption("emoticons_images_url", {
      processor: "string",
      default: "https://twemoji.maxcdn.com/v/13.0.1/72x72/"
    });
  };
  const getEmojiDatabase = option("emoticons_database");
  const getEmojiDatabaseUrl = option("emoticons_database_url");
  const getEmojiDatabaseId = option("emoticons_database_id");
  const getAppendedEmoji = option("emoticons_append");
  const getEmojiImageUrl = option("emoticons_images_url");
  const ALL_CATEGORY = "All";
  const categoryNameMap = {
    symbols: "Symbols",
    people: "People",
    animals_and_nature: "Animals and Nature",
    food_and_drink: "Food and Drink",
    activity: "Activity",
    travel_and_places: "Travel and Places",
    objects: "Objects",
    flags: "Flags",
    user: "User Defined"
  };
  const translateCategory = (categories, name) => has(categories, name) ? categories[name] : name;
  const getUserDefinedEmoji = (editor) => {
    const userDefinedEmoticons = getAppendedEmoji(editor);
    return map(userDefinedEmoticons, (value2) => ({
      keywords: [],
      category: "user",
      ...value2
    }));
  };
  const initDatabase = (editor, databaseUrl, databaseId) => {
    const categories = value();
    const all = value();
    const emojiImagesUrl = getEmojiImageUrl(editor);
    const getEmoji = (lib) => {
      if (startsWith(lib.char, "<img")) {
        return lib.char.replace(/src="([^"]+)"/, (match, url) => `src="${emojiImagesUrl}${url}"`);
      } else {
        return lib.char;
      }
    };
    const processEmojis = (emojis) => {
      const cats = {};
      const everything = [];
      each(emojis, (lib, title) => {
        const entry = {
          title,
          keywords: lib.keywords,
          char: getEmoji(lib),
          category: translateCategory(categoryNameMap, lib.category)
        };
        const current = cats[entry.category] !== void 0 ? cats[entry.category] : [];
        cats[entry.category] = current.concat([entry]);
        everything.push(entry);
      });
      categories.set(cats);
      all.set(everything);
    };
    editor.on("init", () => {
      global2.load(databaseId, databaseUrl).then((emojis) => {
        const userEmojis = getUserDefinedEmoji(editor);
        processEmojis(merge(emojis, userEmojis));
      }, (err) => {
        console.log(`Failed to load emojis: ${err}`);
        categories.set({});
        all.set([]);
      });
    });
    const listCategory = (category) => {
      if (category === ALL_CATEGORY) {
        return listAll();
      }
      return categories.get().bind((cats) => Optional.from(cats[category])).getOr([]);
    };
    const listAll = () => all.get().getOr([]);
    const listCategories = () => [ALL_CATEGORY].concat(keys(categories.get().getOr({})));
    const waitForLoad = () => {
      if (hasLoaded()) {
        return Promise.resolve(true);
      } else {
        return new Promise((resolve, reject) => {
          let numRetries = 15;
          const interval = setInterval(() => {
            if (hasLoaded()) {
              clearInterval(interval);
              resolve(true);
            } else {
              numRetries--;
              if (numRetries < 0) {
                console.log("Could not load emojis from url: " + databaseUrl);
                clearInterval(interval);
                reject(false);
              }
            }
          }, 100);
        });
      }
    };
    const hasLoaded = () => categories.isSet() && all.isSet();
    return {
      listCategories,
      hasLoaded,
      waitForLoad,
      listAll,
      listCategory
    };
  };
  const emojiMatches = (emoji, lowerCasePattern) => contains(emoji.title.toLowerCase(), lowerCasePattern) || exists(emoji.keywords, (k) => contains(k.toLowerCase(), lowerCasePattern));
  const emojisFrom = (list, pattern, maxResults) => {
    const matches = [];
    const lowerCasePattern = pattern.toLowerCase();
    const reachedLimit = maxResults.fold(() => never, (max) => (size) => size >= max);
    for (let i = 0; i < list.length; i++) {
      if (pattern.length === 0 || emojiMatches(list[i], lowerCasePattern)) {
        matches.push({
          value: list[i].char,
          text: list[i].title,
          icon: list[i].char
        });
        if (reachedLimit(matches.length)) {
          break;
        }
      }
    }
    return matches;
  };
  const patternName = "pattern";
  const open = (editor, database) => {
    const initialState = {
      pattern: "",
      results: emojisFrom(database.listAll(), "", Optional.some(300))
    };
    const currentTab = Cell(ALL_CATEGORY);
    const scan = (dialogApi2) => {
      const dialogData = dialogApi2.getData();
      const category = currentTab.get();
      const candidates = database.listCategory(category);
      const results = emojisFrom(candidates, dialogData[patternName], category === ALL_CATEGORY ? Optional.some(300) : Optional.none());
      dialogApi2.setData({ results });
    };
    const updateFilter = last((dialogApi2) => {
      scan(dialogApi2);
    }, 200);
    const searchField = {
      label: "Search",
      type: "input",
      name: patternName
    };
    const resultsField = {
      type: "collection",
      name: "results"
    };
    const getInitialState = () => {
      const body = {
        type: "tabpanel",
        tabs: map$1(database.listCategories(), (cat) => ({
          title: cat,
          name: cat,
          items: [
            searchField,
            resultsField
          ]
        }))
      };
      return {
        title: "Emojis",
        size: "normal",
        body,
        initialData: initialState,
        onTabChange: (dialogApi2, details) => {
          currentTab.set(details.newTabName);
          updateFilter.throttle(dialogApi2);
        },
        onChange: updateFilter.throttle,
        onAction: (dialogApi2, actionData) => {
          if (actionData.name === "results") {
            insertEmoticon(editor, actionData.value);
            dialogApi2.close();
          }
        },
        buttons: [{
          type: "cancel",
          text: "Close",
          primary: true
        }]
      };
    };
    const dialogApi = editor.windowManager.open(getInitialState());
    dialogApi.focus(patternName);
    if (!database.hasLoaded()) {
      dialogApi.block("Loading emojis...");
      database.waitForLoad().then(() => {
        dialogApi.redial(getInitialState());
        updateFilter.throttle(dialogApi);
        dialogApi.focus(patternName);
        dialogApi.unblock();
      }).catch((_err) => {
        dialogApi.redial({
          title: "Emojis",
          body: {
            type: "panel",
            items: [{
              type: "alertbanner",
              level: "error",
              icon: "warning",
              text: "Could not load emojis"
            }]
          },
          buttons: [{
            type: "cancel",
            text: "Close",
            primary: true
          }],
          initialData: {
            pattern: "",
            results: []
          }
        });
        dialogApi.focus(patternName);
        dialogApi.unblock();
      });
    }
  };
  const register$1 = (editor, database) => {
    editor.addCommand("mceEmoticons", () => open(editor, database));
  };
  const setup = (editor) => {
    editor.on("PreInit", () => {
      editor.parser.addAttributeFilter("data-emoticon", (nodes) => {
        each$1(nodes, (node) => {
          node.attr("data-mce-resize", "false");
          node.attr("data-mce-placeholder", "1");
        });
      });
    });
  };
  const init = (editor, database) => {
    editor.ui.registry.addAutocompleter("emoticons", {
      ch: ":",
      columns: "auto",
      minChars: 2,
      fetch: (pattern, maxResults) => database.waitForLoad().then(() => {
        const candidates = database.listAll();
        return emojisFrom(candidates, pattern, Optional.some(maxResults));
      }),
      onAction: (autocompleteApi, rng, value2) => {
        editor.selection.setRng(rng);
        editor.insertContent(value2);
        autocompleteApi.hide();
      }
    });
  };
  const register = (editor) => {
    const onAction = () => editor.execCommand("mceEmoticons");
    editor.ui.registry.addButton("emoticons", {
      tooltip: "Emojis",
      icon: "emoji",
      onAction
    });
    editor.ui.registry.addMenuItem("emoticons", {
      text: "Emojis...",
      icon: "emoji",
      onAction
    });
  };
  var Plugin = () => {
    global$1.add("emoticons", (editor, pluginUrl) => {
      register$2(editor, pluginUrl);
      const databaseUrl = getEmojiDatabaseUrl(editor);
      const databaseId = getEmojiDatabaseId(editor);
      const database = initDatabase(editor, databaseUrl, databaseId);
      register$1(editor, database);
      register(editor);
      init(editor, database);
      setup(editor);
    });
  };
  Plugin();
})();
window.tinymce.Resource.add("tinymce.plugins.emoticons", { grinning: { keywords: ["face", "smile", "happy", "joy", ":D", "grin"], char: "\u{1F600}", fitzpatrick_scale: false, category: "people" }, grimacing: { keywords: ["face", "grimace", "teeth"], char: "\u{1F62C}", fitzpatrick_scale: false, category: "people" }, grin: { keywords: ["face", "happy", "smile", "joy", "kawaii"], char: "\u{1F601}", fitzpatrick_scale: false, category: "people" }, joy: { keywords: ["face", "cry", "tears", "weep", "happy", "happytears", "haha"], char: "\u{1F602}", fitzpatrick_scale: false, category: "people" }, rofl: { keywords: ["face", "rolling", "floor", "laughing", "lol", "haha"], char: "\u{1F923}", fitzpatrick_scale: false, category: "people" }, partying: { keywords: ["face", "celebration", "woohoo"], char: "\u{1F973}", fitzpatrick_scale: false, category: "people" }, smiley: { keywords: ["face", "happy", "joy", "haha", ":D", ":)", "smile", "funny"], char: "\u{1F603}", fitzpatrick_scale: false, category: "people" }, smile: { keywords: ["face", "happy", "joy", "funny", "haha", "laugh", "like", ":D", ":)"], char: "\u{1F604}", fitzpatrick_scale: false, category: "people" }, sweat_smile: { keywords: ["face", "hot", "happy", "laugh", "sweat", "smile", "relief"], char: "\u{1F605}", fitzpatrick_scale: false, category: "people" }, laughing: { keywords: ["happy", "joy", "lol", "satisfied", "haha", "face", "glad", "XD", "laugh"], char: "\u{1F606}", fitzpatrick_scale: false, category: "people" }, innocent: { keywords: ["face", "angel", "heaven", "halo"], char: "\u{1F607}", fitzpatrick_scale: false, category: "people" }, wink: { keywords: ["face", "happy", "mischievous", "secret", ";)", "smile", "eye"], char: "\u{1F609}", fitzpatrick_scale: false, category: "people" }, blush: { keywords: ["face", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy"], char: "\u{1F60A}", fitzpatrick_scale: false, category: "people" }, slightly_smiling_face: { keywords: ["face", "smile"], char: "\u{1F642}", fitzpatrick_scale: false, category: "people" }, upside_down_face: { keywords: ["face", "flipped", "silly", "smile"], char: "\u{1F643}", fitzpatrick_scale: false, category: "people" }, relaxed: { keywords: ["face", "blush", "massage", "happiness"], char: "\u263A\uFE0F", fitzpatrick_scale: false, category: "people" }, yum: { keywords: ["happy", "joy", "tongue", "smile", "face", "silly", "yummy", "nom", "delicious", "savouring"], char: "\u{1F60B}", fitzpatrick_scale: false, category: "people" }, relieved: { keywords: ["face", "relaxed", "phew", "massage", "happiness"], char: "\u{1F60C}", fitzpatrick_scale: false, category: "people" }, heart_eyes: { keywords: ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "heart"], char: "\u{1F60D}", fitzpatrick_scale: false, category: "people" }, smiling_face_with_three_hearts: { keywords: ["face", "love", "like", "affection", "valentines", "infatuation", "crush", "hearts", "adore"], char: "\u{1F970}", fitzpatrick_scale: false, category: "people" }, kissing_heart: { keywords: ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"], char: "\u{1F618}", fitzpatrick_scale: false, category: "people" }, kissing: { keywords: ["love", "like", "face", "3", "valentines", "infatuation", "kiss"], char: "\u{1F617}", fitzpatrick_scale: false, category: "people" }, kissing_smiling_eyes: { keywords: ["face", "affection", "valentines", "infatuation", "kiss"], char: "\u{1F619}", fitzpatrick_scale: false, category: "people" }, kissing_closed_eyes: { keywords: ["face", "love", "like", "affection", "valentines", "infatuation", "kiss"], char: "\u{1F61A}", fitzpatrick_scale: false, category: "people" }, stuck_out_tongue_winking_eye: { keywords: ["face", "prank", "childish", "playful", "mischievous", "smile", "wink", "tongue"], char: "\u{1F61C}", fitzpatrick_scale: false, category: "people" }, zany: { keywords: ["face", "goofy", "crazy"], char: "\u{1F92A}", fitzpatrick_scale: false, category: "people" }, raised_eyebrow: { keywords: ["face", "distrust", "scepticism", "disapproval", "disbelief", "surprise"], char: "\u{1F928}", fitzpatrick_scale: false, category: "people" }, monocle: { keywords: ["face", "stuffy", "wealthy"], char: "\u{1F9D0}", fitzpatrick_scale: false, category: "people" }, stuck_out_tongue_closed_eyes: { keywords: ["face", "prank", "playful", "mischievous", "smile", "tongue"], char: "\u{1F61D}", fitzpatrick_scale: false, category: "people" }, stuck_out_tongue: { keywords: ["face", "prank", "childish", "playful", "mischievous", "smile", "tongue"], char: "\u{1F61B}", fitzpatrick_scale: false, category: "people" }, money_mouth_face: { keywords: ["face", "rich", "dollar", "money"], char: "\u{1F911}", fitzpatrick_scale: false, category: "people" }, nerd_face: { keywords: ["face", "nerdy", "geek", "dork"], char: "\u{1F913}", fitzpatrick_scale: false, category: "people" }, sunglasses: { keywords: ["face", "cool", "smile", "summer", "beach", "sunglass"], char: "\u{1F60E}", fitzpatrick_scale: false, category: "people" }, star_struck: { keywords: ["face", "smile", "starry", "eyes", "grinning"], char: "\u{1F929}", fitzpatrick_scale: false, category: "people" }, clown_face: { keywords: ["face"], char: "\u{1F921}", fitzpatrick_scale: false, category: "people" }, cowboy_hat_face: { keywords: ["face", "cowgirl", "hat"], char: "\u{1F920}", fitzpatrick_scale: false, category: "people" }, hugs: { keywords: ["face", "smile", "hug"], char: "\u{1F917}", fitzpatrick_scale: false, category: "people" }, smirk: { keywords: ["face", "smile", "mean", "prank", "smug", "sarcasm"], char: "\u{1F60F}", fitzpatrick_scale: false, category: "people" }, no_mouth: { keywords: ["face", "hellokitty"], char: "\u{1F636}", fitzpatrick_scale: false, category: "people" }, neutral_face: { keywords: ["indifference", "meh", ":|", "neutral"], char: "\u{1F610}", fitzpatrick_scale: false, category: "people" }, expressionless: { keywords: ["face", "indifferent", "-_-", "meh", "deadpan"], char: "\u{1F611}", fitzpatrick_scale: false, category: "people" }, unamused: { keywords: ["indifference", "bored", "straight face", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "side_eye"], char: "\u{1F612}", fitzpatrick_scale: false, category: "people" }, roll_eyes: { keywords: ["face", "eyeroll", "frustrated"], char: "\u{1F644}", fitzpatrick_scale: false, category: "people" }, thinking: { keywords: ["face", "hmmm", "think", "consider"], char: "\u{1F914}", fitzpatrick_scale: false, category: "people" }, lying_face: { keywords: ["face", "lie", "pinocchio"], char: "\u{1F925}", fitzpatrick_scale: false, category: "people" }, hand_over_mouth: { keywords: ["face", "whoops", "shock", "surprise"], char: "\u{1F92D}", fitzpatrick_scale: false, category: "people" }, shushing: { keywords: ["face", "quiet", "shhh"], char: "\u{1F92B}", fitzpatrick_scale: false, category: "people" }, symbols_over_mouth: { keywords: ["face", "swearing", "cursing", "cussing", "profanity", "expletive"], char: "\u{1F92C}", fitzpatrick_scale: false, category: "people" }, exploding_head: { keywords: ["face", "shocked", "mind", "blown"], char: "\u{1F92F}", fitzpatrick_scale: false, category: "people" }, flushed: { keywords: ["face", "blush", "shy", "flattered"], char: "\u{1F633}", fitzpatrick_scale: false, category: "people" }, disappointed: { keywords: ["face", "sad", "upset", "depressed", ":("], char: "\u{1F61E}", fitzpatrick_scale: false, category: "people" }, worried: { keywords: ["face", "concern", "nervous", ":("], char: "\u{1F61F}", fitzpatrick_scale: false, category: "people" }, angry: { keywords: ["mad", "face", "annoyed", "frustrated"], char: "\u{1F620}", fitzpatrick_scale: false, category: "people" }, rage: { keywords: ["angry", "mad", "hate", "despise"], char: "\u{1F621}", fitzpatrick_scale: false, category: "people" }, pensive: { keywords: ["face", "sad", "depressed", "upset"], char: "\u{1F614}", fitzpatrick_scale: false, category: "people" }, confused: { keywords: ["face", "indifference", "huh", "weird", "hmmm", ":/"], char: "\u{1F615}", fitzpatrick_scale: false, category: "people" }, slightly_frowning_face: { keywords: ["face", "frowning", "disappointed", "sad", "upset"], char: "\u{1F641}", fitzpatrick_scale: false, category: "people" }, frowning_face: { keywords: ["face", "sad", "upset", "frown"], char: "\u2639", fitzpatrick_scale: false, category: "people" }, persevere: { keywords: ["face", "sick", "no", "upset", "oops"], char: "\u{1F623}", fitzpatrick_scale: false, category: "people" }, confounded: { keywords: ["face", "confused", "sick", "unwell", "oops", ":S"], char: "\u{1F616}", fitzpatrick_scale: false, category: "people" }, tired_face: { keywords: ["sick", "whine", "upset", "frustrated"], char: "\u{1F62B}", fitzpatrick_scale: false, category: "people" }, weary: { keywords: ["face", "tired", "sleepy", "sad", "frustrated", "upset"], char: "\u{1F629}", fitzpatrick_scale: false, category: "people" }, pleading: { keywords: ["face", "begging", "mercy"], char: "\u{1F97A}", fitzpatrick_scale: false, category: "people" }, triumph: { keywords: ["face", "gas", "phew", "proud", "pride"], char: "\u{1F624}", fitzpatrick_scale: false, category: "people" }, open_mouth: { keywords: ["face", "surprise", "impressed", "wow", "whoa", ":O"], char: "\u{1F62E}", fitzpatrick_scale: false, category: "people" }, scream: { keywords: ["face", "munch", "scared", "omg"], char: "\u{1F631}", fitzpatrick_scale: false, category: "people" }, fearful: { keywords: ["face", "scared", "terrified", "nervous", "oops", "huh"], char: "\u{1F628}", fitzpatrick_scale: false, category: "people" }, cold_sweat: { keywords: ["face", "nervous", "sweat"], char: "\u{1F630}", fitzpatrick_scale: false, category: "people" }, hushed: { keywords: ["face", "woo", "shh"], char: "\u{1F62F}", fitzpatrick_scale: false, category: "people" }, frowning: { keywords: ["face", "aw", "what"], char: "\u{1F626}", fitzpatrick_scale: false, category: "people" }, anguished: { keywords: ["face", "stunned", "nervous"], char: "\u{1F627}", fitzpatrick_scale: false, category: "people" }, cry: { keywords: ["face", "tears", "sad", "depressed", "upset", ":'("], char: "\u{1F622}", fitzpatrick_scale: false, category: "people" }, disappointed_relieved: { keywords: ["face", "phew", "sweat", "nervous"], char: "\u{1F625}", fitzpatrick_scale: false, category: "people" }, drooling_face: { keywords: ["face"], char: "\u{1F924}", fitzpatrick_scale: false, category: "people" }, sleepy: { keywords: ["face", "tired", "rest", "nap"], char: "\u{1F62A}", fitzpatrick_scale: false, category: "people" }, sweat: { keywords: ["face", "hot", "sad", "tired", "exercise"], char: "\u{1F613}", fitzpatrick_scale: false, category: "people" }, hot: { keywords: ["face", "feverish", "heat", "red", "sweating"], char: "\u{1F975}", fitzpatrick_scale: false, category: "people" }, cold: { keywords: ["face", "blue", "freezing", "frozen", "frostbite", "icicles"], char: "\u{1F976}", fitzpatrick_scale: false, category: "people" }, sob: { keywords: ["face", "cry", "tears", "sad", "upset", "depressed"], char: "\u{1F62D}", fitzpatrick_scale: false, category: "people" }, dizzy_face: { keywords: ["spent", "unconscious", "xox", "dizzy"], char: "\u{1F635}", fitzpatrick_scale: false, category: "people" }, astonished: { keywords: ["face", "xox", "surprised", "poisoned"], char: "\u{1F632}", fitzpatrick_scale: false, category: "people" }, zipper_mouth_face: { keywords: ["face", "sealed", "zipper", "secret"], char: "\u{1F910}", fitzpatrick_scale: false, category: "people" }, nauseated_face: { keywords: ["face", "vomit", "gross", "green", "sick", "throw up", "ill"], char: "\u{1F922}", fitzpatrick_scale: false, category: "people" }, sneezing_face: { keywords: ["face", "gesundheit", "sneeze", "sick", "allergy"], char: "\u{1F927}", fitzpatrick_scale: false, category: "people" }, vomiting: { keywords: ["face", "sick"], char: "\u{1F92E}", fitzpatrick_scale: false, category: "people" }, mask: { keywords: ["face", "sick", "ill", "disease"], char: "\u{1F637}", fitzpatrick_scale: false, category: "people" }, face_with_thermometer: { keywords: ["sick", "temperature", "thermometer", "cold", "fever"], char: "\u{1F912}", fitzpatrick_scale: false, category: "people" }, face_with_head_bandage: { keywords: ["injured", "clumsy", "bandage", "hurt"], char: "\u{1F915}", fitzpatrick_scale: false, category: "people" }, woozy: { keywords: ["face", "dizzy", "intoxicated", "tipsy", "wavy"], char: "\u{1F974}", fitzpatrick_scale: false, category: "people" }, sleeping: { keywords: ["face", "tired", "sleepy", "night", "zzz"], char: "\u{1F634}", fitzpatrick_scale: false, category: "people" }, zzz: { keywords: ["sleepy", "tired", "dream"], char: "\u{1F4A4}", fitzpatrick_scale: false, category: "people" }, poop: { keywords: ["hankey", "shitface", "fail", "turd", "shit"], char: "\u{1F4A9}", fitzpatrick_scale: false, category: "people" }, smiling_imp: { keywords: ["devil", "horns"], char: "\u{1F608}", fitzpatrick_scale: false, category: "people" }, imp: { keywords: ["devil", "angry", "horns"], char: "\u{1F47F}", fitzpatrick_scale: false, category: "people" }, japanese_ogre: { keywords: ["monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon", "japanese", "ogre"], char: "\u{1F479}", fitzpatrick_scale: false, category: "people" }, japanese_goblin: { keywords: ["red", "evil", "mask", "monster", "scary", "creepy", "japanese", "goblin"], char: "\u{1F47A}", fitzpatrick_scale: false, category: "people" }, skull: { keywords: ["dead", "skeleton", "creepy", "death"], char: "\u{1F480}", fitzpatrick_scale: false, category: "people" }, ghost: { keywords: ["halloween", "spooky", "scary"], char: "\u{1F47B}", fitzpatrick_scale: false, category: "people" }, alien: { keywords: ["UFO", "paul", "weird", "outer_space"], char: "\u{1F47D}", fitzpatrick_scale: false, category: "people" }, robot: { keywords: ["computer", "machine", "bot"], char: "\u{1F916}", fitzpatrick_scale: false, category: "people" }, smiley_cat: { keywords: ["animal", "cats", "happy", "smile"], char: "\u{1F63A}", fitzpatrick_scale: false, category: "people" }, smile_cat: { keywords: ["animal", "cats", "smile"], char: "\u{1F638}", fitzpatrick_scale: false, category: "people" }, joy_cat: { keywords: ["animal", "cats", "haha", "happy", "tears"], char: "\u{1F639}", fitzpatrick_scale: false, category: "people" }, heart_eyes_cat: { keywords: ["animal", "love", "like", "affection", "cats", "valentines", "heart"], char: "\u{1F63B}", fitzpatrick_scale: false, category: "people" }, smirk_cat: { keywords: ["animal", "cats", "smirk"], char: "\u{1F63C}", fitzpatrick_scale: false, category: "people" }, kissing_cat: { keywords: ["animal", "cats", "kiss"], char: "\u{1F63D}", fitzpatrick_scale: false, category: "people" }, scream_cat: { keywords: ["animal", "cats", "munch", "scared", "scream"], char: "\u{1F640}", fitzpatrick_scale: false, category: "people" }, crying_cat_face: { keywords: ["animal", "tears", "weep", "sad", "cats", "upset", "cry"], char: "\u{1F63F}", fitzpatrick_scale: false, category: "people" }, pouting_cat: { keywords: ["animal", "cats"], char: "\u{1F63E}", fitzpatrick_scale: false, category: "people" }, palms_up: { keywords: ["hands", "gesture", "cupped", "prayer"], char: "\u{1F932}", fitzpatrick_scale: true, category: "people" }, raised_hands: { keywords: ["gesture", "hooray", "yea", "celebration", "hands"], char: "\u{1F64C}", fitzpatrick_scale: true, category: "people" }, clap: { keywords: ["hands", "praise", "applause", "congrats", "yay"], char: "\u{1F44F}", fitzpatrick_scale: true, category: "people" }, wave: { keywords: ["hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm"], char: "\u{1F44B}", fitzpatrick_scale: true, category: "people" }, call_me_hand: { keywords: ["hands", "gesture"], char: "\u{1F919}", fitzpatrick_scale: true, category: "people" }, "+1": { keywords: ["thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like"], char: "\u{1F44D}", fitzpatrick_scale: true, category: "people" }, "-1": { keywords: ["thumbsdown", "no", "dislike", "hand"], char: "\u{1F44E}", fitzpatrick_scale: true, category: "people" }, facepunch: { keywords: ["angry", "violence", "fist", "hit", "attack", "hand"], char: "\u{1F44A}", fitzpatrick_scale: true, category: "people" }, fist: { keywords: ["fingers", "hand", "grasp"], char: "\u270A", fitzpatrick_scale: true, category: "people" }, fist_left: { keywords: ["hand", "fistbump"], char: "\u{1F91B}", fitzpatrick_scale: true, category: "people" }, fist_right: { keywords: ["hand", "fistbump"], char: "\u{1F91C}", fitzpatrick_scale: true, category: "people" }, v: { keywords: ["fingers", "ohyeah", "hand", "peace", "victory", "two"], char: "\u270C", fitzpatrick_scale: true, category: "people" }, ok_hand: { keywords: ["fingers", "limbs", "perfect", "ok", "okay"], char: "\u{1F44C}", fitzpatrick_scale: true, category: "people" }, raised_hand: { keywords: ["fingers", "stop", "highfive", "palm", "ban"], char: "\u270B", fitzpatrick_scale: true, category: "people" }, raised_back_of_hand: { keywords: ["fingers", "raised", "backhand"], char: "\u{1F91A}", fitzpatrick_scale: true, category: "people" }, open_hands: { keywords: ["fingers", "butterfly", "hands", "open"], char: "\u{1F450}", fitzpatrick_scale: true, category: "people" }, muscle: { keywords: ["arm", "flex", "hand", "summer", "strong", "biceps"], char: "\u{1F4AA}", fitzpatrick_scale: true, category: "people" }, pray: { keywords: ["please", "hope", "wish", "namaste", "highfive"], char: "\u{1F64F}", fitzpatrick_scale: true, category: "people" }, foot: { keywords: ["kick", "stomp"], char: "\u{1F9B6}", fitzpatrick_scale: true, category: "people" }, leg: { keywords: ["kick", "limb"], char: "\u{1F9B5}", fitzpatrick_scale: true, category: "people" }, handshake: { keywords: ["agreement", "shake"], char: "\u{1F91D}", fitzpatrick_scale: false, category: "people" }, point_up: { keywords: ["hand", "fingers", "direction", "up"], char: "\u261D", fitzpatrick_scale: true, category: "people" }, point_up_2: { keywords: ["fingers", "hand", "direction", "up"], char: "\u{1F446}", fitzpatrick_scale: true, category: "people" }, point_down: { keywords: ["fingers", "hand", "direction", "down"], char: "\u{1F447}", fitzpatrick_scale: true, category: "people" }, point_left: { keywords: ["direction", "fingers", "hand", "left"], char: "\u{1F448}", fitzpatrick_scale: true, category: "people" }, point_right: { keywords: ["fingers", "hand", "direction", "right"], char: "\u{1F449}", fitzpatrick_scale: true, category: "people" }, fu: { keywords: ["hand", "fingers", "rude", "middle", "flipping"], char: "\u{1F595}", fitzpatrick_scale: true, category: "people" }, raised_hand_with_fingers_splayed: { keywords: ["hand", "fingers", "palm"], char: "\u{1F590}", fitzpatrick_scale: true, category: "people" }, love_you: { keywords: ["hand", "fingers", "gesture"], char: "\u{1F91F}", fitzpatrick_scale: true, category: "people" }, metal: { keywords: ["hand", "fingers", "evil_eye", "sign_of_horns", "rock_on"], char: "\u{1F918}", fitzpatrick_scale: true, category: "people" }, crossed_fingers: { keywords: ["good", "lucky"], char: "\u{1F91E}", fitzpatrick_scale: true, category: "people" }, vulcan_salute: { keywords: ["hand", "fingers", "spock", "star trek"], char: "\u{1F596}", fitzpatrick_scale: true, category: "people" }, writing_hand: { keywords: ["lower_left_ballpoint_pen", "stationery", "write", "compose"], char: "\u270D", fitzpatrick_scale: true, category: "people" }, selfie: { keywords: ["camera", "phone"], char: "\u{1F933}", fitzpatrick_scale: true, category: "people" }, nail_care: { keywords: ["beauty", "manicure", "finger", "fashion", "nail"], char: "\u{1F485}", fitzpatrick_scale: true, category: "people" }, lips: { keywords: ["mouth", "kiss"], char: "\u{1F444}", fitzpatrick_scale: false, category: "people" }, tooth: { keywords: ["teeth", "dentist"], char: "\u{1F9B7}", fitzpatrick_scale: false, category: "people" }, tongue: { keywords: ["mouth", "playful"], char: "\u{1F445}", fitzpatrick_scale: false, category: "people" }, ear: { keywords: ["face", "hear", "sound", "listen"], char: "\u{1F442}", fitzpatrick_scale: true, category: "people" }, nose: { keywords: ["smell", "sniff"], char: "\u{1F443}", fitzpatrick_scale: true, category: "people" }, eye: { keywords: ["face", "look", "see", "watch", "stare"], char: "\u{1F441}", fitzpatrick_scale: false, category: "people" }, eyes: { keywords: ["look", "watch", "stalk", "peek", "see"], char: "\u{1F440}", fitzpatrick_scale: false, category: "people" }, brain: { keywords: ["smart", "intelligent"], char: "\u{1F9E0}", fitzpatrick_scale: false, category: "people" }, bust_in_silhouette: { keywords: ["user", "person", "human"], char: "\u{1F464}", fitzpatrick_scale: false, category: "people" }, busts_in_silhouette: { keywords: ["user", "person", "human", "group", "team"], char: "\u{1F465}", fitzpatrick_scale: false, category: "people" }, speaking_head: { keywords: ["user", "person", "human", "sing", "say", "talk"], char: "\u{1F5E3}", fitzpatrick_scale: false, category: "people" }, baby: { keywords: ["child", "boy", "girl", "toddler"], char: "\u{1F476}", fitzpatrick_scale: true, category: "people" }, child: { keywords: ["gender-neutral", "young"], char: "\u{1F9D2}", fitzpatrick_scale: true, category: "people" }, boy: { keywords: ["man", "male", "guy", "teenager"], char: "\u{1F466}", fitzpatrick_scale: true, category: "people" }, girl: { keywords: ["female", "woman", "teenager"], char: "\u{1F467}", fitzpatrick_scale: true, category: "people" }, adult: { keywords: ["gender-neutral", "person"], char: "\u{1F9D1}", fitzpatrick_scale: true, category: "people" }, man: { keywords: ["mustache", "father", "dad", "guy", "classy", "sir", "moustache"], char: "\u{1F468}", fitzpatrick_scale: true, category: "people" }, woman: { keywords: ["female", "girls", "lady"], char: "\u{1F469}", fitzpatrick_scale: true, category: "people" }, blonde_woman: { keywords: ["woman", "female", "girl", "blonde", "person"], char: "\u{1F471}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, blonde_man: { keywords: ["man", "male", "boy", "blonde", "guy", "person"], char: "\u{1F471}", fitzpatrick_scale: true, category: "people" }, bearded_person: { keywords: ["person", "bewhiskered"], char: "\u{1F9D4}", fitzpatrick_scale: true, category: "people" }, older_adult: { keywords: ["human", "elder", "senior", "gender-neutral"], char: "\u{1F9D3}", fitzpatrick_scale: true, category: "people" }, older_man: { keywords: ["human", "male", "men", "old", "elder", "senior"], char: "\u{1F474}", fitzpatrick_scale: true, category: "people" }, older_woman: { keywords: ["human", "female", "women", "lady", "old", "elder", "senior"], char: "\u{1F475}", fitzpatrick_scale: true, category: "people" }, man_with_gua_pi_mao: { keywords: ["male", "boy", "chinese"], char: "\u{1F472}", fitzpatrick_scale: true, category: "people" }, woman_with_headscarf: { keywords: ["female", "hijab", "mantilla", "tichel"], char: "\u{1F9D5}", fitzpatrick_scale: true, category: "people" }, woman_with_turban: { keywords: ["female", "indian", "hinduism", "arabs", "woman"], char: "\u{1F473}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_with_turban: { keywords: ["male", "indian", "hinduism", "arabs"], char: "\u{1F473}", fitzpatrick_scale: true, category: "people" }, policewoman: { keywords: ["woman", "police", "law", "legal", "enforcement", "arrest", "911", "female"], char: "\u{1F46E}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, policeman: { keywords: ["man", "police", "law", "legal", "enforcement", "arrest", "911"], char: "\u{1F46E}", fitzpatrick_scale: true, category: "people" }, construction_worker_woman: { keywords: ["female", "human", "wip", "build", "construction", "worker", "labor", "woman"], char: "\u{1F477}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, construction_worker_man: { keywords: ["male", "human", "wip", "guy", "build", "construction", "worker", "labor"], char: "\u{1F477}", fitzpatrick_scale: true, category: "people" }, guardswoman: { keywords: ["uk", "gb", "british", "female", "royal", "woman"], char: "\u{1F482}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, guardsman: { keywords: ["uk", "gb", "british", "male", "guy", "royal"], char: "\u{1F482}", fitzpatrick_scale: true, category: "people" }, female_detective: { keywords: ["human", "spy", "detective", "female", "woman"], char: "\u{1F575}\uFE0F\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, male_detective: { keywords: ["human", "spy", "detective"], char: "\u{1F575}", fitzpatrick_scale: true, category: "people" }, woman_health_worker: { keywords: ["doctor", "nurse", "therapist", "healthcare", "woman", "human"], char: "\u{1F469}\u200D\u2695\uFE0F", fitzpatrick_scale: true, category: "people" }, man_health_worker: { keywords: ["doctor", "nurse", "therapist", "healthcare", "man", "human"], char: "\u{1F468}\u200D\u2695\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_farmer: { keywords: ["rancher", "gardener", "woman", "human"], char: "\u{1F469}\u200D\u{1F33E}", fitzpatrick_scale: true, category: "people" }, man_farmer: { keywords: ["rancher", "gardener", "man", "human"], char: "\u{1F468}\u200D\u{1F33E}", fitzpatrick_scale: true, category: "people" }, woman_cook: { keywords: ["chef", "woman", "human"], char: "\u{1F469}\u200D\u{1F373}", fitzpatrick_scale: true, category: "people" }, man_cook: { keywords: ["chef", "man", "human"], char: "\u{1F468}\u200D\u{1F373}", fitzpatrick_scale: true, category: "people" }, woman_student: { keywords: ["graduate", "woman", "human"], char: "\u{1F469}\u200D\u{1F393}", fitzpatrick_scale: true, category: "people" }, man_student: { keywords: ["graduate", "man", "human"], char: "\u{1F468}\u200D\u{1F393}", fitzpatrick_scale: true, category: "people" }, woman_singer: { keywords: ["rockstar", "entertainer", "woman", "human"], char: "\u{1F469}\u200D\u{1F3A4}", fitzpatrick_scale: true, category: "people" }, man_singer: { keywords: ["rockstar", "entertainer", "man", "human"], char: "\u{1F468}\u200D\u{1F3A4}", fitzpatrick_scale: true, category: "people" }, woman_teacher: { keywords: ["instructor", "professor", "woman", "human"], char: "\u{1F469}\u200D\u{1F3EB}", fitzpatrick_scale: true, category: "people" }, man_teacher: { keywords: ["instructor", "professor", "man", "human"], char: "\u{1F468}\u200D\u{1F3EB}", fitzpatrick_scale: true, category: "people" }, woman_factory_worker: { keywords: ["assembly", "industrial", "woman", "human"], char: "\u{1F469}\u200D\u{1F3ED}", fitzpatrick_scale: true, category: "people" }, man_factory_worker: { keywords: ["assembly", "industrial", "man", "human"], char: "\u{1F468}\u200D\u{1F3ED}", fitzpatrick_scale: true, category: "people" }, woman_technologist: { keywords: ["coder", "developer", "engineer", "programmer", "software", "woman", "human", "laptop", "computer"], char: "\u{1F469}\u200D\u{1F4BB}", fitzpatrick_scale: true, category: "people" }, man_technologist: { keywords: ["coder", "developer", "engineer", "programmer", "software", "man", "human", "laptop", "computer"], char: "\u{1F468}\u200D\u{1F4BB}", fitzpatrick_scale: true, category: "people" }, woman_office_worker: { keywords: ["business", "manager", "woman", "human"], char: "\u{1F469}\u200D\u{1F4BC}", fitzpatrick_scale: true, category: "people" }, man_office_worker: { keywords: ["business", "manager", "man", "human"], char: "\u{1F468}\u200D\u{1F4BC}", fitzpatrick_scale: true, category: "people" }, woman_mechanic: { keywords: ["plumber", "woman", "human", "wrench"], char: "\u{1F469}\u200D\u{1F527}", fitzpatrick_scale: true, category: "people" }, man_mechanic: { keywords: ["plumber", "man", "human", "wrench"], char: "\u{1F468}\u200D\u{1F527}", fitzpatrick_scale: true, category: "people" }, woman_scientist: { keywords: ["biologist", "chemist", "engineer", "physicist", "woman", "human"], char: "\u{1F469}\u200D\u{1F52C}", fitzpatrick_scale: true, category: "people" }, man_scientist: { keywords: ["biologist", "chemist", "engineer", "physicist", "man", "human"], char: "\u{1F468}\u200D\u{1F52C}", fitzpatrick_scale: true, category: "people" }, woman_artist: { keywords: ["painter", "woman", "human"], char: "\u{1F469}\u200D\u{1F3A8}", fitzpatrick_scale: true, category: "people" }, man_artist: { keywords: ["painter", "man", "human"], char: "\u{1F468}\u200D\u{1F3A8}", fitzpatrick_scale: true, category: "people" }, woman_firefighter: { keywords: ["fireman", "woman", "human"], char: "\u{1F469}\u200D\u{1F692}", fitzpatrick_scale: true, category: "people" }, man_firefighter: { keywords: ["fireman", "man", "human"], char: "\u{1F468}\u200D\u{1F692}", fitzpatrick_scale: true, category: "people" }, woman_pilot: { keywords: ["aviator", "plane", "woman", "human"], char: "\u{1F469}\u200D\u2708\uFE0F", fitzpatrick_scale: true, category: "people" }, man_pilot: { keywords: ["aviator", "plane", "man", "human"], char: "\u{1F468}\u200D\u2708\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_astronaut: { keywords: ["space", "rocket", "woman", "human"], char: "\u{1F469}\u200D\u{1F680}", fitzpatrick_scale: true, category: "people" }, man_astronaut: { keywords: ["space", "rocket", "man", "human"], char: "\u{1F468}\u200D\u{1F680}", fitzpatrick_scale: true, category: "people" }, woman_judge: { keywords: ["justice", "court", "woman", "human"], char: "\u{1F469}\u200D\u2696\uFE0F", fitzpatrick_scale: true, category: "people" }, man_judge: { keywords: ["justice", "court", "man", "human"], char: "\u{1F468}\u200D\u2696\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_superhero: { keywords: ["woman", "female", "good", "heroine", "superpowers"], char: "\u{1F9B8}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_superhero: { keywords: ["man", "male", "good", "hero", "superpowers"], char: "\u{1F9B8}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_supervillain: { keywords: ["woman", "female", "evil", "bad", "criminal", "heroine", "superpowers"], char: "\u{1F9B9}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_supervillain: { keywords: ["man", "male", "evil", "bad", "criminal", "hero", "superpowers"], char: "\u{1F9B9}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, mrs_claus: { keywords: ["woman", "female", "xmas", "mother christmas"], char: "\u{1F936}", fitzpatrick_scale: true, category: "people" }, santa: { keywords: ["festival", "man", "male", "xmas", "father christmas"], char: "\u{1F385}", fitzpatrick_scale: true, category: "people" }, sorceress: { keywords: ["woman", "female", "mage", "witch"], char: "\u{1F9D9}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, wizard: { keywords: ["man", "male", "mage", "sorcerer"], char: "\u{1F9D9}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_elf: { keywords: ["woman", "female"], char: "\u{1F9DD}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_elf: { keywords: ["man", "male"], char: "\u{1F9DD}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_vampire: { keywords: ["woman", "female"], char: "\u{1F9DB}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_vampire: { keywords: ["man", "male", "dracula"], char: "\u{1F9DB}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_zombie: { keywords: ["woman", "female", "undead", "walking dead"], char: "\u{1F9DF}\u200D\u2640\uFE0F", fitzpatrick_scale: false, category: "people" }, man_zombie: { keywords: ["man", "male", "dracula", "undead", "walking dead"], char: "\u{1F9DF}\u200D\u2642\uFE0F", fitzpatrick_scale: false, category: "people" }, woman_genie: { keywords: ["woman", "female"], char: "\u{1F9DE}\u200D\u2640\uFE0F", fitzpatrick_scale: false, category: "people" }, man_genie: { keywords: ["man", "male"], char: "\u{1F9DE}\u200D\u2642\uFE0F", fitzpatrick_scale: false, category: "people" }, mermaid: { keywords: ["woman", "female", "merwoman", "ariel"], char: "\u{1F9DC}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, merman: { keywords: ["man", "male", "triton"], char: "\u{1F9DC}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_fairy: { keywords: ["woman", "female"], char: "\u{1F9DA}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_fairy: { keywords: ["man", "male"], char: "\u{1F9DA}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, angel: { keywords: ["heaven", "wings", "halo"], char: "\u{1F47C}", fitzpatrick_scale: true, category: "people" }, pregnant_woman: { keywords: ["baby"], char: "\u{1F930}", fitzpatrick_scale: true, category: "people" }, breastfeeding: { keywords: ["nursing", "baby"], char: "\u{1F931}", fitzpatrick_scale: true, category: "people" }, princess: { keywords: ["girl", "woman", "female", "blond", "crown", "royal", "queen"], char: "\u{1F478}", fitzpatrick_scale: true, category: "people" }, prince: { keywords: ["boy", "man", "male", "crown", "royal", "king"], char: "\u{1F934}", fitzpatrick_scale: true, category: "people" }, bride_with_veil: { keywords: ["couple", "marriage", "wedding", "woman", "bride"], char: "\u{1F470}", fitzpatrick_scale: true, category: "people" }, man_in_tuxedo: { keywords: ["couple", "marriage", "wedding", "groom"], char: "\u{1F935}", fitzpatrick_scale: true, category: "people" }, running_woman: { keywords: ["woman", "walking", "exercise", "race", "running", "female"], char: "\u{1F3C3}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, running_man: { keywords: ["man", "walking", "exercise", "race", "running"], char: "\u{1F3C3}", fitzpatrick_scale: true, category: "people" }, walking_woman: { keywords: ["human", "feet", "steps", "woman", "female"], char: "\u{1F6B6}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, walking_man: { keywords: ["human", "feet", "steps"], char: "\u{1F6B6}", fitzpatrick_scale: true, category: "people" }, dancer: { keywords: ["female", "girl", "woman", "fun"], char: "\u{1F483}", fitzpatrick_scale: true, category: "people" }, man_dancing: { keywords: ["male", "boy", "fun", "dancer"], char: "\u{1F57A}", fitzpatrick_scale: true, category: "people" }, dancing_women: { keywords: ["female", "bunny", "women", "girls"], char: "\u{1F46F}", fitzpatrick_scale: false, category: "people" }, dancing_men: { keywords: ["male", "bunny", "men", "boys"], char: "\u{1F46F}\u200D\u2642\uFE0F", fitzpatrick_scale: false, category: "people" }, couple: { keywords: ["pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage"], char: "\u{1F46B}", fitzpatrick_scale: false, category: "people" }, two_men_holding_hands: { keywords: ["pair", "couple", "love", "like", "bromance", "friendship", "people", "human"], char: "\u{1F46C}", fitzpatrick_scale: false, category: "people" }, two_women_holding_hands: { keywords: ["pair", "friendship", "couple", "love", "like", "female", "people", "human"], char: "\u{1F46D}", fitzpatrick_scale: false, category: "people" }, bowing_woman: { keywords: ["woman", "female", "girl"], char: "\u{1F647}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, bowing_man: { keywords: ["man", "male", "boy"], char: "\u{1F647}", fitzpatrick_scale: true, category: "people" }, man_facepalming: { keywords: ["man", "male", "boy", "disbelief"], char: "\u{1F926}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_facepalming: { keywords: ["woman", "female", "girl", "disbelief"], char: "\u{1F926}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_shrugging: { keywords: ["woman", "female", "girl", "confused", "indifferent", "doubt"], char: "\u{1F937}", fitzpatrick_scale: true, category: "people" }, man_shrugging: { keywords: ["man", "male", "boy", "confused", "indifferent", "doubt"], char: "\u{1F937}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, tipping_hand_woman: { keywords: ["female", "girl", "woman", "human", "information"], char: "\u{1F481}", fitzpatrick_scale: true, category: "people" }, tipping_hand_man: { keywords: ["male", "boy", "man", "human", "information"], char: "\u{1F481}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, no_good_woman: { keywords: ["female", "girl", "woman", "nope"], char: "\u{1F645}", fitzpatrick_scale: true, category: "people" }, no_good_man: { keywords: ["male", "boy", "man", "nope"], char: "\u{1F645}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, ok_woman: { keywords: ["women", "girl", "female", "pink", "human", "woman"], char: "\u{1F646}", fitzpatrick_scale: true, category: "people" }, ok_man: { keywords: ["men", "boy", "male", "blue", "human", "man"], char: "\u{1F646}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, raising_hand_woman: { keywords: ["female", "girl", "woman"], char: "\u{1F64B}", fitzpatrick_scale: true, category: "people" }, raising_hand_man: { keywords: ["male", "boy", "man"], char: "\u{1F64B}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, pouting_woman: { keywords: ["female", "girl", "woman"], char: "\u{1F64E}", fitzpatrick_scale: true, category: "people" }, pouting_man: { keywords: ["male", "boy", "man"], char: "\u{1F64E}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, frowning_woman: { keywords: ["female", "girl", "woman", "sad", "depressed", "discouraged", "unhappy"], char: "\u{1F64D}", fitzpatrick_scale: true, category: "people" }, frowning_man: { keywords: ["male", "boy", "man", "sad", "depressed", "discouraged", "unhappy"], char: "\u{1F64D}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, haircut_woman: { keywords: ["female", "girl", "woman"], char: "\u{1F487}", fitzpatrick_scale: true, category: "people" }, haircut_man: { keywords: ["male", "boy", "man"], char: "\u{1F487}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, massage_woman: { keywords: ["female", "girl", "woman", "head"], char: "\u{1F486}", fitzpatrick_scale: true, category: "people" }, massage_man: { keywords: ["male", "boy", "man", "head"], char: "\u{1F486}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, woman_in_steamy_room: { keywords: ["female", "woman", "spa", "steamroom", "sauna"], char: "\u{1F9D6}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "people" }, man_in_steamy_room: { keywords: ["male", "man", "spa", "steamroom", "sauna"], char: "\u{1F9D6}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "people" }, couple_with_heart_woman_man: { keywords: ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], char: "\u{1F491}", fitzpatrick_scale: false, category: "people" }, couple_with_heart_woman_woman: { keywords: ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], char: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F469}", fitzpatrick_scale: false, category: "people" }, couple_with_heart_man_man: { keywords: ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], char: "\u{1F468}\u200D\u2764\uFE0F\u200D\u{1F468}", fitzpatrick_scale: false, category: "people" }, couplekiss_man_woman: { keywords: ["pair", "valentines", "love", "like", "dating", "marriage"], char: "\u{1F48F}", fitzpatrick_scale: false, category: "people" }, couplekiss_woman_woman: { keywords: ["pair", "valentines", "love", "like", "dating", "marriage"], char: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}", fitzpatrick_scale: false, category: "people" }, couplekiss_man_man: { keywords: ["pair", "valentines", "love", "like", "dating", "marriage"], char: "\u{1F468}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}", fitzpatrick_scale: false, category: "people" }, family_man_woman_boy: { keywords: ["home", "parents", "child", "mom", "dad", "father", "mother", "people", "human"], char: "\u{1F46A}", fitzpatrick_scale: false, category: "people" }, family_man_woman_girl: { keywords: ["home", "parents", "people", "human", "child"], char: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_man_woman_girl_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_woman_boy_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F469}\u200D\u{1F466}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_woman_girl_girl: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_woman_woman_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F469}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_woman_girl: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_woman_woman_girl_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_woman_boy_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F469}\u200D\u{1F466}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_woman_girl_girl: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_man_man_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F468}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_man_girl: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_man_man_girl_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_man_boy_boy: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F468}\u200D\u{1F466}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_man_girl_girl: { keywords: ["home", "parents", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_woman_boy: { keywords: ["home", "parent", "people", "human", "child"], char: "\u{1F469}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_girl: { keywords: ["home", "parent", "people", "human", "child"], char: "\u{1F469}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_woman_girl_boy: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F467}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_boy_boy: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F466}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_woman_girl_girl: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F469}\u200D\u{1F467}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_man_boy: { keywords: ["home", "parent", "people", "human", "child"], char: "\u{1F468}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_girl: { keywords: ["home", "parent", "people", "human", "child"], char: "\u{1F468}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, family_man_girl_boy: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F467}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_boy_boy: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F466}\u200D\u{1F466}", fitzpatrick_scale: false, category: "people" }, family_man_girl_girl: { keywords: ["home", "parent", "people", "human", "children"], char: "\u{1F468}\u200D\u{1F467}\u200D\u{1F467}", fitzpatrick_scale: false, category: "people" }, yarn: { keywords: ["ball", "crochet", "knit"], char: "\u{1F9F6}", fitzpatrick_scale: false, category: "people" }, thread: { keywords: ["needle", "sewing", "spool", "string"], char: "\u{1F9F5}", fitzpatrick_scale: false, category: "people" }, coat: { keywords: ["jacket"], char: "\u{1F9E5}", fitzpatrick_scale: false, category: "people" }, labcoat: { keywords: ["doctor", "experiment", "scientist", "chemist"], char: "\u{1F97C}", fitzpatrick_scale: false, category: "people" }, womans_clothes: { keywords: ["fashion", "shopping_bags", "female"], char: "\u{1F45A}", fitzpatrick_scale: false, category: "people" }, tshirt: { keywords: ["fashion", "cloth", "casual", "shirt", "tee"], char: "\u{1F455}", fitzpatrick_scale: false, category: "people" }, jeans: { keywords: ["fashion", "shopping"], char: "\u{1F456}", fitzpatrick_scale: false, category: "people" }, necktie: { keywords: ["shirt", "suitup", "formal", "fashion", "cloth", "business"], char: "\u{1F454}", fitzpatrick_scale: false, category: "people" }, dress: { keywords: ["clothes", "fashion", "shopping"], char: "\u{1F457}", fitzpatrick_scale: false, category: "people" }, bikini: { keywords: ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"], char: "\u{1F459}", fitzpatrick_scale: false, category: "people" }, kimono: { keywords: ["dress", "fashion", "women", "female", "japanese"], char: "\u{1F458}", fitzpatrick_scale: false, category: "people" }, lipstick: { keywords: ["female", "girl", "fashion", "woman"], char: "\u{1F484}", fitzpatrick_scale: false, category: "people" }, kiss: { keywords: ["face", "lips", "love", "like", "affection", "valentines"], char: "\u{1F48B}", fitzpatrick_scale: false, category: "people" }, footprints: { keywords: ["feet", "tracking", "walking", "beach"], char: "\u{1F463}", fitzpatrick_scale: false, category: "people" }, flat_shoe: { keywords: ["ballet", "slip-on", "slipper"], char: "\u{1F97F}", fitzpatrick_scale: false, category: "people" }, high_heel: { keywords: ["fashion", "shoes", "female", "pumps", "stiletto"], char: "\u{1F460}", fitzpatrick_scale: false, category: "people" }, sandal: { keywords: ["shoes", "fashion", "flip flops"], char: "\u{1F461}", fitzpatrick_scale: false, category: "people" }, boot: { keywords: ["shoes", "fashion"], char: "\u{1F462}", fitzpatrick_scale: false, category: "people" }, mans_shoe: { keywords: ["fashion", "male"], char: "\u{1F45E}", fitzpatrick_scale: false, category: "people" }, athletic_shoe: { keywords: ["shoes", "sports", "sneakers"], char: "\u{1F45F}", fitzpatrick_scale: false, category: "people" }, hiking_boot: { keywords: ["backpacking", "camping", "hiking"], char: "\u{1F97E}", fitzpatrick_scale: false, category: "people" }, socks: { keywords: ["stockings", "clothes"], char: "\u{1F9E6}", fitzpatrick_scale: false, category: "people" }, gloves: { keywords: ["hands", "winter", "clothes"], char: "\u{1F9E4}", fitzpatrick_scale: false, category: "people" }, scarf: { keywords: ["neck", "winter", "clothes"], char: "\u{1F9E3}", fitzpatrick_scale: false, category: "people" }, womans_hat: { keywords: ["fashion", "accessories", "female", "lady", "spring"], char: "\u{1F452}", fitzpatrick_scale: false, category: "people" }, tophat: { keywords: ["magic", "gentleman", "classy", "circus"], char: "\u{1F3A9}", fitzpatrick_scale: false, category: "people" }, billed_hat: { keywords: ["cap", "baseball"], char: "\u{1F9E2}", fitzpatrick_scale: false, category: "people" }, rescue_worker_helmet: { keywords: ["construction", "build"], char: "\u26D1", fitzpatrick_scale: false, category: "people" }, mortar_board: { keywords: ["school", "college", "degree", "university", "graduation", "cap", "hat", "legal", "learn", "education"], char: "\u{1F393}", fitzpatrick_scale: false, category: "people" }, crown: { keywords: ["king", "kod", "leader", "royalty", "lord"], char: "\u{1F451}", fitzpatrick_scale: false, category: "people" }, school_satchel: { keywords: ["student", "education", "bag", "backpack"], char: "\u{1F392}", fitzpatrick_scale: false, category: "people" }, luggage: { keywords: ["packing", "travel"], char: "\u{1F9F3}", fitzpatrick_scale: false, category: "people" }, pouch: { keywords: ["bag", "accessories", "shopping"], char: "\u{1F45D}", fitzpatrick_scale: false, category: "people" }, purse: { keywords: ["fashion", "accessories", "money", "sales", "shopping"], char: "\u{1F45B}", fitzpatrick_scale: false, category: "people" }, handbag: { keywords: ["fashion", "accessory", "accessories", "shopping"], char: "\u{1F45C}", fitzpatrick_scale: false, category: "people" }, briefcase: { keywords: ["business", "documents", "work", "law", "legal", "job", "career"], char: "\u{1F4BC}", fitzpatrick_scale: false, category: "people" }, eyeglasses: { keywords: ["fashion", "accessories", "eyesight", "nerdy", "dork", "geek"], char: "\u{1F453}", fitzpatrick_scale: false, category: "people" }, dark_sunglasses: { keywords: ["face", "cool", "accessories"], char: "\u{1F576}", fitzpatrick_scale: false, category: "people" }, goggles: { keywords: ["eyes", "protection", "safety"], char: "\u{1F97D}", fitzpatrick_scale: false, category: "people" }, ring: { keywords: ["wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement"], char: "\u{1F48D}", fitzpatrick_scale: false, category: "people" }, closed_umbrella: { keywords: ["weather", "rain", "drizzle"], char: "\u{1F302}", fitzpatrick_scale: false, category: "people" }, dog: { keywords: ["animal", "friend", "nature", "woof", "puppy", "pet", "faithful"], char: "\u{1F436}", fitzpatrick_scale: false, category: "animals_and_nature" }, cat: { keywords: ["animal", "meow", "nature", "pet", "kitten"], char: "\u{1F431}", fitzpatrick_scale: false, category: "animals_and_nature" }, mouse: { keywords: ["animal", "nature", "cheese_wedge", "rodent"], char: "\u{1F42D}", fitzpatrick_scale: false, category: "animals_and_nature" }, hamster: { keywords: ["animal", "nature"], char: "\u{1F439}", fitzpatrick_scale: false, category: "animals_and_nature" }, rabbit: { keywords: ["animal", "nature", "pet", "spring", "magic", "bunny"], char: "\u{1F430}", fitzpatrick_scale: false, category: "animals_and_nature" }, fox_face: { keywords: ["animal", "nature", "face"], char: "\u{1F98A}", fitzpatrick_scale: false, category: "animals_and_nature" }, bear: { keywords: ["animal", "nature", "wild"], char: "\u{1F43B}", fitzpatrick_scale: false, category: "animals_and_nature" }, panda_face: { keywords: ["animal", "nature", "panda"], char: "\u{1F43C}", fitzpatrick_scale: false, category: "animals_and_nature" }, koala: { keywords: ["animal", "nature"], char: "\u{1F428}", fitzpatrick_scale: false, category: "animals_and_nature" }, tiger: { keywords: ["animal", "cat", "danger", "wild", "nature", "roar"], char: "\u{1F42F}", fitzpatrick_scale: false, category: "animals_and_nature" }, lion: { keywords: ["animal", "nature"], char: "\u{1F981}", fitzpatrick_scale: false, category: "animals_and_nature" }, cow: { keywords: ["beef", "ox", "animal", "nature", "moo", "milk"], char: "\u{1F42E}", fitzpatrick_scale: false, category: "animals_and_nature" }, pig: { keywords: ["animal", "oink", "nature"], char: "\u{1F437}", fitzpatrick_scale: false, category: "animals_and_nature" }, pig_nose: { keywords: ["animal", "oink"], char: "\u{1F43D}", fitzpatrick_scale: false, category: "animals_and_nature" }, frog: { keywords: ["animal", "nature", "croak", "toad"], char: "\u{1F438}", fitzpatrick_scale: false, category: "animals_and_nature" }, squid: { keywords: ["animal", "nature", "ocean", "sea"], char: "\u{1F991}", fitzpatrick_scale: false, category: "animals_and_nature" }, octopus: { keywords: ["animal", "creature", "ocean", "sea", "nature", "beach"], char: "\u{1F419}", fitzpatrick_scale: false, category: "animals_and_nature" }, shrimp: { keywords: ["animal", "ocean", "nature", "seafood"], char: "\u{1F990}", fitzpatrick_scale: false, category: "animals_and_nature" }, monkey_face: { keywords: ["animal", "nature", "circus"], char: "\u{1F435}", fitzpatrick_scale: false, category: "animals_and_nature" }, gorilla: { keywords: ["animal", "nature", "circus"], char: "\u{1F98D}", fitzpatrick_scale: false, category: "animals_and_nature" }, see_no_evil: { keywords: ["monkey", "animal", "nature", "haha"], char: "\u{1F648}", fitzpatrick_scale: false, category: "animals_and_nature" }, hear_no_evil: { keywords: ["animal", "monkey", "nature"], char: "\u{1F649}", fitzpatrick_scale: false, category: "animals_and_nature" }, speak_no_evil: { keywords: ["monkey", "animal", "nature", "omg"], char: "\u{1F64A}", fitzpatrick_scale: false, category: "animals_and_nature" }, monkey: { keywords: ["animal", "nature", "banana", "circus"], char: "\u{1F412}", fitzpatrick_scale: false, category: "animals_and_nature" }, chicken: { keywords: ["animal", "cluck", "nature", "bird"], char: "\u{1F414}", fitzpatrick_scale: false, category: "animals_and_nature" }, penguin: { keywords: ["animal", "nature"], char: "\u{1F427}", fitzpatrick_scale: false, category: "animals_and_nature" }, bird: { keywords: ["animal", "nature", "fly", "tweet", "spring"], char: "\u{1F426}", fitzpatrick_scale: false, category: "animals_and_nature" }, baby_chick: { keywords: ["animal", "chicken", "bird"], char: "\u{1F424}", fitzpatrick_scale: false, category: "animals_and_nature" }, hatching_chick: { keywords: ["animal", "chicken", "egg", "born", "baby", "bird"], char: "\u{1F423}", fitzpatrick_scale: false, category: "animals_and_nature" }, hatched_chick: { keywords: ["animal", "chicken", "baby", "bird"], char: "\u{1F425}", fitzpatrick_scale: false, category: "animals_and_nature" }, duck: { keywords: ["animal", "nature", "bird", "mallard"], char: "\u{1F986}", fitzpatrick_scale: false, category: "animals_and_nature" }, eagle: { keywords: ["animal", "nature", "bird"], char: "\u{1F985}", fitzpatrick_scale: false, category: "animals_and_nature" }, owl: { keywords: ["animal", "nature", "bird", "hoot"], char: "\u{1F989}", fitzpatrick_scale: false, category: "animals_and_nature" }, bat: { keywords: ["animal", "nature", "blind", "vampire"], char: "\u{1F987}", fitzpatrick_scale: false, category: "animals_and_nature" }, wolf: { keywords: ["animal", "nature", "wild"], char: "\u{1F43A}", fitzpatrick_scale: false, category: "animals_and_nature" }, boar: { keywords: ["animal", "nature"], char: "\u{1F417}", fitzpatrick_scale: false, category: "animals_and_nature" }, horse: { keywords: ["animal", "brown", "nature"], char: "\u{1F434}", fitzpatrick_scale: false, category: "animals_and_nature" }, unicorn: { keywords: ["animal", "nature", "mystical"], char: "\u{1F984}", fitzpatrick_scale: false, category: "animals_and_nature" }, honeybee: { keywords: ["animal", "insect", "nature", "bug", "spring", "honey"], char: "\u{1F41D}", fitzpatrick_scale: false, category: "animals_and_nature" }, bug: { keywords: ["animal", "insect", "nature", "worm"], char: "\u{1F41B}", fitzpatrick_scale: false, category: "animals_and_nature" }, butterfly: { keywords: ["animal", "insect", "nature", "caterpillar"], char: "\u{1F98B}", fitzpatrick_scale: false, category: "animals_and_nature" }, snail: { keywords: ["slow", "animal", "shell"], char: "\u{1F40C}", fitzpatrick_scale: false, category: "animals_and_nature" }, beetle: { keywords: ["animal", "insect", "nature", "ladybug"], char: "\u{1F41E}", fitzpatrick_scale: false, category: "animals_and_nature" }, ant: { keywords: ["animal", "insect", "nature", "bug"], char: "\u{1F41C}", fitzpatrick_scale: false, category: "animals_and_nature" }, grasshopper: { keywords: ["animal", "cricket", "chirp"], char: "\u{1F997}", fitzpatrick_scale: false, category: "animals_and_nature" }, spider: { keywords: ["animal", "arachnid"], char: "\u{1F577}", fitzpatrick_scale: false, category: "animals_and_nature" }, scorpion: { keywords: ["animal", "arachnid"], char: "\u{1F982}", fitzpatrick_scale: false, category: "animals_and_nature" }, crab: { keywords: ["animal", "crustacean"], char: "\u{1F980}", fitzpatrick_scale: false, category: "animals_and_nature" }, snake: { keywords: ["animal", "evil", "nature", "hiss", "python"], char: "\u{1F40D}", fitzpatrick_scale: false, category: "animals_and_nature" }, lizard: { keywords: ["animal", "nature", "reptile"], char: "\u{1F98E}", fitzpatrick_scale: false, category: "animals_and_nature" }, "t-rex": { keywords: ["animal", "nature", "dinosaur", "tyrannosaurus", "extinct"], char: "\u{1F996}", fitzpatrick_scale: false, category: "animals_and_nature" }, sauropod: { keywords: ["animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct"], char: "\u{1F995}", fitzpatrick_scale: false, category: "animals_and_nature" }, turtle: { keywords: ["animal", "slow", "nature", "tortoise"], char: "\u{1F422}", fitzpatrick_scale: false, category: "animals_and_nature" }, tropical_fish: { keywords: ["animal", "swim", "ocean", "beach", "nemo"], char: "\u{1F420}", fitzpatrick_scale: false, category: "animals_and_nature" }, fish: { keywords: ["animal", "food", "nature"], char: "\u{1F41F}", fitzpatrick_scale: false, category: "animals_and_nature" }, blowfish: { keywords: ["animal", "nature", "food", "sea", "ocean"], char: "\u{1F421}", fitzpatrick_scale: false, category: "animals_and_nature" }, dolphin: { keywords: ["animal", "nature", "fish", "sea", "ocean", "flipper", "fins", "beach"], char: "\u{1F42C}", fitzpatrick_scale: false, category: "animals_and_nature" }, shark: { keywords: ["animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach"], char: "\u{1F988}", fitzpatrick_scale: false, category: "animals_and_nature" }, whale: { keywords: ["animal", "nature", "sea", "ocean"], char: "\u{1F433}", fitzpatrick_scale: false, category: "animals_and_nature" }, whale2: { keywords: ["animal", "nature", "sea", "ocean"], char: "\u{1F40B}", fitzpatrick_scale: false, category: "animals_and_nature" }, crocodile: { keywords: ["animal", "nature", "reptile", "lizard", "alligator"], char: "\u{1F40A}", fitzpatrick_scale: false, category: "animals_and_nature" }, leopard: { keywords: ["animal", "nature"], char: "\u{1F406}", fitzpatrick_scale: false, category: "animals_and_nature" }, zebra: { keywords: ["animal", "nature", "stripes", "safari"], char: "\u{1F993}", fitzpatrick_scale: false, category: "animals_and_nature" }, tiger2: { keywords: ["animal", "nature", "roar"], char: "\u{1F405}", fitzpatrick_scale: false, category: "animals_and_nature" }, water_buffalo: { keywords: ["animal", "nature", "ox", "cow"], char: "\u{1F403}", fitzpatrick_scale: false, category: "animals_and_nature" }, ox: { keywords: ["animal", "cow", "beef"], char: "\u{1F402}", fitzpatrick_scale: false, category: "animals_and_nature" }, cow2: { keywords: ["beef", "ox", "animal", "nature", "moo", "milk"], char: "\u{1F404}", fitzpatrick_scale: false, category: "animals_and_nature" }, deer: { keywords: ["animal", "nature", "horns", "venison"], char: "\u{1F98C}", fitzpatrick_scale: false, category: "animals_and_nature" }, dromedary_camel: { keywords: ["animal", "hot", "desert", "hump"], char: "\u{1F42A}", fitzpatrick_scale: false, category: "animals_and_nature" }, camel: { keywords: ["animal", "nature", "hot", "desert", "hump"], char: "\u{1F42B}", fitzpatrick_scale: false, category: "animals_and_nature" }, giraffe: { keywords: ["animal", "nature", "spots", "safari"], char: "\u{1F992}", fitzpatrick_scale: false, category: "animals_and_nature" }, elephant: { keywords: ["animal", "nature", "nose", "th", "circus"], char: "\u{1F418}", fitzpatrick_scale: false, category: "animals_and_nature" }, rhinoceros: { keywords: ["animal", "nature", "horn"], char: "\u{1F98F}", fitzpatrick_scale: false, category: "animals_and_nature" }, goat: { keywords: ["animal", "nature"], char: "\u{1F410}", fitzpatrick_scale: false, category: "animals_and_nature" }, ram: { keywords: ["animal", "sheep", "nature"], char: "\u{1F40F}", fitzpatrick_scale: false, category: "animals_and_nature" }, sheep: { keywords: ["animal", "nature", "wool", "shipit"], char: "\u{1F411}", fitzpatrick_scale: false, category: "animals_and_nature" }, racehorse: { keywords: ["animal", "gamble", "luck"], char: "\u{1F40E}", fitzpatrick_scale: false, category: "animals_and_nature" }, pig2: { keywords: ["animal", "nature"], char: "\u{1F416}", fitzpatrick_scale: false, category: "animals_and_nature" }, rat: { keywords: ["animal", "mouse", "rodent"], char: "\u{1F400}", fitzpatrick_scale: false, category: "animals_and_nature" }, mouse2: { keywords: ["animal", "nature", "rodent"], char: "\u{1F401}", fitzpatrick_scale: false, category: "animals_and_nature" }, rooster: { keywords: ["animal", "nature", "chicken"], char: "\u{1F413}", fitzpatrick_scale: false, category: "animals_and_nature" }, turkey: { keywords: ["animal", "bird"], char: "\u{1F983}", fitzpatrick_scale: false, category: "animals_and_nature" }, dove: { keywords: ["animal", "bird"], char: "\u{1F54A}", fitzpatrick_scale: false, category: "animals_and_nature" }, dog2: { keywords: ["animal", "nature", "friend", "doge", "pet", "faithful"], char: "\u{1F415}", fitzpatrick_scale: false, category: "animals_and_nature" }, poodle: { keywords: ["dog", "animal", "101", "nature", "pet"], char: "\u{1F429}", fitzpatrick_scale: false, category: "animals_and_nature" }, cat2: { keywords: ["animal", "meow", "pet", "cats"], char: "\u{1F408}", fitzpatrick_scale: false, category: "animals_and_nature" }, rabbit2: { keywords: ["animal", "nature", "pet", "magic", "spring"], char: "\u{1F407}", fitzpatrick_scale: false, category: "animals_and_nature" }, chipmunk: { keywords: ["animal", "nature", "rodent", "squirrel"], char: "\u{1F43F}", fitzpatrick_scale: false, category: "animals_and_nature" }, hedgehog: { keywords: ["animal", "nature", "spiny"], char: "\u{1F994}", fitzpatrick_scale: false, category: "animals_and_nature" }, raccoon: { keywords: ["animal", "nature"], char: "\u{1F99D}", fitzpatrick_scale: false, category: "animals_and_nature" }, llama: { keywords: ["animal", "nature", "alpaca"], char: "\u{1F999}", fitzpatrick_scale: false, category: "animals_and_nature" }, hippopotamus: { keywords: ["animal", "nature"], char: "\u{1F99B}", fitzpatrick_scale: false, category: "animals_and_nature" }, kangaroo: { keywords: ["animal", "nature", "australia", "joey", "hop", "marsupial"], char: "\u{1F998}", fitzpatrick_scale: false, category: "animals_and_nature" }, badger: { keywords: ["animal", "nature", "honey"], char: "\u{1F9A1}", fitzpatrick_scale: false, category: "animals_and_nature" }, swan: { keywords: ["animal", "nature", "bird"], char: "\u{1F9A2}", fitzpatrick_scale: false, category: "animals_and_nature" }, peacock: { keywords: ["animal", "nature", "peahen", "bird"], char: "\u{1F99A}", fitzpatrick_scale: false, category: "animals_and_nature" }, parrot: { keywords: ["animal", "nature", "bird", "pirate", "talk"], char: "\u{1F99C}", fitzpatrick_scale: false, category: "animals_and_nature" }, lobster: { keywords: ["animal", "nature", "bisque", "claws", "seafood"], char: "\u{1F99E}", fitzpatrick_scale: false, category: "animals_and_nature" }, mosquito: { keywords: ["animal", "nature", "insect", "malaria"], char: "\u{1F99F}", fitzpatrick_scale: false, category: "animals_and_nature" }, paw_prints: { keywords: ["animal", "tracking", "footprints", "dog", "cat", "pet", "feet"], char: "\u{1F43E}", fitzpatrick_scale: false, category: "animals_and_nature" }, dragon: { keywords: ["animal", "myth", "nature", "chinese", "green"], char: "\u{1F409}", fitzpatrick_scale: false, category: "animals_and_nature" }, dragon_face: { keywords: ["animal", "myth", "nature", "chinese", "green"], char: "\u{1F432}", fitzpatrick_scale: false, category: "animals_and_nature" }, cactus: { keywords: ["vegetable", "plant", "nature"], char: "\u{1F335}", fitzpatrick_scale: false, category: "animals_and_nature" }, christmas_tree: { keywords: ["festival", "vacation", "december", "xmas", "celebration"], char: "\u{1F384}", fitzpatrick_scale: false, category: "animals_and_nature" }, evergreen_tree: { keywords: ["plant", "nature"], char: "\u{1F332}", fitzpatrick_scale: false, category: "animals_and_nature" }, deciduous_tree: { keywords: ["plant", "nature"], char: "\u{1F333}", fitzpatrick_scale: false, category: "animals_and_nature" }, palm_tree: { keywords: ["plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical"], char: "\u{1F334}", fitzpatrick_scale: false, category: "animals_and_nature" }, seedling: { keywords: ["plant", "nature", "grass", "lawn", "spring"], char: "\u{1F331}", fitzpatrick_scale: false, category: "animals_and_nature" }, herb: { keywords: ["vegetable", "plant", "medicine", "weed", "grass", "lawn"], char: "\u{1F33F}", fitzpatrick_scale: false, category: "animals_and_nature" }, shamrock: { keywords: ["vegetable", "plant", "nature", "irish", "clover"], char: "\u2618", fitzpatrick_scale: false, category: "animals_and_nature" }, four_leaf_clover: { keywords: ["vegetable", "plant", "nature", "lucky", "irish"], char: "\u{1F340}", fitzpatrick_scale: false, category: "animals_and_nature" }, bamboo: { keywords: ["plant", "nature", "vegetable", "panda", "pine_decoration"], char: "\u{1F38D}", fitzpatrick_scale: false, category: "animals_and_nature" }, tanabata_tree: { keywords: ["plant", "nature", "branch", "summer"], char: "\u{1F38B}", fitzpatrick_scale: false, category: "animals_and_nature" }, leaves: { keywords: ["nature", "plant", "tree", "vegetable", "grass", "lawn", "spring"], char: "\u{1F343}", fitzpatrick_scale: false, category: "animals_and_nature" }, fallen_leaf: { keywords: ["nature", "plant", "vegetable", "leaves"], char: "\u{1F342}", fitzpatrick_scale: false, category: "animals_and_nature" }, maple_leaf: { keywords: ["nature", "plant", "vegetable", "ca", "fall"], char: "\u{1F341}", fitzpatrick_scale: false, category: "animals_and_nature" }, ear_of_rice: { keywords: ["nature", "plant"], char: "\u{1F33E}", fitzpatrick_scale: false, category: "animals_and_nature" }, hibiscus: { keywords: ["plant", "vegetable", "flowers", "beach"], char: "\u{1F33A}", fitzpatrick_scale: false, category: "animals_and_nature" }, sunflower: { keywords: ["nature", "plant", "fall"], char: "\u{1F33B}", fitzpatrick_scale: false, category: "animals_and_nature" }, rose: { keywords: ["flowers", "valentines", "love", "spring"], char: "\u{1F339}", fitzpatrick_scale: false, category: "animals_and_nature" }, wilted_flower: { keywords: ["plant", "nature", "flower"], char: "\u{1F940}", fitzpatrick_scale: false, category: "animals_and_nature" }, tulip: { keywords: ["flowers", "plant", "nature", "summer", "spring"], char: "\u{1F337}", fitzpatrick_scale: false, category: "animals_and_nature" }, blossom: { keywords: ["nature", "flowers", "yellow"], char: "\u{1F33C}", fitzpatrick_scale: false, category: "animals_and_nature" }, cherry_blossom: { keywords: ["nature", "plant", "spring", "flower"], char: "\u{1F338}", fitzpatrick_scale: false, category: "animals_and_nature" }, bouquet: { keywords: ["flowers", "nature", "spring"], char: "\u{1F490}", fitzpatrick_scale: false, category: "animals_and_nature" }, mushroom: { keywords: ["plant", "vegetable"], char: "\u{1F344}", fitzpatrick_scale: false, category: "animals_and_nature" }, chestnut: { keywords: ["food", "squirrel"], char: "\u{1F330}", fitzpatrick_scale: false, category: "animals_and_nature" }, jack_o_lantern: { keywords: ["halloween", "light", "pumpkin", "creepy", "fall"], char: "\u{1F383}", fitzpatrick_scale: false, category: "animals_and_nature" }, shell: { keywords: ["nature", "sea", "beach"], char: "\u{1F41A}", fitzpatrick_scale: false, category: "animals_and_nature" }, spider_web: { keywords: ["animal", "insect", "arachnid", "silk"], char: "\u{1F578}", fitzpatrick_scale: false, category: "animals_and_nature" }, earth_americas: { keywords: ["globe", "world", "USA", "international"], char: "\u{1F30E}", fitzpatrick_scale: false, category: "animals_and_nature" }, earth_africa: { keywords: ["globe", "world", "international"], char: "\u{1F30D}", fitzpatrick_scale: false, category: "animals_and_nature" }, earth_asia: { keywords: ["globe", "world", "east", "international"], char: "\u{1F30F}", fitzpatrick_scale: false, category: "animals_and_nature" }, full_moon: { keywords: ["nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F315}", fitzpatrick_scale: false, category: "animals_and_nature" }, waning_gibbous_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing_gibbous_moon"], char: "\u{1F316}", fitzpatrick_scale: false, category: "animals_and_nature" }, last_quarter_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F317}", fitzpatrick_scale: false, category: "animals_and_nature" }, waning_crescent_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F318}", fitzpatrick_scale: false, category: "animals_and_nature" }, new_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F311}", fitzpatrick_scale: false, category: "animals_and_nature" }, waxing_crescent_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F312}", fitzpatrick_scale: false, category: "animals_and_nature" }, first_quarter_moon: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F313}", fitzpatrick_scale: false, category: "animals_and_nature" }, waxing_gibbous_moon: { keywords: ["nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep"], char: "\u{1F314}", fitzpatrick_scale: false, category: "animals_and_nature" }, new_moon_with_face: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F31A}", fitzpatrick_scale: false, category: "animals_and_nature" }, full_moon_with_face: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F31D}", fitzpatrick_scale: false, category: "animals_and_nature" }, first_quarter_moon_with_face: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F31B}", fitzpatrick_scale: false, category: "animals_and_nature" }, last_quarter_moon_with_face: { keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], char: "\u{1F31C}", fitzpatrick_scale: false, category: "animals_and_nature" }, sun_with_face: { keywords: ["nature", "morning", "sky"], char: "\u{1F31E}", fitzpatrick_scale: false, category: "animals_and_nature" }, crescent_moon: { keywords: ["night", "sleep", "sky", "evening", "magic"], char: "\u{1F319}", fitzpatrick_scale: false, category: "animals_and_nature" }, star: { keywords: ["night", "yellow"], char: "\u2B50", fitzpatrick_scale: false, category: "animals_and_nature" }, star2: { keywords: ["night", "sparkle", "awesome", "good", "magic"], char: "\u{1F31F}", fitzpatrick_scale: false, category: "animals_and_nature" }, dizzy: { keywords: ["star", "sparkle", "shoot", "magic"], char: "\u{1F4AB}", fitzpatrick_scale: false, category: "animals_and_nature" }, sparkles: { keywords: ["stars", "shine", "shiny", "cool", "awesome", "good", "magic"], char: "\u2728", fitzpatrick_scale: false, category: "animals_and_nature" }, comet: { keywords: ["space"], char: "\u2604", fitzpatrick_scale: false, category: "animals_and_nature" }, sunny: { keywords: ["weather", "nature", "brightness", "summer", "beach", "spring"], char: "\u2600\uFE0F", fitzpatrick_scale: false, category: "animals_and_nature" }, sun_behind_small_cloud: { keywords: ["weather"], char: "\u{1F324}", fitzpatrick_scale: false, category: "animals_and_nature" }, partly_sunny: { keywords: ["weather", "nature", "cloudy", "morning", "fall", "spring"], char: "\u26C5", fitzpatrick_scale: false, category: "animals_and_nature" }, sun_behind_large_cloud: { keywords: ["weather"], char: "\u{1F325}", fitzpatrick_scale: false, category: "animals_and_nature" }, sun_behind_rain_cloud: { keywords: ["weather"], char: "\u{1F326}", fitzpatrick_scale: false, category: "animals_and_nature" }, cloud: { keywords: ["weather", "sky"], char: "\u2601\uFE0F", fitzpatrick_scale: false, category: "animals_and_nature" }, cloud_with_rain: { keywords: ["weather"], char: "\u{1F327}", fitzpatrick_scale: false, category: "animals_and_nature" }, cloud_with_lightning_and_rain: { keywords: ["weather", "lightning"], char: "\u26C8", fitzpatrick_scale: false, category: "animals_and_nature" }, cloud_with_lightning: { keywords: ["weather", "thunder"], char: "\u{1F329}", fitzpatrick_scale: false, category: "animals_and_nature" }, zap: { keywords: ["thunder", "weather", "lightning bolt", "fast"], char: "\u26A1", fitzpatrick_scale: false, category: "animals_and_nature" }, fire: { keywords: ["hot", "cook", "flame"], char: "\u{1F525}", fitzpatrick_scale: false, category: "animals_and_nature" }, boom: { keywords: ["bomb", "explode", "explosion", "collision", "blown"], char: "\u{1F4A5}", fitzpatrick_scale: false, category: "animals_and_nature" }, snowflake: { keywords: ["winter", "season", "cold", "weather", "christmas", "xmas"], char: "\u2744\uFE0F", fitzpatrick_scale: false, category: "animals_and_nature" }, cloud_with_snow: { keywords: ["weather"], char: "\u{1F328}", fitzpatrick_scale: false, category: "animals_and_nature" }, snowman: { keywords: ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen", "without_snow"], char: "\u26C4", fitzpatrick_scale: false, category: "animals_and_nature" }, snowman_with_snow: { keywords: ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen"], char: "\u2603", fitzpatrick_scale: false, category: "animals_and_nature" }, wind_face: { keywords: ["gust", "air"], char: "\u{1F32C}", fitzpatrick_scale: false, category: "animals_and_nature" }, dash: { keywords: ["wind", "air", "fast", "shoo", "fart", "smoke", "puff"], char: "\u{1F4A8}", fitzpatrick_scale: false, category: "animals_and_nature" }, tornado: { keywords: ["weather", "cyclone", "twister"], char: "\u{1F32A}", fitzpatrick_scale: false, category: "animals_and_nature" }, fog: { keywords: ["weather"], char: "\u{1F32B}", fitzpatrick_scale: false, category: "animals_and_nature" }, open_umbrella: { keywords: ["weather", "spring"], char: "\u2602", fitzpatrick_scale: false, category: "animals_and_nature" }, umbrella: { keywords: ["rainy", "weather", "spring"], char: "\u2614", fitzpatrick_scale: false, category: "animals_and_nature" }, droplet: { keywords: ["water", "drip", "faucet", "spring"], char: "\u{1F4A7}", fitzpatrick_scale: false, category: "animals_and_nature" }, sweat_drops: { keywords: ["water", "drip", "oops"], char: "\u{1F4A6}", fitzpatrick_scale: false, category: "animals_and_nature" }, ocean: { keywords: ["sea", "water", "wave", "nature", "tsunami", "disaster"], char: "\u{1F30A}", fitzpatrick_scale: false, category: "animals_and_nature" }, green_apple: { keywords: ["fruit", "nature"], char: "\u{1F34F}", fitzpatrick_scale: false, category: "food_and_drink" }, apple: { keywords: ["fruit", "mac", "school"], char: "\u{1F34E}", fitzpatrick_scale: false, category: "food_and_drink" }, pear: { keywords: ["fruit", "nature", "food"], char: "\u{1F350}", fitzpatrick_scale: false, category: "food_and_drink" }, tangerine: { keywords: ["food", "fruit", "nature", "orange"], char: "\u{1F34A}", fitzpatrick_scale: false, category: "food_and_drink" }, lemon: { keywords: ["fruit", "nature"], char: "\u{1F34B}", fitzpatrick_scale: false, category: "food_and_drink" }, banana: { keywords: ["fruit", "food", "monkey"], char: "\u{1F34C}", fitzpatrick_scale: false, category: "food_and_drink" }, watermelon: { keywords: ["fruit", "food", "picnic", "summer"], char: "\u{1F349}", fitzpatrick_scale: false, category: "food_and_drink" }, grapes: { keywords: ["fruit", "food", "wine"], char: "\u{1F347}", fitzpatrick_scale: false, category: "food_and_drink" }, strawberry: { keywords: ["fruit", "food", "nature"], char: "\u{1F353}", fitzpatrick_scale: false, category: "food_and_drink" }, melon: { keywords: ["fruit", "nature", "food"], char: "\u{1F348}", fitzpatrick_scale: false, category: "food_and_drink" }, cherries: { keywords: ["food", "fruit"], char: "\u{1F352}", fitzpatrick_scale: false, category: "food_and_drink" }, peach: { keywords: ["fruit", "nature", "food"], char: "\u{1F351}", fitzpatrick_scale: false, category: "food_and_drink" }, pineapple: { keywords: ["fruit", "nature", "food"], char: "\u{1F34D}", fitzpatrick_scale: false, category: "food_and_drink" }, coconut: { keywords: ["fruit", "nature", "food", "palm"], char: "\u{1F965}", fitzpatrick_scale: false, category: "food_and_drink" }, kiwi_fruit: { keywords: ["fruit", "food"], char: "\u{1F95D}", fitzpatrick_scale: false, category: "food_and_drink" }, mango: { keywords: ["fruit", "food", "tropical"], char: "\u{1F96D}", fitzpatrick_scale: false, category: "food_and_drink" }, avocado: { keywords: ["fruit", "food"], char: "\u{1F951}", fitzpatrick_scale: false, category: "food_and_drink" }, broccoli: { keywords: ["fruit", "food", "vegetable"], char: "\u{1F966}", fitzpatrick_scale: false, category: "food_and_drink" }, tomato: { keywords: ["fruit", "vegetable", "nature", "food"], char: "\u{1F345}", fitzpatrick_scale: false, category: "food_and_drink" }, eggplant: { keywords: ["vegetable", "nature", "food", "aubergine"], char: "\u{1F346}", fitzpatrick_scale: false, category: "food_and_drink" }, cucumber: { keywords: ["fruit", "food", "pickle"], char: "\u{1F952}", fitzpatrick_scale: false, category: "food_and_drink" }, carrot: { keywords: ["vegetable", "food", "orange"], char: "\u{1F955}", fitzpatrick_scale: false, category: "food_and_drink" }, hot_pepper: { keywords: ["food", "spicy", "chilli", "chili"], char: "\u{1F336}", fitzpatrick_scale: false, category: "food_and_drink" }, potato: { keywords: ["food", "tuber", "vegatable", "starch"], char: "\u{1F954}", fitzpatrick_scale: false, category: "food_and_drink" }, corn: { keywords: ["food", "vegetable", "plant"], char: "\u{1F33D}", fitzpatrick_scale: false, category: "food_and_drink" }, leafy_greens: { keywords: ["food", "vegetable", "plant", "bok choy", "cabbage", "kale", "lettuce"], char: "\u{1F96C}", fitzpatrick_scale: false, category: "food_and_drink" }, sweet_potato: { keywords: ["food", "nature"], char: "\u{1F360}", fitzpatrick_scale: false, category: "food_and_drink" }, peanuts: { keywords: ["food", "nut"], char: "\u{1F95C}", fitzpatrick_scale: false, category: "food_and_drink" }, honey_pot: { keywords: ["bees", "sweet", "kitchen"], char: "\u{1F36F}", fitzpatrick_scale: false, category: "food_and_drink" }, croissant: { keywords: ["food", "bread", "french"], char: "\u{1F950}", fitzpatrick_scale: false, category: "food_and_drink" }, bread: { keywords: ["food", "wheat", "breakfast", "toast"], char: "\u{1F35E}", fitzpatrick_scale: false, category: "food_and_drink" }, baguette_bread: { keywords: ["food", "bread", "french"], char: "\u{1F956}", fitzpatrick_scale: false, category: "food_and_drink" }, bagel: { keywords: ["food", "bread", "bakery", "schmear"], char: "\u{1F96F}", fitzpatrick_scale: false, category: "food_and_drink" }, pretzel: { keywords: ["food", "bread", "twisted"], char: "\u{1F968}", fitzpatrick_scale: false, category: "food_and_drink" }, cheese: { keywords: ["food", "chadder"], char: "\u{1F9C0}", fitzpatrick_scale: false, category: "food_and_drink" }, egg: { keywords: ["food", "chicken", "breakfast"], char: "\u{1F95A}", fitzpatrick_scale: false, category: "food_and_drink" }, bacon: { keywords: ["food", "breakfast", "pork", "pig", "meat"], char: "\u{1F953}", fitzpatrick_scale: false, category: "food_and_drink" }, steak: { keywords: ["food", "cow", "meat", "cut", "chop", "lambchop", "porkchop"], char: "\u{1F969}", fitzpatrick_scale: false, category: "food_and_drink" }, pancakes: { keywords: ["food", "breakfast", "flapjacks", "hotcakes"], char: "\u{1F95E}", fitzpatrick_scale: false, category: "food_and_drink" }, poultry_leg: { keywords: ["food", "meat", "drumstick", "bird", "chicken", "turkey"], char: "\u{1F357}", fitzpatrick_scale: false, category: "food_and_drink" }, meat_on_bone: { keywords: ["good", "food", "drumstick"], char: "\u{1F356}", fitzpatrick_scale: false, category: "food_and_drink" }, bone: { keywords: ["skeleton"], char: "\u{1F9B4}", fitzpatrick_scale: false, category: "food_and_drink" }, fried_shrimp: { keywords: ["food", "animal", "appetizer", "summer"], char: "\u{1F364}", fitzpatrick_scale: false, category: "food_and_drink" }, fried_egg: { keywords: ["food", "breakfast", "kitchen", "egg"], char: "\u{1F373}", fitzpatrick_scale: false, category: "food_and_drink" }, hamburger: { keywords: ["meat", "fast food", "beef", "cheeseburger", "mcdonalds", "burger king"], char: "\u{1F354}", fitzpatrick_scale: false, category: "food_and_drink" }, fries: { keywords: ["chips", "snack", "fast food"], char: "\u{1F35F}", fitzpatrick_scale: false, category: "food_and_drink" }, stuffed_flatbread: { keywords: ["food", "flatbread", "stuffed", "gyro"], char: "\u{1F959}", fitzpatrick_scale: false, category: "food_and_drink" }, hotdog: { keywords: ["food", "frankfurter"], char: "\u{1F32D}", fitzpatrick_scale: false, category: "food_and_drink" }, pizza: { keywords: ["food", "party"], char: "\u{1F355}", fitzpatrick_scale: false, category: "food_and_drink" }, sandwich: { keywords: ["food", "lunch", "bread"], char: "\u{1F96A}", fitzpatrick_scale: false, category: "food_and_drink" }, canned_food: { keywords: ["food", "soup"], char: "\u{1F96B}", fitzpatrick_scale: false, category: "food_and_drink" }, spaghetti: { keywords: ["food", "italian", "noodle"], char: "\u{1F35D}", fitzpatrick_scale: false, category: "food_and_drink" }, taco: { keywords: ["food", "mexican"], char: "\u{1F32E}", fitzpatrick_scale: false, category: "food_and_drink" }, burrito: { keywords: ["food", "mexican"], char: "\u{1F32F}", fitzpatrick_scale: false, category: "food_and_drink" }, green_salad: { keywords: ["food", "healthy", "lettuce"], char: "\u{1F957}", fitzpatrick_scale: false, category: "food_and_drink" }, shallow_pan_of_food: { keywords: ["food", "cooking", "casserole", "paella"], char: "\u{1F958}", fitzpatrick_scale: false, category: "food_and_drink" }, ramen: { keywords: ["food", "japanese", "noodle", "chopsticks"], char: "\u{1F35C}", fitzpatrick_scale: false, category: "food_and_drink" }, stew: { keywords: ["food", "meat", "soup"], char: "\u{1F372}", fitzpatrick_scale: false, category: "food_and_drink" }, fish_cake: { keywords: ["food", "japan", "sea", "beach", "narutomaki", "pink", "swirl", "kamaboko", "surimi", "ramen"], char: "\u{1F365}", fitzpatrick_scale: false, category: "food_and_drink" }, fortune_cookie: { keywords: ["food", "prophecy"], char: "\u{1F960}", fitzpatrick_scale: false, category: "food_and_drink" }, sushi: { keywords: ["food", "fish", "japanese", "rice"], char: "\u{1F363}", fitzpatrick_scale: false, category: "food_and_drink" }, bento: { keywords: ["food", "japanese", "box"], char: "\u{1F371}", fitzpatrick_scale: false, category: "food_and_drink" }, curry: { keywords: ["food", "spicy", "hot", "indian"], char: "\u{1F35B}", fitzpatrick_scale: false, category: "food_and_drink" }, rice_ball: { keywords: ["food", "japanese"], char: "\u{1F359}", fitzpatrick_scale: false, category: "food_and_drink" }, rice: { keywords: ["food", "china", "asian"], char: "\u{1F35A}", fitzpatrick_scale: false, category: "food_and_drink" }, rice_cracker: { keywords: ["food", "japanese"], char: "\u{1F358}", fitzpatrick_scale: false, category: "food_and_drink" }, oden: { keywords: ["food", "japanese"], char: "\u{1F362}", fitzpatrick_scale: false, category: "food_and_drink" }, dango: { keywords: ["food", "dessert", "sweet", "japanese", "barbecue", "meat"], char: "\u{1F361}", fitzpatrick_scale: false, category: "food_and_drink" }, shaved_ice: { keywords: ["hot", "dessert", "summer"], char: "\u{1F367}", fitzpatrick_scale: false, category: "food_and_drink" }, ice_cream: { keywords: ["food", "hot", "dessert"], char: "\u{1F368}", fitzpatrick_scale: false, category: "food_and_drink" }, icecream: { keywords: ["food", "hot", "dessert", "summer"], char: "\u{1F366}", fitzpatrick_scale: false, category: "food_and_drink" }, pie: { keywords: ["food", "dessert", "pastry"], char: "\u{1F967}", fitzpatrick_scale: false, category: "food_and_drink" }, cake: { keywords: ["food", "dessert"], char: "\u{1F370}", fitzpatrick_scale: false, category: "food_and_drink" }, cupcake: { keywords: ["food", "dessert", "bakery", "sweet"], char: "\u{1F9C1}", fitzpatrick_scale: false, category: "food_and_drink" }, moon_cake: { keywords: ["food", "autumn"], char: "\u{1F96E}", fitzpatrick_scale: false, category: "food_and_drink" }, birthday: { keywords: ["food", "dessert", "cake"], char: "\u{1F382}", fitzpatrick_scale: false, category: "food_and_drink" }, custard: { keywords: ["dessert", "food"], char: "\u{1F36E}", fitzpatrick_scale: false, category: "food_and_drink" }, candy: { keywords: ["snack", "dessert", "sweet", "lolly"], char: "\u{1F36C}", fitzpatrick_scale: false, category: "food_and_drink" }, lollipop: { keywords: ["food", "snack", "candy", "sweet"], char: "\u{1F36D}", fitzpatrick_scale: false, category: "food_and_drink" }, chocolate_bar: { keywords: ["food", "snack", "dessert", "sweet"], char: "\u{1F36B}", fitzpatrick_scale: false, category: "food_and_drink" }, popcorn: { keywords: ["food", "movie theater", "films", "snack"], char: "\u{1F37F}", fitzpatrick_scale: false, category: "food_and_drink" }, dumpling: { keywords: ["food", "empanada", "pierogi", "potsticker"], char: "\u{1F95F}", fitzpatrick_scale: false, category: "food_and_drink" }, doughnut: { keywords: ["food", "dessert", "snack", "sweet", "donut"], char: "\u{1F369}", fitzpatrick_scale: false, category: "food_and_drink" }, cookie: { keywords: ["food", "snack", "oreo", "chocolate", "sweet", "dessert"], char: "\u{1F36A}", fitzpatrick_scale: false, category: "food_and_drink" }, milk_glass: { keywords: ["beverage", "drink", "cow"], char: "\u{1F95B}", fitzpatrick_scale: false, category: "food_and_drink" }, beer: { keywords: ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], char: "\u{1F37A}", fitzpatrick_scale: false, category: "food_and_drink" }, beers: { keywords: ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], char: "\u{1F37B}", fitzpatrick_scale: false, category: "food_and_drink" }, clinking_glasses: { keywords: ["beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast"], char: "\u{1F942}", fitzpatrick_scale: false, category: "food_and_drink" }, wine_glass: { keywords: ["drink", "beverage", "drunk", "alcohol", "booze"], char: "\u{1F377}", fitzpatrick_scale: false, category: "food_and_drink" }, tumbler_glass: { keywords: ["drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "glass", "shot"], char: "\u{1F943}", fitzpatrick_scale: false, category: "food_and_drink" }, cocktail: { keywords: ["drink", "drunk", "alcohol", "beverage", "booze", "mojito"], char: "\u{1F378}", fitzpatrick_scale: false, category: "food_and_drink" }, tropical_drink: { keywords: ["beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito"], char: "\u{1F379}", fitzpatrick_scale: false, category: "food_and_drink" }, champagne: { keywords: ["drink", "wine", "bottle", "celebration"], char: "\u{1F37E}", fitzpatrick_scale: false, category: "food_and_drink" }, sake: { keywords: ["wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze"], char: "\u{1F376}", fitzpatrick_scale: false, category: "food_and_drink" }, tea: { keywords: ["drink", "bowl", "breakfast", "green", "british"], char: "\u{1F375}", fitzpatrick_scale: false, category: "food_and_drink" }, cup_with_straw: { keywords: ["drink", "soda"], char: "\u{1F964}", fitzpatrick_scale: false, category: "food_and_drink" }, coffee: { keywords: ["beverage", "caffeine", "latte", "espresso"], char: "\u2615", fitzpatrick_scale: false, category: "food_and_drink" }, baby_bottle: { keywords: ["food", "container", "milk"], char: "\u{1F37C}", fitzpatrick_scale: false, category: "food_and_drink" }, salt: { keywords: ["condiment", "shaker"], char: "\u{1F9C2}", fitzpatrick_scale: false, category: "food_and_drink" }, spoon: { keywords: ["cutlery", "kitchen", "tableware"], char: "\u{1F944}", fitzpatrick_scale: false, category: "food_and_drink" }, fork_and_knife: { keywords: ["cutlery", "kitchen"], char: "\u{1F374}", fitzpatrick_scale: false, category: "food_and_drink" }, plate_with_cutlery: { keywords: ["food", "eat", "meal", "lunch", "dinner", "restaurant"], char: "\u{1F37D}", fitzpatrick_scale: false, category: "food_and_drink" }, bowl_with_spoon: { keywords: ["food", "breakfast", "cereal", "oatmeal", "porridge"], char: "\u{1F963}", fitzpatrick_scale: false, category: "food_and_drink" }, takeout_box: { keywords: ["food", "leftovers"], char: "\u{1F961}", fitzpatrick_scale: false, category: "food_and_drink" }, chopsticks: { keywords: ["food"], char: "\u{1F962}", fitzpatrick_scale: false, category: "food_and_drink" }, soccer: { keywords: ["sports", "football"], char: "\u26BD", fitzpatrick_scale: false, category: "activity" }, basketball: { keywords: ["sports", "balls", "NBA"], char: "\u{1F3C0}", fitzpatrick_scale: false, category: "activity" }, football: { keywords: ["sports", "balls", "NFL"], char: "\u{1F3C8}", fitzpatrick_scale: false, category: "activity" }, baseball: { keywords: ["sports", "balls"], char: "\u26BE", fitzpatrick_scale: false, category: "activity" }, softball: { keywords: ["sports", "balls"], char: "\u{1F94E}", fitzpatrick_scale: false, category: "activity" }, tennis: { keywords: ["sports", "balls", "green"], char: "\u{1F3BE}", fitzpatrick_scale: false, category: "activity" }, volleyball: { keywords: ["sports", "balls"], char: "\u{1F3D0}", fitzpatrick_scale: false, category: "activity" }, rugby_football: { keywords: ["sports", "team"], char: "\u{1F3C9}", fitzpatrick_scale: false, category: "activity" }, flying_disc: { keywords: ["sports", "frisbee", "ultimate"], char: "\u{1F94F}", fitzpatrick_scale: false, category: "activity" }, "8ball": { keywords: ["pool", "hobby", "game", "luck", "magic"], char: "\u{1F3B1}", fitzpatrick_scale: false, category: "activity" }, golf: { keywords: ["sports", "business", "flag", "hole", "summer"], char: "\u26F3", fitzpatrick_scale: false, category: "activity" }, golfing_woman: { keywords: ["sports", "business", "woman", "female"], char: "\u{1F3CC}\uFE0F\u200D\u2640\uFE0F", fitzpatrick_scale: false, category: "activity" }, golfing_man: { keywords: ["sports", "business"], char: "\u{1F3CC}", fitzpatrick_scale: true, category: "activity" }, ping_pong: { keywords: ["sports", "pingpong"], char: "\u{1F3D3}", fitzpatrick_scale: false, category: "activity" }, badminton: { keywords: ["sports"], char: "\u{1F3F8}", fitzpatrick_scale: false, category: "activity" }, goal_net: { keywords: ["sports"], char: "\u{1F945}", fitzpatrick_scale: false, category: "activity" }, ice_hockey: { keywords: ["sports"], char: "\u{1F3D2}", fitzpatrick_scale: false, category: "activity" }, field_hockey: { keywords: ["sports"], char: "\u{1F3D1}", fitzpatrick_scale: false, category: "activity" }, lacrosse: { keywords: ["sports", "ball", "stick"], char: "\u{1F94D}", fitzpatrick_scale: false, category: "activity" }, cricket: { keywords: ["sports"], char: "\u{1F3CF}", fitzpatrick_scale: false, category: "activity" }, ski: { keywords: ["sports", "winter", "cold", "snow"], char: "\u{1F3BF}", fitzpatrick_scale: false, category: "activity" }, skier: { keywords: ["sports", "winter", "snow"], char: "\u26F7", fitzpatrick_scale: false, category: "activity" }, snowboarder: { keywords: ["sports", "winter"], char: "\u{1F3C2}", fitzpatrick_scale: true, category: "activity" }, person_fencing: { keywords: ["sports", "fencing", "sword"], char: "\u{1F93A}", fitzpatrick_scale: false, category: "activity" }, women_wrestling: { keywords: ["sports", "wrestlers"], char: "\u{1F93C}\u200D\u2640\uFE0F", fitzpatrick_scale: false, category: "activity" }, men_wrestling: { keywords: ["sports", "wrestlers"], char: "\u{1F93C}\u200D\u2642\uFE0F", fitzpatrick_scale: false, category: "activity" }, woman_cartwheeling: { keywords: ["gymnastics"], char: "\u{1F938}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, man_cartwheeling: { keywords: ["gymnastics"], char: "\u{1F938}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, woman_playing_handball: { keywords: ["sports"], char: "\u{1F93E}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, man_playing_handball: { keywords: ["sports"], char: "\u{1F93E}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, ice_skate: { keywords: ["sports"], char: "\u26F8", fitzpatrick_scale: false, category: "activity" }, curling_stone: { keywords: ["sports"], char: "\u{1F94C}", fitzpatrick_scale: false, category: "activity" }, skateboard: { keywords: ["board"], char: "\u{1F6F9}", fitzpatrick_scale: false, category: "activity" }, sled: { keywords: ["sleigh", "luge", "toboggan"], char: "\u{1F6F7}", fitzpatrick_scale: false, category: "activity" }, bow_and_arrow: { keywords: ["sports"], char: "\u{1F3F9}", fitzpatrick_scale: false, category: "activity" }, fishing_pole_and_fish: { keywords: ["food", "hobby", "summer"], char: "\u{1F3A3}", fitzpatrick_scale: false, category: "activity" }, boxing_glove: { keywords: ["sports", "fighting"], char: "\u{1F94A}", fitzpatrick_scale: false, category: "activity" }, martial_arts_uniform: { keywords: ["judo", "karate", "taekwondo"], char: "\u{1F94B}", fitzpatrick_scale: false, category: "activity" }, rowing_woman: { keywords: ["sports", "hobby", "water", "ship", "woman", "female"], char: "\u{1F6A3}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, rowing_man: { keywords: ["sports", "hobby", "water", "ship"], char: "\u{1F6A3}", fitzpatrick_scale: true, category: "activity" }, climbing_woman: { keywords: ["sports", "hobby", "woman", "female", "rock"], char: "\u{1F9D7}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, climbing_man: { keywords: ["sports", "hobby", "man", "male", "rock"], char: "\u{1F9D7}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, swimming_woman: { keywords: ["sports", "exercise", "human", "athlete", "water", "summer", "woman", "female"], char: "\u{1F3CA}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, swimming_man: { keywords: ["sports", "exercise", "human", "athlete", "water", "summer"], char: "\u{1F3CA}", fitzpatrick_scale: true, category: "activity" }, woman_playing_water_polo: { keywords: ["sports", "pool"], char: "\u{1F93D}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, man_playing_water_polo: { keywords: ["sports", "pool"], char: "\u{1F93D}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, woman_in_lotus_position: { keywords: ["woman", "female", "meditation", "yoga", "serenity", "zen", "mindfulness"], char: "\u{1F9D8}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, man_in_lotus_position: { keywords: ["man", "male", "meditation", "yoga", "serenity", "zen", "mindfulness"], char: "\u{1F9D8}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, surfing_woman: { keywords: ["sports", "ocean", "sea", "summer", "beach", "woman", "female"], char: "\u{1F3C4}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, surfing_man: { keywords: ["sports", "ocean", "sea", "summer", "beach"], char: "\u{1F3C4}", fitzpatrick_scale: true, category: "activity" }, bath: { keywords: ["clean", "shower", "bathroom"], char: "\u{1F6C0}", fitzpatrick_scale: true, category: "activity" }, basketball_woman: { keywords: ["sports", "human", "woman", "female"], char: "\u26F9\uFE0F\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, basketball_man: { keywords: ["sports", "human"], char: "\u26F9", fitzpatrick_scale: true, category: "activity" }, weight_lifting_woman: { keywords: ["sports", "training", "exercise", "woman", "female"], char: "\u{1F3CB}\uFE0F\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, weight_lifting_man: { keywords: ["sports", "training", "exercise"], char: "\u{1F3CB}", fitzpatrick_scale: true, category: "activity" }, biking_woman: { keywords: ["sports", "bike", "exercise", "hipster", "woman", "female"], char: "\u{1F6B4}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, biking_man: { keywords: ["sports", "bike", "exercise", "hipster"], char: "\u{1F6B4}", fitzpatrick_scale: true, category: "activity" }, mountain_biking_woman: { keywords: ["transportation", "sports", "human", "race", "bike", "woman", "female"], char: "\u{1F6B5}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, mountain_biking_man: { keywords: ["transportation", "sports", "human", "race", "bike"], char: "\u{1F6B5}", fitzpatrick_scale: true, category: "activity" }, horse_racing: { keywords: ["animal", "betting", "competition", "gambling", "luck"], char: "\u{1F3C7}", fitzpatrick_scale: true, category: "activity" }, business_suit_levitating: { keywords: ["suit", "business", "levitate", "hover", "jump"], char: "\u{1F574}", fitzpatrick_scale: true, category: "activity" }, trophy: { keywords: ["win", "award", "contest", "place", "ftw", "ceremony"], char: "\u{1F3C6}", fitzpatrick_scale: false, category: "activity" }, running_shirt_with_sash: { keywords: ["play", "pageant"], char: "\u{1F3BD}", fitzpatrick_scale: false, category: "activity" }, medal_sports: { keywords: ["award", "winning"], char: "\u{1F3C5}", fitzpatrick_scale: false, category: "activity" }, medal_military: { keywords: ["award", "winning", "army"], char: "\u{1F396}", fitzpatrick_scale: false, category: "activity" }, "1st_place_medal": { keywords: ["award", "winning", "first"], char: "\u{1F947}", fitzpatrick_scale: false, category: "activity" }, "2nd_place_medal": { keywords: ["award", "second"], char: "\u{1F948}", fitzpatrick_scale: false, category: "activity" }, "3rd_place_medal": { keywords: ["award", "third"], char: "\u{1F949}", fitzpatrick_scale: false, category: "activity" }, reminder_ribbon: { keywords: ["sports", "cause", "support", "awareness"], char: "\u{1F397}", fitzpatrick_scale: false, category: "activity" }, rosette: { keywords: ["flower", "decoration", "military"], char: "\u{1F3F5}", fitzpatrick_scale: false, category: "activity" }, ticket: { keywords: ["event", "concert", "pass"], char: "\u{1F3AB}", fitzpatrick_scale: false, category: "activity" }, tickets: { keywords: ["sports", "concert", "entrance"], char: "\u{1F39F}", fitzpatrick_scale: false, category: "activity" }, performing_arts: { keywords: ["acting", "theater", "drama"], char: "\u{1F3AD}", fitzpatrick_scale: false, category: "activity" }, art: { keywords: ["design", "paint", "draw", "colors"], char: "\u{1F3A8}", fitzpatrick_scale: false, category: "activity" }, circus_tent: { keywords: ["festival", "carnival", "party"], char: "\u{1F3AA}", fitzpatrick_scale: false, category: "activity" }, woman_juggling: { keywords: ["juggle", "balance", "skill", "multitask"], char: "\u{1F939}\u200D\u2640\uFE0F", fitzpatrick_scale: true, category: "activity" }, man_juggling: { keywords: ["juggle", "balance", "skill", "multitask"], char: "\u{1F939}\u200D\u2642\uFE0F", fitzpatrick_scale: true, category: "activity" }, microphone: { keywords: ["sound", "music", "PA", "sing", "talkshow"], char: "\u{1F3A4}", fitzpatrick_scale: false, category: "activity" }, headphones: { keywords: ["music", "score", "gadgets"], char: "\u{1F3A7}", fitzpatrick_scale: false, category: "activity" }, musical_score: { keywords: ["treble", "clef", "compose"], char: "\u{1F3BC}", fitzpatrick_scale: false, category: "activity" }, musical_keyboard: { keywords: ["piano", "instrument", "compose"], char: "\u{1F3B9}", fitzpatrick_scale: false, category: "activity" }, drum: { keywords: ["music", "instrument", "drumsticks", "snare"], char: "\u{1F941}", fitzpatrick_scale: false, category: "activity" }, saxophone: { keywords: ["music", "instrument", "jazz", "blues"], char: "\u{1F3B7}", fitzpatrick_scale: false, category: "activity" }, trumpet: { keywords: ["music", "brass"], char: "\u{1F3BA}", fitzpatrick_scale: false, category: "activity" }, guitar: { keywords: ["music", "instrument"], char: "\u{1F3B8}", fitzpatrick_scale: false, category: "activity" }, violin: { keywords: ["music", "instrument", "orchestra", "symphony"], char: "\u{1F3BB}", fitzpatrick_scale: false, category: "activity" }, clapper: { keywords: ["movie", "film", "record"], char: "\u{1F3AC}", fitzpatrick_scale: false, category: "activity" }, video_game: { keywords: ["play", "console", "PS4", "controller"], char: "\u{1F3AE}", fitzpatrick_scale: false, category: "activity" }, space_invader: { keywords: ["game", "arcade", "play"], char: "\u{1F47E}", fitzpatrick_scale: false, category: "activity" }, dart: { keywords: ["game", "play", "bar", "target", "bullseye"], char: "\u{1F3AF}", fitzpatrick_scale: false, category: "activity" }, game_die: { keywords: ["dice", "random", "tabletop", "play", "luck"], char: "\u{1F3B2}", fitzpatrick_scale: false, category: "activity" }, chess_pawn: { keywords: ["expendable"], char: "\u265F", fitzpatrick_scale: false, category: "activity" }, slot_machine: { keywords: ["bet", "gamble", "vegas", "fruit machine", "luck", "casino"], char: "\u{1F3B0}", fitzpatrick_scale: false, category: "activity" }, jigsaw: { keywords: ["interlocking", "puzzle", "piece"], char: "\u{1F9E9}", fitzpatrick_scale: false, category: "activity" }, bowling: { keywords: ["sports", "fun", "play"], char: "\u{1F3B3}", fitzpatrick_scale: false, category: "activity" }, red_car: { keywords: ["red", "transportation", "vehicle"], char: "\u{1F697}", fitzpatrick_scale: false, category: "travel_and_places" }, taxi: { keywords: ["uber", "vehicle", "cars", "transportation"], char: "\u{1F695}", fitzpatrick_scale: false, category: "travel_and_places" }, blue_car: { keywords: ["transportation", "vehicle"], char: "\u{1F699}", fitzpatrick_scale: false, category: "travel_and_places" }, bus: { keywords: ["car", "vehicle", "transportation"], char: "\u{1F68C}", fitzpatrick_scale: false, category: "travel_and_places" }, trolleybus: { keywords: ["bart", "transportation", "vehicle"], char: "\u{1F68E}", fitzpatrick_scale: false, category: "travel_and_places" }, racing_car: { keywords: ["sports", "race", "fast", "formula", "f1"], char: "\u{1F3CE}", fitzpatrick_scale: false, category: "travel_and_places" }, police_car: { keywords: ["vehicle", "cars", "transportation", "law", "legal", "enforcement"], char: "\u{1F693}", fitzpatrick_scale: false, category: "travel_and_places" }, ambulance: { keywords: ["health", "911", "hospital"], char: "\u{1F691}", fitzpatrick_scale: false, category: "travel_and_places" }, fire_engine: { keywords: ["transportation", "cars", "vehicle"], char: "\u{1F692}", fitzpatrick_scale: false, category: "travel_and_places" }, minibus: { keywords: ["vehicle", "car", "transportation"], char: "\u{1F690}", fitzpatrick_scale: false, category: "travel_and_places" }, truck: { keywords: ["cars", "transportation"], char: "\u{1F69A}", fitzpatrick_scale: false, category: "travel_and_places" }, articulated_lorry: { keywords: ["vehicle", "cars", "transportation", "express"], char: "\u{1F69B}", fitzpatrick_scale: false, category: "travel_and_places" }, tractor: { keywords: ["vehicle", "car", "farming", "agriculture"], char: "\u{1F69C}", fitzpatrick_scale: false, category: "travel_and_places" }, kick_scooter: { keywords: ["vehicle", "kick", "razor"], char: "\u{1F6F4}", fitzpatrick_scale: false, category: "travel_and_places" }, motorcycle: { keywords: ["race", "sports", "fast"], char: "\u{1F3CD}", fitzpatrick_scale: false, category: "travel_and_places" }, bike: { keywords: ["sports", "bicycle", "exercise", "hipster"], char: "\u{1F6B2}", fitzpatrick_scale: false, category: "travel_and_places" }, motor_scooter: { keywords: ["vehicle", "vespa", "sasha"], char: "\u{1F6F5}", fitzpatrick_scale: false, category: "travel_and_places" }, rotating_light: { keywords: ["police", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal"], char: "\u{1F6A8}", fitzpatrick_scale: false, category: "travel_and_places" }, oncoming_police_car: { keywords: ["vehicle", "law", "legal", "enforcement", "911"], char: "\u{1F694}", fitzpatrick_scale: false, category: "travel_and_places" }, oncoming_bus: { keywords: ["vehicle", "transportation"], char: "\u{1F68D}", fitzpatrick_scale: false, category: "travel_and_places" }, oncoming_automobile: { keywords: ["car", "vehicle", "transportation"], char: "\u{1F698}", fitzpatrick_scale: false, category: "travel_and_places" }, oncoming_taxi: { keywords: ["vehicle", "cars", "uber"], char: "\u{1F696}", fitzpatrick_scale: false, category: "travel_and_places" }, aerial_tramway: { keywords: ["transportation", "vehicle", "ski"], char: "\u{1F6A1}", fitzpatrick_scale: false, category: "travel_and_places" }, mountain_cableway: { keywords: ["transportation", "vehicle", "ski"], char: "\u{1F6A0}", fitzpatrick_scale: false, category: "travel_and_places" }, suspension_railway: { keywords: ["vehicle", "transportation"], char: "\u{1F69F}", fitzpatrick_scale: false, category: "travel_and_places" }, railway_car: { keywords: ["transportation", "vehicle"], char: "\u{1F683}", fitzpatrick_scale: false, category: "travel_and_places" }, train: { keywords: ["transportation", "vehicle", "carriage", "public", "travel"], char: "\u{1F68B}", fitzpatrick_scale: false, category: "travel_and_places" }, monorail: { keywords: ["transportation", "vehicle"], char: "\u{1F69D}", fitzpatrick_scale: false, category: "travel_and_places" }, bullettrain_side: { keywords: ["transportation", "vehicle"], char: "\u{1F684}", fitzpatrick_scale: false, category: "travel_and_places" }, bullettrain_front: { keywords: ["transportation", "vehicle", "speed", "fast", "public", "travel"], char: "\u{1F685}", fitzpatrick_scale: false, category: "travel_and_places" }, light_rail: { keywords: ["transportation", "vehicle"], char: "\u{1F688}", fitzpatrick_scale: false, category: "travel_and_places" }, mountain_railway: { keywords: ["transportation", "vehicle"], char: "\u{1F69E}", fitzpatrick_scale: false, category: "travel_and_places" }, steam_locomotive: { keywords: ["transportation", "vehicle", "train"], char: "\u{1F682}", fitzpatrick_scale: false, category: "travel_and_places" }, train2: { keywords: ["transportation", "vehicle"], char: "\u{1F686}", fitzpatrick_scale: false, category: "travel_and_places" }, metro: { keywords: ["transportation", "blue-square", "mrt", "underground", "tube"], char: "\u{1F687}", fitzpatrick_scale: false, category: "travel_and_places" }, tram: { keywords: ["transportation", "vehicle"], char: "\u{1F68A}", fitzpatrick_scale: false, category: "travel_and_places" }, station: { keywords: ["transportation", "vehicle", "public"], char: "\u{1F689}", fitzpatrick_scale: false, category: "travel_and_places" }, flying_saucer: { keywords: ["transportation", "vehicle", "ufo"], char: "\u{1F6F8}", fitzpatrick_scale: false, category: "travel_and_places" }, helicopter: { keywords: ["transportation", "vehicle", "fly"], char: "\u{1F681}", fitzpatrick_scale: false, category: "travel_and_places" }, small_airplane: { keywords: ["flight", "transportation", "fly", "vehicle"], char: "\u{1F6E9}", fitzpatrick_scale: false, category: "travel_and_places" }, airplane: { keywords: ["vehicle", "transportation", "flight", "fly"], char: "\u2708\uFE0F", fitzpatrick_scale: false, category: "travel_and_places" }, flight_departure: { keywords: ["airport", "flight", "landing"], char: "\u{1F6EB}", fitzpatrick_scale: false, category: "travel_and_places" }, flight_arrival: { keywords: ["airport", "flight", "boarding"], char: "\u{1F6EC}", fitzpatrick_scale: false, category: "travel_and_places" }, sailboat: { keywords: ["ship", "summer", "transportation", "water", "sailing"], char: "\u26F5", fitzpatrick_scale: false, category: "travel_and_places" }, motor_boat: { keywords: ["ship"], char: "\u{1F6E5}", fitzpatrick_scale: false, category: "travel_and_places" }, speedboat: { keywords: ["ship", "transportation", "vehicle", "summer"], char: "\u{1F6A4}", fitzpatrick_scale: false, category: "travel_and_places" }, ferry: { keywords: ["boat", "ship", "yacht"], char: "\u26F4", fitzpatrick_scale: false, category: "travel_and_places" }, passenger_ship: { keywords: ["yacht", "cruise", "ferry"], char: "\u{1F6F3}", fitzpatrick_scale: false, category: "travel_and_places" }, rocket: { keywords: ["launch", "ship", "staffmode", "NASA", "outer space", "outer_space", "fly"], char: "\u{1F680}", fitzpatrick_scale: false, category: "travel_and_places" }, artificial_satellite: { keywords: ["communication", "gps", "orbit", "spaceflight", "NASA", "ISS"], char: "\u{1F6F0}", fitzpatrick_scale: false, category: "travel_and_places" }, seat: { keywords: ["sit", "airplane", "transport", "bus", "flight", "fly"], char: "\u{1F4BA}", fitzpatrick_scale: false, category: "travel_and_places" }, canoe: { keywords: ["boat", "paddle", "water", "ship"], char: "\u{1F6F6}", fitzpatrick_scale: false, category: "travel_and_places" }, anchor: { keywords: ["ship", "ferry", "sea", "boat"], char: "\u2693", fitzpatrick_scale: false, category: "travel_and_places" }, construction: { keywords: ["wip", "progress", "caution", "warning"], char: "\u{1F6A7}", fitzpatrick_scale: false, category: "travel_and_places" }, fuelpump: { keywords: ["gas station", "petroleum"], char: "\u26FD", fitzpatrick_scale: false, category: "travel_and_places" }, busstop: { keywords: ["transportation", "wait"], char: "\u{1F68F}", fitzpatrick_scale: false, category: "travel_and_places" }, vertical_traffic_light: { keywords: ["transportation", "driving"], char: "\u{1F6A6}", fitzpatrick_scale: false, category: "travel_and_places" }, traffic_light: { keywords: ["transportation", "signal"], char: "\u{1F6A5}", fitzpatrick_scale: false, category: "travel_and_places" }, checkered_flag: { keywords: ["contest", "finishline", "race", "gokart"], char: "\u{1F3C1}", fitzpatrick_scale: false, category: "travel_and_places" }, ship: { keywords: ["transportation", "titanic", "deploy"], char: "\u{1F6A2}", fitzpatrick_scale: false, category: "travel_and_places" }, ferris_wheel: { keywords: ["photo", "carnival", "londoneye"], char: "\u{1F3A1}", fitzpatrick_scale: false, category: "travel_and_places" }, roller_coaster: { keywords: ["carnival", "playground", "photo", "fun"], char: "\u{1F3A2}", fitzpatrick_scale: false, category: "travel_and_places" }, carousel_horse: { keywords: ["photo", "carnival"], char: "\u{1F3A0}", fitzpatrick_scale: false, category: "travel_and_places" }, building_construction: { keywords: ["wip", "working", "progress"], char: "\u{1F3D7}", fitzpatrick_scale: false, category: "travel_and_places" }, foggy: { keywords: ["photo", "mountain"], char: "\u{1F301}", fitzpatrick_scale: false, category: "travel_and_places" }, tokyo_tower: { keywords: ["photo", "japanese"], char: "\u{1F5FC}", fitzpatrick_scale: false, category: "travel_and_places" }, factory: { keywords: ["building", "industry", "pollution", "smoke"], char: "\u{1F3ED}", fitzpatrick_scale: false, category: "travel_and_places" }, fountain: { keywords: ["photo", "summer", "water", "fresh"], char: "\u26F2", fitzpatrick_scale: false, category: "travel_and_places" }, rice_scene: { keywords: ["photo", "japan", "asia", "tsukimi"], char: "\u{1F391}", fitzpatrick_scale: false, category: "travel_and_places" }, mountain: { keywords: ["photo", "nature", "environment"], char: "\u26F0", fitzpatrick_scale: false, category: "travel_and_places" }, mountain_snow: { keywords: ["photo", "nature", "environment", "winter", "cold"], char: "\u{1F3D4}", fitzpatrick_scale: false, category: "travel_and_places" }, mount_fuji: { keywords: ["photo", "mountain", "nature", "japanese"], char: "\u{1F5FB}", fitzpatrick_scale: false, category: "travel_and_places" }, volcano: { keywords: ["photo", "nature", "disaster"], char: "\u{1F30B}", fitzpatrick_scale: false, category: "travel_and_places" }, japan: { keywords: ["nation", "country", "japanese", "asia"], char: "\u{1F5FE}", fitzpatrick_scale: false, category: "travel_and_places" }, camping: { keywords: ["photo", "outdoors", "tent"], char: "\u{1F3D5}", fitzpatrick_scale: false, category: "travel_and_places" }, tent: { keywords: ["photo", "camping", "outdoors"], char: "\u26FA", fitzpatrick_scale: false, category: "travel_and_places" }, national_park: { keywords: ["photo", "environment", "nature"], char: "\u{1F3DE}", fitzpatrick_scale: false, category: "travel_and_places" }, motorway: { keywords: ["road", "cupertino", "interstate", "highway"], char: "\u{1F6E3}", fitzpatrick_scale: false, category: "travel_and_places" }, railway_track: { keywords: ["train", "transportation"], char: "\u{1F6E4}", fitzpatrick_scale: false, category: "travel_and_places" }, sunrise: { keywords: ["morning", "view", "vacation", "photo"], char: "\u{1F305}", fitzpatrick_scale: false, category: "travel_and_places" }, sunrise_over_mountains: { keywords: ["view", "vacation", "photo"], char: "\u{1F304}", fitzpatrick_scale: false, category: "travel_and_places" }, desert: { keywords: ["photo", "warm", "saharah"], char: "\u{1F3DC}", fitzpatrick_scale: false, category: "travel_and_places" }, beach_umbrella: { keywords: ["weather", "summer", "sunny", "sand", "mojito"], char: "\u{1F3D6}", fitzpatrick_scale: false, category: "travel_and_places" }, desert_island: { keywords: ["photo", "tropical", "mojito"], char: "\u{1F3DD}", fitzpatrick_scale: false, category: "travel_and_places" }, city_sunrise: { keywords: ["photo", "good morning", "dawn"], char: "\u{1F307}", fitzpatrick_scale: false, category: "travel_and_places" }, city_sunset: { keywords: ["photo", "evening", "sky", "buildings"], char: "\u{1F306}", fitzpatrick_scale: false, category: "travel_and_places" }, cityscape: { keywords: ["photo", "night life", "urban"], char: "\u{1F3D9}", fitzpatrick_scale: false, category: "travel_and_places" }, night_with_stars: { keywords: ["evening", "city", "downtown"], char: "\u{1F303}", fitzpatrick_scale: false, category: "travel_and_places" }, bridge_at_night: { keywords: ["photo", "sanfrancisco"], char: "\u{1F309}", fitzpatrick_scale: false, category: "travel_and_places" }, milky_way: { keywords: ["photo", "space", "stars"], char: "\u{1F30C}", fitzpatrick_scale: false, category: "travel_and_places" }, stars: { keywords: ["night", "photo"], char: "\u{1F320}", fitzpatrick_scale: false, category: "travel_and_places" }, sparkler: { keywords: ["stars", "night", "shine"], char: "\u{1F387}", fitzpatrick_scale: false, category: "travel_and_places" }, fireworks: { keywords: ["photo", "festival", "carnival", "congratulations"], char: "\u{1F386}", fitzpatrick_scale: false, category: "travel_and_places" }, rainbow: { keywords: ["nature", "happy", "unicorn_face", "photo", "sky", "spring"], char: "\u{1F308}", fitzpatrick_scale: false, category: "travel_and_places" }, houses: { keywords: ["buildings", "photo"], char: "\u{1F3D8}", fitzpatrick_scale: false, category: "travel_and_places" }, european_castle: { keywords: ["building", "royalty", "history"], char: "\u{1F3F0}", fitzpatrick_scale: false, category: "travel_and_places" }, japanese_castle: { keywords: ["photo", "building"], char: "\u{1F3EF}", fitzpatrick_scale: false, category: "travel_and_places" }, stadium: { keywords: ["photo", "place", "sports", "concert", "venue"], char: "\u{1F3DF}", fitzpatrick_scale: false, category: "travel_and_places" }, statue_of_liberty: { keywords: ["american", "newyork"], char: "\u{1F5FD}", fitzpatrick_scale: false, category: "travel_and_places" }, house: { keywords: ["building", "home"], char: "\u{1F3E0}", fitzpatrick_scale: false, category: "travel_and_places" }, house_with_garden: { keywords: ["home", "plant", "nature"], char: "\u{1F3E1}", fitzpatrick_scale: false, category: "travel_and_places" }, derelict_house: { keywords: ["abandon", "evict", "broken", "building"], char: "\u{1F3DA}", fitzpatrick_scale: false, category: "travel_and_places" }, office: { keywords: ["building", "bureau", "work"], char: "\u{1F3E2}", fitzpatrick_scale: false, category: "travel_and_places" }, department_store: { keywords: ["building", "shopping", "mall"], char: "\u{1F3EC}", fitzpatrick_scale: false, category: "travel_and_places" }, post_office: { keywords: ["building", "envelope", "communication"], char: "\u{1F3E3}", fitzpatrick_scale: false, category: "travel_and_places" }, european_post_office: { keywords: ["building", "email"], char: "\u{1F3E4}", fitzpatrick_scale: false, category: "travel_and_places" }, hospital: { keywords: ["building", "health", "surgery", "doctor"], char: "\u{1F3E5}", fitzpatrick_scale: false, category: "travel_and_places" }, bank: { keywords: ["building", "money", "sales", "cash", "business", "enterprise"], char: "\u{1F3E6}", fitzpatrick_scale: false, category: "travel_and_places" }, hotel: { keywords: ["building", "accomodation", "checkin"], char: "\u{1F3E8}", fitzpatrick_scale: false, category: "travel_and_places" }, convenience_store: { keywords: ["building", "shopping", "groceries"], char: "\u{1F3EA}", fitzpatrick_scale: false, category: "travel_and_places" }, school: { keywords: ["building", "student", "education", "learn", "teach"], char: "\u{1F3EB}", fitzpatrick_scale: false, category: "travel_and_places" }, love_hotel: { keywords: ["like", "affection", "dating"], char: "\u{1F3E9}", fitzpatrick_scale: false, category: "travel_and_places" }, wedding: { keywords: ["love", "like", "affection", "couple", "marriage", "bride", "groom"], char: "\u{1F492}", fitzpatrick_scale: false, category: "travel_and_places" }, classical_building: { keywords: ["art", "culture", "history"], char: "\u{1F3DB}", fitzpatrick_scale: false, category: "travel_and_places" }, church: { keywords: ["building", "religion", "christ"], char: "\u26EA", fitzpatrick_scale: false, category: "travel_and_places" }, mosque: { keywords: ["islam", "worship", "minaret"], char: "\u{1F54C}", fitzpatrick_scale: false, category: "travel_and_places" }, synagogue: { keywords: ["judaism", "worship", "temple", "jewish"], char: "\u{1F54D}", fitzpatrick_scale: false, category: "travel_and_places" }, kaaba: { keywords: ["mecca", "mosque", "islam"], char: "\u{1F54B}", fitzpatrick_scale: false, category: "travel_and_places" }, shinto_shrine: { keywords: ["temple", "japan", "kyoto"], char: "\u26E9", fitzpatrick_scale: false, category: "travel_and_places" }, watch: { keywords: ["time", "accessories"], char: "\u231A", fitzpatrick_scale: false, category: "objects" }, iphone: { keywords: ["technology", "apple", "gadgets", "dial"], char: "\u{1F4F1}", fitzpatrick_scale: false, category: "objects" }, calling: { keywords: ["iphone", "incoming"], char: "\u{1F4F2}", fitzpatrick_scale: false, category: "objects" }, computer: { keywords: ["technology", "laptop", "screen", "display", "monitor"], char: "\u{1F4BB}", fitzpatrick_scale: false, category: "objects" }, keyboard: { keywords: ["technology", "computer", "type", "input", "text"], char: "\u2328", fitzpatrick_scale: false, category: "objects" }, desktop_computer: { keywords: ["technology", "computing", "screen"], char: "\u{1F5A5}", fitzpatrick_scale: false, category: "objects" }, printer: { keywords: ["paper", "ink"], char: "\u{1F5A8}", fitzpatrick_scale: false, category: "objects" }, computer_mouse: { keywords: ["click"], char: "\u{1F5B1}", fitzpatrick_scale: false, category: "objects" }, trackball: { keywords: ["technology", "trackpad"], char: "\u{1F5B2}", fitzpatrick_scale: false, category: "objects" }, joystick: { keywords: ["game", "play"], char: "\u{1F579}", fitzpatrick_scale: false, category: "objects" }, clamp: { keywords: ["tool"], char: "\u{1F5DC}", fitzpatrick_scale: false, category: "objects" }, minidisc: { keywords: ["technology", "record", "data", "disk", "90s"], char: "\u{1F4BD}", fitzpatrick_scale: false, category: "objects" }, floppy_disk: { keywords: ["oldschool", "technology", "save", "90s", "80s"], char: "\u{1F4BE}", fitzpatrick_scale: false, category: "objects" }, cd: { keywords: ["technology", "dvd", "disk", "disc", "90s"], char: "\u{1F4BF}", fitzpatrick_scale: false, category: "objects" }, dvd: { keywords: ["cd", "disk", "disc"], char: "\u{1F4C0}", fitzpatrick_scale: false, category: "objects" }, vhs: { keywords: ["record", "video", "oldschool", "90s", "80s"], char: "\u{1F4FC}", fitzpatrick_scale: false, category: "objects" }, camera: { keywords: ["gadgets", "photography"], char: "\u{1F4F7}", fitzpatrick_scale: false, category: "objects" }, camera_flash: { keywords: ["photography", "gadgets"], char: "\u{1F4F8}", fitzpatrick_scale: false, category: "objects" }, video_camera: { keywords: ["film", "record"], char: "\u{1F4F9}", fitzpatrick_scale: false, category: "objects" }, movie_camera: { keywords: ["film", "record"], char: "\u{1F3A5}", fitzpatrick_scale: false, category: "objects" }, film_projector: { keywords: ["video", "tape", "record", "movie"], char: "\u{1F4FD}", fitzpatrick_scale: false, category: "objects" }, film_strip: { keywords: ["movie"], char: "\u{1F39E}", fitzpatrick_scale: false, category: "objects" }, telephone_receiver: { keywords: ["technology", "communication", "dial"], char: "\u{1F4DE}", fitzpatrick_scale: false, category: "objects" }, phone: { keywords: ["technology", "communication", "dial", "telephone"], char: "\u260E\uFE0F", fitzpatrick_scale: false, category: "objects" }, pager: { keywords: ["bbcall", "oldschool", "90s"], char: "\u{1F4DF}", fitzpatrick_scale: false, category: "objects" }, fax: { keywords: ["communication", "technology"], char: "\u{1F4E0}", fitzpatrick_scale: false, category: "objects" }, tv: { keywords: ["technology", "program", "oldschool", "show", "television"], char: "\u{1F4FA}", fitzpatrick_scale: false, category: "objects" }, radio: { keywords: ["communication", "music", "podcast", "program"], char: "\u{1F4FB}", fitzpatrick_scale: false, category: "objects" }, studio_microphone: { keywords: ["sing", "recording", "artist", "talkshow"], char: "\u{1F399}", fitzpatrick_scale: false, category: "objects" }, level_slider: { keywords: ["scale"], char: "\u{1F39A}", fitzpatrick_scale: false, category: "objects" }, control_knobs: { keywords: ["dial"], char: "\u{1F39B}", fitzpatrick_scale: false, category: "objects" }, compass: { keywords: ["magnetic", "navigation", "orienteering"], char: "\u{1F9ED}", fitzpatrick_scale: false, category: "objects" }, stopwatch: { keywords: ["time", "deadline"], char: "\u23F1", fitzpatrick_scale: false, category: "objects" }, timer_clock: { keywords: ["alarm"], char: "\u23F2", fitzpatrick_scale: false, category: "objects" }, alarm_clock: { keywords: ["time", "wake"], char: "\u23F0", fitzpatrick_scale: false, category: "objects" }, mantelpiece_clock: { keywords: ["time"], char: "\u{1F570}", fitzpatrick_scale: false, category: "objects" }, hourglass_flowing_sand: { keywords: ["oldschool", "time", "countdown"], char: "\u23F3", fitzpatrick_scale: false, category: "objects" }, hourglass: { keywords: ["time", "clock", "oldschool", "limit", "exam", "quiz", "test"], char: "\u231B", fitzpatrick_scale: false, category: "objects" }, satellite: { keywords: ["communication", "future", "radio", "space"], char: "\u{1F4E1}", fitzpatrick_scale: false, category: "objects" }, battery: { keywords: ["power", "energy", "sustain"], char: "\u{1F50B}", fitzpatrick_scale: false, category: "objects" }, electric_plug: { keywords: ["charger", "power"], char: "\u{1F50C}", fitzpatrick_scale: false, category: "objects" }, bulb: { keywords: ["light", "electricity", "idea"], char: "\u{1F4A1}", fitzpatrick_scale: false, category: "objects" }, flashlight: { keywords: ["dark", "camping", "sight", "night"], char: "\u{1F526}", fitzpatrick_scale: false, category: "objects" }, candle: { keywords: ["fire", "wax"], char: "\u{1F56F}", fitzpatrick_scale: false, category: "objects" }, fire_extinguisher: { keywords: ["quench"], char: "\u{1F9EF}", fitzpatrick_scale: false, category: "objects" }, wastebasket: { keywords: ["bin", "trash", "rubbish", "garbage", "toss"], char: "\u{1F5D1}", fitzpatrick_scale: false, category: "objects" }, oil_drum: { keywords: ["barrell"], char: "\u{1F6E2}", fitzpatrick_scale: false, category: "objects" }, money_with_wings: { keywords: ["dollar", "bills", "payment", "sale"], char: "\u{1F4B8}", fitzpatrick_scale: false, category: "objects" }, dollar: { keywords: ["money", "sales", "bill", "currency"], char: "\u{1F4B5}", fitzpatrick_scale: false, category: "objects" }, yen: { keywords: ["money", "sales", "japanese", "dollar", "currency"], char: "\u{1F4B4}", fitzpatrick_scale: false, category: "objects" }, euro: { keywords: ["money", "sales", "dollar", "currency"], char: "\u{1F4B6}", fitzpatrick_scale: false, category: "objects" }, pound: { keywords: ["british", "sterling", "money", "sales", "bills", "uk", "england", "currency"], char: "\u{1F4B7}", fitzpatrick_scale: false, category: "objects" }, moneybag: { keywords: ["dollar", "payment", "coins", "sale"], char: "\u{1F4B0}", fitzpatrick_scale: false, category: "objects" }, credit_card: { keywords: ["money", "sales", "dollar", "bill", "payment", "shopping"], char: "\u{1F4B3}", fitzpatrick_scale: false, category: "objects" }, gem: { keywords: ["blue", "ruby", "diamond", "jewelry"], char: "\u{1F48E}", fitzpatrick_scale: false, category: "objects" }, balance_scale: { keywords: ["law", "fairness", "weight"], char: "\u2696", fitzpatrick_scale: false, category: "objects" }, toolbox: { keywords: ["tools", "diy", "fix", "maintainer", "mechanic"], char: "\u{1F9F0}", fitzpatrick_scale: false, category: "objects" }, wrench: { keywords: ["tools", "diy", "ikea", "fix", "maintainer"], char: "\u{1F527}", fitzpatrick_scale: false, category: "objects" }, hammer: { keywords: ["tools", "build", "create"], char: "\u{1F528}", fitzpatrick_scale: false, category: "objects" }, hammer_and_pick: { keywords: ["tools", "build", "create"], char: "\u2692", fitzpatrick_scale: false, category: "objects" }, hammer_and_wrench: { keywords: ["tools", "build", "create"], char: "\u{1F6E0}", fitzpatrick_scale: false, category: "objects" }, pick: { keywords: ["tools", "dig"], char: "\u26CF", fitzpatrick_scale: false, category: "objects" }, nut_and_bolt: { keywords: ["handy", "tools", "fix"], char: "\u{1F529}", fitzpatrick_scale: false, category: "objects" }, gear: { keywords: ["cog"], char: "\u2699", fitzpatrick_scale: false, category: "objects" }, brick: { keywords: ["bricks"], char: "\u{1F9F1}", fitzpatrick_scale: false, category: "objects" }, chains: { keywords: ["lock", "arrest"], char: "\u26D3", fitzpatrick_scale: false, category: "objects" }, magnet: { keywords: ["attraction", "magnetic"], char: "\u{1F9F2}", fitzpatrick_scale: false, category: "objects" }, gun: { keywords: ["violence", "weapon", "pistol", "revolver"], char: "\u{1F52B}", fitzpatrick_scale: false, category: "objects" }, bomb: { keywords: ["boom", "explode", "explosion", "terrorism"], char: "\u{1F4A3}", fitzpatrick_scale: false, category: "objects" }, firecracker: { keywords: ["dynamite", "boom", "explode", "explosion", "explosive"], char: "\u{1F9E8}", fitzpatrick_scale: false, category: "objects" }, hocho: { keywords: ["knife", "blade", "cutlery", "kitchen", "weapon"], char: "\u{1F52A}", fitzpatrick_scale: false, category: "objects" }, dagger: { keywords: ["weapon"], char: "\u{1F5E1}", fitzpatrick_scale: false, category: "objects" }, crossed_swords: { keywords: ["weapon"], char: "\u2694", fitzpatrick_scale: false, category: "objects" }, shield: { keywords: ["protection", "security"], char: "\u{1F6E1}", fitzpatrick_scale: false, category: "objects" }, smoking: { keywords: ["kills", "tobacco", "cigarette", "joint", "smoke"], char: "\u{1F6AC}", fitzpatrick_scale: false, category: "objects" }, skull_and_crossbones: { keywords: ["poison", "danger", "deadly", "scary", "death", "pirate", "evil"], char: "\u2620", fitzpatrick_scale: false, category: "objects" }, coffin: { keywords: ["vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box"], char: "\u26B0", fitzpatrick_scale: false, category: "objects" }, funeral_urn: { keywords: ["dead", "die", "death", "rip", "ashes"], char: "\u26B1", fitzpatrick_scale: false, category: "objects" }, amphora: { keywords: ["vase", "jar"], char: "\u{1F3FA}", fitzpatrick_scale: false, category: "objects" }, crystal_ball: { keywords: ["disco", "party", "magic", "circus", "fortune_teller"], char: "\u{1F52E}", fitzpatrick_scale: false, category: "objects" }, prayer_beads: { keywords: ["dhikr", "religious"], char: "\u{1F4FF}", fitzpatrick_scale: false, category: "objects" }, nazar_amulet: { keywords: ["bead", "charm"], char: "\u{1F9FF}", fitzpatrick_scale: false, category: "objects" }, barber: { keywords: ["hair", "salon", "style"], char: "\u{1F488}", fitzpatrick_scale: false, category: "objects" }, alembic: { keywords: ["distilling", "science", "experiment", "chemistry"], char: "\u2697", fitzpatrick_scale: false, category: "objects" }, telescope: { keywords: ["stars", "space", "zoom", "science", "astronomy"], char: "\u{1F52D}", fitzpatrick_scale: false, category: "objects" }, microscope: { keywords: ["laboratory", "experiment", "zoomin", "science", "study"], char: "\u{1F52C}", fitzpatrick_scale: false, category: "objects" }, hole: { keywords: ["embarrassing"], char: "\u{1F573}", fitzpatrick_scale: false, category: "objects" }, pill: { keywords: ["health", "medicine", "doctor", "pharmacy", "drug"], char: "\u{1F48A}", fitzpatrick_scale: false, category: "objects" }, syringe: { keywords: ["health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse"], char: "\u{1F489}", fitzpatrick_scale: false, category: "objects" }, dna: { keywords: ["biologist", "genetics", "life"], char: "\u{1F9EC}", fitzpatrick_scale: false, category: "objects" }, microbe: { keywords: ["amoeba", "bacteria", "germs"], char: "\u{1F9A0}", fitzpatrick_scale: false, category: "objects" }, petri_dish: { keywords: ["bacteria", "biology", "culture", "lab"], char: "\u{1F9EB}", fitzpatrick_scale: false, category: "objects" }, test_tube: { keywords: ["chemistry", "experiment", "lab", "science"], char: "\u{1F9EA}", fitzpatrick_scale: false, category: "objects" }, thermometer: { keywords: ["weather", "temperature", "hot", "cold"], char: "\u{1F321}", fitzpatrick_scale: false, category: "objects" }, broom: { keywords: ["cleaning", "sweeping", "witch"], char: "\u{1F9F9}", fitzpatrick_scale: false, category: "objects" }, basket: { keywords: ["laundry"], char: "\u{1F9FA}", fitzpatrick_scale: false, category: "objects" }, toilet_paper: { keywords: ["roll"], char: "\u{1F9FB}", fitzpatrick_scale: false, category: "objects" }, label: { keywords: ["sale", "tag"], char: "\u{1F3F7}", fitzpatrick_scale: false, category: "objects" }, bookmark: { keywords: ["favorite", "label", "save"], char: "\u{1F516}", fitzpatrick_scale: false, category: "objects" }, toilet: { keywords: ["restroom", "wc", "washroom", "bathroom", "potty"], char: "\u{1F6BD}", fitzpatrick_scale: false, category: "objects" }, shower: { keywords: ["clean", "water", "bathroom"], char: "\u{1F6BF}", fitzpatrick_scale: false, category: "objects" }, bathtub: { keywords: ["clean", "shower", "bathroom"], char: "\u{1F6C1}", fitzpatrick_scale: false, category: "objects" }, soap: { keywords: ["bar", "bathing", "cleaning", "lather"], char: "\u{1F9FC}", fitzpatrick_scale: false, category: "objects" }, sponge: { keywords: ["absorbing", "cleaning", "porous"], char: "\u{1F9FD}", fitzpatrick_scale: false, category: "objects" }, lotion_bottle: { keywords: ["moisturizer", "sunscreen"], char: "\u{1F9F4}", fitzpatrick_scale: false, category: "objects" }, key: { keywords: ["lock", "door", "password"], char: "\u{1F511}", fitzpatrick_scale: false, category: "objects" }, old_key: { keywords: ["lock", "door", "password"], char: "\u{1F5DD}", fitzpatrick_scale: false, category: "objects" }, couch_and_lamp: { keywords: ["read", "chill"], char: "\u{1F6CB}", fitzpatrick_scale: false, category: "objects" }, sleeping_bed: { keywords: ["bed", "rest"], char: "\u{1F6CC}", fitzpatrick_scale: true, category: "objects" }, bed: { keywords: ["sleep", "rest"], char: "\u{1F6CF}", fitzpatrick_scale: false, category: "objects" }, door: { keywords: ["house", "entry", "exit"], char: "\u{1F6AA}", fitzpatrick_scale: false, category: "objects" }, bellhop_bell: { keywords: ["service"], char: "\u{1F6CE}", fitzpatrick_scale: false, category: "objects" }, teddy_bear: { keywords: ["plush", "stuffed"], char: "\u{1F9F8}", fitzpatrick_scale: false, category: "objects" }, framed_picture: { keywords: ["photography"], char: "\u{1F5BC}", fitzpatrick_scale: false, category: "objects" }, world_map: { keywords: ["location", "direction"], char: "\u{1F5FA}", fitzpatrick_scale: false, category: "objects" }, parasol_on_ground: { keywords: ["weather", "summer"], char: "\u26F1", fitzpatrick_scale: false, category: "objects" }, moyai: { keywords: ["rock", "easter island", "moai"], char: "\u{1F5FF}", fitzpatrick_scale: false, category: "objects" }, shopping: { keywords: ["mall", "buy", "purchase"], char: "\u{1F6CD}", fitzpatrick_scale: false, category: "objects" }, shopping_cart: { keywords: ["trolley"], char: "\u{1F6D2}", fitzpatrick_scale: false, category: "objects" }, balloon: { keywords: ["party", "celebration", "birthday", "circus"], char: "\u{1F388}", fitzpatrick_scale: false, category: "objects" }, flags: { keywords: ["fish", "japanese", "koinobori", "carp", "banner"], char: "\u{1F38F}", fitzpatrick_scale: false, category: "objects" }, ribbon: { keywords: ["decoration", "pink", "girl", "bowtie"], char: "\u{1F380}", fitzpatrick_scale: false, category: "objects" }, gift: { keywords: ["present", "birthday", "christmas", "xmas"], char: "\u{1F381}", fitzpatrick_scale: false, category: "objects" }, confetti_ball: { keywords: ["festival", "party", "birthday", "circus"], char: "\u{1F38A}", fitzpatrick_scale: false, category: "objects" }, tada: { keywords: ["party", "congratulations", "birthday", "magic", "circus", "celebration"], char: "\u{1F389}", fitzpatrick_scale: false, category: "objects" }, dolls: { keywords: ["japanese", "toy", "kimono"], char: "\u{1F38E}", fitzpatrick_scale: false, category: "objects" }, wind_chime: { keywords: ["nature", "ding", "spring", "bell"], char: "\u{1F390}", fitzpatrick_scale: false, category: "objects" }, crossed_flags: { keywords: ["japanese", "nation", "country", "border"], char: "\u{1F38C}", fitzpatrick_scale: false, category: "objects" }, izakaya_lantern: { keywords: ["light", "paper", "halloween", "spooky"], char: "\u{1F3EE}", fitzpatrick_scale: false, category: "objects" }, red_envelope: { keywords: ["gift"], char: "\u{1F9E7}", fitzpatrick_scale: false, category: "objects" }, email: { keywords: ["letter", "postal", "inbox", "communication"], char: "\u2709\uFE0F", fitzpatrick_scale: false, category: "objects" }, envelope_with_arrow: { keywords: ["email", "communication"], char: "\u{1F4E9}", fitzpatrick_scale: false, category: "objects" }, incoming_envelope: { keywords: ["email", "inbox"], char: "\u{1F4E8}", fitzpatrick_scale: false, category: "objects" }, "e-mail": { keywords: ["communication", "inbox"], char: "\u{1F4E7}", fitzpatrick_scale: false, category: "objects" }, love_letter: { keywords: ["email", "like", "affection", "envelope", "valentines"], char: "\u{1F48C}", fitzpatrick_scale: false, category: "objects" }, postbox: { keywords: ["email", "letter", "envelope"], char: "\u{1F4EE}", fitzpatrick_scale: false, category: "objects" }, mailbox_closed: { keywords: ["email", "communication", "inbox"], char: "\u{1F4EA}", fitzpatrick_scale: false, category: "objects" }, mailbox: { keywords: ["email", "inbox", "communication"], char: "\u{1F4EB}", fitzpatrick_scale: false, category: "objects" }, mailbox_with_mail: { keywords: ["email", "inbox", "communication"], char: "\u{1F4EC}", fitzpatrick_scale: false, category: "objects" }, mailbox_with_no_mail: { keywords: ["email", "inbox"], char: "\u{1F4ED}", fitzpatrick_scale: false, category: "objects" }, package: { keywords: ["mail", "gift", "cardboard", "box", "moving"], char: "\u{1F4E6}", fitzpatrick_scale: false, category: "objects" }, postal_horn: { keywords: ["instrument", "music"], char: "\u{1F4EF}", fitzpatrick_scale: false, category: "objects" }, inbox_tray: { keywords: ["email", "documents"], char: "\u{1F4E5}", fitzpatrick_scale: false, category: "objects" }, outbox_tray: { keywords: ["inbox", "email"], char: "\u{1F4E4}", fitzpatrick_scale: false, category: "objects" }, scroll: { keywords: ["documents", "ancient", "history", "paper"], char: "\u{1F4DC}", fitzpatrick_scale: false, category: "objects" }, page_with_curl: { keywords: ["documents", "office", "paper"], char: "\u{1F4C3}", fitzpatrick_scale: false, category: "objects" }, bookmark_tabs: { keywords: ["favorite", "save", "order", "tidy"], char: "\u{1F4D1}", fitzpatrick_scale: false, category: "objects" }, receipt: { keywords: ["accounting", "expenses"], char: "\u{1F9FE}", fitzpatrick_scale: false, category: "objects" }, bar_chart: { keywords: ["graph", "presentation", "stats"], char: "\u{1F4CA}", fitzpatrick_scale: false, category: "objects" }, chart_with_upwards_trend: { keywords: ["graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success"], char: "\u{1F4C8}", fitzpatrick_scale: false, category: "objects" }, chart_with_downwards_trend: { keywords: ["graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure"], char: "\u{1F4C9}", fitzpatrick_scale: false, category: "objects" }, page_facing_up: { keywords: ["documents", "office", "paper", "information"], char: "\u{1F4C4}", fitzpatrick_scale: false, category: "objects" }, date: { keywords: ["calendar", "schedule"], char: "\u{1F4C5}", fitzpatrick_scale: false, category: "objects" }, calendar: { keywords: ["schedule", "date", "planning"], char: "\u{1F4C6}", fitzpatrick_scale: false, category: "objects" }, spiral_calendar: { keywords: ["date", "schedule", "planning"], char: "\u{1F5D3}", fitzpatrick_scale: false, category: "objects" }, card_index: { keywords: ["business", "stationery"], char: "\u{1F4C7}", fitzpatrick_scale: false, category: "objects" }, card_file_box: { keywords: ["business", "stationery"], char: "\u{1F5C3}", fitzpatrick_scale: false, category: "objects" }, ballot_box: { keywords: ["election", "vote"], char: "\u{1F5F3}", fitzpatrick_scale: false, category: "objects" }, file_cabinet: { keywords: ["filing", "organizing"], char: "\u{1F5C4}", fitzpatrick_scale: false, category: "objects" }, clipboard: { keywords: ["stationery", "documents"], char: "\u{1F4CB}", fitzpatrick_scale: false, category: "objects" }, spiral_notepad: { keywords: ["memo", "stationery"], char: "\u{1F5D2}", fitzpatrick_scale: false, category: "objects" }, file_folder: { keywords: ["documents", "business", "office"], char: "\u{1F4C1}", fitzpatrick_scale: false, category: "objects" }, open_file_folder: { keywords: ["documents", "load"], char: "\u{1F4C2}", fitzpatrick_scale: false, category: "objects" }, card_index_dividers: { keywords: ["organizing", "business", "stationery"], char: "\u{1F5C2}", fitzpatrick_scale: false, category: "objects" }, newspaper_roll: { keywords: ["press", "headline"], char: "\u{1F5DE}", fitzpatrick_scale: false, category: "objects" }, newspaper: { keywords: ["press", "headline"], char: "\u{1F4F0}", fitzpatrick_scale: false, category: "objects" }, notebook: { keywords: ["stationery", "record", "notes", "paper", "study"], char: "\u{1F4D3}", fitzpatrick_scale: false, category: "objects" }, closed_book: { keywords: ["read", "library", "knowledge", "textbook", "learn"], char: "\u{1F4D5}", fitzpatrick_scale: false, category: "objects" }, green_book: { keywords: ["read", "library", "knowledge", "study"], char: "\u{1F4D7}", fitzpatrick_scale: false, category: "objects" }, blue_book: { keywords: ["read", "library", "knowledge", "learn", "study"], char: "\u{1F4D8}", fitzpatrick_scale: false, category: "objects" }, orange_book: { keywords: ["read", "library", "knowledge", "textbook", "study"], char: "\u{1F4D9}", fitzpatrick_scale: false, category: "objects" }, notebook_with_decorative_cover: { keywords: ["classroom", "notes", "record", "paper", "study"], char: "\u{1F4D4}", fitzpatrick_scale: false, category: "objects" }, ledger: { keywords: ["notes", "paper"], char: "\u{1F4D2}", fitzpatrick_scale: false, category: "objects" }, books: { keywords: ["literature", "library", "study"], char: "\u{1F4DA}", fitzpatrick_scale: false, category: "objects" }, open_book: { keywords: ["book", "read", "library", "knowledge", "literature", "learn", "study"], char: "\u{1F4D6}", fitzpatrick_scale: false, category: "objects" }, safety_pin: { keywords: ["diaper"], char: "\u{1F9F7}", fitzpatrick_scale: false, category: "objects" }, link: { keywords: ["rings", "url"], char: "\u{1F517}", fitzpatrick_scale: false, category: "objects" }, paperclip: { keywords: ["documents", "stationery"], char: "\u{1F4CE}", fitzpatrick_scale: false, category: "objects" }, paperclips: { keywords: ["documents", "stationery"], char: "\u{1F587}", fitzpatrick_scale: false, category: "objects" }, scissors: { keywords: ["stationery", "cut"], char: "\u2702\uFE0F", fitzpatrick_scale: false, category: "objects" }, triangular_ruler: { keywords: ["stationery", "math", "architect", "sketch"], char: "\u{1F4D0}", fitzpatrick_scale: false, category: "objects" }, straight_ruler: { keywords: ["stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch"], char: "\u{1F4CF}", fitzpatrick_scale: false, category: "objects" }, abacus: { keywords: ["calculation"], char: "\u{1F9EE}", fitzpatrick_scale: false, category: "objects" }, pushpin: { keywords: ["stationery", "mark", "here"], char: "\u{1F4CC}", fitzpatrick_scale: false, category: "objects" }, round_pushpin: { keywords: ["stationery", "location", "map", "here"], char: "\u{1F4CD}", fitzpatrick_scale: false, category: "objects" }, triangular_flag_on_post: { keywords: ["mark", "milestone", "place"], char: "\u{1F6A9}", fitzpatrick_scale: false, category: "objects" }, white_flag: { keywords: ["losing", "loser", "lost", "surrender", "give up", "fail"], char: "\u{1F3F3}", fitzpatrick_scale: false, category: "objects" }, black_flag: { keywords: ["pirate"], char: "\u{1F3F4}", fitzpatrick_scale: false, category: "objects" }, rainbow_flag: { keywords: ["flag", "rainbow", "pride", "gay", "lgbt", "glbt", "queer", "homosexual", "lesbian", "bisexual", "transgender"], char: "\u{1F3F3}\uFE0F\u200D\u{1F308}", fitzpatrick_scale: false, category: "objects" }, closed_lock_with_key: { keywords: ["security", "privacy"], char: "\u{1F510}", fitzpatrick_scale: false, category: "objects" }, lock: { keywords: ["security", "password", "padlock"], char: "\u{1F512}", fitzpatrick_scale: false, category: "objects" }, unlock: { keywords: ["privacy", "security"], char: "\u{1F513}", fitzpatrick_scale: false, category: "objects" }, lock_with_ink_pen: { keywords: ["security", "secret"], char: "\u{1F50F}", fitzpatrick_scale: false, category: "objects" }, pen: { keywords: ["stationery", "writing", "write"], char: "\u{1F58A}", fitzpatrick_scale: false, category: "objects" }, fountain_pen: { keywords: ["stationery", "writing", "write"], char: "\u{1F58B}", fitzpatrick_scale: false, category: "objects" }, black_nib: { keywords: ["pen", "stationery", "writing", "write"], char: "\u2712\uFE0F", fitzpatrick_scale: false, category: "objects" }, memo: { keywords: ["write", "documents", "stationery", "pencil", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose"], char: "\u{1F4DD}", fitzpatrick_scale: false, category: "objects" }, pencil2: { keywords: ["stationery", "write", "paper", "writing", "school", "study"], char: "\u270F\uFE0F", fitzpatrick_scale: false, category: "objects" }, crayon: { keywords: ["drawing", "creativity"], char: "\u{1F58D}", fitzpatrick_scale: false, category: "objects" }, paintbrush: { keywords: ["drawing", "creativity", "art"], char: "\u{1F58C}", fitzpatrick_scale: false, category: "objects" }, mag: { keywords: ["search", "zoom", "find", "detective"], char: "\u{1F50D}", fitzpatrick_scale: false, category: "objects" }, mag_right: { keywords: ["search", "zoom", "find", "detective"], char: "\u{1F50E}", fitzpatrick_scale: false, category: "objects" }, heart: { keywords: ["love", "like", "valentines"], char: "\u2764\uFE0F", fitzpatrick_scale: false, category: "symbols" }, orange_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F9E1}", fitzpatrick_scale: false, category: "symbols" }, yellow_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F49B}", fitzpatrick_scale: false, category: "symbols" }, green_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F49A}", fitzpatrick_scale: false, category: "symbols" }, blue_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F499}", fitzpatrick_scale: false, category: "symbols" }, purple_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F49C}", fitzpatrick_scale: false, category: "symbols" }, black_heart: { keywords: ["evil"], char: "\u{1F5A4}", fitzpatrick_scale: false, category: "symbols" }, broken_heart: { keywords: ["sad", "sorry", "break", "heart", "heartbreak"], char: "\u{1F494}", fitzpatrick_scale: false, category: "symbols" }, heavy_heart_exclamation: { keywords: ["decoration", "love"], char: "\u2763", fitzpatrick_scale: false, category: "symbols" }, two_hearts: { keywords: ["love", "like", "affection", "valentines", "heart"], char: "\u{1F495}", fitzpatrick_scale: false, category: "symbols" }, revolving_hearts: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F49E}", fitzpatrick_scale: false, category: "symbols" }, heartbeat: { keywords: ["love", "like", "affection", "valentines", "pink", "heart"], char: "\u{1F493}", fitzpatrick_scale: false, category: "symbols" }, heartpulse: { keywords: ["like", "love", "affection", "valentines", "pink"], char: "\u{1F497}", fitzpatrick_scale: false, category: "symbols" }, sparkling_heart: { keywords: ["love", "like", "affection", "valentines"], char: "\u{1F496}", fitzpatrick_scale: false, category: "symbols" }, cupid: { keywords: ["love", "like", "heart", "affection", "valentines"], char: "\u{1F498}", fitzpatrick_scale: false, category: "symbols" }, gift_heart: { keywords: ["love", "valentines"], char: "\u{1F49D}", fitzpatrick_scale: false, category: "symbols" }, heart_decoration: { keywords: ["purple-square", "love", "like"], char: "\u{1F49F}", fitzpatrick_scale: false, category: "symbols" }, peace_symbol: { keywords: ["hippie"], char: "\u262E", fitzpatrick_scale: false, category: "symbols" }, latin_cross: { keywords: ["christianity"], char: "\u271D", fitzpatrick_scale: false, category: "symbols" }, star_and_crescent: { keywords: ["islam"], char: "\u262A", fitzpatrick_scale: false, category: "symbols" }, om: { keywords: ["hinduism", "buddhism", "sikhism", "jainism"], char: "\u{1F549}", fitzpatrick_scale: false, category: "symbols" }, wheel_of_dharma: { keywords: ["hinduism", "buddhism", "sikhism", "jainism"], char: "\u2638", fitzpatrick_scale: false, category: "symbols" }, star_of_david: { keywords: ["judaism"], char: "\u2721", fitzpatrick_scale: false, category: "symbols" }, six_pointed_star: { keywords: ["purple-square", "religion", "jewish", "hexagram"], char: "\u{1F52F}", fitzpatrick_scale: false, category: "symbols" }, menorah: { keywords: ["hanukkah", "candles", "jewish"], char: "\u{1F54E}", fitzpatrick_scale: false, category: "symbols" }, yin_yang: { keywords: ["balance"], char: "\u262F", fitzpatrick_scale: false, category: "symbols" }, orthodox_cross: { keywords: ["suppedaneum", "religion"], char: "\u2626", fitzpatrick_scale: false, category: "symbols" }, place_of_worship: { keywords: ["religion", "church", "temple", "prayer"], char: "\u{1F6D0}", fitzpatrick_scale: false, category: "symbols" }, ophiuchus: { keywords: ["sign", "purple-square", "constellation", "astrology"], char: "\u26CE", fitzpatrick_scale: false, category: "symbols" }, aries: { keywords: ["sign", "purple-square", "zodiac", "astrology"], char: "\u2648", fitzpatrick_scale: false, category: "symbols" }, taurus: { keywords: ["purple-square", "sign", "zodiac", "astrology"], char: "\u2649", fitzpatrick_scale: false, category: "symbols" }, gemini: { keywords: ["sign", "zodiac", "purple-square", "astrology"], char: "\u264A", fitzpatrick_scale: false, category: "symbols" }, cancer: { keywords: ["sign", "zodiac", "purple-square", "astrology"], char: "\u264B", fitzpatrick_scale: false, category: "symbols" }, leo: { keywords: ["sign", "purple-square", "zodiac", "astrology"], char: "\u264C", fitzpatrick_scale: false, category: "symbols" }, virgo: { keywords: ["sign", "zodiac", "purple-square", "astrology"], char: "\u264D", fitzpatrick_scale: false, category: "symbols" }, libra: { keywords: ["sign", "purple-square", "zodiac", "astrology"], char: "\u264E", fitzpatrick_scale: false, category: "symbols" }, scorpius: { keywords: ["sign", "zodiac", "purple-square", "astrology", "scorpio"], char: "\u264F", fitzpatrick_scale: false, category: "symbols" }, sagittarius: { keywords: ["sign", "zodiac", "purple-square", "astrology"], char: "\u2650", fitzpatrick_scale: false, category: "symbols" }, capricorn: { keywords: ["sign", "zodiac", "purple-square", "astrology"], char: "\u2651", fitzpatrick_scale: false, category: "symbols" }, aquarius: { keywords: ["sign", "purple-square", "zodiac", "astrology"], char: "\u2652", fitzpatrick_scale: false, category: "symbols" }, pisces: { keywords: ["purple-square", "sign", "zodiac", "astrology"], char: "\u2653", fitzpatrick_scale: false, category: "symbols" }, id: { keywords: ["purple-square", "words"], char: "\u{1F194}", fitzpatrick_scale: false, category: "symbols" }, atom_symbol: { keywords: ["science", "physics", "chemistry"], char: "\u269B", fitzpatrick_scale: false, category: "symbols" }, u7a7a: { keywords: ["kanji", "japanese", "chinese", "empty", "sky", "blue-square"], char: "\u{1F233}", fitzpatrick_scale: false, category: "symbols" }, u5272: { keywords: ["cut", "divide", "chinese", "kanji", "pink-square"], char: "\u{1F239}", fitzpatrick_scale: false, category: "symbols" }, radioactive: { keywords: ["nuclear", "danger"], char: "\u2622", fitzpatrick_scale: false, category: "symbols" }, biohazard: { keywords: ["danger"], char: "\u2623", fitzpatrick_scale: false, category: "symbols" }, mobile_phone_off: { keywords: ["mute", "orange-square", "silence", "quiet"], char: "\u{1F4F4}", fitzpatrick_scale: false, category: "symbols" }, vibration_mode: { keywords: ["orange-square", "phone"], char: "\u{1F4F3}", fitzpatrick_scale: false, category: "symbols" }, u6709: { keywords: ["orange-square", "chinese", "have", "kanji"], char: "\u{1F236}", fitzpatrick_scale: false, category: "symbols" }, u7121: { keywords: ["nothing", "chinese", "kanji", "japanese", "orange-square"], char: "\u{1F21A}", fitzpatrick_scale: false, category: "symbols" }, u7533: { keywords: ["chinese", "japanese", "kanji", "orange-square"], char: "\u{1F238}", fitzpatrick_scale: false, category: "symbols" }, u55b6: { keywords: ["japanese", "opening hours", "orange-square"], char: "\u{1F23A}", fitzpatrick_scale: false, category: "symbols" }, u6708: { keywords: ["chinese", "month", "moon", "japanese", "orange-square", "kanji"], char: "\u{1F237}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, eight_pointed_black_star: { keywords: ["orange-square", "shape", "polygon"], char: "\u2734\uFE0F", fitzpatrick_scale: false, category: "symbols" }, vs: { keywords: ["words", "orange-square"], char: "\u{1F19A}", fitzpatrick_scale: false, category: "symbols" }, accept: { keywords: ["ok", "good", "chinese", "kanji", "agree", "yes", "orange-circle"], char: "\u{1F251}", fitzpatrick_scale: false, category: "symbols" }, white_flower: { keywords: ["japanese", "spring"], char: "\u{1F4AE}", fitzpatrick_scale: false, category: "symbols" }, ideograph_advantage: { keywords: ["chinese", "kanji", "obtain", "get", "circle"], char: "\u{1F250}", fitzpatrick_scale: false, category: "symbols" }, secret: { keywords: ["privacy", "chinese", "sshh", "kanji", "red-circle"], char: "\u3299\uFE0F", fitzpatrick_scale: false, category: "symbols" }, congratulations: { keywords: ["chinese", "kanji", "japanese", "red-circle"], char: "\u3297\uFE0F", fitzpatrick_scale: false, category: "symbols" }, u5408: { keywords: ["japanese", "chinese", "join", "kanji", "red-square"], char: "\u{1F234}", fitzpatrick_scale: false, category: "symbols" }, u6e80: { keywords: ["full", "chinese", "japanese", "red-square", "kanji"], char: "\u{1F235}", fitzpatrick_scale: false, category: "symbols" }, u7981: { keywords: ["kanji", "japanese", "chinese", "forbidden", "limit", "restricted", "red-square"], char: "\u{1F232}", fitzpatrick_scale: false, category: "symbols" }, a: { keywords: ["red-square", "alphabet", "letter"], char: "\u{1F170}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, b: { keywords: ["red-square", "alphabet", "letter"], char: "\u{1F171}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, ab: { keywords: ["red-square", "alphabet"], char: "\u{1F18E}", fitzpatrick_scale: false, category: "symbols" }, cl: { keywords: ["alphabet", "words", "red-square"], char: "\u{1F191}", fitzpatrick_scale: false, category: "symbols" }, o2: { keywords: ["alphabet", "red-square", "letter"], char: "\u{1F17E}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, sos: { keywords: ["help", "red-square", "words", "emergency", "911"], char: "\u{1F198}", fitzpatrick_scale: false, category: "symbols" }, no_entry: { keywords: ["limit", "security", "privacy", "bad", "denied", "stop", "circle"], char: "\u26D4", fitzpatrick_scale: false, category: "symbols" }, name_badge: { keywords: ["fire", "forbid"], char: "\u{1F4DB}", fitzpatrick_scale: false, category: "symbols" }, no_entry_sign: { keywords: ["forbid", "stop", "limit", "denied", "disallow", "circle"], char: "\u{1F6AB}", fitzpatrick_scale: false, category: "symbols" }, x: { keywords: ["no", "delete", "remove", "cancel", "red"], char: "\u274C", fitzpatrick_scale: false, category: "symbols" }, o: { keywords: ["circle", "round"], char: "\u2B55", fitzpatrick_scale: false, category: "symbols" }, stop_sign: { keywords: ["stop"], char: "\u{1F6D1}", fitzpatrick_scale: false, category: "symbols" }, anger: { keywords: ["angry", "mad"], char: "\u{1F4A2}", fitzpatrick_scale: false, category: "symbols" }, hotsprings: { keywords: ["bath", "warm", "relax"], char: "\u2668\uFE0F", fitzpatrick_scale: false, category: "symbols" }, no_pedestrians: { keywords: ["rules", "crossing", "walking", "circle"], char: "\u{1F6B7}", fitzpatrick_scale: false, category: "symbols" }, do_not_litter: { keywords: ["trash", "bin", "garbage", "circle"], char: "\u{1F6AF}", fitzpatrick_scale: false, category: "symbols" }, no_bicycles: { keywords: ["cyclist", "prohibited", "circle"], char: "\u{1F6B3}", fitzpatrick_scale: false, category: "symbols" }, "non-potable_water": { keywords: ["drink", "faucet", "tap", "circle"], char: "\u{1F6B1}", fitzpatrick_scale: false, category: "symbols" }, underage: { keywords: ["18", "drink", "pub", "night", "minor", "circle"], char: "\u{1F51E}", fitzpatrick_scale: false, category: "symbols" }, no_mobile_phones: { keywords: ["iphone", "mute", "circle"], char: "\u{1F4F5}", fitzpatrick_scale: false, category: "symbols" }, exclamation: { keywords: ["heavy_exclamation_mark", "danger", "surprise", "punctuation", "wow", "warning"], char: "\u2757", fitzpatrick_scale: false, category: "symbols" }, grey_exclamation: { keywords: ["surprise", "punctuation", "gray", "wow", "warning"], char: "\u2755", fitzpatrick_scale: false, category: "symbols" }, question: { keywords: ["doubt", "confused"], char: "\u2753", fitzpatrick_scale: false, category: "symbols" }, grey_question: { keywords: ["doubts", "gray", "huh", "confused"], char: "\u2754", fitzpatrick_scale: false, category: "symbols" }, bangbang: { keywords: ["exclamation", "surprise"], char: "\u203C\uFE0F", fitzpatrick_scale: false, category: "symbols" }, interrobang: { keywords: ["wat", "punctuation", "surprise"], char: "\u2049\uFE0F", fitzpatrick_scale: false, category: "symbols" }, 100: { keywords: ["score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass", "hundred"], char: "\u{1F4AF}", fitzpatrick_scale: false, category: "symbols" }, low_brightness: { keywords: ["sun", "afternoon", "warm", "summer"], char: "\u{1F505}", fitzpatrick_scale: false, category: "symbols" }, high_brightness: { keywords: ["sun", "light"], char: "\u{1F506}", fitzpatrick_scale: false, category: "symbols" }, trident: { keywords: ["weapon", "spear"], char: "\u{1F531}", fitzpatrick_scale: false, category: "symbols" }, fleur_de_lis: { keywords: ["decorative", "scout"], char: "\u269C", fitzpatrick_scale: false, category: "symbols" }, part_alternation_mark: { keywords: ["graph", "presentation", "stats", "business", "economics", "bad"], char: "\u303D\uFE0F", fitzpatrick_scale: false, category: "symbols" }, warning: { keywords: ["exclamation", "wip", "alert", "error", "problem", "issue"], char: "\u26A0\uFE0F", fitzpatrick_scale: false, category: "symbols" }, children_crossing: { keywords: ["school", "warning", "danger", "sign", "driving", "yellow-diamond"], char: "\u{1F6B8}", fitzpatrick_scale: false, category: "symbols" }, beginner: { keywords: ["badge", "shield"], char: "\u{1F530}", fitzpatrick_scale: false, category: "symbols" }, recycle: { keywords: ["arrow", "environment", "garbage", "trash"], char: "\u267B\uFE0F", fitzpatrick_scale: false, category: "symbols" }, u6307: { keywords: ["chinese", "point", "green-square", "kanji"], char: "\u{1F22F}", fitzpatrick_scale: false, category: "symbols" }, chart: { keywords: ["green-square", "graph", "presentation", "stats"], char: "\u{1F4B9}", fitzpatrick_scale: false, category: "symbols" }, sparkle: { keywords: ["stars", "green-square", "awesome", "good", "fireworks"], char: "\u2747\uFE0F", fitzpatrick_scale: false, category: "symbols" }, eight_spoked_asterisk: { keywords: ["star", "sparkle", "green-square"], char: "\u2733\uFE0F", fitzpatrick_scale: false, category: "symbols" }, negative_squared_cross_mark: { keywords: ["x", "green-square", "no", "deny"], char: "\u274E", fitzpatrick_scale: false, category: "symbols" }, white_check_mark: { keywords: ["green-square", "ok", "agree", "vote", "election", "answer", "tick"], char: "\u2705", fitzpatrick_scale: false, category: "symbols" }, diamond_shape_with_a_dot_inside: { keywords: ["jewel", "blue", "gem", "crystal", "fancy"], char: "\u{1F4A0}", fitzpatrick_scale: false, category: "symbols" }, cyclone: { keywords: ["weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon"], char: "\u{1F300}", fitzpatrick_scale: false, category: "symbols" }, loop: { keywords: ["tape", "cassette"], char: "\u27BF", fitzpatrick_scale: false, category: "symbols" }, globe_with_meridians: { keywords: ["earth", "international", "world", "internet", "interweb", "i18n"], char: "\u{1F310}", fitzpatrick_scale: false, category: "symbols" }, m: { keywords: ["alphabet", "blue-circle", "letter"], char: "\u24C2\uFE0F", fitzpatrick_scale: false, category: "symbols" }, atm: { keywords: ["money", "sales", "cash", "blue-square", "payment", "bank"], char: "\u{1F3E7}", fitzpatrick_scale: false, category: "symbols" }, sa: { keywords: ["japanese", "blue-square", "katakana"], char: "\u{1F202}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, passport_control: { keywords: ["custom", "blue-square"], char: "\u{1F6C2}", fitzpatrick_scale: false, category: "symbols" }, customs: { keywords: ["passport", "border", "blue-square"], char: "\u{1F6C3}", fitzpatrick_scale: false, category: "symbols" }, baggage_claim: { keywords: ["blue-square", "airport", "transport"], char: "\u{1F6C4}", fitzpatrick_scale: false, category: "symbols" }, left_luggage: { keywords: ["blue-square", "travel"], char: "\u{1F6C5}", fitzpatrick_scale: false, category: "symbols" }, wheelchair: { keywords: ["blue-square", "disabled", "a11y", "accessibility"], char: "\u267F", fitzpatrick_scale: false, category: "symbols" }, no_smoking: { keywords: ["cigarette", "blue-square", "smell", "smoke"], char: "\u{1F6AD}", fitzpatrick_scale: false, category: "symbols" }, wc: { keywords: ["toilet", "restroom", "blue-square"], char: "\u{1F6BE}", fitzpatrick_scale: false, category: "symbols" }, parking: { keywords: ["cars", "blue-square", "alphabet", "letter"], char: "\u{1F17F}\uFE0F", fitzpatrick_scale: false, category: "symbols" }, potable_water: { keywords: ["blue-square", "liquid", "restroom", "cleaning", "faucet"], char: "\u{1F6B0}", fitzpatrick_scale: false, category: "symbols" }, mens: { keywords: ["toilet", "restroom", "wc", "blue-square", "gender", "male"], char: "\u{1F6B9}", fitzpatrick_scale: false, category: "symbols" }, womens: { keywords: ["purple-square", "woman", "female", "toilet", "loo", "restroom", "gender"], char: "\u{1F6BA}", fitzpatrick_scale: false, category: "symbols" }, baby_symbol: { keywords: ["orange-square", "child"], char: "\u{1F6BC}", fitzpatrick_scale: false, category: "symbols" }, restroom: { keywords: ["blue-square", "toilet", "refresh", "wc", "gender"], char: "\u{1F6BB}", fitzpatrick_scale: false, category: "symbols" }, put_litter_in_its_place: { keywords: ["blue-square", "sign", "human", "info"], char: "\u{1F6AE}", fitzpatrick_scale: false, category: "symbols" }, cinema: { keywords: ["blue-square", "record", "film", "movie", "curtain", "stage", "theater"], char: "\u{1F3A6}", fitzpatrick_scale: false, category: "symbols" }, signal_strength: { keywords: ["blue-square", "reception", "phone", "internet", "connection", "wifi", "bluetooth", "bars"], char: "\u{1F4F6}", fitzpatrick_scale: false, category: "symbols" }, koko: { keywords: ["blue-square", "here", "katakana", "japanese", "destination"], char: "\u{1F201}", fitzpatrick_scale: false, category: "symbols" }, ng: { keywords: ["blue-square", "words", "shape", "icon"], char: "\u{1F196}", fitzpatrick_scale: false, category: "symbols" }, ok: { keywords: ["good", "agree", "yes", "blue-square"], char: "\u{1F197}", fitzpatrick_scale: false, category: "symbols" }, up: { keywords: ["blue-square", "above", "high"], char: "\u{1F199}", fitzpatrick_scale: false, category: "symbols" }, cool: { keywords: ["words", "blue-square"], char: "\u{1F192}", fitzpatrick_scale: false, category: "symbols" }, new: { keywords: ["blue-square", "words", "start"], char: "\u{1F195}", fitzpatrick_scale: false, category: "symbols" }, free: { keywords: ["blue-square", "words"], char: "\u{1F193}", fitzpatrick_scale: false, category: "symbols" }, zero: { keywords: ["0", "numbers", "blue-square", "null"], char: "0\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, one: { keywords: ["blue-square", "numbers", "1"], char: "1\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, two: { keywords: ["numbers", "2", "prime", "blue-square"], char: "2\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, three: { keywords: ["3", "numbers", "prime", "blue-square"], char: "3\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, four: { keywords: ["4", "numbers", "blue-square"], char: "4\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, five: { keywords: ["5", "numbers", "blue-square", "prime"], char: "5\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, six: { keywords: ["6", "numbers", "blue-square"], char: "6\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, seven: { keywords: ["7", "numbers", "blue-square", "prime"], char: "7\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, eight: { keywords: ["8", "blue-square", "numbers"], char: "8\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, nine: { keywords: ["blue-square", "numbers", "9"], char: "9\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, keycap_ten: { keywords: ["numbers", "10", "blue-square"], char: "\u{1F51F}", fitzpatrick_scale: false, category: "symbols" }, asterisk: { keywords: ["star", "keycap"], char: "*\u20E3", fitzpatrick_scale: false, category: "symbols" }, 1234: { keywords: ["numbers", "blue-square"], char: "\u{1F522}", fitzpatrick_scale: false, category: "symbols" }, eject_button: { keywords: ["blue-square"], char: "\u23CF\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_forward: { keywords: ["blue-square", "right", "direction", "play"], char: "\u25B6\uFE0F", fitzpatrick_scale: false, category: "symbols" }, pause_button: { keywords: ["pause", "blue-square"], char: "\u23F8", fitzpatrick_scale: false, category: "symbols" }, next_track_button: { keywords: ["forward", "next", "blue-square"], char: "\u23ED", fitzpatrick_scale: false, category: "symbols" }, stop_button: { keywords: ["blue-square"], char: "\u23F9", fitzpatrick_scale: false, category: "symbols" }, record_button: { keywords: ["blue-square"], char: "\u23FA", fitzpatrick_scale: false, category: "symbols" }, play_or_pause_button: { keywords: ["blue-square", "play", "pause"], char: "\u23EF", fitzpatrick_scale: false, category: "symbols" }, previous_track_button: { keywords: ["backward"], char: "\u23EE", fitzpatrick_scale: false, category: "symbols" }, fast_forward: { keywords: ["blue-square", "play", "speed", "continue"], char: "\u23E9", fitzpatrick_scale: false, category: "symbols" }, rewind: { keywords: ["play", "blue-square"], char: "\u23EA", fitzpatrick_scale: false, category: "symbols" }, twisted_rightwards_arrows: { keywords: ["blue-square", "shuffle", "music", "random"], char: "\u{1F500}", fitzpatrick_scale: false, category: "symbols" }, repeat: { keywords: ["loop", "record"], char: "\u{1F501}", fitzpatrick_scale: false, category: "symbols" }, repeat_one: { keywords: ["blue-square", "loop"], char: "\u{1F502}", fitzpatrick_scale: false, category: "symbols" }, arrow_backward: { keywords: ["blue-square", "left", "direction"], char: "\u25C0\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_up_small: { keywords: ["blue-square", "triangle", "direction", "point", "forward", "top"], char: "\u{1F53C}", fitzpatrick_scale: false, category: "symbols" }, arrow_down_small: { keywords: ["blue-square", "direction", "bottom"], char: "\u{1F53D}", fitzpatrick_scale: false, category: "symbols" }, arrow_double_up: { keywords: ["blue-square", "direction", "top"], char: "\u23EB", fitzpatrick_scale: false, category: "symbols" }, arrow_double_down: { keywords: ["blue-square", "direction", "bottom"], char: "\u23EC", fitzpatrick_scale: false, category: "symbols" }, arrow_right: { keywords: ["blue-square", "next"], char: "\u27A1\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_left: { keywords: ["blue-square", "previous", "back"], char: "\u2B05\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_up: { keywords: ["blue-square", "continue", "top", "direction"], char: "\u2B06\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_down: { keywords: ["blue-square", "direction", "bottom"], char: "\u2B07\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_upper_right: { keywords: ["blue-square", "point", "direction", "diagonal", "northeast"], char: "\u2197\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_lower_right: { keywords: ["blue-square", "direction", "diagonal", "southeast"], char: "\u2198\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_lower_left: { keywords: ["blue-square", "direction", "diagonal", "southwest"], char: "\u2199\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_upper_left: { keywords: ["blue-square", "point", "direction", "diagonal", "northwest"], char: "\u2196\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_up_down: { keywords: ["blue-square", "direction", "way", "vertical"], char: "\u2195\uFE0F", fitzpatrick_scale: false, category: "symbols" }, left_right_arrow: { keywords: ["shape", "direction", "horizontal", "sideways"], char: "\u2194\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrows_counterclockwise: { keywords: ["blue-square", "sync", "cycle"], char: "\u{1F504}", fitzpatrick_scale: false, category: "symbols" }, arrow_right_hook: { keywords: ["blue-square", "return", "rotate", "direction"], char: "\u21AA\uFE0F", fitzpatrick_scale: false, category: "symbols" }, leftwards_arrow_with_hook: { keywords: ["back", "return", "blue-square", "undo", "enter"], char: "\u21A9\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_heading_up: { keywords: ["blue-square", "direction", "top"], char: "\u2934\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrow_heading_down: { keywords: ["blue-square", "direction", "bottom"], char: "\u2935\uFE0F", fitzpatrick_scale: false, category: "symbols" }, hash: { keywords: ["symbol", "blue-square", "twitter"], char: "#\uFE0F\u20E3", fitzpatrick_scale: false, category: "symbols" }, information_source: { keywords: ["blue-square", "alphabet", "letter"], char: "\u2139\uFE0F", fitzpatrick_scale: false, category: "symbols" }, abc: { keywords: ["blue-square", "alphabet"], char: "\u{1F524}", fitzpatrick_scale: false, category: "symbols" }, abcd: { keywords: ["blue-square", "alphabet"], char: "\u{1F521}", fitzpatrick_scale: false, category: "symbols" }, capital_abcd: { keywords: ["alphabet", "words", "blue-square"], char: "\u{1F520}", fitzpatrick_scale: false, category: "symbols" }, symbols: { keywords: ["blue-square", "music", "note", "ampersand", "percent", "glyphs", "characters"], char: "\u{1F523}", fitzpatrick_scale: false, category: "symbols" }, musical_note: { keywords: ["score", "tone", "sound"], char: "\u{1F3B5}", fitzpatrick_scale: false, category: "symbols" }, notes: { keywords: ["music", "score"], char: "\u{1F3B6}", fitzpatrick_scale: false, category: "symbols" }, wavy_dash: { keywords: ["draw", "line", "moustache", "mustache", "squiggle", "scribble"], char: "\u3030\uFE0F", fitzpatrick_scale: false, category: "symbols" }, curly_loop: { keywords: ["scribble", "draw", "shape", "squiggle"], char: "\u27B0", fitzpatrick_scale: false, category: "symbols" }, heavy_check_mark: { keywords: ["ok", "nike", "answer", "yes", "tick"], char: "\u2714\uFE0F", fitzpatrick_scale: false, category: "symbols" }, arrows_clockwise: { keywords: ["sync", "cycle", "round", "repeat"], char: "\u{1F503}", fitzpatrick_scale: false, category: "symbols" }, heavy_plus_sign: { keywords: ["math", "calculation", "addition", "more", "increase"], char: "\u2795", fitzpatrick_scale: false, category: "symbols" }, heavy_minus_sign: { keywords: ["math", "calculation", "subtract", "less"], char: "\u2796", fitzpatrick_scale: false, category: "symbols" }, heavy_division_sign: { keywords: ["divide", "math", "calculation"], char: "\u2797", fitzpatrick_scale: false, category: "symbols" }, heavy_multiplication_x: { keywords: ["math", "calculation"], char: "\u2716\uFE0F", fitzpatrick_scale: false, category: "symbols" }, infinity: { keywords: ["forever"], char: "\u267E", fitzpatrick_scale: false, category: "symbols" }, heavy_dollar_sign: { keywords: ["money", "sales", "payment", "currency", "buck"], char: "\u{1F4B2}", fitzpatrick_scale: false, category: "symbols" }, currency_exchange: { keywords: ["money", "sales", "dollar", "travel"], char: "\u{1F4B1}", fitzpatrick_scale: false, category: "symbols" }, copyright: { keywords: ["ip", "license", "circle", "law", "legal"], char: "\xA9\uFE0F", fitzpatrick_scale: false, category: "symbols" }, registered: { keywords: ["alphabet", "circle"], char: "\xAE\uFE0F", fitzpatrick_scale: false, category: "symbols" }, tm: { keywords: ["trademark", "brand", "law", "legal"], char: "\u2122\uFE0F", fitzpatrick_scale: false, category: "symbols" }, end: { keywords: ["words", "arrow"], char: "\u{1F51A}", fitzpatrick_scale: false, category: "symbols" }, back: { keywords: ["arrow", "words", "return"], char: "\u{1F519}", fitzpatrick_scale: false, category: "symbols" }, on: { keywords: ["arrow", "words"], char: "\u{1F51B}", fitzpatrick_scale: false, category: "symbols" }, top: { keywords: ["words", "blue-square"], char: "\u{1F51D}", fitzpatrick_scale: false, category: "symbols" }, soon: { keywords: ["arrow", "words"], char: "\u{1F51C}", fitzpatrick_scale: false, category: "symbols" }, ballot_box_with_check: { keywords: ["ok", "agree", "confirm", "black-square", "vote", "election", "yes", "tick"], char: "\u2611\uFE0F", fitzpatrick_scale: false, category: "symbols" }, radio_button: { keywords: ["input", "old", "music", "circle"], char: "\u{1F518}", fitzpatrick_scale: false, category: "symbols" }, white_circle: { keywords: ["shape", "round"], char: "\u26AA", fitzpatrick_scale: false, category: "symbols" }, black_circle: { keywords: ["shape", "button", "round"], char: "\u26AB", fitzpatrick_scale: false, category: "symbols" }, red_circle: { keywords: ["shape", "error", "danger"], char: "\u{1F534}", fitzpatrick_scale: false, category: "symbols" }, large_blue_circle: { keywords: ["shape", "icon", "button"], char: "\u{1F535}", fitzpatrick_scale: false, category: "symbols" }, small_orange_diamond: { keywords: ["shape", "jewel", "gem"], char: "\u{1F538}", fitzpatrick_scale: false, category: "symbols" }, small_blue_diamond: { keywords: ["shape", "jewel", "gem"], char: "\u{1F539}", fitzpatrick_scale: false, category: "symbols" }, large_orange_diamond: { keywords: ["shape", "jewel", "gem"], char: "\u{1F536}", fitzpatrick_scale: false, category: "symbols" }, large_blue_diamond: { keywords: ["shape", "jewel", "gem"], char: "\u{1F537}", fitzpatrick_scale: false, category: "symbols" }, small_red_triangle: { keywords: ["shape", "direction", "up", "top"], char: "\u{1F53A}", fitzpatrick_scale: false, category: "symbols" }, black_small_square: { keywords: ["shape", "icon"], char: "\u25AA\uFE0F", fitzpatrick_scale: false, category: "symbols" }, white_small_square: { keywords: ["shape", "icon"], char: "\u25AB\uFE0F", fitzpatrick_scale: false, category: "symbols" }, black_large_square: { keywords: ["shape", "icon", "button"], char: "\u2B1B", fitzpatrick_scale: false, category: "symbols" }, white_large_square: { keywords: ["shape", "icon", "stone", "button"], char: "\u2B1C", fitzpatrick_scale: false, category: "symbols" }, small_red_triangle_down: { keywords: ["shape", "direction", "bottom"], char: "\u{1F53B}", fitzpatrick_scale: false, category: "symbols" }, black_medium_square: { keywords: ["shape", "button", "icon"], char: "\u25FC\uFE0F", fitzpatrick_scale: false, category: "symbols" }, white_medium_square: { keywords: ["shape", "stone", "icon"], char: "\u25FB\uFE0F", fitzpatrick_scale: false, category: "symbols" }, black_medium_small_square: { keywords: ["icon", "shape", "button"], char: "\u25FE", fitzpatrick_scale: false, category: "symbols" }, white_medium_small_square: { keywords: ["shape", "stone", "icon", "button"], char: "\u25FD", fitzpatrick_scale: false, category: "symbols" }, black_square_button: { keywords: ["shape", "input", "frame"], char: "\u{1F532}", fitzpatrick_scale: false, category: "symbols" }, white_square_button: { keywords: ["shape", "input"], char: "\u{1F533}", fitzpatrick_scale: false, category: "symbols" }, speaker: { keywords: ["sound", "volume", "silence", "broadcast"], char: "\u{1F508}", fitzpatrick_scale: false, category: "symbols" }, sound: { keywords: ["volume", "speaker", "broadcast"], char: "\u{1F509}", fitzpatrick_scale: false, category: "symbols" }, loud_sound: { keywords: ["volume", "noise", "noisy", "speaker", "broadcast"], char: "\u{1F50A}", fitzpatrick_scale: false, category: "symbols" }, mute: { keywords: ["sound", "volume", "silence", "quiet"], char: "\u{1F507}", fitzpatrick_scale: false, category: "symbols" }, mega: { keywords: ["sound", "speaker", "volume"], char: "\u{1F4E3}", fitzpatrick_scale: false, category: "symbols" }, loudspeaker: { keywords: ["volume", "sound"], char: "\u{1F4E2}", fitzpatrick_scale: false, category: "symbols" }, bell: { keywords: ["sound", "notification", "christmas", "xmas", "chime"], char: "\u{1F514}", fitzpatrick_scale: false, category: "symbols" }, no_bell: { keywords: ["sound", "volume", "mute", "quiet", "silent"], char: "\u{1F515}", fitzpatrick_scale: false, category: "symbols" }, black_joker: { keywords: ["poker", "cards", "game", "play", "magic"], char: "\u{1F0CF}", fitzpatrick_scale: false, category: "symbols" }, mahjong: { keywords: ["game", "play", "chinese", "kanji"], char: "\u{1F004}", fitzpatrick_scale: false, category: "symbols" }, spades: { keywords: ["poker", "cards", "suits", "magic"], char: "\u2660\uFE0F", fitzpatrick_scale: false, category: "symbols" }, clubs: { keywords: ["poker", "cards", "magic", "suits"], char: "\u2663\uFE0F", fitzpatrick_scale: false, category: "symbols" }, hearts: { keywords: ["poker", "cards", "magic", "suits"], char: "\u2665\uFE0F", fitzpatrick_scale: false, category: "symbols" }, diamonds: { keywords: ["poker", "cards", "magic", "suits"], char: "\u2666\uFE0F", fitzpatrick_scale: false, category: "symbols" }, flower_playing_cards: { keywords: ["game", "sunset", "red"], char: "\u{1F3B4}", fitzpatrick_scale: false, category: "symbols" }, thought_balloon: { keywords: ["bubble", "cloud", "speech", "thinking", "dream"], char: "\u{1F4AD}", fitzpatrick_scale: false, category: "symbols" }, right_anger_bubble: { keywords: ["caption", "speech", "thinking", "mad"], char: "\u{1F5EF}", fitzpatrick_scale: false, category: "symbols" }, speech_balloon: { keywords: ["bubble", "words", "message", "talk", "chatting"], char: "\u{1F4AC}", fitzpatrick_scale: false, category: "symbols" }, left_speech_bubble: { keywords: ["words", "message", "talk", "chatting"], char: "\u{1F5E8}", fitzpatrick_scale: false, category: "symbols" }, clock1: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F550}", fitzpatrick_scale: false, category: "symbols" }, clock2: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F551}", fitzpatrick_scale: false, category: "symbols" }, clock3: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F552}", fitzpatrick_scale: false, category: "symbols" }, clock4: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F553}", fitzpatrick_scale: false, category: "symbols" }, clock5: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F554}", fitzpatrick_scale: false, category: "symbols" }, clock6: { keywords: ["time", "late", "early", "schedule", "dawn", "dusk"], char: "\u{1F555}", fitzpatrick_scale: false, category: "symbols" }, clock7: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F556}", fitzpatrick_scale: false, category: "symbols" }, clock8: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F557}", fitzpatrick_scale: false, category: "symbols" }, clock9: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F558}", fitzpatrick_scale: false, category: "symbols" }, clock10: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F559}", fitzpatrick_scale: false, category: "symbols" }, clock11: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F55A}", fitzpatrick_scale: false, category: "symbols" }, clock12: { keywords: ["time", "noon", "midnight", "midday", "late", "early", "schedule"], char: "\u{1F55B}", fitzpatrick_scale: false, category: "symbols" }, clock130: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F55C}", fitzpatrick_scale: false, category: "symbols" }, clock230: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F55D}", fitzpatrick_scale: false, category: "symbols" }, clock330: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F55E}", fitzpatrick_scale: false, category: "symbols" }, clock430: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F55F}", fitzpatrick_scale: false, category: "symbols" }, clock530: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F560}", fitzpatrick_scale: false, category: "symbols" }, clock630: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F561}", fitzpatrick_scale: false, category: "symbols" }, clock730: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F562}", fitzpatrick_scale: false, category: "symbols" }, clock830: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F563}", fitzpatrick_scale: false, category: "symbols" }, clock930: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F564}", fitzpatrick_scale: false, category: "symbols" }, clock1030: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F565}", fitzpatrick_scale: false, category: "symbols" }, clock1130: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F566}", fitzpatrick_scale: false, category: "symbols" }, clock1230: { keywords: ["time", "late", "early", "schedule"], char: "\u{1F567}", fitzpatrick_scale: false, category: "symbols" }, afghanistan: { keywords: ["af", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, aland_islands: { keywords: ["\xC5land", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1FD}", fitzpatrick_scale: false, category: "flags" }, albania: { keywords: ["al", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, algeria: { keywords: ["dz", "flag", "nation", "country", "banner"], char: "\u{1F1E9}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, american_samoa: { keywords: ["american", "ws", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, andorra: { keywords: ["ad", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, angola: { keywords: ["ao", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, anguilla: { keywords: ["ai", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, antarctica: { keywords: ["aq", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F6}", fitzpatrick_scale: false, category: "flags" }, antigua_barbuda: { keywords: ["antigua", "barbuda", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, argentina: { keywords: ["ar", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, armenia: { keywords: ["am", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, aruba: { keywords: ["aw", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, australia: { keywords: ["au", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, austria: { keywords: ["at", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, azerbaijan: { keywords: ["az", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, bahamas: { keywords: ["bs", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, bahrain: { keywords: ["bh", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, bangladesh: { keywords: ["bd", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, barbados: { keywords: ["bb", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1E7}", fitzpatrick_scale: false, category: "flags" }, belarus: { keywords: ["by", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, belgium: { keywords: ["be", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, belize: { keywords: ["bz", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, benin: { keywords: ["bj", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1EF}", fitzpatrick_scale: false, category: "flags" }, bermuda: { keywords: ["bm", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, bhutan: { keywords: ["bt", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, bolivia: { keywords: ["bo", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, caribbean_netherlands: { keywords: ["bonaire", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F6}", fitzpatrick_scale: false, category: "flags" }, bosnia_herzegovina: { keywords: ["bosnia", "herzegovina", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, botswana: { keywords: ["bw", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, brazil: { keywords: ["br", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, british_indian_ocean_territory: { keywords: ["british", "indian", "ocean", "territory", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, british_virgin_islands: { keywords: ["british", "virgin", "islands", "bvi", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, brunei: { keywords: ["bn", "darussalam", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, bulgaria: { keywords: ["bg", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, burkina_faso: { keywords: ["burkina", "faso", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, burundi: { keywords: ["bi", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, cape_verde: { keywords: ["cabo", "verde", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FB}", fitzpatrick_scale: false, category: "flags" }, cambodia: { keywords: ["kh", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, cameroon: { keywords: ["cm", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, canada: { keywords: ["ca", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, canary_islands: { keywords: ["canary", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, cayman_islands: { keywords: ["cayman", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, central_african_republic: { keywords: ["central", "african", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, chad: { keywords: ["td", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, chile: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, cn: { keywords: ["china", "chinese", "prc", "flag", "country", "nation", "banner"], char: "\u{1F1E8}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, christmas_island: { keywords: ["christmas", "island", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FD}", fitzpatrick_scale: false, category: "flags" }, cocos_islands: { keywords: ["cocos", "keeling", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, colombia: { keywords: ["co", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, comoros: { keywords: ["km", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, congo_brazzaville: { keywords: ["congo", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, congo_kinshasa: { keywords: ["congo", "democratic", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, cook_islands: { keywords: ["cook", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, costa_rica: { keywords: ["costa", "rica", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, croatia: { keywords: ["hr", "flag", "nation", "country", "banner"], char: "\u{1F1ED}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, cuba: { keywords: ["cu", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, curacao: { keywords: ["cura\xE7ao", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, cyprus: { keywords: ["cy", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, czech_republic: { keywords: ["cz", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, denmark: { keywords: ["dk", "flag", "nation", "country", "banner"], char: "\u{1F1E9}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, djibouti: { keywords: ["dj", "flag", "nation", "country", "banner"], char: "\u{1F1E9}\u{1F1EF}", fitzpatrick_scale: false, category: "flags" }, dominica: { keywords: ["dm", "flag", "nation", "country", "banner"], char: "\u{1F1E9}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, dominican_republic: { keywords: ["dominican", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1E9}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, ecuador: { keywords: ["ec", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, egypt: { keywords: ["eg", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, el_salvador: { keywords: ["el", "salvador", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1FB}", fitzpatrick_scale: false, category: "flags" }, equatorial_guinea: { keywords: ["equatorial", "gn", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F6}", fitzpatrick_scale: false, category: "flags" }, eritrea: { keywords: ["er", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, estonia: { keywords: ["ee", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, ethiopia: { keywords: ["et", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, eu: { keywords: ["european", "union", "flag", "banner"], char: "\u{1F1EA}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, falkland_islands: { keywords: ["falkland", "islands", "malvinas", "flag", "nation", "country", "banner"], char: "\u{1F1EB}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, faroe_islands: { keywords: ["faroe", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1EB}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, fiji: { keywords: ["fj", "flag", "nation", "country", "banner"], char: "\u{1F1EB}\u{1F1EF}", fitzpatrick_scale: false, category: "flags" }, finland: { keywords: ["fi", "flag", "nation", "country", "banner"], char: "\u{1F1EB}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, fr: { keywords: ["banner", "flag", "nation", "france", "french", "country"], char: "\u{1F1EB}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, french_guiana: { keywords: ["french", "guiana", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, french_polynesia: { keywords: ["french", "polynesia", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, french_southern_territories: { keywords: ["french", "southern", "territories", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, gabon: { keywords: ["ga", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, gambia: { keywords: ["gm", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, georgia: { keywords: ["ge", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, de: { keywords: ["german", "nation", "flag", "country", "banner"], char: "\u{1F1E9}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, ghana: { keywords: ["gh", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, gibraltar: { keywords: ["gi", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, greece: { keywords: ["gr", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, greenland: { keywords: ["gl", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, grenada: { keywords: ["gd", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, guadeloupe: { keywords: ["gp", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F5}", fitzpatrick_scale: false, category: "flags" }, guam: { keywords: ["gu", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, guatemala: { keywords: ["gt", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, guernsey: { keywords: ["gg", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, guinea: { keywords: ["gn", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, guinea_bissau: { keywords: ["gw", "bissau", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, guyana: { keywords: ["gy", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, haiti: { keywords: ["ht", "flag", "nation", "country", "banner"], char: "\u{1F1ED}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, honduras: { keywords: ["hn", "flag", "nation", "country", "banner"], char: "\u{1F1ED}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, hong_kong: { keywords: ["hong", "kong", "flag", "nation", "country", "banner"], char: "\u{1F1ED}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, hungary: { keywords: ["hu", "flag", "nation", "country", "banner"], char: "\u{1F1ED}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, iceland: { keywords: ["is", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, india: { keywords: ["in", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, indonesia: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, iran: { keywords: ["iran,", "islamic", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, iraq: { keywords: ["iq", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F6}", fitzpatrick_scale: false, category: "flags" }, ireland: { keywords: ["ie", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, isle_of_man: { keywords: ["isle", "man", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, israel: { keywords: ["il", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, it: { keywords: ["italy", "flag", "nation", "country", "banner"], char: "\u{1F1EE}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, cote_divoire: { keywords: ["ivory", "coast", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, jamaica: { keywords: ["jm", "flag", "nation", "country", "banner"], char: "\u{1F1EF}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, jp: { keywords: ["japanese", "nation", "flag", "country", "banner"], char: "\u{1F1EF}\u{1F1F5}", fitzpatrick_scale: false, category: "flags" }, jersey: { keywords: ["je", "flag", "nation", "country", "banner"], char: "\u{1F1EF}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, jordan: { keywords: ["jo", "flag", "nation", "country", "banner"], char: "\u{1F1EF}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, kazakhstan: { keywords: ["kz", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, kenya: { keywords: ["ke", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, kiribati: { keywords: ["ki", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, kosovo: { keywords: ["xk", "flag", "nation", "country", "banner"], char: "\u{1F1FD}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, kuwait: { keywords: ["kw", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, kyrgyzstan: { keywords: ["kg", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, laos: { keywords: ["lao", "democratic", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, latvia: { keywords: ["lv", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1FB}", fitzpatrick_scale: false, category: "flags" }, lebanon: { keywords: ["lb", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1E7}", fitzpatrick_scale: false, category: "flags" }, lesotho: { keywords: ["ls", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, liberia: { keywords: ["lr", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, libya: { keywords: ["ly", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, liechtenstein: { keywords: ["li", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, lithuania: { keywords: ["lt", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, luxembourg: { keywords: ["lu", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, macau: { keywords: ["macao", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, macedonia: { keywords: ["macedonia,", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, madagascar: { keywords: ["mg", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, malawi: { keywords: ["mw", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, malaysia: { keywords: ["my", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, maldives: { keywords: ["mv", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FB}", fitzpatrick_scale: false, category: "flags" }, mali: { keywords: ["ml", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, malta: { keywords: ["mt", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, marshall_islands: { keywords: ["marshall", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, martinique: { keywords: ["mq", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F6}", fitzpatrick_scale: false, category: "flags" }, mauritania: { keywords: ["mr", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, mauritius: { keywords: ["mu", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, mayotte: { keywords: ["yt", "flag", "nation", "country", "banner"], char: "\u{1F1FE}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, mexico: { keywords: ["mx", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FD}", fitzpatrick_scale: false, category: "flags" }, micronesia: { keywords: ["micronesia,", "federated", "states", "flag", "nation", "country", "banner"], char: "\u{1F1EB}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, moldova: { keywords: ["moldova,", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, monaco: { keywords: ["mc", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, mongolia: { keywords: ["mn", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, montenegro: { keywords: ["me", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, montserrat: { keywords: ["ms", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, morocco: { keywords: ["ma", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, mozambique: { keywords: ["mz", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, myanmar: { keywords: ["mm", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, namibia: { keywords: ["na", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, nauru: { keywords: ["nr", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, nepal: { keywords: ["np", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1F5}", fitzpatrick_scale: false, category: "flags" }, netherlands: { keywords: ["nl", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, new_caledonia: { keywords: ["new", "caledonia", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, new_zealand: { keywords: ["new", "zealand", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, nicaragua: { keywords: ["ni", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, niger: { keywords: ["ne", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, nigeria: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, niue: { keywords: ["nu", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, norfolk_island: { keywords: ["norfolk", "island", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, northern_mariana_islands: { keywords: ["northern", "mariana", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1F2}\u{1F1F5}", fitzpatrick_scale: false, category: "flags" }, north_korea: { keywords: ["north", "korea", "nation", "flag", "country", "banner"], char: "\u{1F1F0}\u{1F1F5}", fitzpatrick_scale: false, category: "flags" }, norway: { keywords: ["no", "flag", "nation", "country", "banner"], char: "\u{1F1F3}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, oman: { keywords: ["om_symbol", "flag", "nation", "country", "banner"], char: "\u{1F1F4}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, pakistan: { keywords: ["pk", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, palau: { keywords: ["pw", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, palestinian_territories: { keywords: ["palestine", "palestinian", "territories", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, panama: { keywords: ["pa", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, papua_new_guinea: { keywords: ["papua", "new", "guinea", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, paraguay: { keywords: ["py", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, peru: { keywords: ["pe", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, philippines: { keywords: ["ph", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, pitcairn_islands: { keywords: ["pitcairn", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, poland: { keywords: ["pl", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, portugal: { keywords: ["pt", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, puerto_rico: { keywords: ["puerto", "rico", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, qatar: { keywords: ["qa", "flag", "nation", "country", "banner"], char: "\u{1F1F6}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, reunion: { keywords: ["r\xE9union", "flag", "nation", "country", "banner"], char: "\u{1F1F7}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, romania: { keywords: ["ro", "flag", "nation", "country", "banner"], char: "\u{1F1F7}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, ru: { keywords: ["russian", "federation", "flag", "nation", "country", "banner"], char: "\u{1F1F7}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, rwanda: { keywords: ["rw", "flag", "nation", "country", "banner"], char: "\u{1F1F7}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, st_barthelemy: { keywords: ["saint", "barth\xE9lemy", "flag", "nation", "country", "banner"], char: "\u{1F1E7}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, st_helena: { keywords: ["saint", "helena", "ascension", "tristan", "cunha", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, st_kitts_nevis: { keywords: ["saint", "kitts", "nevis", "flag", "nation", "country", "banner"], char: "\u{1F1F0}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, st_lucia: { keywords: ["saint", "lucia", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, st_pierre_miquelon: { keywords: ["saint", "pierre", "miquelon", "flag", "nation", "country", "banner"], char: "\u{1F1F5}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, st_vincent_grenadines: { keywords: ["saint", "vincent", "grenadines", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, samoa: { keywords: ["ws", "flag", "nation", "country", "banner"], char: "\u{1F1FC}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, san_marino: { keywords: ["san", "marino", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, sao_tome_principe: { keywords: ["sao", "tome", "principe", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, saudi_arabia: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, senegal: { keywords: ["sn", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, serbia: { keywords: ["rs", "flag", "nation", "country", "banner"], char: "\u{1F1F7}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, seychelles: { keywords: ["sc", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, sierra_leone: { keywords: ["sierra", "leone", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, singapore: { keywords: ["sg", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, sint_maarten: { keywords: ["sint", "maarten", "dutch", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1FD}", fitzpatrick_scale: false, category: "flags" }, slovakia: { keywords: ["sk", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, slovenia: { keywords: ["si", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, solomon_islands: { keywords: ["solomon", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1E7}", fitzpatrick_scale: false, category: "flags" }, somalia: { keywords: ["so", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, south_africa: { keywords: ["south", "africa", "flag", "nation", "country", "banner"], char: "\u{1F1FF}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, south_georgia_south_sandwich_islands: { keywords: ["south", "georgia", "sandwich", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1EC}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, kr: { keywords: ["south", "korea", "nation", "flag", "country", "banner"], char: "\u{1F1F0}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, south_sudan: { keywords: ["south", "sd", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, es: { keywords: ["spain", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, sri_lanka: { keywords: ["sri", "lanka", "flag", "nation", "country", "banner"], char: "\u{1F1F1}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, sudan: { keywords: ["sd", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1E9}", fitzpatrick_scale: false, category: "flags" }, suriname: { keywords: ["sr", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, swaziland: { keywords: ["sz", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, sweden: { keywords: ["se", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, switzerland: { keywords: ["ch", "flag", "nation", "country", "banner"], char: "\u{1F1E8}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, syria: { keywords: ["syrian", "arab", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1F8}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, taiwan: { keywords: ["tw", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, tajikistan: { keywords: ["tj", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1EF}", fitzpatrick_scale: false, category: "flags" }, tanzania: { keywords: ["tanzania,", "united", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, thailand: { keywords: ["th", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, timor_leste: { keywords: ["timor", "leste", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F1}", fitzpatrick_scale: false, category: "flags" }, togo: { keywords: ["tg", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, tokelau: { keywords: ["tk", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F0}", fitzpatrick_scale: false, category: "flags" }, tonga: { keywords: ["to", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F4}", fitzpatrick_scale: false, category: "flags" }, trinidad_tobago: { keywords: ["trinidad", "tobago", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F9}", fitzpatrick_scale: false, category: "flags" }, tunisia: { keywords: ["tn", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, tr: { keywords: ["turkey", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F7}", fitzpatrick_scale: false, category: "flags" }, turkmenistan: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, turks_caicos_islands: { keywords: ["turks", "caicos", "islands", "flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1E8}", fitzpatrick_scale: false, category: "flags" }, tuvalu: { keywords: ["flag", "nation", "country", "banner"], char: "\u{1F1F9}\u{1F1FB}", fitzpatrick_scale: false, category: "flags" }, uganda: { keywords: ["ug", "flag", "nation", "country", "banner"], char: "\u{1F1FA}\u{1F1EC}", fitzpatrick_scale: false, category: "flags" }, ukraine: { keywords: ["ua", "flag", "nation", "country", "banner"], char: "\u{1F1FA}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, united_arab_emirates: { keywords: ["united", "arab", "emirates", "flag", "nation", "country", "banner"], char: "\u{1F1E6}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, uk: { keywords: ["united", "kingdom", "great", "britain", "northern", "ireland", "flag", "nation", "country", "banner", "british", "UK", "english", "england", "union jack"], char: "\u{1F1EC}\u{1F1E7}", fitzpatrick_scale: false, category: "flags" }, england: { keywords: ["flag", "english"], char: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}", fitzpatrick_scale: false, category: "flags" }, scotland: { keywords: ["flag", "scottish"], char: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}", fitzpatrick_scale: false, category: "flags" }, wales: { keywords: ["flag", "welsh"], char: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0077}\u{E006C}\u{E0073}\u{E007F}", fitzpatrick_scale: false, category: "flags" }, us: { keywords: ["united", "states", "america", "flag", "nation", "country", "banner"], char: "\u{1F1FA}\u{1F1F8}", fitzpatrick_scale: false, category: "flags" }, us_virgin_islands: { keywords: ["virgin", "islands", "us", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1EE}", fitzpatrick_scale: false, category: "flags" }, uruguay: { keywords: ["uy", "flag", "nation", "country", "banner"], char: "\u{1F1FA}\u{1F1FE}", fitzpatrick_scale: false, category: "flags" }, uzbekistan: { keywords: ["uz", "flag", "nation", "country", "banner"], char: "\u{1F1FA}\u{1F1FF}", fitzpatrick_scale: false, category: "flags" }, vanuatu: { keywords: ["vu", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1FA}", fitzpatrick_scale: false, category: "flags" }, vatican_city: { keywords: ["vatican", "city", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1E6}", fitzpatrick_scale: false, category: "flags" }, venezuela: { keywords: ["ve", "bolivarian", "republic", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, vietnam: { keywords: ["viet", "nam", "flag", "nation", "country", "banner"], char: "\u{1F1FB}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, wallis_futuna: { keywords: ["wallis", "futuna", "flag", "nation", "country", "banner"], char: "\u{1F1FC}\u{1F1EB}", fitzpatrick_scale: false, category: "flags" }, western_sahara: { keywords: ["western", "sahara", "flag", "nation", "country", "banner"], char: "\u{1F1EA}\u{1F1ED}", fitzpatrick_scale: false, category: "flags" }, yemen: { keywords: ["ye", "flag", "nation", "country", "banner"], char: "\u{1F1FE}\u{1F1EA}", fitzpatrick_scale: false, category: "flags" }, zambia: { keywords: ["zm", "flag", "nation", "country", "banner"], char: "\u{1F1FF}\u{1F1F2}", fitzpatrick_scale: false, category: "flags" }, zimbabwe: { keywords: ["zw", "flag", "nation", "country", "banner"], char: "\u{1F1FF}\u{1F1FC}", fitzpatrick_scale: false, category: "flags" }, united_nations: { keywords: ["un", "flag", "banner"], char: "\u{1F1FA}\u{1F1F3}", fitzpatrick_scale: false, category: "flags" }, pirate_flag: { keywords: ["skull", "crossbones", "flag", "banner"], char: "\u{1F3F4}\u200D\u2620\uFE0F", fitzpatrick_scale: false, category: "flags" } });
(function() {
  var global$2 = tinymce.util.Tools.resolve("tinymce.PluginManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType = (type) => (value) => typeOf(value) === type;
  const isSimpleType = (type) => (value) => typeof value === type;
  const isString = isType("string");
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const option = (name2) => (editor) => editor.options.get(name2);
  const register = (editor) => {
    const registerOption = editor.options.register;
    const toolbarProcessor = (defaultValue) => (value) => {
      const valid = isBoolean(value) || isString(value);
      if (valid) {
        if (isBoolean(value)) {
          return {
            value: value ? defaultValue : "",
            valid
          };
        } else {
          return {
            value: value.trim(),
            valid
          };
        }
      } else {
        return {
          valid: false,
          message: "Must be a boolean or string."
        };
      }
    };
    const defaultSelectionToolbar = "bold italic | quicklink h2 h3 blockquote";
    registerOption("quickbars_selection_toolbar", {
      processor: toolbarProcessor(defaultSelectionToolbar),
      default: defaultSelectionToolbar
    });
    const defaultInsertToolbar = "quickimage quicktable";
    registerOption("quickbars_insert_toolbar", {
      processor: toolbarProcessor(defaultInsertToolbar),
      default: defaultInsertToolbar
    });
    const defaultImageToolbar = "alignleft aligncenter alignright";
    registerOption("quickbars_image_toolbar", {
      processor: toolbarProcessor(defaultImageToolbar),
      default: defaultImageToolbar
    });
  };
  const getTextSelectionToolbarItems = option("quickbars_selection_toolbar");
  const getInsertToolbarItems = option("quickbars_insert_toolbar");
  const getImageToolbarItems = option("quickbars_image_toolbar");
  let unique2 = 0;
  const generate = (prefix) => {
    const date = new Date();
    const time = date.getTime();
    const random = Math.floor(Math.random() * 1e9);
    unique2++;
    return prefix + "_" + random + unique2 + String(time);
  };
  const insertTable = (editor, columns, rows) => {
    editor.execCommand("mceInsertTable", false, {
      rows,
      columns
    });
  };
  const insertBlob = (editor, base64, blob) => {
    const blobCache = editor.editorUpload.blobCache;
    const blobInfo = blobCache.create(generate("mceu"), blob, base64);
    blobCache.add(blobInfo);
    editor.insertContent(editor.dom.createHTML("img", { src: blobInfo.blobUri() }));
  };
  const blobToBase64 = (blob) => {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => {
        resolve(reader.result.split(",")[1]);
      };
      reader.readAsDataURL(blob);
    });
  };
  var global$1 = tinymce.util.Tools.resolve("tinymce.Env");
  var global2 = tinymce.util.Tools.resolve("tinymce.util.Delay");
  const pickFile = (editor) => new Promise((resolve) => {
    const fileInput = document.createElement("input");
    fileInput.type = "file";
    fileInput.accept = "image/*";
    fileInput.style.position = "fixed";
    fileInput.style.left = "0";
    fileInput.style.top = "0";
    fileInput.style.opacity = "0.001";
    document.body.appendChild(fileInput);
    const changeHandler = (e) => {
      resolve(Array.prototype.slice.call(e.target.files));
    };
    fileInput.addEventListener("change", changeHandler);
    const cancelHandler = (e) => {
      const cleanup = () => {
        resolve([]);
        fileInput.parentNode.removeChild(fileInput);
      };
      if (global$1.os.isAndroid() && e.type !== "remove") {
        global2.setEditorTimeout(editor, cleanup, 0);
      } else {
        cleanup();
      }
      editor.off("focusin remove", cancelHandler);
    };
    editor.on("focusin remove", cancelHandler);
    fileInput.click();
  });
  const setupButtons = (editor) => {
    editor.ui.registry.addButton("quickimage", {
      icon: "image",
      tooltip: "Insert image",
      onAction: () => {
        pickFile(editor).then((files) => {
          if (files.length > 0) {
            const blob = files[0];
            blobToBase64(blob).then((base64) => {
              insertBlob(editor, base64, blob);
            });
          }
        });
      }
    });
    editor.ui.registry.addButton("quicktable", {
      icon: "table",
      tooltip: "Insert table",
      onAction: () => {
        insertTable(editor, 2, 2);
      }
    });
  };
  const constant = (value) => {
    return () => {
      return value;
    };
  };
  const never = constant(false);
  class Optional {
    constructor(tag, value) {
      this.tag = tag;
      this.value = value;
    }
    static some(value) {
      return new Optional(true, value);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder) {
      if (this.tag) {
        return binder(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value) {
      return isNonNullable(value) ? Optional.some(value) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot) => {
    if (is2(scope, a)) {
      return Optional.some(scope);
    } else if (isFunction(isRoot) && isRoot(scope)) {
      return Optional.none();
    } else {
      return ancestor2(scope, a, isRoot);
    }
  };
  const ELEMENT = 1;
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom(node);
  };
  const fromDom = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  const SugarElement = {
    fromHtml,
    fromTag,
    fromText,
    fromDom,
    fromPoint
  };
  const is = (element, selector) => {
    const dom = element.dom;
    if (dom.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const name = (element) => {
    const r = element.dom.nodeName;
    return r.toLowerCase();
  };
  const ancestor$1 = (scope, predicate, isRoot) => {
    let element = scope.dom;
    const stop = isFunction(isRoot) ? isRoot : never;
    while (element.parentNode) {
      element = element.parentNode;
      const el = SugarElement.fromDom(element);
      if (predicate(el)) {
        return Optional.some(el);
      } else if (stop(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const closest$1 = (scope, predicate, isRoot) => {
    const is2 = (s, test) => test(s);
    return ClosestOrAncestor(is2, ancestor$1, scope, predicate, isRoot);
  };
  const ancestor = (scope, selector, isRoot) => ancestor$1(scope, (e) => is(e, selector), isRoot);
  const closest = (scope, selector, isRoot) => {
    const is$1 = (element, selector2) => is(element, selector2);
    return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
  };
  const addToEditor$1 = (editor) => {
    const insertToolbarItems = getInsertToolbarItems(editor);
    if (insertToolbarItems.length > 0) {
      editor.ui.registry.addContextToolbar("quickblock", {
        predicate: (node) => {
          const sugarNode = SugarElement.fromDom(node);
          const textBlockElementsMap = editor.schema.getTextBlockElements();
          const isRoot = (elem) => elem.dom === editor.getBody();
          return closest(sugarNode, "table", isRoot).fold(() => closest$1(sugarNode, (elem) => name(elem) in textBlockElementsMap && editor.dom.isEmpty(elem.dom), isRoot).isSome(), never);
        },
        items: insertToolbarItems,
        position: "line",
        scope: "editor"
      });
    }
  };
  const addToEditor = (editor) => {
    const isEditable = (node) => editor.dom.getContentEditableParent(node) !== "false";
    const isImage = (node) => node.nodeName === "IMG" || node.nodeName === "FIGURE" && /image/i.test(node.className);
    const imageToolbarItems = getImageToolbarItems(editor);
    if (imageToolbarItems.length > 0) {
      editor.ui.registry.addContextToolbar("imageselection", {
        predicate: isImage,
        items: imageToolbarItems,
        position: "node"
      });
    }
    const textToolbarItems = getTextSelectionToolbarItems(editor);
    if (textToolbarItems.length > 0) {
      editor.ui.registry.addContextToolbar("textselection", {
        predicate: (node) => !isImage(node) && !editor.selection.isCollapsed() && isEditable(node),
        items: textToolbarItems,
        position: "selection",
        scope: "editor"
      });
    }
  };
  var Plugin = () => {
    global$2.add("quickbars", (editor) => {
      register(editor);
      setupButtons(editor);
      addToEditor$1(editor);
      addToEditor(editor);
    });
  };
  Plugin();
})();
tinymce.IconManager.add("default", {
  icons: {
    "accessibility-check": '<svg width="24" height="24"><path d="M12 2a2 2 0 0 1 2 2 2 2 0 0 1-2 2 2 2 0 0 1-2-2c0-1.1.9-2 2-2Zm8 7h-5v12c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5c0-.6-.4-1-1-1a1 1 0 0 0-1 1v5c0 .6-.4 1-1 1a1 1 0 0 1-1-1V9H4a1 1 0 1 1 0-2h16c.6 0 1 .4 1 1s-.4 1-1 1Z" fill-rule="nonzero"/></svg>',
    "action-next": '<svg width="24" height="24"><path fill-rule="nonzero" d="M5.7 7.3a1 1 0 0 0-1.4 1.4l7.7 7.7 7.7-7.7a1 1 0 1 0-1.4-1.4L12 13.6 5.7 7.3Z"/></svg>',
    "action-prev": '<svg width="24" height="24"><path fill-rule="nonzero" d="M18.3 15.7a1 1 0 0 0 1.4-1.4L12 6.6l-7.7 7.7a1 1 0 0 0 1.4 1.4L12 9.4l6.3 6.3Z"/></svg>',
    "align-center": '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm3 4h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm-3-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "align-justify": '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0 4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "align-left": '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 4h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Zm0-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "align-none": '<svg width="24" height="24"><path d="M14.2 5 13 7H5a1 1 0 1 1 0-2h9.2Zm4 0h.8a1 1 0 0 1 0 2h-2l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h6.8Zm4 0H19a1 1 0 0 1 0 2h-4.4l1.2-2Zm-6.4 4-1.2 2H5a1 1 0 0 1 0-2h4.4Zm4 0H19a1 1 0 0 1 0 2h-6.8l1.2-2ZM7 17l-1.2 2H5a1 1 0 0 1 0-2h2Zm4 0h8a1 1 0 0 1 0 2H9.8l1.2-2Zm5.2-13.5 1.3.7-9.7 16.3-1.3-.7 9.7-16.3Z" fill-rule="evenodd"/></svg>',
    "align-right": '<svg width="24" height="24"><path d="M5 5h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2Zm6 4h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 8h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-6-4h14c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "arrow-left": '<svg width="24" height="24"><path d="m5.6 13 12 6a1 1 0 0 0 1.4-1V6a1 1 0 0 0-1.4-.9l-12 6a1 1 0 0 0 0 1.8Z" fill-rule="evenodd"/></svg>',
    "arrow-right": '<svg width="24" height="24"><path d="m18.5 13-12 6A1 1 0 0 1 5 18V6a1 1 0 0 1 1.4-.9l12 6a1 1 0 0 1 0 1.8Z" fill-rule="evenodd"/></svg>',
    "bold": '<svg width="24" height="24"><path d="M7.8 19c-.3 0-.5 0-.6-.2l-.2-.5V5.7c0-.2 0-.4.2-.5l.6-.2h5c1.5 0 2.7.3 3.5 1 .7.6 1.1 1.4 1.1 2.5a3 3 0 0 1-.6 1.9c-.4.6-1 1-1.6 1.2.4.1.9.3 1.3.6s.8.7 1 1.2c.4.4.5 1 .5 1.6 0 1.3-.4 2.3-1.3 3-.8.7-2.1 1-3.8 1H7.8Zm5-8.3c.6 0 1.2-.1 1.6-.5.4-.3.6-.7.6-1.3 0-1.1-.8-1.7-2.3-1.7H9.3v3.5h3.4Zm.5 6c.7 0 1.3-.1 1.7-.4.4-.4.6-.9.6-1.5s-.2-1-.7-1.4c-.4-.3-1-.4-2-.4H9.4v3.8h4Z" fill-rule="evenodd"/></svg>',
    "bookmark": '<svg width="24" height="24"><path d="M6 4v17l6-4 6 4V4c0-.6-.4-1-1-1H7a1 1 0 0 0-1 1Z" fill-rule="nonzero"/></svg>',
    "border-style": '<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="2" x="3" y="6" rx="1"/><rect width="2.8" height="2" x="3" y="16" rx="1"/><rect width="2.8" height="2" x="6.8" y="16" rx="1"/><rect width="2.8" height="2" x="10.6" y="16" rx="1"/><rect width="2.8" height="2" x="14.4" y="16" rx="1"/><rect width="2.8" height="2" x="18.2" y="16" rx="1"/><rect width="8" height="2" x="3" y="11" rx="1"/><rect width="8" height="2" x="13" y="11" rx="1"/></g></svg>',
    "border-width": '<svg width="24" height="24"><g fill-rule="evenodd"><rect width="18" height="5" x="3" y="5" rx="1"/><rect width="18" height="3.5" x="3" y="11.5" rx="1"/><rect width="18" height="2" x="3" y="17" rx="1"/></g></svg>',
    "brightness": '<svg width="24" height="24"><path d="M12 17c.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7v-1c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3Zm0-10a1 1 0 0 1-.7-.3A1 1 0 0 1 11 6V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v1c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3Zm7 4c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-1a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1ZM7 12c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H5a1 1 0 0 1-.7-.3A1 1 0 0 1 4 12c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h1c.3 0 .5.1.7.3.2.2.3.4.3.7Zm10 3.5.7.8c.2.1.3.4.3.6 0 .3-.1.6-.3.8a1 1 0 0 1-.8.3 1 1 0 0 1-.6-.3l-.8-.7a1 1 0 0 1-.3-.8c0-.2.1-.5.3-.7a1 1 0 0 1 1.4 0Zm-10-7-.7-.8a1 1 0 0 1-.3-.6c0-.3.1-.6.3-.8.2-.2.5-.3.8-.3.2 0 .5.1.7.3l.7.7c.2.2.3.5.3.8 0 .2-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.8-.3Zm10 0a1 1 0 0 1-.8.3 1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.6.3-.8l.8-.7c.1-.2.4-.3.6-.3.3 0 .6.1.8.3.2.2.3.5.3.8 0 .2-.1.5-.3.7l-.7.7Zm-10 7c.2-.2.5-.3.8-.3.2 0 .5.1.7.3a1 1 0 0 1 0 1.4l-.8.8a1 1 0 0 1-.6.3 1 1 0 0 1-.8-.3 1 1 0 0 1-.3-.8c0-.2.1-.5.3-.6l.7-.8ZM12 8a4 4 0 0 1 3.7 2.4 4 4 0 0 1 0 3.2A4 4 0 0 1 12 16a4 4 0 0 1-3.7-2.4 4 4 0 0 1 0-3.2A4 4 0 0 1 12 8Zm0 6.5c.7 0 1.3-.2 1.8-.7.5-.5.7-1.1.7-1.8s-.2-1.3-.7-1.8c-.5-.5-1.1-.7-1.8-.7s-1.3.2-1.8.7c-.5.5-.7 1.1-.7 1.8s.2 1.3.7 1.8c.5.5 1.1.7 1.8.7Z" fill-rule="evenodd"/></svg>',
    "browse": '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-4v-2h4V8H5v10h4v2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9.4-2.3 2.3a1 1 0 1 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 0 1-1.4 1.4L13 13.4V20a1 1 0 0 1-2 0v-6.6Z" fill-rule="nonzero"/></svg>',
    "cancel": '<svg width="24" height="24"><path d="M12 4.6a7.4 7.4 0 1 1 0 14.8 7.4 7.4 0 0 1 0-14.8ZM12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18Zm0 8L14.8 8l1 1.1-2.7 2.8 2.7 2.7-1.1 1.1-2.7-2.7-2.7 2.7-1-1.1 2.6-2.7-2.7-2.7 1-1.1 2.8 2.7Z" fill-rule="nonzero"/></svg>',
    "cell-background-color": '<svg width="24" height="24"><path d="m15.7 2 1.6 1.6-2.7 2.6 5.9 5.8c.7.7.7 1.7 0 2.4l-6.3 6.1a1.7 1.7 0 0 1-2.4 0l-6.3-6.1c-.7-.7-.7-1.7 0-2.4L15.7 2ZM18 12l-4.5-4L9 12h9ZM4 16s2 2.4 2 3.8C6 21 5.1 22 4 22s-2-1-2-2.2C2 18.4 4 16 4 16Z"/></svg>',
    "cell-border-color": '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M5 13v5h2v2H5a2 2 0 0 1-2-2v-5h2zm8-7V4h6a2 2 0 0 1 2 2h-8z" opacity=".2"/><path fill-rule="nonzero" d="M13 4v2H5v7H3V6c0-1.1.9-2 2-2h8zm-2.6 14.1.1-.1.1.1.2.3.2.2.2.2c.4.6.8 1.2.8 1.7 0 .8-.7 1.5-1.5 1.5S9 21.3 9 20.5c0-.5.4-1.1.8-1.7l.2-.2.2-.2.2-.3z"/><path d="m13 11-2 2H5v-2h6V6h2z"/><path fill-rule="nonzero" d="m18.4 8 1 1-1.8 1.9 4 4c.5.4.5 1.1 0 1.6l-4.3 4.2a1.2 1.2 0 0 1-1.6 0l-4.4-4.2c-.4-.5-.4-1.2 0-1.7l7-6.8Zm1.6 7-3-3-3 3h6Z"/></g></svg>',
    "change-case": '<svg width="24" height="24"><path d="M18.4 18.2v-.6c-.5.8-1.3 1.2-2.4 1.2-2.2 0-3.3-1.6-3.3-4.8 0-3.1 1-4.7 3.3-4.7 1.1 0 1.8.3 2.4 1.1v-.6c0-.5.4-.8.8-.8s.8.3.8.8v8.4c0 .5-.4.8-.8.8a.8.8 0 0 1-.8-.8zm-2-7.4c-1.3 0-1.8.9-1.8 3.2 0 2.4.5 3.3 1.7 3.3 1.3 0 1.8-.9 1.8-3.2 0-2.4-.5-3.3-1.7-3.3zM10 15.7H5.5l-.8 2.6a1 1 0 0 1-1 .7h-.2a.7.7 0 0 1-.7-1l4-12a1 1 0 0 1 2 0l4 12a.7.7 0 0 1-.8 1h-.2a1 1 0 0 1-1-.7l-.8-2.6zm-.3-1.5-2-6.5-1.9 6.5h3.9z" fill-rule="evenodd"/></svg>',
    "character-count": '<svg width="24" height="24"><path d="M4 11.5h16v1H4v-1Zm4.8-6.8V10H7.7V5.8h-1v-1h2ZM11 8.3V9h2v1h-3V7.7l2-1v-.9h-2v-1h3v2.4l-2 1Zm6.3-3.4V10h-3.1V9h2.1V8h-2.1V6.8h2.1v-1h-2.1v-1h3.1ZM5.8 16.4c0-.5.2-.8.5-1 .2-.2.6-.3 1.2-.3l.8.1c.2 0 .4.2.5.3l.4.4v2.8l.2.3H8.2V18.7l-.6.3H7c-.4 0-.7 0-1-.2a1 1 0 0 1-.3-.9c0-.3 0-.6.3-.8.3-.2.7-.4 1.2-.4l.6-.2h.3v-.2l-.1-.2a.8.8 0 0 0-.5-.1 1 1 0 0 0-.4 0l-.3.4h-1Zm2.3.8h-.2l-.2.1-.4.1a1 1 0 0 0-.4.2l-.2.2.1.3.5.1h.4l.4-.4v-.6Zm2-3.4h1.2v1.7l.5-.3h.5c.5 0 .9.1 1.2.5.3.4.5.8.5 1.4 0 .6-.2 1.1-.5 1.5-.3.4-.7.6-1.3.6l-.6-.1-.4-.4v.4h-1.1v-5.4Zm1.1 3.3c0 .3 0 .6.2.8a.7.7 0 0 0 1.2 0l.2-.8c0-.4 0-.6-.2-.8a.7.7 0 0 0-.6-.3l-.6.3-.2.8Zm6.1-.5c0-.2 0-.3-.2-.4a.8.8 0 0 0-.5-.2c-.3 0-.5.1-.6.3l-.2.9c0 .3 0 .6.2.8.1.2.3.3.6.3.2 0 .4 0 .5-.2l.2-.4h1.1c0 .5-.3.8-.6 1.1a2 2 0 0 1-1.3.4c-.5 0-1-.2-1.3-.6a2 2 0 0 1-.5-1.4c0-.6.1-1.1.5-1.5.3-.4.8-.5 1.4-.5.5 0 1 0 1.2.3.4.3.5.7.5 1.2h-1v-.1Z" fill-rule="evenodd"/></svg>',
    "checklist-rtl": '<svg width="24" height="24"><path d="M5 17h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 0 1 0-2zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1H5a1 1 0 1 1 0-2zm14.2 11c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L18 8c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8z" fill-rule="evenodd"/></svg>',
    "checklist": '<svg width="24" height="24"><path d="M11 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2h-8a1 1 0 0 1 0-2ZM7.2 16c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 20c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 14c-.2.3-.7.4-1 0l-1.3-1.3a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Zm0-6c.2-.4.6-.5.9-.3.3.2.4.6.2 1L6 8c-.2.3-.7.4-1 0L3.8 6.9a.7.7 0 0 1 0-1c.3-.2.7-.2 1 0l.7.9 1.7-2.8Z" fill-rule="evenodd"/></svg>',
    "checkmark": '<svg width="24" height="24"><path d="M18.2 5.4a1 1 0 0 1 1.6 1.2l-8 12a1 1 0 0 1-1.5.1l-5-5a1 1 0 1 1 1.4-1.4l4.1 4.1 7.4-11Z" fill-rule="nonzero"/></svg>',
    "chevron-down": '<svg width="10" height="10"><path d="M8.7 2.2c.3-.3.8-.3 1 0 .4.4.4.9 0 1.2L5.7 7.8c-.3.3-.9.3-1.2 0L.2 3.4a.8.8 0 0 1 0-1.2c.3-.3.8-.3 1.1 0L5 6l3.7-3.8Z" fill-rule="nonzero"/></svg>',
    "chevron-left": '<svg width="10" height="10"><path d="M7.8 1.3 4 5l3.8 3.7c.3.3.3.8 0 1-.4.4-.9.4-1.2 0L2.2 5.7a.8.8 0 0 1 0-1.2L6.6.2C7 0 7.4 0 7.8.2c.3.3.3.8 0 1.1Z" fill-rule="nonzero"/></svg>',
    "chevron-right": '<svg width="10" height="10"><path d="M2.2 1.3a.8.8 0 0 1 0-1c.4-.4.9-.4 1.2 0l4.4 4.1c.3.4.3.9 0 1.2L3.4 9.8c-.3.3-.8.3-1.2 0a.8.8 0 0 1 0-1.1L6 5 2.2 1.3Z" fill-rule="nonzero"/></svg>',
    "chevron-up": '<svg width="10" height="10"><path d="M8.7 7.8 5 4 1.3 7.8c-.3.3-.8.3-1 0a.8.8 0 0 1 0-1.2l4.1-4.4c.3-.3.9-.3 1.2 0l4.2 4.4c.3.3.3.9 0 1.2-.3.3-.8.3-1.1 0Z" fill-rule="nonzero"/></svg>',
    "close": '<svg width="24" height="24"><path d="M17.3 8.2 13.4 12l3.9 3.8a1 1 0 0 1-1.5 1.5L12 13.4l-3.8 3.9a1 1 0 0 1-1.5-1.5l3.9-3.8-3.9-3.8a1 1 0 0 1 1.5-1.5l3.8 3.9 3.8-3.9a1 1 0 0 1 1.5 1.5Z" fill-rule="evenodd"/></svg>',
    "code-sample": '<svg width="24" height="26"><path d="M7.1 11a2.8 2.8 0 0 1-.8 2 2.8 2.8 0 0 1 .8 2v1.7c0 .3.1.6.4.8.2.3.5.4.8.4.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.7 0-1.4-.3-2-.8-.5-.6-.8-1.3-.8-2V15c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4v-.8c0-.2.2-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V9.3c0-.7.3-1.4.8-2 .6-.5 1.3-.8 2-.8.3 0 .4.2.4.4v.8c0 .2-.1.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8V11Zm9.8 0V9.3c0-.3-.1-.6-.4-.8-.2-.3-.5-.4-.8-.4a.4.4 0 0 1-.4-.4V7c0-.2.1-.4.4-.4.7 0 1.4.3 2 .8.5.6.8 1.3.8 2V11c0 .3.1.6.4.8.2.3.5.4.8.4.2 0 .4.2.4.4v.8c0 .2-.2.4-.4.4-.3 0-.6.1-.8.4-.3.2-.4.5-.4.8v1.7c0 .7-.3 1.4-.8 2-.6.5-1.3.8-2 .8a.4.4 0 0 1-.4-.4v-.8c0-.2.1-.4.4-.4.3 0 .6-.1.8-.4.3-.2.4-.5.4-.8V15a2.8 2.8 0 0 1 .8-2 2.8 2.8 0 0 1-.8-2Zm-3.3-.4c0 .4-.1.8-.5 1.1-.3.3-.7.5-1.1.5-.4 0-.8-.2-1.1-.5-.4-.3-.5-.7-.5-1.1 0-.5.1-.9.5-1.2.3-.3.7-.4 1.1-.4.4 0 .8.1 1.1.4.4.3.5.7.5 1.2ZM12 13c.4 0 .8.1 1.1.5.4.3.5.7.5 1.1 0 1-.1 1.6-.5 2a3 3 0 0 1-1.1 1c-.4.3-.8.4-1.1.4a.5.5 0 0 1-.5-.5V17a3 3 0 0 0 1-.2l.6-.6c-.6 0-1-.2-1.3-.5-.2-.3-.3-.7-.3-1 0-.5.1-1 .5-1.2.3-.4.7-.5 1.1-.5Z" fill-rule="evenodd"/></svg>',
    "color-levels": '<svg width="24" height="24"><path d="M17.5 11.4A9 9 0 0 1 18 14c0 .5 0 1-.2 1.4 0 .4-.3.9-.5 1.3a6.2 6.2 0 0 1-3.7 3 5.7 5.7 0 0 1-3.2 0A5.9 5.9 0 0 1 7.6 18a6.2 6.2 0 0 1-1.4-2.6 6.7 6.7 0 0 1 0-2.8c0-.4.1-.9.3-1.3a13.6 13.6 0 0 1 2.3-4A20 20 0 0 1 12 4a26.4 26.4 0 0 1 3.2 3.4 18.2 18.2 0 0 1 2.3 4Zm-2 4.5c.4-.7.5-1.4.5-2a7.3 7.3 0 0 0-1-3.2c.2.6.2 1.2.2 1.9a4.5 4.5 0 0 1-1.3 3 5.3 5.3 0 0 1-2.3 1.5 4.9 4.9 0 0 1-2 .1 4.3 4.3 0 0 0 2.4.8 4 4 0 0 0 2-.6 4 4 0 0 0 1.5-1.5Z" fill-rule="evenodd"/></svg>',
    "color-picker": '<svg width="24" height="24"><path d="M12 3a9 9 0 0 0 0 18 1.5 1.5 0 0 0 1.1-2.5c-.2-.3-.4-.6-.4-1 0-.8.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.4-4-8-9-8Zm-5.5 9a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3-4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Zm3 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z" fill-rule="nonzero"/></svg>',
    "color-swatch-remove-color": '<svg width="24" height="24"><path stroke="#000" stroke-width="2" d="M21 3 3 21" fill-rule="evenodd"/></svg>',
    "color-swatch": '<svg width="24" height="24"><rect x="3" y="3" width="18" height="18" rx="1" fill-rule="evenodd"/></svg>',
    "comment-add": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/><path d="M13 10h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V8a1 1 0 0 1 2 0v2Z"/></g></svg>',
    "comment": '<svg width="24" height="24"><path fill-rule="nonzero" d="m9 19 3-2h7c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H5a1 1 0 0 0-1 1v10c0 .6.4 1 1 1h4v2Zm-2 4v-4H5a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h14a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-6.4L7 23Z"/></svg>',
    "contrast": '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-6 8a6 6 0 0 0 6 6V6a6 6 0 0 0-6 6Z" fill-rule="evenodd"/></svg>',
    "copy": '<svg width="24" height="24"><path d="M16 3H6a2 2 0 0 0-2 2v11h2V5h10V3Zm1 4a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7Zm0 12V9h-7v10h7Z" fill-rule="nonzero"/></svg>',
    "crop": '<svg width="24" height="24"><path d="M17 8v7h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v2c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-2H7V9H5a1 1 0 1 1 0-2h2V5c0-.6.4-1 1-1s1 .4 1 1v2h7l3-3 1 1-3 3ZM9 9v5l5-5H9Zm1 6h5v-5l-5 5Z" fill-rule="evenodd"/></svg>',
    "cut-column": '<svg width="24" height="24"><path fill-rule="evenodd" d="M7.2 4.5c.9 0 1.6.4 2.2 1A3.7 3.7 0 0 1 10.5 8v.5l1 1 4-4 1-.5a3.3 3.3 0 0 1 2 0c.4 0 .7.3 1 .5L17 8h4v13h-6V10l-1.5 1.5.5.5v4l-2.5-2.5-1 1v.5c0 .4 0 .8-.3 1.2-.2.5-.4.9-.8 1.2-.6.7-1.3 1-2.2 1-.8.2-1.5 0-2-.6l-.5-.8-.2-1c0-.4 0-.8.3-1.2A3.9 3.9 0 0 1 7 12.7c.5-.2 1-.3 1.5-.2l1-1-1-1c-.5 0-1 0-1.5-.2-.5-.1-1-.4-1.4-.9-.4-.3-.6-.7-.8-1.2L4.5 7c0-.4 0-.7.2-1 0-.3.3-.6.5-.8.5-.5 1.2-.8 2-.7Zm12.3 5h-3v10h3v-10ZM8 13.8h-.3l-.4.2a2.8 2.8 0 0 0-.7.4v.1a2.8 2.8 0 0 0-.6.8l-.1.4v.7l.2.5.5.2h.7a2.6 2.6 0 0 0 .8-.3 2.4 2.4 0 0 0 .7-.7 2.5 2.5 0 0 0 .3-.8 1.5 1.5 0 0 0 0-.8 1 1 0 0 0-.2-.4 1 1 0 0 0-.5-.2H8Zm3.5-3.7c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4ZM7 5.8h-.4a1 1 0 0 0-.5.3 1 1 0 0 0-.2.5v.7a2.5 2.5 0 0 0 .3.8l.2.3h.1l.4.4.4.2.4.1h.7L9 9l.2-.4a1.6 1.6 0 0 0 0-.8 2.6 2.6 0 0 0-.3-.8A2.5 2.5 0 0 0 7.7 6l-.4-.1H7Z"/></svg>',
    "cut-row": '<svg width="24" height="24"><path fill-rule="evenodd" d="M22 3v5H9l3 3 2-2h4l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8.7.6 1 1.3 1 2.2.2.8 0 1.5-.6 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l2 2V3h14ZM8.5 15.3h-.3a2.6 2.6 0 0 0-.8.4 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3L9 18V18l.4-.4.2-.4.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2h-.5Zm7 0H15a1 1 0 0 0-.4.3 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4a2.8 2.8 0 0 0 .5.7h.1a2.8 2.8 0 0 0 .8.6l.4.1h.7l.5-.2.2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3h-.3ZM12 11.6c-.4 0-.7.1-1 .4-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4s.7-.1 1-.4c.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4Zm8.5-7.1h-11v2h11v-2Z"/></svg>',
    "cut": '<svg width="24" height="24"><path d="M18 15c.6.7 1 1.4 1 2.3 0 .8-.2 1.5-.7 2l-.8.5-1 .2c-.4 0-.8 0-1.2-.3a3.9 3.9 0 0 1-2.1-2.2c-.2-.5-.3-1-.2-1.5l-1-1-1 1c0 .5 0 1-.2 1.5-.1.5-.4 1-.9 1.4-.3.4-.7.6-1.2.8l-1.2.3c-.4 0-.7 0-1-.2-.3 0-.6-.3-.8-.5-.5-.5-.8-1.2-.7-2 0-.9.4-1.6 1-2.2A3.7 3.7 0 0 1 8.6 14H9l1-1-4-4-.5-1a3.3 3.3 0 0 1 0-2c0-.4.3-.7.5-1l6 6 6-6 .5 1a3.3 3.3 0 0 1 0 2c0 .4-.3.7-.5 1l-4 4 1 1h.5c.4 0 .8 0 1.2.3.5.2.9.4 1.2.8Zm-8.5 2.2.1-.4v-.7a1 1 0 0 0-.2-.5 1 1 0 0 0-.4-.2 1.6 1.6 0 0 0-.8 0 2.6 2.6 0 0 0-.8.3 2.5 2.5 0 0 0-.9 1.1l-.1.4v.7l.2.5.5.2h.7a2.5 2.5 0 0 0 .8-.3 2.8 2.8 0 0 0 1-1Zm2.5-2.8c.4 0 .7-.1 1-.4.3-.3.4-.6.4-1s-.1-.7-.4-1c-.3-.3-.6-.4-1-.4s-.7.1-1 .4c-.3.3-.4.6-.4 1s.1.7.4 1c.3.3.6.4 1 .4Zm5.4 4 .2-.5v-.7a2.6 2.6 0 0 0-.3-.8 2.4 2.4 0 0 0-.7-.7 2.5 2.5 0 0 0-.8-.3 1.5 1.5 0 0 0-.8 0 1 1 0 0 0-.4.2 1 1 0 0 0-.2.5 1.5 1.5 0 0 0 0 .7v.4l.3.4.3.4a2.8 2.8 0 0 0 .8.5l.4.1h.7l.5-.2Z" fill-rule="evenodd"/></svg>',
    "document-properties": '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',
    "drag": '<svg width="24" height="24"><path d="M13 5h2v2h-2V5Zm0 4h2v2h-2V9ZM9 9h2v2H9V9Zm4 4h2v2h-2v-2Zm-4 0h2v2H9v-2Zm0 4h2v2H9v-2Zm4 0h2v2h-2v-2ZM9 5h2v2H9V5Z" fill-rule="evenodd"/></svg>',
    "duplicate-column": '<svg width="24" height="24"><path d="M17 6v16h-7V6h7Zm-2 2h-3v12h3V8Zm-2-6v2H8v15H6V2h7Z"/></svg>',
    "duplicate-row": '<svg width="24" height="24"><path d="M22 11v7H6v-7h16Zm-2 2H8v3h12v-3Zm-1-6v2H4v5H2V7h17Z"/></svg>',
    "duplicate": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M16 3v2H6v11H4V5c0-1.1.9-2 2-2h10Zm3 8h-2V9h-7v10h9a2 2 0 0 1-2 2h-7a2 2 0 0 1-2-2V9c0-1.2.9-2 2-2h7a2 2 0 0 1 2 2v2Z"/><path d="M17 14h1a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1h-1a1 1 0 0 1 0-2h1v-1a1 1 0 0 1 2 0v1Z"/></g></svg>',
    "edit-block": '<svg width="24" height="24"><path fill-rule="nonzero" d="m19.8 8.8-9.4 9.4c-.2.2-.5.4-.9.4l-5.4 1.2 1.2-5.4.5-.8 9.4-9.4c.7-.7 1.8-.7 2.5 0l2.1 2.1c.7.7.7 1.8 0 2.5Zm-2-.2 1-.9v-.3l-2.2-2.2a.3.3 0 0 0-.3 0l-1 1L18 8.5Zm-1 1-2.5-2.4-6 6 2.5 2.5 6-6Zm-7 7.1-2.6-2.4-.3.3-.1.2-.7 3 3.1-.6h.1l.4-.5Z"/></svg>',
    "edit-image": '<svg width="24" height="24"><path d="M18 16h2V7a2 2 0 0 0-2-2H7v2h11v9ZM6 17h15a1 1 0 0 1 0 2h-1v1a1 1 0 0 1-2 0v-1H6a2 2 0 0 1-2-2V7H3a1 1 0 1 1 0-2h1V4a1 1 0 1 1 2 0v13Zm3-5.3 1.3 2 3-4.7 3.7 6H7l2-3.3Z" fill-rule="nonzero"/></svg>',
    "embed-page": '<svg width="24" height="24"><path d="M19 6V5H5v14h2A13 13 0 0 1 19 6Zm0 1.4c-.8.8-1.6 2.4-2.2 4.6H19V7.4Zm0 5.6h-2.4c-.4 1.8-.6 3.8-.6 6h3v-6Zm-4 6c0-2.2.2-4.2.6-6H13c-.7 1.8-1.1 3.8-1.1 6h3Zm-4 0c0-2.2.4-4.2 1-6H9.6A12 12 0 0 0 8 19h3ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm11.8 9c.4-1.9 1-3.4 1.8-4.5a9.2 9.2 0 0 0-4 4.5h2.2Zm-3.4 0a12 12 0 0 1 2.8-4 12 12 0 0 0-5 4h2.2Z" fill-rule="nonzero"/></svg>',
    "embed": '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm4.8 2.6 5.6 4a.5.5 0 0 1 0 .8l-5.6 4A.5.5 0 0 1 9 16V8a.5.5 0 0 1 .8-.4Z" fill-rule="nonzero"/></svg>',
    "emoji": '<svg width="24" height="24"><path d="M9 11c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm6 0c.6 0 1-.4 1-1s-.4-1-1-1a1 1 0 0 0-1 1c0 .6.4 1 1 1Zm-3 5.5c2.1 0 4-1.5 4.4-3.5H7.6c.5 2 2.3 3.5 4.4 3.5ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm0 14.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13Z" fill-rule="nonzero"/></svg>',
    "export": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M14.4 3 18 7v1h-5V5H7v14h9a1 1 0 0 1 2 0c0 1-.8 2-1.9 2H7c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2h7.5Z"/><path d="M18.1 12c.5 0 .9.4.9 1 0 .5-.3 1-.8 1h-7.3c-.5 0-.9-.4-.9-1 0-.5.3-1 .8-1h7.3Z"/><path d="M16.4 9.2a1 1 0 0 1 1.4.2l2.4 3.6-2.4 3.6a1 1 0 0 1-1.7-1v-.2l1.7-2.4-1.6-2.4a1 1 0 0 1 .2-1.4Z"/></g></svg>',
    "fill": '<svg width="24" height="26"><path d="m16.6 12-9-9-1.4 1.4 2.4 2.4-5.2 5.1c-.5.6-.5 1.6 0 2.2L9 19.6a1.5 1.5 0 0 0 2.2 0l5.5-5.5c.5-.6.5-1.6 0-2.2ZM5.2 13 10 8.2l4.8 4.8H5.2ZM19 14.5s-2 2.2-2 3.5c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.3-2-3.5-2-3.5Z" fill-rule="nonzero"/></svg>',
    "flip-horizontally": '<svg width="24" height="24"><path d="M14 19h2v-2h-2v2Zm4-8h2V9h-2v2ZM4 7v10c0 1.1.9 2 2 2h3v-2H6V7h3V5H6a2 2 0 0 0-2 2Zm14-2v2h2a2 2 0 0 0-2-2Zm-7 16h2V3h-2v18Zm7-6h2v-2h-2v2Zm-4-8h2V5h-2v2Zm4 12a2 2 0 0 0 2-2h-2v2Z" fill-rule="nonzero"/></svg>',
    "flip-vertically": '<svg width="24" height="24"><path d="M5 14v2h2v-2H5Zm8 4v2h2v-2h-2Zm4-14H7a2 2 0 0 0-2 2v3h2V6h10v3h2V6a2 2 0 0 0-2-2Zm2 14h-2v2a2 2 0 0 0 2-2ZM3 11v2h18v-2H3Zm6 7v2h2v-2H9Zm8-4v2h2v-2h-2ZM5 18c0 1.1.9 2 2 2v-2H5Z" fill-rule="nonzero"/></svg>',
    "format-painter": '<svg width="24" height="24"><path d="M18 5V4c0-.5-.4-1-1-1H5a1 1 0 0 0-1 1v4c0 .6.5 1 1 1h12c.6 0 1-.4 1-1V7h1v4H9v9c0 .6.4 1 1 1h2c.6 0 1-.4 1-1v-7h8V5h-3Z" fill-rule="nonzero"/></svg>',
    "format": '<svg width="24" height="24"><path fill-rule="evenodd" d="M17 5a1 1 0 0 1 0 2h-4v11a1 1 0 0 1-2 0V7H7a1 1 0 1 1 0-2h10Z"/></svg>',
    "fullscreen": '<svg width="24" height="24"><path d="m15.3 10-1.2-1.3 2.9-3h-2.3a.9.9 0 1 1 0-1.7H19c.5 0 .9.4.9.9v4.4a.9.9 0 1 1-1.8 0V7l-2.9 3Zm0 4 3 3v-2.3a.9.9 0 1 1 1.7 0V19c0 .5-.4.9-.9.9h-4.4a.9.9 0 1 1 0-1.8H17l-3-2.9 1.3-1.2ZM10 15.4l-2.9 3h2.3a.9.9 0 1 1 0 1.7H5a.9.9 0 0 1-.9-.9v-4.4a.9.9 0 1 1 1.8 0V17l2.9-3 1.2 1.3ZM8.7 10 5.7 7v2.3a.9.9 0 0 1-1.7 0V5c0-.5.4-.9.9-.9h4.4a.9.9 0 0 1 0 1.8H7l3 2.9-1.3 1.2Z" fill-rule="nonzero"/></svg>',
    "gallery": '<svg width="24" height="24"><path fill-rule="nonzero" d="m5 15.7 2.3-2.2c.3-.3.7-.3 1 0L11 16l5.1-5c.3-.4.8-.4 1 0l2 1.9V8H5v7.7ZM5 18V19h3l1.8-1.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 6h16c.6 0 1 .4 1 1v13c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V7c0-.6.4-1 1-1Zm6 7a2 2 0 1 1 0-4 2 2 0 0 1 0 4ZM4.5 4h15a.5.5 0 1 1 0 1h-15a.5.5 0 0 1 0-1Zm2-2h11a.5.5 0 1 1 0 1h-11a.5.5 0 0 1 0-1Z"/></svg>',
    "gamma": '<svg width="24" height="24"><path d="M4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm1 2v14h14V5H5Zm6.5 11.8V14L9.2 8.7a5.1 5.1 0 0 0-.4-.8l-.1-.2H8v-1l.3-.1.3-.1h.7a1 1 0 0 1 .6.5l.1.3a8.5 8.5 0 0 1 .3.6l1.9 4.6 2-5.2a1 1 0 0 1 1-.6.5.5 0 0 1 .5.6L13 14v2.8a.7.7 0 0 1-1.4 0Z" fill-rule="nonzero"/></svg>',
    "help": '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M12 5.5a6.5 6.5 0 0 0-6 9 6.3 6.3 0 0 0 1.4 2l1 1a6.3 6.3 0 0 0 3.6 1 6.5 6.5 0 0 0 6-9 6.3 6.3 0 0 0-1.4-2l-1-1a6.3 6.3 0 0 0-3.6-1ZM12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Z"/><path d="M9.6 9.7a.7.7 0 0 1-.7-.8c0-1.1 1.5-1.8 3.2-1.8 1.8 0 3.2.8 3.2 2.4 0 1.4-.4 2.1-1.5 2.8-.2 0-.3.1-.3.2a2 2 0 0 0-.8.8.8.8 0 0 1-1.4-.6c.3-.7.8-1 1.3-1.5l.4-.2c.7-.4.8-.6.8-1.5 0-.5-.6-.9-1.7-.9-.5 0-1 .1-1.4.3-.2 0-.3.1-.3.2v-.2c0 .4-.4.8-.8.8Z" fill-rule="nonzero"/><circle cx="12" cy="16" r="1"/></g></svg>',
    "highlight-bg-color": '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-highlight-bg-color__color" d="M3 18h18v3H3z"/><path fill-rule="nonzero" d="M7.7 16.7H3l3.3-3.3-.7-.8L10.2 8l4 4.1-4 4.2c-.2.2-.6.2-.8 0l-.6-.7-1.1 1.1zm5-7.5L11 7.4l3-2.9a2 2 0 0 1 2.6 0L18 6c.7.7.7 2 0 2.7l-2.9 2.9-1.8-1.8-.5-.6"/></g></svg>',
    "home": '<svg width="24" height="24"><path fill-rule="nonzero" d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',
    "horizontal-rule": '<svg width="24" height="24"><path d="M4 11h16v2H4z" fill-rule="evenodd"/></svg>',
    "image-options": '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',
    "image": '<svg width="24" height="24"><path d="m5 15.7 3.3-3.2c.3-.3.7-.3 1 0L12 15l4.1-4c.3-.4.8-.4 1 0l2 1.9V5H5v10.7ZM5 18V19h3l2.8-2.9-2-2L5 17.9Zm14-3-2.5-2.4-6.4 6.5H19v-4ZM4 3h16c.6 0 1 .4 1 1v16c0 .6-.4 1-1 1H4a1 1 0 0 1-1-1V4c0-.6.4-1 1-1Zm6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" fill-rule="nonzero"/></svg>',
    "indent": '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm-2.6-3.8L6.2 12l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',
    "info": '<svg width="24" height="24"><path d="M12 4a7.8 7.8 0 0 1 5.7 2.3A8 8 0 1 1 12 4Zm-1 3v2h2V7h-2Zm3 10v-1h-1v-5h-3v1h1v4h-1v1h4Z" fill-rule="evenodd"/></svg>',
    "insert-character": '<svg width="24" height="24"><path d="M15 18h4l1-2v4h-6v-3.3l1.4-1a6 6 0 0 0 1.8-2.9 6.3 6.3 0 0 0-.1-4.1 5.8 5.8 0 0 0-3-3.2c-.6-.3-1.3-.5-2.1-.5a5.1 5.1 0 0 0-3.9 1.8 6.3 6.3 0 0 0-1.3 6 6.2 6.2 0 0 0 1.8 3l1.4.9V20H4v-4l1 2h4v-.5l-2-1L5.4 15A6.5 6.5 0 0 1 4 11c0-1 .2-1.9.6-2.7A7 7 0 0 1 6.3 6C7.1 5.4 8 5 9 4.5c1-.3 2-.5 3.1-.5a8.8 8.8 0 0 1 5.7 2 7 7 0 0 1 1.7 2.3 6 6 0 0 1 .2 4.8c-.2.7-.6 1.3-1 1.9a7.6 7.6 0 0 1-3.6 2.5v.5Z" fill-rule="evenodd"/></svg>',
    "insert-time": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M12 19a7 7 0 1 0 0-14 7 7 0 0 0 0 14Zm0 2a9 9 0 1 1 0-18 9 9 0 0 1 0 18Z"/><path d="M16 12h-3V7c0-.6-.4-1-1-1a1 1 0 0 0-1 1v7h5c.6 0 1-.4 1-1s-.4-1-1-1Z"/></g></svg>',
    "invert": '<svg width="24" height="24"><path d="M18 19.3 16.5 18a5.8 5.8 0 0 1-3.1 1.9 6.1 6.1 0 0 1-5.5-1.6A5.8 5.8 0 0 1 6 14v-.3l.1-1.2A13.9 13.9 0 0 1 7.7 9l-3-3 .7-.8 2.8 2.9 9 8.9 1.5 1.6-.7.6Zm0-5.5v.3l-.1 1.1-.4 1-1.2-1.2a4.3 4.3 0 0 0 .2-1v-.2c0-.4 0-.8-.2-1.3l-.5-1.4a14.8 14.8 0 0 0-3-4.2L12 6a26.1 26.1 0 0 0-2.2 2.5l-1-1a20.9 20.9 0 0 1 2.9-3.3L12 4l1 .8a22.2 22.2 0 0 1 4 5.4c.6 1.2 1 2.4 1 3.6Z" fill-rule="evenodd"/></svg>',
    "italic": '<svg width="24" height="24"><path d="m16.7 4.7-.1.9h-.3c-.6 0-1 0-1.4.3-.3.3-.4.6-.5 1.1l-2.1 9.8v.6c0 .5.4.8 1.4.8h.2l-.2.8H8l.2-.8h.2c1.1 0 1.8-.5 2-1.5l2-9.8.1-.5c0-.6-.4-.8-1.4-.8h-.3l.2-.9h5.8Z" fill-rule="evenodd"/></svg>',
    "language": '<svg width="24" height="24"><path d="M12 3a9 9 0 1 1 0 18 9 9 0 0 1 0-18Zm4.3 13.3c-.5 1-1.2 2-2 2.9a7.5 7.5 0 0 0 3.2-2.1l-.2-.2a6 6 0 0 0-1-.6Zm-8.6 0c-.5.2-.9.5-1.2.8.9 1 2 1.7 3.2 2a10 10 0 0 1-2-2.8Zm3.6-.8c-.8 0-1.6.1-2.2.3.5 1 1.2 1.9 2.1 2.7Zm1.5 0v3c.9-.8 1.6-1.7 2.1-2.7-.6-.2-1.4-.3-2.1-.3Zm-6-2.7H4.5c.2 1 .5 2.1 1 3h.3l1.3-1a10 10 0 0 1-.3-2Zm12.7 0h-2.3c0 .7-.1 1.4-.3 2l1.6 1.1c.5-1 .9-2 1-3.1Zm-3.8 0h-3V14c1 0 2 .1 2.7.4.2-.5.3-1 .3-1.6Zm-4.4 0h-3l.3 1.6c.8-.3 1.7-.4 2.7-.4v-1.3Zm-5.5-5c-.7 1-1.1 2.2-1.3 3.5h2.3c0-1 .2-1.8.5-2.6l-1.5-1Zm2.9 1.4v.1c-.2.6-.4 1.3-.4 2h3V9.4c-1 0-1.8-.1-2.6-.3Zm6.6 0h-.1l-2.4.3v1.8h3l-.5-2.1Zm3-1.4-.3.1-1.3.8c.3.8.5 1.6.5 2.6h2.3a7.5 7.5 0 0 0-1.3-3.5Zm-9 0 2 .2V5.5a9 9 0 0 0-2 2.2Zm3.5-2.3V8c.6 0 1.3 0 1.9-.2a9 9 0 0 0-2-2.3Zm-3-.7h-.1c-1.1.4-2.1 1-3 1.8l1.2.7a10 10 0 0 1 1.9-2.5Zm4.4 0 .1.1a10 10 0 0 1 1.8 2.4l1.1-.7a7.5 7.5 0 0 0-3-1.8Z"/></svg>',
    "line-height": '<svg width="24" height="24"><path d="M21 5a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zm0 4a1 1 0 0 1 .1 2H13a1 1 0 0 1-.1-2H21zM7 3.6l3.7 3.7a1 1 0 0 1-1.3 1.5h-.1L8 7.3v9.2l1.3-1.3a1 1 0 0 1 1.3 0h.1c.4.4.4 1 0 1.3v.1L7 20.4l-3.7-3.7a1 1 0 0 1 1.3-1.5h.1L6 16.7V7.4L4.7 8.7a1 1 0 0 1-1.3 0h-.1a1 1 0 0 1 0-1.3v-.1L7 3.6z"/></svg>',
    "line": '<svg width="24" height="24"><path d="m15 9-8 8H4v-3l8-8 3 3Zm1-1-3-3 1-1h1c-.2 0 0 0 0 0l2 2s0 .2 0 0v1l-1 1ZM4 18h16v2H4v-2Z" fill-rule="evenodd"/></svg>',
    "link": '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2-2a2 2 0 1 0-2.6-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2Z" fill-rule="nonzero"/></svg>',
    "list-bull-circle": '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M11 16a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 26a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6ZM11 36a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm0 1a3 3 0 1 1 0-6 3 3 0 0 1 0 6Z" fill-rule="nonzero"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
    "list-bull-default": '<svg width="48" height="48"><g fill-rule="evenodd"><circle cx="11" cy="14" r="3"/><circle cx="11" cy="24" r="3"/><circle cx="11" cy="34" r="3"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
    "list-bull-square": '<svg width="48" height="48"><g fill-rule="evenodd"><path d="M8 11h6v6H8zM8 21h6v6H8zM8 31h6v6H8z"/><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/></g></svg>',
    "list-num-default-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 17v-4.8h-.1l-1.5 1v-1.1l1.6-1.1h1.2v6zM33.3 17.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm1.7 5.7c0-1.2 1-2 2.2-2 1.3 0 2.1.8 2.1 1.8 0 .7-.3 1.2-1.3 2.2l-1.2 1v.2h2.6v1h-4.3v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H35zm-1.7 4.3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7zm3.2 7.3v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H35c0-1.1 1-1.8 2.2-1.8 1.2 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.7.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .6 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7zm-3.3 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7z"/></g></svg>',
    "list-num-default": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10 17v-4.8l-1.5 1v-1.1l1.6-1h1.2V17h-1.2Zm3.6.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-5 5.7c0-1.2.8-2 2.1-2s2.1.8 2.1 1.8c0 .7-.3 1.2-1.4 2.2l-1.1 1v.2h2.6v1H8.6v-.9l2-1.9c.8-.8 1-1.1 1-1.5 0-.5-.4-.8-1-.8-.5 0-.9.3-.9.9H8.5Zm6.3 4.3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM10 34.4v-1h.7c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7s-1 .3-1 .8H8.6c0-1.1 1-1.8 2.2-1.8 1.3 0 2.1.6 2.1 1.6 0 .7-.4 1.2-1 1.3v.1c.8.1 1.3.7 1.3 1.4 0 1-1 1.9-2.4 1.9-1.3 0-2.2-.8-2.3-2h1.2c0 .6.5 1 1.1 1 .7 0 1-.4 1-1 0-.5-.3-.8-1-.8h-.7Zm4.7 2.7c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Z"/></g></svg>',
    "list-num-lower-alpha-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M36.5 16c-.9 0-1.5-.5-1.5-1.3s.6-1.3 1.8-1.4h1v-.4c0-.4-.2-.6-.7-.6-.4 0-.7.1-.8.4h-1.1c0-.8.8-1.4 2-1.4S39 12 39 13V16h-1.2v-.6c-.3.4-.8.7-1.4.7Zm.4-.8c.6 0 1-.4 1-.9V14h-1c-.5.1-.7.3-.7.6 0 .4.3.6.7.6ZM33.1 16.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7ZM37.7 26c-.7 0-1.2-.2-1.5-.7v.7H35v-6.3h1.2v2.5c.3-.5.8-.9 1.5-.9 1.1 0 1.8 1 1.8 2.4 0 1.5-.7 2.4-1.8 2.4Zm-.5-3.6c-.6 0-1 .5-1 1.3s.4 1.4 1 1.4c.7 0 1-.6 1-1.4 0-.8-.3-1.3-1-1.3ZM33.2 26.1c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7zm6 7h-1c-.1-.5-.4-.8-1-.8s-1 .5-1 1.4c0 1 .4 1.4 1 1.4.5 0 .9-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7zm-6.1 3c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7z"/></g></svg>',
    "list-num-lower-alpha": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.3 15.2c.5 0 1-.4 1-.9V14h-1c-.5.1-.8.3-.8.6 0 .4.3.6.8.6Zm-.4.9c-1 0-1.5-.6-1.5-1.4 0-.8.6-1.3 1.7-1.4h1.1v-.4c0-.4-.2-.6-.7-.6-.5 0-.8.1-.9.4h-1c0-.8.8-1.4 2-1.4 1.1 0 1.8.6 1.8 1.6V16h-1.1v-.6h-.1c-.2.4-.7.7-1.3.7Zm4.6 0c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-3.2 10c-.6 0-1.2-.3-1.4-.8v.7H8.5v-6.3H10v2.5c.3-.5.8-.9 1.4-.9 1.2 0 1.9 1 1.9 2.4 0 1.5-.7 2.4-1.9 2.4Zm-.4-3.7c-.7 0-1 .5-1 1.3s.3 1.4 1 1.4c.6 0 1-.6 1-1.4 0-.8-.4-1.3-1-1.3Zm4 3.7c-.5 0-.7-.3-.7-.7 0-.4.2-.7.7-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-2.2 7h-1.2c0-.5-.4-.8-.9-.8-.6 0-1 .5-1 1.4 0 1 .4 1.4 1 1.4.5 0 .8-.2 1-.7h1c0 1-.8 1.7-2 1.7-1.4 0-2.2-.9-2.2-2.4s.8-2.4 2.2-2.4c1.2 0 2 .7 2 1.7Zm1.8 3c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
    "list-num-lower-greek-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M37.4 16c-1.2 0-2-.8-2-2.3 0-1.5.8-2.4 2-2.4.6 0 1 .4 1.3 1v-.9H40v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1-.7h-.2c-.2.4-.7.8-1.3.8Zm.3-1c.6 0 1-.5 1-1.3s-.4-1.3-1-1.3-1 .5-1 1.3.4 1.4 1 1.4ZM33.3 16.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM36 21.9c0-1.5.8-2.3 2.1-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.9 1.3.9.3 1.3.8 1.3 1.7 0 1.2-.7 1.9-1.8 1.9-.6 0-1.1-.3-1.4-.8v2.2H36V22Zm1.8 1.2v-1h.3c.5 0 .9-.2.9-.7 0-.5-.3-.8-.9-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1 1.3s1-.4 1-1-.4-1-1.2-1h-.3ZM33.3 26.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7ZM37.1 34.6 34.8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.2.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1ZM33.3 36.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
    "list-num-lower-greek": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M10.5 15c.7 0 1-.5 1-1.3s-.3-1.3-1-1.3c-.5 0-.9.5-.9 1.3s.4 1.4 1 1.4Zm-.3 1c-1.1 0-1.8-.8-1.8-2.3 0-1.5.7-2.4 1.8-2.4.7 0 1.1.4 1.3 1h.1v-.9h1.2v3.2c0 .4.1.5.4.5h.2v.9h-.6c-.6 0-1-.2-1.1-.7h-.1c-.2.4-.7.8-1.4.8Zm5 .1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.7-.7.5 0 .8.3.8.7 0 .4-.3.7-.8.7Zm-4.9 7v-1h.3c.6 0 1-.2 1-.7 0-.5-.4-.8-1-.8-.5 0-.8.3-.8 1v2.2c0 .8.4 1.3 1.1 1.3.6 0 1-.4 1-1s-.5-1-1.3-1h-.3ZM8.6 22c0-1.5.7-2.3 2-2.3 1.2 0 2 .6 2 1.6 0 .6-.3 1-.8 1.3.8.3 1.3.8 1.3 1.7 0 1.2-.8 1.9-1.9 1.9-.6 0-1.1-.3-1.3-.8v2.2H8.5V22Zm6.2 4.2c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm-4.5 8.5L8 30h1.4l1.7 3.5 1.7-3.5h1.1l-2.2 4.6v.1c.5.8.7 1.4.7 1.8 0 .4-.1.8-.4 1-.2.2-.6.3-1 .3-.9 0-1.3-.4-1.3-1.2 0-.5.2-1 .5-1.7l.1-.2Zm.7 1a2 2 0 0 0-.4.9c0 .3.1.4.4.4.3 0 .4-.1.4-.4 0-.2-.1-.6-.4-1Zm4.5.5c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
    "list-num-lower-roman-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M32.9 16v-1.2h-1.3V16H33Zm0 10v-1.2h-1.3V26H33Zm0 10v-1.2h-1.3V36H33Z"/><path fill-rule="nonzero" d="M36 21h-1.5v5H36zM36 31h-1.5v5H36zM39 21h-1.5v5H39zM39 31h-1.5v5H39zM42 31h-1.5v5H42zM36 11h-1.5v5H36zM36 19h-1.5v1H36zM36 29h-1.5v1H36zM39 19h-1.5v1H39zM39 29h-1.5v1H39zM42 29h-1.5v1H42zM36 9h-1.5v1H36z"/></g></svg>',
    "list-num-lower-roman": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 16v-1.2h1.3V16H15Zm0 10v-1.2h1.3V26H15Zm0 10v-1.2h1.3V36H15Z"/><path fill-rule="nonzero" d="M12 21h1.5v5H12zM12 31h1.5v5H12zM9 21h1.5v5H9zM9 31h1.5v5H9zM6 31h1.5v5H6zM12 11h1.5v5H12zM12 19h1.5v1H12zM12 29h1.5v1H12zM9 19h1.5v1H9zM9 29h1.5v1H9zM6 29h1.5v1H6zM12 9h1.5v1H12z"/></g></svg>',
    "list-num-upper-alpha-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="m39.3 17-.5-1.4h-2l-.5 1.4H35l2-6h1.6l2 6h-1.3Zm-1.6-4.7-.7 2.3h1.6l-.8-2.3ZM33.4 17c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7Zm4.7 9.9h-2.7v-6H38c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7Zm-1.4-5v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4h1.1c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9h-1.1V26ZM33 27.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm4.9 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm-4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
    "list-num-upper-alpha": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="m12.6 17-.5-1.4h-2L9.5 17H8.3l2-6H12l2 6h-1.3ZM11 12.3l-.7 2.3h1.6l-.8-2.3Zm4.7 4.8c-.4 0-.7-.3-.7-.7 0-.4.3-.7.7-.7.5 0 .7.3.7.7 0 .4-.2.7-.7.7ZM11.4 27H8.7v-6h2.6c1.2 0 1.9.6 1.9 1.5 0 .6-.5 1.2-1 1.3.7.1 1.3.7 1.3 1.5 0 1-.8 1.7-2 1.7ZM10 22v1.5h1c.6 0 1-.3 1-.8 0-.4-.4-.7-1-.7h-1Zm0 4H11c.7 0 1.1-.3 1.1-.8 0-.6-.4-.9-1.1-.9H10V26Zm5.4 1.1c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Zm-4.1 10c-1.8 0-2.8-1.1-2.8-3.1s1-3.1 2.8-3.1c1.4 0 2.5.9 2.6 2.2h-1.3c0-.7-.6-1.1-1.3-1.1-1 0-1.6.7-1.6 2s.6 2 1.6 2c.7 0 1.2-.4 1.4-1h1.2c-.1 1.3-1.2 2.2-2.6 2.2Zm4.5 0c-.5 0-.8-.3-.8-.7 0-.4.3-.7.8-.7.4 0 .7.3.7.7 0 .4-.3.7-.7.7Z"/></g></svg>',
    "list-num-upper-roman-rtl": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M8 12h22v4H8zM8 22h22v4H8zM8 32h22v4H8z"/><path d="M31.6 17v-1.2H33V17h-1.3Zm0 10v-1.2H33V27h-1.3Zm0 10v-1.2H33V37h-1.3Z"/><path fill-rule="nonzero" d="M34.5 20H36v7h-1.5zM34.5 30H36v7h-1.5zM37.5 20H39v7h-1.5zM37.5 30H39v7h-1.5zM40.5 30H42v7h-1.5zM34.5 10H36v7h-1.5z"/></g></svg>',
    "list-num-upper-roman": '<svg width="48" height="48"><g fill-rule="evenodd"><path opacity=".2" d="M18 12h22v4H18zM18 22h22v4H18zM18 32h22v4H18z"/><path d="M15.1 17v-1.2h1.3V17H15Zm0 10v-1.2h1.3V27H15Zm0 10v-1.2h1.3V37H15Z"/><path fill-rule="nonzero" d="M12 20h1.5v7H12zM12 30h1.5v7H12zM9 20h1.5v7H9zM9 30h1.5v7H9zM6 30h1.5v7H6zM12 10h1.5v7H12z"/></g></svg>',
    "lock": '<svg width="24" height="24"><path d="M16.3 11c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H8V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h.3ZM10 8v3h4V8a1 1 0 0 0-.3-.7A1 1 0 0 0 13 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7Z" fill-rule="evenodd"/></svg>',
    "ltr": '<svg width="24" height="24"><path d="M11 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 7.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L11 5ZM4.4 16.2 6.2 15l-1.8-1.2a1 1 0 0 1 1.2-1.6l3 2a1 1 0 0 1 0 1.6l-3 2a1 1 0 1 1-1.2-1.6Z" fill-rule="evenodd"/></svg>',
    "more-drawer": '<svg width="24" height="24"><path d="M6 10a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm12 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Zm-6 0a2 2 0 0 0-2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2 2 2 0 0 0-2-2Z" fill-rule="nonzero"/></svg>',
    "new-document": '<svg width="24" height="24"><path d="M14.4 3H7a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h10a2 2 0 0 0 2-2V7.6L14.4 3ZM17 19H7V5h6v4h4v10Z" fill-rule="nonzero"/></svg>',
    "new-tab": '<svg width="24" height="24"><path d="m15 13 2-2v8H5V7h8l-2 2H7v8h8v-4Zm4-8v5.5l-2-2-5.6 5.5H10v-1.4L15.5 7l-2-2H19Z" fill-rule="evenodd"/></svg>',
    "non-breaking": '<svg width="24" height="24"><path d="M11 11H8a1 1 0 1 1 0-2h3V6c0-.6.4-1 1-1s1 .4 1 1v3h3c.6 0 1 .4 1 1s-.4 1-1 1h-3v3c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-3Zm10 4v5H3v-5c0-.6.4-1 1-1s1 .4 1 1v3h14v-3c0-.6.4-1 1-1s1 .4 1 1Z" fill-rule="evenodd"/></svg>',
    "notice": '<svg width="24" height="24"><path d="M17.8 9.8 15.4 4 20 8.5v7L15.5 20h-7L4 15.5v-7L8.5 4h7l2.3 5.8Zm0 0 2.2 5.7-2.3-5.8ZM13 17v-2h-2v2h2Zm0-4V7h-2v6h2Z" fill-rule="evenodd"/></svg>',
    "ordered-list-rtl": '<svg width="24" height="24"><path d="M6 17h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 0 1 0-2Zm0-6h8a1 1 0 0 1 0 2H6a1 1 0 1 1 0-2Zm13-1v3.5a.5.5 0 1 1-1 0V5h-.5a.5.5 0 1 1 0-1H19Zm-1 8.8.2.2h1.3a.5.5 0 1 1 0 1h-1.6a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2h-1.3a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3Zm2 4.2v2c0 .6-.4 1-1 1h-1.5a.5.5 0 0 1 0-1h1.2a.3.3 0 1 0 0-.6h-1.3a.4.4 0 1 1 0-.8h1.3a.3.3 0 0 0 0-.6h-1.2a.5.5 0 1 1 0-1H19c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',
    "ordered-list": '<svg width="24" height="24"><path d="M10 17h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0-6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 1 1 0-2ZM6 4v3.5c0 .3-.2.5-.5.5a.5.5 0 0 1-.5-.5V5h-.5a.5.5 0 0 1 0-1H6Zm-1 8.8.2.2h1.3c.3 0 .5.2.5.5s-.2.5-.5.5H4.9a1 1 0 0 1-.9-1V13c0-.4.3-.8.6-1l1.2-.4.2-.3a.2.2 0 0 0-.2-.2H4.5a.5.5 0 0 1-.5-.5c0-.3.2-.5.5-.5h1.6c.5 0 .9.4.9 1v.1c0 .4-.3.8-.6 1l-1.2.4-.2.3ZM7 17v2c0 .6-.4 1-1 1H4.5a.5.5 0 0 1 0-1h1.2c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.4a.4.4 0 1 1 0-.8h1.3c.2 0 .3-.1.3-.3 0-.2-.1-.3-.3-.3H4.5a.5.5 0 1 1 0-1H6c.6 0 1 .4 1 1Z" fill-rule="evenodd"/></svg>',
    "orientation": '<svg width="24" height="24"><path d="M7.3 6.4 1 13l6.4 6.5 6.5-6.5-6.5-6.5ZM3.7 13l3.6-3.7L11 13l-3.7 3.7-3.6-3.7ZM12 6l2.8 2.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0L9.2 5.7a.8.8 0 0 1 0-1.2L13.6.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L12 4h1a9 9 0 1 1-4.3 16.9l1.5-1.5A7 7 0 1 0 13 6h-1Z" fill-rule="nonzero"/></svg>',
    "outdent": '<svg width="24" height="24"><path d="M7 5h12c.6 0 1 .4 1 1s-.4 1-1 1H7a1 1 0 1 1 0-2Zm5 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm0 4h7c.6 0 1 .4 1 1s-.4 1-1 1h-7a1 1 0 0 1 0-2Zm-5 4h12a1 1 0 0 1 0 2H7a1 1 0 0 1 0-2Zm1.6-3.8a1 1 0 0 1-1.2 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 0 1 1.2 1.6L6.8 12l1.8 1.2Z" fill-rule="evenodd"/></svg>',
    "page-break": '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M5 11c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h1c.6 0 1 .4 1 1s-.4 1-1 1h-1a1 1 0 0 1 0-2Zm4 0c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2ZM7 3v5h10V3c0-.6.4-1 1-1s1 .4 1 1v7H5V3c0-.6.4-1 1-1s1 .4 1 1ZM6 22a1 1 0 0 1-1-1v-7h14v7c0 .6-.4 1-1 1a1 1 0 0 1-1-1v-5H7v5c0 .6-.4 1-1 1Z"/></g></svg>',
    "paragraph": '<svg width="24" height="24"><path fill-rule="evenodd" d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z"/></svg>',
    "paste-column-after": '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h7v2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm8 7v12h-6V8h6Zm-1.5 1.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
    "paste-column-before": '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V18c0 1-.8 2-1.9 2H11v-2h7V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v2H4V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm-2 7v12H4V8h6ZM8.5 9.5h-3v9h3v-9ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
    "paste-row-after": '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V11h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h14c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 11v5H8v-5h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
    "paste-row-before": '<svg width="24" height="24"><path fill-rule="evenodd" d="M12 1a3 3 0 0 1 2.8 2H18c1 0 2 .8 2 1.9V7h-2V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h12v-4h2v4c0 1-.8 2-1.9 2H6c-1 0-2-.8-2-1.9V5c0-1 .8-2 1.9-2H9.2A3 3 0 0 1 12 1Zm10 7v5H8V8h14Zm-1.5 1.5h-11v2h11v-2ZM12 3a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z"/></svg>',
    "paste-text": '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Zm0 9h6v2h-.5l-.5-1h-1v4h.8v1h-3.6v-1h.8v-4h-1l-.5 1H12v-2Z" fill-rule="nonzero"/></svg>',
    "paste": '<svg width="24" height="24"><path d="M18 9V5h-2v1c0 .6-.4 1-1 1H9a1 1 0 0 1-1-1V5H6v13h3V9h9ZM9 20H6a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2h3.2A3 3 0 0 1 12 1a3 3 0 0 1 2.8 2H18a2 2 0 0 1 2 2v4h1v12H9v-1Zm1.5-9.5v9h9v-9h-9ZM12 3a1 1 0 0 0-1 1c0 .5.4 1 1 1s1-.5 1-1-.4-1-1-1Z" fill-rule="nonzero"/></svg>',
    "permanent-pen": '<svg width="24" height="24"><path d="M10.5 17.5 8 20H3v-3l3.5-3.5a2 2 0 0 1 0-3L14 3l1 1-7.3 7.3a1 1 0 0 0 0 1.4l3.6 3.6c.4.4 1 .4 1.4 0L20 9l1 1-7.6 7.6a2 2 0 0 1-2.8 0l-.1-.1Z" fill-rule="nonzero"/></svg>',
    "plus": '<svg width="24" height="24"><path d="M12 4c.5 0 1 .4 1 .9V11h6a1 1 0 0 1 .1 2H13v6a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H11V5c0-.6.4-1 1-1Z"/></svg>',
    "preferences": '<svg width="24" height="24"><path d="m20.1 13.5-1.9.2a5.8 5.8 0 0 1-.6 1.5l1.2 1.5c.4.4.3 1 0 1.4l-.7.7a1 1 0 0 1-1.4 0l-1.5-1.2a6.2 6.2 0 0 1-1.5.6l-.2 1.9c0 .5-.5.9-1 .9h-1a1 1 0 0 1-1-.9l-.2-1.9a5.8 5.8 0 0 1-1.5-.6l-1.5 1.2a1 1 0 0 1-1.4 0l-.7-.7a1 1 0 0 1 0-1.4l1.2-1.5a6.2 6.2 0 0 1-.6-1.5l-1.9-.2a1 1 0 0 1-.9-1v-1c0-.5.4-1 .9-1l1.9-.2a5.8 5.8 0 0 1 .6-1.5L5.2 7.3a1 1 0 0 1 0-1.4l.7-.7a1 1 0 0 1 1.4 0l1.5 1.2a6.2 6.2 0 0 1 1.5-.6l.2-1.9c0-.5.5-.9 1-.9h1c.5 0 1 .4 1 .9l.2 1.9a5.8 5.8 0 0 1 1.5.6l1.5-1.2a1 1 0 0 1 1.4 0l.7.7c.3.4.4 1 0 1.4l-1.2 1.5a6.2 6.2 0 0 1 .6 1.5l1.9.2c.5 0 .9.5.9 1v1c0 .5-.4 1-.9 1ZM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z" fill-rule="evenodd"/></svg>',
    "preview": '<svg width="24" height="24"><path d="M3.5 12.5c.5.8 1.1 1.6 1.8 2.3 2 2 4.2 3.2 6.7 3.2s4.7-1.2 6.7-3.2a16.2 16.2 0 0 0 2.1-2.8 15.7 15.7 0 0 0-2.1-2.8c-2-2-4.2-3.2-6.7-3.2a9.3 9.3 0 0 0-6.7 3.2A16.2 16.2 0 0 0 3.2 12c0 .2.2.3.3.5Zm-2.4-1 .7-1.2L4 7.8C6.2 5.4 8.9 4 12 4c3 0 5.8 1.4 8.1 3.8a18.2 18.2 0 0 1 2.8 3.7v1l-.7 1.2-2.1 2.5c-2.3 2.4-5 3.8-8.1 3.8-3 0-5.8-1.4-8.1-3.8a18.2 18.2 0 0 1-2.8-3.7 1 1 0 0 1 0-1Zm12-3.3a2 2 0 1 0 2.7 2.6 4 4 0 1 1-2.6-2.6Z" fill-rule="nonzero"/></svg>',
    "print": '<svg width="24" height="24"><path d="M18 8H6a3 3 0 0 0-3 3v6h2v3h14v-3h2v-6a3 3 0 0 0-3-3Zm-1 10H7v-4h10v4Zm.5-5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5Zm.5-8H6v2h12V5Z" fill-rule="nonzero"/></svg>',
    "quote": '<svg width="24" height="24"><path d="M7.5 17h.9c.4 0 .7-.2.9-.6L11 13V8c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Zm8 0h.9c.4 0 .7-.2.9-.6L19 13V8c0-.6-.4-1-1-1h-4a1 1 0 0 0-1 1v4c0 .6.4 1 1 1h2l-1.3 2.7a1 1 0 0 0 .8 1.3Z" fill-rule="nonzero"/></svg>',
    "redo": '<svg width="24" height="24"><path d="M17.6 10H12c-2.8 0-4.4 1.4-4.9 3.5-.4 2 .3 4 1.4 4.6a1 1 0 1 1-1 1.8c-2-1.2-2.9-4.1-2.3-6.8.6-3 3-5.1 6.8-5.1h5.6l-3.3-3.3a1 1 0 1 1 1.4-1.4l5 5a1 1 0 0 1 0 1.4l-5 5a1 1 0 0 1-1.4-1.4l3.3-3.3Z" fill-rule="nonzero"/></svg>',
    "reload": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="m5 22.1-1.2-4.7v-.2a1 1 0 0 1 1-1l5 .4a1 1 0 1 1-.2 2l-2.2-.2a7.8 7.8 0 0 0 8.4.2 7.5 7.5 0 0 0 3.5-6.4 1 1 0 1 1 2 0 9.5 9.5 0 0 1-4.5 8 9.9 9.9 0 0 1-10.2 0l.4 1.4a1 1 0 1 1-2 .5ZM13.6 7.4c0-.5.5-1 1-.9l2.8.2a8 8 0 0 0-9.5-1 7.5 7.5 0 0 0-3.6 7 1 1 0 0 1-2 0 9.5 9.5 0 0 1 4.5-8.6 10 10 0 0 1 10.9.3l-.3-1a1 1 0 0 1 2-.5l1.1 4.8a1 1 0 0 1-1 1.2l-5-.4a1 1 0 0 1-.9-1Z"/></g></svg>',
    "remove-formatting": '<svg width="24" height="24"><path d="M13.2 6a1 1 0 0 1 0 .2l-2.6 10a1 1 0 0 1-1 .8h-.2a.8.8 0 0 1-.8-1l2.6-10H8a1 1 0 1 1 0-2h9a1 1 0 0 1 0 2h-3.8ZM5 18h7a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Zm13 1.5L16.5 18 15 19.5a.7.7 0 0 1-1-1l1.5-1.5-1.5-1.5a.7.7 0 0 1 1-1l1.5 1.5 1.5-1.5a.7.7 0 0 1 1 1L17.5 17l1.5 1.5a.7.7 0 0 1-1 1Z" fill-rule="evenodd"/></svg>',
    "remove": '<svg width="24" height="24"><path d="M16 7h3a1 1 0 0 1 0 2h-1v9a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V9H5a1 1 0 1 1 0-2h3V6a3 3 0 0 1 3-3h2a3 3 0 0 1 3 3v1Zm-2 0V6c0-.6-.4-1-1-1h-2a1 1 0 0 0-1 1v1h4Zm2 2H8v9c0 .6.4 1 1 1h6c.6 0 1-.4 1-1V9Zm-7 3a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Zm4 0a1 1 0 0 1 2 0v4a1 1 0 0 1-2 0v-4Z" fill-rule="nonzero"/></svg>',
    "resize-handle": '<svg width="10" height="10"><g fill-rule="nonzero"><path d="M8.1 1.1A.5.5 0 1 1 9 2l-7 7A.5.5 0 1 1 1 8l7-7ZM8.1 5.1A.5.5 0 1 1 9 6l-3 3A.5.5 0 1 1 5 8l3-3Z"/></g></svg>',
    "resize": '<svg width="24" height="24"><path d="M4 5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h6c.3 0 .5.1.7.3.2.2.3.4.3.7 0 .3-.1.5-.3.7a1 1 0 0 1-.7.3H7.4L18 16.6V13c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3.3 0 .5.1.7.3.2.2.3.4.3.7v6c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-6a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3.6L6 7.4V11c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3 1 1 0 0 1-.7-.3A1 1 0 0 1 4 11V5Z" fill-rule="evenodd"/></svg>',
    "restore-draft": '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M17 13c0 .6-.4 1-1 1h-4V8c0-.6.4-1 1-1s1 .4 1 1v4h2c.6 0 1 .4 1 1Z"/><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></g></svg>',
    "rotate-left": '<svg width="24" height="24"><path d="M4.7 10H9a1 1 0 0 1 0 2H3a1 1 0 0 1-1-1V5a1 1 0 1 1 2 0v3l2.5-2.4a9.2 9.2 0 0 1 10.8-1.5A9 9 0 0 1 13.4 21c-2.4.1-4.7-.7-6.5-2.2a1 1 0 1 1 1.3-1.5 7.2 7.2 0 0 0 11.6-3.7 7 7 0 0 0-3.5-7.7A7.2 7.2 0 0 0 8 7L4.7 10Z" fill-rule="nonzero"/></svg>',
    "rotate-right": '<svg width="24" height="24"><path d="M20 8V5a1 1 0 0 1 2 0v6c0 .6-.4 1-1 1h-6a1 1 0 0 1 0-2h4.3L16 7A7.2 7.2 0 0 0 7.7 6a7 7 0 0 0 3 13.1c1.9.1 3.7-.5 5-1.7a1 1 0 0 1 1.4 1.5A9.2 9.2 0 0 1 2.2 14c-.9-3.9 1-8 4.5-9.9 3.5-1.9 8-1.3 10.8 1.5L20 8Z" fill-rule="nonzero"/></svg>',
    "rtl": '<svg width="24" height="24"><path d="M8 5h8v2h-2v12h-2V7h-2v12H8v-7c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 4.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L8 5Zm12 11.2a1 1 0 1 1-1 1.6l-3-2a1 1 0 0 1 0-1.6l3-2a1 1 0 1 1 1 1.6L18.4 15l1.8 1.2Z" fill-rule="evenodd"/></svg>',
    "save": '<svg width="24" height="24"><path d="M5 16h14a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2c0-1.1.9-2 2-2Zm0 2v2h14v-2H5Zm10 0h2v2h-2v-2Zm-4-6.4L8.7 9.3a1 1 0 1 0-1.4 1.4l4 4c.4.4 1 .4 1.4 0l4-4a1 1 0 1 0-1.4-1.4L13 11.6V4a1 1 0 0 0-2 0v7.6Z" fill-rule="nonzero"/></svg>',
    "search": '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Z" fill-rule="nonzero"/></svg>',
    "select-all": '<svg width="24" height="24"><path d="M3 5h2V3a2 2 0 0 0-2 2Zm0 8h2v-2H3v2Zm4 8h2v-2H7v2ZM3 9h2V7H3v2Zm10-6h-2v2h2V3Zm6 0v2h2a2 2 0 0 0-2-2ZM5 21v-2H3c0 1.1.9 2 2 2Zm-2-4h2v-2H3v2ZM9 3H7v2h2V3Zm2 18h2v-2h-2v2Zm8-8h2v-2h-2v2Zm0 8a2 2 0 0 0 2-2h-2v2Zm0-12h2V7h-2v2Zm0 8h2v-2h-2v2Zm-4 4h2v-2h-2v2Zm0-16h2V3h-2v2ZM7 17h10V7H7v10Zm2-8h6v6H9V9Z" fill-rule="nonzero"/></svg>',
    "selected": '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm3.6 10.9L7 12.3a.7.7 0 0 0-1 1L9.6 17 18 8.6a.7.7 0 0 0 0-1 .7.7 0 0 0-1 0l-7.4 7.3Z"/></svg>',
    "settings": '<svg width="24" height="24"><path d="M11 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V8H5a1 1 0 1 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.5V6ZM8 8h2V6H8v2Zm9 2.8v.2h2c.6 0 1 .4 1 1s-.4 1-1 1h-2v.3c0 .2 0 .3-.2.5l-.6.2h-2.4c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V13H5a1 1 0 0 1 0-2h8v-.3c0-.2 0-.3.2-.5l.6-.2h2.4c.3 0 .4 0 .6.2l.2.6ZM14 13h2v-2h-2v2Zm-3 2.8v.2h8c.6 0 1 .4 1 1s-.4 1-1 1h-8v.3c0 .2 0 .3-.2.5l-.6.2H7.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6V18H5a1 1 0 0 1 0-2h2v-.3c0-.2 0-.3.2-.5l.5-.2h2.5c.3 0 .4 0 .6.2l.2.6ZM8 18h2v-2H8v2Z" fill-rule="evenodd"/></svg>',
    "sharpen": '<svg width="24" height="24"><path d="m16 6 4 4-8 9-8-9 4-4h8Zm-4 10.2 5.5-6.2-.1-.1H12v-.3h5.1l-.2-.2H12V9h4.6l-.2-.2H12v-.3h4.1l-.2-.2H12V8h3.6l-.2-.2H8.7L6.5 10l.1.1H12v.3H6.9l.2.2H12v.3H7.3l.2.2H12v.3H7.7l.3.2h4v.3H8.2l.2.2H12v.3H8.6l.3.2H12v.3H9l.3.2H12v.3H9.5l.2.2H12v.3h-2l.2.2H12v.3h-1.6l.2.2H12v.3h-1.1l.2.2h.9v.3h-.7l.2.2h.5v.3h-.3l.3.2Z" fill-rule="evenodd"/></svg>',
    "sourcecode": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M9.8 15.7c.3.3.3.8 0 1-.3.4-.9.4-1.2 0l-4.4-4.1a.8.8 0 0 1 0-1.2l4.4-4.2c.3-.3.9-.3 1.2 0 .3.3.3.8 0 1.1L6 12l3.8 3.7ZM14.2 15.7c-.3.3-.3.8 0 1 .4.4.9.4 1.2 0l4.4-4.1c.3-.3.3-.9 0-1.2l-4.4-4.2a.8.8 0 0 0-1.2 0c-.3.3-.3.8 0 1.1L18 12l-3.8 3.7Z"/></g></svg>',
    "spell-check": '<svg width="24" height="24"><path d="M6 8v3H5V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h2c.3 0 .5.1.7.3.2.2.3.4.3.7v6H8V8H6Zm0-3v2h2V5H6Zm13 0h-3v5h3v1h-3a1 1 0 0 1-.7-.3 1 1 0 0 1-.3-.7V5c0-.3.1-.5.3-.7.2-.2.4-.3.7-.3h3v1Zm-5 1.5-.1.7c-.1.2-.3.3-.6.3.3 0 .5.1.6.3l.1.7V10c0 .3-.1.5-.3.7a1 1 0 0 1-.7.3h-3V4h3c.3 0 .5.1.7.3.2.2.3.4.3.7v1.5ZM13 10V8h-2v2h2Zm0-3V5h-2v2h2Zm3 5 1 1-6.5 7L7 15.5l1.3-1 2.2 2.2L16 12Z" fill-rule="evenodd"/></svg>',
    "strike-through": '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M15.6 8.5c-.5-.7-1-1.1-1.3-1.3-.6-.4-1.3-.6-2-.6-2.7 0-2.8 1.7-2.8 2.1 0 1.6 1.8 2 3.2 2.3 4.4.9 4.6 2.8 4.6 3.9 0 1.4-.7 4.1-5 4.1A6.2 6.2 0 0 1 7 16.4l1.5-1.1c.4.6 1.6 2 3.7 2 1.6 0 2.5-.4 3-1.2.4-.8.3-2-.8-2.6-.7-.4-1.6-.7-2.9-1-1-.2-3.9-.8-3.9-3.6C7.6 6 10.3 5 12.4 5c2.9 0 4.2 1.6 4.7 2.4l-1.5 1.1Z"/><path d="M5 11h14a1 1 0 0 1 0 2H5a1 1 0 0 1 0-2Z" fill-rule="nonzero"/></g></svg>',
    "subscript": '<svg width="24" height="24"><path d="m10.4 10 4.6 4.6-1.4 1.4L9 11.4 4.4 16 3 14.6 7.6 10 3 5.4 4.4 4 9 8.6 13.6 4 15 5.4 10.4 10ZM21 19h-5v-1l1-.8 1.7-1.6c.3-.4.5-.8.5-1.2 0-.3 0-.6-.2-.7-.2-.2-.5-.3-.9-.3a2 2 0 0 0-.8.2l-.7.3-.4-1.1 1-.6 1.2-.2c.8 0 1.4.3 1.8.7.4.4.6.9.6 1.5s-.2 1.1-.5 1.6a8 8 0 0 1-1.3 1.3l-.6.6h2.6V19Z" fill-rule="nonzero"/></svg>',
    "superscript": '<svg width="24" height="24"><path d="M15 9.4 10.4 14l4.6 4.6-1.4 1.4L9 15.4 4.4 20 3 18.6 7.6 14 3 9.4 4.4 8 9 12.6 13.6 8 15 9.4Zm5.9 1.6h-5v-1l1-.8 1.7-1.6c.3-.5.5-.9.5-1.3 0-.3 0-.5-.2-.7-.2-.2-.5-.3-.9-.3l-.8.2-.7.4-.4-1.2c.2-.2.5-.4 1-.5.3-.2.8-.2 1.2-.2.8 0 1.4.2 1.8.6.4.4.6 1 .6 1.6 0 .5-.2 1-.5 1.5l-1.3 1.4-.6.5h2.6V11Z" fill-rule="nonzero"/></svg>',
    "table-caption": '<svg width="24" height="24"><g fill-rule="nonzero"><rect width="12" height="2" x="3" y="4" rx="1"/><path d="M19 8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-8c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></g></svg>',
    "table-cell-classes": '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M13 4v9H3V6c0-1.1.9-2 2-2h8Zm-2 2H5v5h6V6Z"/><path fill-rule="nonzero" d="M13 4h6a2 2 0 0 1 2 2v7h-8v-2h6V6h-6V4Z" opacity=".2"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/><path fill-rule="nonzero" d="M3 13v5c0 1.1.9 2 2 2h8v-7h-2v5H5v-5H3Z" opacity=".2"/></g></svg>',
    "table-cell-properties": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8 0h-6v5h6v-5Zm-8-7H5v5h6V6Z"/></svg>',
    "table-cell-select-all": '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z" opacity=".2"/></g></svg>',
    "table-cell-select-inner": '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v12h14V6Z" opacity=".2"/><path d="M13 6v5h6v2h-6v5h-2v-5H5v-2h6V6h2Z"/></g></svg>',
    "table-classes": '<svg width="24" height="24"><g fill-rule="evenodd"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v7h-8v7H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 9H5v5h6v-5Zm8-7h-6v5h6V6Zm-8 0H5v5h6V6Z"/><path d="m18 20-2.6 1.6.7-3-2.4-2 3.1-.2 1.2-2.9 1.2 2.9 3.1.2-2.4 2 .7 3z"/></g></svg>',
    "table-delete-column": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-4 4h-2V6h-2v2H9V6H5v12h4v-2h2v2h2v-2h2v2h4V6h-4v2Zm.3.5 1 1.2-3 2.3 3 2.3-1 1.2L12 13l-3.3 2.6-1-1.2 3-2.3-3-2.3 1-1.2L12 11l3.3-2.5Z"/></svg>',
    "table-delete-row": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 2H5v3h2.5v2H5v2h2.5v2H5v3h14v-3h-2.5v-2H19v-2h-2.5V9H19V6Zm-4.7 1.8 1.2 1L13 12l2.6 3.3-1.2 1-2.3-3-2.3 3-1.2-1L11 12 8.5 8.7l1.2-1 2.3 3 2.3-3Z"/></svg>',
    "table-delete-table": '<svg width="24" height="24"><g fill-rule="nonzero"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 6v12h14V6H5Z"/><path d="m14.4 8.6 1.1 1-2.4 2.4 2.4 2.4-1.1 1.1-2.4-2.4-2.4 2.4-1-1.1 2.3-2.4-2.3-2.4 1-1 2.4 2.3z"/></g></svg>',
    "table-insert-column-after": '<svg width="24" height="24"><path fill-rule="nonzero" d="M20 4c.6 0 1 .4 1 1v2a1 1 0 0 1-2 0V6h-8v12h8v-1a1 1 0 0 1 2 0v2c0 .5-.4 1-.9 1H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h15ZM9 13H5v5h4v-5Zm7-5c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H17v2a1 1 0 0 1-2 .1V13h-2a1 1 0 0 1-.1-2H15V9c0-.6.4-1 1-1ZM9 6H5v5h4V6Z"/></svg>',
    "table-insert-column-before": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a1 1 0 0 1-1-1v-2a1 1 0 0 1 2 0v1h8V6H5v1a1 1 0 1 1-2 0V5c0-.6.4-1 1-1h15Zm0 9h-4v5h4v-5ZM8 8c.5 0 1 .4 1 .9V11h2a1 1 0 0 1 .1 2H9v2a1 1 0 0 1-2 .1V13H5a1 1 0 0 1-.1-2H7V9c0-.6.4-1 1-1Zm11-2h-4v5h4V6Z"/></svg>',
    "table-insert-row-above": '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4a1 1 0 1 1 0 2H5v6h14V6h-1a1 1 0 0 1 0-2h2c.6 0 1 .4 1 1v13a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-.6.4-1 1-1h2Zm5 10H5v4h6v-4Zm8 0h-6v4h6v-4ZM12 3c.5 0 1 .4 1 .9V6h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 .1V8H9a1 1 0 0 1 0-2h2V4c0-.6.4-1 1-1Z"/></svg>',
    "table-insert-row-after": '<svg width="24" height="24"><path fill-rule="nonzero" d="M12 13c.5 0 1 .4 1 .9V16h2a1 1 0 0 1 .1 2H13v2a1 1 0 0 1-2 .1V18H9a1 1 0 0 1-.1-2H11v-2c0-.6.4-1 1-1Zm6 7a1 1 0 0 1 0-2h1v-6H5v6h1a1 1 0 0 1 0 2H4a1 1 0 0 1-1-1V6c0-1.1.9-2 2-2h14a2 2 0 0 1 2 2v13c0 .5-.4 1-.9 1H18ZM11 6H5v4h6V6Zm8 0h-6v4h6V6Z"/></svg>',
    "table-left-header": '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm0 9h-4v5h4v-5Zm-6 0H9v5h4v-5Zm0-7H9v5h4V6Zm6 0h-4v5h4V6Z"/></svg>',
    "table-merge-cells": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15.5V18h3v-2.5H5Zm14-5h-9V18h9v-7.5ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Zm-8 7.5h3v-3H5v3Z"/></svg>',
    "table-row-numbering-rtl": '<svg width="24" height="24"><path d="M6 4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H6Zm0 12h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 11h8v3H6v-3Zm11 0c.6 0 1 .4 1 1v1a1 1 0 0 1-2 0v-1c0-.6.4-1 1-1ZM6 6h8v3H6V6Zm11 0c.6 0 1 .4 1 1v1a1 1 0 1 1-2 0V7c0-.6.4-1 1-1Z"/></svg>',
    "table-row-numbering": '<svg width="24" height="24"><path d="M18 4a2 2 0 0 1 2 2v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h12Zm0 12h-8v3h8v-3ZM7 16a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8v-3ZM7 11a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1c0-.6-.4-1-1-1Zm11-5h-8v3h8V6ZM7 6a1 1 0 0 0-1 1v1a1 1 0 1 0 2 0V7c0-.6-.4-1-1-1Z"/></svg>',
    "table-row-properties": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 15v3h6v-3H5Zm14 0h-6v3h6v-3Zm0-9h-6v3h6V6ZM5 9h6V6H5v3Z"/></svg>',
    "table-split-cells": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM8 15.5H5V18h3v-2.5Zm11-5h-9V18h9v-7.5Zm-2.5 1 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2Zm-8.5-1H5v3h3v-3ZM19 6h-4v2.5h4V6ZM8 6H5v2.5h3V6Zm5 0h-3v2.5h3V6Z"/></svg>',
    "table-top-header": '<svg width="24" height="24"><path d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14Zm-8 11H5v3h6v-3Zm8 0h-6v3h6v-3Zm0-5h-6v3h6v-3ZM5 13h6v-3H5v3Z"/></svg>',
    "table": '<svg width="24" height="24"><path fill-rule="nonzero" d="M19 4a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2h14ZM5 14v4h6v-4H5Zm14 0h-6v4h6v-4Zm0-6h-6v4h6V8ZM5 12h6V8H5v4Z"/></svg>',
    "template": '<svg width="24" height="24"><path d="M19 19v-1H5v1h14ZM9 16v-4a5 5 0 1 1 6 0v4h4a2 2 0 0 1 2 2v3H3v-3c0-1.1.9-2 2-2h4Zm4 0v-5l.8-.6a3 3 0 1 0-3.6 0l.8.6v5h2Z" fill-rule="nonzero"/></svg>',
    "temporary-placeholder": '<svg width="24" height="24"><g fill-rule="evenodd"><path d="M9 7.6V6h2.5V4.5a.5.5 0 1 1 1 0V6H15v1.6a8 8 0 1 1-6 0Zm-2.6 5.3a.5.5 0 0 0 .3.6c.3 0 .6 0 .6-.3l.1-.2a5 5 0 0 1 3.3-2.8c.3-.1.4-.4.4-.6-.1-.3-.4-.5-.6-.4a6 6 0 0 0-4.1 3.7Z"/><circle cx="14" cy="4" r="1"/><circle cx="12" cy="2" r="1"/><circle cx="10" cy="4" r="1"/></g></svg>',
    "text-color": '<svg width="24" height="24"><g fill-rule="evenodd"><path id="tox-icon-text-color__color" d="M3 18h18v3H3z"/><path d="M8.7 16h-.8a.5.5 0 0 1-.5-.6l2.7-9c.1-.3.3-.4.5-.4h2.8c.2 0 .4.1.5.4l2.7 9a.5.5 0 0 1-.5.6h-.8a.5.5 0 0 1-.4-.4l-.7-2.2c0-.3-.3-.4-.5-.4h-3.4c-.2 0-.4.1-.5.4l-.7 2.2c0 .3-.2.4-.4.4Zm2.6-7.6-.6 2a.5.5 0 0 0 .5.6h1.6a.5.5 0 0 0 .5-.6l-.6-2c0-.3-.3-.4-.5-.4h-.4c-.2 0-.4.1-.5.4Z"/></g></svg>',
    "toc": '<svg width="24" height="24"><path d="M5 5c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 1 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h11c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Zm0-4c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 1 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm-3 8c.6 0 1 .4 1 1s-.4 1-1 1a1 1 0 0 1 0-2Zm3 0h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "translate": '<svg width="24" height="24"><path d="m12.7 14.3-.3.7-.4.7-2.2-2.2-3.1 3c-.3.4-.8.4-1 0a.7.7 0 0 1 0-1l3.1-3A12.4 12.4 0 0 1 6.7 9H8a10.1 10.1 0 0 0 1.7 2.4c.5-.5 1-1.1 1.4-1.8l.9-2H4.7a.7.7 0 1 1 0-1.5h4.4v-.7c0-.4.3-.8.7-.8.4 0 .7.4.7.8v.7H15c.4 0 .8.3.8.7 0 .4-.4.8-.8.8h-1.4a12.3 12.3 0 0 1-1 2.4 13.5 13.5 0 0 1-1.7 2.3l1.9 1.8Zm4.3-3 2.7 7.3a.5.5 0 0 1-.4.7 1 1 0 0 1-1-.7l-.6-1.5h-3.4l-.6 1.5a1 1 0 0 1-1 .7.5.5 0 0 1-.4-.7l2.7-7.4a1 1 0 0 1 2 0Zm-2.2 4.4h2.4L16 12.5l-1.2 3.2Z" fill-rule="evenodd"/></svg>',
    "underline": '<svg width="24" height="24"><path d="M16 5c.6 0 1 .4 1 1v5.5a4 4 0 0 1-.4 1.8l-1 1.4a5.3 5.3 0 0 1-5.5 1 5 5 0 0 1-1.6-1c-.5-.4-.8-.9-1.1-1.4a4 4 0 0 1-.4-1.8V6c0-.6.4-1 1-1s1 .4 1 1v5.5c0 .3 0 .6.2 1l.6.7a3.3 3.3 0 0 0 2.2.8 3.4 3.4 0 0 0 2.2-.8c.3-.2.4-.5.6-.8l.2-.9V6c0-.6.4-1 1-1ZM8 17h8c.6 0 1 .4 1 1s-.4 1-1 1H8a1 1 0 0 1 0-2Z" fill-rule="evenodd"/></svg>',
    "undo": '<svg width="24" height="24"><path d="M6.4 8H12c3.7 0 6.2 2 6.8 5.1.6 2.7-.4 5.6-2.3 6.8a1 1 0 0 1-1-1.8c1.1-.6 1.8-2.7 1.4-4.6-.5-2.1-2.1-3.5-4.9-3.5H6.4l3.3 3.3a1 1 0 1 1-1.4 1.4l-5-5a1 1 0 0 1 0-1.4l5-5a1 1 0 0 1 1.4 1.4L6.4 8Z" fill-rule="nonzero"/></svg>',
    "unlink": '<svg width="24" height="24"><path d="M6.2 12.3a1 1 0 0 1 1.4 1.4l-2 2a2 2 0 1 0 2.6 2.8l4.8-4.8a1 1 0 0 0 0-1.4 1 1 0 1 1 1.4-1.3 2.9 2.9 0 0 1 0 4L9.6 20a3.9 3.9 0 0 1-5.5-5.5l2-2Zm11.6-.6a1 1 0 0 1-1.4-1.4l2.1-2a2 2 0 1 0-2.7-2.8L11 10.3a1 1 0 0 0 0 1.4A1 1 0 1 1 9.6 13a2.9 2.9 0 0 1 0-4L14.4 4a3.9 3.9 0 0 1 5.5 5.5l-2 2ZM7.6 6.3a.8.8 0 0 1-1 1.1L3.3 4.2a.7.7 0 1 1 1-1l3.2 3.1ZM5.1 8.6a.8.8 0 0 1 0 1.5H3a.8.8 0 0 1 0-1.5H5Zm5-3.5a.8.8 0 0 1-1.5 0V3a.8.8 0 0 1 1.5 0V5Zm6 11.8a.8.8 0 0 1 1-1l3.2 3.2a.8.8 0 0 1-1 1L16 17Zm-2.2 2a.8.8 0 0 1 1.5 0V21a.8.8 0 0 1-1.5 0V19Zm5-3.5a.7.7 0 1 1 0-1.5H21a.8.8 0 0 1 0 1.5H19Z" fill-rule="nonzero"/></svg>',
    "unlock": '<svg width="24" height="24"><path d="M16 5c.8 0 1.5.3 2.1.9.6.6.9 1.3.9 2.1v3h-2V8a1 1 0 0 0-.3-.7A1 1 0 0 0 16 7h-2a1 1 0 0 0-.7.3 1 1 0 0 0-.3.7v3h.3c.2 0 .3 0 .5.2l.2.6v7.4c0 .3 0 .4-.2.6l-.6.2H4.8c-.3 0-.4 0-.6-.2a.7.7 0 0 1-.2-.6v-7.4c0-.3 0-.4.2-.6l.5-.2H11V8c0-.8.3-1.5.9-2.1.6-.6 1.3-.9 2.1-.9h2Z" fill-rule="evenodd"/></svg>',
    "unordered-list": '<svg width="24" height="24"><path d="M11 5h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2Zm0 6h8c.6 0 1 .4 1 1s-.4 1-1 1h-8a1 1 0 0 1 0-2ZM4.5 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Zm0 6c0-.4.1-.8.4-1 .3-.4.7-.5 1.1-.5.4 0 .8.1 1 .4.4.3.5.7.5 1.1 0 .4-.1.8-.4 1-.3.4-.7.5-1.1.5-.4 0-.8-.1-1-.4-.4-.3-.5-.7-.5-1.1Z" fill-rule="evenodd"/></svg>',
    "unselected": '<svg width="24" height="24"><path fill-rule="nonzero" d="M6 4h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6c0-1.1.9-2 2-2Zm0 1a1 1 0 0 0-1 1v12c0 .6.4 1 1 1h12c.6 0 1-.4 1-1V6c0-.6-.4-1-1-1H6Z"/></svg>',
    "upload": '<svg width="24" height="24"><path d="M18 19v-2a1 1 0 0 1 2 0v3c0 .6-.4 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 2 0v2h12ZM11 6.4 8.7 8.7a1 1 0 0 1-1.4-1.4l4-4a1 1 0 0 1 1.4 0l4 4a1 1 0 1 1-1.4 1.4L13 6.4V16a1 1 0 0 1-2 0V6.4Z" fill-rule="nonzero"/></svg>',
    "user": '<svg width="24" height="24"><path d="M12 24a12 12 0 1 1 0-24 12 12 0 0 1 0 24Zm-8.7-5.3a11 11 0 0 0 17.4 0C19.4 16.3 14.6 15 12 15c-2.6 0-7.4 1.3-8.7 3.7ZM12 13c2.2 0 4-2 4-4.5S14.2 4 12 4 8 6 8 8.5 9.8 13 12 13Z" fill-rule="nonzero"/></svg>',
    "vertical-align": '<svg width="24" height="24"><g fill-rule="nonzero"><rect width="18" height="2" x="3" y="11" rx="1"/><path d="M12 2c.6 0 1 .4 1 1v4l2-1.3a1 1 0 0 1 1.2 1.5l-.1.1-4.1 3-4-3a1 1 0 0 1 1-1.7l2 1.5V3c0-.6.4-1 1-1zm0 11.8 4 2.9a1 1 0 0 1-1 1.7l-2-1.5V21c0 .5-.4 1-.9 1H12a1 1 0 0 1-1-1v-4l-2 1.3a1 1 0 0 1-1.2-.1l-.1-.1a1 1 0 0 1 .1-1.3l.1-.1 4.1-3z"/></g></svg>',
    "visualblocks": '<svg width="24" height="24"><path d="M9 19v2H7v-2h2Zm-4 0v2a2 2 0 0 1-2-2h2Zm8 0v2h-2v-2h2Zm8 0a2 2 0 0 1-2 2v-2h2Zm-4 0v2h-2v-2h2ZM15 7a1 1 0 0 1 0 2v7a1 1 0 0 1-2 0V9h-1v7a1 1 0 0 1-2 0v-4a2.5 2.5 0 0 1-.2-5H15ZM5 15v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 11v2H3v-2h2Zm16 0v2h-2v-2h2ZM5 7v2H3V7h2Zm16 0v2h-2V7h2ZM5 3v2H3c0-1.1.9-2 2-2Zm8 0v2h-2V3h2Zm6 0a2 2 0 0 1 2 2h-2V3ZM9 3v2H7V3h2Zm8 0v2h-2V3h2Z" fill-rule="evenodd"/></svg>',
    "visualchars": '<svg width="24" height="24"><path d="M10 5h7a1 1 0 0 1 0 2h-1v11a1 1 0 0 1-2 0V7h-2v11a1 1 0 0 1-2 0v-6c-.5 0-1 0-1.4-.3A3.4 3.4 0 0 1 6.8 10a3.3 3.3 0 0 1 0-2.8 3.4 3.4 0 0 1 1.8-1.8L10 5Z" fill-rule="evenodd"/></svg>',
    "warning": '<svg width="24" height="24"><path d="M19.8 18.3c.2.5.3.9 0 1.2-.1.3-.5.5-1 .5H5.2c-.5 0-.9-.2-1-.5-.3-.3-.2-.7 0-1.2L11 4.7l.5-.5.5-.2c.2 0 .3 0 .5.2.2 0 .3.3.5.5l6.8 13.6ZM12 18c.3 0 .5-.1.7-.3.2-.2.3-.4.3-.7a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7c0 .3.1.5.3.7.2.2.4.3.7.3Zm.7-3 .3-4a1 1 0 0 0-.3-.7 1 1 0 0 0-.7-.3 1 1 0 0 0-.7.3 1 1 0 0 0-.3.7l.3 4h1.4Z" fill-rule="evenodd"/></svg>',
    "zoom-in": '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-1-9a1 1 0 0 1 2 0v6a1 1 0 0 1-2 0V8Zm-2 4a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>',
    "zoom-out": '<svg width="24" height="24"><path d="M16 17.3a8 8 0 1 1 1.4-1.4l4.3 4.4a1 1 0 0 1-1.4 1.4l-4.4-4.3Zm-5-.3a6 6 0 1 0 0-12 6 6 0 0 0 0 12Zm-3-5a1 1 0 0 1 0-2h6a1 1 0 0 1 0 2H8Z" fill-rule="nonzero"/></svg>'
  }
});
(function() {
  var global$1 = tinymce.util.Tools.resolve("tinymce.ModelManager");
  const hasProto = (v, constructor, predicate) => {
    var _a;
    if (predicate(v, constructor.prototype)) {
      return true;
    } else {
      return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
    }
  };
  const typeOf = (x) => {
    const t = typeof x;
    if (x === null) {
      return "null";
    } else if (t === "object" && Array.isArray(x)) {
      return "array";
    } else if (t === "object" && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
      return "string";
    } else {
      return t;
    }
  };
  const isType$1 = (type2) => (value2) => typeOf(value2) === type2;
  const isSimpleType = (type2) => (value2) => typeof value2 === type2;
  const eq$2 = (t) => (a) => t === a;
  const isString = isType$1("string");
  const isObject = isType$1("object");
  const isArray = isType$1("array");
  const isNull = eq$2(null);
  const isBoolean = isSimpleType("boolean");
  const isNullable = (a) => a === null || a === void 0;
  const isNonNullable = (a) => !isNullable(a);
  const isFunction = isSimpleType("function");
  const isNumber = isSimpleType("number");
  const noop = () => {
  };
  const compose = (fa, fb) => {
    return (...args) => {
      return fa(fb.apply(null, args));
    };
  };
  const compose1 = (fbc, fab) => (a) => fbc(fab(a));
  const constant = (value2) => {
    return () => {
      return value2;
    };
  };
  const identity = (x) => {
    return x;
  };
  const tripleEquals = (a, b) => {
    return a === b;
  };
  function curry(fn, ...initialArgs) {
    return (...restArgs) => {
      const all2 = initialArgs.concat(restArgs);
      return fn.apply(null, all2);
    };
  }
  const not = (f) => (t) => !f(t);
  const die = (msg) => {
    return () => {
      throw new Error(msg);
    };
  };
  const apply = (f) => {
    return f();
  };
  const never = constant(false);
  const always = constant(true);
  class Optional {
    constructor(tag, value2) {
      this.tag = tag;
      this.value = value2;
    }
    static some(value2) {
      return new Optional(true, value2);
    }
    static none() {
      return Optional.singletonNone;
    }
    fold(onNone, onSome) {
      if (this.tag) {
        return onSome(this.value);
      } else {
        return onNone();
      }
    }
    isSome() {
      return this.tag;
    }
    isNone() {
      return !this.tag;
    }
    map(mapper) {
      if (this.tag) {
        return Optional.some(mapper(this.value));
      } else {
        return Optional.none();
      }
    }
    bind(binder2) {
      if (this.tag) {
        return binder2(this.value);
      } else {
        return Optional.none();
      }
    }
    exists(predicate) {
      return this.tag && predicate(this.value);
    }
    forall(predicate) {
      return !this.tag || predicate(this.value);
    }
    filter(predicate) {
      if (!this.tag || predicate(this.value)) {
        return this;
      } else {
        return Optional.none();
      }
    }
    getOr(replacement) {
      return this.tag ? this.value : replacement;
    }
    or(replacement) {
      return this.tag ? this : replacement;
    }
    getOrThunk(thunk) {
      return this.tag ? this.value : thunk();
    }
    orThunk(thunk) {
      return this.tag ? this : thunk();
    }
    getOrDie(message) {
      if (!this.tag) {
        throw new Error(message !== null && message !== void 0 ? message : "Called getOrDie on None");
      } else {
        return this.value;
      }
    }
    static from(value2) {
      return isNonNullable(value2) ? Optional.some(value2) : Optional.none();
    }
    getOrNull() {
      return this.tag ? this.value : null;
    }
    getOrUndefined() {
      return this.value;
    }
    each(worker) {
      if (this.tag) {
        worker(this.value);
      }
    }
    toArray() {
      return this.tag ? [this.value] : [];
    }
    toString() {
      return this.tag ? `some(${this.value})` : "none()";
    }
  }
  Optional.singletonNone = new Optional(false);
  const nativeSlice = Array.prototype.slice;
  const nativeIndexOf = Array.prototype.indexOf;
  const nativePush = Array.prototype.push;
  const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
  const exists = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return true;
      }
    }
    return false;
  };
  const range$1 = (num, f) => {
    const r2 = [];
    for (let i = 0; i < num; i++) {
      r2.push(f(i));
    }
    return r2;
  };
  const map$1 = (xs, f) => {
    const len = xs.length;
    const r2 = new Array(len);
    for (let i = 0; i < len; i++) {
      const x = xs[i];
      r2[i] = f(x, i);
    }
    return r2;
  };
  const each$2 = (xs, f) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      f(x, i);
    }
  };
  const eachr = (xs, f) => {
    for (let i = xs.length - 1; i >= 0; i--) {
      const x = xs[i];
      f(x, i);
    }
  };
  const partition = (xs, pred) => {
    const pass = [];
    const fail = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      const arr = pred(x, i) ? pass : fail;
      arr.push(x);
    }
    return {
      pass,
      fail
    };
  };
  const filter$2 = (xs, pred) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        r2.push(x);
      }
    }
    return r2;
  };
  const foldr = (xs, f, acc) => {
    eachr(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const foldl = (xs, f, acc) => {
    each$2(xs, (x, i) => {
      acc = f(acc, x, i);
    });
    return acc;
  };
  const findUntil = (xs, pred, until) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(x);
      } else if (until(x, i)) {
        break;
      }
    }
    return Optional.none();
  };
  const find$1 = (xs, pred) => {
    return findUntil(xs, pred, never);
  };
  const findIndex = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      if (pred(x, i)) {
        return Optional.some(i);
      }
    }
    return Optional.none();
  };
  const flatten = (xs) => {
    const r2 = [];
    for (let i = 0, len = xs.length; i < len; ++i) {
      if (!isArray(xs[i])) {
        throw new Error("Arr.flatten item " + i + " was not an array, input: " + xs);
      }
      nativePush.apply(r2, xs[i]);
    }
    return r2;
  };
  const bind$2 = (xs, f) => flatten(map$1(xs, f));
  const forall = (xs, pred) => {
    for (let i = 0, len = xs.length; i < len; ++i) {
      const x = xs[i];
      if (pred(x, i) !== true) {
        return false;
      }
    }
    return true;
  };
  const reverse = (xs) => {
    const r2 = nativeSlice.call(xs, 0);
    r2.reverse();
    return r2;
  };
  const mapToObject = (xs, f) => {
    const r2 = {};
    for (let i = 0, len = xs.length; i < len; i++) {
      const x = xs[i];
      r2[String(x)] = f(x, i);
    }
    return r2;
  };
  const sort$1 = (xs, comparator) => {
    const copy2 = nativeSlice.call(xs, 0);
    copy2.sort(comparator);
    return copy2;
  };
  const get$d = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  const head = (xs) => get$d(xs, 0);
  const last$2 = (xs) => get$d(xs, xs.length - 1);
  const findMap = (arr, f) => {
    for (let i = 0; i < arr.length; i++) {
      const r2 = f(arr[i], i);
      if (r2.isSome()) {
        return r2;
      }
    }
    return Optional.none();
  };
  const keys = Object.keys;
  const hasOwnProperty = Object.hasOwnProperty;
  const each$1 = (obj, f) => {
    const props = keys(obj);
    for (let k = 0, len = props.length; k < len; k++) {
      const i = props[k];
      const x = obj[i];
      f(x, i);
    }
  };
  const map = (obj, f) => {
    return tupleMap(obj, (x, i) => ({
      k: i,
      v: f(x, i)
    }));
  };
  const tupleMap = (obj, f) => {
    const r2 = {};
    each$1(obj, (x, i) => {
      const tuple = f(x, i);
      r2[tuple.k] = tuple.v;
    });
    return r2;
  };
  const objAcc = (r2) => (x, i) => {
    r2[i] = x;
  };
  const internalFilter = (obj, pred, onTrue, onFalse) => {
    const r2 = {};
    each$1(obj, (x, i) => {
      (pred(x, i) ? onTrue : onFalse)(x, i);
    });
    return r2;
  };
  const filter$1 = (obj, pred) => {
    const t = {};
    internalFilter(obj, pred, objAcc(t), noop);
    return t;
  };
  const mapToArray = (obj, f) => {
    const r2 = [];
    each$1(obj, (value2, name2) => {
      r2.push(f(value2, name2));
    });
    return r2;
  };
  const values = (obj) => {
    return mapToArray(obj, identity);
  };
  const get$c = (obj, key2) => {
    return has$1(obj, key2) ? Optional.from(obj[key2]) : Optional.none();
  };
  const has$1 = (obj, key2) => hasOwnProperty.call(obj, key2);
  const hasNonNullableKey = (obj, key2) => has$1(obj, key2) && obj[key2] !== void 0 && obj[key2] !== null;
  const isEmpty = (r2) => {
    for (const x in r2) {
      if (hasOwnProperty.call(r2, x)) {
        return false;
      }
    }
    return true;
  };
  typeof window !== "undefined" ? window : Function("return this;")();
  const COMMENT = 8;
  const DOCUMENT = 9;
  const DOCUMENT_FRAGMENT = 11;
  const ELEMENT = 1;
  const TEXT = 3;
  const name = (element) => {
    const r2 = element.dom.nodeName;
    return r2.toLowerCase();
  };
  const type = (element) => element.dom.nodeType;
  const isType = (t) => (element) => type(element) === t;
  const isComment = (element) => type(element) === COMMENT || name(element) === "#comment";
  const isElement = isType(ELEMENT);
  const isText = isType(TEXT);
  const isDocument = isType(DOCUMENT);
  const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  const isTag = (tag) => (e) => isElement(e) && name(e) === tag;
  const rawSet = (dom, key2, value2) => {
    if (isString(value2) || isBoolean(value2) || isNumber(value2)) {
      dom.setAttribute(key2, value2 + "");
    } else {
      console.error("Invalid call to Attribute.set. Key ", key2, ":: Value ", value2, ":: Element ", dom);
      throw new Error("Attribute value was not simple");
    }
  };
  const set$2 = (element, key2, value2) => {
    rawSet(element.dom, key2, value2);
  };
  const setAll$1 = (element, attrs) => {
    const dom = element.dom;
    each$1(attrs, (v, k) => {
      rawSet(dom, k, v);
    });
  };
  const setOptions = (element, attrs) => {
    each$1(attrs, (v, k) => {
      v.fold(() => {
        remove$7(element, k);
      }, (value2) => {
        rawSet(element.dom, k, value2);
      });
    });
  };
  const get$b = (element, key2) => {
    const v = element.dom.getAttribute(key2);
    return v === null ? void 0 : v;
  };
  const getOpt = (element, key2) => Optional.from(get$b(element, key2));
  const remove$7 = (element, key2) => {
    element.dom.removeAttribute(key2);
  };
  const clone$2 = (element) => foldl(element.dom.attributes, (acc, attr) => {
    acc[attr.name] = attr.value;
    return acc;
  }, {});
  const fromHtml$1 = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    if (!div.hasChildNodes() || div.childNodes.length > 1) {
      const message = "HTML does not have a single root node";
      console.error(message, html);
      throw new Error(message);
    }
    return fromDom$1(div.childNodes[0]);
  };
  const fromTag = (tag, scope) => {
    const doc = scope || document;
    const node = doc.createElement(tag);
    return fromDom$1(node);
  };
  const fromText = (text, scope) => {
    const doc = scope || document;
    const node = doc.createTextNode(text);
    return fromDom$1(node);
  };
  const fromDom$1 = (node) => {
    if (node === null || node === void 0) {
      throw new Error("Node cannot be null or undefined");
    }
    return { dom: node };
  };
  const fromPoint$1 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
  const SugarElement = {
    fromHtml: fromHtml$1,
    fromTag,
    fromText,
    fromDom: fromDom$1,
    fromPoint: fromPoint$1
  };
  const is$2 = (element, selector) => {
    const dom = element.dom;
    if (dom.nodeType !== ELEMENT) {
      return false;
    } else {
      const elem = dom;
      if (elem.matches !== void 0) {
        return elem.matches(selector);
      } else if (elem.msMatchesSelector !== void 0) {
        return elem.msMatchesSelector(selector);
      } else if (elem.webkitMatchesSelector !== void 0) {
        return elem.webkitMatchesSelector(selector);
      } else if (elem.mozMatchesSelector !== void 0) {
        return elem.mozMatchesSelector(selector);
      } else {
        throw new Error("Browser lacks native selectors");
      }
    }
  };
  const bypassSelector = (dom) => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  const all$1 = (selector, scope) => {
    const base2 = scope === void 0 ? document : scope.dom;
    return bypassSelector(base2) ? [] : map$1(base2.querySelectorAll(selector), SugarElement.fromDom);
  };
  const one = (selector, scope) => {
    const base2 = scope === void 0 ? document : scope.dom;
    return bypassSelector(base2) ? Optional.none() : Optional.from(base2.querySelector(selector)).map(SugarElement.fromDom);
  };
  const eq$1 = (e1, e2) => e1.dom === e2.dom;
  const contains$1 = (e1, e2) => {
    const d1 = e1.dom;
    const d2 = e2.dom;
    return d1 === d2 ? false : d1.contains(d2);
  };
  const is$1 = is$2;
  const owner = (element) => SugarElement.fromDom(element.dom.ownerDocument);
  const documentOrOwner = (dos) => isDocument(dos) ? dos : owner(dos);
  const documentElement = (element) => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
  const defaultView = (element) => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
  const parent = (element) => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  const parentElement = (element) => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
  const parents = (element, isRoot) => {
    const stop = isFunction(isRoot) ? isRoot : never;
    let dom = element.dom;
    const ret = [];
    while (dom.parentNode !== null && dom.parentNode !== void 0) {
      const rawParent = dom.parentNode;
      const p = SugarElement.fromDom(rawParent);
      ret.push(p);
      if (stop(p) === true) {
        break;
      } else {
        dom = rawParent;
      }
    }
    return ret;
  };
  const prevSibling = (element) => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
  const nextSibling = (element) => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  const children$2 = (element) => map$1(element.dom.childNodes, SugarElement.fromDom);
  const child$2 = (element, index2) => {
    const cs = element.dom.childNodes;
    return Optional.from(cs[index2]).map(SugarElement.fromDom);
  };
  const firstChild = (element) => child$2(element, 0);
  const before$3 = (marker, element) => {
    const parent$1 = parent(marker);
    parent$1.each((v) => {
      v.dom.insertBefore(element.dom, marker.dom);
    });
  };
  const after$5 = (marker, element) => {
    const sibling = nextSibling(marker);
    sibling.fold(() => {
      const parent$1 = parent(marker);
      parent$1.each((v) => {
        append$1(v, element);
      });
    }, (v) => {
      before$3(v, element);
    });
  };
  const prepend = (parent2, element) => {
    const firstChild$1 = firstChild(parent2);
    firstChild$1.fold(() => {
      append$1(parent2, element);
    }, (v) => {
      parent2.dom.insertBefore(element.dom, v.dom);
    });
  };
  const append$1 = (parent2, element) => {
    parent2.dom.appendChild(element.dom);
  };
  const appendAt = (parent2, element, index2) => {
    child$2(parent2, index2).fold(() => {
      append$1(parent2, element);
    }, (v) => {
      before$3(v, element);
    });
  };
  const wrap = (element, wrapper) => {
    before$3(element, wrapper);
    append$1(wrapper, element);
  };
  const after$4 = (marker, elements) => {
    each$2(elements, (x, i) => {
      const e = i === 0 ? marker : elements[i - 1];
      after$5(e, x);
    });
  };
  const append = (parent2, elements) => {
    each$2(elements, (x) => {
      append$1(parent2, x);
    });
  };
  const empty = (element) => {
    element.dom.textContent = "";
    each$2(children$2(element), (rogue) => {
      remove$6(rogue);
    });
  };
  const remove$6 = (element) => {
    const dom = element.dom;
    if (dom.parentNode !== null) {
      dom.parentNode.removeChild(dom);
    }
  };
  const unwrap = (wrapper) => {
    const children2 = children$2(wrapper);
    if (children2.length > 0) {
      after$4(wrapper, children2);
    }
    remove$6(wrapper);
  };
  const clone$1 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  const shallow = (original) => clone$1(original, false);
  const deep = (original) => clone$1(original, true);
  const shallowAs = (original, tag) => {
    const nu2 = SugarElement.fromTag(tag);
    const attributes = clone$2(original);
    setAll$1(nu2, attributes);
    return nu2;
  };
  const copy$2 = (original, tag) => {
    const nu2 = shallowAs(original, tag);
    const cloneChildren = children$2(deep(original));
    append(nu2, cloneChildren);
    return nu2;
  };
  const mutate$1 = (original, tag) => {
    const nu2 = shallowAs(original, tag);
    after$5(original, nu2);
    const children2 = children$2(original);
    append(nu2, children2);
    remove$6(original);
    return nu2;
  };
  const validSectionList = [
    "tfoot",
    "thead",
    "tbody",
    "colgroup"
  ];
  const isValidSection = (parentName) => contains$2(validSectionList, parentName);
  const grid = (rows2, columns2) => ({
    rows: rows2,
    columns: columns2
  });
  const address = (row2, column) => ({
    row: row2,
    column
  });
  const detail = (element, rowspan, colspan) => ({
    element,
    rowspan,
    colspan
  });
  const detailnew = (element, rowspan, colspan, isNew) => ({
    element,
    rowspan,
    colspan,
    isNew
  });
  const extended = (element, rowspan, colspan, row2, column, isLocked) => ({
    element,
    rowspan,
    colspan,
    row: row2,
    column,
    isLocked
  });
  const rowdetail = (element, cells2, section2) => ({
    element,
    cells: cells2,
    section: section2
  });
  const rowdetailnew = (element, cells2, section2, isNew) => ({
    element,
    cells: cells2,
    section: section2,
    isNew
  });
  const elementnew = (element, isNew, isLocked) => ({
    element,
    isNew,
    isLocked
  });
  const rowcells = (element, cells2, section2, isNew) => ({
    element,
    cells: cells2,
    section: section2,
    isNew
  });
  const bounds = (startRow, startCol, finishRow, finishCol) => ({
    startRow,
    startCol,
    finishRow,
    finishCol
  });
  const columnext = (element, colspan, column) => ({
    element,
    colspan,
    column
  });
  const colgroup = (element, columns2) => ({
    element,
    columns: columns2
  });
  const isShadowRoot = (dos) => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  const isSupported$1 = constant(supported);
  const getRootNode = supported ? (e) => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  const getShadowRoot = (e) => {
    const r2 = getRootNode(e);
    return isShadowRoot(r2) ? Optional.some(r2) : Optional.none();
  };
  const getShadowHost = (e) => SugarElement.fromDom(e.dom.host);
  const getOriginalEventTarget = (event) => {
    if (isSupported$1() && isNonNullable(event.target)) {
      const el = SugarElement.fromDom(event.target);
      if (isElement(el) && isOpenShadowHost(el)) {
        if (event.composed && event.composedPath) {
          const composedPath = event.composedPath();
          if (composedPath) {
            return head(composedPath);
          }
        }
      }
    }
    return Optional.from(event.target);
  };
  const isOpenShadowHost = (element) => isNonNullable(element.dom.shadowRoot);
  const inBody = (element) => {
    const dom = isText(element) ? element.dom.parentNode : element.dom;
    if (dom === void 0 || dom === null || dom.ownerDocument === null) {
      return false;
    }
    const doc = dom.ownerDocument;
    return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  };
  const body$1 = () => getBody$1(SugarElement.fromDom(document));
  const getBody$1 = (doc) => {
    const b = doc.dom.body;
    if (b === null || b === void 0) {
      throw new Error("Body is not available yet");
    }
    return SugarElement.fromDom(b);
  };
  const ancestors$4 = (scope, predicate, isRoot) => filter$2(parents(scope, isRoot), predicate);
  const children$1 = (scope, predicate) => filter$2(children$2(scope), predicate);
  const descendants$1 = (scope, predicate) => {
    let result = [];
    each$2(children$2(scope), (x) => {
      if (predicate(x)) {
        result = result.concat([x]);
      }
      result = result.concat(descendants$1(x, predicate));
    });
    return result;
  };
  const ancestors$3 = (scope, selector, isRoot) => ancestors$4(scope, (e) => is$2(e, selector), isRoot);
  const children = (scope, selector) => children$1(scope, (e) => is$2(e, selector));
  const descendants = (scope, selector) => all$1(selector, scope);
  var ClosestOrAncestor = (is2, ancestor2, scope, a, isRoot) => {
    if (is2(scope, a)) {
      return Optional.some(scope);
    } else if (isFunction(isRoot) && isRoot(scope)) {
      return Optional.none();
    } else {
      return ancestor2(scope, a, isRoot);
    }
  };
  const ancestor$2 = (scope, predicate, isRoot) => {
    let element = scope.dom;
    const stop = isFunction(isRoot) ? isRoot : never;
    while (element.parentNode) {
      element = element.parentNode;
      const el = SugarElement.fromDom(element);
      if (predicate(el)) {
        return Optional.some(el);
      } else if (stop(el)) {
        break;
      }
    }
    return Optional.none();
  };
  const closest$2 = (scope, predicate, isRoot) => {
    const is2 = (s, test) => test(s);
    return ClosestOrAncestor(is2, ancestor$2, scope, predicate, isRoot);
  };
  const child$1 = (scope, predicate) => {
    const pred = (node) => predicate(SugarElement.fromDom(node));
    const result = find$1(scope.dom.childNodes, pred);
    return result.map(SugarElement.fromDom);
  };
  const descendant$1 = (scope, predicate) => {
    const descend = (node) => {
      for (let i = 0; i < node.childNodes.length; i++) {
        const child2 = SugarElement.fromDom(node.childNodes[i]);
        if (predicate(child2)) {
          return Optional.some(child2);
        }
        const res = descend(node.childNodes[i]);
        if (res.isSome()) {
          return res;
        }
      }
      return Optional.none();
    };
    return descend(scope.dom);
  };
  const ancestor$1 = (scope, selector, isRoot) => ancestor$2(scope, (e) => is$2(e, selector), isRoot);
  const child = (scope, selector) => child$1(scope, (e) => is$2(e, selector));
  const descendant = (scope, selector) => one(selector, scope);
  const closest$1 = (scope, selector, isRoot) => {
    const is2 = (element, selector2) => is$2(element, selector2);
    return ClosestOrAncestor(is2, ancestor$1, scope, selector, isRoot);
  };
  const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists((left2) => comparator(left2, rhs));
  const cat = (arr) => {
    const r2 = [];
    const push = (x) => {
      r2.push(x);
    };
    for (let i = 0; i < arr.length; i++) {
      arr[i].each(push);
    }
    return r2;
  };
  const bindFrom = (a, f) => a !== void 0 && a !== null ? f(a) : Optional.none();
  const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  const checkRange = (str, substr, start) => substr === "" || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  const contains = (str, substr) => {
    return str.indexOf(substr) !== -1;
  };
  const startsWith = (str, prefix) => {
    return checkRange(str, prefix, 0);
  };
  const endsWith = (str, suffix) => {
    return checkRange(str, suffix, str.length - suffix.length);
  };
  const blank = (r2) => (s) => s.replace(r2, "");
  const trim = blank(/^\s+|\s+$/g);
  const isNotEmpty = (s) => s.length > 0;
  const toFloat = (value2) => {
    const num = parseFloat(value2);
    return isNaN(num) ? Optional.none() : Optional.some(num);
  };
  const isSupported = (dom) => dom.style !== void 0 && isFunction(dom.style.getPropertyValue);
  const internalSet = (dom, property, value2) => {
    if (!isString(value2)) {
      console.error("Invalid call to CSS.set. Property ", property, ":: Value ", value2, ":: Element ", dom);
      throw new Error("CSS value must be a string: " + value2);
    }
    if (isSupported(dom)) {
      dom.style.setProperty(property, value2);
    }
  };
  const internalRemove = (dom, property) => {
    if (isSupported(dom)) {
      dom.style.removeProperty(property);
    }
  };
  const set$1 = (element, property, value2) => {
    const dom = element.dom;
    internalSet(dom, property, value2);
  };
  const setAll = (element, css2) => {
    const dom = element.dom;
    each$1(css2, (v, k) => {
      internalSet(dom, k, v);
    });
  };
  const get$a = (element, property) => {
    const dom = element.dom;
    const styles2 = window.getComputedStyle(dom);
    const r2 = styles2.getPropertyValue(property);
    return r2 === "" && !inBody(element) ? getUnsafeProperty(dom, property) : r2;
  };
  const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : "";
  const getRaw$2 = (element, property) => {
    const dom = element.dom;
    const raw = getUnsafeProperty(dom, property);
    return Optional.from(raw).filter((r2) => r2.length > 0);
  };
  const remove$5 = (element, property) => {
    const dom = element.dom;
    internalRemove(dom, property);
    if (is(getOpt(element, "style").map(trim), "")) {
      remove$7(element, "style");
    }
  };
  const copy$1 = (source, target) => {
    const sourceDom = source.dom;
    const targetDom = target.dom;
    if (isSupported(sourceDom) && isSupported(targetDom)) {
      targetDom.style.cssText = sourceDom.style.cssText;
    }
  };
  const getAttrValue = (cell2, name2, fallback2 = 0) => getOpt(cell2, name2).map((value2) => parseInt(value2, 10)).getOr(fallback2);
  const getSpan = (cell2, type2) => getAttrValue(cell2, type2, 1);
  const hasColspan = (cellOrCol) => {
    if (isTag("col")(cellOrCol)) {
      return getAttrValue(cellOrCol, "span", 1) > 1;
    } else {
      return getSpan(cellOrCol, "colspan") > 1;
    }
  };
  const hasRowspan = (cell2) => getSpan(cell2, "rowspan") > 1;
  const getCssValue = (element, property) => parseInt(get$a(element, property), 10);
  const minWidth = constant(10);
  const minHeight = constant(10);
  const firstLayer = (scope, selector) => {
    return filterFirstLayer(scope, selector, always);
  };
  const filterFirstLayer = (scope, selector, predicate) => {
    return bind$2(children$2(scope), (x) => {
      if (is$2(x, selector)) {
        return predicate(x) ? [x] : [];
      } else {
        return filterFirstLayer(x, selector, predicate);
      }
    });
  };
  const lookup = (tags, element, isRoot = never) => {
    if (isRoot(element)) {
      return Optional.none();
    }
    if (contains$2(tags, name(element))) {
      return Optional.some(element);
    }
    const isRootOrUpperTable = (elm) => is$2(elm, "table") || isRoot(elm);
    return ancestor$1(element, tags.join(","), isRootOrUpperTable);
  };
  const cell = (element, isRoot) => lookup([
    "td",
    "th"
  ], element, isRoot);
  const cells$1 = (ancestor2) => firstLayer(ancestor2, "th,td");
  const columns$1 = (ancestor2) => {
    if (is$2(ancestor2, "colgroup")) {
      return children(ancestor2, "col");
    } else {
      return bind$2(columnGroups(ancestor2), (columnGroup) => children(columnGroup, "col"));
    }
  };
  const table = (element, isRoot) => closest$1(element, "table", isRoot);
  const rows$1 = (ancestor2) => firstLayer(ancestor2, "tr");
  const columnGroups = (ancestor2) => table(ancestor2).fold(constant([]), (table2) => children(table2, "colgroup"));
  const fromRowsOrColGroups = (elems, getSection) => map$1(elems, (row2) => {
    if (name(row2) === "colgroup") {
      const cells2 = map$1(columns$1(row2), (column) => {
        const colspan = getAttrValue(column, "span", 1);
        return detail(column, 1, colspan);
      });
      return rowdetail(row2, cells2, "colgroup");
    } else {
      const cells2 = map$1(cells$1(row2), (cell2) => {
        const rowspan = getAttrValue(cell2, "rowspan", 1);
        const colspan = getAttrValue(cell2, "colspan", 1);
        return detail(cell2, rowspan, colspan);
      });
      return rowdetail(row2, cells2, getSection(row2));
    }
  });
  const getParentSection = (group) => parent(group).map((parent2) => {
    const parentName = name(parent2);
    return isValidSection(parentName) ? parentName : "tbody";
  }).getOr("tbody");
  const fromTable$1 = (table2) => {
    const rows2 = rows$1(table2);
    const columnGroups$1 = columnGroups(table2);
    const elems = [
      ...columnGroups$1,
      ...rows2
    ];
    return fromRowsOrColGroups(elems, getParentSection);
  };
  const fromPastedRows = (elems, section2) => fromRowsOrColGroups(elems, () => section2);
  const cached = (f) => {
    let called = false;
    let r2;
    return (...args) => {
      if (!called) {
        called = true;
        r2 = f.apply(null, args);
      }
      return r2;
    };
  };
  const DeviceType = (os, browser, userAgent, mediaMatch2) => {
    const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
    const isiPhone = os.isiOS() && !isiPad;
    const isMobile = os.isiOS() || os.isAndroid();
    const isTouch = isMobile || mediaMatch2("(pointer:coarse)");
    const isTablet = isiPad || !isiPhone && isMobile && mediaMatch2("(min-device-width:768px)");
    const isPhone = isiPhone || isMobile && !isTablet;
    const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
    const isDesktop = !isPhone && !isTablet && !iOSwebview;
    return {
      isiPad: constant(isiPad),
      isiPhone: constant(isiPhone),
      isTablet: constant(isTablet),
      isPhone: constant(isPhone),
      isTouch: constant(isTouch),
      isAndroid: os.isAndroid,
      isiOS: os.isiOS,
      isWebView: constant(iOSwebview),
      isDesktop: constant(isDesktop)
    };
  };
  const firstMatch = (regexes, s) => {
    for (let i = 0; i < regexes.length; i++) {
      const x = regexes[i];
      if (x.test(s)) {
        return x;
      }
    }
    return void 0;
  };
  const find = (regexes, agent) => {
    const r2 = firstMatch(regexes, agent);
    if (!r2) {
      return {
        major: 0,
        minor: 0
      };
    }
    const group = (i) => {
      return Number(agent.replace(r2, "$" + i));
    };
    return nu$2(group(1), group(2));
  };
  const detect$5 = (versionRegexes, agent) => {
    const cleanedAgent = String(agent).toLowerCase();
    if (versionRegexes.length === 0) {
      return unknown$2();
    }
    return find(versionRegexes, cleanedAgent);
  };
  const unknown$2 = () => {
    return nu$2(0, 0);
  };
  const nu$2 = (major, minor) => {
    return {
      major,
      minor
    };
  };
  const Version = {
    nu: nu$2,
    detect: detect$5,
    unknown: unknown$2
  };
  const detectBrowser$1 = (browsers2, userAgentData) => {
    return findMap(userAgentData.brands, (uaBrand) => {
      const lcBrand = uaBrand.brand.toLowerCase();
      return find$1(browsers2, (browser) => {
        var _a;
        return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
      }).map((info) => ({
        current: info.name,
        version: Version.nu(parseInt(uaBrand.version, 10), 0)
      }));
    });
  };
  const detect$4 = (candidates, userAgent) => {
    const agent = String(userAgent).toLowerCase();
    return find$1(candidates, (candidate) => {
      return candidate.search(agent);
    });
  };
  const detectBrowser = (browsers2, userAgent) => {
    return detect$4(browsers2, userAgent).map((browser) => {
      const version = Version.detect(browser.versionRegexes, userAgent);
      return {
        current: browser.name,
        version
      };
    });
  };
  const detectOs = (oses2, userAgent) => {
    return detect$4(oses2, userAgent).map((os) => {
      const version = Version.detect(os.versionRegexes, userAgent);
      return {
        current: os.name,
        version
      };
    });
  };
  const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  const checkContains = (target) => {
    return (uastring) => {
      return contains(uastring, target);
    };
  };
  const browsers = [
    {
      name: "Edge",
      versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
      search: (uastring) => {
        return contains(uastring, "edge/") && contains(uastring, "chrome") && contains(uastring, "safari") && contains(uastring, "applewebkit");
      }
    },
    {
      name: "Chromium",
      brand: "Chromium",
      versionRegexes: [
        /.*?chrome\/([0-9]+)\.([0-9]+).*/,
        normalVersionRegex
      ],
      search: (uastring) => {
        return contains(uastring, "chrome") && !contains(uastring, "chromeframe");
      }
    },
    {
      name: "IE",
      versionRegexes: [
        /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
        /.*?rv:([0-9]+)\.([0-9]+).*/
      ],
      search: (uastring) => {
        return contains(uastring, "msie") || contains(uastring, "trident");
      }
    },
    {
      name: "Opera",
      versionRegexes: [
        normalVersionRegex,
        /.*?opera\/([0-9]+)\.([0-9]+).*/
      ],
      search: checkContains("opera")
    },
    {
      name: "Firefox",
      versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
      search: checkContains("firefox")
    },
    {
      name: "Safari",
      versionRegexes: [
        normalVersionRegex,
        /.*?cpu os ([0-9]+)_([0-9]+).*/
      ],
      search: (uastring) => {
        return (contains(uastring, "safari") || contains(uastring, "mobile/")) && contains(uastring, "applewebkit");
      }
    }
  ];
  const oses = [
    {
      name: "Windows",
      search: checkContains("win"),
      versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "iOS",
      search: (uastring) => {
        return contains(uastring, "iphone") || contains(uastring, "ipad");
      },
      versionRegexes: [
        /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
        /.*cpu os ([0-9]+)_([0-9]+).*/,
        /.*cpu iphone os ([0-9]+)_([0-9]+).*/
      ]
    },
    {
      name: "Android",
      search: checkContains("android"),
      versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
    },
    {
      name: "macOS",
      search: checkContains("mac os x"),
      versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
    },
    {
      name: "Linux",
      search: checkContains("linux"),
      versionRegexes: []
    },
    {
      name: "Solaris",
      search: checkContains("sunos"),
      versionRegexes: []
    },
    {
      name: "FreeBSD",
      search: checkContains("freebsd"),
      versionRegexes: []
    },
    {
      name: "ChromeOS",
      search: checkContains("cros"),
      versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
    }
  ];
  const PlatformInfo = {
    browsers: constant(browsers),
    oses: constant(oses)
  };
  const edge = "Edge";
  const chromium = "Chromium";
  const ie = "IE";
  const opera = "Opera";
  const firefox = "Firefox";
  const safari = "Safari";
  const unknown$1 = () => {
    return nu$1({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu$1 = (info) => {
    const current = info.current;
    const version = info.version;
    const isBrowser = (name2) => () => current === name2;
    return {
      current,
      version,
      isEdge: isBrowser(edge),
      isChromium: isBrowser(chromium),
      isIE: isBrowser(ie),
      isOpera: isBrowser(opera),
      isFirefox: isBrowser(firefox),
      isSafari: isBrowser(safari)
    };
  };
  const Browser = {
    unknown: unknown$1,
    nu: nu$1,
    edge: constant(edge),
    chromium: constant(chromium),
    ie: constant(ie),
    opera: constant(opera),
    firefox: constant(firefox),
    safari: constant(safari)
  };
  const windows = "Windows";
  const ios = "iOS";
  const android = "Android";
  const linux = "Linux";
  const macos = "macOS";
  const solaris = "Solaris";
  const freebsd = "FreeBSD";
  const chromeos = "ChromeOS";
  const unknown = () => {
    return nu({
      current: void 0,
      version: Version.unknown()
    });
  };
  const nu = (info) => {
    const current = info.current;
    const version = info.version;
    const isOS = (name2) => () => current === name2;
    return {
      current,
      version,
      isWindows: isOS(windows),
      isiOS: isOS(ios),
      isAndroid: isOS(android),
      isMacOS: isOS(macos),
      isLinux: isOS(linux),
      isSolaris: isOS(solaris),
      isFreeBSD: isOS(freebsd),
      isChromeOS: isOS(chromeos)
    };
  };
  const OperatingSystem = {
    unknown,
    nu,
    windows: constant(windows),
    ios: constant(ios),
    android: constant(android),
    linux: constant(linux),
    macos: constant(macos),
    solaris: constant(solaris),
    freebsd: constant(freebsd),
    chromeos: constant(chromeos)
  };
  const detect$3 = (userAgent, userAgentDataOpt, mediaMatch2) => {
    const browsers2 = PlatformInfo.browsers();
    const oses2 = PlatformInfo.oses();
    const browser = userAgentDataOpt.bind((userAgentData) => detectBrowser$1(browsers2, userAgentData)).orThunk(() => detectBrowser(browsers2, userAgent)).fold(Browser.unknown, Browser.nu);
    const os = detectOs(oses2, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
    const deviceType = DeviceType(os, browser, userAgent, mediaMatch2);
    return {
      browser,
      os,
      deviceType
    };
  };
  const PlatformDetection = { detect: detect$3 };
  const mediaMatch = (query) => window.matchMedia(query).matches;
  let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  const detect$2 = () => platform();
  const Dimension = (name2, getOffset) => {
    const set2 = (element, h2) => {
      if (!isNumber(h2) && !h2.match(/^[0-9]+$/)) {
        throw new Error(name2 + ".set accepts only positive integer values. Value was " + h2);
      }
      const dom = element.dom;
      if (isSupported(dom)) {
        dom.style[name2] = h2 + "px";
      }
    };
    const get2 = (element) => {
      const r2 = getOffset(element);
      if (r2 <= 0 || r2 === null) {
        const css2 = get$a(element, name2);
        return parseFloat(css2) || 0;
      }
      return r2;
    };
    const getOuter2 = get2;
    const aggregate = (element, properties) => foldl(properties, (acc, property) => {
      const val = get$a(element, property);
      const value2 = val === void 0 ? 0 : parseInt(val, 10);
      return isNaN(value2) ? acc : acc + value2;
    }, 0);
    const max = (element, value2, properties) => {
      const cumulativeInclusions = aggregate(element, properties);
      const absoluteMax = value2 > cumulativeInclusions ? value2 - cumulativeInclusions : 0;
      return absoluteMax;
    };
    return {
      set: set2,
      get: get2,
      getOuter: getOuter2,
      aggregate,
      max
    };
  };
  const toNumber = (px, fallback2) => toFloat(px).getOr(fallback2);
  const getProp = (element, name2, fallback2) => toNumber(get$a(element, name2), fallback2);
  const calcContentBoxSize = (element, size, upper, lower) => {
    const paddingUpper = getProp(element, `padding-${upper}`, 0);
    const paddingLower = getProp(element, `padding-${lower}`, 0);
    const borderUpper = getProp(element, `border-${upper}-width`, 0);
    const borderLower = getProp(element, `border-${lower}-width`, 0);
    return size - paddingUpper - paddingLower - borderUpper - borderLower;
  };
  const getCalculatedWidth = (element, boxSizing) => {
    const dom = element.dom;
    const width2 = dom.getBoundingClientRect().width || dom.offsetWidth;
    return boxSizing === "border-box" ? width2 : calcContentBoxSize(element, width2, "left", "right");
  };
  const getHeight$1 = (element) => getProp(element, "height", element.dom.offsetHeight);
  const getWidth = (element) => getProp(element, "width", element.dom.offsetWidth);
  const getInnerWidth = (element) => getCalculatedWidth(element, "content-box");
  const api$2 = Dimension("width", (element) => element.dom.offsetWidth);
  const get$9 = (element) => api$2.get(element);
  const getOuter$2 = (element) => api$2.getOuter(element);
  const getInner = getInnerWidth;
  const getRuntime$1 = getWidth;
  const addCells = (gridRow, index2, cells2) => {
    const existingCells = gridRow.cells;
    const before2 = existingCells.slice(0, index2);
    const after2 = existingCells.slice(index2);
    const newCells = before2.concat(cells2).concat(after2);
    return setCells(gridRow, newCells);
  };
  const addCell = (gridRow, index2, cell2) => addCells(gridRow, index2, [cell2]);
  const mutateCell = (gridRow, index2, cell2) => {
    const cells2 = gridRow.cells;
    cells2[index2] = cell2;
  };
  const setCells = (gridRow, cells2) => rowcells(gridRow.element, cells2, gridRow.section, gridRow.isNew);
  const mapCells = (gridRow, f) => {
    const cells2 = gridRow.cells;
    const r2 = map$1(cells2, f);
    return rowcells(gridRow.element, r2, gridRow.section, gridRow.isNew);
  };
  const getCell = (gridRow, index2) => gridRow.cells[index2];
  const getCellElement = (gridRow, index2) => getCell(gridRow, index2).element;
  const cellLength = (gridRow) => gridRow.cells.length;
  const extractGridDetails = (grid2) => {
    const result = partition(grid2, (row2) => row2.section === "colgroup");
    return {
      rows: result.fail,
      cols: result.pass
    };
  };
  const clone = (gridRow, cloneRow2, cloneCell) => {
    const newCells = map$1(gridRow.cells, cloneCell);
    return rowcells(cloneRow2(gridRow.element), newCells, gridRow.section, true);
  };
  const LOCKED_COL_ATTR = "data-snooker-locked-cols";
  const getLockedColumnsFromTable = (table2) => getOpt(table2, LOCKED_COL_ATTR).bind((lockedColStr) => Optional.from(lockedColStr.match(/\d+/g))).map((lockedCols) => mapToObject(lockedCols, always));
  const getLockedColumnsFromGrid = (grid2) => {
    const locked = foldl(extractGridDetails(grid2).rows, (acc, row2) => {
      each$2(row2.cells, (cell2, idx) => {
        if (cell2.isLocked) {
          acc[idx] = true;
        }
      });
      return acc;
    }, {});
    const lockedArr = mapToArray(locked, (_val, key2) => parseInt(key2, 10));
    return sort$1(lockedArr);
  };
  const key = (row2, column) => {
    return row2 + "," + column;
  };
  const getAt = (warehouse, row2, column) => Optional.from(warehouse.access[key(row2, column)]);
  const findItem = (warehouse, item, comparator) => {
    const filtered = filterItems(warehouse, (detail2) => {
      return comparator(item, detail2.element);
    });
    return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none();
  };
  const filterItems = (warehouse, predicate) => {
    const all2 = bind$2(warehouse.all, (r2) => {
      return r2.cells;
    });
    return filter$2(all2, predicate);
  };
  const generateColumns = (rowData) => {
    const columnsGroup = {};
    let index2 = 0;
    each$2(rowData.cells, (column) => {
      const colspan = column.colspan;
      range$1(colspan, (columnIndex) => {
        const colIndex = index2 + columnIndex;
        columnsGroup[colIndex] = columnext(column.element, colspan, colIndex);
      });
      index2 += colspan;
    });
    return columnsGroup;
  };
  const generate$1 = (list) => {
    const access = {};
    const cells2 = [];
    const tableOpt = head(list).map((rowData) => rowData.element).bind(table);
    const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({});
    let maxRows = 0;
    let maxColumns = 0;
    let rowCount = 0;
    const {
      pass: colgroupRows,
      fail: rows2
    } = partition(list, (rowData) => rowData.section === "colgroup");
    each$2(rows2, (rowData) => {
      const currentRow = [];
      each$2(rowData.cells, (rowCell) => {
        let start = 0;
        while (access[key(rowCount, start)] !== void 0) {
          start++;
        }
        const isLocked = hasNonNullableKey(lockedColumns, start.toString());
        const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked);
        for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) {
          for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) {
            const rowPosition = rowCount + occupiedRowPosition;
            const columnPosition = start + occupiedColumnPosition;
            const newpos = key(rowPosition, columnPosition);
            access[newpos] = current;
            maxColumns = Math.max(maxColumns, columnPosition + 1);
          }
        }
        currentRow.push(current);
      });
      maxRows++;
      cells2.push(rowdetail(rowData.element, currentRow, rowData.section));
      rowCount++;
    });
    const { columns: columns2, colgroups } = last$2(colgroupRows).map((rowData) => {
      const columns3 = generateColumns(rowData);
      const colgroup$1 = colgroup(rowData.element, values(columns3));
      return {
        colgroups: [colgroup$1],
        columns: columns3
      };
    }).getOrThunk(() => ({
      colgroups: [],
      columns: {}
    }));
    const grid$1 = grid(maxRows, maxColumns);
    return {
      grid: grid$1,
      access,
      all: cells2,
      columns: columns2,
      colgroups
    };
  };
  const fromTable = (table2) => {
    const list = fromTable$1(table2);
    return generate$1(list);
  };
  const justCells = (warehouse) => bind$2(warehouse.all, (w) => w.cells);
  const justColumns = (warehouse) => values(warehouse.columns);
  const hasColumns = (warehouse) => keys(warehouse.columns).length > 0;
  const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]);
  const Warehouse = {
    fromTable,
    generate: generate$1,
    getAt,
    findItem,
    filterItems,
    justCells,
    justColumns,
    hasColumns,
    getColumnAt
  };
  const columns = (warehouse, isValidCell = always) => {
    const grid2 = warehouse.grid;
    const cols = range$1(grid2.columns, identity);
    const rowsArr = range$1(grid2.rows, identity);
    return map$1(cols, (col2) => {
      const getBlock = () => bind$2(rowsArr, (r2) => Warehouse.getAt(warehouse, r2, col2).filter((detail2) => detail2.column === col2).toArray());
      const isValid = (detail2) => detail2.colspan === 1 && isValidCell(detail2.element);
      const getFallback = () => Warehouse.getAt(warehouse, 0, col2);
      return decide(getBlock, isValid, getFallback);
    });
  };
  const decide = (getBlock, isValid, getFallback) => {
    const inBlock = getBlock();
    const validInBlock = find$1(inBlock, isValid);
    const detailOption = validInBlock.orThunk(() => Optional.from(inBlock[0]).orThunk(getFallback));
    return detailOption.map((detail2) => detail2.element);
  };
  const rows = (warehouse) => {
    const grid2 = warehouse.grid;
    const rowsArr = range$1(grid2.rows, identity);
    const cols = range$1(grid2.columns, identity);
    return map$1(rowsArr, (row2) => {
      const getBlock = () => bind$2(cols, (c) => Warehouse.getAt(warehouse, row2, c).filter((detail2) => detail2.row === row2).fold(constant([]), (detail2) => [detail2]));
      const isSingle = (detail2) => detail2.rowspan === 1;
      const getFallback = () => Warehouse.getAt(warehouse, row2, 0);
      return decide(getBlock, isSingle, getFallback);
    });
  };
  const deduce = (xs, index2) => {
    if (index2 < 0 || index2 >= xs.length - 1) {
      return Optional.none();
    }
    const current = xs[index2].fold(() => {
      const rest = reverse(xs.slice(0, index2));
      return findMap(rest, (a, i) => a.map((aa) => ({
        value: aa,
        delta: i + 1
      })));
    }, (c) => Optional.some({
      value: c,
      delta: 0
    }));
    const next = xs[index2 + 1].fold(() => {
      const rest = xs.slice(index2 + 1);
      return findMap(rest, (a, i) => a.map((aa) => ({
        value: aa,
        delta: i + 1
      })));
    }, (n) => Optional.some({
      value: n,
      delta: 1
    }));
    return current.bind((c) => next.map((n) => {
      const extras = n.delta + c.delta;
      return Math.abs(n.value - c.value) / extras;
    }));
  };
  const onDirection = (isLtr, isRtl) => (element) => getDirection(element) === "rtl" ? isRtl : isLtr;
  const getDirection = (element) => get$a(element, "direction") === "rtl" ? "rtl" : "ltr";
  const api$1 = Dimension("height", (element) => {
    const dom = element.dom;
    return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
  });
  const get$8 = (element) => api$1.get(element);
  const getOuter$1 = (element) => api$1.getOuter(element);
  const getRuntime = getHeight$1;
  const r = (left2, top) => {
    const translate2 = (x, y) => r(left2 + x, top + y);
    return {
      left: left2,
      top,
      translate: translate2
    };
  };
  const SugarPosition = r;
  const boxPosition = (dom) => {
    const box = dom.getBoundingClientRect();
    return SugarPosition(box.left, box.top);
  };
  const firstDefinedOrZero = (a, b) => {
    if (a !== void 0) {
      return a;
    } else {
      return b !== void 0 ? b : 0;
    }
  };
  const absolute = (element) => {
    const doc = element.dom.ownerDocument;
    const body2 = doc.body;
    const win = doc.defaultView;
    const html = doc.documentElement;
    if (body2 === element.dom) {
      return SugarPosition(body2.offsetLeft, body2.offsetTop);
    }
    const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
    const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
    const clientTop = firstDefinedOrZero(html.clientTop, body2.clientTop);
    const clientLeft = firstDefinedOrZero(html.clientLeft, body2.clientLeft);
    return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
  };
  const viewport = (element) => {
    const dom = element.dom;
    const doc = dom.ownerDocument;
    const body2 = doc.body;
    if (body2 === dom) {
      return SugarPosition(body2.offsetLeft, body2.offsetTop);
    }
    if (!inBody(element)) {
      return SugarPosition(0, 0);
    }
    return boxPosition(dom);
  };
  const rowInfo = (row2, y) => ({
    row: row2,
    y
  });
  const colInfo = (col2, x) => ({
    col: col2,
    x
  });
  const rtlEdge = (cell2) => {
    const pos = absolute(cell2);
    return pos.left + getOuter$2(cell2);
  };
  const ltrEdge = (cell2) => {
    return absolute(cell2).left;
  };
  const getLeftEdge = (index2, cell2) => {
    return colInfo(index2, ltrEdge(cell2));
  };
  const getRightEdge = (index2, cell2) => {
    return colInfo(index2, rtlEdge(cell2));
  };
  const getTop$1 = (cell2) => {
    return absolute(cell2).top;
  };
  const getTopEdge = (index2, cell2) => {
    return rowInfo(index2, getTop$1(cell2));
  };
  const getBottomEdge = (index2, cell2) => {
    return rowInfo(index2, getTop$1(cell2) + getOuter$1(cell2));
  };
  const findPositions = (getInnerEdge, getOuterEdge, array) => {
    if (array.length === 0) {
      return [];
    }
    const lines = map$1(array.slice(1), (cellOption, index2) => {
      return cellOption.map((cell2) => {
        return getInnerEdge(index2, cell2);
      });
    });
    const lastLine = array[array.length - 1].map((cell2) => {
      return getOuterEdge(array.length - 1, cell2);
    });
    return lines.concat([lastLine]);
  };
  const negate = (step) => {
    return -step;
  };
  const height = {
    delta: identity,
    positions: (optElements) => findPositions(getTopEdge, getBottomEdge, optElements),
    edge: getTop$1
  };
  const ltr$1 = {
    delta: identity,
    edge: ltrEdge,
    positions: (optElements) => findPositions(getLeftEdge, getRightEdge, optElements)
  };
  const rtl$1 = {
    delta: negate,
    edge: rtlEdge,
    positions: (optElements) => findPositions(getRightEdge, getLeftEdge, optElements)
  };
  const detect$1 = onDirection(ltr$1, rtl$1);
  const width = {
    delta: (amount, table2) => detect$1(table2).delta(amount, table2),
    positions: (cols, table2) => detect$1(table2).positions(cols, table2),
    edge: (cell2) => detect$1(cell2).edge(cell2)
  };
  const units = {
    unsupportedLength: [
      "em",
      "ex",
      "cap",
      "ch",
      "ic",
      "rem",
      "lh",
      "rlh",
      "vw",
      "vh",
      "vi",
      "vb",
      "vmin",
      "vmax",
      "cm",
      "mm",
      "Q",
      "in",
      "pc",
      "pt",
      "px"
    ],
    fixed: [
      "px",
      "pt"
    ],
    relative: ["%"],
    empty: [""]
  };
  const pattern = (() => {
    const decimalDigits = "[0-9]+";
    const signedInteger = "[+-]?" + decimalDigits;
    const exponentPart = "[eE]" + signedInteger;
    const dot = "\\.";
    const opt = (input) => `(?:${input})?`;
    const unsignedDecimalLiteral = [
      "Infinity",
      decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
      dot + decimalDigits + opt(exponentPart),
      decimalDigits + opt(exponentPart)
    ].join("|");
    const float = `[+-]?(?:${unsignedDecimalLiteral})`;
    return new RegExp(`^(${float})(.*)$`);
  })();
  const isUnit = (unit, accepted) => exists(accepted, (acc) => exists(units[acc], (check) => unit === check));
  const parse = (input, accepted) => {
    const match = Optional.from(pattern.exec(input));
    return match.bind((array) => {
      const value2 = Number(array[1]);
      const unitRaw = array[2];
      if (isUnit(unitRaw, accepted)) {
        return Optional.some({
          value: value2,
          unit: unitRaw
        });
      } else {
        return Optional.none();
      }
    });
  };
  const rPercentageBasedSizeRegex = /(\d+(\.\d+)?)%/;
  const rPixelBasedSizeRegex = /(\d+(\.\d+)?)px|em/;
  const isCol$2 = isTag("col");
  const getPercentSize = (elm, outerGetter, innerGetter) => {
    const relativeParent = parentElement(elm).getOrThunk(() => getBody$1(owner(elm)));
    return outerGetter(elm) / innerGetter(relativeParent) * 100;
  };
  const setPixelWidth = (cell2, amount) => {
    set$1(cell2, "width", amount + "px");
  };
  const setPercentageWidth = (cell2, amount) => {
    set$1(cell2, "width", amount + "%");
  };
  const setHeight = (cell2, amount) => {
    set$1(cell2, "height", amount + "px");
  };
  const getHeightValue = (cell2) => getRuntime(cell2) + "px";
  const convert = (cell2, number, getter, setter) => {
    const newSize = table(cell2).map((table2) => {
      const total2 = getter(table2);
      return Math.floor(number / 100 * total2);
    }).getOr(number);
    setter(cell2, newSize);
    return newSize;
  };
  const normalizePixelSize = (value2, cell2, getter, setter) => {
    const number = parseFloat(value2);
    return endsWith(value2, "%") && name(cell2) !== "table" ? convert(cell2, number, getter, setter) : number;
  };
  const getTotalHeight = (cell2) => {
    const value2 = getHeightValue(cell2);
    if (!value2) {
      return get$8(cell2);
    }
    return normalizePixelSize(value2, cell2, get$8, setHeight);
  };
  const get$7 = (cell2, type2, f) => {
    const v = f(cell2);
    const span = getSpan(cell2, type2);
    return v / span;
  };
  const getRaw$1 = (element, prop) => {
    return getRaw$2(element, prop).orThunk(() => {
      return getOpt(element, prop).map((val) => val + "px");
    });
  };
  const getRawWidth$1 = (element) => getRaw$1(element, "width");
  const getRawHeight = (element) => getRaw$1(element, "height");
  const getPercentageWidth = (cell2) => getPercentSize(cell2, get$9, getInner);
  const getPixelWidth$1 = (cell2) => isCol$2(cell2) ? get$9(cell2) : getRuntime$1(cell2);
  const getHeight = (cell2) => {
    return get$7(cell2, "rowspan", getTotalHeight);
  };
  const getGenericWidth = (cell2) => {
    const width2 = getRawWidth$1(cell2);
    return width2.bind((w) => parse(w, [
      "fixed",
      "relative",
      "empty"
    ]));
  };
  const setGenericWidth = (cell2, amount, unit) => {
    set$1(cell2, "width", amount + unit);
  };
  const getPixelTableWidth = (table2) => get$9(table2) + "px";
  const getPercentTableWidth = (table2) => getPercentSize(table2, get$9, getInner) + "%";
  const isPercentSizing$1 = (table2) => getRawWidth$1(table2).exists((size) => rPercentageBasedSizeRegex.test(size));
  const isPixelSizing$1 = (table2) => getRawWidth$1(table2).exists((size) => rPixelBasedSizeRegex.test(size));
  const isNoneSizing$1 = (table2) => getRawWidth$1(table2).isNone();
  const percentageBasedSizeRegex = constant(rPercentageBasedSizeRegex);
  const isCol$1 = isTag("col");
  const getRawW = (cell2) => {
    return getRawWidth$1(cell2).getOrThunk(() => getPixelWidth$1(cell2) + "px");
  };
  const getRawH = (cell2) => {
    return getRawHeight(cell2).getOrThunk(() => getHeight(cell2) + "px");
  };
  const justCols = (warehouse) => map$1(Warehouse.justColumns(warehouse), (column) => Optional.from(column.element));
  const isValidColumn = (cell2) => {
    const browser = detect$2().browser;
    const supportsColWidths = browser.isChromium() || browser.isFirefox();
    return isCol$1(cell2) ? supportsColWidths : true;
  };
  const getDimension = (cellOpt, index2, backups, filter2, getter, fallback2) => cellOpt.filter(filter2).fold(() => fallback2(deduce(backups, index2)), (cell2) => getter(cell2));
  const getWidthFrom = (warehouse, table2, getWidth2, fallback2) => {
    const columnCells = columns(warehouse);
    const columns$12 = Warehouse.hasColumns(warehouse) ? justCols(warehouse) : columnCells;
    const backups = [Optional.some(width.edge(table2))].concat(map$1(width.positions(columnCells, table2), (pos) => pos.map((p) => p.x)));
    const colFilter = not(hasColspan);
    return map$1(columns$12, (cellOption, c) => {
      return getDimension(cellOption, c, backups, colFilter, (column) => {
        if (isValidColumn(column)) {
          return getWidth2(column);
        } else {
          const cell2 = bindFrom(columnCells[c], identity);
          return getDimension(cell2, c, backups, colFilter, (cell3) => fallback2(Optional.some(get$9(cell3))), fallback2);
        }
      }, fallback2);
    });
  };
  const getDeduced = (deduced) => {
    return deduced.map((d) => {
      return d + "px";
    }).getOr("");
  };
  const getRawWidths = (warehouse, table2) => {
    return getWidthFrom(warehouse, table2, getRawW, getDeduced);
  };
  const getPercentageWidths = (warehouse, table2, tableSize) => {
    return getWidthFrom(warehouse, table2, getPercentageWidth, (deduced) => {
      return deduced.fold(() => {
        return tableSize.minCellWidth();
      }, (cellWidth) => {
        return cellWidth / tableSize.pixelWidth() * 100;
      });
    });
  };
  const getPixelWidths = (warehouse, table2, tableSize) => {
    return getWidthFrom(warehouse, table2, getPixelWidth$1, (deduced) => {
      return deduced.getOrThunk(tableSize.minCellWidth);
    });
  };
  const getHeightFrom = (warehouse, table2, direction, getHeight2, fallback2) => {
    const rows$12 = rows(warehouse);
    const backups = [Optional.some(direction.edge(table2))].concat(map$1(direction.positions(rows$12, table2), (pos) => pos.map((p) => p.y)));
    return map$1(rows$12, (cellOption, c) => {
      return getDimension(cellOption, c, backups, not(hasRowspan), getHeight2, fallback2);
    });
  };
  const getPixelHeights = (warehouse, table2, direction) => {
    return getHeightFrom(warehouse, table2, direction, getHeight, (deduced) => {
      return deduced.getOrThunk(minHeight);
    });
  };
  const getRawHeights = (warehouse, table2, direction) => {
    return getHeightFrom(warehouse, table2, direction, getRawH, getDeduced);
  };
  const widthLookup = (table2, getter) => () => {
    if (inBody(table2)) {
      return getter(table2);
    } else {
      return parseFloat(getRaw$2(table2, "width").getOr("0"));
    }
  };
  const noneSize = (table2) => {
    const getWidth2 = widthLookup(table2, get$9);
    const zero2 = constant(0);
    const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table2, tableSize);
    return {
      width: getWidth2,
      pixelWidth: getWidth2,
      getWidths,
      getCellDelta: zero2,
      singleColumnWidth: constant([0]),
      minCellWidth: zero2,
      setElementWidth: noop,
      adjustTableWidth: noop,
      isRelative: true,
      label: "none"
    };
  };
  const percentageSize = (table2) => {
    const getFloatWidth = widthLookup(table2, (elem) => parseFloat(getPercentTableWidth(elem)));
    const getWidth2 = widthLookup(table2, get$9);
    const getCellDelta = (delta) => delta / getWidth2() * 100;
    const singleColumnWidth = (w, _delta) => [100 - w];
    const minCellWidth = () => minWidth() / getWidth2() * 100;
    const adjustTableWidth = (delta) => {
      const currentWidth = getFloatWidth();
      const change = delta / 100 * currentWidth;
      const newWidth = currentWidth + change;
      setPercentageWidth(table2, newWidth);
    };
    const getWidths = (warehouse, tableSize) => getPercentageWidths(warehouse, table2, tableSize);
    return {
      width: getFloatWidth,
      pixelWidth: getWidth2,
      getWidths,
      getCellDelta,
      singleColumnWidth,
      minCellWidth,
      setElementWidth: setPercentageWidth,
      adjustTableWidth,
      isRelative: true,
      label: "percent"
    };
  };
  const pixelSize = (table2) => {
    const getWidth2 = widthLookup(table2, get$9);
    const getCellDelta = identity;
    const singleColumnWidth = (w, delta) => {
      const newNext = Math.max(minWidth(), w + delta);
      return [newNext - w];
    };
    const adjustTableWidth = (delta) => {
      const newWidth = getWidth2() + delta;
      setPixelWidth(table2, newWidth);
    };
    const getWidths = (warehouse, tableSize) => getPixelWidths(warehouse, table2, tableSize);
    return {
      width: getWidth2,
      pixelWidth: getWidth2,
      getWidths,
      getCellDelta,
      singleColumnWidth,
      minCellWidth: minWidth,
      setElementWidth: setPixelWidth,
      adjustTableWidth,
      isRelative: false,
      label: "pixel"
    };
  };
  const chooseSize = (element, width2) => {
    const percentMatch = percentageBasedSizeRegex().exec(width2);
    if (percentMatch !== null) {
      return percentageSize(element);
    } else {
      return pixelSize(element);
    }
  };
  const getTableSize = (table2) => {
    const width2 = getRawWidth$1(table2);
    return width2.fold(() => noneSize(table2), (w) => chooseSize(table2, w));
  };
  const TableSize = {
    getTableSize,
    pixelSize,
    percentageSize,
    noneSize
  };
  const statsStruct = (minRow, minCol, maxRow, maxCol, allCells, selectedCells) => ({
    minRow,
    minCol,
    maxRow,
    maxCol,
    allCells,
    selectedCells
  });
  const findSelectedStats = (house, isSelected) => {
    const totalColumns = house.grid.columns;
    const totalRows = house.grid.rows;
    let minRow = totalRows;
    let minCol = totalColumns;
    let maxRow = 0;
    let maxCol = 0;
    const allCells = [];
    const selectedCells = [];
    each$1(house.access, (detail2) => {
      allCells.push(detail2);
      if (isSelected(detail2)) {
        selectedCells.push(detail2);
        const startRow = detail2.row;
        const endRow = startRow + detail2.rowspan - 1;
        const startCol = detail2.column;
        const endCol = startCol + detail2.colspan - 1;
        if (startRow < minRow) {
          minRow = startRow;
        } else if (endRow > maxRow) {
          maxRow = endRow;
        }
        if (startCol < minCol) {
          minCol = startCol;
        } else if (endCol > maxCol) {
          maxCol = endCol;
        }
      }
    });
    return statsStruct(minRow, minCol, maxRow, maxCol, allCells, selectedCells);
  };
  const makeCell = (list, seenSelected, rowIndex) => {
    const row2 = list[rowIndex].element;
    const td = SugarElement.fromTag("td");
    append$1(td, SugarElement.fromTag("br"));
    const f = seenSelected ? append$1 : prepend;
    f(row2, td);
  };
  const fillInGaps = (list, house, stats, isSelected) => {
    const rows2 = filter$2(list, (row2) => row2.section !== "colgroup");
    const totalColumns = house.grid.columns;
    const totalRows = house.grid.rows;
    for (let i = 0; i < totalRows; i++) {
      let seenSelected = false;
      for (let j = 0; j < totalColumns; j++) {
        if (!(i < stats.minRow || i > stats.maxRow || j < stats.minCol || j > stats.maxCol)) {
          const needCell = Warehouse.getAt(house, i, j).filter(isSelected).isNone();
          if (needCell) {
            makeCell(rows2, seenSelected, i);
          } else {
            seenSelected = true;
          }
        }
      }
    }
  };
  const clean = (replica, stats, house, widthDelta) => {
    each$1(house.columns, (col2) => {
      if (col2.column < stats.minCol || col2.column > stats.maxCol) {
        remove$6(col2.element);
      }
    });
    const emptyRows = filter$2(firstLayer(replica, "tr"), (row2) => row2.dom.childElementCount === 0);
    each$2(emptyRows, remove$6);
    if (stats.minCol === stats.maxCol || stats.minRow === stats.maxRow) {
      each$2(firstLayer(replica, "th,td"), (cell2) => {
        remove$7(cell2, "rowspan");
        remove$7(cell2, "colspan");
      });
    }
    remove$7(replica, LOCKED_COL_ATTR);
    remove$7(replica, "data-snooker-col-series");
    const tableSize = TableSize.getTableSize(replica);
    tableSize.adjustTableWidth(widthDelta);
  };
  const getTableWidthDelta = (table2, warehouse, tableSize, stats) => {
    if (stats.minCol === 0 && warehouse.grid.columns === stats.maxCol + 1) {
      return 0;
    }
    const colWidths = getPixelWidths(warehouse, table2, tableSize);
    const allColsWidth = foldl(colWidths, (acc, width2) => acc + width2, 0);
    const selectedColsWidth = foldl(colWidths.slice(stats.minCol, stats.maxCol + 1), (acc, width2) => acc + width2, 0);
    const newWidth = selectedColsWidth / allColsWidth * tableSize.pixelWidth();
    const delta = newWidth - tableSize.pixelWidth();
    return tableSize.getCellDelta(delta);
  };
  const extract$1 = (table2, selectedSelector) => {
    const isSelected = (detail2) => is$2(detail2.element, selectedSelector);
    const replica = deep(table2);
    const list = fromTable$1(replica);
    const tableSize = TableSize.getTableSize(table2);
    const replicaHouse = Warehouse.generate(list);
    const replicaStats = findSelectedStats(replicaHouse, isSelected);
    const selector = "th:not(" + selectedSelector + "),td:not(" + selectedSelector + ")";
    const unselectedCells = filterFirstLayer(replica, "th,td", (cell2) => is$2(cell2, selector));
    each$2(unselectedCells, remove$6);
    fillInGaps(list, replicaHouse, replicaStats, isSelected);
    const house = Warehouse.fromTable(table2);
    const widthDelta = getTableWidthDelta(table2, house, tableSize, replicaStats);
    clean(replica, replicaStats, replicaHouse, widthDelta);
    return replica;
  };
  const nbsp = "\xA0";
  const NodeValue = (is2, name2) => {
    const get2 = (element) => {
      if (!is2(element)) {
        throw new Error("Can only get " + name2 + " value of a " + name2 + " node");
      }
      return getOption2(element).getOr("");
    };
    const getOption2 = (element) => is2(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
    const set2 = (element, value2) => {
      if (!is2(element)) {
        throw new Error("Can only set raw " + name2 + " value of a " + name2 + " node");
      }
      element.dom.nodeValue = value2;
    };
    return {
      get: get2,
      getOption: getOption2,
      set: set2
    };
  };
  const api = NodeValue(isText, "text");
  const get$6 = (element) => api.get(element);
  const getOption = (element) => api.getOption(element);
  const set = (element, value2) => api.set(element, value2);
  const getEnd = (element) => name(element) === "img" ? 1 : getOption(element).fold(() => children$2(element).length, (v) => v.length);
  const isTextNodeWithCursorPosition = (el) => getOption(el).filter((text) => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
  const elementsWithCursorPosition = [
    "img",
    "br"
  ];
  const isCursorPosition = (elem) => {
    const hasCursorPosition = isTextNodeWithCursorPosition(elem);
    return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem));
  };
  const first = (element) => descendant$1(element, isCursorPosition);
  const last$1 = (element) => descendantRtl(element, isCursorPosition);
  const descendantRtl = (scope, predicate) => {
    const descend = (element) => {
      const children2 = children$2(element);
      for (let i = children2.length - 1; i >= 0; i--) {
        const child2 = children2[i];
        if (predicate(child2)) {
          return Optional.some(child2);
        }
        const res = descend(child2);
        if (res.isSome()) {
          return res;
        }
      }
      return Optional.none();
    };
    return descend(scope);
  };
  const transferableAttributes = {
    scope: [
      "row",
      "col"
    ]
  };
  const createCell = (doc) => () => {
    const td = SugarElement.fromTag("td", doc.dom);
    append$1(td, SugarElement.fromTag("br", doc.dom));
    return td;
  };
  const createCol = (doc) => () => {
    return SugarElement.fromTag("col", doc.dom);
  };
  const createColgroup = (doc) => () => {
    return SugarElement.fromTag("colgroup", doc.dom);
  };
  const createRow$1 = (doc) => () => {
    return SugarElement.fromTag("tr", doc.dom);
  };
  const replace$1 = (cell2, tag, attrs) => {
    const replica = copy$2(cell2, tag);
    each$1(attrs, (v, k) => {
      if (v === null) {
        remove$7(replica, k);
      } else {
        set$2(replica, k, v);
      }
    });
    return replica;
  };
  const pasteReplace = (cell2) => {
    return cell2;
  };
  const cloneFormats = (oldCell, newCell, formats) => {
    const first$1 = first(oldCell);
    return first$1.map((firstText) => {
      const formatSelector = formats.join(",");
      const parents2 = ancestors$3(firstText, formatSelector, (element) => {
        return eq$1(element, oldCell);
      });
      return foldr(parents2, (last2, parent2) => {
        const clonedFormat = shallow(parent2);
        remove$7(clonedFormat, "contenteditable");
        append$1(last2, clonedFormat);
        return clonedFormat;
      }, newCell);
    }).getOr(newCell);
  };
  const cloneAppropriateAttributes = (original, clone2) => {
    each$1(transferableAttributes, (validAttributes, attributeName) => getOpt(original, attributeName).filter((attribute) => contains$2(validAttributes, attribute)).each((attribute) => set$2(clone2, attributeName, attribute)));
  };
  const cellOperations = (mutate2, doc, formatsToClone) => {
    const cloneCss = (prev, clone2) => {
      copy$1(prev.element, clone2);
      remove$5(clone2, "height");
      if (prev.colspan !== 1) {
        remove$5(clone2, "width");
      }
    };
    const newCell = (prev) => {
      const td = SugarElement.fromTag(name(prev.element), doc.dom);
      const formats = formatsToClone.getOr([
        "strong",
        "em",
        "b",
        "i",
        "span",
        "font",
        "h1",
        "h2",
        "h3",
        "h4",
        "h5",
        "h6",
        "p",
        "div"
      ]);
      const lastNode = formats.length > 0 ? cloneFormats(prev.element, td, formats) : td;
      append$1(lastNode, SugarElement.fromTag("br"));
      cloneCss(prev, td);
      cloneAppropriateAttributes(prev.element, td);
      mutate2(prev.element, td);
      return td;
    };
    const newCol = (prev) => {
      const col2 = SugarElement.fromTag(name(prev.element), doc.dom);
      cloneCss(prev, col2);
      mutate2(prev.element, col2);
      return col2;
    };
    return {
      col: newCol,
      colgroup: createColgroup(doc),
      row: createRow$1(doc),
      cell: newCell,
      replace: replace$1,
      colGap: createCol(doc),
      gap: createCell(doc)
    };
  };
  const paste$1 = (doc) => {
    return {
      col: createCol(doc),
      colgroup: createColgroup(doc),
      row: createRow$1(doc),
      cell: createCell(doc),
      replace: pasteReplace,
      colGap: createCol(doc),
      gap: createCell(doc)
    };
  };
  const fromHtml = (html, scope) => {
    const doc = scope || document;
    const div = doc.createElement("div");
    div.innerHTML = html;
    return children$2(SugarElement.fromDom(div));
  };
  const fromDom = (nodes) => map$1(nodes, SugarElement.fromDom);
  const getBody = (editor) => SugarElement.fromDom(editor.getBody());
  const getIsRoot = (editor) => (element) => eq$1(element, getBody(editor));
  const removeDataStyle = (table2) => {
    remove$7(table2, "data-mce-style");
    const removeStyleAttribute = (element) => remove$7(element, "data-mce-style");
    each$2(cells$1(table2), removeStyleAttribute);
    each$2(columns$1(table2), removeStyleAttribute);
    each$2(rows$1(table2), removeStyleAttribute);
  };
  const getSelectionStart = (editor) => SugarElement.fromDom(editor.selection.getStart());
  const getPixelWidth = (elm) => elm.getBoundingClientRect().width;
  const getPixelHeight = (elm) => elm.getBoundingClientRect().height;
  const getRawWidth = (editor, elm) => {
    const raw = editor.dom.getStyle(elm, "width") || editor.dom.getAttrib(elm, "width");
    return Optional.from(raw).filter(isNotEmpty);
  };
  const isPercentage$1 = (value2) => /^(\d+(\.\d+)?)%$/.test(value2);
  const isPixel = (value2) => /^(\d+(\.\d+)?)px$/.test(value2);
  const inSelection = (bounds2, detail2) => {
    const leftEdge = detail2.column;
    const rightEdge = detail2.column + detail2.colspan - 1;
    const topEdge = detail2.row;
    const bottomEdge = detail2.row + detail2.rowspan - 1;
    return leftEdge <= bounds2.finishCol && rightEdge >= bounds2.startCol && (topEdge <= bounds2.finishRow && bottomEdge >= bounds2.startRow);
  };
  const isWithin = (bounds2, detail2) => {
    return detail2.column >= bounds2.startCol && detail2.column + detail2.colspan - 1 <= bounds2.finishCol && detail2.row >= bounds2.startRow && detail2.row + detail2.rowspan - 1 <= bounds2.finishRow;
  };
  const isRectangular = (warehouse, bounds2) => {
    let isRect = true;
    const detailIsWithin = curry(isWithin, bounds2);
    for (let i = bounds2.startRow; i <= bounds2.finishRow; i++) {
      for (let j = bounds2.startCol; j <= bounds2.finishCol; j++) {
        isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin);
      }
    }
    return isRect ? Optional.some(bounds2) : Optional.none();
  };
  const getBounds = (detailA, detailB) => {
    return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1));
  };
  const getAnyBox = (warehouse, startCell, finishCell) => {
    const startCoords = Warehouse.findItem(warehouse, startCell, eq$1);
    const finishCoords = Warehouse.findItem(warehouse, finishCell, eq$1);
    return startCoords.bind((sc) => {
      return finishCoords.map((fc) => {
        return getBounds(sc, fc);
      });
    });
  };
  const getBox$1 = (warehouse, startCell, finishCell) => {
    return getAnyBox(warehouse, startCell, finishCell).bind((bounds2) => {
      return isRectangular(warehouse, bounds2);
    });
  };
  const moveBy$1 = (warehouse, cell2, row2, column) => {
    return Warehouse.findItem(warehouse, cell2, eq$1).bind((detail2) => {
      const startRow = row2 > 0 ? detail2.row + detail2.rowspan - 1 : detail2.row;
      const startCol = column > 0 ? detail2.column + detail2.colspan - 1 : detail2.column;
      const dest = Warehouse.getAt(warehouse, startRow + row2, startCol + column);
      return dest.map((d) => {
        return d.element;
      });
    });
  };
  const intercepts$1 = (warehouse, start, finish) => {
    return getAnyBox(warehouse, start, finish).map((bounds2) => {
      const inside = Warehouse.filterItems(warehouse, curry(inSelection, bounds2));
      return map$1(inside, (detail2) => {
        return detail2.element;
      });
    });
  };
  const parentCell = (warehouse, innerCell) => {
    const isContainedBy = (c1, c2) => {
      return contains$1(c2, c1);
    };
    return Warehouse.findItem(warehouse, innerCell, isContainedBy).map((detail2) => {
      return detail2.element;
    });
  };
  const moveBy = (cell2, deltaRow, deltaColumn) => {
    return table(cell2).bind((table2) => {
      const warehouse = getWarehouse(table2);
      return moveBy$1(warehouse, cell2, deltaRow, deltaColumn);
    });
  };
  const intercepts = (table2, first2, last2) => {
    const warehouse = getWarehouse(table2);
    return intercepts$1(warehouse, first2, last2);
  };
  const nestedIntercepts = (table2, first2, firstTable, last2, lastTable) => {
    const warehouse = getWarehouse(table2);
    const optStartCell = eq$1(table2, firstTable) ? Optional.some(first2) : parentCell(warehouse, first2);
    const optLastCell = eq$1(table2, lastTable) ? Optional.some(last2) : parentCell(warehouse, last2);
    return optStartCell.bind((startCell) => optLastCell.bind((lastCell) => intercepts$1(warehouse, startCell, lastCell)));
  };
  const getBox = (table2, first2, last2) => {
    const warehouse = getWarehouse(table2);
    return getBox$1(warehouse, first2, last2);
  };
  const getWarehouse = Warehouse.fromTable;
  var TagBoundaries = [
    "body",
    "p",
    "div",
    "article",
    "aside",
    "figcaption",
    "figure",
    "footer",
    "header",
    "nav",
    "section",
    "ol",
    "ul",
    "li",
    "table",
    "thead",
    "tbody",
    "tfoot",
    "caption",
    "tr",
    "td",
    "th",
    "h1",
    "h2",
    "h3",
    "h4",
    "h5",
    "h6",
    "blockquote",
    "pre",
    "address"
  ];
  var DomUniverse = () => {
    const clone2 = (element) => {
      return SugarElement.fromDom(element.dom.cloneNode(false));
    };
    const document2 = (element) => documentOrOwner(element).dom;
    const isBoundary = (element) => {
      if (!isElement(element)) {
        return false;
      }
      if (name(element) === "body") {
        return true;
      }
      return contains$2(TagBoundaries, name(element));
    };
    const isEmptyTag2 = (element) => {
      if (!isElement(element)) {
        return false;
      }
      return contains$2([
        "br",
        "img",
        "hr",
        "input"
      ], name(element));
    };
    const isNonEditable = (element) => isElement(element) && get$b(element, "contenteditable") === "false";
    const comparePosition = (element, other) => {
      return element.dom.compareDocumentPosition(other.dom);
    };
    const copyAttributesTo = (source, destination) => {
      const as = clone$2(source);
      setAll$1(destination, as);
    };
    const isSpecial = (element) => {
      const tag = name(element);
      return contains$2([
        "script",
        "noscript",
        "iframe",
        "noframes",
        "noembed",
        "title",
        "style",
        "textarea",
        "xmp"
      ], tag);
    };
    const getLanguage = (element) => isElement(element) ? getOpt(element, "lang") : Optional.none();
    return {
      up: constant({
        selector: ancestor$1,
        closest: closest$1,
        predicate: ancestor$2,
        all: parents
      }),
      down: constant({
        selector: descendants,
        predicate: descendants$1
      }),
      styles: constant({
        get: get$a,
        getRaw: getRaw$2,
        set: set$1,
        remove: remove$5
      }),
      attrs: constant({
        get: get$b,
        set: set$2,
        remove: remove$7,
        copyTo: copyAttributesTo
      }),
      insert: constant({
        before: before$3,
        after: after$5,
        afterAll: after$4,
        append: append$1,
        appendAll: append,
        prepend,
        wrap
      }),
      remove: constant({
        unwrap,
        remove: remove$6
      }),
      create: constant({
        nu: SugarElement.fromTag,
        clone: clone2,
        text: SugarElement.fromText
      }),
      query: constant({
        comparePosition,
        prevSibling,
        nextSibling
      }),
      property: constant({
        children: children$2,
        name,
        parent,
        document: document2,
        isText,
        isComment,
        isElement,
        isSpecial,
        getLanguage,
        getText: get$6,
        setText: set,
        isBoundary,
        isEmptyTag: isEmptyTag2,
        isNonEditable
      }),
      eq: eq$1,
      is: is$1
    };
  };
  const all = (universe2, look, elements, f) => {
    const head2 = elements[0];
    const tail = elements.slice(1);
    return f(universe2, look, head2, tail);
  };
  const oneAll = (universe2, look, elements) => {
    return elements.length > 0 ? all(universe2, look, elements, unsafeOne) : Optional.none();
  };
  const unsafeOne = (universe2, look, head2, tail) => {
    const start = look(universe2, head2);
    return foldr(tail, (b, a) => {
      const current = look(universe2, a);
      return commonElement(universe2, b, current);
    }, start);
  };
  const commonElement = (universe2, start, end) => {
    return start.bind((s) => {
      return end.filter(curry(universe2.eq, s));
    });
  };
  const eq = (universe2, item) => {
    return curry(universe2.eq, item);
  };
  const ancestors$2 = (universe2, start, end, isRoot = never) => {
    const ps1 = [start].concat(universe2.up().all(start));
    const ps2 = [end].concat(universe2.up().all(end));
    const prune2 = (path) => {
      const index2 = findIndex(path, isRoot);
      return index2.fold(() => {
        return path;
      }, (ind) => {
        return path.slice(0, ind + 1);
      });
    };
    const pruned1 = prune2(ps1);
    const pruned2 = prune2(ps2);
    const shared = find$1(pruned1, (x) => {
      return exists(pruned2, eq(universe2, x));
    });
    return {
      firstpath: pruned1,
      secondpath: pruned2,
      shared
    };
  };
  const sharedOne$1 = oneAll;
  const ancestors$1 = ancestors$2;
  const universe$3 = DomUniverse();
  const sharedOne = (look, elements) => {
    return sharedOne$1(universe$3, (_universe, element) => {
      return look(element);
    }, elements);
  };
  const ancestors = (start, finish, isRoot) => {
    return ancestors$1(universe$3, start, finish, isRoot);
  };
  const lookupTable = (container) => {
    return ancestor$1(container, "table");
  };
  const identify = (start, finish, isRoot) => {
    const getIsRoot2 = (rootTable) => {
      return (element) => {
        return isRoot !== void 0 && isRoot(element) || eq$1(element, rootTable);
      };
    };
    if (eq$1(start, finish)) {
      return Optional.some({
        boxes: Optional.some([start]),
        start,
        finish
      });
    } else {
      return lookupTable(start).bind((startTable) => {
        return lookupTable(finish).bind((finishTable) => {
          if (eq$1(startTable, finishTable)) {
            return Optional.some({
              boxes: intercepts(startTable, start, finish),
              start,
              finish
            });
          } else if (contains$1(startTable, finishTable)) {
            const ancestorCells = ancestors$3(finish, "td,th", getIsRoot2(startTable));
            const finishCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : finish;
            return Optional.some({
              boxes: nestedIntercepts(startTable, start, startTable, finish, finishTable),
              start,
              finish: finishCell
            });
          } else if (contains$1(finishTable, startTable)) {
            const ancestorCells = ancestors$3(start, "td,th", getIsRoot2(finishTable));
            const startCell = ancestorCells.length > 0 ? ancestorCells[ancestorCells.length - 1] : start;
            return Optional.some({
              boxes: nestedIntercepts(finishTable, start, startTable, finish, finishTable),
              start,
              finish: startCell
            });
          } else {
            return ancestors(start, finish).shared.bind((lca) => {
              return closest$1(lca, "table", isRoot).bind((lcaTable) => {
                const finishAncestorCells = ancestors$3(finish, "td,th", getIsRoot2(lcaTable));
                const finishCell = finishAncestorCells.length > 0 ? finishAncestorCells[finishAncestorCells.length - 1] : finish;
                const startAncestorCells = ancestors$3(start, "td,th", getIsRoot2(lcaTable));
                const startCell = startAncestorCells.length > 0 ? startAncestorCells[startAncestorCells.length - 1] : start;
                return Optional.some({
                  boxes: nestedIntercepts(lcaTable, start, startTable, finish, finishTable),
                  start: startCell,
                  finish: finishCell
                });
              });
            });
          }
        });
      });
    }
  };
  const retrieve$1 = (container, selector) => {
    const sels = descendants(container, selector);
    return sels.length > 0 ? Optional.some(sels) : Optional.none();
  };
  const getLast = (boxes, lastSelectedSelector) => {
    return find$1(boxes, (box) => {
      return is$2(box, lastSelectedSelector);
    });
  };
  const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => {
    return descendant(container, firstSelectedSelector).bind((first2) => {
      return descendant(container, lastSelectedSelector).bind((last2) => {
        return sharedOne(lookupTable, [
          first2,
          last2
        ]).map((table2) => {
          return {
            first: first2,
            last: last2,
            table: table2
          };
        });
      });
    });
  };
  const expandTo = (finish, firstSelectedSelector) => {
    return ancestor$1(finish, "table").bind((table2) => {
      return descendant(table2, firstSelectedSelector).bind((start) => {
        return identify(start, finish).bind((identified) => {
          return identified.boxes.map((boxes) => {
            return {
              boxes,
              start: identified.start,
              finish: identified.finish
            };
          });
        });
      });
    });
  };
  const shiftSelection = (boxes, deltaRow, deltaColumn, firstSelectedSelector, lastSelectedSelector) => {
    return getLast(boxes, lastSelectedSelector).bind((last2) => {
      return moveBy(last2, deltaRow, deltaColumn).bind((finish) => {
        return expandTo(finish, firstSelectedSelector);
      });
    });
  };
  const retrieve = (container, selector) => {
    return retrieve$1(container, selector);
  };
  const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => {
    return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind((edges) => {
      const isRoot = (ancestor2) => {
        return eq$1(container, ancestor2);
      };
      const sectionSelector = "thead,tfoot,tbody,table";
      const firstAncestor = ancestor$1(edges.first, sectionSelector, isRoot);
      const lastAncestor = ancestor$1(edges.last, sectionSelector, isRoot);
      return firstAncestor.bind((fA) => {
        return lastAncestor.bind((lA) => {
          return eq$1(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none();
        });
      });
    });
  };
  const selection = identity;
  const unmergable = (selectedCells) => {
    const hasSpan = (elem, type2) => getOpt(elem, type2).exists((span) => parseInt(span, 10) > 1);
    const hasRowOrColSpan = (elem) => hasSpan(elem, "rowspan") || hasSpan(elem, "colspan");
    return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none();
  };
  const mergable = (table2, selectedCells, ephemera2) => {
    if (selectedCells.length <= 1) {
      return Optional.none();
    } else {
      return retrieveBox(table2, ephemera2.firstSelectedSelector, ephemera2.lastSelectedSelector).map((bounds2) => ({
        bounds: bounds2,
        cells: selectedCells
      }));
    }
  };
  const strSelected = "data-mce-selected";
  const strSelectedSelector = "td[" + strSelected + "],th[" + strSelected + "]";
  const strAttributeSelector = "[" + strSelected + "]";
  const strFirstSelected = "data-mce-first-selected";
  const strFirstSelectedSelector = "td[" + strFirstSelected + "],th[" + strFirstSelected + "]";
  const strLastSelected = "data-mce-last-selected";
  const strLastSelectedSelector = "td[" + strLastSelected + "],th[" + strLastSelected + "]";
  const attributeSelector = strAttributeSelector;
  const ephemera = {
    selected: strSelected,
    selectedSelector: strSelectedSelector,
    firstSelected: strFirstSelected,
    firstSelectedSelector: strFirstSelectedSelector,
    lastSelected: strLastSelected,
    lastSelectedSelector: strLastSelectedSelector
  };
  const forMenu = (selectedCells, table2, cell2) => ({
    element: cell2,
    mergable: mergable(table2, selectedCells, ephemera),
    unmergable: unmergable(selectedCells),
    selection: selection(selectedCells)
  });
  const paste = (element, clipboard, generators) => ({
    element,
    clipboard,
    generators
  });
  const pasteRows = (selectedCells, _cell, clipboard, generators) => ({
    selection: selection(selectedCells),
    clipboard,
    generators
  });
  const getSelectionCellFallback = (element) => table(element).bind((table2) => retrieve(table2, ephemera.firstSelectedSelector)).fold(constant(element), (cells2) => cells2[0]);
  const getSelectionFromSelector = (selector) => (initCell, isRoot) => {
    const cellName = name(initCell);
    const cell2 = cellName === "col" || cellName === "colgroup" ? getSelectionCellFallback(initCell) : initCell;
    return closest$1(cell2, selector, isRoot);
  };
  const getSelectionCellOrCaption = getSelectionFromSelector("th,td,caption");
  const getSelectionCell = getSelectionFromSelector("th,td");
  const getCellsFromSelection = (editor) => fromDom(editor.model.table.getSelectedCells());
  const getCellsFromFakeSelection = (editor) => filter$2(getCellsFromSelection(editor), (cell2) => is$2(cell2, ephemera.selectedSelector));
  const extractSelected = (cells2) => {
    return table(cells2[0]).map((table2) => {
      const replica = extract$1(table2, attributeSelector);
      removeDataStyle(replica);
      return [replica];
    });
  };
  const serializeElements = (editor, elements) => map$1(elements, (elm) => editor.selection.serializer.serialize(elm.dom, {})).join("");
  const getTextContent = (elements) => map$1(elements, (element) => element.dom.innerText).join("");
  const registerEvents = (editor, actions) => {
    editor.on("BeforeGetContent", (e) => {
      const multiCellContext = (cells2) => {
        e.preventDefault();
        extractSelected(cells2).each((elements) => {
          e.content = e.format === "text" ? getTextContent(elements) : serializeElements(editor, elements);
        });
      };
      if (e.selection === true) {
        const cells2 = getCellsFromFakeSelection(editor);
        if (cells2.length >= 1) {
          multiCellContext(cells2);
        }
      }
    });
    editor.on("BeforeSetContent", (e) => {
      if (e.selection === true && e.paste === true) {
        const selectedCells = getCellsFromSelection(editor);
        head(selectedCells).each((cell2) => {
          table(cell2).each((table2) => {
            const elements = filter$2(fromHtml(e.content), (content) => {
              return name(content) !== "meta";
            });
            const isTable2 = isTag("table");
            if (elements.length === 1 && isTable2(elements[0])) {
              e.preventDefault();
              const doc = SugarElement.fromDom(editor.getDoc());
              const generators = paste$1(doc);
              const targets = paste(cell2, elements[0], generators);
              actions.pasteCells(table2, targets).each(() => {
                editor.focus();
              });
            }
          });
        });
      }
    });
  };
  const point = (element, offset) => ({
    element,
    offset
  });
  const scan$1 = (universe2, element, direction) => {
    if (universe2.property().isText(element) && universe2.property().getText(element).trim().length === 0 || universe2.property().isComment(element)) {
      return direction(element).bind((elem) => {
        return scan$1(universe2, elem, direction).orThunk(() => {
          return Optional.some(elem);
        });
      });
    } else {
      return Optional.none();
    }
  };
  const toEnd = (universe2, element) => {
    if (universe2.property().isText(element)) {
      return universe2.property().getText(element).length;
    }
    const children2 = universe2.property().children(element);
    return children2.length;
  };
  const freefallRtl$2 = (universe2, element) => {
    const candidate = scan$1(universe2, element, universe2.query().prevSibling).getOr(element);
    if (universe2.property().isText(candidate)) {
      return point(candidate, toEnd(universe2, candidate));
    }
    const children2 = universe2.property().children(candidate);
    return children2.length > 0 ? freefallRtl$2(universe2, children2[children2.length - 1]) : point(candidate, toEnd(universe2, candidate));
  };
  const freefallRtl$1 = freefallRtl$2;
  const universe$2 = DomUniverse();
  const freefallRtl = (element) => {
    return freefallRtl$1(universe$2, element);
  };
  const halve = (main, other) => {
    if (!hasColspan(main)) {
      const width2 = getGenericWidth(main);
      width2.each((w) => {
        const newWidth = w.value / 2;
        setGenericWidth(main, newWidth, w.unit);
        setGenericWidth(other, newWidth, w.unit);
      });
    }
  };
  const zero = (array) => map$1(array, constant(0));
  const surround = (sizes, startIndex, endIndex, results, f) => f(sizes.slice(0, startIndex)).concat(results).concat(f(sizes.slice(endIndex)));
  const clampDeltaHelper = (predicate) => (sizes, index2, delta, minCellSize) => {
    if (!predicate(delta)) {
      return delta;
    } else {
      const newSize = Math.max(minCellSize, sizes[index2] - Math.abs(delta));
      const diff = Math.abs(newSize - sizes[index2]);
      return delta >= 0 ? diff : -diff;
    }
  };
  const clampNegativeDelta = clampDeltaHelper((delta) => delta < 0);
  const clampDelta = clampDeltaHelper(always);
  const resizeTable = () => {
    const calcFixedDeltas = (sizes, index2, next, delta, minCellSize) => {
      const clampedDelta = clampNegativeDelta(sizes, index2, delta, minCellSize);
      return surround(sizes, index2, next + 1, [
        clampedDelta,
        0
      ], zero);
    };
    const calcRelativeDeltas = (sizes, index2, delta, minCellSize) => {
      const ratio = (100 + delta) / 100;
      const newThis = Math.max(minCellSize, (sizes[index2] + delta) / ratio);
      return map$1(sizes, (size, idx) => {
        const newSize = idx === index2 ? newThis : size / ratio;
        return newSize - size;
      });
    };
    const calcLeftEdgeDeltas = (sizes, index2, next, delta, minCellSize, isRelative) => {
      if (isRelative) {
        return calcRelativeDeltas(sizes, index2, delta, minCellSize);
      } else {
        return calcFixedDeltas(sizes, index2, next, delta, minCellSize);
      }
    };
    const calcMiddleDeltas = (sizes, _prev, index2, next, delta, minCellSize, isRelative) => calcLeftEdgeDeltas(sizes, index2, next, delta, minCellSize, isRelative);
    const resizeTable2 = (resizer, delta) => resizer(delta);
    const calcRightEdgeDeltas = (sizes, _prev, index2, delta, minCellSize, isRelative) => {
      if (isRelative) {
        return calcRelativeDeltas(sizes, index2, delta, minCellSize);
      } else {
        const clampedDelta = clampNegativeDelta(sizes, index2, delta, minCellSize);
        return zero(sizes.slice(0, index2)).concat([clampedDelta]);
      }
    };
    const calcRedestributedWidths = (sizes, totalWidth, pixelDelta, isRelative) => {
      if (isRelative) {
        const tableWidth = totalWidth + pixelDelta;
        const ratio = tableWidth / totalWidth;
        const newSizes = map$1(sizes, (size) => size / ratio);
        return {
          delta: ratio * 100 - 100,
          newSizes
        };
      } else {
        return {
          delta: pixelDelta,
          newSizes: sizes
        };
      }
    };
    return {
      resizeTable: resizeTable2,
      clampTableDelta: clampNegativeDelta,
      calcLeftEdgeDeltas,
      calcMiddleDeltas,
      calcRightEdgeDeltas,
      calcRedestributedWidths
    };
  };
  const preserveTable = () => {
    const calcLeftEdgeDeltas = (sizes, index2, next, delta, minCellSize) => {
      const idx = delta >= 0 ? next : index2;
      const clampedDelta = clampDelta(sizes, idx, delta, minCellSize);
      return surround(sizes, index2, next + 1, [
        clampedDelta,
        -clampedDelta
      ], zero);
    };
    const calcMiddleDeltas = (sizes, _prev, index2, next, delta, minCellSize) => calcLeftEdgeDeltas(sizes, index2, next, delta, minCellSize);
    const resizeTable2 = (resizer, delta, isLastColumn) => {
      if (isLastColumn) {
        resizer(delta);
      }
    };
    const calcRightEdgeDeltas = (sizes, _prev, _index, delta, _minCellSize, isRelative) => {
      if (isRelative) {
        return zero(sizes);
      } else {
        const diff = delta / sizes.length;
        return map$1(sizes, constant(diff));
      }
    };
    const clampTableDelta = (sizes, index2, delta, minCellSize, isLastColumn) => {
      if (isLastColumn) {
        if (delta >= 0) {
          return delta;
        } else {
          const maxDelta = foldl(sizes, (a, b) => a + b - minCellSize, 0);
          return Math.max(-maxDelta, delta);
        }
      } else {
        return clampNegativeDelta(sizes, index2, delta, minCellSize);
      }
    };
    const calcRedestributedWidths = (sizes, _totalWidth, _pixelDelta, _isRelative) => ({
      delta: 0,
      newSizes: sizes
    });
    return {
      resizeTable: resizeTable2,
      clampTableDelta,
      calcLeftEdgeDeltas,
      calcMiddleDeltas,
      calcRightEdgeDeltas,
      calcRedestributedWidths
    };
  };
  const getGridSize = (table2) => {
    const warehouse = Warehouse.fromTable(table2);
    return warehouse.grid;
  };
  const isHeaderCell = isTag("th");
  const isHeaderCells = (cells2) => forall(cells2, (cell2) => isHeaderCell(cell2.element));
  const getRowHeaderType = (isHeaderRow, isHeaderCells2) => {
    if (isHeaderRow && isHeaderCells2) {
      return "sectionCells";
    } else if (isHeaderRow) {
      return "section";
    } else {
      return "cells";
    }
  };
  const getRowType = (row2) => {
    const isHeaderRow = row2.section === "thead";
    const isHeaderCells2 = is(findCommonCellType(row2.cells), "th");
    if (row2.section === "tfoot") {
      return { type: "footer" };
    } else if (isHeaderRow || isHeaderCells2) {
      return {
        type: "header",
        subType: getRowHeaderType(isHeaderRow, isHeaderCells2)
      };
    } else {
      return { type: "body" };
    }
  };
  const findCommonCellType = (cells2) => {
    const headerCells = filter$2(cells2, (cell2) => isHeaderCell(cell2.element));
    if (headerCells.length === 0) {
      return Optional.some("td");
    } else if (headerCells.length === cells2.length) {
      return Optional.some("th");
    } else {
      return Optional.none();
    }
  };
  const findCommonRowType = (rows2) => {
    const rowTypes = map$1(rows2, (row2) => getRowType(row2).type);
    const hasHeader = contains$2(rowTypes, "header");
    const hasFooter = contains$2(rowTypes, "footer");
    if (!hasHeader && !hasFooter) {
      return Optional.some("body");
    } else {
      const hasBody = contains$2(rowTypes, "body");
      if (hasHeader && !hasBody && !hasFooter) {
        return Optional.some("header");
      } else if (!hasHeader && !hasBody && hasFooter) {
        return Optional.some("footer");
      } else {
        return Optional.none();
      }
    }
  };
  const findTableRowHeaderType = (warehouse) => findMap(warehouse.all, (row2) => {
    const rowType = getRowType(row2);
    return rowType.type === "header" ? Optional.from(rowType.subType) : Optional.none();
  });
  const transformCell = (cell2, comparator, substitution) => elementnew(substitution(cell2.element, comparator), true, cell2.isLocked);
  const transformRow = (row2, section2) => row2.section !== section2 ? rowcells(row2.element, row2.cells, section2, row2.isNew) : row2;
  const section = () => ({
    transformRow,
    transformCell: (cell2, comparator, substitution) => {
      const newCell = substitution(cell2.element, comparator);
      const fixedCell = name(newCell) !== "td" ? mutate$1(newCell, "td") : newCell;
      return elementnew(fixedCell, cell2.isNew, cell2.isLocked);
    }
  });
  const sectionCells = () => ({
    transformRow,
    transformCell
  });
  const cells = () => ({
    transformRow: (row2, section2) => {
      const newSection = section2 === "thead" ? "tbody" : section2;
      return transformRow(row2, newSection);
    },
    transformCell
  });
  const fallback = () => ({
    transformRow: identity,
    transformCell
  });
  const getTableSectionType = (table2, fallback2) => {
    const warehouse = Warehouse.fromTable(table2);
    const type2 = findTableRowHeaderType(warehouse).getOr(fallback2);
    switch (type2) {
      case "section":
        return section();
      case "sectionCells":
        return sectionCells();
      case "cells":
        return cells();
    }
  };
  const TableSection = {
    getTableSectionType,
    section,
    sectionCells,
    cells,
    fallback
  };
  const closest = (target) => closest$1(target, "[contenteditable]");
  const isEditable$1 = (element, assumeEditable = false) => {
    if (inBody(element)) {
      return element.dom.isContentEditable;
    } else {
      return closest(element).fold(constant(assumeEditable), (editable) => getRaw(editable) === "true");
    }
  };
  const getRaw = (element) => element.dom.contentEditable;
  const setIfNot = (element, property, value2, ignore) => {
    if (value2 === ignore) {
      remove$7(element, property);
    } else {
      set$2(element, property, value2);
    }
  };
  const insert$1 = (table2, selector, element) => {
    last$2(children(table2, selector)).fold(() => prepend(table2, element), (child2) => after$5(child2, element));
  };
  const generateSection = (table2, sectionName) => {
    const section2 = child(table2, sectionName).getOrThunk(() => {
      const newSection = SugarElement.fromTag(sectionName, owner(table2).dom);
      if (sectionName === "thead") {
        insert$1(table2, "caption,colgroup", newSection);
      } else if (sectionName === "colgroup") {
        insert$1(table2, "caption", newSection);
      } else {
        append$1(table2, newSection);
      }
      return newSection;
    });
    empty(section2);
    return section2;
  };
  const render$1 = (table2, grid2) => {
    const newRows = [];
    const newCells = [];
    const syncRows = (gridSection) => map$1(gridSection, (row2) => {
      if (row2.isNew) {
        newRows.push(row2.element);
      }
      const tr = row2.element;
      empty(tr);
      each$2(row2.cells, (cell2) => {
        if (cell2.isNew) {
          newCells.push(cell2.element);
        }
        setIfNot(cell2.element, "colspan", cell2.colspan, 1);
        setIfNot(cell2.element, "rowspan", cell2.rowspan, 1);
        append$1(tr, cell2.element);
      });
      return tr;
    });
    const syncColGroup = (gridSection) => bind$2(gridSection, (colGroup) => map$1(colGroup.cells, (col2) => {
      setIfNot(col2.element, "span", col2.colspan, 1);
      return col2.element;
    }));
    const renderSection = (gridSection, sectionName) => {
      const section2 = generateSection(table2, sectionName);
      const sync2 = sectionName === "colgroup" ? syncColGroup : syncRows;
      const sectionElems = sync2(gridSection);
      append(section2, sectionElems);
    };
    const removeSection = (sectionName) => {
      child(table2, sectionName).each(remove$6);
    };
    const renderOrRemoveSection = (gridSection, sectionName) => {
      if (gridSection.length > 0) {
        renderSection(gridSection, sectionName);
      } else {
        removeSection(sectionName);
      }
    };
    const headSection = [];
    const bodySection = [];
    const footSection = [];
    const columnGroupsSection = [];
    each$2(grid2, (row2) => {
      switch (row2.section) {
        case "thead":
          headSection.push(row2);
          break;
        case "tbody":
          bodySection.push(row2);
          break;
        case "tfoot":
          footSection.push(row2);
          break;
        case "colgroup":
          columnGroupsSection.push(row2);
          break;
      }
    });
    renderOrRemoveSection(columnGroupsSection, "colgroup");
    renderOrRemoveSection(headSection, "thead");
    renderOrRemoveSection(bodySection, "tbody");
    renderOrRemoveSection(footSection, "tfoot");
    return {
      newRows,
      newCells
    };
  };
  const copy = (grid2) => map$1(grid2, (row2) => {
    const tr = shallow(row2.element);
    each$2(row2.cells, (cell2) => {
      const clonedCell = deep(cell2.element);
      setIfNot(clonedCell, "colspan", cell2.colspan, 1);
      setIfNot(clonedCell, "rowspan", cell2.rowspan, 1);
      append$1(tr, clonedCell);
    });
    return tr;
  });
  const getColumn = (grid2, index2) => {
    return map$1(grid2, (row2) => {
      return getCell(row2, index2);
    });
  };
  const getRow = (grid2, index2) => {
    return grid2[index2];
  };
  const findDiff = (xs, comp) => {
    if (xs.length === 0) {
      return 0;
    }
    const first2 = xs[0];
    const index2 = findIndex(xs, (x) => {
      return !comp(first2.element, x.element);
    });
    return index2.getOr(xs.length);
  };
  const subgrid = (grid2, row2, column, comparator) => {
    const gridRow = getRow(grid2, row2);
    const isColRow = gridRow.section === "colgroup";
    const colspan = findDiff(gridRow.cells.slice(column), comparator);
    const rowspan = isColRow ? 1 : findDiff(getColumn(grid2.slice(row2), column), comparator);
    return {
      colspan,
      rowspan
    };
  };
  const toDetails = (grid2, comparator) => {
    const seen = map$1(grid2, (row2) => map$1(row2.cells, never));
    const updateSeen = (rowIndex, columnIndex, rowspan, colspan) => {
      for (let row2 = rowIndex; row2 < rowIndex + rowspan; row2++) {
        for (let column = columnIndex; column < columnIndex + colspan; column++) {
          seen[row2][column] = true;
        }
      }
    };
    return map$1(grid2, (row2, rowIndex) => {
      const details = bind$2(row2.cells, (cell2, columnIndex) => {
        if (seen[rowIndex][columnIndex] === false) {
          const result = subgrid(grid2, rowIndex, columnIndex, comparator);
          updateSeen(rowIndex, columnIndex, result.rowspan, result.colspan);
          return [detailnew(cell2.element, result.rowspan, result.colspan, cell2.isNew)];
        } else {
          return [];
        }
      });
      return rowdetailnew(row2.element, details, row2.section, row2.isNew);
    });
  };
  const toGrid = (warehouse, generators, isNew) => {
    const grid2 = [];
    each$2(warehouse.colgroups, (colgroup2) => {
      const colgroupCols = [];
      for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) {
        const element = Warehouse.getColumnAt(warehouse, columnIndex).map((column) => elementnew(column.element, isNew, false)).getOrThunk(() => elementnew(generators.colGap(), true, false));
        colgroupCols.push(element);
      }
      grid2.push(rowcells(colgroup2.element, colgroupCols, "colgroup", isNew));
    });
    for (let rowIndex = 0; rowIndex < warehouse.grid.rows; rowIndex++) {
      const rowCells = [];
      for (let columnIndex = 0; columnIndex < warehouse.grid.columns; columnIndex++) {
        const element = Warehouse.getAt(warehouse, rowIndex, columnIndex).map((item) => elementnew(item.element, isNew, item.isLocked)).getOrThunk(() => elementnew(generators.gap(), true, false));
        rowCells.push(element);
      }
      const rowDetail = warehouse.all[rowIndex];
      const row2 = rowcells(rowDetail.element, rowCells, rowDetail.section, isNew);
      grid2.push(row2);
    }
    return grid2;
  };
  const fromWarehouse = (warehouse, generators) => toGrid(warehouse, generators, false);
  const toDetailList = (grid2) => toDetails(grid2, eq$1);
  const findInWarehouse = (warehouse, element) => findMap(warehouse.all, (r2) => find$1(r2.cells, (e) => eq$1(element, e.element)));
  const extractCells = (warehouse, target, predicate) => {
    const details = map$1(target.selection, (cell$1) => {
      return cell(cell$1).bind((lc) => findInWarehouse(warehouse, lc)).filter(predicate);
    });
    const cells2 = cat(details);
    return someIf(cells2.length > 0, cells2);
  };
  const run = (operation, extract2, adjustment, postAction, genWrappers) => (table2, target, generators, behaviours) => {
    const warehouse = Warehouse.fromTable(table2);
    const tableSection = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.section).getOrThunk(TableSection.fallback);
    const output = extract2(warehouse, target).map((info) => {
      const model = fromWarehouse(warehouse, generators);
      const result = operation(model, info, eq$1, genWrappers(generators), tableSection);
      const lockedColumns = getLockedColumnsFromGrid(result.grid);
      const grid2 = toDetailList(result.grid);
      return {
        info,
        grid: grid2,
        cursor: result.cursor,
        lockedColumns
      };
    });
    return output.bind((out) => {
      const newElements = render$1(table2, out.grid);
      const tableSizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.sizing).getOrThunk(() => TableSize.getTableSize(table2));
      const resizing = Optional.from(behaviours === null || behaviours === void 0 ? void 0 : behaviours.resize).getOrThunk(preserveTable);
      adjustment(table2, out.grid, out.info, {
        sizing: tableSizing,
        resize: resizing,
        section: tableSection
      });
      postAction(table2);
      remove$7(table2, LOCKED_COL_ATTR);
      if (out.lockedColumns.length > 0) {
        set$2(table2, LOCKED_COL_ATTR, out.lockedColumns.join(","));
      }
      return Optional.some({
        cursor: out.cursor,
        newRows: newElements.newRows,
        newCells: newElements.newCells
      });
    });
  };
  const onPaste = (warehouse, target) => cell(target.element).bind((cell2) => findInWarehouse(warehouse, cell2).map((details) => {
    const value2 = {
      ...details,
      generators: target.generators,
      clipboard: target.clipboard
    };
    return value2;
  }));
  const onPasteByEditor = (warehouse, target) => extractCells(warehouse, target, always).map((cells2) => ({
    cells: cells2,
    generators: target.generators,
    clipboard: target.clipboard
  }));
  const onMergable = (_warehouse, target) => target.mergable;
  const onUnmergable = (_warehouse, target) => target.unmergable;
  const onCells = (warehouse, target) => extractCells(warehouse, target, always);
  const onUnlockedCells = (warehouse, target) => extractCells(warehouse, target, (detail2) => !detail2.isLocked);
  const isUnlockedTableCell = (warehouse, cell2) => findInWarehouse(warehouse, cell2).exists((detail2) => !detail2.isLocked);
  const allUnlocked = (warehouse, cells2) => forall(cells2, (cell2) => isUnlockedTableCell(warehouse, cell2));
  const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter((mergeable) => allUnlocked(warehouse, mergeable.cells));
  const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter((cells2) => allUnlocked(warehouse, cells2));
  const merge$2 = (grid2, bounds2, comparator, substitution) => {
    const rows2 = extractGridDetails(grid2).rows;
    if (rows2.length === 0) {
      return grid2;
    }
    for (let i = bounds2.startRow; i <= bounds2.finishRow; i++) {
      for (let j = bounds2.startCol; j <= bounds2.finishCol; j++) {
        const row2 = rows2[i];
        const isLocked = getCell(row2, j).isLocked;
        mutateCell(row2, j, elementnew(substitution(), false, isLocked));
      }
    }
    return grid2;
  };
  const unmerge = (grid2, target, comparator, substitution) => {
    const rows2 = extractGridDetails(grid2).rows;
    let first2 = true;
    for (let i = 0; i < rows2.length; i++) {
      for (let j = 0; j < cellLength(rows2[0]); j++) {
        const row2 = rows2[i];
        const currentCell = getCell(row2, j);
        const currentCellElm = currentCell.element;
        const isToReplace = comparator(currentCellElm, target);
        if (isToReplace && !first2) {
          mutateCell(row2, j, elementnew(substitution(), true, currentCell.isLocked));
        } else if (isToReplace) {
          first2 = false;
        }
      }
    }
    return grid2;
  };
  const uniqueCells = (row2, comparator) => {
    return foldl(row2, (rest, cell2) => {
      return exists(rest, (currentCell) => {
        return comparator(currentCell.element, cell2.element);
      }) ? rest : rest.concat([cell2]);
    }, []);
  };
  const splitCols = (grid2, index2, comparator, substitution) => {
    if (index2 > 0 && index2 < grid2[0].cells.length) {
      each$2(grid2, (row2) => {
        const prevCell = row2.cells[index2 - 1];
        let offset = 0;
        const substitute = substitution();
        while (row2.cells.length > index2 + offset && comparator(prevCell.element, row2.cells[index2 + offset].element)) {
          mutateCell(row2, index2 + offset, elementnew(substitute, true, row2.cells[index2 + offset].isLocked));
          offset++;
        }
      });
    }
    return grid2;
  };
  const splitRows = (grid2, index2, comparator, substitution) => {
    const rows2 = extractGridDetails(grid2).rows;
    if (index2 > 0 && index2 < rows2.length) {
      const rowPrevCells = rows2[index2 - 1].cells;
      const cells2 = uniqueCells(rowPrevCells, comparator);
      each$2(cells2, (cell2) => {
        let replacement = Optional.none();
        for (let i = index2; i < rows2.length; i++) {
          for (let j = 0; j < cellLength(rows2[0]); j++) {
            const row2 = rows2[i];
            const current = getCell(row2, j);
            const isToReplace = comparator(current.element, cell2.element);
            if (isToReplace) {
              if (replacement.isNone()) {
                replacement = Optional.some(substitution());
              }
              replacement.each((sub) => {
                mutateCell(row2, j, elementnew(sub, true, current.isLocked));
              });
            }
          }
        }
      });
    }
    return grid2;
  };
  const value$1 = (value2) => {
    const applyHelper = (fn) => fn(value2);
    const constHelper = constant(value2);
    const outputHelper = () => output;
    const output = {
      tag: true,
      inner: value2,
      fold: (_onError, onValue) => onValue(value2),
      isValue: always,
      isError: never,
      map: (mapper) => Result.value(mapper(value2)),
      mapError: outputHelper,
      bind: applyHelper,
      exists: applyHelper,
      forall: applyHelper,
      getOr: constHelper,
      or: outputHelper,
      getOrThunk: constHelper,
      orThunk: outputHelper,
      getOrDie: constHelper,
      each: (fn) => {
        fn(value2);
      },
      toOptional: () => Optional.some(value2)
    };
    return output;
  };
  const error = (error2) => {
    const outputHelper = () => output;
    const output = {
      tag: false,
      inner: error2,
      fold: (onError, _onValue) => onError(error2),
      isValue: never,
      isError: always,
      map: outputHelper,
      mapError: (mapper) => Result.error(mapper(error2)),
      bind: outputHelper,
      exists: never,
      forall: always,
      getOr: identity,
      or: identity,
      getOrThunk: apply,
      orThunk: apply,
      getOrDie: die(String(error2)),
      each: noop,
      toOptional: Optional.none
    };
    return output;
  };
  const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
  const Result = {
    value: value$1,
    error,
    fromOption
  };
  const measure = (startAddress, gridA, gridB) => {
    if (startAddress.row >= gridA.length || startAddress.column > cellLength(gridA[0])) {
      return Result.error("invalid start address out of table bounds, row: " + startAddress.row + ", column: " + startAddress.column);
    }
    const rowRemainder = gridA.slice(startAddress.row);
    const colRemainder = rowRemainder[0].cells.slice(startAddress.column);
    const colRequired = cellLength(gridB[0]);
    const rowRequired = gridB.length;
    return Result.value({
      rowDelta: rowRemainder.length - rowRequired,
      colDelta: colRemainder.length - colRequired
    });
  };
  const measureWidth = (gridA, gridB) => {
    const colLengthA = cellLength(gridA[0]);
    const colLengthB = cellLength(gridB[0]);
    return {
      rowDelta: 0,
      colDelta: colLengthA - colLengthB
    };
  };
  const measureHeight = (gridA, gridB) => {
    const rowLengthA = gridA.length;
    const rowLengthB = gridB.length;
    return {
      rowDelta: rowLengthA - rowLengthB,
      colDelta: 0
    };
  };
  const generateElements = (amount, row2, generators, isLocked) => {
    const generator = row2.section === "colgroup" ? generators.col : generators.cell;
    return range$1(amount, (idx) => elementnew(generator(), true, isLocked(idx)));
  };
  const rowFill = (grid2, amount, generators, lockedColumns) => {
    const exampleRow = grid2[grid2.length - 1];
    return grid2.concat(range$1(amount, () => {
      const generator = exampleRow.section === "colgroup" ? generators.colgroup : generators.row;
      const row2 = clone(exampleRow, generator, identity);
      const elements = generateElements(row2.cells.length, row2, generators, (idx) => has$1(lockedColumns, idx.toString()));
      return setCells(row2, elements);
    }));
  };
  const colFill = (grid2, amount, generators, startIndex) => map$1(grid2, (row2) => {
    const newChildren = generateElements(amount, row2, generators, never);
    return addCells(row2, startIndex, newChildren);
  });
  const lockedColFill = (grid2, generators, lockedColumns) => map$1(grid2, (row2) => {
    return foldl(lockedColumns, (acc, colNum) => {
      const newChild = generateElements(1, row2, generators, always)[0];
      return addCell(acc, colNum, newChild);
    }, row2);
  });
  const tailor = (gridA, delta, generators) => {
    const fillCols = delta.colDelta < 0 ? colFill : identity;
    const fillRows = delta.rowDelta < 0 ? rowFill : identity;
    const lockedColumns = getLockedColumnsFromGrid(gridA);
    const gridWidth = cellLength(gridA[0]);
    const isLastColLocked = exists(lockedColumns, (locked) => locked === gridWidth - 1);
    const modifiedCols = fillCols(gridA, Math.abs(delta.colDelta), generators, isLastColLocked ? gridWidth - 1 : gridWidth);
    const newLockedColumns = getLockedColumnsFromGrid(modifiedCols);
    return fillRows(modifiedCols, Math.abs(delta.rowDelta), generators, mapToObject(newLockedColumns, always));
  };
  const isSpanning = (grid2, row2, col2, comparator) => {
    const candidate = getCell(grid2[row2], col2);
    const matching = curry(comparator, candidate.element);
    const currentRow = grid2[row2];
    return grid2.length > 1 && cellLength(currentRow) > 1 && (col2 > 0 && matching(getCellElement(currentRow, col2 - 1)) || col2 < currentRow.cells.length - 1 && matching(getCellElement(currentRow, col2 + 1)) || row2 > 0 && matching(getCellElement(grid2[row2 - 1], col2)) || row2 < grid2.length - 1 && matching(getCellElement(grid2[row2 + 1], col2)));
  };
  const mergeTables = (startAddress, gridA, gridBRows, generator, comparator, lockedColumns) => {
    const startRow = startAddress.row;
    const startCol = startAddress.column;
    const mergeHeight = gridBRows.length;
    const mergeWidth = cellLength(gridBRows[0]);
    const endRow = startRow + mergeHeight;
    const endCol = startCol + mergeWidth + lockedColumns.length;
    const lockedColumnObj = mapToObject(lockedColumns, always);
    for (let r2 = startRow; r2 < endRow; r2++) {
      let skippedCol = 0;
      for (let c = startCol; c < endCol; c++) {
        if (lockedColumnObj[c]) {
          skippedCol++;
          continue;
        }
        if (isSpanning(gridA, r2, c, comparator)) {
          unmerge(gridA, getCellElement(gridA[r2], c), comparator, generator.cell);
        }
        const gridBColIndex = c - startCol - skippedCol;
        const newCell = getCell(gridBRows[r2 - startRow], gridBColIndex);
        const newCellElm = newCell.element;
        const replacement = generator.replace(newCellElm);
        mutateCell(gridA[r2], c, elementnew(replacement, true, newCell.isLocked));
      }
    }
    return gridA;
  };
  const getValidStartAddress = (currentStartAddress, grid2, lockedColumns) => {
    const gridColLength = cellLength(grid2[0]);
    const adjustedRowAddress = extractGridDetails(grid2).cols.length + currentStartAddress.row;
    const possibleColAddresses = range$1(gridColLength - currentStartAddress.column, (num) => num + currentStartAddress.column);
    const validColAddress = find$1(possibleColAddresses, (num) => forall(lockedColumns, (col2) => col2 !== num)).getOr(gridColLength - 1);
    return {
      row: adjustedRowAddress,
      column: validColAddress
    };
  };
  const getLockedColumnsWithinBounds = (startAddress, rows2, lockedColumns) => filter$2(lockedColumns, (colNum) => colNum >= startAddress.column && colNum <= cellLength(rows2[0]) + startAddress.column);
  const merge$1 = (startAddress, gridA, gridB, generator, comparator) => {
    const lockedColumns = getLockedColumnsFromGrid(gridA);
    const validStartAddress = getValidStartAddress(startAddress, gridA, lockedColumns);
    const gridBRows = extractGridDetails(gridB).rows;
    const lockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, lockedColumns);
    const result = measure(validStartAddress, gridA, gridBRows);
    return result.map((diff) => {
      const delta = {
        ...diff,
        colDelta: diff.colDelta - lockedColumnsWithinBounds.length
      };
      const fittedGrid = tailor(gridA, delta, generator);
      const newLockedColumns = getLockedColumnsFromGrid(fittedGrid);
      const newLockedColumnsWithinBounds = getLockedColumnsWithinBounds(validStartAddress, gridBRows, newLockedColumns);
      return mergeTables(validStartAddress, fittedGrid, gridBRows, generator, comparator, newLockedColumnsWithinBounds);
    });
  };
  const insertCols = (index2, gridA, gridB, generator, comparator) => {
    splitCols(gridA, index2, comparator, generator.cell);
    const delta = measureHeight(gridB, gridA);
    const fittedNewGrid = tailor(gridB, delta, generator);
    const secondDelta = measureHeight(gridA, fittedNewGrid);
    const fittedOldGrid = tailor(gridA, secondDelta, generator);
    return map$1(fittedOldGrid, (gridRow, i) => {
      return addCells(gridRow, index2, fittedNewGrid[i].cells);
    });
  };
  const insertRows = (index2, gridA, gridB, generator, comparator) => {
    splitRows(gridA, index2, comparator, generator.cell);
    const locked = getLockedColumnsFromGrid(gridA);
    const diff = measureWidth(gridA, gridB);
    const delta = {
      ...diff,
      colDelta: diff.colDelta - locked.length
    };
    const fittedOldGrid = tailor(gridA, delta, generator);
    const {
      cols: oldCols,
      rows: oldRows
    } = extractGridDetails(fittedOldGrid);
    const newLocked = getLockedColumnsFromGrid(fittedOldGrid);
    const secondDiff = measureWidth(gridB, gridA);
    const secondDelta = {
      ...secondDiff,
      colDelta: secondDiff.colDelta + newLocked.length
    };
    const fittedGridB = lockedColFill(gridB, generator, newLocked);
    const fittedNewGrid = tailor(fittedGridB, secondDelta, generator);
    return [
      ...oldCols,
      ...oldRows.slice(0, index2),
      ...fittedNewGrid,
      ...oldRows.slice(index2, oldRows.length)
    ];
  };
  const cloneRow = (row2, cloneCell, comparator, substitution) => clone(row2, (elem) => substitution(elem, comparator), cloneCell);
  const insertRowAt = (grid2, index2, example, comparator, substitution) => {
    const { rows: rows2, cols } = extractGridDetails(grid2);
    const before2 = rows2.slice(0, index2);
    const after2 = rows2.slice(index2);
    const newRow = cloneRow(rows2[example], (ex, c) => {
      const withinSpan = index2 > 0 && index2 < rows2.length && comparator(getCellElement(rows2[index2 - 1], c), getCellElement(rows2[index2], c));
      const ret = withinSpan ? getCell(rows2[index2], c) : elementnew(substitution(ex.element, comparator), true, ex.isLocked);
      return ret;
    }, comparator, substitution);
    return [
      ...cols,
      ...before2,
      newRow,
      ...after2
    ];
  };
  const getElementFor = (row2, column, section2, withinSpan, example, comparator, substitution) => {
    if (section2 === "colgroup" || !withinSpan) {
      const cell2 = getCell(row2, example);
      return elementnew(substitution(cell2.element, comparator), true, false);
    } else {
      return getCell(row2, column);
    }
  };
  const insertColumnAt = (grid2, index2, example, comparator, substitution) => map$1(grid2, (row2) => {
    const withinSpan = index2 > 0 && index2 < cellLength(row2) && comparator(getCellElement(row2, index2 - 1), getCellElement(row2, index2));
    const sub = getElementFor(row2, index2, row2.section, withinSpan, example, comparator, substitution);
    return addCell(row2, index2, sub);
  });
  const deleteColumnsAt = (grid2, columns2) => bind$2(grid2, (row2) => {
    const existingCells = row2.cells;
    const cells2 = foldr(columns2, (acc, column) => column >= 0 && column < acc.length ? acc.slice(0, column).concat(acc.slice(column + 1)) : acc, existingCells);
    return cells2.length > 0 ? [rowcells(row2.element, cells2, row2.section, row2.isNew)] : [];
  });
  const deleteRowsAt = (grid2, start, finish) => {
    const { rows: rows2, cols } = extractGridDetails(grid2);
    return [
      ...cols,
      ...rows2.slice(0, start),
      ...rows2.slice(finish + 1)
    ];
  };
  const notInStartRow = (grid2, rowIndex, colIndex, comparator) => getCellElement(grid2[rowIndex], colIndex) !== void 0 && (rowIndex > 0 && comparator(getCellElement(grid2[rowIndex - 1], colIndex), getCellElement(grid2[rowIndex], colIndex)));
  const notInStartColumn = (row2, index2, comparator) => index2 > 0 && comparator(getCellElement(row2, index2 - 1), getCellElement(row2, index2));
  const isDuplicatedCell = (grid2, rowIndex, colIndex, comparator) => notInStartRow(grid2, rowIndex, colIndex, comparator) || notInStartColumn(grid2[rowIndex], colIndex, comparator);
  const rowReplacerPredicate = (targetRow, columnHeaders) => {
    const entireTableIsHeader = forall(columnHeaders, identity) && isHeaderCells(targetRow.cells);
    return entireTableIsHeader ? always : (cell2, _rowIndex, colIndex) => {
      const type2 = name(cell2.element);
      return !(type2 === "th" && columnHeaders[colIndex]);
    };
  };
  const columnReplacePredicate = (targetColumn, rowHeaders) => {
    const entireTableIsHeader = forall(rowHeaders, identity) && isHeaderCells(targetColumn);
    return entireTableIsHeader ? always : (cell2, rowIndex, _colIndex) => {
      const type2 = name(cell2.element);
      return !(type2 === "th" && rowHeaders[rowIndex]);
    };
  };
  const determineScope = (applyScope, cell2, newScope, isInHeader) => {
    const hasSpan = (scope) => scope === "row" ? hasRowspan(cell2) : hasColspan(cell2);
    const getScope = (scope) => hasSpan(scope) ? `${scope}group` : scope;
    if (applyScope) {
      return isHeaderCell(cell2) ? getScope(newScope) : null;
    } else if (isInHeader && isHeaderCell(cell2)) {
      const oppositeScope = newScope === "row" ? "col" : "row";
      return getScope(oppositeScope);
    } else {
      return null;
    }
  };
  const rowScopeGenerator = (applyScope, columnHeaders) => (cell2, rowIndex, columnIndex) => Optional.some(determineScope(applyScope, cell2.element, "col", columnHeaders[columnIndex]));
  const columnScopeGenerator = (applyScope, rowHeaders) => (cell2, rowIndex) => Optional.some(determineScope(applyScope, cell2.element, "row", rowHeaders[rowIndex]));
  const replace = (cell2, comparator, substitute) => elementnew(substitute(cell2.element, comparator), true, cell2.isLocked);
  const replaceIn = (grid2, targets, comparator, substitute, replacer, genScope, shouldReplace) => {
    const isTarget = (cell2) => {
      return exists(targets, (target) => {
        return comparator(cell2.element, target.element);
      });
    };
    return map$1(grid2, (row2, rowIndex) => {
      return mapCells(row2, (cell2, colIndex) => {
        if (isTarget(cell2)) {
          const newCell = shouldReplace(cell2, rowIndex, colIndex) ? replacer(cell2, comparator, substitute) : cell2;
          genScope(newCell, rowIndex, colIndex).each((scope) => {
            setOptions(newCell.element, { scope: Optional.from(scope) });
          });
          return newCell;
        } else {
          return cell2;
        }
      });
    });
  };
  const getColumnCells = (rows2, columnIndex, comparator) => bind$2(rows2, (row2, i) => {
    return isDuplicatedCell(rows2, i, columnIndex, comparator) ? [] : [getCell(row2, columnIndex)];
  });
  const getRowCells = (rows2, rowIndex, comparator) => {
    const targetRow = rows2[rowIndex];
    return bind$2(targetRow.cells, (item, i) => {
      return isDuplicatedCell(rows2, rowIndex, i, comparator) ? [] : [item];
    });
  };
  const replaceColumns = (grid2, indexes, applyScope, comparator, substitution) => {
    const rows2 = extractGridDetails(grid2).rows;
    const targets = bind$2(indexes, (index2) => getColumnCells(rows2, index2, comparator));
    const rowHeaders = map$1(rows2, (row2) => isHeaderCells(row2.cells));
    const shouldReplaceCell = columnReplacePredicate(targets, rowHeaders);
    const scopeGenerator = columnScopeGenerator(applyScope, rowHeaders);
    return replaceIn(grid2, targets, comparator, substitution, replace, scopeGenerator, shouldReplaceCell);
  };
  const replaceRows = (grid2, indexes, section2, applyScope, comparator, substitution, tableSection) => {
    const { cols, rows: rows2 } = extractGridDetails(grid2);
    const targetRow = rows2[indexes[0]];
    const targets = bind$2(indexes, (index2) => getRowCells(rows2, index2, comparator));
    const columnHeaders = map$1(targetRow.cells, (_cell, index2) => isHeaderCells(getColumnCells(rows2, index2, comparator)));
    const newRows = [...rows2];
    each$2(indexes, (index2) => {
      newRows[index2] = tableSection.transformRow(rows2[index2], section2);
    });
    const newGrid = [
      ...cols,
      ...newRows
    ];
    const shouldReplaceCell = rowReplacerPredicate(targetRow, columnHeaders);
    const scopeGenerator = rowScopeGenerator(applyScope, columnHeaders);
    return replaceIn(newGrid, targets, comparator, substitution, tableSection.transformCell, scopeGenerator, shouldReplaceCell);
  };
  const replaceCells = (grid2, details, comparator, substitution) => {
    const rows2 = extractGridDetails(grid2).rows;
    const targetCells = map$1(details, (detail2) => getCell(rows2[detail2.row], detail2.column));
    return replaceIn(grid2, targetCells, comparator, substitution, replace, Optional.none, always);
  };
  const generate = (cases) => {
    if (!isArray(cases)) {
      throw new Error("cases must be an array");
    }
    if (cases.length === 0) {
      throw new Error("there must be at least one case");
    }
    const constructors = [];
    const adt2 = {};
    each$2(cases, (acase, count) => {
      const keys$1 = keys(acase);
      if (keys$1.length !== 1) {
        throw new Error("one and only one name per case");
      }
      const key2 = keys$1[0];
      const value2 = acase[key2];
      if (adt2[key2] !== void 0) {
        throw new Error("duplicate key detected:" + key2);
      } else if (key2 === "cata") {
        throw new Error("cannot have a case named cata (sorry)");
      } else if (!isArray(value2)) {
        throw new Error("case arguments must be an array");
      }
      constructors.push(key2);
      adt2[key2] = (...args) => {
        const argLength = args.length;
        if (argLength !== value2.length) {
          throw new Error("Wrong number of arguments to case " + key2 + ". Expected " + value2.length + " (" + value2 + "), got " + argLength);
        }
        const match = (branches) => {
          const branchKeys = keys(branches);
          if (constructors.length !== branchKeys.length) {
            throw new Error("Wrong number of arguments to match. Expected: " + constructors.join(",") + "\nActual: " + branchKeys.join(","));
          }
          const allReqd = forall(constructors, (reqKey) => {
            return contains$2(branchKeys, reqKey);
          });
          if (!allReqd) {
            throw new Error("Not all branches were specified when using match. Specified: " + branchKeys.join(", ") + "\nRequired: " + constructors.join(", "));
          }
          return branches[key2].apply(null, args);
        };
        return {
          fold: (...foldArgs) => {
            if (foldArgs.length !== cases.length) {
              throw new Error("Wrong number of arguments to fold. Expected " + cases.length + ", got " + foldArgs.length);
            }
            const target = foldArgs[count];
            return target.apply(null, args);
          },
          match,
          log: (label) => {
            console.log(label, {
              constructors,
              constructor: key2,
              params: args
            });
          }
        };
      };
    });
    return adt2;
  };
  const Adt = { generate };
  const adt$6 = Adt.generate([
    { none: [] },
    { only: ["index"] },
    {
      left: [
        "index",
        "next"
      ]
    },
    {
      middle: [
        "prev",
        "index",
        "next"
      ]
    },
    {
      right: [
        "prev",
        "index"
      ]
    }
  ]);
  const ColumnContext = { ...adt$6 };
  const neighbours = (input, index2) => {
    if (input.length === 0) {
      return ColumnContext.none();
    }
    if (input.length === 1) {
      return ColumnContext.only(0);
    }
    if (index2 === 0) {
      return ColumnContext.left(0, 1);
    }
    if (index2 === input.length - 1) {
      return ColumnContext.right(index2 - 1, index2);
    }
    if (index2 > 0 && index2 < input.length - 1) {
      return ColumnContext.middle(index2 - 1, index2, index2 + 1);
    }
    return ColumnContext.none();
  };
  const determine = (input, column, step, tableSize, resize2) => {
    const result = input.slice(0);
    const context = neighbours(input, column);
    const onNone = constant(map$1(result, constant(0)));
    const onOnly = (index2) => tableSize.singleColumnWidth(result[index2], step);
    const onLeft = (index2, next) => resize2.calcLeftEdgeDeltas(result, index2, next, step, tableSize.minCellWidth(), tableSize.isRelative);
    const onMiddle = (prev, index2, next) => resize2.calcMiddleDeltas(result, prev, index2, next, step, tableSize.minCellWidth(), tableSize.isRelative);
    const onRight = (prev, index2) => resize2.calcRightEdgeDeltas(result, prev, index2, step, tableSize.minCellWidth(), tableSize.isRelative);
    return context.fold(onNone, onOnly, onLeft, onMiddle, onRight);
  };
  const total = (start, end, measures) => {
    let r2 = 0;
    for (let i = start; i < end; i++) {
      r2 += measures[i] !== void 0 ? measures[i] : 0;
    }
    return r2;
  };
  const recalculateWidthForCells = (warehouse, widths) => {
    const all2 = Warehouse.justCells(warehouse);
    return map$1(all2, (cell2) => {
      const width2 = total(cell2.column, cell2.column + cell2.colspan, widths);
      return {
        element: cell2.element,
        width: width2,
        colspan: cell2.colspan
      };
    });
  };
  const recalculateWidthForColumns = (warehouse, widths) => {
    const groups = Warehouse.justColumns(warehouse);
    return map$1(groups, (column, index2) => ({
      element: column.element,
      width: widths[index2],
      colspan: column.colspan
    }));
  };
  const recalculateHeightForCells = (warehouse, heights) => {
    const all2 = Warehouse.justCells(warehouse);
    return map$1(all2, (cell2) => {
      const height2 = total(cell2.row, cell2.row + cell2.rowspan, heights);
      return {
        element: cell2.element,
        height: height2,
        rowspan: cell2.rowspan
      };
    });
  };
  const matchRowHeight = (warehouse, heights) => {
    return map$1(warehouse.all, (row2, i) => {
      return {
        element: row2.element,
        height: heights[i]
      };
    });
  };
  const sumUp = (newSize) => foldr(newSize, (b, a) => b + a, 0);
  const recalculate = (warehouse, widths) => {
    if (Warehouse.hasColumns(warehouse)) {
      return recalculateWidthForColumns(warehouse, widths);
    } else {
      return recalculateWidthForCells(warehouse, widths);
    }
  };
  const recalculateAndApply = (warehouse, widths, tableSize) => {
    const newSizes = recalculate(warehouse, widths);
    each$2(newSizes, (cell2) => {
      tableSize.setElementWidth(cell2.element, cell2.width);
    });
  };
  const adjustWidth = (table2, delta, index2, resizing, tableSize) => {
    const warehouse = Warehouse.fromTable(table2);
    const step = tableSize.getCellDelta(delta);
    const widths = tableSize.getWidths(warehouse, tableSize);
    const isLastColumn = index2 === warehouse.grid.columns - 1;
    const clampedStep = resizing.clampTableDelta(widths, index2, step, tableSize.minCellWidth(), isLastColumn);
    const deltas = determine(widths, index2, clampedStep, tableSize, resizing);
    const newWidths = map$1(deltas, (dx, i) => dx + widths[i]);
    recalculateAndApply(warehouse, newWidths, tableSize);
    resizing.resizeTable(tableSize.adjustTableWidth, clampedStep, isLastColumn);
  };
  const adjustHeight = (table2, delta, index2, direction) => {
    const warehouse = Warehouse.fromTable(table2);
    const heights = getPixelHeights(warehouse, table2, direction);
    const newHeights = map$1(heights, (dy, i) => index2 === i ? Math.max(delta + dy, minHeight()) : dy);
    const newCellSizes = recalculateHeightForCells(warehouse, newHeights);
    const newRowSizes = matchRowHeight(warehouse, newHeights);
    each$2(newRowSizes, (row2) => {
      setHeight(row2.element, row2.height);
    });
    each$2(newCellSizes, (cell2) => {
      setHeight(cell2.element, cell2.height);
    });
    const total2 = sumUp(newHeights);
    setHeight(table2, total2);
  };
  const adjustAndRedistributeWidths$1 = (_table, list, details, tableSize, resizeBehaviour) => {
    const warehouse = Warehouse.generate(list);
    const sizes = tableSize.getWidths(warehouse, tableSize);
    const tablePixelWidth = tableSize.pixelWidth();
    const { newSizes, delta } = resizeBehaviour.calcRedestributedWidths(sizes, tablePixelWidth, details.pixelDelta, tableSize.isRelative);
    recalculateAndApply(warehouse, newSizes, tableSize);
    tableSize.adjustTableWidth(delta);
  };
  const adjustWidthTo = (_table, list, _info, tableSize) => {
    const warehouse = Warehouse.generate(list);
    const widths = tableSize.getWidths(warehouse, tableSize);
    recalculateAndApply(warehouse, widths, tableSize);
  };
  const uniqueColumns = (details) => {
    const uniqueCheck = (rest, detail2) => {
      const columnExists = exists(rest, (currentDetail) => currentDetail.column === detail2.column);
      return columnExists ? rest : rest.concat([detail2]);
    };
    return foldl(details, uniqueCheck, []).sort((detailA, detailB) => detailA.column - detailB.column);
  };
  const isCol = isTag("col");
  const isColgroup = isTag("colgroup");
  const isRow$1 = (element) => name(element) === "tr" || isColgroup(element);
  const elementToData = (element) => {
    const colspan = getAttrValue(element, "colspan", 1);
    const rowspan = getAttrValue(element, "rowspan", 1);
    return {
      element,
      colspan,
      rowspan
    };
  };
  const modification = (generators, toData = elementToData) => {
    const nuCell = (data) => isCol(data.element) ? generators.col(data) : generators.cell(data);
    const nuRow = (data) => isColgroup(data.element) ? generators.colgroup(data) : generators.row(data);
    const add2 = (element) => {
      if (isRow$1(element)) {
        return nuRow({ element });
      } else {
        const cell2 = element;
        const replacement = nuCell(toData(cell2));
        recent = Optional.some({
          item: cell2,
          replacement
        });
        return replacement;
      }
    };
    let recent = Optional.none();
    const getOrInit = (element, comparator) => {
      return recent.fold(() => {
        return add2(element);
      }, (p) => {
        return comparator(element, p.item) ? p.replacement : add2(element);
      });
    };
    return { getOrInit };
  };
  const transform$1 = (tag) => {
    return (generators) => {
      const list = [];
      const find2 = (element, comparator) => {
        return find$1(list, (x) => {
          return comparator(x.item, element);
        });
      };
      const makeNew = (element) => {
        const attrs = tag === "td" ? { scope: null } : {};
        const cell2 = generators.replace(element, tag, attrs);
        list.push({
          item: element,
          sub: cell2
        });
        return cell2;
      };
      const replaceOrInit = (element, comparator) => {
        if (isRow$1(element) || isCol(element)) {
          return element;
        } else {
          const cell2 = element;
          return find2(cell2, comparator).fold(() => {
            return makeNew(cell2);
          }, (p) => {
            return comparator(element, p.item) ? p.sub : makeNew(cell2);
          });
        }
      };
      return { replaceOrInit };
    };
  };
  const getScopeAttribute = (cell2) => getOpt(cell2, "scope").map((attribute) => attribute.substr(0, 3));
  const merging = (generators) => {
    const unmerge2 = (cell2) => {
      const scope = getScopeAttribute(cell2);
      scope.each((attribute) => set$2(cell2, "scope", attribute));
      return () => {
        const raw = generators.cell({
          element: cell2,
          colspan: 1,
          rowspan: 1
        });
        remove$5(raw, "width");
        remove$5(cell2, "width");
        scope.each((attribute) => set$2(raw, "scope", attribute));
        return raw;
      };
    };
    const merge2 = (cells2) => {
      const getScopeProperty = () => {
        const stringAttributes = cat(map$1(cells2, getScopeAttribute));
        if (stringAttributes.length === 0) {
          return Optional.none();
        } else {
          const baseScope = stringAttributes[0];
          const scopes = [
            "row",
            "col"
          ];
          const isMixed = exists(stringAttributes, (attribute) => {
            return attribute !== baseScope && contains$2(scopes, attribute);
          });
          return isMixed ? Optional.none() : Optional.from(baseScope);
        }
      };
      remove$5(cells2[0], "width");
      getScopeProperty().fold(() => remove$7(cells2[0], "scope"), (attribute) => set$2(cells2[0], "scope", attribute + "group"));
      return constant(cells2[0]);
    };
    return {
      unmerge: unmerge2,
      merge: merge2
    };
  };
  const Generators = {
    modification,
    transform: transform$1,
    merging
  };
  const blockList = [
    "body",
    "p",
    "div",
    "article",
    "aside",
    "figcaption",
    "figure",
    "footer",
    "header",
    "nav",
    "section",
    "ol",
    "ul",
    "table",
    "thead",
    "tfoot",
    "tbody",
    "caption",
    "tr",
    "td",
    "th",
    "h1",
    "h2",
    "h3",
    "h4",
    "h5",
    "h6",
    "blockquote",
    "pre",
    "address"
  ];
  const isList$1 = (universe2, item) => {
    const tagName = universe2.property().name(item);
    return contains$2([
      "ol",
      "ul"
    ], tagName);
  };
  const isBlock$1 = (universe2, item) => {
    const tagName = universe2.property().name(item);
    return contains$2(blockList, tagName);
  };
  const isEmptyTag$1 = (universe2, item) => {
    return contains$2([
      "br",
      "img",
      "hr",
      "input"
    ], universe2.property().name(item));
  };
  const universe$1 = DomUniverse();
  const isBlock = (element) => {
    return isBlock$1(universe$1, element);
  };
  const isList = (element) => {
    return isList$1(universe$1, element);
  };
  const isEmptyTag = (element) => {
    return isEmptyTag$1(universe$1, element);
  };
  const merge = (cells2) => {
    const isBr2 = isTag("br");
    const advancedBr = (children2) => {
      return forall(children2, (c) => {
        return isBr2(c) || isText(c) && get$6(c).trim().length === 0;
      });
    };
    const isListItem = (el) => {
      return name(el) === "li" || ancestor$2(el, isList).isSome();
    };
    const siblingIsBlock = (el) => {
      return nextSibling(el).map((rightSibling) => {
        if (isBlock(rightSibling)) {
          return true;
        }
        if (isEmptyTag(rightSibling)) {
          return name(rightSibling) === "img" ? false : true;
        }
        return false;
      }).getOr(false);
    };
    const markCell = (cell2) => {
      return last$1(cell2).bind((rightEdge) => {
        const rightSiblingIsBlock = siblingIsBlock(rightEdge);
        return parent(rightEdge).map((parent2) => {
          return rightSiblingIsBlock === true || isListItem(parent2) || isBr2(rightEdge) || isBlock(parent2) && !eq$1(cell2, parent2) ? [] : [SugarElement.fromTag("br")];
        });
      }).getOr([]);
    };
    const markContent = () => {
      const content = bind$2(cells2, (cell2) => {
        const children2 = children$2(cell2);
        return advancedBr(children2) ? [] : children2.concat(markCell(cell2));
      });
      return content.length === 0 ? [SugarElement.fromTag("br")] : content;
    };
    const contents = markContent();
    empty(cells2[0]);
    append(cells2[0], contents);
  };
  const isEditable = (elem) => isEditable$1(elem, true);
  const prune = (table2) => {
    const cells2 = cells$1(table2);
    if (cells2.length === 0) {
      remove$6(table2);
    }
  };
  const outcome = (grid2, cursor) => ({
    grid: grid2,
    cursor
  });
  const findEditableCursorPosition = (rows2) => findMap(rows2, (row2) => findMap(row2.cells, (cell2) => {
    const elem = cell2.element;
    return someIf(isEditable(elem), elem);
  }));
  const elementFromGrid = (grid2, row2, column) => {
    var _a, _b;
    const rows2 = extractGridDetails(grid2).rows;
    return Optional.from((_b = (_a = rows2[row2]) === null || _a === void 0 ? void 0 : _a.cells[column]) === null || _b === void 0 ? void 0 : _b.element).filter(isEditable).orThunk(() => findEditableCursorPosition(rows2));
  };
  const bundle = (grid2, row2, column) => {
    const cursorElement = elementFromGrid(grid2, row2, column);
    return outcome(grid2, cursorElement);
  };
  const uniqueRows = (details) => {
    const rowCompilation = (rest, detail2) => {
      const rowExists = exists(rest, (currentDetail) => currentDetail.row === detail2.row);
      return rowExists ? rest : rest.concat([detail2]);
    };
    return foldl(details, rowCompilation, []).sort((detailA, detailB) => detailA.row - detailB.row);
  };
  const opInsertRowsBefore = (grid2, details, comparator, genWrappers) => {
    const targetIndex = details[0].row;
    const rows2 = uniqueRows(details);
    const newGrid = foldr(rows2, (acc, row2) => {
      const newG = insertRowAt(acc.grid, targetIndex, row2.row + acc.delta, comparator, genWrappers.getOrInit);
      return {
        grid: newG,
        delta: acc.delta + 1
      };
    }, {
      grid: grid2,
      delta: 0
    }).grid;
    return bundle(newGrid, targetIndex, details[0].column);
  };
  const opInsertRowsAfter = (grid2, details, comparator, genWrappers) => {
    const rows2 = uniqueRows(details);
    const target = rows2[rows2.length - 1];
    const targetIndex = target.row + target.rowspan;
    const newGrid = foldr(rows2, (newG, row2) => {
      return insertRowAt(newG, targetIndex, row2.row, comparator, genWrappers.getOrInit);
    }, grid2);
    return bundle(newGrid, targetIndex, details[0].column);
  };
  const opInsertColumnsBefore = (grid2, extractDetail, comparator, genWrappers) => {
    const details = extractDetail.details;
    const columns2 = uniqueColumns(details);
    const targetIndex = columns2[0].column;
    const newGrid = foldr(columns2, (acc, col2) => {
      const newG = insertColumnAt(acc.grid, targetIndex, col2.column + acc.delta, comparator, genWrappers.getOrInit);
      return {
        grid: newG,
        delta: acc.delta + 1
      };
    }, {
      grid: grid2,
      delta: 0
    }).grid;
    return bundle(newGrid, details[0].row, targetIndex);
  };
  const opInsertColumnsAfter = (grid2, extractDetail, comparator, genWrappers) => {
    const details = extractDetail.details;
    const target = details[details.length - 1];
    const targetIndex = target.column + target.colspan;
    const columns2 = uniqueColumns(details);
    const newGrid = foldr(columns2, (newG, col2) => {
      return insertColumnAt(newG, targetIndex, col2.column, comparator, genWrappers.getOrInit);
    }, grid2);
    return bundle(newGrid, details[0].row, targetIndex);
  };
  const opMakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => {
    const columns2 = uniqueColumns(details);
    const columnIndexes = map$1(columns2, (detail2) => detail2.column);
    const newGrid = replaceColumns(initialGrid, columnIndexes, true, comparator, genWrappers.replaceOrInit);
    return bundle(newGrid, details[0].row, details[0].column);
  };
  const opMakeCellsHeader = (initialGrid, details, comparator, genWrappers) => {
    const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit);
    return bundle(newGrid, details[0].row, details[0].column);
  };
  const opUnmakeColumnsHeader = (initialGrid, details, comparator, genWrappers) => {
    const columns2 = uniqueColumns(details);
    const columnIndexes = map$1(columns2, (detail2) => detail2.column);
    const newGrid = replaceColumns(initialGrid, columnIndexes, false, comparator, genWrappers.replaceOrInit);
    return bundle(newGrid, details[0].row, details[0].column);
  };
  const opUnmakeCellsHeader = (initialGrid, details, comparator, genWrappers) => {
    const newGrid = replaceCells(initialGrid, details, comparator, genWrappers.replaceOrInit);
    return bundle(newGrid, details[0].row, details[0].column);
  };
  const makeRowsSection = (section2, applyScope) => (initialGrid, details, comparator, genWrappers, tableSection) => {
    const rows2 = uniqueRows(details);
    const rowIndexes = map$1(rows2, (detail2) => detail2.row);
    const newGrid = replaceRows(initialGrid, rowIndexes, section2, applyScope, comparator, genWrappers.replaceOrInit, tableSection);
    return bundle(newGrid, details[0].row, details[0].column);
  };
  const opMakeRowsHeader = makeRowsSection("thead", true);
  const opMakeRowsBody = makeRowsSection("tbody", false);
  const opMakeRowsFooter = makeRowsSection("tfoot", false);
  const opEraseColumns = (grid2, extractDetail, _comparator, _genWrappers) => {
    const columns2 = uniqueColumns(extractDetail.details);
    const newGrid = deleteColumnsAt(grid2, map$1(columns2, (column) => column.column));
    const maxColIndex = newGrid.length > 0 ? newGrid[0].cells.length - 1 : 0;
    return bundle(newGrid, columns2[0].row, Math.min(columns2[0].column, maxColIndex));
  };
  const opEraseRows = (grid2, details, _comparator, _genWrappers) => {
    const rows2 = uniqueRows(details);
    const newGrid = deleteRowsAt(grid2, rows2[0].row, rows2[rows2.length - 1].row);
    const maxRowIndex = newGrid.length > 0 ? newGrid.length - 1 : 0;
    return bundle(newGrid, Math.min(details[0].row, maxRowIndex), details[0].column);
  };
  const opMergeCells = (grid2, mergable2, comparator, genWrappers) => {
    const cells2 = mergable2.cells;
    merge(cells2);
    const newGrid = merge$2(grid2, mergable2.bounds, comparator, genWrappers.merge(cells2));
    return outcome(newGrid, Optional.from(cells2[0]));
  };
  const opUnmergeCells = (grid2, unmergable2, comparator, genWrappers) => {
    const unmerge$1 = (b, cell2) => unmerge(b, cell2, comparator, genWrappers.unmerge(cell2));
    const newGrid = foldr(unmergable2, unmerge$1, grid2);
    return outcome(newGrid, Optional.from(unmergable2[0]));
  };
  const opPasteCells = (grid2, pasteDetails, comparator, _genWrappers) => {
    const gridify = (table2, generators) => {
      const wh = Warehouse.fromTable(table2);
      return toGrid(wh, generators, true);
    };
    const gridB = gridify(pasteDetails.clipboard, pasteDetails.generators);
    const startAddress = address(pasteDetails.row, pasteDetails.column);
    const mergedGrid = merge$1(startAddress, grid2, gridB, pasteDetails.generators, comparator);
    return mergedGrid.fold(() => outcome(grid2, Optional.some(pasteDetails.element)), (newGrid) => {
      return bundle(newGrid, pasteDetails.row, pasteDetails.column);
    });
  };
  const gridifyRows = (rows2, generators, context) => {
    const pasteDetails = fromPastedRows(rows2, context.section);
    const wh = Warehouse.generate(pasteDetails);
    return toGrid(wh, generators, true);
  };
  const opPasteColsBefore = (grid2, pasteDetails, comparator, _genWrappers) => {
    const rows2 = extractGridDetails(grid2).rows;
    const index2 = pasteDetails.cells[0].column;
    const context = rows2[pasteDetails.cells[0].row];
    const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context);
    const mergedGrid = insertCols(index2, grid2, gridB, pasteDetails.generators, comparator);
    return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column);
  };
  const opPasteColsAfter = (grid2, pasteDetails, comparator, _genWrappers) => {
    const rows2 = extractGridDetails(grid2).rows;
    const index2 = pasteDetails.cells[pasteDetails.cells.length - 1].column + pasteDetails.cells[pasteDetails.cells.length - 1].colspan;
    const context = rows2[pasteDetails.cells[0].row];
    const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context);
    const mergedGrid = insertCols(index2, grid2, gridB, pasteDetails.generators, comparator);
    return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column);
  };
  const opPasteRowsBefore = (grid2, pasteDetails, comparator, _genWrappers) => {
    const rows2 = extractGridDetails(grid2).rows;
    const index2 = pasteDetails.cells[0].row;
    const context = rows2[index2];
    const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context);
    const mergedGrid = insertRows(index2, grid2, gridB, pasteDetails.generators, comparator);
    return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column);
  };
  const opPasteRowsAfter = (grid2, pasteDetails, comparator, _genWrappers) => {
    const rows2 = extractGridDetails(grid2).rows;
    const index2 = pasteDetails.cells[pasteDetails.cells.length - 1].row + pasteDetails.cells[pasteDetails.cells.length - 1].rowspan;
    const context = rows2[pasteDetails.cells[0].row];
    const gridB = gridifyRows(pasteDetails.clipboard, pasteDetails.generators, context);
    const mergedGrid = insertRows(index2, grid2, gridB, pasteDetails.generators, comparator);
    return bundle(mergedGrid, pasteDetails.cells[0].row, pasteDetails.cells[0].column);
  };
  const opGetColumnsType = (table2, target) => {
    const house = Warehouse.fromTable(table2);
    const details = onCells(house, target);
    return details.bind((selectedCells) => {
      const lastSelectedCell = selectedCells[selectedCells.length - 1];
      const minColRange = selectedCells[0].column;
      const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan;
      const selectedColumnCells = flatten(map$1(house.all, (row2) => filter$2(row2.cells, (cell2) => cell2.column >= minColRange && cell2.column < maxColRange)));
      return findCommonCellType(selectedColumnCells);
    }).getOr("");
  };
  const opGetCellsType = (table2, target) => {
    const house = Warehouse.fromTable(table2);
    const details = onCells(house, target);
    return details.bind(findCommonCellType).getOr("");
  };
  const opGetRowsType = (table2, target) => {
    const house = Warehouse.fromTable(table2);
    const details = onCells(house, target);
    return details.bind((selectedCells) => {
      const lastSelectedCell = selectedCells[selectedCells.length - 1];
      const minRowRange = selectedCells[0].row;
      const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan;
      const selectedRows = house.all.slice(minRowRange, maxRowRange);
      return findCommonRowType(selectedRows);
    }).getOr("");
  };
  const resize = (table2, list, details, behaviours) => adjustWidthTo(table2, list, details, behaviours.sizing);
  const adjustAndRedistributeWidths = (table2, list, details, behaviours) => adjustAndRedistributeWidths$1(table2, list, details, behaviours.sizing, behaviours.resize);
  const firstColumnIsLocked = (_warehouse, details) => exists(details, (detail2) => detail2.column === 0 && detail2.isLocked);
  const lastColumnIsLocked = (warehouse, details) => exists(details, (detail2) => detail2.column + detail2.colspan >= warehouse.grid.columns && detail2.isLocked);
  const getColumnsWidth = (warehouse, details) => {
    const columns$12 = columns(warehouse);
    const uniqueCols = uniqueColumns(details);
    return foldl(uniqueCols, (acc, detail2) => {
      const column = columns$12[detail2.column];
      const colWidth = column.map(getOuter$2).getOr(0);
      return acc + colWidth;
    }, 0);
  };
  const insertColumnsExtractor = (before2) => (warehouse, target) => onCells(warehouse, target).filter((details) => {
    const checkLocked = before2 ? firstColumnIsLocked : lastColumnIsLocked;
    return !checkLocked(warehouse, details);
  }).map((details) => ({
    details,
    pixelDelta: getColumnsWidth(warehouse, details)
  }));
  const eraseColumnsExtractor = (warehouse, target) => onUnlockedCells(warehouse, target).map((details) => ({
    details,
    pixelDelta: -getColumnsWidth(warehouse, details)
  }));
  const pasteColumnsExtractor = (before2) => (warehouse, target) => onPasteByEditor(warehouse, target).filter((details) => {
    const checkLocked = before2 ? firstColumnIsLocked : lastColumnIsLocked;
    return !checkLocked(warehouse, details.cells);
  });
  const headerCellGenerator = Generators.transform("th");
  const bodyCellGenerator = Generators.transform("td");
  const insertRowsBefore = run(opInsertRowsBefore, onCells, noop, noop, Generators.modification);
  const insertRowsAfter = run(opInsertRowsAfter, onCells, noop, noop, Generators.modification);
  const insertColumnsBefore = run(opInsertColumnsBefore, insertColumnsExtractor(true), adjustAndRedistributeWidths, noop, Generators.modification);
  const insertColumnsAfter = run(opInsertColumnsAfter, insertColumnsExtractor(false), adjustAndRedistributeWidths, noop, Generators.modification);
  const eraseColumns = run(opEraseColumns, eraseColumnsExtractor, adjustAndRedistributeWidths, prune, Generators.modification);
  const eraseRows = run(opEraseRows, onCells, noop, prune, Generators.modification);
  const makeColumnsHeader = run(opMakeColumnsHeader, onUnlockedCells, noop, noop, headerCellGenerator);
  const unmakeColumnsHeader = run(opUnmakeColumnsHeader, onUnlockedCells, noop, noop, bodyCellGenerator);
  const makeRowsHeader = run(opMakeRowsHeader, onUnlockedCells, noop, noop, headerCellGenerator);
  const makeRowsBody = run(opMakeRowsBody, onUnlockedCells, noop, noop, bodyCellGenerator);
  const makeRowsFooter = run(opMakeRowsFooter, onUnlockedCells, noop, noop, bodyCellGenerator);
  const makeCellsHeader = run(opMakeCellsHeader, onUnlockedCells, noop, noop, headerCellGenerator);
  const unmakeCellsHeader = run(opUnmakeCellsHeader, onUnlockedCells, noop, noop, bodyCellGenerator);
  const mergeCells = run(opMergeCells, onUnlockedMergable, resize, noop, Generators.merging);
  const unmergeCells = run(opUnmergeCells, onUnlockedUnmergable, resize, noop, Generators.merging);
  const pasteCells = run(opPasteCells, onPaste, resize, noop, Generators.modification);
  const pasteColsBefore = run(opPasteColsBefore, pasteColumnsExtractor(true), noop, noop, Generators.modification);
  const pasteColsAfter = run(opPasteColsAfter, pasteColumnsExtractor(false), noop, noop, Generators.modification);
  const pasteRowsBefore = run(opPasteRowsBefore, onPasteByEditor, noop, noop, Generators.modification);
  const pasteRowsAfter = run(opPasteRowsAfter, onPasteByEditor, noop, noop, Generators.modification);
  const getColumnsType = opGetColumnsType;
  const getCellsType = opGetCellsType;
  const getRowsType = opGetRowsType;
  const fireNewRow = (editor, row2) => editor.dispatch("NewRow", { node: row2 });
  const fireNewCell = (editor, cell2) => editor.dispatch("NewCell", { node: cell2 });
  const fireTableModified = (editor, table2, data) => {
    editor.dispatch("TableModified", {
      ...data,
      table: table2
    });
  };
  const fireTableSelectionChange = (editor, cells2, start, finish, otherCells) => {
    editor.dispatch("TableSelectionChange", {
      cells: cells2,
      start,
      finish,
      otherCells
    });
  };
  const fireTableSelectionClear = (editor) => {
    editor.dispatch("TableSelectionClear");
  };
  const fireObjectResizeStart = (editor, target, width2, height2, origin) => {
    editor.dispatch("ObjectResizeStart", {
      target,
      width: width2,
      height: height2,
      origin
    });
  };
  const fireObjectResized = (editor, target, width2, height2, origin) => {
    editor.dispatch("ObjectResized", {
      target,
      width: width2,
      height: height2,
      origin
    });
  };
  const styleModified = {
    structure: false,
    style: true
  };
  const structureModified = {
    structure: true,
    style: false
  };
  const styleAndStructureModified = {
    structure: true,
    style: true
  };
  const option = (name2) => (editor) => editor.options.get(name2);
  const defaultWidth = "100%";
  const getPixelForcedWidth = (editor) => {
    var _a;
    const dom = editor.dom;
    const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody();
    return getInner(SugarElement.fromDom(parentBlock)) + "px";
  };
  const determineDefaultTableStyles = (editor, defaultStyles) => {
    if (isTableResponsiveForced(editor) || !shouldStyleWithCss(editor)) {
      return defaultStyles;
    } else if (isTablePixelsForced(editor)) {
      return {
        ...defaultStyles,
        width: getPixelForcedWidth(editor)
      };
    } else {
      return {
        ...defaultStyles,
        width: defaultWidth
      };
    }
  };
  const determineDefaultTableAttributes = (editor, defaultAttributes) => {
    if (isTableResponsiveForced(editor) || shouldStyleWithCss(editor)) {
      return defaultAttributes;
    } else if (isTablePixelsForced(editor)) {
      return {
        ...defaultAttributes,
        width: getPixelForcedWidth(editor)
      };
    } else {
      return {
        ...defaultAttributes,
        width: defaultWidth
      };
    }
  };
  const register = (editor) => {
    const registerOption = editor.options.register;
    registerOption("table_clone_elements", { processor: "string[]" });
    registerOption("table_use_colgroups", {
      processor: "boolean",
      default: true
    });
    registerOption("table_header_type", {
      processor: (value2) => {
        const valid = contains$2([
          "section",
          "cells",
          "sectionCells",
          "auto"
        ], value2);
        return valid ? {
          value: value2,
          valid
        } : {
          valid: false,
          message: "Must be one of: section, cells, sectionCells or auto."
        };
      },
      default: "section"
    });
    registerOption("table_sizing_mode", {
      processor: "string",
      default: "auto"
    });
    registerOption("table_default_attributes", {
      processor: "object",
      default: { border: "1" }
    });
    registerOption("table_default_styles", {
      processor: "object",
      default: { "border-collapse": "collapse" }
    });
    registerOption("table_column_resizing", {
      processor: (value2) => {
        const valid = contains$2([
          "preservetable",
          "resizetable"
        ], value2);
        return valid ? {
          value: value2,
          valid
        } : {
          valid: false,
          message: "Must be preservetable, or resizetable."
        };
      },
      default: "preservetable"
    });
    registerOption("table_resize_bars", {
      processor: "boolean",
      default: true
    });
    registerOption("table_style_by_css", {
      processor: "boolean",
      default: true
    });
  };
  const getTableCloneElements = (editor) => {
    return Optional.from(editor.options.get("table_clone_elements"));
  };
  const hasTableObjectResizing = (editor) => {
    const objectResizing = editor.options.get("object_resizing");
    return contains$2(objectResizing.split(","), "table");
  };
  const getTableHeaderType = option("table_header_type");
  const getTableColumnResizingBehaviour = option("table_column_resizing");
  const isPreserveTableColumnResizing = (editor) => getTableColumnResizingBehaviour(editor) === "preservetable";
  const isResizeTableColumnResizing = (editor) => getTableColumnResizingBehaviour(editor) === "resizetable";
  const getTableSizingMode = option("table_sizing_mode");
  const isTablePercentagesForced = (editor) => getTableSizingMode(editor) === "relative";
  const isTablePixelsForced = (editor) => getTableSizingMode(editor) === "fixed";
  const isTableResponsiveForced = (editor) => getTableSizingMode(editor) === "responsive";
  const hasTableResizeBars = option("table_resize_bars");
  const shouldStyleWithCss = option("table_style_by_css");
  const getTableDefaultAttributes = (editor) => {
    const options = editor.options;
    const defaultAttributes = options.get("table_default_attributes");
    return options.isSet("table_default_attributes") ? defaultAttributes : determineDefaultTableAttributes(editor, defaultAttributes);
  };
  const getTableDefaultStyles = (editor) => {
    const options = editor.options;
    const defaultStyles = options.get("table_default_styles");
    return options.isSet("table_default_styles") ? defaultStyles : determineDefaultTableStyles(editor, defaultStyles);
  };
  const tableUseColumnGroup = option("table_use_colgroups");
  const get$5 = (editor, table2) => {
    if (isTablePercentagesForced(editor)) {
      return TableSize.percentageSize(table2);
    } else if (isTablePixelsForced(editor)) {
      return TableSize.pixelSize(table2);
    } else {
      return TableSize.getTableSize(table2);
    }
  };
  const TableActions = (editor, resizeHandler, cellSelectionHandler) => {
    const isTableBody = (editor2) => name(getBody(editor2)) === "table";
    const lastRowGuard = (table2) => isTableBody(editor) === false || getGridSize(table2).rows > 1;
    const lastColumnGuard = (table2) => isTableBody(editor) === false || getGridSize(table2).columns > 1;
    const cloneFormats2 = getTableCloneElements(editor);
    const colMutationOp = isResizeTableColumnResizing(editor) ? noop : halve;
    const getTableSectionType2 = (table2) => {
      switch (getTableHeaderType(editor)) {
        case "section":
          return TableSection.section();
        case "sectionCells":
          return TableSection.sectionCells();
        case "cells":
          return TableSection.cells();
        default:
          return TableSection.getTableSectionType(table2, "section");
      }
    };
    const setSelectionFromAction = (table2, result) => result.cursor.fold(() => {
      const cells2 = cells$1(table2);
      return head(cells2).filter(inBody).map((firstCell) => {
        cellSelectionHandler.clearSelectedCells(table2.dom);
        const rng = editor.dom.createRng();
        rng.selectNode(firstCell.dom);
        editor.selection.setRng(rng);
        set$2(firstCell, "data-mce-selected", "1");
        return rng;
      });
    }, (cell2) => {
      const des = freefallRtl(cell2);
      const rng = editor.dom.createRng();
      rng.setStart(des.element.dom, des.offset);
      rng.setEnd(des.element.dom, des.offset);
      editor.selection.setRng(rng);
      cellSelectionHandler.clearSelectedCells(table2.dom);
      return Optional.some(rng);
    });
    const execute = (operation, guard, mutate2, effect) => (table2, target, noEvents = false) => {
      removeDataStyle(table2);
      const doc = SugarElement.fromDom(editor.getDoc());
      const generators = cellOperations(mutate2, doc, cloneFormats2);
      const behaviours = {
        sizing: get$5(editor, table2),
        resize: isResizeTableColumnResizing(editor) ? resizeTable() : preserveTable(),
        section: getTableSectionType2(table2)
      };
      return guard(table2) ? operation(table2, target, generators, behaviours).bind((result) => {
        resizeHandler.refresh(table2.dom);
        each$2(result.newRows, (row2) => {
          fireNewRow(editor, row2.dom);
        });
        each$2(result.newCells, (cell2) => {
          fireNewCell(editor, cell2.dom);
        });
        const range2 = setSelectionFromAction(table2, result);
        if (inBody(table2)) {
          removeDataStyle(table2);
          if (!noEvents) {
            fireTableModified(editor, table2.dom, effect);
          }
        }
        return range2.map((rng) => ({
          rng,
          effect
        }));
      }) : Optional.none();
    };
    const deleteRow = execute(eraseRows, lastRowGuard, noop, structureModified);
    const deleteColumn = execute(eraseColumns, lastColumnGuard, noop, structureModified);
    const insertRowsBefore$1 = execute(insertRowsBefore, always, noop, structureModified);
    const insertRowsAfter$1 = execute(insertRowsAfter, always, noop, structureModified);
    const insertColumnsBefore$1 = execute(insertColumnsBefore, always, colMutationOp, structureModified);
    const insertColumnsAfter$1 = execute(insertColumnsAfter, always, colMutationOp, structureModified);
    const mergeCells$1 = execute(mergeCells, always, noop, structureModified);
    const unmergeCells$1 = execute(unmergeCells, always, noop, structureModified);
    const pasteColsBefore$1 = execute(pasteColsBefore, always, noop, structureModified);
    const pasteColsAfter$1 = execute(pasteColsAfter, always, noop, structureModified);
    const pasteRowsBefore$1 = execute(pasteRowsBefore, always, noop, structureModified);
    const pasteRowsAfter$1 = execute(pasteRowsAfter, always, noop, structureModified);
    const pasteCells$1 = execute(pasteCells, always, noop, styleAndStructureModified);
    const makeCellsHeader$1 = execute(makeCellsHeader, always, noop, structureModified);
    const unmakeCellsHeader$1 = execute(unmakeCellsHeader, always, noop, structureModified);
    const makeColumnsHeader$1 = execute(makeColumnsHeader, always, noop, structureModified);
    const unmakeColumnsHeader$1 = execute(unmakeColumnsHeader, always, noop, structureModified);
    const makeRowsHeader$1 = execute(makeRowsHeader, always, noop, structureModified);
    const makeRowsBody$1 = execute(makeRowsBody, always, noop, structureModified);
    const makeRowsFooter$1 = execute(makeRowsFooter, always, noop, structureModified);
    const getTableCellType = getCellsType;
    const getTableColType = getColumnsType;
    const getTableRowType = getRowsType;
    return {
      deleteRow,
      deleteColumn,
      insertRowsBefore: insertRowsBefore$1,
      insertRowsAfter: insertRowsAfter$1,
      insertColumnsBefore: insertColumnsBefore$1,
      insertColumnsAfter: insertColumnsAfter$1,
      mergeCells: mergeCells$1,
      unmergeCells: unmergeCells$1,
      pasteColsBefore: pasteColsBefore$1,
      pasteColsAfter: pasteColsAfter$1,
      pasteRowsBefore: pasteRowsBefore$1,
      pasteRowsAfter: pasteRowsAfter$1,
      pasteCells: pasteCells$1,
      makeCellsHeader: makeCellsHeader$1,
      unmakeCellsHeader: unmakeCellsHeader$1,
      makeColumnsHeader: makeColumnsHeader$1,
      unmakeColumnsHeader: unmakeColumnsHeader$1,
      makeRowsHeader: makeRowsHeader$1,
      makeRowsBody: makeRowsBody$1,
      makeRowsFooter: makeRowsFooter$1,
      getTableRowType,
      getTableCellType,
      getTableColType
    };
  };
  const constrainSpan = (element, property, value2) => {
    const currentColspan = getAttrValue(element, property, 1);
    if (value2 === 1 || currentColspan <= 1) {
      remove$7(element, property);
    } else {
      set$2(element, property, Math.min(value2, currentColspan));
    }
  };
  const isColInRange = (minColRange, maxColRange) => (cell2) => {
    const endCol = cell2.column + cell2.colspan - 1;
    const startCol = cell2.column;
    return endCol >= minColRange && startCol < maxColRange;
  };
  const generateColGroup = (house, minColRange, maxColRange) => {
    if (Warehouse.hasColumns(house)) {
      const colsToCopy = filter$2(Warehouse.justColumns(house), isColInRange(minColRange, maxColRange));
      const copiedCols = map$1(colsToCopy, (c) => {
        const clonedCol = deep(c.element);
        constrainSpan(clonedCol, "span", maxColRange - minColRange);
        return clonedCol;
      });
      const fakeColgroup = SugarElement.fromTag("colgroup");
      append(fakeColgroup, copiedCols);
      return [fakeColgroup];
    } else {
      return [];
    }
  };
  const generateRows = (house, minColRange, maxColRange) => map$1(house.all, (row2) => {
    const cellsToCopy = filter$2(row2.cells, isColInRange(minColRange, maxColRange));
    const copiedCells = map$1(cellsToCopy, (cell2) => {
      const clonedCell = deep(cell2.element);
      constrainSpan(clonedCell, "colspan", maxColRange - minColRange);
      return clonedCell;
    });
    const fakeTR = SugarElement.fromTag("tr");
    append(fakeTR, copiedCells);
    return fakeTR;
  });
  const copyCols = (table2, target) => {
    const house = Warehouse.fromTable(table2);
    const details = onUnlockedCells(house, target);
    return details.map((selectedCells) => {
      const lastSelectedCell = selectedCells[selectedCells.length - 1];
      const minColRange = selectedCells[0].column;
      const maxColRange = lastSelectedCell.column + lastSelectedCell.colspan;
      const fakeColGroups = generateColGroup(house, minColRange, maxColRange);
      const fakeRows = generateRows(house, minColRange, maxColRange);
      return [
        ...fakeColGroups,
        ...fakeRows
      ];
    });
  };
  const copyRows = (table2, target, generators) => {
    const warehouse = Warehouse.fromTable(table2);
    const details = onCells(warehouse, target);
    return details.bind((selectedCells) => {
      const grid2 = toGrid(warehouse, generators, false);
      const rows2 = extractGridDetails(grid2).rows;
      const slicedGrid = rows2.slice(selectedCells[0].row, selectedCells[selectedCells.length - 1].row + selectedCells[selectedCells.length - 1].rowspan);
      const filteredGrid = bind$2(slicedGrid, (row2) => {
        const newCells = filter$2(row2.cells, (cell2) => !cell2.isLocked);
        return newCells.length > 0 ? [{
          ...row2,
          cells: newCells
        }] : [];
      });
      const slicedDetails = toDetailList(filteredGrid);
      return someIf(slicedDetails.length > 0, slicedDetails);
    }).map((slicedDetails) => copy(slicedDetails));
  };
  const adt$5 = Adt.generate([
    { invalid: ["raw"] },
    { pixels: ["value"] },
    { percent: ["value"] }
  ]);
  const validateFor = (suffix, type2, value2) => {
    const rawAmount = value2.substring(0, value2.length - suffix.length);
    const amount = parseFloat(rawAmount);
    return rawAmount === amount.toString() ? type2(amount) : adt$5.invalid(value2);
  };
  const from = (value2) => {
    if (endsWith(value2, "%")) {
      return validateFor("%", adt$5.percent, value2);
    }
    if (endsWith(value2, "px")) {
      return validateFor("px", adt$5.pixels, value2);
    }
    return adt$5.invalid(value2);
  };
  const Size = {
    ...adt$5,
    from
  };
  const redistributeToPercent = (widths, totalWidth) => {
    return map$1(widths, (w) => {
      const colType = Size.from(w);
      return colType.fold(() => {
        return w;
      }, (px) => {
        const ratio = px / totalWidth * 100;
        return ratio + "%";
      }, (pc) => {
        return pc + "%";
      });
    });
  };
  const redistributeToPx = (widths, totalWidth, newTotalWidth) => {
    const scale = newTotalWidth / totalWidth;
    return map$1(widths, (w) => {
      const colType = Size.from(w);
      return colType.fold(() => {
        return w;
      }, (px) => {
        return px * scale + "px";
      }, (pc) => {
        return pc / 100 * newTotalWidth + "px";
      });
    });
  };
  const redistributeEmpty = (newWidthType, columns2) => {
    const f = newWidthType.fold(() => constant(""), (pixels) => {
      const num = pixels / columns2;
      return constant(num + "px");
    }, () => {
      const num = 100 / columns2;
      return constant(num + "%");
    });
    return range$1(columns2, f);
  };
  const redistributeValues = (newWidthType, widths, totalWidth) => {
    return newWidthType.fold(() => {
      return widths;
    }, (px) => {
      return redistributeToPx(widths, totalWidth, px);
    }, (_pc) => {
      return redistributeToPercent(widths, totalWidth);
    });
  };
  const redistribute$1 = (widths, totalWidth, newWidth) => {
    const newType = Size.from(newWidth);
    const floats = forall(widths, (s) => {
      return s === "0px";
    }) ? redistributeEmpty(newType, widths.length) : redistributeValues(newType, widths, totalWidth);
    return normalize(floats);
  };
  const sum = (values2, fallback2) => {
    if (values2.length === 0) {
      return fallback2;
    }
    return foldr(values2, (rest, v) => {
      return Size.from(v).fold(constant(0), identity, identity) + rest;
    }, 0);
  };
  const roundDown = (num, unit) => {
    const floored = Math.floor(num);
    return {
      value: floored + unit,
      remainder: num - floored
    };
  };
  const add$3 = (value2, amount) => {
    return Size.from(value2).fold(constant(value2), (px) => {
      return px + amount + "px";
    }, (pc) => {
      return pc + amount + "%";
    });
  };
  const normalize = (values2) => {
    if (values2.length === 0) {
      return values2;
    }
    const scan2 = foldr(values2, (rest, value2) => {
      const info = Size.from(value2).fold(() => ({
        value: value2,
        remainder: 0
      }), (num) => roundDown(num, "px"), (num) => ({
        value: num + "%",
        remainder: 0
      }));
      return {
        output: [info.value].concat(rest.output),
        remainder: rest.remainder + info.remainder
      };
    }, {
      output: [],
      remainder: 0
    });
    const r2 = scan2.output;
    return r2.slice(0, r2.length - 1).concat([add$3(r2[r2.length - 1], Math.round(scan2.remainder))]);
  };
  const validate = Size.from;
  const redistributeToW = (newWidths, cells2, unit) => {
    each$2(cells2, (cell2) => {
      const widths = newWidths.slice(cell2.column, cell2.colspan + cell2.column);
      const w = sum(widths, minWidth());
      set$1(cell2.element, "width", w + unit);
    });
  };
  const redistributeToColumns = (newWidths, columns2, unit) => {
    each$2(columns2, (column, index2) => {
      const width2 = sum([newWidths[index2]], minWidth());
      set$1(column.element, "width", width2 + unit);
    });
  };
  const redistributeToH = (newHeights, rows2, cells2, unit) => {
    each$2(cells2, (cell2) => {
      const heights = newHeights.slice(cell2.row, cell2.rowspan + cell2.row);
      const h2 = sum(heights, minHeight());
      set$1(cell2.element, "height", h2 + unit);
    });
    each$2(rows2, (row2, i) => {
      set$1(row2.element, "height", newHeights[i]);
    });
  };
  const getUnit = (newSize) => {
    return validate(newSize).fold(constant("px"), constant("px"), constant("%"));
  };
  const redistribute = (table2, optWidth, optHeight) => {
    const warehouse = Warehouse.fromTable(table2);
    const rows2 = warehouse.all;
    const cells2 = Warehouse.justCells(warehouse);
    const columns2 = Warehouse.justColumns(warehouse);
    optWidth.each((newWidth) => {
      const widthUnit = getUnit(newWidth);
      const totalWidth = get$9(table2);
      const oldWidths = getRawWidths(warehouse, table2);
      const nuWidths = redistribute$1(oldWidths, totalWidth, newWidth);
      if (Warehouse.hasColumns(warehouse)) {
        redistributeToColumns(nuWidths, columns2, widthUnit);
      } else {
        redistributeToW(nuWidths, cells2, widthUnit);
      }
      set$1(table2, "width", newWidth);
    });
    optHeight.each((newHeight) => {
      const hUnit = getUnit(newHeight);
      const totalHeight = get$8(table2);
      const oldHeights = getRawHeights(warehouse, table2, height);
      const nuHeights = redistribute$1(oldHeights, totalHeight, newHeight);
      redistributeToH(nuHeights, rows2, cells2, hUnit);
      set$1(table2, "height", newHeight);
    });
  };
  const isPercentSizing = isPercentSizing$1;
  const isPixelSizing = isPixelSizing$1;
  const isNoneSizing = isNoneSizing$1;
  const cleanupLegacyAttributes = (element) => {
    remove$7(element, "width");
  };
  const convertToPercentSize = (table2) => {
    const newWidth = getPercentTableWidth(table2);
    redistribute(table2, Optional.some(newWidth), Optional.none());
    cleanupLegacyAttributes(table2);
  };
  const convertToPixelSize = (table2) => {
    const newWidth = getPixelTableWidth(table2);
    redistribute(table2, Optional.some(newWidth), Optional.none());
    cleanupLegacyAttributes(table2);
  };
  const convertToNoneSize = (table2) => {
    remove$5(table2, "width");
    const columns2 = columns$1(table2);
    const rowElements = columns2.length > 0 ? columns2 : cells$1(table2);
    each$2(rowElements, (cell2) => {
      remove$5(cell2, "width");
      cleanupLegacyAttributes(cell2);
    });
    cleanupLegacyAttributes(table2);
  };
  const DefaultRenderOptions = {
    styles: {
      "border-collapse": "collapse",
      "width": "100%"
    },
    attributes: { border: "1" },
    colGroups: false
  };
  const tableHeaderCell = () => SugarElement.fromTag("th");
  const tableCell = () => SugarElement.fromTag("td");
  const tableColumn = () => SugarElement.fromTag("col");
  const createRow = (columns2, rowHeaders, columnHeaders, rowIndex) => {
    const tr = SugarElement.fromTag("tr");
    for (let j = 0; j < columns2; j++) {
      const td = rowIndex < rowHeaders || j < columnHeaders ? tableHeaderCell() : tableCell();
      if (j < columnHeaders) {
        set$2(td, "scope", "row");
      }
      if (rowIndex < rowHeaders) {
        set$2(td, "scope", "col");
      }
      append$1(td, SugarElement.fromTag("br"));
      append$1(tr, td);
    }
    return tr;
  };
  const createGroupRow = (columns2) => {
    const columnGroup = SugarElement.fromTag("colgroup");
    range$1(columns2, () => append$1(columnGroup, tableColumn()));
    return columnGroup;
  };
  const createRows = (rows2, columns2, rowHeaders, columnHeaders) => range$1(rows2, (r2) => createRow(columns2, rowHeaders, columnHeaders, r2));
  const render = (rows2, columns2, rowHeaders, columnHeaders, headerType, renderOpts = DefaultRenderOptions) => {
    const table2 = SugarElement.fromTag("table");
    const rowHeadersGoInThead = headerType !== "cells";
    setAll(table2, renderOpts.styles);
    setAll$1(table2, renderOpts.attributes);
    if (renderOpts.colGroups) {
      append$1(table2, createGroupRow(columns2));
    }
    const actualRowHeaders = Math.min(rows2, rowHeaders);
    if (rowHeadersGoInThead && rowHeaders > 0) {
      const thead = SugarElement.fromTag("thead");
      append$1(table2, thead);
      const theadRowHeaders = headerType === "sectionCells" ? actualRowHeaders : 0;
      const theadRows = createRows(rowHeaders, columns2, theadRowHeaders, columnHeaders);
      append(thead, theadRows);
    }
    const tbody = SugarElement.fromTag("tbody");
    append$1(table2, tbody);
    const numRows = rowHeadersGoInThead ? rows2 - actualRowHeaders : rows2;
    const numRowHeaders = rowHeadersGoInThead ? 0 : rowHeaders;
    const tbodyRows = createRows(numRows, columns2, numRowHeaders, columnHeaders);
    append(tbody, tbodyRows);
    return table2;
  };
  const get$4 = (element) => element.dom.innerHTML;
  const getOuter = (element) => {
    const container = SugarElement.fromTag("div");
    const clone2 = SugarElement.fromDom(element.dom.cloneNode(true));
    append$1(container, clone2);
    return get$4(container);
  };
  const placeCaretInCell = (editor, cell2) => {
    editor.selection.select(cell2.dom, true);
    editor.selection.collapse(true);
  };
  const selectFirstCellInTable = (editor, tableElm) => {
    descendant(tableElm, "td,th").each(curry(placeCaretInCell, editor));
  };
  const fireEvents = (editor, table2) => {
    each$2(descendants(table2, "tr"), (row2) => {
      fireNewRow(editor, row2.dom);
      each$2(descendants(row2, "th,td"), (cell2) => {
        fireNewCell(editor, cell2.dom);
      });
    });
  };
  const isPercentage = (width2) => isString(width2) && width2.indexOf("%") !== -1;
  const insert = (editor, columns2, rows2, colHeaders, rowHeaders) => {
    const defaultStyles = getTableDefaultStyles(editor);
    const options = {
      styles: defaultStyles,
      attributes: getTableDefaultAttributes(editor),
      colGroups: tableUseColumnGroup(editor)
    };
    editor.undoManager.ignore(() => {
      const table2 = render(rows2, columns2, rowHeaders, colHeaders, getTableHeaderType(editor), options);
      set$2(table2, "data-mce-id", "__mce");
      const html = getOuter(table2);
      editor.insertContent(html);
      editor.addVisual();
    });
    return descendant(getBody(editor), 'table[data-mce-id="__mce"]').map((table2) => {
      if (isTablePixelsForced(editor)) {
        convertToPixelSize(table2);
      } else if (isTableResponsiveForced(editor)) {
        convertToNoneSize(table2);
      } else if (isTablePercentagesForced(editor) || isPercentage(defaultStyles.width)) {
        convertToPercentSize(table2);
      }
      removeDataStyle(table2);
      remove$7(table2, "data-mce-id");
      fireEvents(editor, table2);
      selectFirstCellInTable(editor, table2);
      return table2.dom;
    }).getOr(null);
  };
  const insertTable = (editor, rows2, columns2, options = {}) => {
    const checkInput = (val) => isNumber(val) && val > 0;
    if (checkInput(rows2) && checkInput(columns2)) {
      const headerRows = options.headerRows || 0;
      const headerColumns = options.headerColumns || 0;
      return insert(editor, columns2, rows2, headerColumns, headerRows);
    } else {
      console.error("Invalid values for mceInsertTable - rows and columns values are required to insert a table.");
      return null;
    }
  };
  var global2 = tinymce.util.Tools.resolve("tinymce.FakeClipboard");
  const tableTypeBase = "x-tinymce/dom-table-";
  const tableTypeRow = tableTypeBase + "rows";
  const tableTypeColumn = tableTypeBase + "columns";
  const setData = (items) => {
    const fakeClipboardItem = global2.FakeClipboardItem(items);
    global2.write([fakeClipboardItem]);
  };
  const getData = (type2) => {
    var _a;
    const items = (_a = global2.read()) !== null && _a !== void 0 ? _a : [];
    return findMap(items, (item) => Optional.from(item.getType(type2)));
  };
  const clearData = (type2) => {
    if (getData(type2).isSome()) {
      global2.clear();
    }
  };
  const setRows = (rowsOpt) => {
    rowsOpt.fold(clearRows, (rows2) => setData({ [tableTypeRow]: rows2 }));
  };
  const getRows = () => getData(tableTypeRow);
  const clearRows = () => clearData(tableTypeRow);
  const setColumns = (columnsOpt) => {
    columnsOpt.fold(clearColumns, (columns2) => setData({ [tableTypeColumn]: columns2 }));
  };
  const getColumns = () => getData(tableTypeColumn);
  const clearColumns = () => clearData(tableTypeColumn);
  const getSelectionStartCellOrCaption = (editor) => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor));
  const getSelectionStartCell = (editor) => getSelectionCell(getSelectionStart(editor), getIsRoot(editor));
  const registerCommands = (editor, actions) => {
    const isRoot = getIsRoot(editor);
    const eraseTable = () => getSelectionStartCellOrCaption(editor).each((cellOrCaption) => {
      table(cellOrCaption, isRoot).filter(not(isRoot)).each((table2) => {
        const cursor = SugarElement.fromText("");
        after$5(table2, cursor);
        remove$6(table2);
        if (editor.dom.isEmpty(editor.getBody())) {
          editor.setContent("");
          editor.selection.setCursorLocation();
        } else {
          const rng = editor.dom.createRng();
          rng.setStart(cursor.dom, 0);
          rng.setEnd(cursor.dom, 0);
          editor.selection.setRng(rng);
          editor.nodeChanged();
        }
      });
    });
    const setSizingMode = (sizing) => getSelectionStartCellOrCaption(editor).each((cellOrCaption) => {
      const isForcedSizing = isTableResponsiveForced(editor) || isTablePixelsForced(editor) || isTablePercentagesForced(editor);
      if (!isForcedSizing) {
        table(cellOrCaption, isRoot).each((table2) => {
          if (sizing === "relative" && !isPercentSizing(table2)) {
            convertToPercentSize(table2);
          } else if (sizing === "fixed" && !isPixelSizing(table2)) {
            convertToPixelSize(table2);
          } else if (sizing === "responsive" && !isNoneSizing(table2)) {
            convertToNoneSize(table2);
          }
          removeDataStyle(table2);
          fireTableModified(editor, table2.dom, structureModified);
        });
      }
    });
    const getTableFromCell = (cell2) => table(cell2, isRoot);
    const performActionOnSelection = (action) => getSelectionStartCell(editor).bind((cell2) => getTableFromCell(cell2).map((table2) => action(table2, cell2)));
    const toggleTableClass = (_ui, clazz) => {
      performActionOnSelection((table2) => {
        editor.formatter.toggle("tableclass", { value: clazz }, table2.dom);
        fireTableModified(editor, table2.dom, styleModified);
      });
    };
    const toggleTableCellClass = (_ui, clazz) => {
      performActionOnSelection((table2) => {
        const selectedCells = getCellsFromSelection(editor);
        const allHaveClass = forall(selectedCells, (cell2) => editor.formatter.match("tablecellclass", { value: clazz }, cell2.dom));
        const formatterAction = allHaveClass ? editor.formatter.remove : editor.formatter.apply;
        each$2(selectedCells, (cell2) => formatterAction("tablecellclass", { value: clazz }, cell2.dom));
        fireTableModified(editor, table2.dom, styleModified);
      });
    };
    const toggleCaption = () => {
      getSelectionStartCellOrCaption(editor).each((cellOrCaption) => {
        table(cellOrCaption, isRoot).each((table2) => {
          child(table2, "caption").fold(() => {
            const caption = SugarElement.fromTag("caption");
            append$1(caption, SugarElement.fromText("Caption"));
            appendAt(table2, caption, 0);
            editor.selection.setCursorLocation(caption.dom, 0);
          }, (caption) => {
            if (isTag("caption")(cellOrCaption)) {
              one("td", table2).each((td) => editor.selection.setCursorLocation(td.dom, 0));
            }
            remove$6(caption);
          });
          fireTableModified(editor, table2.dom, structureModified);
        });
      });
    };
    const postExecute = (_data) => {
      editor.focus();
    };
    const actOnSelection = (execute, noEvents = false) => performActionOnSelection((table2, startCell) => {
      const targets = forMenu(getCellsFromSelection(editor), table2, startCell);
      execute(table2, targets, noEvents).each(postExecute);
    });
    const copyRowSelection = () => performActionOnSelection((table2, startCell) => {
      const targets = forMenu(getCellsFromSelection(editor), table2, startCell);
      const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), Optional.none());
      return copyRows(table2, targets, generators);
    });
    const copyColSelection = () => performActionOnSelection((table2, startCell) => {
      const targets = forMenu(getCellsFromSelection(editor), table2, startCell);
      return copyCols(table2, targets);
    });
    const pasteOnSelection = (execute, getRows2) => getRows2().each((rows2) => {
      const clonedRows = map$1(rows2, (row2) => deep(row2));
      performActionOnSelection((table2, startCell) => {
        const generators = paste$1(SugarElement.fromDom(editor.getDoc()));
        const targets = pasteRows(getCellsFromSelection(editor), startCell, clonedRows, generators);
        execute(table2, targets).each(postExecute);
      });
    });
    const actOnType = (getAction) => (_ui, args) => get$c(args, "type").each((type2) => {
      actOnSelection(getAction(type2), args.no_events);
    });
    each$1({
      mceTableSplitCells: () => actOnSelection(actions.unmergeCells),
      mceTableMergeCells: () => actOnSelection(actions.mergeCells),
      mceTableInsertRowBefore: () => actOnSelection(actions.insertRowsBefore),
      mceTableInsertRowAfter: () => actOnSelection(actions.insertRowsAfter),
      mceTableInsertColBefore: () => actOnSelection(actions.insertColumnsBefore),
      mceTableInsertColAfter: () => actOnSelection(actions.insertColumnsAfter),
      mceTableDeleteCol: () => actOnSelection(actions.deleteColumn),
      mceTableDeleteRow: () => actOnSelection(actions.deleteRow),
      mceTableCutCol: () => copyColSelection().each((selection2) => {
        setColumns(selection2);
        actOnSelection(actions.deleteColumn);
      }),
      mceTableCutRow: () => copyRowSelection().each((selection2) => {
        setRows(selection2);
        actOnSelection(actions.deleteRow);
      }),
      mceTableCopyCol: () => copyColSelection().each((selection2) => setColumns(selection2)),
      mceTableCopyRow: () => copyRowSelection().each((selection2) => setRows(selection2)),
      mceTablePasteColBefore: () => pasteOnSelection(actions.pasteColsBefore, getColumns),
      mceTablePasteColAfter: () => pasteOnSelection(actions.pasteColsAfter, getColumns),
      mceTablePasteRowBefore: () => pasteOnSelection(actions.pasteRowsBefore, getRows),
      mceTablePasteRowAfter: () => pasteOnSelection(actions.pasteRowsAfter, getRows),
      mceTableDelete: eraseTable,
      mceTableCellToggleClass: toggleTableCellClass,
      mceTableToggleClass: toggleTableClass,
      mceTableToggleCaption: toggleCaption,
      mceTableSizingMode: (_ui, sizing) => setSizingMode(sizing),
      mceTableCellType: actOnType((type2) => type2 === "th" ? actions.makeCellsHeader : actions.unmakeCellsHeader),
      mceTableColType: actOnType((type2) => type2 === "th" ? actions.makeColumnsHeader : actions.unmakeColumnsHeader),
      mceTableRowType: actOnType((type2) => {
        switch (type2) {
          case "header":
            return actions.makeRowsHeader;
          case "footer":
            return actions.makeRowsFooter;
          default:
            return actions.makeRowsBody;
        }
      })
    }, (func, name2) => editor.addCommand(name2, func));
    editor.addCommand("mceInsertTable", (_ui, args) => {
      insertTable(editor, args.rows, args.columns, args.options);
    });
    editor.addCommand("mceTableApplyCellStyle", (_ui, args) => {
      const getFormatName = (style) => "tablecell" + style.toLowerCase().replace("-", "");
      if (!isObject(args)) {
        return;
      }
      const cells2 = getCellsFromSelection(editor);
      if (cells2.length === 0) {
        return;
      }
      const validArgs = filter$1(args, (value2, style) => editor.formatter.has(getFormatName(style)) && isString(value2));
      if (isEmpty(validArgs)) {
        return;
      }
      each$1(validArgs, (value2, style) => {
        const formatName = getFormatName(style);
        each$2(cells2, (cell2) => {
          if (value2 === "") {
            editor.formatter.remove(formatName, { value: null }, cell2.dom, true);
          } else {
            editor.formatter.apply(formatName, { value: value2 }, cell2.dom);
          }
        });
      });
      getTableFromCell(cells2[0]).each((table2) => fireTableModified(editor, table2.dom, styleModified));
    });
  };
  const registerQueryCommands = (editor, actions) => {
    const isRoot = getIsRoot(editor);
    const lookupOnSelection = (action) => getSelectionCell(getSelectionStart(editor)).bind((cell2) => table(cell2, isRoot).map((table2) => {
      const targets = forMenu(getCellsFromSelection(editor), table2, cell2);
      return action(table2, targets);
    })).getOr("");
    each$1({
      mceTableRowType: () => lookupOnSelection(actions.getTableRowType),
      mceTableCellType: () => lookupOnSelection(actions.getTableCellType),
      mceTableColType: () => lookupOnSelection(actions.getTableColType)
    }, (func, name2) => editor.addQueryValueHandler(name2, func));
  };
  const adt$4 = Adt.generate([
    { before: ["element"] },
    {
      on: [
        "element",
        "offset"
      ]
    },
    { after: ["element"] }
  ]);
  const cata$1 = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
  const getStart$1 = (situ) => situ.fold(identity, identity, identity);
  const before$2 = adt$4.before;
  const on = adt$4.on;
  const after$3 = adt$4.after;
  const Situ = {
    before: before$2,
    on,
    after: after$3,
    cata: cata$1,
    getStart: getStart$1
  };
  const create$4 = (selection2, kill) => ({
    selection: selection2,
    kill
  });
  const Response = { create: create$4 };
  const selectNode = (win, element) => {
    const rng = win.document.createRange();
    rng.selectNode(element.dom);
    return rng;
  };
  const selectNodeContents = (win, element) => {
    const rng = win.document.createRange();
    selectNodeContentsUsing(rng, element);
    return rng;
  };
  const selectNodeContentsUsing = (rng, element) => rng.selectNodeContents(element.dom);
  const setStart = (rng, situ) => {
    situ.fold((e) => {
      rng.setStartBefore(e.dom);
    }, (e, o) => {
      rng.setStart(e.dom, o);
    }, (e) => {
      rng.setStartAfter(e.dom);
    });
  };
  const setFinish = (rng, situ) => {
    situ.fold((e) => {
      rng.setEndBefore(e.dom);
    }, (e, o) => {
      rng.setEnd(e.dom, o);
    }, (e) => {
      rng.setEndAfter(e.dom);
    });
  };
  const relativeToNative = (win, startSitu, finishSitu) => {
    const range2 = win.document.createRange();
    setStart(range2, startSitu);
    setFinish(range2, finishSitu);
    return range2;
  };
  const exactToNative = (win, start, soffset, finish, foffset) => {
    const rng = win.document.createRange();
    rng.setStart(start.dom, soffset);
    rng.setEnd(finish.dom, foffset);
    return rng;
  };
  const toRect = (rect) => ({
    left: rect.left,
    top: rect.top,
    right: rect.right,
    bottom: rect.bottom,
    width: rect.width,
    height: rect.height
  });
  const getFirstRect$1 = (rng) => {
    const rects = rng.getClientRects();
    const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
    return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
  };
  const adt$3 = Adt.generate([
    {
      ltr: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    },
    {
      rtl: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    }
  ]);
  const fromRange = (win, type2, range2) => type2(SugarElement.fromDom(range2.startContainer), range2.startOffset, SugarElement.fromDom(range2.endContainer), range2.endOffset);
  const getRanges = (win, selection2) => selection2.match({
    domRange: (rng) => {
      return {
        ltr: constant(rng),
        rtl: Optional.none
      };
    },
    relative: (startSitu, finishSitu) => {
      return {
        ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
        rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
      };
    },
    exact: (start, soffset, finish, foffset) => {
      return {
        ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
        rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
      };
    }
  });
  const doDiagnose = (win, ranges) => {
    const rng = ranges.ltr();
    if (rng.collapsed) {
      const reversed = ranges.rtl().filter((rev) => rev.collapsed === false);
      return reversed.map((rev) => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
    } else {
      return fromRange(win, adt$3.ltr, rng);
    }
  };
  const diagnose = (win, selection2) => {
    const ranges = getRanges(win, selection2);
    return doDiagnose(win, ranges);
  };
  const asLtrRange = (win, selection2) => {
    const diagnosis = diagnose(win, selection2);
    return diagnosis.match({
      ltr: (start, soffset, finish, foffset) => {
        const rng = win.document.createRange();
        rng.setStart(start.dom, soffset);
        rng.setEnd(finish.dom, foffset);
        return rng;
      },
      rtl: (start, soffset, finish, foffset) => {
        const rng = win.document.createRange();
        rng.setStart(finish.dom, foffset);
        rng.setEnd(start.dom, soffset);
        return rng;
      }
    });
  };
  adt$3.ltr;
  adt$3.rtl;
  const create$3 = (start, soffset, finish, foffset) => ({
    start,
    soffset,
    finish,
    foffset
  });
  const SimRange = { create: create$3 };
  const create$2 = (start, soffset, finish, foffset) => {
    return {
      start: Situ.on(start, soffset),
      finish: Situ.on(finish, foffset)
    };
  };
  const Situs = { create: create$2 };
  const convertToRange = (win, selection2) => {
    const rng = asLtrRange(win, selection2);
    return SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset);
  };
  const makeSitus = Situs.create;
  const sync = (container, isRoot, start, soffset, finish, foffset, selectRange) => {
    if (!(eq$1(start, finish) && soffset === foffset)) {
      return closest$1(start, "td,th", isRoot).bind((s) => {
        return closest$1(finish, "td,th", isRoot).bind((f) => {
          return detect(container, isRoot, s, f, selectRange);
        });
      });
    } else {
      return Optional.none();
    }
  };
  const detect = (container, isRoot, start, finish, selectRange) => {
    if (!eq$1(start, finish)) {
      return identify(start, finish, isRoot).bind((cellSel) => {
        const boxes = cellSel.boxes.getOr([]);
        if (boxes.length > 1) {
          selectRange(container, boxes, cellSel.start, cellSel.finish);
          return Optional.some(Response.create(Optional.some(makeSitus(start, 0, start, getEnd(start))), true));
        } else {
          return Optional.none();
        }
      });
    } else {
      return Optional.none();
    }
  };
  const update = (rows2, columns2, container, selected, annotations) => {
    const updateSelection = (newSels) => {
      annotations.clearBeforeUpdate(container);
      annotations.selectRange(container, newSels.boxes, newSels.start, newSels.finish);
      return newSels.boxes;
    };
    return shiftSelection(selected, rows2, columns2, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map(updateSelection);
  };
  const traverse = (item, mode) => ({
    item,
    mode
  });
  const backtrack = (universe2, item, _direction, transition = sidestep) => {
    return universe2.property().parent(item).map((p) => {
      return traverse(p, transition);
    });
  };
  const sidestep = (universe2, item, direction, transition = advance) => {
    return direction.sibling(universe2, item).map((p) => {
      return traverse(p, transition);
    });
  };
  const advance = (universe2, item, direction, transition = advance) => {
    const children2 = universe2.property().children(item);
    const result = direction.first(children2);
    return result.map((r2) => {
      return traverse(r2, transition);
    });
  };
  const successors = [
    {
      current: backtrack,
      next: sidestep,
      fallback: Optional.none()
    },
    {
      current: sidestep,
      next: advance,
      fallback: Optional.some(backtrack)
    },
    {
      current: advance,
      next: advance,
      fallback: Optional.some(sidestep)
    }
  ];
  const go = (universe2, item, mode, direction, rules = successors) => {
    const ruleOpt = find$1(rules, (succ) => {
      return succ.current === mode;
    });
    return ruleOpt.bind((rule) => {
      return rule.current(universe2, item, direction, rule.next).orThunk(() => {
        return rule.fallback.bind((fb) => {
          return go(universe2, item, fb, direction);
        });
      });
    });
  };
  const left$1 = () => {
    const sibling = (universe2, item) => {
      return universe2.query().prevSibling(item);
    };
    const first2 = (children2) => {
      return children2.length > 0 ? Optional.some(children2[children2.length - 1]) : Optional.none();
    };
    return {
      sibling,
      first: first2
    };
  };
  const right$1 = () => {
    const sibling = (universe2, item) => {
      return universe2.query().nextSibling(item);
    };
    const first2 = (children2) => {
      return children2.length > 0 ? Optional.some(children2[0]) : Optional.none();
    };
    return {
      sibling,
      first: first2
    };
  };
  const Walkers = {
    left: left$1,
    right: right$1
  };
  const hone = (universe2, item, predicate, mode, direction, isRoot) => {
    const next = go(universe2, item, mode, direction);
    return next.bind((n) => {
      if (isRoot(n.item)) {
        return Optional.none();
      } else {
        return predicate(n.item) ? Optional.some(n.item) : hone(universe2, n.item, predicate, n.mode, direction, isRoot);
      }
    });
  };
  const left = (universe2, item, predicate, isRoot) => {
    return hone(universe2, item, predicate, sidestep, Walkers.left(), isRoot);
  };
  const right = (universe2, item, predicate, isRoot) => {
    return hone(universe2, item, predicate, sidestep, Walkers.right(), isRoot);
  };
  const isLeaf = (universe2) => (element) => universe2.property().children(element).length === 0;
  const before$1 = (universe2, item, isRoot) => {
    return seekLeft$1(universe2, item, isLeaf(universe2), isRoot);
  };
  const after$2 = (universe2, item, isRoot) => {
    return seekRight$1(universe2, item, isLeaf(universe2), isRoot);
  };
  const seekLeft$1 = left;
  const seekRight$1 = right;
  const universe = DomUniverse();
  const before = (element, isRoot) => {
    return before$1(universe, element, isRoot);
  };
  const after$1 = (element, isRoot) => {
    return after$2(universe, element, isRoot);
  };
  const seekLeft = (element, predicate, isRoot) => {
    return seekLeft$1(universe, element, predicate, isRoot);
  };
  const seekRight = (element, predicate, isRoot) => {
    return seekRight$1(universe, element, predicate, isRoot);
  };
  const ancestor = (scope, predicate, isRoot) => ancestor$2(scope, predicate, isRoot).isSome();
  const adt$2 = Adt.generate([
    { none: ["message"] },
    { success: [] },
    { failedUp: ["cell"] },
    { failedDown: ["cell"] }
  ]);
  const isOverlapping = (bridge, before2, after2) => {
    const beforeBounds = bridge.getRect(before2);
    const afterBounds = bridge.getRect(after2);
    return afterBounds.right > beforeBounds.left && afterBounds.left < beforeBounds.right;
  };
  const isRow = (elem) => {
    return closest$1(elem, "tr");
  };
  const verify = (bridge, before2, beforeOffset, after2, afterOffset, failure, isRoot) => {
    return closest$1(after2, "td,th", isRoot).bind((afterCell) => {
      return closest$1(before2, "td,th", isRoot).map((beforeCell) => {
        if (!eq$1(afterCell, beforeCell)) {
          return sharedOne(isRow, [
            afterCell,
            beforeCell
          ]).fold(() => {
            return isOverlapping(bridge, beforeCell, afterCell) ? adt$2.success() : failure(beforeCell);
          }, (_sharedRow) => {
            return failure(beforeCell);
          });
        } else {
          return eq$1(after2, afterCell) && getEnd(afterCell) === afterOffset ? failure(beforeCell) : adt$2.none("in same cell");
        }
      });
    }).getOr(adt$2.none("default"));
  };
  const cata = (subject, onNone, onSuccess, onFailedUp, onFailedDown) => {
    return subject.fold(onNone, onSuccess, onFailedUp, onFailedDown);
  };
  const BeforeAfter = {
    ...adt$2,
    verify,
    cata
  };
  const inParent = (parent2, children2, element, index2) => ({
    parent: parent2,
    children: children2,
    element,
    index: index2
  });
  const indexInParent = (element) => parent(element).bind((parent2) => {
    const children2 = children$2(parent2);
    return indexOf(children2, element).map((index2) => inParent(parent2, children2, element, index2));
  });
  const indexOf = (elements, element) => findIndex(elements, curry(eq$1, element));
  const isBr = isTag("br");
  const gatherer = (cand, gather, isRoot) => {
    return gather(cand, isRoot).bind((target) => {
      return isText(target) && get$6(target).trim().length === 0 ? gatherer(target, gather, isRoot) : Optional.some(target);
    });
  };
  const handleBr = (isRoot, element, direction) => {
    return direction.traverse(element).orThunk(() => {
      return gatherer(element, direction.gather, isRoot);
    }).map(direction.relative);
  };
  const findBr = (element, offset) => {
    return child$2(element, offset).filter(isBr).orThunk(() => {
      return child$2(element, offset - 1).filter(isBr);
    });
  };
  const handleParent = (isRoot, element, offset, direction) => {
    return findBr(element, offset).bind((br) => {
      return direction.traverse(br).fold(() => {
        return gatherer(br, direction.gather, isRoot).map(direction.relative);
      }, (adjacent) => {
        return indexInParent(adjacent).map((info) => {
          return Situ.on(info.parent, info.index);
        });
      });
    });
  };
  const tryBr = (isRoot, element, offset, direction) => {
    const target = isBr(element) ? handleBr(isRoot, element, direction) : handleParent(isRoot, element, offset, direction);
    return target.map((tgt) => {
      return {
        start: tgt,
        finish: tgt
      };
    });
  };
  const process = (analysis) => {
    return BeforeAfter.cata(analysis, (_message) => {
      return Optional.none();
    }, () => {
      return Optional.none();
    }, (cell2) => {
      return Optional.some(point(cell2, 0));
    }, (cell2) => {
      return Optional.some(point(cell2, getEnd(cell2)));
    });
  };
  const moveDown = (caret, amount) => {
    return {
      left: caret.left,
      top: caret.top + amount,
      right: caret.right,
      bottom: caret.bottom + amount
    };
  };
  const moveUp = (caret, amount) => {
    return {
      left: caret.left,
      top: caret.top - amount,
      right: caret.right,
      bottom: caret.bottom - amount
    };
  };
  const translate = (caret, xDelta, yDelta) => {
    return {
      left: caret.left + xDelta,
      top: caret.top + yDelta,
      right: caret.right + xDelta,
      bottom: caret.bottom + yDelta
    };
  };
  const getTop = (caret) => {
    return caret.top;
  };
  const getBottom = (caret) => {
    return caret.bottom;
  };
  const getPartialBox = (bridge, element, offset) => {
    if (offset >= 0 && offset < getEnd(element)) {
      return bridge.getRangedRect(element, offset, element, offset + 1);
    } else if (offset > 0) {
      return bridge.getRangedRect(element, offset - 1, element, offset);
    }
    return Optional.none();
  };
  const toCaret = (rect) => ({
    left: rect.left,
    top: rect.top,
    right: rect.right,
    bottom: rect.bottom
  });
  const getElemBox = (bridge, element) => {
    return Optional.some(bridge.getRect(element));
  };
  const getBoxAt = (bridge, element, offset) => {
    if (isElement(element)) {
      return getElemBox(bridge, element).map(toCaret);
    } else if (isText(element)) {
      return getPartialBox(bridge, element, offset).map(toCaret);
    } else {
      return Optional.none();
    }
  };
  const getEntireBox = (bridge, element) => {
    if (isElement(element)) {
      return getElemBox(bridge, element).map(toCaret);
    } else if (isText(element)) {
      return bridge.getRangedRect(element, 0, element, getEnd(element)).map(toCaret);
    } else {
      return Optional.none();
    }
  };
  const JUMP_SIZE = 5;
  const NUM_RETRIES = 100;
  const adt$1 = Adt.generate([
    { none: [] },
    { retry: ["caret"] }
  ]);
  const isOutside = (caret, box) => {
    return caret.left < box.left || Math.abs(box.right - caret.left) < 1 || caret.left > box.right;
  };
  const inOutsideBlock = (bridge, element, caret) => {
    return closest$2(element, isBlock).fold(never, (cell2) => {
      return getEntireBox(bridge, cell2).exists((box) => {
        return isOutside(caret, box);
      });
    });
  };
  const adjustDown = (bridge, element, guessBox, original, caret) => {
    const lowerCaret = moveDown(caret, JUMP_SIZE);
    if (Math.abs(guessBox.bottom - original.bottom) < 1) {
      return adt$1.retry(lowerCaret);
    } else if (guessBox.top > caret.bottom) {
      return adt$1.retry(lowerCaret);
    } else if (guessBox.top === caret.bottom) {
      return adt$1.retry(moveDown(caret, 1));
    } else {
      return inOutsideBlock(bridge, element, caret) ? adt$1.retry(translate(lowerCaret, JUMP_SIZE, 0)) : adt$1.none();
    }
  };
  const adjustUp = (bridge, element, guessBox, original, caret) => {
    const higherCaret = moveUp(caret, JUMP_SIZE);
    if (Math.abs(guessBox.top - original.top) < 1) {
      return adt$1.retry(higherCaret);
    } else if (guessBox.bottom < caret.top) {
      return adt$1.retry(higherCaret);
    } else if (guessBox.bottom === caret.top) {
      return adt$1.retry(moveUp(caret, 1));
    } else {
      return inOutsideBlock(bridge, element, caret) ? adt$1.retry(translate(higherCaret, JUMP_SIZE, 0)) : adt$1.none();
    }
  };
  const upMovement = {
    point: getTop,
    adjuster: adjustUp,
    move: moveUp,
    gather: before
  };
  const downMovement = {
    point: getBottom,
    adjuster: adjustDown,
    move: moveDown,
    gather: after$1
  };
  const isAtTable = (bridge, x, y) => {
    return bridge.elementFromPoint(x, y).filter((elm) => {
      return name(elm) === "table";
    }).isSome();
  };
  const adjustForTable = (bridge, movement, original, caret, numRetries) => {
    return adjustTil(bridge, movement, original, movement.move(caret, JUMP_SIZE), numRetries);
  };
  const adjustTil = (bridge, movement, original, caret, numRetries) => {
    if (numRetries === 0) {
      return Optional.some(caret);
    }
    if (isAtTable(bridge, caret.left, movement.point(caret))) {
      return adjustForTable(bridge, movement, original, caret, numRetries - 1);
    }
    return bridge.situsFromPoint(caret.left, movement.point(caret)).bind((guess) => {
      return guess.start.fold(Optional.none, (element) => {
        return getEntireBox(bridge, element).bind((guessBox) => {
          return movement.adjuster(bridge, element, guessBox, original, caret).fold(Optional.none, (newCaret) => {
            return adjustTil(bridge, movement, original, newCaret, numRetries - 1);
          });
        }).orThunk(() => {
          return Optional.some(caret);
        });
      }, Optional.none);
    });
  };
  const checkScroll = (movement, adjusted, bridge) => {
    if (movement.point(adjusted) > bridge.getInnerHeight()) {
      return Optional.some(movement.point(adjusted) - bridge.getInnerHeight());
    } else if (movement.point(adjusted) < 0) {
      return Optional.some(-movement.point(adjusted));
    } else {
      return Optional.none();
    }
  };
  const retry = (movement, bridge, caret) => {
    const moved = movement.move(caret, JUMP_SIZE);
    const adjusted = adjustTil(bridge, movement, caret, moved, NUM_RETRIES).getOr(moved);
    return checkScroll(movement, adjusted, bridge).fold(() => {
      return bridge.situsFromPoint(adjusted.left, movement.point(adjusted));
    }, (delta) => {
      bridge.scrollBy(0, delta);
      return bridge.situsFromPoint(adjusted.left, movement.point(adjusted) - delta);
    });
  };
  const Retries = {
    tryUp: curry(retry, upMovement),
    tryDown: curry(retry, downMovement),
    getJumpSize: constant(JUMP_SIZE)
  };
  const MAX_RETRIES = 20;
  const findSpot = (bridge, isRoot, direction) => {
    return bridge.getSelection().bind((sel) => {
      return tryBr(isRoot, sel.finish, sel.foffset, direction).fold(() => {
        return Optional.some(point(sel.finish, sel.foffset));
      }, (brNeighbour) => {
        const range2 = bridge.fromSitus(brNeighbour);
        const analysis = BeforeAfter.verify(bridge, sel.finish, sel.foffset, range2.finish, range2.foffset, direction.failure, isRoot);
        return process(analysis);
      });
    });
  };
  const scan = (bridge, isRoot, element, offset, direction, numRetries) => {
    if (numRetries === 0) {
      return Optional.none();
    }
    return tryCursor(bridge, isRoot, element, offset, direction).bind((situs) => {
      const range2 = bridge.fromSitus(situs);
      const analysis = BeforeAfter.verify(bridge, element, offset, range2.finish, range2.foffset, direction.failure, isRoot);
      return BeforeAfter.cata(analysis, () => {
        return Optional.none();
      }, () => {
        return Optional.some(situs);
      }, (cell2) => {
        if (eq$1(element, cell2) && offset === 0) {
          return tryAgain(bridge, element, offset, moveUp, direction);
        } else {
          return scan(bridge, isRoot, cell2, 0, direction, numRetries - 1);
        }
      }, (cell2) => {
        if (eq$1(element, cell2) && offset === getEnd(cell2)) {
          return tryAgain(bridge, element, offset, moveDown, direction);
        } else {
          return scan(bridge, isRoot, cell2, getEnd(cell2), direction, numRetries - 1);
        }
      });
    });
  };
  const tryAgain = (bridge, element, offset, move, direction) => {
    return getBoxAt(bridge, element, offset).bind((box) => {
      return tryAt(bridge, direction, move(box, Retries.getJumpSize()));
    });
  };
  const tryAt = (bridge, direction, box) => {
    const browser = detect$2().browser;
    if (browser.isChromium() || browser.isSafari() || browser.isFirefox()) {
      return direction.retry(bridge, box);
    } else {
      return Optional.none();
    }
  };
  const tryCursor = (bridge, isRoot, element, offset, direction) => {
    return getBoxAt(bridge, element, offset).bind((box) => {
      return tryAt(bridge, direction, box);
    });
  };
  const handle$1 = (bridge, isRoot, direction) => {
    return findSpot(bridge, isRoot, direction).bind((spot) => {
      return scan(bridge, isRoot, spot.element, spot.offset, direction, MAX_RETRIES).map(bridge.fromSitus);
    });
  };
  const inSameTable = (elem, table2) => {
    return ancestor(elem, (e) => {
      return parent(e).exists((p) => {
        return eq$1(p, table2);
      });
    });
  };
  const simulate = (bridge, isRoot, direction, initial, anchor) => {
    return closest$1(initial, "td,th", isRoot).bind((start) => {
      return closest$1(start, "table", isRoot).bind((table2) => {
        if (!inSameTable(anchor, table2)) {
          return Optional.none();
        }
        return handle$1(bridge, isRoot, direction).bind((range2) => {
          return closest$1(range2.finish, "td,th", isRoot).map((finish) => {
            return {
              start,
              finish,
              range: range2
            };
          });
        });
      });
    });
  };
  const navigate = (bridge, isRoot, direction, initial, anchor, precheck) => {
    return precheck(initial, isRoot).orThunk(() => {
      return simulate(bridge, isRoot, direction, initial, anchor).map((info) => {
        const range2 = info.range;
        return Response.create(Optional.some(makeSitus(range2.start, range2.soffset, range2.finish, range2.foffset)), true);
      });
    });
  };
  const firstUpCheck = (initial, isRoot) => {
    return closest$1(initial, "tr", isRoot).bind((startRow) => {
      return closest$1(startRow, "table", isRoot).bind((table2) => {
        const rows2 = descendants(table2, "tr");
        if (eq$1(startRow, rows2[0])) {
          return seekLeft(table2, (element) => {
            return last$1(element).isSome();
          }, isRoot).map((last2) => {
            const lastOffset = getEnd(last2);
            return Response.create(Optional.some(makeSitus(last2, lastOffset, last2, lastOffset)), true);
          });
        } else {
          return Optional.none();
        }
      });
    });
  };
  const lastDownCheck = (initial, isRoot) => {
    return closest$1(initial, "tr", isRoot).bind((startRow) => {
      return closest$1(startRow, "table", isRoot).bind((table2) => {
        const rows2 = descendants(table2, "tr");
        if (eq$1(startRow, rows2[rows2.length - 1])) {
          return seekRight(table2, (element) => {
            return first(element).isSome();
          }, isRoot).map((first2) => {
            return Response.create(Optional.some(makeSitus(first2, 0, first2, 0)), true);
          });
        } else {
          return Optional.none();
        }
      });
    });
  };
  const select = (bridge, container, isRoot, direction, initial, anchor, selectRange) => {
    return simulate(bridge, isRoot, direction, initial, anchor).bind((info) => {
      return detect(container, isRoot, info.start, info.finish, selectRange);
    });
  };
  const Cell = (initial) => {
    let value2 = initial;
    const get2 = () => {
      return value2;
    };
    const set2 = (v) => {
      value2 = v;
    };
    return {
      get: get2,
      set: set2
    };
  };
  const singleton = (doRevoke) => {
    const subject = Cell(Optional.none());
    const revoke = () => subject.get().each(doRevoke);
    const clear2 = () => {
      revoke();
      subject.set(Optional.none());
    };
    const isSet = () => subject.get().isSome();
    const get2 = () => subject.get();
    const set2 = (s) => {
      revoke();
      subject.set(Optional.some(s));
    };
    return {
      clear: clear2,
      isSet,
      get: get2,
      set: set2
    };
  };
  const value = () => {
    const subject = singleton(noop);
    const on2 = (f) => subject.get().each(f);
    return {
      ...subject,
      on: on2
    };
  };
  const findCell = (target, isRoot) => closest$1(target, "td,th", isRoot);
  const MouseSelection = (bridge, container, isRoot, annotations) => {
    const cursor = value();
    const clearstate = cursor.clear;
    const applySelection = (event) => {
      cursor.on((start) => {
        annotations.clearBeforeUpdate(container);
        findCell(event.target, isRoot).each((finish) => {
          identify(start, finish, isRoot).each((cellSel) => {
            const boxes = cellSel.boxes.getOr([]);
            if (boxes.length === 1) {
              const singleCell = boxes[0];
              const isNonEditableCell = getRaw(singleCell) === "false";
              const isCellClosestContentEditable = is(closest(event.target), singleCell, eq$1);
              if (isNonEditableCell && isCellClosestContentEditable) {
                annotations.selectRange(container, boxes, singleCell, singleCell);
                bridge.selectContents(singleCell);
              }
            } else if (boxes.length > 1) {
              annotations.selectRange(container, boxes, cellSel.start, cellSel.finish);
              bridge.selectContents(finish);
            }
          });
        });
      });
    };
    const mousedown = (event) => {
      annotations.clear(container);
      findCell(event.target, isRoot).each(cursor.set);
    };
    const mouseover = (event) => {
      applySelection(event);
    };
    const mouseup = (event) => {
      applySelection(event);
      clearstate();
    };
    return {
      clearstate,
      mousedown,
      mouseover,
      mouseup
    };
  };
  const down = {
    traverse: nextSibling,
    gather: after$1,
    relative: Situ.before,
    retry: Retries.tryDown,
    failure: BeforeAfter.failedDown
  };
  const up = {
    traverse: prevSibling,
    gather: before,
    relative: Situ.before,
    retry: Retries.tryUp,
    failure: BeforeAfter.failedUp
  };
  const isKey = (key2) => {
    return (keycode) => {
      return keycode === key2;
    };
  };
  const isUp = isKey(38);
  const isDown = isKey(40);
  const isNavigation = (keycode) => {
    return keycode >= 37 && keycode <= 40;
  };
  const ltr = {
    isBackward: isKey(37),
    isForward: isKey(39)
  };
  const rtl = {
    isBackward: isKey(39),
    isForward: isKey(37)
  };
  const get$3 = (_DOC) => {
    const doc = _DOC !== void 0 ? _DOC.dom : document;
    const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
    const y = doc.body.scrollTop || doc.documentElement.scrollTop;
    return SugarPosition(x, y);
  };
  const by = (x, y, _DOC) => {
    const doc = _DOC !== void 0 ? _DOC.dom : document;
    const win = doc.defaultView;
    if (win) {
      win.scrollBy(x, y);
    }
  };
  const adt = Adt.generate([
    { domRange: ["rng"] },
    {
      relative: [
        "startSitu",
        "finishSitu"
      ]
    },
    {
      exact: [
        "start",
        "soffset",
        "finish",
        "foffset"
      ]
    }
  ]);
  const exactFromRange = (simRange) => adt.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
  const getStart = (selection2) => selection2.match({
    domRange: (rng) => SugarElement.fromDom(rng.startContainer),
    relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
    exact: (start, _soffset, _finish, _foffset) => start
  });
  const domRange = adt.domRange;
  const relative = adt.relative;
  const exact = adt.exact;
  const getWin = (selection2) => {
    const start = getStart(selection2);
    return defaultView(start);
  };
  const range = SimRange.create;
  const SimSelection = {
    domRange,
    relative,
    exact,
    exactFromRange,
    getWin,
    range
  };
  const caretPositionFromPoint = (doc, x, y) => {
    var _a, _b;
    return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind((pos) => {
      if (pos.offsetNode === null) {
        return Optional.none();
      }
      const r2 = doc.dom.createRange();
      r2.setStart(pos.offsetNode, pos.offset);
      r2.collapse();
      return Optional.some(r2);
    });
  };
  const caretRangeFromPoint = (doc, x, y) => {
    var _a, _b;
    return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
  };
  const availableSearch = (() => {
    if (document.caretPositionFromPoint) {
      return caretPositionFromPoint;
    } else if (document.caretRangeFromPoint) {
      return caretRangeFromPoint;
    } else {
      return Optional.none;
    }
  })();
  const fromPoint = (win, x, y) => {
    const doc = SugarElement.fromDom(win.document);
    return availableSearch(doc, x, y).map((rng) => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
  };
  const beforeSpecial = (element, offset) => {
    const name$1 = name(element);
    if (name$1 === "input") {
      return Situ.after(element);
    } else if (!contains$2([
      "br",
      "img"
    ], name$1)) {
      return Situ.on(element, offset);
    } else {
      return offset === 0 ? Situ.before(element) : Situ.after(element);
    }
  };
  const preprocessRelative = (startSitu, finishSitu) => {
    const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
    const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
    return SimSelection.relative(start, finish);
  };
  const preprocessExact = (start, soffset, finish, foffset) => {
    const startSitu = beforeSpecial(start, soffset);
    const finishSitu = beforeSpecial(finish, foffset);
    return SimSelection.relative(startSitu, finishSitu);
  };
  const makeRange = (start, soffset, finish, foffset) => {
    const doc = owner(start);
    const rng = doc.dom.createRange();
    rng.setStart(start.dom, soffset);
    rng.setEnd(finish.dom, foffset);
    return rng;
  };
  const after = (start, soffset, finish, foffset) => {
    const r2 = makeRange(start, soffset, finish, foffset);
    const same = eq$1(start, finish) && soffset === foffset;
    return r2.collapsed && !same;
  };
  const getNativeSelection = (win) => Optional.from(win.getSelection());
  const doSetNativeRange = (win, rng) => {
    getNativeSelection(win).each((selection2) => {
      selection2.removeAllRanges();
      selection2.addRange(rng);
    });
  };
  const doSetRange = (win, start, soffset, finish, foffset) => {
    const rng = exactToNative(win, start, soffset, finish, foffset);
    doSetNativeRange(win, rng);
  };
  const setLegacyRtlRange = (win, selection2, start, soffset, finish, foffset) => {
    selection2.collapse(start.dom, soffset);
    selection2.extend(finish.dom, foffset);
  };
  const setRangeFromRelative = (win, relative2) => diagnose(win, relative2).match({
    ltr: (start, soffset, finish, foffset) => {
      doSetRange(win, start, soffset, finish, foffset);
    },
    rtl: (start, soffset, finish, foffset) => {
      getNativeSelection(win).each((selection2) => {
        if (selection2.setBaseAndExtent) {
          selection2.setBaseAndExtent(start.dom, soffset, finish.dom, foffset);
        } else if (selection2.extend) {
          try {
            setLegacyRtlRange(win, selection2, start, soffset, finish, foffset);
          } catch (e) {
            doSetRange(win, finish, foffset, start, soffset);
          }
        } else {
          doSetRange(win, finish, foffset, start, soffset);
        }
      });
    }
  });
  const setExact = (win, start, soffset, finish, foffset) => {
    const relative2 = preprocessExact(start, soffset, finish, foffset);
    setRangeFromRelative(win, relative2);
  };
  const setRelative = (win, startSitu, finishSitu) => {
    const relative2 = preprocessRelative(startSitu, finishSitu);
    setRangeFromRelative(win, relative2);
  };
  const readRange = (selection2) => {
    if (selection2.rangeCount > 0) {
      const firstRng = selection2.getRangeAt(0);
      const lastRng = selection2.getRangeAt(selection2.rangeCount - 1);
      return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
    } else {
      return Optional.none();
    }
  };
  const doGetExact = (selection2) => {
    if (selection2.anchorNode === null || selection2.focusNode === null) {
      return readRange(selection2);
    } else {
      const anchor = SugarElement.fromDom(selection2.anchorNode);
      const focus = SugarElement.fromDom(selection2.focusNode);
      return after(anchor, selection2.anchorOffset, focus, selection2.focusOffset) ? Optional.some(SimRange.create(anchor, selection2.anchorOffset, focus, selection2.focusOffset)) : readRange(selection2);
    }
  };
  const setToElement = (win, element, selectNodeContents$1 = true) => {
    const rngGetter = selectNodeContents$1 ? selectNodeContents : selectNode;
    const rng = rngGetter(win, element);
    doSetNativeRange(win, rng);
  };
  const getExact = (win) => getNativeSelection(win).filter((sel) => sel.rangeCount > 0).bind(doGetExact);
  const get$2 = (win) => getExact(win).map((range2) => SimSelection.exact(range2.start, range2.soffset, range2.finish, range2.foffset));
  const getFirstRect = (win, selection2) => {
    const rng = asLtrRange(win, selection2);
    return getFirstRect$1(rng);
  };
  const getAtPoint = (win, x, y) => fromPoint(win, x, y);
  const clear = (win) => {
    getNativeSelection(win).each((selection2) => selection2.removeAllRanges());
  };
  const WindowBridge = (win) => {
    const elementFromPoint = (x, y) => {
      return SugarElement.fromPoint(SugarElement.fromDom(win.document), x, y);
    };
    const getRect = (element) => {
      return element.dom.getBoundingClientRect();
    };
    const getRangedRect = (start, soffset, finish, foffset) => {
      const sel = SimSelection.exact(start, soffset, finish, foffset);
      return getFirstRect(win, sel);
    };
    const getSelection = () => {
      return get$2(win).map((exactAdt) => {
        return convertToRange(win, exactAdt);
      });
    };
    const fromSitus = (situs) => {
      const relative2 = SimSelection.relative(situs.start, situs.finish);
      return convertToRange(win, relative2);
    };
    const situsFromPoint = (x, y) => {
      return getAtPoint(win, x, y).map((exact2) => {
        return Situs.create(exact2.start, exact2.soffset, exact2.finish, exact2.foffset);
      });
    };
    const clearSelection = () => {
      clear(win);
    };
    const collapseSelection = (toStart = false) => {
      get$2(win).each((sel) => sel.fold((rng) => rng.collapse(toStart), (startSitu, finishSitu) => {
        const situ = toStart ? startSitu : finishSitu;
        setRelative(win, situ, situ);
      }, (start, soffset, finish, foffset) => {
        const node = toStart ? start : finish;
        const offset = toStart ? soffset : foffset;
        setExact(win, node, offset, node, offset);
      }));
    };
    const selectNode2 = (element) => {
      setToElement(win, element, false);
    };
    const selectContents = (element) => {
      setToElement(win, element);
    };
    const setSelection = (sel) => {
      setExact(win, sel.start, sel.soffset, sel.finish, sel.foffset);
    };
    const setRelativeSelection = (start, finish) => {
      setRelative(win, start, finish);
    };
    const getInnerHeight = () => {
      return win.innerHeight;
    };
    const getScrollY = () => {
      const pos = get$3(SugarElement.fromDom(win.document));
      return pos.top;
    };
    const scrollBy = (x, y) => {
      by(x, y, SugarElement.fromDom(win.document));
    };
    return {
      elementFromPoint,
      getRect,
      getRangedRect,
      getSelection,
      fromSitus,
      situsFromPoint,
      clearSelection,
      collapseSelection,
      setSelection,
      setRelativeSelection,
      selectNode: selectNode2,
      selectContents,
      getInnerHeight,
      getScrollY,
      scrollBy
    };
  };
  const rc = (rows2, cols) => ({
    rows: rows2,
    cols
  });
  const mouse = (win, container, isRoot, annotations) => {
    const bridge = WindowBridge(win);
    const handlers = MouseSelection(bridge, container, isRoot, annotations);
    return {
      clearstate: handlers.clearstate,
      mousedown: handlers.mousedown,
      mouseover: handlers.mouseover,
      mouseup: handlers.mouseup
    };
  };
  const keyboard = (win, container, isRoot, annotations) => {
    const bridge = WindowBridge(win);
    const clearToNavigate = () => {
      annotations.clear(container);
      return Optional.none();
    };
    const keydown = (event, start, soffset, finish, foffset, direction) => {
      const realEvent = event.raw;
      const keycode = realEvent.which;
      const shiftKey = realEvent.shiftKey === true;
      const handler = retrieve$1(container, annotations.selectedSelector).fold(() => {
        if (isNavigation(keycode) && !shiftKey) {
          annotations.clearBeforeUpdate(container);
        }
        if (isDown(keycode) && shiftKey) {
          return curry(select, bridge, container, isRoot, down, finish, start, annotations.selectRange);
        } else if (isUp(keycode) && shiftKey) {
          return curry(select, bridge, container, isRoot, up, finish, start, annotations.selectRange);
        } else if (isDown(keycode)) {
          return curry(navigate, bridge, isRoot, down, finish, start, lastDownCheck);
        } else if (isUp(keycode)) {
          return curry(navigate, bridge, isRoot, up, finish, start, firstUpCheck);
        } else {
          return Optional.none;
        }
      }, (selected) => {
        const update$1 = (attempts) => {
          return () => {
            const navigation = findMap(attempts, (delta) => {
              return update(delta.rows, delta.cols, container, selected, annotations);
            });
            return navigation.fold(() => {
              return getEdges(container, annotations.firstSelectedSelector, annotations.lastSelectedSelector).map((edges) => {
                const relative2 = isDown(keycode) || direction.isForward(keycode) ? Situ.after : Situ.before;
                bridge.setRelativeSelection(Situ.on(edges.first, 0), relative2(edges.table));
                annotations.clear(container);
                return Response.create(Optional.none(), true);
              });
            }, (_) => {
              return Optional.some(Response.create(Optional.none(), true));
            });
          };
        };
        if (isDown(keycode) && shiftKey) {
          return update$1([rc(1, 0)]);
        } else if (isUp(keycode) && shiftKey) {
          return update$1([rc(-1, 0)]);
        } else if (direction.isBackward(keycode) && shiftKey) {
          return update$1([
            rc(0, -1),
            rc(-1, 0)
          ]);
        } else if (direction.isForward(keycode) && shiftKey) {
          return update$1([
            rc(0, 1),
            rc(1, 0)
          ]);
        } else if (isNavigation(keycode) && !shiftKey) {
          return clearToNavigate;
        } else {
          return Optional.none;
        }
      });
      return handler();
    };
    const keyup = (event, start, soffset, finish, foffset) => {
      return retrieve$1(container, annotations.selectedSelector).fold(() => {
        const realEvent = event.raw;
        const keycode = realEvent.which;
        const shiftKey = realEvent.shiftKey === true;
        if (!shiftKey) {
          return Optional.none();
        }
        if (isNavigation(keycode)) {
          return sync(container, isRoot, start, soffset, finish, foffset, annotations.selectRange);
        } else {
          return Optional.none();
        }
      }, Optional.none);
    };
    return {
      keydown,
      keyup
    };
  };
  const external = (win, container, isRoot, annotations) => {
    const bridge = WindowBridge(win);
    return (start, finish) => {
      annotations.clearBeforeUpdate(container);
      identify(start, finish, isRoot).each((cellSel) => {
        const boxes = cellSel.boxes.getOr([]);
        annotations.selectRange(container, boxes, cellSel.start, cellSel.finish);
        bridge.selectContents(finish);
        bridge.collapseSelection();
      });
    };
  };
  const read = (element, attr) => {
    const value2 = get$b(element, attr);
    return value2 === void 0 || value2 === "" ? [] : value2.split(" ");
  };
  const add$2 = (element, attr, id) => {
    const old = read(element, attr);
    const nu2 = old.concat([id]);
    set$2(element, attr, nu2.join(" "));
    return true;
  };
  const remove$4 = (element, attr, id) => {
    const nu2 = filter$2(read(element, attr), (v) => v !== id);
    if (nu2.length > 0) {
      set$2(element, attr, nu2.join(" "));
    } else {
      remove$7(element, attr);
    }
    return false;
  };
  const supports = (element) => element.dom.classList !== void 0;
  const get$1 = (element) => read(element, "class");
  const add$1 = (element, clazz) => add$2(element, "class", clazz);
  const remove$3 = (element, clazz) => remove$4(element, "class", clazz);
  const add = (element, clazz) => {
    if (supports(element)) {
      element.dom.classList.add(clazz);
    } else {
      add$1(element, clazz);
    }
  };
  const cleanClass = (element) => {
    const classList = supports(element) ? element.dom.classList : get$1(element);
    if (classList.length === 0) {
      remove$7(element, "class");
    }
  };
  const remove$2 = (element, clazz) => {
    if (supports(element)) {
      const classList = element.dom.classList;
      classList.remove(clazz);
    } else {
      remove$3(element, clazz);
    }
    cleanClass(element);
  };
  const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
  const remove$1 = (element, classes) => {
    each$2(classes, (x) => {
      remove$2(element, x);
    });
  };
  const addClass = (clazz) => (element) => {
    add(element, clazz);
  };
  const removeClasses = (classes) => (element) => {
    remove$1(element, classes);
  };
  const byClass = (ephemera2) => {
    const addSelectionClass = addClass(ephemera2.selected);
    const removeSelectionClasses = removeClasses([
      ephemera2.selected,
      ephemera2.lastSelected,
      ephemera2.firstSelected
    ]);
    const clear2 = (container) => {
      const sels = descendants(container, ephemera2.selectedSelector);
      each$2(sels, removeSelectionClasses);
    };
    const selectRange = (container, cells2, start, finish) => {
      clear2(container);
      each$2(cells2, addSelectionClass);
      add(start, ephemera2.firstSelected);
      add(finish, ephemera2.lastSelected);
    };
    return {
      clearBeforeUpdate: clear2,
      clear: clear2,
      selectRange,
      selectedSelector: ephemera2.selectedSelector,
      firstSelectedSelector: ephemera2.firstSelectedSelector,
      lastSelectedSelector: ephemera2.lastSelectedSelector
    };
  };
  const byAttr = (ephemera2, onSelection, onClear) => {
    const removeSelectionAttributes = (element) => {
      remove$7(element, ephemera2.selected);
      remove$7(element, ephemera2.firstSelected);
      remove$7(element, ephemera2.lastSelected);
    };
    const addSelectionAttribute = (element) => {
      set$2(element, ephemera2.selected, "1");
    };
    const clear2 = (container) => {
      clearBeforeUpdate(container);
      onClear();
    };
    const clearBeforeUpdate = (container) => {
      const sels = descendants(container, `${ephemera2.selectedSelector},${ephemera2.firstSelectedSelector},${ephemera2.lastSelectedSelector}`);
      each$2(sels, removeSelectionAttributes);
    };
    const selectRange = (container, cells2, start, finish) => {
      clear2(container);
      each$2(cells2, addSelectionAttribute);
      set$2(start, ephemera2.firstSelected, "1");
      set$2(finish, ephemera2.lastSelected, "1");
      onSelection(cells2, start, finish);
    };
    return {
      clearBeforeUpdate,
      clear: clear2,
      selectRange,
      selectedSelector: ephemera2.selectedSelector,
      firstSelectedSelector: ephemera2.firstSelectedSelector,
      lastSelectedSelector: ephemera2.lastSelectedSelector
    };
  };
  const SelectionAnnotation = {
    byClass,
    byAttr
  };
  const fold = (subject, onNone, onMultiple, onSingle) => {
    switch (subject.tag) {
      case "none":
        return onNone();
      case "single":
        return onSingle(subject.element);
      case "multiple":
        return onMultiple(subject.elements);
    }
  };
  const none = () => ({ tag: "none" });
  const multiple = (elements) => ({
    tag: "multiple",
    elements
  });
  const single = (element) => ({
    tag: "single",
    element
  });
  const Selections = (lazyRoot, getStart2, selectedSelector) => {
    const get2 = () => retrieve(lazyRoot(), selectedSelector).fold(() => getStart2().fold(none, single), multiple);
    return { get: get2 };
  };
  const getUpOrLeftCells = (grid2, selectedCells) => {
    const upGrid = grid2.slice(0, selectedCells[selectedCells.length - 1].row + 1);
    const upDetails = toDetailList(upGrid);
    return bind$2(upDetails, (detail2) => {
      const slicedCells = detail2.cells.slice(0, selectedCells[selectedCells.length - 1].column + 1);
      return map$1(slicedCells, (cell2) => cell2.element);
    });
  };
  const getDownOrRightCells = (grid2, selectedCells) => {
    const downGrid = grid2.slice(selectedCells[0].row + selectedCells[0].rowspan - 1, grid2.length);
    const downDetails = toDetailList(downGrid);
    return bind$2(downDetails, (detail2) => {
      const slicedCells = detail2.cells.slice(selectedCells[0].column + selectedCells[0].colspan - 1, detail2.cells.length);
      return map$1(slicedCells, (cell2) => cell2.element);
    });
  };
  const getOtherCells = (table2, target, generators) => {
    const warehouse = Warehouse.fromTable(table2);
    const details = onCells(warehouse, target);
    return details.map((selectedCells) => {
      const grid2 = toGrid(warehouse, generators, false);
      const { rows: rows2 } = extractGridDetails(grid2);
      const upOrLeftCells = getUpOrLeftCells(rows2, selectedCells);
      const downOrRightCells = getDownOrRightCells(rows2, selectedCells);
      return {
        upOrLeftCells,
        downOrRightCells
      };
    });
  };
  const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
    target,
    x,
    y,
    stop,
    prevent,
    kill,
    raw
  });
  const fromRawEvent$1 = (rawEvent) => {
    const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
    const stop = () => rawEvent.stopPropagation();
    const prevent = () => rawEvent.preventDefault();
    const kill = compose(prevent, stop);
    return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  };
  const handle = (filter2, handler) => (rawEvent) => {
    if (filter2(rawEvent)) {
      handler(fromRawEvent$1(rawEvent));
    }
  };
  const binder = (element, event, filter2, handler, useCapture) => {
    const wrapped = handle(filter2, handler);
    element.dom.addEventListener(event, wrapped, useCapture);
    return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  };
  const bind$1 = (element, event, filter2, handler) => binder(element, event, filter2, handler, false);
  const unbind = (element, event, handler, useCapture) => {
    element.dom.removeEventListener(event, handler, useCapture);
  };
  const filter = always;
  const bind = (element, event, handler) => bind$1(element, event, filter, handler);
  const fromRawEvent = fromRawEvent$1;
  const hasInternalTarget = (e) => has(SugarElement.fromDom(e.target), "ephox-snooker-resizer-bar") === false;
  const TableCellSelectionHandler = (editor, resizeHandler) => {
    const cellSelection = Selections(() => SugarElement.fromDom(editor.getBody()), () => getSelectionCell(getSelectionStart(editor), getIsRoot(editor)), ephemera.selectedSelector);
    const onSelection = (cells2, start, finish) => {
      const tableOpt = table(start);
      tableOpt.each((table2) => {
        const cloneFormats2 = getTableCloneElements(editor);
        const generators = cellOperations(noop, SugarElement.fromDom(editor.getDoc()), cloneFormats2);
        const selectedCells = getCellsFromSelection(editor);
        const otherCells = getOtherCells(table2, { selection: selectedCells }, generators);
        fireTableSelectionChange(editor, cells2, start, finish, otherCells);
      });
    };
    const onClear = () => fireTableSelectionClear(editor);
    const annotations = SelectionAnnotation.byAttr(ephemera, onSelection, onClear);
    editor.on("init", (_e) => {
      const win = editor.getWin();
      const body2 = getBody(editor);
      const isRoot = getIsRoot(editor);
      const syncSelection = () => {
        const sel = editor.selection;
        const start = SugarElement.fromDom(sel.getStart());
        const end = SugarElement.fromDom(sel.getEnd());
        const shared = sharedOne(table, [
          start,
          end
        ]);
        shared.fold(() => annotations.clear(body2), noop);
      };
      const mouseHandlers = mouse(win, body2, isRoot, annotations);
      const keyHandlers = keyboard(win, body2, isRoot, annotations);
      const external$1 = external(win, body2, isRoot, annotations);
      const hasShiftKey = (event) => event.raw.shiftKey === true;
      editor.on("TableSelectorChange", (e) => external$1(e.start, e.finish));
      const handleResponse = (event, response) => {
        if (!hasShiftKey(event)) {
          return;
        }
        if (response.kill) {
          event.kill();
        }
        response.selection.each((ns) => {
          const relative2 = SimSelection.relative(ns.start, ns.finish);
          const rng = asLtrRange(win, relative2);
          editor.selection.setRng(rng);
        });
      };
      const keyup = (event) => {
        const wrappedEvent = fromRawEvent(event);
        if (wrappedEvent.raw.shiftKey && isNavigation(wrappedEvent.raw.which)) {
          const rng = editor.selection.getRng();
          const start = SugarElement.fromDom(rng.startContainer);
          const end = SugarElement.fromDom(rng.endContainer);
          keyHandlers.keyup(wrappedEvent, start, rng.startOffset, end, rng.endOffset).each((response) => {
            handleResponse(wrappedEvent, response);
          });
        }
      };
      const keydown = (event) => {
        const wrappedEvent = fromRawEvent(event);
        resizeHandler.hide();
        const rng = editor.selection.getRng();
        const start = SugarElement.fromDom(rng.startContainer);
        const end = SugarElement.fromDom(rng.endContainer);
        const direction = onDirection(ltr, rtl)(SugarElement.fromDom(editor.selection.getStart()));
        keyHandlers.keydown(wrappedEvent, start, rng.startOffset, end, rng.endOffset, direction).each((response) => {
          handleResponse(wrappedEvent, response);
        });
        resizeHandler.show();
      };
      const isLeftMouse = (raw) => raw.button === 0;
      const isLeftButtonPressed = (raw) => {
        if (raw.buttons === void 0) {
          return true;
        }
        return (raw.buttons & 1) !== 0;
      };
      const dragStart = (_e2) => {
        mouseHandlers.clearstate();
      };
      const mouseDown = (e) => {
        if (isLeftMouse(e) && hasInternalTarget(e)) {
          mouseHandlers.mousedown(fromRawEvent(e));
        }
      };
      const mouseOver = (e) => {
        if (isLeftButtonPressed(e) && hasInternalTarget(e)) {
          mouseHandlers.mouseover(fromRawEvent(e));
        }
      };
      const mouseUp = (e) => {
        if (isLeftMouse(e) && hasInternalTarget(e)) {
          mouseHandlers.mouseup(fromRawEvent(e));
        }
      };
      const getDoubleTap = () => {
        const lastTarget = Cell(SugarElement.fromDom(body2));
        const lastTimeStamp = Cell(0);
        const touchEnd = (t) => {
          const target = SugarElement.fromDom(t.target);
          if (isTag("td")(target) || isTag("th")(target)) {
            const lT = lastTarget.get();
            const lTS = lastTimeStamp.get();
            if (eq$1(lT, target) && t.timeStamp - lTS < 300) {
              t.preventDefault();
              external$1(target, target);
            }
          }
          lastTarget.set(target);
          lastTimeStamp.set(t.timeStamp);
        };
        return { touchEnd };
      };
      const doubleTap = getDoubleTap();
      editor.on("dragstart", dragStart);
      editor.on("mousedown", mouseDown);
      editor.on("mouseover", mouseOver);
      editor.on("mouseup", mouseUp);
      editor.on("touchend", doubleTap.touchEnd);
      editor.on("keyup", keyup);
      editor.on("keydown", keydown);
      editor.on("NodeChange", syncSelection);
    });
    editor.on("PreInit", () => {
      editor.serializer.addTempAttr(ephemera.firstSelected);
      editor.serializer.addTempAttr(ephemera.lastSelected);
    });
    const clearSelectedCells = (container) => annotations.clear(SugarElement.fromDom(container));
    const getSelectedCells = () => fold(cellSelection.get(), constant([]), (cells2) => {
      return map$1(cells2, (cell2) => cell2.dom);
    }, (cell2) => [cell2.dom]);
    return {
      getSelectedCells,
      clearSelectedCells
    };
  };
  const Event2 = (fields) => {
    let handlers = [];
    const bind2 = (handler) => {
      if (handler === void 0) {
        throw new Error("Event bind error: undefined handler");
      }
      handlers.push(handler);
    };
    const unbind2 = (handler) => {
      handlers = filter$2(handlers, (h2) => {
        return h2 !== handler;
      });
    };
    const trigger = (...args) => {
      const event = {};
      each$2(fields, (name2, i) => {
        event[name2] = args[i];
      });
      each$2(handlers, (handler) => {
        handler(event);
      });
    };
    return {
      bind: bind2,
      unbind: unbind2,
      trigger
    };
  };
  const create$1 = (typeDefs) => {
    const registry = map(typeDefs, (event) => {
      return {
        bind: event.bind,
        unbind: event.unbind
      };
    });
    const trigger = map(typeDefs, (event) => {
      return event.trigger;
    });
    return {
      registry,
      trigger
    };
  };
  const last = (fn, rate) => {
    let timer = null;
    const cancel = () => {
      if (!isNull(timer)) {
        clearTimeout(timer);
        timer = null;
      }
    };
    const throttle = (...args) => {
      cancel();
      timer = setTimeout(() => {
        timer = null;
        fn.apply(null, args);
      }, rate);
    };
    return {
      cancel,
      throttle
    };
  };
  const sort = (arr) => {
    return arr.slice(0).sort();
  };
  const reqMessage = (required, keys2) => {
    throw new Error("All required keys (" + sort(required).join(", ") + ") were not specified. Specified keys were: " + sort(keys2).join(", ") + ".");
  };
  const unsuppMessage = (unsupported) => {
    throw new Error("Unsupported keys for object: " + sort(unsupported).join(", "));
  };
  const validateStrArr = (label, array) => {
    if (!isArray(array)) {
      throw new Error("The " + label + " fields must be an array. Was: " + array + ".");
    }
    each$2(array, (a) => {
      if (!isString(a)) {
        throw new Error("The value " + a + " in the " + label + " fields was not a string.");
      }
    });
  };
  const invalidTypeMessage = (incorrect, type2) => {
    throw new Error("All values need to be of type: " + type2 + ". Keys (" + sort(incorrect).join(", ") + ") were not.");
  };
  const checkDupes = (everything) => {
    const sorted = sort(everything);
    const dupe = find$1(sorted, (s, i) => {
      return i < sorted.length - 1 && s === sorted[i + 1];
    });
    dupe.each((d) => {
      throw new Error("The field: " + d + " occurs more than once in the combined fields: [" + sorted.join(", ") + "].");
    });
  };
  const base = (handleUnsupported, required) => {
    return baseWith(handleUnsupported, required, {
      validate: isFunction,
      label: "function"
    });
  };
  const baseWith = (handleUnsupported, required, pred) => {
    if (required.length === 0) {
      throw new Error("You must specify at least one required field.");
    }
    validateStrArr("required", required);
    checkDupes(required);
    return (obj) => {
      const keys$1 = keys(obj);
      const allReqd = forall(required, (req) => {
        return contains$2(keys$1, req);
      });
      if (!allReqd) {
        reqMessage(required, keys$1);
      }
      handleUnsupported(required, keys$1);
      const invalidKeys = filter$2(required, (key2) => {
        return !pred.validate(obj[key2], key2);
      });
      if (invalidKeys.length > 0) {
        invalidTypeMessage(invalidKeys, pred.label);
      }
      return obj;
    };
  };
  const handleExact = (required, keys2) => {
    const unsupported = filter$2(keys2, (key2) => {
      return !contains$2(required, key2);
    });
    if (unsupported.length > 0) {
      unsuppMessage(unsupported);
    }
  };
  const exactly = (required) => base(handleExact, required);
  const DragMode = exactly([
    "compare",
    "extract",
    "mutate",
    "sink"
  ]);
  const DragSink = exactly([
    "element",
    "start",
    "stop",
    "destroy"
  ]);
  const DragApi = exactly([
    "forceDrop",
    "drop",
    "move",
    "delayDrop"
  ]);
  const InDrag = () => {
    let previous = Optional.none();
    const reset = () => {
      previous = Optional.none();
    };
    const update2 = (mode, nu2) => {
      const result = previous.map((old) => {
        return mode.compare(old, nu2);
      });
      previous = Optional.some(nu2);
      return result;
    };
    const onEvent = (event, mode) => {
      const dataOption = mode.extract(event);
      dataOption.each((data) => {
        const offset = update2(mode, data);
        offset.each((d) => {
          events.trigger.move(d);
        });
      });
    };
    const events = create$1({ move: Event2(["info"]) });
    return {
      onEvent,
      reset,
      events: events.registry
    };
  };
  const NoDrag = () => {
    const events = create$1({ move: Event2(["info"]) });
    return {
      onEvent: noop,
      reset: noop,
      events: events.registry
    };
  };
  const Movement = () => {
    const noDragState = NoDrag();
    const inDragState = InDrag();
    let dragState = noDragState;
    const on2 = () => {
      dragState.reset();
      dragState = inDragState;
    };
    const off = () => {
      dragState.reset();
      dragState = noDragState;
    };
    const onEvent = (event, mode) => {
      dragState.onEvent(event, mode);
    };
    const isOn = () => {
      return dragState === inDragState;
    };
    return {
      on: on2,
      off,
      isOn,
      onEvent,
      events: inDragState.events
    };
  };
  const setup = (mutation, mode, settings) => {
    let active = false;
    const events = create$1({
      start: Event2([]),
      stop: Event2([])
    });
    const movement = Movement();
    const drop = () => {
      sink2.stop();
      if (movement.isOn()) {
        movement.off();
        events.trigger.stop();
      }
    };
    const throttledDrop = last(drop, 200);
    const go2 = (parent2) => {
      sink2.start(parent2);
      movement.on();
      events.trigger.start();
    };
    const mousemove = (event) => {
      throttledDrop.cancel();
      movement.onEvent(event, mode);
    };
    movement.events.move.bind((event) => {
      mode.mutate(mutation, event.info);
    });
    const on2 = () => {
      active = true;
    };
    const off = () => {
      active = false;
    };
    const runIfActive = (f) => {
      return (...args) => {
        if (active) {
          f.apply(null, args);
        }
      };
    };
    const sink2 = mode.sink(DragApi({
      forceDrop: drop,
      drop: runIfActive(drop),
      move: runIfActive(mousemove),
      delayDrop: runIfActive(throttledDrop.throttle)
    }), settings);
    const destroy2 = () => {
      sink2.destroy();
    };
    return {
      element: sink2.element,
      go: go2,
      on: on2,
      off,
      destroy: destroy2,
      events: events.registry
    };
  };
  const css = (namespace) => {
    const dashNamespace = namespace.replace(/\./g, "-");
    const resolve2 = (str) => {
      return dashNamespace + "-" + str;
    };
    return { resolve: resolve2 };
  };
  const styles$1 = css("ephox-dragster");
  const resolve$1 = styles$1.resolve;
  const Blocker = (options) => {
    const settings = {
      layerClass: resolve$1("blocker"),
      ...options
    };
    const div = SugarElement.fromTag("div");
    set$2(div, "role", "presentation");
    setAll(div, {
      position: "fixed",
      left: "0px",
      top: "0px",
      width: "100%",
      height: "100%"
    });
    add(div, resolve$1("blocker"));
    add(div, settings.layerClass);
    const element = constant(div);
    const destroy2 = () => {
      remove$6(div);
    };
    return {
      element,
      destroy: destroy2
    };
  };
  const compare = (old, nu2) => {
    return SugarPosition(nu2.left - old.left, nu2.top - old.top);
  };
  const extract = (event) => {
    return Optional.some(SugarPosition(event.x, event.y));
  };
  const mutate = (mutation, info) => {
    mutation.mutate(info.left, info.top);
  };
  const sink = (dragApi, settings) => {
    const blocker = Blocker(settings);
    const mdown = bind(blocker.element(), "mousedown", dragApi.forceDrop);
    const mup = bind(blocker.element(), "mouseup", dragApi.drop);
    const mmove = bind(blocker.element(), "mousemove", dragApi.move);
    const mout = bind(blocker.element(), "mouseout", dragApi.delayDrop);
    const destroy2 = () => {
      blocker.destroy();
      mup.unbind();
      mmove.unbind();
      mout.unbind();
      mdown.unbind();
    };
    const start = (parent2) => {
      append$1(parent2, blocker.element());
    };
    const stop = () => {
      remove$6(blocker.element());
    };
    return DragSink({
      element: blocker.element,
      start,
      stop,
      destroy: destroy2
    });
  };
  var MouseDrag = DragMode({
    compare,
    extract,
    sink,
    mutate
  });
  const transform = (mutation, settings = {}) => {
    var _a;
    const mode = (_a = settings.mode) !== null && _a !== void 0 ? _a : MouseDrag;
    return setup(mutation, mode, settings);
  };
  const styles = css("ephox-snooker");
  const resolve = styles.resolve;
  const Mutation = () => {
    const events = create$1({
      drag: Event2([
        "xDelta",
        "yDelta"
      ])
    });
    const mutate2 = (x, y) => {
      events.trigger.drag(x, y);
    };
    return {
      mutate: mutate2,
      events: events.registry
    };
  };
  const BarMutation = () => {
    const events = create$1({
      drag: Event2([
        "xDelta",
        "yDelta",
        "target"
      ])
    });
    let target = Optional.none();
    const delegate = Mutation();
    delegate.events.drag.bind((event) => {
      target.each((t) => {
        events.trigger.drag(event.xDelta, event.yDelta, t);
      });
    });
    const assign = (t) => {
      target = Optional.some(t);
    };
    const get2 = () => {
      return target;
    };
    return {
      assign,
      get: get2,
      mutate: delegate.mutate,
      events: events.registry
    };
  };
  const col = (column, x, y, w, h2) => {
    const bar = SugarElement.fromTag("div");
    setAll(bar, {
      position: "absolute",
      left: x - w / 2 + "px",
      top: y + "px",
      height: h2 + "px",
      width: w + "px"
    });
    setAll$1(bar, {
      "data-column": column,
      "role": "presentation"
    });
    return bar;
  };
  const row = (r2, x, y, w, h2) => {
    const bar = SugarElement.fromTag("div");
    setAll(bar, {
      position: "absolute",
      left: x + "px",
      top: y - h2 / 2 + "px",
      height: h2 + "px",
      width: w + "px"
    });
    setAll$1(bar, {
      "data-row": r2,
      "role": "presentation"
    });
    return bar;
  };
  const resizeBar = resolve("resizer-bar");
  const resizeRowBar = resolve("resizer-rows");
  const resizeColBar = resolve("resizer-cols");
  const BAR_THICKNESS = 7;
  const resizableRows = (warehouse, isResizable2) => bind$2(warehouse.all, (row2, i) => isResizable2(row2.element) ? [i] : []);
  const resizableColumns = (warehouse, isResizable2) => {
    const resizableCols = [];
    range$1(warehouse.grid.columns, (index2) => {
      const colElmOpt = Warehouse.getColumnAt(warehouse, index2).map((col2) => col2.element);
      if (colElmOpt.forall(isResizable2)) {
        resizableCols.push(index2);
      }
    });
    return filter$2(resizableCols, (colIndex) => {
      const columnCells = Warehouse.filterItems(warehouse, (cell2) => cell2.column === colIndex);
      return forall(columnCells, (cell2) => isResizable2(cell2.element));
    });
  };
  const destroy = (wire) => {
    const previous = descendants(wire.parent(), "." + resizeBar);
    each$2(previous, remove$6);
  };
  const drawBar = (wire, positions, create2) => {
    const origin = wire.origin();
    each$2(positions, (cpOption) => {
      cpOption.each((cp) => {
        const bar = create2(origin, cp);
        add(bar, resizeBar);
        append$1(wire.parent(), bar);
      });
    });
  };
  const refreshCol = (wire, colPositions, position, tableHeight) => {
    drawBar(wire, colPositions, (origin, cp) => {
      const colBar = col(cp.col, cp.x - origin.left, position.top - origin.top, BAR_THICKNESS, tableHeight);
      add(colBar, resizeColBar);
      return colBar;
    });
  };
  const refreshRow = (wire, rowPositions, position, tableWidth) => {
    drawBar(wire, rowPositions, (origin, cp) => {
      const rowBar = row(cp.row, position.left - origin.left, cp.y - origin.top, tableWidth, BAR_THICKNESS);
      add(rowBar, resizeRowBar);
      return rowBar;
    });
  };
  const refreshGrid = (warhouse, wire, table2, rows2, cols) => {
    const position = absolute(table2);
    const isResizable2 = wire.isResizable;
    const rowPositions = rows2.length > 0 ? height.positions(rows2, table2) : [];
    const resizableRowBars = rowPositions.length > 0 ? resizableRows(warhouse, isResizable2) : [];
    const resizableRowPositions = filter$2(rowPositions, (_pos, i) => exists(resizableRowBars, (barIndex) => i === barIndex));
    refreshRow(wire, resizableRowPositions, position, getOuter$2(table2));
    const colPositions = cols.length > 0 ? width.positions(cols, table2) : [];
    const resizableColBars = colPositions.length > 0 ? resizableColumns(warhouse, isResizable2) : [];
    const resizableColPositions = filter$2(colPositions, (_pos, i) => exists(resizableColBars, (barIndex) => i === barIndex));
    refreshCol(wire, resizableColPositions, position, getOuter$1(table2));
  };
  const refresh = (wire, table2) => {
    destroy(wire);
    if (wire.isResizable(table2)) {
      const warehouse = Warehouse.fromTable(table2);
      const rows$12 = rows(warehouse);
      const cols = columns(warehouse);
      refreshGrid(warehouse, wire, table2, rows$12, cols);
    }
  };
  const each = (wire, f) => {
    const bars = descendants(wire.parent(), "." + resizeBar);
    each$2(bars, f);
  };
  const hide = (wire) => {
    each(wire, (bar) => {
      set$1(bar, "display", "none");
    });
  };
  const show = (wire) => {
    each(wire, (bar) => {
      set$1(bar, "display", "block");
    });
  };
  const isRowBar = (element) => {
    return has(element, resizeRowBar);
  };
  const isColBar = (element) => {
    return has(element, resizeColBar);
  };
  const resizeBarDragging = resolve("resizer-bar-dragging");
  const BarManager = (wire) => {
    const mutation = BarMutation();
    const resizing = transform(mutation, {});
    let hoverTable = Optional.none();
    const getResizer = (element, type2) => {
      return Optional.from(get$b(element, type2));
    };
    mutation.events.drag.bind((event) => {
      getResizer(event.target, "data-row").each((_dataRow) => {
        const currentRow = getCssValue(event.target, "top");
        set$1(event.target, "top", currentRow + event.yDelta + "px");
      });
      getResizer(event.target, "data-column").each((_dataCol) => {
        const currentCol = getCssValue(event.target, "left");
        set$1(event.target, "left", currentCol + event.xDelta + "px");
      });
    });
    const getDelta = (target, dir) => {
      const newX = getCssValue(target, dir);
      const oldX = getAttrValue(target, "data-initial-" + dir, 0);
      return newX - oldX;
    };
    resizing.events.stop.bind(() => {
      mutation.get().each((target) => {
        hoverTable.each((table2) => {
          getResizer(target, "data-row").each((row2) => {
            const delta = getDelta(target, "top");
            remove$7(target, "data-initial-top");
            events.trigger.adjustHeight(table2, delta, parseInt(row2, 10));
          });
          getResizer(target, "data-column").each((column) => {
            const delta = getDelta(target, "left");
            remove$7(target, "data-initial-left");
            events.trigger.adjustWidth(table2, delta, parseInt(column, 10));
          });
          refresh(wire, table2);
        });
      });
    });
    const handler = (target, dir) => {
      events.trigger.startAdjust();
      mutation.assign(target);
      set$2(target, "data-initial-" + dir, getCssValue(target, dir));
      add(target, resizeBarDragging);
      set$1(target, "opacity", "0.2");
      resizing.go(wire.parent());
    };
    const mousedown = bind(wire.parent(), "mousedown", (event) => {
      if (isRowBar(event.target)) {
        handler(event.target, "top");
      }
      if (isColBar(event.target)) {
        handler(event.target, "left");
      }
    });
    const isRoot = (e) => {
      return eq$1(e, wire.view());
    };
    const findClosestEditableTable = (target) => closest$1(target, "table", isRoot).filter(isEditable$1);
    const mouseover = bind(wire.view(), "mouseover", (event) => {
      findClosestEditableTable(event.target).fold(() => {
        if (inBody(event.target)) {
          destroy(wire);
        }
      }, (table2) => {
        hoverTable = Optional.some(table2);
        refresh(wire, table2);
      });
    });
    const destroy$1 = () => {
      mousedown.unbind();
      mouseover.unbind();
      resizing.destroy();
      destroy(wire);
    };
    const refresh$1 = (tbl) => {
      refresh(wire, tbl);
    };
    const events = create$1({
      adjustHeight: Event2([
        "table",
        "delta",
        "row"
      ]),
      adjustWidth: Event2([
        "table",
        "delta",
        "column"
      ]),
      startAdjust: Event2([])
    });
    return {
      destroy: destroy$1,
      refresh: refresh$1,
      on: resizing.on,
      off: resizing.off,
      hideBars: curry(hide, wire),
      showBars: curry(show, wire),
      events: events.registry
    };
  };
  const create = (wire, resizing, lazySizing) => {
    const hdirection = height;
    const vdirection = width;
    const manager = BarManager(wire);
    const events = create$1({
      beforeResize: Event2([
        "table",
        "type"
      ]),
      afterResize: Event2([
        "table",
        "type"
      ]),
      startDrag: Event2([])
    });
    manager.events.adjustHeight.bind((event) => {
      const table2 = event.table;
      events.trigger.beforeResize(table2, "row");
      const delta = hdirection.delta(event.delta, table2);
      adjustHeight(table2, delta, event.row, hdirection);
      events.trigger.afterResize(table2, "row");
    });
    manager.events.startAdjust.bind((_event) => {
      events.trigger.startDrag();
    });
    manager.events.adjustWidth.bind((event) => {
      const table2 = event.table;
      events.trigger.beforeResize(table2, "col");
      const delta = vdirection.delta(event.delta, table2);
      const tableSize = lazySizing(table2);
      adjustWidth(table2, delta, event.column, resizing, tableSize);
      events.trigger.afterResize(table2, "col");
    });
    return {
      on: manager.on,
      off: manager.off,
      refreshBars: manager.refresh,
      hideBars: manager.hideBars,
      showBars: manager.showBars,
      destroy: manager.destroy,
      events: events.registry
    };
  };
  const TableResize = { create };
  const only = (element, isResizable2) => {
    const parent2 = isDocument(element) ? documentElement(element) : element;
    return {
      parent: constant(parent2),
      view: constant(element),
      origin: constant(SugarPosition(0, 0)),
      isResizable: isResizable2
    };
  };
  const detached = (editable, chrome, isResizable2) => {
    const origin = () => absolute(chrome);
    return {
      parent: constant(chrome),
      view: constant(editable),
      origin,
      isResizable: isResizable2
    };
  };
  const body = (editable, chrome, isResizable2) => {
    return {
      parent: constant(chrome),
      view: constant(editable),
      origin: constant(SugarPosition(0, 0)),
      isResizable: isResizable2
    };
  };
  const ResizeWire = {
    only,
    detached,
    body
  };
  const createContainer = () => {
    const container = SugarElement.fromTag("div");
    setAll(container, {
      position: "static",
      height: "0",
      width: "0",
      padding: "0",
      margin: "0",
      border: "0"
    });
    append$1(body$1(), container);
    return container;
  };
  const get = (editor, isResizable2) => {
    return editor.inline ? ResizeWire.body(SugarElement.fromDom(editor.getBody()), createContainer(), isResizable2) : ResizeWire.only(SugarElement.fromDom(editor.getDoc()), isResizable2);
  };
  const remove = (editor, wire) => {
    if (editor.inline) {
      remove$6(wire.parent());
    }
  };
  const isTable = (node) => isNonNullable(node) && node.tagName === "TABLE";
  const barResizerPrefix = "bar-";
  const isResizable = (elm) => get$b(elm, "data-mce-resize") !== "false";
  const syncPixels = (table2) => {
    const warehouse = Warehouse.fromTable(table2);
    if (!Warehouse.hasColumns(warehouse)) {
      each$2(cells$1(table2), (cell2) => {
        const computedWidth = get$a(cell2, "width");
        set$1(cell2, "width", computedWidth);
        remove$7(cell2, "width");
      });
    }
  };
  const TableResizeHandler = (editor) => {
    const selectionRng = value();
    const tableResize = value();
    const resizeWire = value();
    let startW;
    let startRawW;
    const lazySizing = (table2) => get$5(editor, table2);
    const lazyResizingBehaviour = () => isPreserveTableColumnResizing(editor) ? preserveTable() : resizeTable();
    const getNumColumns = (table2) => getGridSize(table2).columns;
    const afterCornerResize = (table2, origin, width2) => {
      const isRightEdgeResize = endsWith(origin, "e");
      if (startRawW === "") {
        convertToPercentSize(table2);
      }
      if (width2 !== startW && startRawW !== "") {
        set$1(table2, "width", startRawW);
        const resizing = lazyResizingBehaviour();
        const tableSize = lazySizing(table2);
        const col2 = isPreserveTableColumnResizing(editor) || isRightEdgeResize ? getNumColumns(table2) - 1 : 0;
        adjustWidth(table2, width2 - startW, col2, resizing, tableSize);
      } else if (isPercentage$1(startRawW)) {
        const percentW = parseFloat(startRawW.replace("%", ""));
        const targetPercentW = width2 * percentW / startW;
        set$1(table2, "width", targetPercentW + "%");
      }
      if (isPixel(startRawW)) {
        syncPixels(table2);
      }
    };
    const destroy2 = () => {
      tableResize.on((sz) => {
        sz.destroy();
      });
      resizeWire.on((w) => {
        remove(editor, w);
      });
    };
    editor.on("init", () => {
      const rawWire = get(editor, isResizable);
      resizeWire.set(rawWire);
      if (hasTableObjectResizing(editor) && hasTableResizeBars(editor)) {
        const resizing = lazyResizingBehaviour();
        const sz = TableResize.create(rawWire, resizing, lazySizing);
        sz.on();
        sz.events.startDrag.bind((_event) => {
          selectionRng.set(editor.selection.getRng());
        });
        sz.events.beforeResize.bind((event) => {
          const rawTable = event.table.dom;
          fireObjectResizeStart(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type);
        });
        sz.events.afterResize.bind((event) => {
          const table2 = event.table;
          const rawTable = table2.dom;
          removeDataStyle(table2);
          selectionRng.on((rng) => {
            editor.selection.setRng(rng);
            editor.focus();
          });
          fireObjectResized(editor, rawTable, getPixelWidth(rawTable), getPixelHeight(rawTable), barResizerPrefix + event.type);
          editor.undoManager.add();
        });
        tableResize.set(sz);
      }
    });
    editor.on("ObjectResizeStart", (e) => {
      const targetElm = e.target;
      if (isTable(targetElm)) {
        const table2 = SugarElement.fromDom(targetElm);
        each$2(editor.dom.select(".mce-clonedresizable"), (clone2) => {
          editor.dom.addClass(clone2, "mce-" + getTableColumnResizingBehaviour(editor) + "-columns");
        });
        if (!isPixelSizing(table2) && isTablePixelsForced(editor)) {
          convertToPixelSize(table2);
        } else if (!isPercentSizing(table2) && isTablePercentagesForced(editor)) {
          convertToPercentSize(table2);
        }
        if (isNoneSizing(table2) && startsWith(e.origin, barResizerPrefix)) {
          convertToPercentSize(table2);
        }
        startW = e.width;
        startRawW = isTableResponsiveForced(editor) ? "" : getRawWidth(editor, targetElm).getOr("");
      }
    });
    editor.on("ObjectResized", (e) => {
      const targetElm = e.target;
      if (isTable(targetElm)) {
        const table2 = SugarElement.fromDom(targetElm);
        const origin = e.origin;
        if (startsWith(origin, "corner-")) {
          afterCornerResize(table2, origin, e.width);
        }
        removeDataStyle(table2);
        fireTableModified(editor, table2.dom, styleModified);
      }
    });
    editor.on("SwitchMode", () => {
      tableResize.on((resize2) => {
        if (editor.mode.isReadOnly()) {
          resize2.hideBars();
        } else {
          resize2.showBars();
        }
      });
    });
    editor.on("remove", () => {
      destroy2();
    });
    const refresh2 = (table2) => {
      tableResize.on((resize2) => resize2.refreshBars(SugarElement.fromDom(table2)));
    };
    const hide2 = () => {
      tableResize.on((resize2) => resize2.hideBars());
    };
    const show2 = () => {
      tableResize.on((resize2) => resize2.showBars());
    };
    return {
      refresh: refresh2,
      hide: hide2,
      show: show2
    };
  };
  const setupTable = (editor) => {
    register(editor);
    const resizeHandler = TableResizeHandler(editor);
    const cellSelectionHandler = TableCellSelectionHandler(editor, resizeHandler);
    const actions = TableActions(editor, resizeHandler, cellSelectionHandler);
    registerCommands(editor, actions);
    registerQueryCommands(editor, actions);
    registerEvents(editor, actions);
    return {
      getSelectedCells: cellSelectionHandler.getSelectedCells,
      clearSelectedCells: cellSelectionHandler.clearSelectedCells
    };
  };
  const DomModel = (editor) => {
    const table2 = setupTable(editor);
    return { table: table2 };
  };
  var Model = () => {
    global$1.add("dom", DomModel);
  };
  Model();
})();
var _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};
const _sfc_main = {
  name: "tinymce-editor",
  components: {
    Editor
  },
  props: {
    value: {
      type: String,
      default: ""
    },
    disabled: {
      type: Boolean,
      default: false
    },
    imagesUploadHandler: {
      type: Function,
      default: () => {
      }
    },
    height: {
      type: Number,
      default: 770
    },
    plugins: {
      type: [String, Array],
      default: "preview searchreplace visualblocks visualchars fullscreen image link media code table charmap nonbreaking insertdatetime advlist lists autosave emoticons quickbars pagebreak anchor"
    },
    toolbar: {
      type: [String, Array],
      default: "code undo redo restoredraft | cut copy paste pastetext | forecolor backcolor bold italic underline strikethrough link | alignleft aligncenter alignright alignjustify outdent indent formatpainter |       styleselect formatselect fontfamily fontsize | numlist bullist  | blockquote subscript superscript removeformat |       emoticons table image media charmap pagebreak insertdatetime | fullscreen preview | searchreplace anchor"
    }
  },
  data() {
    return {
      init: {
        menubar: true,
        language_url: "/tinymce/langs/zh-Hans.js",
        language: "zh-Hans",
        skin_url: "/tinymce/skins/ui/oxide",
        min_height: 450,
        max_height: 770,
        toolbar_mode: "sliding",
        content_css: "/tinymce/skins/content/default/content.css",
        plugins: this.plugins,
        toolbar: this.toolbar,
        content_style: "p {margin: 5px 0;}",
        font_size_formats: "12px 14px 16px 18px 24px 36px 48px 56px 72px",
        font_family_formats: "\u5FAE\u8F6F\u96C5\u9ED1=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;\u82F9\u679C\u82F9\u65B9=PingFang SC,Microsoft YaHei,sans-serif;\u5B8B\u4F53=simsun,serif;\u4EFF\u5B8B\u4F53=FangSong,serif;\u9ED1\u4F53=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;",
        branding: false,
        images_upload_handler: this.imagesUploadHandler
      },
      content: this.value
    };
  },
  mounted() {
    tinymce$1.init({
      plugins: "lists",
      toolbar: "numlist bullist"
    });
  },
  methods: {},
  watch: {
    value(newValue) {
      this.content = newValue;
    },
    content(newValue) {
      this.$emit("input", newValue);
    }
  }
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_Editor = resolveComponent("Editor");
  return openBlock(), createElementBlock("div", null, [
    createVNode(_component_Editor, {
      modelValue: $data.content,
      "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => $data.content = $event),
      init: $data.init,
      disabled: $props.disabled
    }, null, 8, ["modelValue", "init", "disabled"])
  ]);
}
var index = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export { index as TinymceEditor };
