function Bd(n, e) {
  for (var t = 0; t < e.length; t++) {
    const i = e[t];
    if (typeof i != "string" && !Array.isArray(i)) {
      for (const s in i)
        if (s !== "default" && !(s in n)) {
          const r = Object.getOwnPropertyDescriptor(i, s);
          r && Object.defineProperty(n, s, r.get ? r : {
            enumerable: !0,
            get: () => i[s]
          });
        }
    }
  }
  return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Fd() {
  try {
    return navigator.userAgent.toLowerCase();
  } catch {
    return "";
  }
}
const wt = Fd(), S = {
  isMac: oc(wt),
  isWindows: Nd(wt),
  isGecko: Ld(wt),
  isSafari: $d(wt),
  isiOS: zd(wt),
  isAndroid: Hd(wt),
  isBlink: Wd(wt),
  features: {
    isRegExpUnicodePropertySupported: Ud()
  }
};
function oc(n) {
  return n.indexOf("macintosh") > -1;
}
function Nd(n) {
  return n.indexOf("windows") > -1;
}
function Ld(n) {
  return !!n.match(/gecko\/\d+/);
}
function $d(n) {
  return n.indexOf(" applewebkit/") > -1 && n.indexOf("chrome") === -1;
}
function zd(n) {
  return !!n.match(/iphone|ipad/i) || oc(n) && navigator.maxTouchPoints > 0;
}
function Hd(n) {
  return n.indexOf("android") > -1;
}
function Wd(n) {
  return n.indexOf("chrome/") > -1 && n.indexOf("edge/") < 0;
}
function Ud() {
  let n = !1;
  try {
    n = "ć".search(new RegExp("[\\p{L}]", "u")) === 0;
  } catch {
  }
  return n;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function ac(n, e, t, i) {
  t = t || function(l, c) {
    return l === c;
  };
  const s = Array.isArray(n) ? n : Array.prototype.slice.call(n), r = Array.isArray(e) ? e : Array.prototype.slice.call(e), o = jd(s, r, t);
  return i ? Gd(o, r.length) : qd(r, o);
}
function jd(n, e, t) {
  const i = uo(n, e, t);
  if (i === -1)
    return { firstIndex: -1, lastIndexOld: -1, lastIndexNew: -1 };
  const s = ho(n, i), r = ho(e, i), o = uo(s, r, t), a = n.length - o, l = e.length - o;
  return { firstIndex: i, lastIndexOld: a, lastIndexNew: l };
}
function uo(n, e, t) {
  for (let i = 0; i < Math.max(n.length, e.length); i++)
    if (n[i] === void 0 || e[i] === void 0 || !t(n[i], e[i]))
      return i;
  return -1;
}
function ho(n, e) {
  return n.slice(e).reverse();
}
function qd(n, e) {
  const t = [], { firstIndex: i, lastIndexOld: s, lastIndexNew: r } = e;
  return r - i > 0 && t.push({
    index: i,
    type: "insert",
    values: n.slice(i, r)
  }), s - i > 0 && t.push({
    index: i + (r - i),
    type: "delete",
    howMany: s - i
  }), t;
}
function Gd(n, e) {
  const { firstIndex: t, lastIndexOld: i, lastIndexNew: s } = n;
  if (t === -1)
    return Array(e).fill("equal");
  let r = [];
  return t > 0 && (r = r.concat(Array(t).fill("equal"))), s - t > 0 && (r = r.concat(Array(s - t).fill("insert"))), i - t > 0 && (r = r.concat(Array(i - t).fill("delete"))), s < e && (r = r.concat(Array(e - s).fill("equal"))), r;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function yi(n, e, t) {
  t = t || function(b, E) {
    return b === E;
  };
  const i = n.length, s = e.length;
  if (i > 200 || s > 200 || i + s > 300)
    return yi.fastDiff(n, e, t, !0);
  let r, o;
  if (s < i) {
    const b = n;
    n = e, e = b, r = "delete", o = "insert";
  } else
    r = "insert", o = "delete";
  const a = n.length, l = e.length, c = l - a, u = {}, h = {};
  function f(b) {
    const E = (h[b - 1] !== void 0 ? h[b - 1] : -1) + 1, A = h[b + 1] !== void 0 ? h[b + 1] : -1, ue = E > A ? -1 : 1;
    u[b + ue] && (u[b] = u[b + ue].slice(0)), u[b] || (u[b] = []), u[b].push(E > A ? r : o);
    let ke = Math.max(E, A), ge = ke - b;
    for (; ge < a && ke < l && t(n[ge], e[ke]); )
      ge++, ke++, u[b].push("equal");
    return ke;
  }
  let m = 0, p;
  do {
    for (p = -m; p < c; p++)
      h[p] = f(p);
    for (p = c + m; p > c; p--)
      h[p] = f(p);
    h[c] = f(c), m++;
  } while (h[c] !== l);
  return u[c].slice(1);
}
yi.fastDiff = ac;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function fo() {
  return function n() {
    n.called = !0;
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ze {
  /**
   * @param source The emitter.
   * @param name The event name.
   */
  constructor(e, t) {
    this.source = e, this.name = t, this.path = [], this.stop = fo(), this.off = fo();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const le = new Array(256).fill("").map((n, e) => ("0" + e.toString(16)).slice(-2));
function Ye() {
  const n = Math.random() * 4294967296 >>> 0, e = Math.random() * 4294967296 >>> 0, t = Math.random() * 4294967296 >>> 0, i = Math.random() * 4294967296 >>> 0;
  return "e" + le[n >> 0 & 255] + le[n >> 8 & 255] + le[n >> 16 & 255] + le[n >> 24 & 255] + le[e >> 0 & 255] + le[e >> 8 & 255] + le[e >> 16 & 255] + le[e >> 24 & 255] + le[t >> 0 & 255] + le[t >> 8 & 255] + le[t >> 16 & 255] + le[t >> 24 & 255] + le[i >> 0 & 255] + le[i >> 8 & 255] + le[i >> 16 & 255] + le[i >> 24 & 255];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const be = {
  get(n = "normal") {
    return typeof n != "number" ? this[n] || this.normal : n;
  },
  highest: 1e5,
  high: 1e3,
  normal: 0,
  low: -1e3,
  lowest: -1e5
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Kd(n, e) {
  const t = be.get(e.priority);
  for (let i = 0; i < n.length; i++)
    if (be.get(n[i].priority) < t) {
      n.splice(i, 0, e);
      return;
    }
  n.push(e);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Jd = "https://ckeditor.com/docs/ckeditor5/latest/support/error-codes.html";
class d extends Error {
  /**
   * Creates an instance of the CKEditorError class.
   *
   * @param errorName The error id in an `error-name` format. A link to this error documentation page will be added
   * to the thrown error's `message`.
   * @param context A context of the error by which the {@link module:watchdog/watchdog~Watchdog watchdog}
   * is able to determine which editor crashed. It should be an editor instance or a property connected to it. It can be also
   * a `null` value if the editor should not be restarted in case of the error (e.g. during the editor initialization).
   * The error context should be checked using the `areConnectedThroughProperties( editor, context )` utility
   * to check if the object works as the context.
   * @param data Additional data describing the error. A stringified version of this object
   * will be appended to the error message, so the data are quickly visible in the console. The original
   * data object will also be later available under the {@link #data} property.
   */
  constructor(e, t, i) {
    super(Zd(e, i)), this.name = "CKEditorError", this.context = t, this.data = i;
  }
  /**
   * Checks if the error is of the `CKEditorError` type.
   */
  is(e) {
    return e === "CKEditorError";
  }
  /**
   * A utility that ensures that the thrown error is a {@link module:utils/ckeditorerror~CKEditorError} one.
   * It is useful when combined with the {@link module:watchdog/watchdog~Watchdog} feature, which can restart the editor in case
   * of a {@link module:utils/ckeditorerror~CKEditorError} error.
   *
   * @param err The error to rethrow.
   * @param context An object connected through properties with the editor instance. This context will be used
   * by the watchdog to verify which editor should be restarted.
   */
  static rethrowUnexpectedError(e, t) {
    if (e.is && e.is("CKEditorError"))
      throw e;
    const i = new d(e.message, t);
    throw i.stack = e.stack, i;
  }
}
function q(n, e) {
  console.warn(...Yd(n, e));
}
function lc(n) {
  return `
Read more: ${Jd}#error-${n}`;
}
function Zd(n, e) {
  const t = /* @__PURE__ */ new WeakSet(), s = e ? ` ${JSON.stringify(e, (o, a) => {
    if (typeof a == "object" && a !== null) {
      if (t.has(a))
        return `[object ${a.constructor.name}]`;
      t.add(a);
    }
    return a;
  })}` : "", r = lc(n);
  return n + s + r;
}
function Yd(n, e) {
  const t = lc(n);
  return e ? [n, e, t] : [n, t];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Xd = "38.1.1", Qd = new Date(2023, 6, 11);
/* istanbul ignore next -- @preserve */
const mo = typeof window == "object" ? window : global;
/* istanbul ignore next -- @preserve */
if (mo.CKEDITOR_VERSION)
  throw new d("ckeditor-duplicated-modules", null);
mo.CKEDITOR_VERSION = Xd;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const jt = Symbol("listeningTo"), xs = Symbol("emitterId"), Ue = Symbol("delegations"), cc = N(Object);
function N(n) {
  if (!n)
    return cc;
  class e extends n {
    on(i, s, r) {
      this.listenTo(this, i, s, r);
    }
    once(i, s, r) {
      let o = !1;
      const a = (l, ...c) => {
        o || (o = !0, l.off(), s.call(this, l, ...c));
      };
      this.listenTo(this, i, a, r);
    }
    off(i, s) {
      this.stopListening(this, i, s);
    }
    listenTo(i, s, r, o = {}) {
      let a, l;
      this[jt] || (this[jt] = {});
      const c = this[jt];
      jn(i) || uc(i);
      const u = jn(i);
      (a = c[u]) || (a = c[u] = {
        emitter: i,
        callbacks: {}
      }), (l = a.callbacks[s]) || (l = a.callbacks[s] = []), l.push(r), sf(this, i, s, r, o);
    }
    stopListening(i, s, r) {
      const o = this[jt];
      let a = i && jn(i);
      const l = o && a ? o[a] : void 0, c = l && s ? l.callbacks[s] : void 0;
      if (!(!o || i && !l || s && !c))
        if (r)
          qn(this, i, s, r), c.indexOf(r) !== -1 && (c.length === 1 ? delete l.callbacks[s] : qn(this, i, s, r));
        else if (c) {
          for (; r = c.pop(); )
            qn(this, i, s, r);
          delete l.callbacks[s];
        } else if (l) {
          for (s in l.callbacks)
            this.stopListening(i, s);
          delete o[a];
        } else {
          for (a in o)
            this.stopListening(o[a].emitter);
          delete this[jt];
        }
    }
    fire(i, ...s) {
      try {
        const r = i instanceof Ze ? i : new Ze(this, i), o = r.name;
        let a = dc(this, o);
        if (r.path.push(this), a) {
          const c = [r, ...s];
          a = Array.from(a);
          for (let u = 0; u < a.length && (a[u].callback.apply(this, c), r.off.called && (delete r.off.called, this._removeEventListener(o, a[u].callback)), !r.stop.called); u++)
            ;
        }
        const l = this[Ue];
        if (l) {
          const c = l.get(o), u = l.get("*");
          c && go(c, r, s), u && go(u, r, s);
        }
        return r.return;
      } catch (r) {
        /* istanbul ignore next -- @preserve */
        d.rethrowUnexpectedError(r, this);
      }
    }
    delegate(...i) {
      return {
        to: (s, r) => {
          this[Ue] || (this[Ue] = /* @__PURE__ */ new Map()), i.forEach((o) => {
            const a = this[Ue].get(o);
            a ? a.set(s, r) : this[Ue].set(o, /* @__PURE__ */ new Map([[s, r]]));
          });
        }
      };
    }
    stopDelegating(i, s) {
      if (this[Ue])
        if (!i)
          this[Ue].clear();
        else if (!s)
          this[Ue].delete(i);
        else {
          const r = this[Ue].get(i);
          r && r.delete(s);
        }
    }
    _addEventListener(i, s, r) {
      nf(this, i);
      const o = Ss(this, i), a = be.get(r.priority), l = {
        callback: s,
        priority: a
      };
      for (const c of o)
        Kd(c, l);
    }
    _removeEventListener(i, s) {
      const r = Ss(this, i);
      for (const o of r)
        for (let a = 0; a < o.length; a++)
          o[a].callback == s && (o.splice(a, 1), a--);
    }
  }
  return e;
}
[
  "on",
  "once",
  "off",
  "listenTo",
  "stopListening",
  "fire",
  "delegate",
  "stopDelegating",
  "_addEventListener",
  "_removeEventListener"
].forEach((n) => {
  N[n] = cc.prototype[n];
});
function ef(n, e) {
  const t = n[jt];
  return t && t[e] ? t[e].emitter : null;
}
function uc(n, e) {
  n[xs] || (n[xs] = e || Ye());
}
function jn(n) {
  return n[xs];
}
function hc(n) {
  return n._events || Object.defineProperty(n, "_events", {
    value: {}
  }), n._events;
}
function tf() {
  return {
    callbacks: [],
    childEvents: []
  };
}
function nf(n, e) {
  const t = hc(n);
  if (t[e])
    return;
  let i = e, s = null;
  const r = [];
  for (; i !== "" && !t[i]; )
    t[i] = tf(), r.push(t[i]), s && t[i].childEvents.push(s), s = i, i = i.substr(0, i.lastIndexOf(":"));
  if (i !== "") {
    for (const o of r)
      o.callbacks = t[i].callbacks.slice();
    t[i].childEvents.push(s);
  }
}
function Ss(n, e) {
  const t = hc(n)[e];
  if (!t)
    return [];
  let i = [t.callbacks];
  for (let s = 0; s < t.childEvents.length; s++) {
    const r = Ss(n, t.childEvents[s]);
    i = i.concat(r);
  }
  return i;
}
function dc(n, e) {
  let t;
  return !n._events || !(t = n._events[e]) || !t.callbacks.length ? e.indexOf(":") > -1 ? dc(n, e.substr(0, e.lastIndexOf(":"))) : null : t.callbacks;
}
function go(n, e, t) {
  for (let [i, s] of n) {
    s ? typeof s == "function" && (s = s(e.name)) : s = e.name;
    const r = new Ze(e.source, s);
    r.path = [...e.path], i.fire(r, ...t);
  }
}
function sf(n, e, t, i, s) {
  e._addEventListener ? e._addEventListener(t, i, s) : n._addEventListener.call(e, t, i, s);
}
function qn(n, e, t, i) {
  e._removeEventListener ? e._removeEventListener(t, i) : n._removeEventListener.call(e, t, i);
}
var rf = typeof global == "object" && global && global.Object === Object && global;
const fc = rf;
var of = typeof self == "object" && self && self.Object === Object && self, af = fc || of || Function("return this")();
const Re = af;
var lf = Re.Symbol;
const $e = lf;
var mc = Object.prototype, cf = mc.hasOwnProperty, uf = mc.toString, mi = $e ? $e.toStringTag : void 0;
function hf(n) {
  var e = cf.call(n, mi), t = n[mi];
  try {
    n[mi] = void 0;
    var i = !0;
  } catch {
  }
  var s = uf.call(n);
  return i && (e ? n[mi] = t : delete n[mi]), s;
}
var df = Object.prototype, ff = df.toString;
function mf(n) {
  return ff.call(n);
}
var gf = "[object Null]", pf = "[object Undefined]", po = $e ? $e.toStringTag : void 0;
function dt(n) {
  return n == null ? n === void 0 ? pf : gf : po && po in Object(n) ? hf(n) : mf(n);
}
function Ae(n) {
  return n != null && typeof n == "object";
}
var wf = "[object Symbol]";
function xn(n) {
  return typeof n == "symbol" || Ae(n) && dt(n) == wf;
}
function gc(n, e) {
  for (var t = -1, i = n == null ? 0 : n.length, s = Array(i); ++t < i; )
    s[t] = e(n[t], t, n);
  return s;
}
var bf = Array.isArray;
const he = bf;
var _f = 1 / 0, wo = $e ? $e.prototype : void 0, bo = wo ? wo.toString : void 0;
function pc(n) {
  if (typeof n == "string")
    return n;
  if (he(n))
    return gc(n, pc) + "";
  if (xn(n))
    return bo ? bo.call(n) : "";
  var e = n + "";
  return e == "0" && 1 / n == -_f ? "-0" : e;
}
var vf = /\s/;
function yf(n) {
  for (var e = n.length; e-- && vf.test(n.charAt(e)); )
    ;
  return e;
}
var kf = /^\s+/;
function Cf(n) {
  return n && n.slice(0, yf(n) + 1).replace(kf, "");
}
function G(n) {
  var e = typeof n;
  return n != null && (e == "object" || e == "function");
}
var _o = 0 / 0, Ef = /^[-+]0x[0-9a-f]+$/i, Af = /^0b[01]+$/i, Tf = /^0o[0-7]+$/i, Pf = parseInt;
function vo(n) {
  if (typeof n == "number")
    return n;
  if (xn(n))
    return _o;
  if (G(n)) {
    var e = typeof n.valueOf == "function" ? n.valueOf() : n;
    n = G(e) ? e + "" : e;
  }
  if (typeof n != "string")
    return n === 0 ? n : +n;
  n = Cf(n);
  var t = Af.test(n);
  return t || Tf.test(n) ? Pf(n.slice(2), t ? 2 : 8) : Ef.test(n) ? _o : +n;
}
function kt(n) {
  return n;
}
var xf = "[object AsyncFunction]", Sf = "[object Function]", If = "[object GeneratorFunction]", Rf = "[object Proxy]";
function Pt(n) {
  if (!G(n))
    return !1;
  var e = dt(n);
  return e == Sf || e == If || e == xf || e == Rf;
}
var Of = Re["__core-js_shared__"];
const Gn = Of;
var yo = function() {
  var n = /[^.]+$/.exec(Gn && Gn.keys && Gn.keys.IE_PROTO || "");
  return n ? "Symbol(src)_1." + n : "";
}();
function Mf(n) {
  return !!yo && yo in n;
}
var Vf = Function.prototype, Df = Vf.toString;
function Rt(n) {
  if (n != null) {
    try {
      return Df.call(n);
    } catch {
    }
    try {
      return n + "";
    } catch {
    }
  }
  return "";
}
var Bf = /[\\^$.*+?()[\]{}|]/g, Ff = /^\[object .+?Constructor\]$/, Nf = Function.prototype, Lf = Object.prototype, $f = Nf.toString, zf = Lf.hasOwnProperty, Hf = RegExp(
  "^" + $f.call(zf).replace(Bf, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
);
function Wf(n) {
  if (!G(n) || Mf(n))
    return !1;
  var e = Pt(n) ? Hf : Ff;
  return e.test(Rt(n));
}
function Uf(n, e) {
  return n == null ? void 0 : n[e];
}
function Ot(n, e) {
  var t = Uf(n, e);
  return Wf(t) ? t : void 0;
}
var jf = Ot(Re, "WeakMap");
const Is = jf;
var ko = Object.create, qf = function() {
  function n() {
  }
  return function(e) {
    if (!G(e))
      return {};
    if (ko)
      return ko(e);
    n.prototype = e;
    var t = new n();
    return n.prototype = void 0, t;
  };
}();
const Gf = qf;
function Kf(n, e, t) {
  switch (t.length) {
    case 0:
      return n.call(e);
    case 1:
      return n.call(e, t[0]);
    case 2:
      return n.call(e, t[0], t[1]);
    case 3:
      return n.call(e, t[0], t[1], t[2]);
  }
  return n.apply(e, t);
}
function dr(n, e) {
  var t = -1, i = n.length;
  for (e || (e = Array(i)); ++t < i; )
    e[t] = n[t];
  return e;
}
var Jf = 800, Zf = 16, Yf = Date.now;
function Xf(n) {
  var e = 0, t = 0;
  return function() {
    var i = Yf(), s = Zf - (i - t);
    if (t = i, s > 0) {
      if (++e >= Jf)
        return arguments[0];
    } else
      e = 0;
    return n.apply(void 0, arguments);
  };
}
function Qf(n) {
  return function() {
    return n;
  };
}
var em = function() {
  try {
    var n = Ot(Object, "defineProperty");
    return n({}, "", {}), n;
  } catch {
  }
}();
const hn = em;
var tm = hn ? function(n, e) {
  return hn(n, "toString", {
    configurable: !0,
    enumerable: !1,
    value: Qf(e),
    writable: !0
  });
} : kt;
const im = tm;
var nm = Xf(im);
const sm = nm;
function rm(n, e) {
  for (var t = -1, i = n == null ? 0 : n.length; ++t < i && e(n[t], t, n) !== !1; )
    ;
  return n;
}
function om(n, e, t, i) {
  for (var s = n.length, r = t + (i ? 1 : -1); i ? r-- : ++r < s; )
    if (e(n[r], r, n))
      return r;
  return -1;
}
function am(n) {
  return n !== n;
}
function lm(n, e, t) {
  for (var i = t - 1, s = n.length; ++i < s; )
    if (n[i] === e)
      return i;
  return -1;
}
function cm(n, e, t) {
  return e === e ? lm(n, e, t) : om(n, am, t);
}
var um = 9007199254740991, hm = /^(?:0|[1-9]\d*)$/;
function fr(n, e) {
  var t = typeof n;
  return e = e ?? um, !!e && (t == "number" || t != "symbol" && hm.test(n)) && n > -1 && n % 1 == 0 && n < e;
}
function mr(n, e, t) {
  e == "__proto__" && hn ? hn(n, e, {
    configurable: !0,
    enumerable: !0,
    value: t,
    writable: !0
  }) : n[e] = t;
}
function zi(n, e) {
  return n === e || n !== n && e !== e;
}
var dm = Object.prototype, fm = dm.hasOwnProperty;
function gr(n, e, t) {
  var i = n[e];
  (!(fm.call(n, e) && zi(i, t)) || t === void 0 && !(e in n)) && mr(n, e, t);
}
function ui(n, e, t, i) {
  var s = !t;
  t || (t = {});
  for (var r = -1, o = e.length; ++r < o; ) {
    var a = e[r], l = i ? i(t[a], n[a], a, t, n) : void 0;
    l === void 0 && (l = n[a]), s ? mr(t, a, l) : gr(t, a, l);
  }
  return t;
}
var Co = Math.max;
function mm(n, e, t) {
  return e = Co(e === void 0 ? n.length - 1 : e, 0), function() {
    for (var i = arguments, s = -1, r = Co(i.length - e, 0), o = Array(r); ++s < r; )
      o[s] = i[e + s];
    s = -1;
    for (var a = Array(e + 1); ++s < e; )
      a[s] = i[s];
    return a[e] = t(o), Kf(n, this, a);
  };
}
function wc(n, e) {
  return sm(mm(n, e, kt), n + "");
}
var gm = 9007199254740991;
function bc(n) {
  return typeof n == "number" && n > -1 && n % 1 == 0 && n <= gm;
}
function Sn(n) {
  return n != null && bc(n.length) && !Pt(n);
}
function pm(n, e, t) {
  if (!G(t))
    return !1;
  var i = typeof e;
  return (i == "number" ? Sn(t) && fr(e, t.length) : i == "string" && e in t) ? zi(t[e], n) : !1;
}
function pr(n) {
  return wc(function(e, t) {
    var i = -1, s = t.length, r = s > 1 ? t[s - 1] : void 0, o = s > 2 ? t[2] : void 0;
    for (r = n.length > 3 && typeof r == "function" ? (s--, r) : void 0, o && pm(t[0], t[1], o) && (r = s < 3 ? void 0 : r, s = 1), e = Object(e); ++i < s; ) {
      var a = t[i];
      a && n(e, a, i, r);
    }
    return e;
  });
}
var wm = Object.prototype;
function wr(n) {
  var e = n && n.constructor, t = typeof e == "function" && e.prototype || wm;
  return n === t;
}
function bm(n, e) {
  for (var t = -1, i = Array(n); ++t < n; )
    i[t] = e(t);
  return i;
}
var _m = "[object Arguments]";
function Eo(n) {
  return Ae(n) && dt(n) == _m;
}
var _c = Object.prototype, vm = _c.hasOwnProperty, ym = _c.propertyIsEnumerable, km = Eo(function() {
  return arguments;
}()) ? Eo : function(n) {
  return Ae(n) && vm.call(n, "callee") && !ym.call(n, "callee");
};
const Rs = km;
function Cm() {
  return !1;
}
var vc = typeof exports == "object" && exports && !exports.nodeType && exports, Ao = vc && typeof module == "object" && module && !module.nodeType && module, Em = Ao && Ao.exports === vc, To = Em ? Re.Buffer : void 0, Am = To ? To.isBuffer : void 0, Tm = Am || Cm;
const Pi = Tm;
var Pm = "[object Arguments]", xm = "[object Array]", Sm = "[object Boolean]", Im = "[object Date]", Rm = "[object Error]", Om = "[object Function]", Mm = "[object Map]", Vm = "[object Number]", Dm = "[object Object]", Bm = "[object RegExp]", Fm = "[object Set]", Nm = "[object String]", Lm = "[object WeakMap]", $m = "[object ArrayBuffer]", zm = "[object DataView]", Hm = "[object Float32Array]", Wm = "[object Float64Array]", Um = "[object Int8Array]", jm = "[object Int16Array]", qm = "[object Int32Array]", Gm = "[object Uint8Array]", Km = "[object Uint8ClampedArray]", Jm = "[object Uint16Array]", Zm = "[object Uint32Array]", W = {};
W[Hm] = W[Wm] = W[Um] = W[jm] = W[qm] = W[Gm] = W[Km] = W[Jm] = W[Zm] = !0;
W[Pm] = W[xm] = W[$m] = W[Sm] = W[zm] = W[Im] = W[Rm] = W[Om] = W[Mm] = W[Vm] = W[Dm] = W[Bm] = W[Fm] = W[Nm] = W[Lm] = !1;
function Ym(n) {
  return Ae(n) && bc(n.length) && !!W[dt(n)];
}
function In(n) {
  return function(e) {
    return n(e);
  };
}
var yc = typeof exports == "object" && exports && !exports.nodeType && exports, ki = yc && typeof module == "object" && module && !module.nodeType && module, Xm = ki && ki.exports === yc, Kn = Xm && fc.process, Qm = function() {
  try {
    var n = ki && ki.require && ki.require("util").types;
    return n || Kn && Kn.binding && Kn.binding("util");
  } catch {
  }
}();
const ei = Qm;
var Po = ei && ei.isTypedArray, eg = Po ? In(Po) : Ym;
const br = eg;
var tg = Object.prototype, ig = tg.hasOwnProperty;
function kc(n, e) {
  var t = he(n), i = !t && Rs(n), s = !t && !i && Pi(n), r = !t && !i && !s && br(n), o = t || i || s || r, a = o ? bm(n.length, String) : [], l = a.length;
  for (var c in n)
    (e || ig.call(n, c)) && !(o && // Safari 9 has enumerable `arguments.length` in strict mode.
    (c == "length" || // Node.js 0.10 has enumerable non-index properties on buffers.
    s && (c == "offset" || c == "parent") || // PhantomJS 2 has enumerable non-index properties on typed arrays.
    r && (c == "buffer" || c == "byteLength" || c == "byteOffset") || // Skip index properties.
    fr(c, l))) && a.push(c);
  return a;
}
function Cc(n, e) {
  return function(t) {
    return n(e(t));
  };
}
var ng = Cc(Object.keys, Object);
const sg = ng;
var rg = Object.prototype, og = rg.hasOwnProperty;
function ag(n) {
  if (!wr(n))
    return sg(n);
  var e = [];
  for (var t in Object(n))
    og.call(n, t) && t != "constructor" && e.push(t);
  return e;
}
function _r(n) {
  return Sn(n) ? kc(n) : ag(n);
}
function lg(n) {
  var e = [];
  if (n != null)
    for (var t in Object(n))
      e.push(t);
  return e;
}
var cg = Object.prototype, ug = cg.hasOwnProperty;
function hg(n) {
  if (!G(n))
    return lg(n);
  var e = wr(n), t = [];
  for (var i in n)
    i == "constructor" && (e || !ug.call(n, i)) || t.push(i);
  return t;
}
function hi(n) {
  return Sn(n) ? kc(n, !0) : hg(n);
}
var dg = pr(function(n, e) {
  ui(e, hi(e), n);
});
const Ec = dg;
var fg = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, mg = /^\w*$/;
function gg(n, e) {
  if (he(n))
    return !1;
  var t = typeof n;
  return t == "number" || t == "symbol" || t == "boolean" || n == null || xn(n) ? !0 : mg.test(n) || !fg.test(n) || e != null && n in Object(e);
}
var pg = Ot(Object, "create");
const xi = pg;
function wg() {
  this.__data__ = xi ? xi(null) : {}, this.size = 0;
}
function bg(n) {
  var e = this.has(n) && delete this.__data__[n];
  return this.size -= e ? 1 : 0, e;
}
var _g = "__lodash_hash_undefined__", vg = Object.prototype, yg = vg.hasOwnProperty;
function kg(n) {
  var e = this.__data__;
  if (xi) {
    var t = e[n];
    return t === _g ? void 0 : t;
  }
  return yg.call(e, n) ? e[n] : void 0;
}
var Cg = Object.prototype, Eg = Cg.hasOwnProperty;
function Ag(n) {
  var e = this.__data__;
  return xi ? e[n] !== void 0 : Eg.call(e, n);
}
var Tg = "__lodash_hash_undefined__";
function Pg(n, e) {
  var t = this.__data__;
  return this.size += this.has(n) ? 0 : 1, t[n] = xi && e === void 0 ? Tg : e, this;
}
function xt(n) {
  var e = -1, t = n == null ? 0 : n.length;
  for (this.clear(); ++e < t; ) {
    var i = n[e];
    this.set(i[0], i[1]);
  }
}
xt.prototype.clear = wg;
xt.prototype.delete = bg;
xt.prototype.get = kg;
xt.prototype.has = Ag;
xt.prototype.set = Pg;
function xg() {
  this.__data__ = [], this.size = 0;
}
function Rn(n, e) {
  for (var t = n.length; t--; )
    if (zi(n[t][0], e))
      return t;
  return -1;
}
var Sg = Array.prototype, Ig = Sg.splice;
function Rg(n) {
  var e = this.__data__, t = Rn(e, n);
  if (t < 0)
    return !1;
  var i = e.length - 1;
  return t == i ? e.pop() : Ig.call(e, t, 1), --this.size, !0;
}
function Og(n) {
  var e = this.__data__, t = Rn(e, n);
  return t < 0 ? void 0 : e[t][1];
}
function Mg(n) {
  return Rn(this.__data__, n) > -1;
}
function Vg(n, e) {
  var t = this.__data__, i = Rn(t, n);
  return i < 0 ? (++this.size, t.push([n, e])) : t[i][1] = e, this;
}
function Qe(n) {
  var e = -1, t = n == null ? 0 : n.length;
  for (this.clear(); ++e < t; ) {
    var i = n[e];
    this.set(i[0], i[1]);
  }
}
Qe.prototype.clear = xg;
Qe.prototype.delete = Rg;
Qe.prototype.get = Og;
Qe.prototype.has = Mg;
Qe.prototype.set = Vg;
var Dg = Ot(Re, "Map");
const Si = Dg;
function Bg() {
  this.size = 0, this.__data__ = {
    hash: new xt(),
    map: new (Si || Qe)(),
    string: new xt()
  };
}
function Fg(n) {
  var e = typeof n;
  return e == "string" || e == "number" || e == "symbol" || e == "boolean" ? n !== "__proto__" : n === null;
}
function On(n, e) {
  var t = n.__data__;
  return Fg(e) ? t[typeof e == "string" ? "string" : "hash"] : t.map;
}
function Ng(n) {
  var e = On(this, n).delete(n);
  return this.size -= e ? 1 : 0, e;
}
function Lg(n) {
  return On(this, n).get(n);
}
function $g(n) {
  return On(this, n).has(n);
}
function zg(n, e) {
  var t = On(this, n), i = t.size;
  return t.set(n, e), this.size += t.size == i ? 0 : 1, this;
}
function et(n) {
  var e = -1, t = n == null ? 0 : n.length;
  for (this.clear(); ++e < t; ) {
    var i = n[e];
    this.set(i[0], i[1]);
  }
}
et.prototype.clear = Bg;
et.prototype.delete = Ng;
et.prototype.get = Lg;
et.prototype.has = $g;
et.prototype.set = zg;
var Hg = "Expected a function";
function vr(n, e) {
  if (typeof n != "function" || e != null && typeof e != "function")
    throw new TypeError(Hg);
  var t = function() {
    var i = arguments, s = e ? e.apply(this, i) : i[0], r = t.cache;
    if (r.has(s))
      return r.get(s);
    var o = n.apply(this, i);
    return t.cache = r.set(s, o) || r, o;
  };
  return t.cache = new (vr.Cache || et)(), t;
}
vr.Cache = et;
var Wg = 500;
function Ug(n) {
  var e = vr(n, function(i) {
    return t.size === Wg && t.clear(), i;
  }), t = e.cache;
  return e;
}
var jg = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g, qg = /\\(\\)?/g, Gg = Ug(function(n) {
  var e = [];
  return n.charCodeAt(0) === 46 && e.push(""), n.replace(jg, function(t, i, s, r) {
    e.push(s ? r.replace(qg, "$1") : i || t);
  }), e;
});
const Kg = Gg;
function Mn(n) {
  return n == null ? "" : pc(n);
}
function yr(n, e) {
  return he(n) ? n : gg(n, e) ? [n] : Kg(Mn(n));
}
var Jg = 1 / 0;
function kr(n) {
  if (typeof n == "string" || xn(n))
    return n;
  var e = n + "";
  return e == "0" && 1 / n == -Jg ? "-0" : e;
}
function Ac(n, e) {
  e = yr(e, n);
  for (var t = 0, i = e.length; n != null && t < i; )
    n = n[kr(e[t++])];
  return t && t == i ? n : void 0;
}
function dn(n, e, t) {
  var i = n == null ? void 0 : Ac(n, e);
  return i === void 0 ? t : i;
}
function Tc(n, e) {
  for (var t = -1, i = e.length, s = n.length; ++t < i; )
    n[s + t] = e[t];
  return n;
}
var Zg = Cc(Object.getPrototypeOf, Object);
const Cr = Zg;
var Yg = "[object Object]", Xg = Function.prototype, Qg = Object.prototype, Pc = Xg.toString, ep = Qg.hasOwnProperty, tp = Pc.call(Object);
function de(n) {
  if (!Ae(n) || dt(n) != Yg)
    return !1;
  var e = Cr(n);
  if (e === null)
    return !0;
  var t = ep.call(e, "constructor") && e.constructor;
  return typeof t == "function" && t instanceof t && Pc.call(t) == tp;
}
function xc(n, e, t) {
  var i = -1, s = n.length;
  e < 0 && (e = -e > s ? 0 : s + e), t = t > s ? s : t, t < 0 && (t += s), s = e > t ? 0 : t - e >>> 0, e >>>= 0;
  for (var r = Array(s); ++i < s; )
    r[i] = n[i + e];
  return r;
}
function ip(n, e, t) {
  var i = n.length;
  return t = t === void 0 ? i : t, !e && t >= i ? n : xc(n, e, t);
}
var np = "\\ud800-\\udfff", sp = "\\u0300-\\u036f", rp = "\\ufe20-\\ufe2f", op = "\\u20d0-\\u20ff", ap = sp + rp + op, lp = "\\ufe0e\\ufe0f", cp = "\\u200d", up = RegExp("[" + cp + np + ap + lp + "]");
function Sc(n) {
  return up.test(n);
}
function hp(n) {
  return n.split("");
}
var Ic = "\\ud800-\\udfff", dp = "\\u0300-\\u036f", fp = "\\ufe20-\\ufe2f", mp = "\\u20d0-\\u20ff", gp = dp + fp + mp, pp = "\\ufe0e\\ufe0f", wp = "[" + Ic + "]", Os = "[" + gp + "]", Ms = "\\ud83c[\\udffb-\\udfff]", bp = "(?:" + Os + "|" + Ms + ")", Rc = "[^" + Ic + "]", Oc = "(?:\\ud83c[\\udde6-\\uddff]){2}", Mc = "[\\ud800-\\udbff][\\udc00-\\udfff]", _p = "\\u200d", Vc = bp + "?", Dc = "[" + pp + "]?", vp = "(?:" + _p + "(?:" + [Rc, Oc, Mc].join("|") + ")" + Dc + Vc + ")*", yp = Dc + Vc + vp, kp = "(?:" + [Rc + Os + "?", Os, Oc, Mc, wp].join("|") + ")", Cp = RegExp(Ms + "(?=" + Ms + ")|" + kp + yp, "g");
function Ep(n) {
  return n.match(Cp) || [];
}
function Ap(n) {
  return Sc(n) ? Ep(n) : hp(n);
}
function Tp(n) {
  return function(e) {
    e = Mn(e);
    var t = Sc(e) ? Ap(e) : void 0, i = t ? t[0] : e.charAt(0), s = t ? ip(t, 1).join("") : e.slice(1);
    return i[n]() + s;
  };
}
var Pp = Tp("toUpperCase");
const Bc = Pp;
function xp(n, e, t, i) {
  var s = -1, r = n == null ? 0 : n.length;
  for (i && r && (t = n[++s]); ++s < r; )
    t = e(t, n[s], s, n);
  return t;
}
function Sp(n) {
  return function(e) {
    return n == null ? void 0 : n[e];
  };
}
var Ip = {
  // Latin-1 Supplement block.
  À: "A",
  Á: "A",
  Â: "A",
  Ã: "A",
  Ä: "A",
  Å: "A",
  à: "a",
  á: "a",
  â: "a",
  ã: "a",
  ä: "a",
  å: "a",
  Ç: "C",
  ç: "c",
  Ð: "D",
  ð: "d",
  È: "E",
  É: "E",
  Ê: "E",
  Ë: "E",
  è: "e",
  é: "e",
  ê: "e",
  ë: "e",
  Ì: "I",
  Í: "I",
  Î: "I",
  Ï: "I",
  ì: "i",
  í: "i",
  î: "i",
  ï: "i",
  Ñ: "N",
  ñ: "n",
  Ò: "O",
  Ó: "O",
  Ô: "O",
  Õ: "O",
  Ö: "O",
  Ø: "O",
  ò: "o",
  ó: "o",
  ô: "o",
  õ: "o",
  ö: "o",
  ø: "o",
  Ù: "U",
  Ú: "U",
  Û: "U",
  Ü: "U",
  ù: "u",
  ú: "u",
  û: "u",
  ü: "u",
  Ý: "Y",
  ý: "y",
  ÿ: "y",
  Æ: "Ae",
  æ: "ae",
  Þ: "Th",
  þ: "th",
  ß: "ss",
  // Latin Extended-A block.
  Ā: "A",
  Ă: "A",
  Ą: "A",
  ā: "a",
  ă: "a",
  ą: "a",
  Ć: "C",
  Ĉ: "C",
  Ċ: "C",
  Č: "C",
  ć: "c",
  ĉ: "c",
  ċ: "c",
  č: "c",
  Ď: "D",
  Đ: "D",
  ď: "d",
  đ: "d",
  Ē: "E",
  Ĕ: "E",
  Ė: "E",
  Ę: "E",
  Ě: "E",
  ē: "e",
  ĕ: "e",
  ė: "e",
  ę: "e",
  ě: "e",
  Ĝ: "G",
  Ğ: "G",
  Ġ: "G",
  Ģ: "G",
  ĝ: "g",
  ğ: "g",
  ġ: "g",
  ģ: "g",
  Ĥ: "H",
  Ħ: "H",
  ĥ: "h",
  ħ: "h",
  Ĩ: "I",
  Ī: "I",
  Ĭ: "I",
  Į: "I",
  İ: "I",
  ĩ: "i",
  ī: "i",
  ĭ: "i",
  į: "i",
  ı: "i",
  Ĵ: "J",
  ĵ: "j",
  Ķ: "K",
  ķ: "k",
  ĸ: "k",
  Ĺ: "L",
  Ļ: "L",
  Ľ: "L",
  Ŀ: "L",
  Ł: "L",
  ĺ: "l",
  ļ: "l",
  ľ: "l",
  ŀ: "l",
  ł: "l",
  Ń: "N",
  Ņ: "N",
  Ň: "N",
  Ŋ: "N",
  ń: "n",
  ņ: "n",
  ň: "n",
  ŋ: "n",
  Ō: "O",
  Ŏ: "O",
  Ő: "O",
  ō: "o",
  ŏ: "o",
  ő: "o",
  Ŕ: "R",
  Ŗ: "R",
  Ř: "R",
  ŕ: "r",
  ŗ: "r",
  ř: "r",
  Ś: "S",
  Ŝ: "S",
  Ş: "S",
  Š: "S",
  ś: "s",
  ŝ: "s",
  ş: "s",
  š: "s",
  Ţ: "T",
  Ť: "T",
  Ŧ: "T",
  ţ: "t",
  ť: "t",
  ŧ: "t",
  Ũ: "U",
  Ū: "U",
  Ŭ: "U",
  Ů: "U",
  Ű: "U",
  Ų: "U",
  ũ: "u",
  ū: "u",
  ŭ: "u",
  ů: "u",
  ű: "u",
  ų: "u",
  Ŵ: "W",
  ŵ: "w",
  Ŷ: "Y",
  ŷ: "y",
  Ÿ: "Y",
  Ź: "Z",
  Ż: "Z",
  Ž: "Z",
  ź: "z",
  ż: "z",
  ž: "z",
  Ĳ: "IJ",
  ĳ: "ij",
  Œ: "Oe",
  œ: "oe",
  ŉ: "'n",
  ſ: "s"
}, Rp = Sp(Ip);
const Op = Rp;
var Mp = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g, Vp = "\\u0300-\\u036f", Dp = "\\ufe20-\\ufe2f", Bp = "\\u20d0-\\u20ff", Fp = Vp + Dp + Bp, Np = "[" + Fp + "]", Lp = RegExp(Np, "g");
function $p(n) {
  return n = Mn(n), n && n.replace(Mp, Op).replace(Lp, "");
}
var zp = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
function Hp(n) {
  return n.match(zp) || [];
}
var Wp = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
function Up(n) {
  return Wp.test(n);
}
var Fc = "\\ud800-\\udfff", jp = "\\u0300-\\u036f", qp = "\\ufe20-\\ufe2f", Gp = "\\u20d0-\\u20ff", Kp = jp + qp + Gp, Nc = "\\u2700-\\u27bf", Lc = "a-z\\xdf-\\xf6\\xf8-\\xff", Jp = "\\xac\\xb1\\xd7\\xf7", Zp = "\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf", Yp = "\\u2000-\\u206f", Xp = " \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000", $c = "A-Z\\xc0-\\xd6\\xd8-\\xde", Qp = "\\ufe0e\\ufe0f", zc = Jp + Zp + Yp + Xp, Hc = "['’]", xo = "[" + zc + "]", ew = "[" + Kp + "]", Wc = "\\d+", tw = "[" + Nc + "]", Uc = "[" + Lc + "]", jc = "[^" + Fc + zc + Wc + Nc + Lc + $c + "]", iw = "\\ud83c[\\udffb-\\udfff]", nw = "(?:" + ew + "|" + iw + ")", sw = "[^" + Fc + "]", qc = "(?:\\ud83c[\\udde6-\\uddff]){2}", Gc = "[\\ud800-\\udbff][\\udc00-\\udfff]", qt = "[" + $c + "]", rw = "\\u200d", So = "(?:" + Uc + "|" + jc + ")", ow = "(?:" + qt + "|" + jc + ")", Io = "(?:" + Hc + "(?:d|ll|m|re|s|t|ve))?", Ro = "(?:" + Hc + "(?:D|LL|M|RE|S|T|VE))?", Kc = nw + "?", Jc = "[" + Qp + "]?", aw = "(?:" + rw + "(?:" + [sw, qc, Gc].join("|") + ")" + Jc + Kc + ")*", lw = "\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])", cw = "\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])", uw = Jc + Kc + aw, hw = "(?:" + [tw, qc, Gc].join("|") + ")" + uw, dw = RegExp([
  qt + "?" + Uc + "+" + Io + "(?=" + [xo, qt, "$"].join("|") + ")",
  ow + "+" + Ro + "(?=" + [xo, qt + So, "$"].join("|") + ")",
  qt + "?" + So + "+" + Io,
  qt + "+" + Ro,
  cw,
  lw,
  Wc,
  hw
].join("|"), "g");
function fw(n) {
  return n.match(dw) || [];
}
function mw(n, e, t) {
  return n = Mn(n), e = t ? void 0 : e, e === void 0 ? Up(n) ? fw(n) : Hp(n) : n.match(e) || [];
}
var gw = "['’]", pw = RegExp(gw, "g");
function ww(n) {
  return function(e) {
    return xp(mw($p(e).replace(pw, "")), n, "");
  };
}
function bw() {
  this.__data__ = new Qe(), this.size = 0;
}
function _w(n) {
  var e = this.__data__, t = e.delete(n);
  return this.size = e.size, t;
}
function vw(n) {
  return this.__data__.get(n);
}
function yw(n) {
  return this.__data__.has(n);
}
var kw = 200;
function Cw(n, e) {
  var t = this.__data__;
  if (t instanceof Qe) {
    var i = t.__data__;
    if (!Si || i.length < kw - 1)
      return i.push([n, e]), this.size = ++t.size, this;
    t = this.__data__ = new et(i);
  }
  return t.set(n, e), this.size = t.size, this;
}
function Ne(n) {
  var e = this.__data__ = new Qe(n);
  this.size = e.size;
}
Ne.prototype.clear = bw;
Ne.prototype.delete = _w;
Ne.prototype.get = vw;
Ne.prototype.has = yw;
Ne.prototype.set = Cw;
function Ew(n, e) {
  return n && ui(e, _r(e), n);
}
function Aw(n, e) {
  return n && ui(e, hi(e), n);
}
var Zc = typeof exports == "object" && exports && !exports.nodeType && exports, Oo = Zc && typeof module == "object" && module && !module.nodeType && module, Tw = Oo && Oo.exports === Zc, Mo = Tw ? Re.Buffer : void 0, Vo = Mo ? Mo.allocUnsafe : void 0;
function Yc(n, e) {
  if (e)
    return n.slice();
  var t = n.length, i = Vo ? Vo(t) : new n.constructor(t);
  return n.copy(i), i;
}
function Pw(n, e) {
  for (var t = -1, i = n == null ? 0 : n.length, s = 0, r = []; ++t < i; ) {
    var o = n[t];
    e(o, t, n) && (r[s++] = o);
  }
  return r;
}
function Xc() {
  return [];
}
var xw = Object.prototype, Sw = xw.propertyIsEnumerable, Do = Object.getOwnPropertySymbols, Iw = Do ? function(n) {
  return n == null ? [] : (n = Object(n), Pw(Do(n), function(e) {
    return Sw.call(n, e);
  }));
} : Xc;
const Er = Iw;
function Rw(n, e) {
  return ui(n, Er(n), e);
}
var Ow = Object.getOwnPropertySymbols, Mw = Ow ? function(n) {
  for (var e = []; n; )
    Tc(e, Er(n)), n = Cr(n);
  return e;
} : Xc;
const Qc = Mw;
function Vw(n, e) {
  return ui(n, Qc(n), e);
}
function eu(n, e, t) {
  var i = e(n);
  return he(n) ? i : Tc(i, t(n));
}
function Vs(n) {
  return eu(n, _r, Er);
}
function Dw(n) {
  return eu(n, hi, Qc);
}
var Bw = Ot(Re, "DataView");
const Ds = Bw;
var Fw = Ot(Re, "Promise");
const Bs = Fw;
var Nw = Ot(Re, "Set");
const Fs = Nw;
var Bo = "[object Map]", Lw = "[object Object]", Fo = "[object Promise]", No = "[object Set]", Lo = "[object WeakMap]", $o = "[object DataView]", $w = Rt(Ds), zw = Rt(Si), Hw = Rt(Bs), Ww = Rt(Fs), Uw = Rt(Is), yt = dt;
(Ds && yt(new Ds(new ArrayBuffer(1))) != $o || Si && yt(new Si()) != Bo || Bs && yt(Bs.resolve()) != Fo || Fs && yt(new Fs()) != No || Is && yt(new Is()) != Lo) && (yt = function(n) {
  var e = dt(n), t = e == Lw ? n.constructor : void 0, i = t ? Rt(t) : "";
  if (i)
    switch (i) {
      case $w:
        return $o;
      case zw:
        return Bo;
      case Hw:
        return Fo;
      case Ww:
        return No;
      case Uw:
        return Lo;
    }
  return e;
});
const Ii = yt;
var jw = Object.prototype, qw = jw.hasOwnProperty;
function Gw(n) {
  var e = n.length, t = new n.constructor(e);
  return e && typeof n[0] == "string" && qw.call(n, "index") && (t.index = n.index, t.input = n.input), t;
}
var Kw = Re.Uint8Array;
const fn = Kw;
function Ar(n) {
  var e = new n.constructor(n.byteLength);
  return new fn(e).set(new fn(n)), e;
}
function Jw(n, e) {
  var t = e ? Ar(n.buffer) : n.buffer;
  return new n.constructor(t, n.byteOffset, n.byteLength);
}
var Zw = /\w*$/;
function Yw(n) {
  var e = new n.constructor(n.source, Zw.exec(n));
  return e.lastIndex = n.lastIndex, e;
}
var zo = $e ? $e.prototype : void 0, Ho = zo ? zo.valueOf : void 0;
function Xw(n) {
  return Ho ? Object(Ho.call(n)) : {};
}
function tu(n, e) {
  var t = e ? Ar(n.buffer) : n.buffer;
  return new n.constructor(t, n.byteOffset, n.length);
}
var Qw = "[object Boolean]", eb = "[object Date]", tb = "[object Map]", ib = "[object Number]", nb = "[object RegExp]", sb = "[object Set]", rb = "[object String]", ob = "[object Symbol]", ab = "[object ArrayBuffer]", lb = "[object DataView]", cb = "[object Float32Array]", ub = "[object Float64Array]", hb = "[object Int8Array]", db = "[object Int16Array]", fb = "[object Int32Array]", mb = "[object Uint8Array]", gb = "[object Uint8ClampedArray]", pb = "[object Uint16Array]", wb = "[object Uint32Array]";
function bb(n, e, t) {
  var i = n.constructor;
  switch (e) {
    case ab:
      return Ar(n);
    case Qw:
    case eb:
      return new i(+n);
    case lb:
      return Jw(n, t);
    case cb:
    case ub:
    case hb:
    case db:
    case fb:
    case mb:
    case gb:
    case pb:
    case wb:
      return tu(n, t);
    case tb:
      return new i();
    case ib:
    case rb:
      return new i(n);
    case nb:
      return Yw(n);
    case sb:
      return new i();
    case ob:
      return Xw(n);
  }
}
function iu(n) {
  return typeof n.constructor == "function" && !wr(n) ? Gf(Cr(n)) : {};
}
var _b = "[object Map]";
function vb(n) {
  return Ae(n) && Ii(n) == _b;
}
var Wo = ei && ei.isMap, yb = Wo ? In(Wo) : vb;
const kb = yb;
var Cb = "[object Set]";
function Eb(n) {
  return Ae(n) && Ii(n) == Cb;
}
var Uo = ei && ei.isSet, Ab = Uo ? In(Uo) : Eb;
const Tb = Ab;
var Pb = 1, xb = 2, Sb = 4, nu = "[object Arguments]", Ib = "[object Array]", Rb = "[object Boolean]", Ob = "[object Date]", Mb = "[object Error]", su = "[object Function]", Vb = "[object GeneratorFunction]", Db = "[object Map]", Bb = "[object Number]", ru = "[object Object]", Fb = "[object RegExp]", Nb = "[object Set]", Lb = "[object String]", $b = "[object Symbol]", zb = "[object WeakMap]", Hb = "[object ArrayBuffer]", Wb = "[object DataView]", Ub = "[object Float32Array]", jb = "[object Float64Array]", qb = "[object Int8Array]", Gb = "[object Int16Array]", Kb = "[object Int32Array]", Jb = "[object Uint8Array]", Zb = "[object Uint8ClampedArray]", Yb = "[object Uint16Array]", Xb = "[object Uint32Array]", L = {};
L[nu] = L[Ib] = L[Hb] = L[Wb] = L[Rb] = L[Ob] = L[Ub] = L[jb] = L[qb] = L[Gb] = L[Kb] = L[Db] = L[Bb] = L[ru] = L[Fb] = L[Nb] = L[Lb] = L[$b] = L[Jb] = L[Zb] = L[Yb] = L[Xb] = !0;
L[Mb] = L[su] = L[zb] = !1;
function Xt(n, e, t, i, s, r) {
  var o, a = e & Pb, l = e & xb, c = e & Sb;
  if (t && (o = s ? t(n, i, s, r) : t(n)), o !== void 0)
    return o;
  if (!G(n))
    return n;
  var u = he(n);
  if (u) {
    if (o = Gw(n), !a)
      return dr(n, o);
  } else {
    var h = Ii(n), f = h == su || h == Vb;
    if (Pi(n))
      return Yc(n, a);
    if (h == ru || h == nu || f && !s) {
      if (o = l || f ? {} : iu(n), !a)
        return l ? Vw(n, Aw(o, n)) : Rw(n, Ew(o, n));
    } else {
      if (!L[h])
        return s ? n : {};
      o = bb(n, h, a);
    }
  }
  r || (r = new Ne());
  var m = r.get(n);
  if (m)
    return m;
  r.set(n, o), Tb(n) ? n.forEach(function(E) {
    o.add(Xt(E, e, t, E, n, r));
  }) : kb(n) && n.forEach(function(E, A) {
    o.set(A, Xt(E, e, t, A, n, r));
  });
  var p = c ? l ? Dw : Vs : l ? hi : _r, b = u ? void 0 : p(n);
  return rm(b || n, function(E, A) {
    b && (A = E, E = n[A]), gr(o, A, Xt(E, e, t, A, n, r));
  }), o;
}
var Qb = 4;
function ou(n) {
  return Xt(n, Qb);
}
var e0 = 1, t0 = 4;
function tt(n) {
  return Xt(n, e0 | t0);
}
var i0 = 1, n0 = 4;
function Tr(n, e) {
  return e = typeof e == "function" ? e : void 0, Xt(n, i0 | n0, e);
}
var s0 = "__lodash_hash_undefined__";
function r0(n) {
  return this.__data__.set(n, s0), this;
}
function o0(n) {
  return this.__data__.has(n);
}
function mn(n) {
  var e = -1, t = n == null ? 0 : n.length;
  for (this.__data__ = new et(); ++e < t; )
    this.add(n[e]);
}
mn.prototype.add = mn.prototype.push = r0;
mn.prototype.has = o0;
function a0(n, e) {
  for (var t = -1, i = n == null ? 0 : n.length; ++t < i; )
    if (e(n[t], t, n))
      return !0;
  return !1;
}
function l0(n, e) {
  return n.has(e);
}
var c0 = 1, u0 = 2;
function au(n, e, t, i, s, r) {
  var o = t & c0, a = n.length, l = e.length;
  if (a != l && !(o && l > a))
    return !1;
  var c = r.get(n), u = r.get(e);
  if (c && u)
    return c == e && u == n;
  var h = -1, f = !0, m = t & u0 ? new mn() : void 0;
  for (r.set(n, e), r.set(e, n); ++h < a; ) {
    var p = n[h], b = e[h];
    if (i)
      var E = o ? i(b, p, h, e, n, r) : i(p, b, h, n, e, r);
    if (E !== void 0) {
      if (E)
        continue;
      f = !1;
      break;
    }
    if (m) {
      if (!a0(e, function(A, ue) {
        if (!l0(m, ue) && (p === A || s(p, A, t, i, r)))
          return m.push(ue);
      })) {
        f = !1;
        break;
      }
    } else if (!(p === b || s(p, b, t, i, r))) {
      f = !1;
      break;
    }
  }
  return r.delete(n), r.delete(e), f;
}
function h0(n) {
  var e = -1, t = Array(n.size);
  return n.forEach(function(i, s) {
    t[++e] = [s, i];
  }), t;
}
function d0(n) {
  var e = -1, t = Array(n.size);
  return n.forEach(function(i) {
    t[++e] = i;
  }), t;
}
var f0 = 1, m0 = 2, g0 = "[object Boolean]", p0 = "[object Date]", w0 = "[object Error]", b0 = "[object Map]", _0 = "[object Number]", v0 = "[object RegExp]", y0 = "[object Set]", k0 = "[object String]", C0 = "[object Symbol]", E0 = "[object ArrayBuffer]", A0 = "[object DataView]", jo = $e ? $e.prototype : void 0, Jn = jo ? jo.valueOf : void 0;
function T0(n, e, t, i, s, r, o) {
  switch (t) {
    case A0:
      if (n.byteLength != e.byteLength || n.byteOffset != e.byteOffset)
        return !1;
      n = n.buffer, e = e.buffer;
    case E0:
      return !(n.byteLength != e.byteLength || !r(new fn(n), new fn(e)));
    case g0:
    case p0:
    case _0:
      return zi(+n, +e);
    case w0:
      return n.name == e.name && n.message == e.message;
    case v0:
    case k0:
      return n == e + "";
    case b0:
      var a = h0;
    case y0:
      var l = i & f0;
      if (a || (a = d0), n.size != e.size && !l)
        return !1;
      var c = o.get(n);
      if (c)
        return c == e;
      i |= m0, o.set(n, e);
      var u = au(a(n), a(e), i, s, r, o);
      return o.delete(n), u;
    case C0:
      if (Jn)
        return Jn.call(n) == Jn.call(e);
  }
  return !1;
}
var P0 = 1, x0 = Object.prototype, S0 = x0.hasOwnProperty;
function I0(n, e, t, i, s, r) {
  var o = t & P0, a = Vs(n), l = a.length, c = Vs(e), u = c.length;
  if (l != u && !o)
    return !1;
  for (var h = l; h--; ) {
    var f = a[h];
    if (!(o ? f in e : S0.call(e, f)))
      return !1;
  }
  var m = r.get(n), p = r.get(e);
  if (m && p)
    return m == e && p == n;
  var b = !0;
  r.set(n, e), r.set(e, n);
  for (var E = o; ++h < l; ) {
    f = a[h];
    var A = n[f], ue = e[f];
    if (i)
      var ke = o ? i(ue, A, f, e, n, r) : i(A, ue, f, n, e, r);
    if (!(ke === void 0 ? A === ue || s(A, ue, t, i, r) : ke)) {
      b = !1;
      break;
    }
    E || (E = f == "constructor");
  }
  if (b && !E) {
    var ge = n.constructor, Me = e.constructor;
    ge != Me && "constructor" in n && "constructor" in e && !(typeof ge == "function" && ge instanceof ge && typeof Me == "function" && Me instanceof Me) && (b = !1);
  }
  return r.delete(n), r.delete(e), b;
}
var R0 = 1, qo = "[object Arguments]", Go = "[object Array]", Ui = "[object Object]", O0 = Object.prototype, Ko = O0.hasOwnProperty;
function M0(n, e, t, i, s, r) {
  var o = he(n), a = he(e), l = o ? Go : Ii(n), c = a ? Go : Ii(e);
  l = l == qo ? Ui : l, c = c == qo ? Ui : c;
  var u = l == Ui, h = c == Ui, f = l == c;
  if (f && Pi(n)) {
    if (!Pi(e))
      return !1;
    o = !0, u = !1;
  }
  if (f && !u)
    return r || (r = new Ne()), o || br(n) ? au(n, e, t, i, s, r) : T0(n, e, l, t, i, s, r);
  if (!(t & R0)) {
    var m = u && Ko.call(n, "__wrapped__"), p = h && Ko.call(e, "__wrapped__");
    if (m || p) {
      var b = m ? n.value() : n, E = p ? e.value() : e;
      return r || (r = new Ne()), s(b, E, t, i, r);
    }
  }
  return f ? (r || (r = new Ne()), I0(n, e, t, i, s, r)) : !1;
}
function Pr(n, e, t, i, s) {
  return n === e ? !0 : n == null || e == null || !Ae(n) && !Ae(e) ? n !== n && e !== e : M0(n, e, t, i, Pr, s);
}
function V0(n) {
  return function(e, t, i) {
    for (var s = -1, r = Object(e), o = i(e), a = o.length; a--; ) {
      var l = o[n ? a : ++s];
      if (t(r[l], l, r) === !1)
        break;
    }
    return e;
  };
}
var D0 = V0();
const B0 = D0;
var F0 = function() {
  return Re.Date.now();
};
const Zn = F0;
var N0 = "Expected a function", L0 = Math.max, $0 = Math.min;
function ti(n, e, t) {
  var i, s, r, o, a, l, c = 0, u = !1, h = !1, f = !0;
  if (typeof n != "function")
    throw new TypeError(N0);
  e = vo(e) || 0, G(t) && (u = !!t.leading, h = "maxWait" in t, r = h ? L0(vo(t.maxWait) || 0, e) : r, f = "trailing" in t ? !!t.trailing : f);
  function m(k) {
    var x = i, C = s;
    return i = s = void 0, c = k, o = n.apply(C, x), o;
  }
  function p(k) {
    return c = k, a = setTimeout(A, e), u ? m(k) : o;
  }
  function b(k) {
    var x = k - l, C = k - c, K = e - x;
    return h ? $0(K, r - C) : K;
  }
  function E(k) {
    var x = k - l, C = k - c;
    return l === void 0 || x >= e || x < 0 || h && C >= r;
  }
  function A() {
    var k = Zn();
    if (E(k))
      return ue(k);
    a = setTimeout(A, b(k));
  }
  function ue(k) {
    return a = void 0, f && i ? m(k) : (i = s = void 0, o);
  }
  function ke() {
    a !== void 0 && clearTimeout(a), c = 0, i = l = s = a = void 0;
  }
  function ge() {
    return a === void 0 ? o : ue(Zn());
  }
  function Me() {
    var k = Zn(), x = E(k);
    if (i = arguments, s = this, l = k, x) {
      if (a === void 0)
        return p(l);
      if (h)
        return clearTimeout(a), a = setTimeout(A, e), m(l);
    }
    return a === void 0 && (a = setTimeout(A, e)), o;
  }
  return Me.cancel = ke, Me.flush = ge, Me;
}
function Ns(n, e, t) {
  (t !== void 0 && !zi(n[e], t) || t === void 0 && !(e in n)) && mr(n, e, t);
}
function z0(n) {
  return Ae(n) && Sn(n);
}
function Ls(n, e) {
  if (!(e === "constructor" && typeof n[e] == "function") && e != "__proto__")
    return n[e];
}
function H0(n) {
  return ui(n, hi(n));
}
function W0(n, e, t, i, s, r, o) {
  var a = Ls(n, t), l = Ls(e, t), c = o.get(l);
  if (c) {
    Ns(n, t, c);
    return;
  }
  var u = r ? r(a, l, t + "", n, e, o) : void 0, h = u === void 0;
  if (h) {
    var f = he(l), m = !f && Pi(l), p = !f && !m && br(l);
    u = l, f || m || p ? he(a) ? u = a : z0(a) ? u = dr(a) : m ? (h = !1, u = Yc(l, !0)) : p ? (h = !1, u = tu(l, !0)) : u = [] : de(l) || Rs(l) ? (u = a, Rs(a) ? u = H0(a) : (!G(a) || Pt(a)) && (u = iu(l))) : h = !1;
  }
  h && (o.set(l, u), s(u, l, i, r, o), o.delete(l)), Ns(n, t, u);
}
function xr(n, e, t, i, s) {
  n !== e && B0(e, function(r, o) {
    if (s || (s = new Ne()), G(r))
      W0(n, e, o, t, xr, i, s);
    else {
      var a = i ? i(Ls(n, o), r, o + "", n, e, s) : void 0;
      a === void 0 && (a = r), Ns(n, o, a);
    }
  }, hi);
}
var U0 = pr(function(n, e, t, i) {
  xr(n, e, t, i);
});
const j0 = U0;
function q0(n) {
  var e = n == null ? 0 : n.length;
  return e ? n[e - 1] : void 0;
}
var G0 = "[object String]";
function Jo(n) {
  return typeof n == "string" || !he(n) && Ae(n) && dt(n) == G0;
}
function K0(n, e) {
  return e.length < 2 ? n : Ac(n, xc(e, 0, -1));
}
function di(n) {
  return Ae(n) && n.nodeType === 1 && !de(n);
}
function gn(n, e) {
  return Pr(n, e);
}
function J0(n, e, t) {
  t = typeof t == "function" ? t : void 0;
  var i = t ? t(n, e) : void 0;
  return i === void 0 ? Pr(n, e, void 0, t) : !!i;
}
var Z0 = pr(function(n, e, t) {
  xr(n, e, t);
});
const lu = Z0;
function Y0(n, e) {
  return e = yr(e, n), n = K0(n, e), n == null || delete n[kr(q0(e))];
}
function X0(n, e, t, i) {
  if (!G(n))
    return n;
  e = yr(e, n);
  for (var s = -1, r = e.length, o = r - 1, a = n; a != null && ++s < r; ) {
    var l = kr(e[s]), c = t;
    if (l === "__proto__" || l === "constructor" || l === "prototype")
      return n;
    if (s != o) {
      var u = a[l];
      c = i ? i(u, l, a) : void 0, c === void 0 && (c = G(u) ? u : fr(e[s + 1]) ? [] : {});
    }
    gr(a, l, c), a = a[l];
  }
  return n;
}
function Q0(n, e, t, i) {
  for (var s = t - 1, r = n.length; ++s < r; )
    if (i(n[s], e))
      return s;
  return -1;
}
var e_ = Array.prototype, Zo = e_.splice;
function t_(n, e, t, i) {
  var s = i ? Q0 : cm, r = -1, o = e.length, a = n;
  for (n === e && (e = dr(e)), t && (a = gc(n, In(t))); ++r < o; )
    for (var l = 0, c = e[r], u = t ? t(c) : c; (l = s(a, u, l, i)) > -1; )
      a !== n && Zo.call(a, l, 1), Zo.call(n, l, 1);
  return n;
}
function i_(n, e) {
  return n && n.length && e && e.length ? t_(n, e) : n;
}
var n_ = wc(i_);
const s_ = n_;
function r_(n, e, t) {
  return n == null ? n : X0(n, e, t);
}
var o_ = ww(function(n, e, t) {
  return n + (t ? " " : "") + Bc(e);
});
const a_ = o_;
var l_ = "Expected a function";
function Vn(n, e, t) {
  var i = !0, s = !0;
  if (typeof n != "function")
    throw new TypeError(l_);
  return G(t) && (i = "leading" in t ? !!t.leading : i, s = "trailing" in t ? !!t.trailing : s), ti(n, e, {
    leading: i,
    maxWait: e,
    trailing: s
  });
}
function c_(n, e) {
  return n == null ? !0 : Y0(n, e);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const pn = Symbol("observableProperties"), Dn = Symbol("boundObservables"), wn = Symbol("boundProperties"), Nt = Symbol("decoratedMethods"), Yo = Symbol("decoratedOriginal"), cu = z(N());
function z(n) {
  if (!n)
    return cu;
  class e extends n {
    set(i, s) {
      if (G(i)) {
        Object.keys(i).forEach((o) => {
          this.set(o, i[o]);
        }, this);
        return;
      }
      Yn(this);
      const r = this[pn];
      if (i in this && !r.has(i))
        throw new d("observable-set-cannot-override", this);
      Object.defineProperty(this, i, {
        enumerable: !0,
        configurable: !0,
        get() {
          return r.get(i);
        },
        set(o) {
          const a = r.get(i);
          let l = this.fire(`set:${i}`, i, o, a);
          l === void 0 && (l = o), (a !== l || !r.has(i)) && (r.set(i, l), this.fire(`change:${i}`, i, l, a));
        }
      }), this[i] = s;
    }
    bind(...i) {
      if (!i.length || !Xo(i))
        throw new d("observable-bind-wrong-properties", this);
      if (new Set(i).size !== i.length)
        throw new d("observable-bind-duplicate-properties", this);
      Yn(this);
      const s = this[wn];
      i.forEach((o) => {
        if (s.has(o))
          throw new d("observable-bind-rebind", this);
      });
      const r = /* @__PURE__ */ new Map();
      return i.forEach((o) => {
        const a = { property: o, to: [] };
        s.set(o, a), r.set(o, a);
      }), {
        to: u_,
        toMany: h_,
        _observable: this,
        _bindProperties: i,
        _to: [],
        _bindings: r
      };
    }
    unbind(...i) {
      if (!this[pn])
        return;
      const s = this[wn], r = this[Dn];
      if (i.length) {
        if (!Xo(i))
          throw new d("observable-unbind-wrong-properties", this);
        i.forEach((o) => {
          const a = s.get(o);
          a && (a.to.forEach(([l, c]) => {
            const u = r.get(l), h = u[c];
            h.delete(a), h.size || delete u[c], Object.keys(u).length || (r.delete(l), this.stopListening(l, "change"));
          }), s.delete(o));
        });
      } else
        r.forEach((o, a) => {
          this.stopListening(a, "change");
        }), r.clear(), s.clear();
    }
    decorate(i) {
      Yn(this);
      const s = this[i];
      if (!s)
        throw new d("observablemixin-cannot-decorate-undefined", this, { object: this, methodName: i });
      this.on(i, (r, o) => {
        r.return = s.apply(this, o);
      }), this[i] = function(...r) {
        return this.fire(i, r);
      }, this[i][Yo] = s, this[Nt] || (this[Nt] = []), this[Nt].push(i);
    }
    // Override the EmitterMixin stopListening method to be able to clean (and restore) decorated methods.
    // This is needed in case of:
    //  1. Have x.foo() decorated.
    //  2. Call x.stopListening()
    //  3. Call x.foo(). Problem: nothing happens (the original foo() method is not executed)
    stopListening(i, s, r) {
      if (!i && this[Nt]) {
        for (const o of this[Nt])
          this[o] = this[o][Yo];
        delete this[Nt];
      }
      super.stopListening(i, s, r);
    }
  }
  return e;
}
[
  "set",
  "bind",
  "unbind",
  "decorate",
  "on",
  "once",
  "off",
  "listenTo",
  "stopListening",
  "fire",
  "delegate",
  "stopDelegating",
  "_addEventListener",
  "_removeEventListener"
].forEach((n) => {
  z[n] = cu.prototype[n];
});
function Yn(n) {
  n[pn] || (Object.defineProperty(n, pn, {
    value: /* @__PURE__ */ new Map()
  }), Object.defineProperty(n, Dn, {
    value: /* @__PURE__ */ new Map()
  }), Object.defineProperty(n, wn, {
    value: /* @__PURE__ */ new Map()
  }));
}
function u_(...n) {
  const e = f_(...n), t = Array.from(this._bindings.keys()), i = t.length;
  if (!e.callback && e.to.length > 1)
    throw new d("observable-bind-to-no-callback", this);
  if (i > 1 && e.callback)
    throw new d("observable-bind-to-extra-callback", this);
  e.to.forEach((s) => {
    if (s.properties.length && s.properties.length !== i)
      throw new d("observable-bind-to-properties-length", this);
    s.properties.length || (s.properties = this._bindProperties);
  }), this._to = e.to, e.callback && (this._bindings.get(t[0]).callback = e.callback), p_(this._observable, this._to), g_(this), this._bindProperties.forEach((s) => {
    uu(this._observable, s);
  });
}
function h_(n, e, t) {
  if (this._bindings.size > 1)
    throw new d("observable-bind-to-many-not-one-binding", this);
  this.to(
    ...d_(n, e),
    // ...using given callback to parse attribute values.
    t
  );
}
function d_(n, e) {
  const t = n.map((i) => [i, e]);
  return Array.prototype.concat.apply([], t);
}
function Xo(n) {
  return n.every((e) => typeof e == "string");
}
function f_(...n) {
  if (!n.length)
    throw new d("observable-bind-to-parse-error", null);
  const e = { to: [] };
  let t;
  return typeof n[n.length - 1] == "function" && (e.callback = n.pop()), n.forEach((i) => {
    if (typeof i == "string")
      t.properties.push(i);
    else if (typeof i == "object")
      t = { observable: i, properties: [] }, e.to.push(t);
    else
      throw new d("observable-bind-to-parse-error", null);
  }), e;
}
function m_(n, e, t, i) {
  const s = n[Dn], r = s.get(t), o = r || {};
  o[i] || (o[i] = /* @__PURE__ */ new Set()), o[i].add(e), r || s.set(t, o);
}
function g_(n) {
  let e;
  n._bindings.forEach((t, i) => {
    n._to.forEach((s) => {
      e = s.properties[t.callback ? 0 : n._bindProperties.indexOf(i)], t.to.push([s.observable, e]), m_(n._observable, t, s.observable, e);
    });
  });
}
function uu(n, e) {
  const i = n[wn].get(e);
  let s;
  i.callback ? s = i.callback.apply(n, i.to.map((r) => r[0][r[1]])) : (s = i.to[0], s = s[0][s[1]]), Object.prototype.hasOwnProperty.call(n, e) ? n[e] = s : n.set(e, s);
}
function p_(n, e) {
  e.forEach((t) => {
    const i = n[Dn];
    let s;
    i.get(t.observable) || n.listenTo(t.observable, "change", (r, o) => {
      s = i.get(t.observable)[o], s && s.forEach((a) => {
        uu(n, a.property);
      });
    });
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function $s(n) {
  let e = 0;
  for (const t of n)
    e++;
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function ce(n, e) {
  const t = Math.min(n.length, e.length);
  for (let i = 0; i < t; i++)
    if (n[i] != e[i])
      return i;
  return n.length == e.length ? "same" : n.length < e.length ? "prefix" : "extension";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function _e(n) {
  return !!(n && n[Symbol.iterator]);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function w_(n, e, t = {}, i = []) {
  const s = t && t.xmlns, r = s ? n.createElementNS(s, e) : n.createElement(e);
  for (const o in t)
    r.setAttribute(o, t[o]);
  (Jo(i) || !_e(i)) && (i = [i]);
  for (let o of i)
    Jo(o) && (o = n.createTextNode(o)), r.appendChild(o);
  return r;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class hu {
  /**
   * Creates an instance of the {@link ~Config} class.
   *
   * @param configurations The initial configurations to be set. Usually, provided by the user.
   * @param defaultConfigurations The default configurations. Usually, provided by the system.
   */
  constructor(e, t) {
    this._config = {}, t && this.define(Qo(t)), e && this._setObjectToTarget(this._config, e);
  }
  set(e, t) {
    this._setToTarget(this._config, e, t);
  }
  define(e, t) {
    this._setToTarget(this._config, e, t, !0);
  }
  /**
   * Gets the value for a configuration entry.
   *
   * ```ts
   * config.get( 'name' );
   * ```
   *
   * Deep configurations can be retrieved by separating each part with a dot.
   *
   * ```ts
   * config.get( 'toolbar.collapsed' );
   * ```
   *
   * @param name The configuration name. Configuration names are case-sensitive.
   * @returns The configuration value or `undefined` if the configuration entry was not found.
   */
  get(e) {
    return this._getFromSource(this._config, e);
  }
  /**
   * Iterates over all top level configuration names.
   */
  *names() {
    for (const e of Object.keys(this._config))
      yield e;
  }
  /**
   * Saves passed configuration to the specified target (nested object).
   *
   * @param target Nested config object.
   * @param name The configuration name or an object from which take properties as
   * configuration entries. Configuration names are case-sensitive.
   * @param value The configuration value. Used if a name is passed.
   * @param isDefine Define if passed configuration should overwrite existing one.
   */
  _setToTarget(e, t, i, s = !1) {
    if (de(t)) {
      this._setObjectToTarget(e, t, s);
      return;
    }
    const r = t.split(".");
    t = r.pop();
    for (const o of r)
      de(e[o]) || (e[o] = {}), e = e[o];
    if (de(i)) {
      de(e[t]) || (e[t] = {}), e = e[t], this._setObjectToTarget(e, i, s);
      return;
    }
    s && typeof e[t] < "u" || (e[t] = i);
  }
  /**
   * Get specified configuration from specified source (nested object).
   *
   * @param source level of nested object.
   * @param name The configuration name. Configuration names are case-sensitive.
   * @returns The configuration value or `undefined` if the configuration entry was not found.
   */
  _getFromSource(e, t) {
    const i = t.split(".");
    t = i.pop();
    for (const s of i) {
      if (!de(e[s])) {
        e = null;
        break;
      }
      e = e[s];
    }
    return e ? Qo(e[t]) : void 0;
  }
  /**
   * Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.
   *
   * @param target Nested config object.
   * @param configuration Configuration data set
   * @param isDefine Defines if passed configuration is default configuration or not.
   */
  _setObjectToTarget(e, t, i) {
    Object.keys(t).forEach((s) => {
      this._setToTarget(e, s, t[s], i);
    });
  }
}
function Qo(n) {
  return Tr(n, b_);
}
function b_(n) {
  return di(n) ? n : void 0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function lt(n) {
  if (n) {
    if (n.defaultView)
      return n instanceof n.defaultView.Document;
    if (n.ownerDocument && n.ownerDocument.defaultView)
      return n instanceof n.ownerDocument.defaultView.Node;
  }
  return !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function bn(n) {
  const e = Object.prototype.toString.apply(n);
  return e == "[object Window]" || e == "[object global]";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const du = it(N());
function it(n) {
  if (!n)
    return du;
  class e extends n {
    listenTo(i, s, r, o = {}) {
      if (lt(i) || bn(i)) {
        const a = {
          capture: !!o.useCapture,
          passive: !!o.usePassive
        }, l = this._getProxyEmitter(i, a) || new __(i, a);
        this.listenTo(l, s, r, o);
      } else
        super.listenTo(i, s, r, o);
    }
    stopListening(i, s, r) {
      if (lt(i) || bn(i)) {
        const o = this._getAllProxyEmitters(i);
        for (const a of o)
          this.stopListening(a, s, r);
      } else
        super.stopListening(i, s, r);
    }
    /**
     * Retrieves ProxyEmitter instance for given DOM Node residing in this Host and given options.
     *
     * @param node DOM Node of the ProxyEmitter.
     * @param options Additional options.
     * @param options.useCapture Indicates that events of this type will be dispatched to the registered
     * listener before being dispatched to any EventTarget beneath it in the DOM tree.
     * @param options.usePassive Indicates that the function specified by listener will never call preventDefault()
     * and prevents blocking browser's main thread by this event handler.
     * @returns ProxyEmitter instance bound to the DOM Node.
     */
    _getProxyEmitter(i, s) {
      return ef(this, fu(i, s));
    }
    /**
     * Retrieves all the ProxyEmitter instances for given DOM Node residing in this Host.
     *
     * @param node DOM Node of the ProxyEmitter.
     */
    _getAllProxyEmitters(i) {
      return [
        { capture: !1, passive: !1 },
        { capture: !1, passive: !0 },
        { capture: !0, passive: !1 },
        { capture: !0, passive: !0 }
      ].map((s) => this._getProxyEmitter(i, s)).filter((s) => !!s);
    }
  }
  return e;
}
[
  "_getProxyEmitter",
  "_getAllProxyEmitters",
  "on",
  "once",
  "off",
  "listenTo",
  "stopListening",
  "fire",
  "delegate",
  "stopDelegating",
  "_addEventListener",
  "_removeEventListener"
].forEach((n) => {
  it[n] = du.prototype[n];
});
class __ extends N() {
  /**
   * @param node DOM Node that fires events.
   * @param options Additional options.
   * @param options.useCapture Indicates that events of this type will be dispatched to the registered
   * listener before being dispatched to any EventTarget beneath it in the DOM tree.
   * @param options.usePassive Indicates that the function specified by listener will never call preventDefault()
   * and prevents blocking browser's main thread by this event handler.
   */
  constructor(e, t) {
    super(), uc(this, fu(e, t)), this._domNode = e, this._options = t;
  }
  /**
   * Registers a callback function to be executed when an event is fired.
   *
   * It attaches a native DOM listener to the DOM Node. When fired,
   * a corresponding Emitter event will also fire with DOM Event object as an argument.
   *
   * **Note**: This is automatically called by the
   * {@link module:utils/emittermixin~Emitter#listenTo `Emitter#listenTo()`}.
   *
   * @param event The name of the event.
   */
  attach(e) {
    if (this._domListeners && this._domListeners[e])
      return;
    const t = this._createDomListener(e);
    this._domNode.addEventListener(e, t, this._options), this._domListeners || (this._domListeners = {}), this._domListeners[e] = t;
  }
  /**
   * Stops executing the callback on the given event.
   *
   * **Note**: This is automatically called by the
   * {@link module:utils/emittermixin~Emitter#stopListening `Emitter#stopListening()`}.
   *
   * @param event The name of the event.
   */
  detach(e) {
    let t;
    this._domListeners[e] && (!(t = this._events[e]) || !t.callbacks.length) && this._domListeners[e].removeListener();
  }
  /**
   * Adds callback to emitter for given event.
   *
   * @internal
   * @param event The name of the event.
   * @param callback The function to be called on event.
   * @param options Additional options.
   */
  _addEventListener(e, t, i) {
    this.attach(e), N().prototype._addEventListener.call(this, e, t, i);
  }
  /**
   * Removes callback from emitter for given event.
   *
   * @internal
   * @param event The name of the event.
   * @param callback The function to stop being called.
   */
  _removeEventListener(e, t) {
    N().prototype._removeEventListener.call(this, e, t), this.detach(e);
  }
  /**
   * Creates a native DOM listener callback. When the native DOM event
   * is fired it will fire corresponding event on this ProxyEmitter.
   * Note: A native DOM Event is passed as an argument.
   *
   * @param event The name of the event.
   * @returns The DOM listener callback.
   */
  _createDomListener(e) {
    const t = (i) => {
      this.fire(e, i);
    };
    return t.removeListener = () => {
      this._domNode.removeEventListener(e, t, this._options), delete this._domListeners[e];
    }, t;
  }
}
function v_(n) {
  return n["data-ck-expando"] || (n["data-ck-expando"] = Ye());
}
function fu(n, e) {
  let t = v_(n);
  for (const i of Object.keys(e).sort())
    e[i] && (t += "-" + i);
  return t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let zs;
try {
  zs = { window, document };
} catch {
  /* istanbul ignore next -- @preserve */
  zs = { window: {}, document: {} };
}
const I = zs;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function y_(n) {
  let e = n.parentElement;
  if (!e)
    return null;
  for (; e.tagName != "BODY"; ) {
    const t = e.style.overflowY || I.window.getComputedStyle(e).overflowY;
    if (t === "auto" || t === "scroll")
      break;
    if (e = e.parentElement, !e)
      return null;
  }
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function mu(n) {
  const e = [];
  let t = n;
  for (; t && t.nodeType != Node.DOCUMENT_NODE; )
    e.unshift(t), t = t.parentNode;
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function k_(n) {
  return n instanceof HTMLTextAreaElement ? n.value : n.innerHTML;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function J(n) {
  return Object.prototype.toString.call(n) == "[object Text]";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Bn(n) {
  return Object.prototype.toString.apply(n) == "[object Range]";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function gu(n) {
  const e = n.ownerDocument.defaultView.getComputedStyle(n);
  return {
    top: parseInt(e.borderTopWidth, 10),
    right: parseInt(e.borderRightWidth, 10),
    bottom: parseInt(e.borderBottomWidth, 10),
    left: parseInt(e.borderLeftWidth, 10)
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const pu = ["top", "right", "bottom", "left", "width", "height"];
class V {
  /**
   * Creates an instance of rect.
   *
   * ```ts
   * // Rect of an HTMLElement.
   * const rectA = new Rect( document.body );
   *
   * // Rect of a DOM Range.
   * const rectB = new Rect( document.getSelection().getRangeAt( 0 ) );
   *
   * // Rect of a window (web browser viewport).
   * const rectC = new Rect( window );
   *
   * // Rect out of an object.
   * const rectD = new Rect( { top: 0, right: 10, bottom: 10, left: 0, width: 10, height: 10 } );
   *
   * // Rect out of another Rect instance.
   * const rectE = new Rect( rectD );
   *
   * // Rect out of a ClientRect.
   * const rectF = new Rect( document.body.getClientRects().item( 0 ) );
   * ```
   *
   * **Note**: By default a rect of an HTML element includes its CSS borders and scrollbars (if any)
   * ant the rect of a `window` includes scrollbars too. Use {@link #excludeScrollbarsAndBorders}
   * to get the inner part of the rect.
   *
   * @param source A source object to create the rect.
   */
  constructor(e) {
    const t = Bn(e);
    if (Object.defineProperty(this, "_source", {
      // If the source is a Rect instance, copy it's #_source.
      value: e._source || e,
      writable: !0,
      enumerable: !1
    }), wu(e) || t)
      if (t) {
        const i = V.getDomRangeRects(e);
        ji(this, V.getBoundingRect(i));
      } else
        ji(this, e.getBoundingClientRect());
    else if (bn(e)) {
      const { innerWidth: i, innerHeight: s } = e;
      ji(this, {
        top: 0,
        right: i,
        bottom: s,
        left: 0,
        width: i,
        height: s
      });
    } else
      ji(this, e);
  }
  /**
   * Returns a clone of the rect.
   *
   * @returns A cloned rect.
   */
  clone() {
    return new V(this);
  }
  /**
   * Moves the rect so that its upper–left corner lands in desired `[ x, y ]` location.
   *
   * @param x Desired horizontal location.
   * @param y Desired vertical location.
   * @returns A rect which has been moved.
   */
  moveTo(e, t) {
    return this.top = t, this.right = e + this.width, this.bottom = t + this.height, this.left = e, this;
  }
  /**
   * Moves the rect in–place by a dedicated offset.
   *
   * @param x A horizontal offset.
   * @param y A vertical offset
   * @returns A rect which has been moved.
   */
  moveBy(e, t) {
    return this.top += t, this.right += e, this.left += e, this.bottom += t, this;
  }
  /**
   * Returns a new rect a a result of intersection with another rect.
   */
  getIntersection(e) {
    const t = {
      top: Math.max(this.top, e.top),
      right: Math.min(this.right, e.right),
      bottom: Math.min(this.bottom, e.bottom),
      left: Math.max(this.left, e.left),
      width: 0,
      height: 0
    };
    return t.width = t.right - t.left, t.height = t.bottom - t.top, t.width < 0 || t.height < 0 ? null : new V(t);
  }
  /**
   * Returns the area of intersection with another rect.
   *
   * @returns Area of intersection.
   */
  getIntersectionArea(e) {
    const t = this.getIntersection(e);
    return t ? t.getArea() : 0;
  }
  /**
   * Returns the area of the rect.
   */
  getArea() {
    return this.width * this.height;
  }
  /**
   * Returns a new rect, a part of the original rect, which is actually visible to the user,
   * e.g. an original rect cropped by parent element rects which have `overflow` set in CSS
   * other than `"visible"`.
   *
   * If there's no such visible rect, which is when the rect is limited by one or many of
   * the ancestors, `null` is returned.
   *
   * **Note**: This method does not consider the boundaries of the viewport (window).
   * To get a rect cropped by all ancestors and the viewport, use an intersection such as:
   *
   * ```ts
   * const visibleInViewportRect = new Rect( window ).getIntersection( new Rect( source ).getVisible() );
   * ```
   *
   * @returns A visible rect instance or `null`, if there's none.
   */
  getVisible() {
    const e = this._source;
    let t = this.clone();
    if (ea(e))
      return t;
    let i = e, s = e.parentNode || e.commonAncestorContainer, r;
    for (; s && !ea(s); ) {
      if (i instanceof HTMLElement && ta(i) === "absolute" && (r = i), r && (ta(s) !== "relative" || C_(s) === "visible")) {
        i = s, s = s.parentNode;
        continue;
      }
      const o = new V(s), a = t.getIntersection(o);
      if (a)
        a.getArea() < t.getArea() && (t = a);
      else
        return null;
      i = s, s = s.parentNode;
    }
    return t;
  }
  /**
   * Checks if all property values ({@link #top}, {@link #left}, {@link #right},
   * {@link #bottom}, {@link #width} and {@link #height}) are the equal in both rect
   * instances.
   *
   * @param anotherRect A rect instance to compare with.
   * @returns `true` when Rects are equal. `false` otherwise.
   */
  isEqual(e) {
    for (const t of pu)
      if (this[t] !== e[t])
        return !1;
    return !0;
  }
  /**
   * Checks whether a rect fully contains another rect instance.
   *
   * @param anotherRect
   * @returns `true` if contains, `false` otherwise.
   */
  contains(e) {
    const t = this.getIntersection(e);
    return !!(t && t.isEqual(e));
  }
  /**
   * Excludes scrollbars and CSS borders from the rect.
   *
   * * Borders are removed when {@link #_source} is an HTML element.
   * * Scrollbars are excluded from HTML elements and the `window`.
   *
   * @returns A rect which has been updated.
   */
  excludeScrollbarsAndBorders() {
    const e = this._source;
    let t, i, s;
    if (bn(e))
      t = e.innerWidth - e.document.documentElement.clientWidth, i = e.innerHeight - e.document.documentElement.clientHeight, s = e.getComputedStyle(e.document.documentElement).direction;
    else {
      const r = gu(e);
      t = e.offsetWidth - e.clientWidth - r.left - r.right, i = e.offsetHeight - e.clientHeight - r.top - r.bottom, s = e.ownerDocument.defaultView.getComputedStyle(e).direction, this.left += r.left, this.top += r.top, this.right -= r.right, this.bottom -= r.bottom, this.width = this.right - this.left, this.height = this.bottom - this.top;
    }
    return this.width -= t, s === "ltr" ? this.right -= t : this.left += t, this.height -= i, this.bottom -= i, this;
  }
  /**
   * Returns an array of rects of the given native DOM Range.
   *
   * @param range A native DOM range.
   * @returns DOM Range rects.
   */
  static getDomRangeRects(e) {
    const t = [], i = Array.from(e.getClientRects());
    if (i.length)
      for (const s of i)
        t.push(new V(s));
    else {
      let s = e.startContainer;
      J(s) && (s = s.parentNode);
      const r = new V(s.getBoundingClientRect());
      r.right = r.left, r.width = 0, t.push(r);
    }
    return t;
  }
  /**
   * Returns a bounding rectangle that contains all the given `rects`.
   *
   * @param rects A list of rectangles that should be contained in the result rectangle.
   * @returns Bounding rectangle or `null` if no `rects` were given.
   */
  static getBoundingRect(e) {
    const t = {
      left: Number.POSITIVE_INFINITY,
      top: Number.POSITIVE_INFINITY,
      right: Number.NEGATIVE_INFINITY,
      bottom: Number.NEGATIVE_INFINITY,
      width: 0,
      height: 0
    };
    let i = 0;
    for (const s of e)
      i++, t.left = Math.min(t.left, s.left), t.top = Math.min(t.top, s.top), t.right = Math.max(t.right, s.right), t.bottom = Math.max(t.bottom, s.bottom);
    return i == 0 ? null : (t.width = t.right - t.left, t.height = t.bottom - t.top, new V(t));
  }
}
function ji(n, e) {
  for (const t of pu)
    n[t] = e[t];
}
function ea(n) {
  return wu(n) ? n === n.ownerDocument.body : !1;
}
function wu(n) {
  return n !== null && typeof n == "object" && n.nodeType === 1 && typeof n.getBoundingClientRect == "function";
}
function ta(n) {
  return n.ownerDocument.defaultView.getComputedStyle(n).position;
}
function C_(n) {
  return n.ownerDocument.defaultView.getComputedStyle(n).overflow;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $ {
  /**
   * Creates an instance of the `ResizeObserver` class.
   *
   * @param element A DOM element that is to be observed for resizing. Note that
   * the element must be visible (i.e. not detached from DOM) for the observer to work.
   * @param callback A function called when the observed element was resized. It passes
   * the [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)
   * object with information about the resize event.
   */
  constructor(e, t) {
    $._observerInstance || $._createObserver(), this._element = e, this._callback = t, $._addElementCallback(e, t), $._observerInstance.observe(e);
  }
  /**
   * The element observed by this observer.
   */
  get element() {
    return this._element;
  }
  /**
   * Destroys the observer which disables the `callback` passed to the {@link #constructor}.
   */
  destroy() {
    $._deleteElementCallback(this._element, this._callback);
  }
  /**
   * Registers a new resize callback for the DOM element.
   */
  static _addElementCallback(e, t) {
    $._elementCallbacks || ($._elementCallbacks = /* @__PURE__ */ new Map());
    let i = $._elementCallbacks.get(e);
    i || (i = /* @__PURE__ */ new Set(), $._elementCallbacks.set(e, i)), i.add(t);
  }
  /**
   * Removes a resize callback from the DOM element. If no callbacks are left
   * for the element, it removes the element from the native observer.
   */
  static _deleteElementCallback(e, t) {
    const i = $._getElementCallbacks(e);
    i && (i.delete(t), i.size || ($._elementCallbacks.delete(e), $._observerInstance.unobserve(e))), $._elementCallbacks && !$._elementCallbacks.size && ($._observerInstance = null, $._elementCallbacks = null);
  }
  /**
   * Returns are registered resize callbacks for the DOM element.
   */
  static _getElementCallbacks(e) {
    return $._elementCallbacks ? $._elementCallbacks.get(e) : null;
  }
  /**
   * Creates the single native observer shared across all `ResizeObserver` instances.
   */
  static _createObserver() {
    $._observerInstance = new I.window.ResizeObserver((e) => {
      for (const t of e) {
        const i = $._getElementCallbacks(t.target);
        if (i)
          for (const s of i)
            s(t);
      }
    });
  }
}
$._observerInstance = null;
$._elementCallbacks = null;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function ia(n, e) {
  n instanceof HTMLTextAreaElement && (n.value = e), n.innerHTML = e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Sr(n) {
  return (e) => e + n;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function qi(n) {
  let e = 0;
  for (; n.previousSibling; )
    n = n.previousSibling, e++;
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function bu(n, e, t) {
  n.insertBefore(t, n.childNodes[e] || null);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Zt(n) {
  return n && n.nodeType === Node.COMMENT_NODE;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function _u(n) {
  try {
    I.document.createAttribute(n);
  } catch {
    return !1;
  }
  return !0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function St(n) {
  return !!(n && n.getClientRects && n.getClientRects().length);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function E_(n) {
  return !n || !n.parentNode || n.offsetParent === I.document.body ? null : n.offsetParent;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function vu({ element: n, target: e, positions: t, limiter: i, fitInViewport: s, viewportOffsetConfig: r }) {
  Pt(e) && (e = e()), Pt(i) && (i = i());
  const o = E_(n), a = new V(n), l = new V(e);
  let c;
  const u = s && A_(r) || null, h = { targetRect: l, elementRect: a, positionedElementAncestor: o, viewportRect: u };
  if (!i && !s)
    c = new Hs(t[0], h);
  else {
    const f = i && new V(i).getVisible();
    Object.assign(h, { limiterRect: f, viewportRect: u }), c = T_(t, h) || new Hs(t[0], h);
  }
  return c;
}
function A_(n) {
  n = Object.assign({ top: 0, bottom: 0, left: 0, right: 0 }, n);
  const e = new V(I.window);
  return e.top += n.top, e.height -= n.top, e.bottom -= n.bottom, e.height -= n.bottom, e;
}
function T_(n, e) {
  const { elementRect: t } = e, i = t.getArea(), s = n.map((a) => new Hs(a, e)).filter((a) => !!a.name);
  let r = 0, o = null;
  for (const a of s) {
    const { limiterIntersectionArea: l, viewportIntersectionArea: c } = a;
    if (l === i)
      return a;
    const u = c ** 2 + l ** 2;
    u > r && (r = u, o = a);
  }
  return o;
}
function P_(n, e) {
  const t = yu(new V(e)), i = gu(e);
  let s = 0, r = 0;
  s -= t.left, r -= t.top, s += e.scrollLeft, r += e.scrollTop, s -= i.left, r -= i.top, n.moveBy(s, r);
}
function yu(n) {
  const { scrollX: e, scrollY: t } = I.window;
  return n.clone().moveBy(e, t);
}
class Hs {
  /**
   * Creates an instance of the {@link module:utils/dom/position~PositionObject} class.
   *
   * @param positioningFunction function The function that defines the expected
   * coordinates the positioned element should move to.
   * @param options options object.
   * @param options.elementRect The positioned element rect.
   * @param options.targetRect The target element rect.
   * @param options.viewportRect The viewport rect.
   * @param options.limiterRect The limiter rect.
   * @param options.positionedElementAncestor Nearest element ancestor element which CSS position is not "static".
   */
  constructor(e, t) {
    const i = e(t.targetRect, t.elementRect, t.viewportRect);
    if (!i)
      return;
    const { left: s, top: r, name: o, config: a } = i;
    this.name = o, this.config = a, this._positioningFunctionCorrdinates = { left: s, top: r }, this._options = t;
  }
  /**
   * The left value in pixels in the CSS `position: absolute` coordinate system.
   * Set it on the positioned element in DOM to move it to the position.
   */
  get left() {
    return this._absoluteRect.left;
  }
  /**
   * The top value in pixels in the CSS `position: absolute` coordinate system.
   * Set it on the positioned element in DOM to move it to the position.
   */
  get top() {
    return this._absoluteRect.top;
  }
  /**
   * An intersection area between positioned element and limiter within viewport constraints.
   */
  get limiterIntersectionArea() {
    const e = this._options.limiterRect;
    if (e) {
      const t = this._options.viewportRect;
      if (t) {
        const i = e.getIntersection(t);
        if (i)
          return i.getIntersectionArea(this._rect);
      } else
        return e.getIntersectionArea(this._rect);
    }
    return 0;
  }
  /**
   * An intersection area between positioned element and viewport.
   */
  get viewportIntersectionArea() {
    const e = this._options.viewportRect;
    return e ? e.getIntersectionArea(this._rect) : 0;
  }
  /**
   * An already positioned element rect. A clone of the element rect passed to the constructor
   * but placed in the viewport according to the positioning function.
   */
  get _rect() {
    return this._cachedRect ? this._cachedRect : (this._cachedRect = this._options.elementRect.clone().moveTo(this._positioningFunctionCorrdinates.left, this._positioningFunctionCorrdinates.top), this._cachedRect);
  }
  /**
   * An already absolutely positioned element rect. See ({@link #_rect}).
   */
  get _absoluteRect() {
    return this._cachedAbsoluteRect ? this._cachedAbsoluteRect : (this._cachedAbsoluteRect = yu(this._rect), this._options.positionedElementAncestor && P_(this._cachedAbsoluteRect, this._options.positionedElementAncestor), this._cachedAbsoluteRect);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function na(n) {
  const e = n.parentNode;
  e && e.removeChild(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function x_({ target: n, viewportOffset: e = 0, ancestorOffset: t = 0, alignToTop: i, forceScroll: s }) {
  const r = Ir(n);
  let o = r, a = null;
  for (e = R_(e); o; ) {
    let l;
    o == r ? l = sa(n) : l = sa(a), I_({
      parent: l,
      getRect: () => ra(n, o),
      alignToTop: i,
      ancestorOffset: t,
      forceScroll: s
    });
    const c = ra(n, o);
    if (S_({
      window: o,
      rect: c,
      viewportOffset: e,
      alignToTop: i,
      forceScroll: s
    }), o.parent != o) {
      if (a = o.frameElement, o = o.parent, !a)
        return;
    } else
      o = null;
  }
}
function S_({ window: n, rect: e, alignToTop: t, forceScroll: i, viewportOffset: s }) {
  const r = e.clone().moveBy(0, s.bottom), o = e.clone().moveBy(0, -s.top), a = new V(n).excludeScrollbarsAndBorders(), l = [o, r], c = t && i, u = l.every((b) => a.contains(b));
  let { scrollX: h, scrollY: f } = n;
  const m = h, p = f;
  c ? f -= a.top - e.top + s.top : u || (Cu(o, a) ? f -= a.top - e.top + s.top : ku(r, a) && (t ? f += e.top - a.top - s.top : f += e.bottom - a.bottom + s.bottom)), u || (Eu(e, a) ? h -= a.left - e.left + s.left : Au(e, a) && (h += e.right - a.right + s.right)), (h != m || f !== p) && n.scrollTo(h, f);
}
function I_({ parent: n, getRect: e, alignToTop: t, forceScroll: i, ancestorOffset: s = 0 }) {
  const r = Ir(n), o = t && i;
  let a, l, c;
  for (; n != r.document.body; )
    l = e(), a = new V(n).excludeScrollbarsAndBorders(), c = a.contains(l), o ? n.scrollTop -= a.top - l.top + s : c || (Cu(l, a) ? n.scrollTop -= a.top - l.top + s : ku(l, a) && (t ? n.scrollTop += l.top - a.top - s : n.scrollTop += l.bottom - a.bottom + s)), c || (Eu(l, a) ? n.scrollLeft -= a.left - l.left + s : Au(l, a) && (n.scrollLeft += l.right - a.right + s)), n = n.parentNode;
}
function ku(n, e) {
  return n.bottom > e.bottom;
}
function Cu(n, e) {
  return n.top < e.top;
}
function Eu(n, e) {
  return n.left < e.left;
}
function Au(n, e) {
  return n.right > e.right;
}
function Ir(n) {
  return Bn(n) ? n.startContainer.ownerDocument.defaultView : n.ownerDocument.defaultView;
}
function sa(n) {
  if (Bn(n)) {
    let e = n.commonAncestorContainer;
    return J(e) && (e = e.parentNode), e;
  } else
    return n.parentNode;
}
function ra(n, e) {
  const t = Ir(n), i = new V(n);
  if (t === e)
    return i;
  {
    let s = t;
    for (; s != e; ) {
      const r = s.frameElement, o = new V(r).excludeScrollbarsAndBorders();
      i.moveBy(o.left, o.top), s = s.parent;
    }
  }
  return i;
}
function R_(n) {
  return typeof n == "number" ? {
    top: n,
    bottom: n,
    left: n,
    right: n
  } : n;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const O_ = {
  ctrl: "⌃",
  cmd: "⌘",
  alt: "⌥",
  shift: "⇧"
}, M_ = {
  ctrl: "Ctrl+",
  alt: "Alt+",
  shift: "Shift+"
}, R = N_(), V_ = Object.fromEntries(Object.entries(R).map(([n, e]) => [e, n.charAt(0).toUpperCase() + n.slice(1)]));
function ii(n) {
  let e;
  if (typeof n == "string") {
    if (e = R[n.toLowerCase()], !e)
      throw new d("keyboard-unknown-key", null, { key: n });
  } else
    e = n.keyCode + (n.altKey ? R.alt : 0) + (n.ctrlKey ? R.ctrl : 0) + (n.shiftKey ? R.shift : 0) + (n.metaKey ? R.cmd : 0);
  return e;
}
function Rr(n) {
  return typeof n == "string" && (n = L_(n)), n.map((e) => typeof e == "string" ? B_(e) : e).reduce((e, t) => t + e, 0);
}
function oa(n) {
  let e = Rr(n);
  return Object.entries(S.isMac ? O_ : M_).reduce((s, [r, o]) => (e & R[r] && (e &= ~R[r], s += o), s), "") + (e ? V_[e] : "");
}
function D_(n) {
  return n == R.arrowright || n == R.arrowleft || n == R.arrowup || n == R.arrowdown;
}
function Tu(n, e) {
  const t = e === "ltr";
  switch (n) {
    case R.arrowleft:
      return t ? "left" : "right";
    case R.arrowright:
      return t ? "right" : "left";
    case R.arrowup:
      return "up";
    case R.arrowdown:
      return "down";
  }
}
function B_(n) {
  if (n.endsWith("!"))
    return ii(n.slice(0, -1));
  const e = ii(n);
  return S.isMac && e == R.ctrl ? R.cmd : e;
}
function F_(n, e) {
  const t = Tu(n, e);
  return t === "down" || t === "right";
}
function N_() {
  const n = {
    arrowleft: 37,
    arrowup: 38,
    arrowright: 39,
    arrowdown: 40,
    backspace: 8,
    delete: 46,
    enter: 13,
    space: 32,
    esc: 27,
    tab: 9,
    // The idea about these numbers is that they do not collide with any real key codes, so we can use them
    // like bit masks.
    ctrl: 1114112,
    shift: 2228224,
    alt: 4456448,
    cmd: 8912896
  };
  for (let e = 65; e <= 90; e++) {
    const t = String.fromCharCode(e);
    n[t.toLowerCase()] = e;
  }
  for (let e = 48; e <= 57; e++)
    n[e - 48] = e;
  for (let e = 112; e <= 123; e++)
    n["f" + (e - 111)] = e;
  for (const e of "`-=[];',./\\")
    n[e] = e.charCodeAt(0);
  return n;
}
function L_(n) {
  return n.split("+").map((e) => e.trim());
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const $_ = [
  "ar",
  "ara",
  "fa",
  "per",
  "fas",
  "he",
  "heb",
  "ku",
  "kur",
  "ug",
  "uig"
  // Uighur, Uyghur
];
function aa(n) {
  return $_.includes(n) ? "rtl" : "ltr";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function X(n) {
  return Array.isArray(n) ? n : [n];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
/* istanbul ignore else -- @preserve */
I.window.CKEDITOR_TRANSLATIONS || (I.window.CKEDITOR_TRANSLATIONS = {});
function z_(n, e, t = 1) {
  if (typeof t != "number")
    throw new d("translation-service-quantity-not-a-number", null, { quantity: t });
  const i = W_();
  i === 1 && (n = Object.keys(I.window.CKEDITOR_TRANSLATIONS)[0]);
  const s = e.id || e.string;
  if (i === 0 || !H_(n, s))
    return t !== 1 ? e.plural : e.string;
  const r = I.window.CKEDITOR_TRANSLATIONS[n].dictionary, o = I.window.CKEDITOR_TRANSLATIONS[n].getPluralForm || ((c) => c === 1 ? 0 : 1), a = r[s];
  if (typeof a == "string")
    return a;
  const l = Number(o(t));
  return a[l];
}
function H_(n, e) {
  return !!I.window.CKEDITOR_TRANSLATIONS[n] && !!I.window.CKEDITOR_TRANSLATIONS[n].dictionary[e];
}
function W_() {
  return Object.keys(I.window.CKEDITOR_TRANSLATIONS).length;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class U_ {
  /**
   * Creates a new instance of the locale class. Learn more about
   * {@glink features/ui-language configuring the language of the editor}.
   *
   * @param options Locale configuration.
   * @param options.uiLanguage The editor UI language code in the
   * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. See {@link #uiLanguage}.
   * @param options.contentLanguage The editor content language code in the
   * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. If not specified, the same as `options.language`.
   * See {@link #contentLanguage}.
   */
  constructor({ uiLanguage: e = "en", contentLanguage: t } = {}) {
    this.uiLanguage = e, this.contentLanguage = t || this.uiLanguage, this.uiLanguageDirection = aa(this.uiLanguage), this.contentLanguageDirection = aa(this.contentLanguage), this.t = (i, s) => this._t(i, s);
  }
  /**
   * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.
   *
   * **Note**: This property was deprecated. Please use {@link #uiLanguage} and {@link #contentLanguage}
   * properties instead.
   *
   * @deprecated
   */
  get language() {
    return console.warn("locale-deprecated-language-property: The Locale#language property has been deprecated and will be removed in the near future. Please use #uiLanguage and #contentLanguage properties instead."), this.uiLanguage;
  }
  /**
   * An unbound version of the {@link #t} method.
   */
  _t(e, t = []) {
    t = X(t), typeof e == "string" && (e = { string: e });
    const s = !!e.plural ? t[0] : 1, r = z_(this.uiLanguage, e, s);
    return j_(r, t);
  }
}
function j_(n, e) {
  return n.replace(/%(\d+)/g, (t, i) => i < e.length ? e[i] : t);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class He extends N() {
  constructor(e = {}, t = {}) {
    super();
    const i = _e(e);
    if (i || (t = e), this._items = [], this._itemMap = /* @__PURE__ */ new Map(), this._idProperty = t.idProperty || "id", this._bindToExternalToInternalMap = /* @__PURE__ */ new WeakMap(), this._bindToInternalToExternalMap = /* @__PURE__ */ new WeakMap(), this._skippedIndexesFromExternal = [], i)
      for (const s of e)
        this._items.push(s), this._itemMap.set(this._getItemIdBeforeAdding(s), s);
  }
  /**
   * The number of items available in the collection.
   */
  get length() {
    return this._items.length;
  }
  /**
   * Returns the first item from the collection or null when collection is empty.
   */
  get first() {
    return this._items[0] || null;
  }
  /**
   * Returns the last item from the collection or null when collection is empty.
   */
  get last() {
    return this._items[this.length - 1] || null;
  }
  /**
   * Adds an item into the collection.
   *
   * If the item does not have an id, then it will be automatically generated and set on the item.
   *
   * @param item
   * @param index The position of the item in the collection. The item
   * is pushed to the collection when `index` not specified.
   * @fires add
   * @fires change
   */
  add(e, t) {
    return this.addMany([e], t);
  }
  /**
   * Adds multiple items into the collection.
   *
   * Any item not containing an id will get an automatically generated one.
   *
   * @param items
   * @param index The position of the insertion. Items will be appended if no `index` is specified.
   * @fires add
   * @fires change
   */
  addMany(e, t) {
    if (t === void 0)
      t = this._items.length;
    else if (t > this._items.length || t < 0)
      throw new d("collection-add-item-invalid-index", this);
    let i = 0;
    for (const s of e) {
      const r = this._getItemIdBeforeAdding(s), o = t + i;
      this._items.splice(o, 0, s), this._itemMap.set(r, s), this.fire("add", s, o), i++;
    }
    return this.fire("change", {
      added: e,
      removed: [],
      index: t
    }), this;
  }
  /**
   * Gets an item by its ID or index.
   *
   * @param idOrIndex The item ID or index in the collection.
   * @returns The requested item or `null` if such item does not exist.
   */
  get(e) {
    let t;
    if (typeof e == "string")
      t = this._itemMap.get(e);
    else if (typeof e == "number")
      t = this._items[e];
    else
      throw new d("collection-get-invalid-arg", this);
    return t || null;
  }
  /**
   * Returns a Boolean indicating whether the collection contains an item.
   *
   * @param itemOrId The item or its ID in the collection.
   * @returns `true` if the collection contains the item, `false` otherwise.
   */
  has(e) {
    if (typeof e == "string")
      return this._itemMap.has(e);
    {
      const t = this._idProperty, i = e[t];
      return i && this._itemMap.has(i);
    }
  }
  /**
   * Gets an index of an item in the collection.
   * When an item is not defined in the collection, the index will equal -1.
   *
   * @param itemOrId The item or its ID in the collection.
   * @returns The index of a given item.
   */
  getIndex(e) {
    let t;
    return typeof e == "string" ? t = this._itemMap.get(e) : t = e, t ? this._items.indexOf(t) : -1;
  }
  /**
   * Removes an item from the collection.
   *
   * @param subject The item to remove, its ID or index in the collection.
   * @returns The removed item.
   * @fires remove
   * @fires change
   */
  remove(e) {
    const [t, i] = this._remove(e);
    return this.fire("change", {
      added: [],
      removed: [t],
      index: i
    }), t;
  }
  /**
   * Executes the callback for each item in the collection and composes an array or values returned by this callback.
   *
   * @typeParam U The result type of the callback.
   * @param callback
   * @param ctx Context in which the `callback` will be called.
   * @returns The result of mapping.
   */
  map(e, t) {
    return this._items.map(e, t);
  }
  /**
   * Finds the first item in the collection for which the `callback` returns a true value.
   *
   * @param callback
   * @param ctx Context in which the `callback` will be called.
   * @returns The item for which `callback` returned a true value.
   */
  find(e, t) {
    return this._items.find(e, t);
  }
  /**
   * Returns an array with items for which the `callback` returned a true value.
   *
   * @param callback
   * @param ctx Context in which the `callback` will be called.
   * @returns The array with matching items.
   */
  filter(e, t) {
    return this._items.filter(e, t);
  }
  /**
   * Removes all items from the collection and destroys the binding created using
   * {@link #bindTo}.
   *
   * @fires remove
   * @fires change
   */
  clear() {
    this._bindToCollection && (this.stopListening(this._bindToCollection), this._bindToCollection = null);
    const e = Array.from(this._items);
    for (; this.length; )
      this._remove(0);
    this.fire("change", {
      added: [],
      removed: e,
      index: 0
    });
  }
  /**
   * Binds and synchronizes the collection with another one.
   *
   * The binding can be a simple factory:
   *
   * ```ts
   * class FactoryClass {
   * 	public label: string;
   *
   * 	constructor( data: { label: string } ) {
   * 		this.label = data.label;
   * 	}
   * }
   *
   * const source = new Collection<{ label: string }>( { idProperty: 'label' } );
   * const target = new Collection<FactoryClass>();
   *
   * target.bindTo( source ).as( FactoryClass );
   *
   * source.add( { label: 'foo' } );
   * source.add( { label: 'bar' } );
   *
   * console.log( target.length ); // 2
   * console.log( target.get( 1 ).label ); // 'bar'
   *
   * source.remove( 0 );
   * console.log( target.length ); // 1
   * console.log( target.get( 0 ).label ); // 'bar'
   * ```
   *
   * or the factory driven by a custom callback:
   *
   * ```ts
   * class FooClass {
   * 	public label: string;
   *
   * 	constructor( data: { label: string } ) {
   * 		this.label = data.label;
   * 	}
   * }
   *
   * class BarClass {
   * 	public label: string;
   *
   * 	constructor( data: { label: string } ) {
   * 		this.label = data.label;
   * 	}
   * }
   *
   * const source = new Collection<{ label: string }>( { idProperty: 'label' } );
   * const target = new Collection<FooClass | BarClass>();
   *
   * target.bindTo( source ).using( ( item ) => {
   * 	if ( item.label == 'foo' ) {
   * 		return new FooClass( item );
   * 	} else {
   * 		return new BarClass( item );
   * 	}
   * } );
   *
   * source.add( { label: 'foo' } );
   * source.add( { label: 'bar' } );
   *
   * console.log( target.length ); // 2
   * console.log( target.get( 0 ) instanceof FooClass ); // true
   * console.log( target.get( 1 ) instanceof BarClass ); // true
   * ```
   *
   * or the factory out of property name:
   *
   * ```ts
   * const source = new Collection<{ nested: { value: string } }>();
   * const target = new Collection<{ value: string }>();
   *
   * target.bindTo( source ).using( 'nested' );
   *
   * source.add( { nested: { value: 'foo' } } );
   * source.add( { nested: { value: 'bar' } } );
   *
   * console.log( target.length ); // 2
   * console.log( target.get( 0 ).value ); // 'foo'
   * console.log( target.get( 1 ).value ); // 'bar'
   * ```
   *
   * It's possible to skip specified items by returning null value:
   *
   * ```ts
   * const source = new Collection<{ hidden: boolean }>();
   * const target = new Collection<{ hidden: boolean }>();
   *
   * target.bindTo( source ).using( item => {
   * 	if ( item.hidden ) {
   * 		return null;
   * 	}
   *
   * 	return item;
   * } );
   *
   * source.add( { hidden: true } );
   * source.add( { hidden: false } );
   *
   * console.log( source.length ); // 2
   * console.log( target.length ); // 1
   * ```
   *
   * **Note**: {@link #clear} can be used to break the binding.
   *
   * @typeParam S The type of `externalCollection` element.
   * @param externalCollection A collection to be bound.
   * @returns The binding chain object.
   */
  bindTo(e) {
    if (this._bindToCollection)
      throw new d("collection-bind-to-rebind", this);
    return this._bindToCollection = e, {
      as: (t) => {
        this._setUpBindToBinding((i) => new t(i));
      },
      using: (t) => {
        typeof t == "function" ? this._setUpBindToBinding(t) : this._setUpBindToBinding((i) => i[t]);
      }
    };
  }
  /**
   * Finalizes and activates a binding initiated by {@link #bindTo}.
   *
   * @param factory A function which produces collection items.
   */
  _setUpBindToBinding(e) {
    const t = this._bindToCollection, i = (s, r, o) => {
      const a = t._bindToCollection == this, l = t._bindToInternalToExternalMap.get(r);
      if (a && l)
        this._bindToExternalToInternalMap.set(r, l), this._bindToInternalToExternalMap.set(l, r);
      else {
        const c = e(r);
        if (!c) {
          this._skippedIndexesFromExternal.push(o);
          return;
        }
        let u = o;
        for (const h of this._skippedIndexesFromExternal)
          o > h && u--;
        for (const h of t._skippedIndexesFromExternal)
          u >= h && u++;
        this._bindToExternalToInternalMap.set(r, c), this._bindToInternalToExternalMap.set(c, r), this.add(c, u);
        for (let h = 0; h < t._skippedIndexesFromExternal.length; h++)
          u <= t._skippedIndexesFromExternal[h] && t._skippedIndexesFromExternal[h]++;
      }
    };
    for (const s of t)
      i(null, s, t.getIndex(s));
    this.listenTo(t, "add", i), this.listenTo(t, "remove", (s, r, o) => {
      const a = this._bindToExternalToInternalMap.get(r);
      a && this.remove(a), this._skippedIndexesFromExternal = this._skippedIndexesFromExternal.reduce((l, c) => (o < c && l.push(c - 1), o > c && l.push(c), l), []);
    });
  }
  /**
   * Returns an unique id property for a given `item`.
   *
   * The method will generate new id and assign it to the `item` if it doesn't have any.
   *
   * @param item Item to be added.
   */
  _getItemIdBeforeAdding(e) {
    const t = this._idProperty;
    let i;
    if (t in e) {
      if (i = e[t], typeof i != "string")
        throw new d("collection-add-invalid-id", this);
      if (this.get(i))
        throw new d("collection-add-item-already-exists", this);
    } else
      e[t] = i = Ye();
    return i;
  }
  /**
   * Core {@link #remove} method implementation shared in other functions.
   *
   * In contrast this method **does not** fire the {@link #event:change} event.
   *
   * @param subject The item to remove, its id or index in the collection.
   * @returns Returns an array with the removed item and its index.
   * @fires remove
   */
  _remove(e) {
    let t, i, s, r = !1;
    const o = this._idProperty;
    if (typeof e == "string" ? (i = e, s = this._itemMap.get(i), r = !s, s && (t = this._items.indexOf(s))) : typeof e == "number" ? (t = e, s = this._items[t], r = !s, s && (i = s[o])) : (s = e, i = s[o], t = this._items.indexOf(s), r = t == -1 || !this._itemMap.get(i)), r)
      throw new d("collection-remove-404", this);
    this._items.splice(t, 1), this._itemMap.delete(i);
    const a = this._bindToInternalToExternalMap.get(s);
    return this._bindToInternalToExternalMap.delete(s), this._bindToExternalToInternalMap.delete(a), this.fire("remove", s, t), [s, t];
  }
  /**
   * Iterable interface.
   */
  [Symbol.iterator]() {
    return this._items[Symbol.iterator]();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Te(n) {
  const e = n.next();
  return e.done ? null : e.value;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ye extends it(z()) {
  constructor() {
    super(), this._elements = /* @__PURE__ */ new Set(), this._nextEventLoopTimeout = null, this.set("isFocused", !1), this.set("focusedElement", null);
  }
  /**
   * Starts tracking the specified element.
   */
  add(e) {
    if (this._elements.has(e))
      throw new d("focustracker-add-element-already-exist", this);
    this.listenTo(e, "focus", () => this._focus(e), { useCapture: !0 }), this.listenTo(e, "blur", () => this._blur(), { useCapture: !0 }), this._elements.add(e);
  }
  /**
   * Stops tracking the specified element and stops listening on this element.
   */
  remove(e) {
    e === this.focusedElement && this._blur(), this._elements.has(e) && (this.stopListening(e), this._elements.delete(e));
  }
  /**
   * Destroys the focus tracker by:
   * - Disabling all event listeners attached to tracked elements.
   * - Removing all tracked elements that were previously added.
   */
  destroy() {
    this.stopListening();
  }
  /**
   * Stores currently focused element and set {@link #isFocused} as `true`.
   */
  _focus(e) {
    clearTimeout(this._nextEventLoopTimeout), this.focusedElement = e, this.isFocused = !0;
  }
  /**
   * Clears currently focused element and set {@link #isFocused} as `false`.
   * This method uses `setTimeout` to change order of fires `blur` and `focus` events.
   */
  _blur() {
    clearTimeout(this._nextEventLoopTimeout), this._nextEventLoopTimeout = setTimeout(() => {
      this.focusedElement = null, this.isFocused = !1;
    }, 0);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Oe {
  /**
   * Creates an instance of the keystroke handler.
   */
  constructor() {
    this._listener = new (it())();
  }
  /**
   * Starts listening for `keydown` events from a given emitter.
   */
  listenTo(e) {
    this._listener.listenTo(e, "keydown", (t, i) => {
      this._listener.fire("_keydown:" + ii(i), i);
    });
  }
  /**
   * Registers a handler for the specified keystroke.
   *
   * @param keystroke Keystroke defined in a format accepted by
   * the {@link module:utils/keyboard~parseKeystroke} function.
   * @param callback A function called with the
   * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
   * a helper function to call both `preventDefault()` and `stopPropagation()` on the underlying event.
   * @param options Additional options.
   * @param options.priority The priority of the keystroke
   * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority
   * are called in the order they were added.
   */
  set(e, t, i = {}) {
    const s = Rr(e), r = i.priority;
    this._listener.listenTo(this._listener, "_keydown:" + s, (o, a) => {
      t(a, () => {
        a.preventDefault(), a.stopPropagation(), o.stop();
      }), o.return = !0;
    }, { priority: r });
  }
  /**
   * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.
   *
   * @param keyEvtData Key event data.
   * @returns Whether the keystroke was handled.
   */
  press(e) {
    return !!this._listener.fire("_keydown:" + ii(e), e);
  }
  /**
   * Stops listening to `keydown` events from the given emitter.
   */
  stopListening(e) {
    this._listener.stopListening(e);
  }
  /**
   * Destroys the keystroke handler.
   */
  destroy() {
    this.stopListening();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function q_(n) {
  const e = /* @__PURE__ */ new Map();
  for (const t in n)
    e.set(t, n[t]);
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Xe(n) {
  return _e(n) ? new Map(n) : q_(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const G_ = 1e4;
function K_(n, e, t, i) {
  if (Math.max(e.length, n.length) > G_)
    return n.slice(0, t).concat(e).concat(n.slice(t + i, n.length));
  {
    const s = Array.from(n);
    return s.splice(t, i, ...e), s;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Ws(n, e) {
  let t;
  function i(...s) {
    i.cancel(), t = setTimeout(() => n(...s), e);
  }
  return i.cancel = () => {
    clearTimeout(t);
  }, i;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function J_(n) {
  function e(h) {
    return h.length >= 40 && h.length <= 255 ? "VALID" : "INVALID";
  }
  if (!n)
    return "INVALID";
  let t = "";
  try {
    t = atob(n);
  } catch {
    return "INVALID";
  }
  const i = t.split("-"), s = i[0], r = i[1];
  if (!r)
    return e(n);
  try {
    atob(r);
  } catch {
    try {
      if (atob(s), !atob(s).length)
        return e(n);
    } catch {
      return e(n);
    }
  }
  if (s.length < 40 || s.length > 255)
    return "INVALID";
  let o = "";
  try {
    atob(s), o = atob(r);
  } catch {
    return "INVALID";
  }
  if (o.length !== 8)
    return "INVALID";
  const a = Number(o.substring(0, 4)), l = Number(o.substring(4, 6)) - 1, c = Number(o.substring(6, 8)), u = new Date(a, l, c);
  return u < Qd || isNaN(Number(u)) ? "INVALID" : "VALID";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Z_(n) {
  return !!n && n.length == 1 && /[\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f]/.test(n);
}
function Y_(n) {
  return !!n && n.length == 1 && /[\ud800-\udbff]/.test(n);
}
function X_(n) {
  return !!n && n.length == 1 && /[\udc00-\udfff]/.test(n);
}
function Or(n, e) {
  return Y_(n.charAt(e - 1)) && X_(n.charAt(e));
}
function Mr(n, e) {
  return Z_(n.charAt(e));
}
const Q_ = e1();
function Pu(n, e) {
  const t = String(n).matchAll(Q_);
  return Array.from(t).some((i) => i.index < e && e < i.index + i[0].length);
}
function e1() {
  const n = [
    // Emoji Tag Sequence (ETS)
    /\p{Emoji}[\u{E0020}-\u{E007E}]+\u{E007F}/u,
    // Emoji Keycap Sequence
    /\p{Emoji}\u{FE0F}?\u{20E3}/u,
    // Emoji Presentation Sequence
    /\p{Emoji}\u{FE0F}/u,
    // Single-Character Emoji / Emoji Modifier Sequence
    /(?=\p{General_Category=Other_Symbol})\p{Emoji}\p{Emoji_Modifier}*/u
  ], e = /\p{Regional_Indicator}{2}/u.source, t = "(?:" + n.map((s) => s.source).join("|") + ")", i = `${e}|${t}(?:‍${t})*`;
  return new RegExp(i, "ug");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class _ extends z() {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(), this._disableStack = /* @__PURE__ */ new Set(), this.editor = e, this.set("isEnabled", !0);
  }
  /**
   * Disables the plugin.
   *
   * Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed
   * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.
   * The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.
   *
   * Disabling and enabling a plugin:
   *
   * ```ts
   * plugin.isEnabled; // -> true
   * plugin.forceDisabled( 'MyFeature' );
   * plugin.isEnabled; // -> false
   * plugin.clearForceDisabled( 'MyFeature' );
   * plugin.isEnabled; // -> true
   * ```
   *
   * Plugin disabled by multiple features:
   *
   * ```ts
   * plugin.forceDisabled( 'MyFeature' );
   * plugin.forceDisabled( 'OtherFeature' );
   * plugin.clearForceDisabled( 'MyFeature' );
   * plugin.isEnabled; // -> false
   * plugin.clearForceDisabled( 'OtherFeature' );
   * plugin.isEnabled; // -> true
   * ```
   *
   * Multiple disabling with the same identifier is redundant:
   *
   * ```ts
   * plugin.forceDisabled( 'MyFeature' );
   * plugin.forceDisabled( 'MyFeature' );
   * plugin.clearForceDisabled( 'MyFeature' );
   * plugin.isEnabled; // -> true
   * ```
   *
   * **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,
   * so the plugin might be still disabled after {@link #clearForceDisabled} was used.
   *
   * @param id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.
   */
  forceDisabled(e) {
    this._disableStack.add(e), this._disableStack.size == 1 && (this.on("set:isEnabled", la, { priority: "highest" }), this.isEnabled = !1);
  }
  /**
   * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.
   *
   * @param id Unique identifier, equal to the one passed in {@link #forceDisabled} call.
   */
  clearForceDisabled(e) {
    this._disableStack.delete(e), this._disableStack.size == 0 && (this.off("set:isEnabled", la), this.isEnabled = !0);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    this.stopListening();
  }
  /**
   * @inheritDoc
   */
  static get isContextPlugin() {
    return !1;
  }
}
function la(n) {
  n.return = !1, n.stop();
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class te extends z() {
  /**
   * Creates a new `Command` instance.
   *
   * @param editor The editor on which this command will be used.
   */
  constructor(e) {
    super(), this.editor = e, this.set("value", void 0), this.set("isEnabled", !1), this._affectsData = !0, this._isEnabledBasedOnSelection = !0, this._disableStack = /* @__PURE__ */ new Set(), this.decorate("execute"), this.listenTo(this.editor.model.document, "change", () => {
      this.refresh();
    }), this.listenTo(e, "change:isReadOnly", () => {
      this.refresh();
    }), this.on("set:isEnabled", (t) => {
      this.affectsData && (e.isReadOnly || this._isEnabledBasedOnSelection && !e.model.canEditAt(e.model.document.selection)) && (t.return = !1, t.stop());
    }, { priority: "highest" }), this.on("execute", (t) => {
      this.isEnabled || t.stop();
    }, { priority: "high" });
  }
  /**
   * A flag indicating whether a command execution changes the editor data or not.
   *
   * Commands with `affectsData` set to `false` will not be automatically disabled in
   * the {@link module:core/editor/editor~Editor#isReadOnly read-only mode} and
   * {@glink features/read-only#related-features other editor modes} with restricted user write permissions.
   *
   * **Note:** You do not have to set it for your every command. It is `true` by default.
   *
   * @default true
   */
  get affectsData() {
    return this._affectsData;
  }
  set affectsData(e) {
    this._affectsData = e;
  }
  /**
   * Refreshes the command. The command should update its {@link #isEnabled} and {@link #value} properties
   * in this method.
   *
   * This method is automatically called when
   * {@link module:engine/model/document~Document#event:change any changes are applied to the document}.
   */
  refresh() {
    this.isEnabled = !0;
  }
  /**
   * Disables the command.
   *
   * Command may be disabled by multiple features or algorithms (at once). When disabling a command, unique id should be passed
   * (e.g. the feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the command.
   * The command becomes enabled only after all features {@link #clearForceDisabled enabled it back}.
   *
   * Disabling and enabling a command:
   *
   * ```ts
   * command.isEnabled; // -> true
   * command.forceDisabled( 'MyFeature' );
   * command.isEnabled; // -> false
   * command.clearForceDisabled( 'MyFeature' );
   * command.isEnabled; // -> true
   * ```
   *
   * Command disabled by multiple features:
   *
   * ```ts
   * command.forceDisabled( 'MyFeature' );
   * command.forceDisabled( 'OtherFeature' );
   * command.clearForceDisabled( 'MyFeature' );
   * command.isEnabled; // -> false
   * command.clearForceDisabled( 'OtherFeature' );
   * command.isEnabled; // -> true
   * ```
   *
   * Multiple disabling with the same identifier is redundant:
   *
   * ```ts
   * command.forceDisabled( 'MyFeature' );
   * command.forceDisabled( 'MyFeature' );
   * command.clearForceDisabled( 'MyFeature' );
   * command.isEnabled; // -> true
   * ```
   *
   * **Note:** some commands or algorithms may have more complex logic when it comes to enabling or disabling certain commands,
   * so the command might be still disabled after {@link #clearForceDisabled} was used.
   *
   * @param id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the command.
   */
  forceDisabled(e) {
    this._disableStack.add(e), this._disableStack.size == 1 && (this.on("set:isEnabled", ca, { priority: "highest" }), this.isEnabled = !1);
  }
  /**
   * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.
   *
   * @param id Unique identifier, equal to the one passed in {@link #forceDisabled} call.
   */
  clearForceDisabled(e) {
    this._disableStack.delete(e), this._disableStack.size == 0 && (this.off("set:isEnabled", ca), this.refresh());
  }
  /**
   * Executes the command.
   *
   * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`}
   * to the command.
   *
   * The `execute()` method will automatically abort when the command is disabled ({@link #isEnabled} is `false`).
   * This behavior is implemented by a high priority listener to the {@link #event:execute} event.
   *
   * In order to see how to disable a command from "outside" see the {@link #isEnabled} documentation.
   *
   * This method may return a value, which would be forwarded all the way down to the
   * {@link module:core/editor/editor~Editor#execute `editor.execute()`}.
   *
   * @fires execute
   */
  execute(...e) {
  }
  /**
   * Destroys the command.
   */
  destroy() {
    this.stopListening();
  }
}
function ca(n) {
  n.return = !1, n.stop();
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class xu extends N() {
  /**
   * Creates an instance of the plugin collection class.
   * Allows loading and initializing plugins and their dependencies.
   * Allows providing a list of already loaded plugins. These plugins will not be destroyed along with this collection.
   *
   * @param availablePlugins Plugins (constructors) which the collection will be able to use
   * when {@link module:core/plugincollection~PluginCollection#init} is used with the plugin names (strings, instead of constructors).
   * Usually, the editor will pass its built-in plugins to the collection so they can later be
   * used in `config.plugins` or `config.removePlugins` by names.
   * @param contextPlugins A list of already initialized plugins represented by a `[ PluginConstructor, pluginInstance ]` pair.
   */
  constructor(e, t = [], i = []) {
    super(), this._plugins = /* @__PURE__ */ new Map(), this._context = e, this._availablePlugins = /* @__PURE__ */ new Map();
    for (const s of t)
      s.pluginName && this._availablePlugins.set(s.pluginName, s);
    this._contextPlugins = /* @__PURE__ */ new Map();
    for (const [s, r] of i)
      this._contextPlugins.set(s, r), this._contextPlugins.set(r, s), s.pluginName && this._availablePlugins.set(s.pluginName, s);
  }
  /**
   * Iterable interface.
   *
   * Returns `[ PluginConstructor, pluginInstance ]` pairs.
   */
  *[Symbol.iterator]() {
    for (const e of this._plugins)
      typeof e[0] == "function" && (yield e);
  }
  /**
   * Gets the plugin instance by its constructor or name.
   *
   * ```ts
   * // Check if 'Clipboard' plugin was loaded.
   * if ( editor.plugins.has( 'ClipboardPipeline' ) ) {
   * 	// Get clipboard plugin instance
   * 	const clipboard = editor.plugins.get( 'ClipboardPipeline' );
   *
   * 	this.listenTo( clipboard, 'inputTransformation', ( evt, data ) => {
   * 		// Do something on clipboard input.
   * 	} );
   * }
   * ```
   *
   * **Note**: This method will throw an error if a plugin is not loaded. Use `{@link #has editor.plugins.has()}`
   * to check if a plugin is available.
   *
   * @param key The plugin constructor or {@link module:core/plugin~PluginStaticMembers#pluginName name}.
   */
  get(e) {
    const t = this._plugins.get(e);
    if (!t) {
      let i = e;
      throw typeof e == "function" && (i = e.pluginName || e.name), new d("plugincollection-plugin-not-loaded", this._context, { plugin: i });
    }
    return t;
  }
  /**
   * Checks if a plugin is loaded.
   *
   * ```ts
   * // Check if the 'Clipboard' plugin was loaded.
   * if ( editor.plugins.has( 'ClipboardPipeline' ) ) {
   * 	// Now use the clipboard plugin instance:
   * 	const clipboard = editor.plugins.get( 'ClipboardPipeline' );
   *
   * 	// ...
   * }
   * ```
   *
   * @param key The plugin constructor or {@link module:core/plugin~PluginStaticMembers#pluginName name}.
   */
  has(e) {
    return this._plugins.has(e);
  }
  /**
   * Initializes a set of plugins and adds them to the collection.
   *
   * @param plugins An array of {@link module:core/plugin~PluginInterface plugin constructors}
   * or {@link module:core/plugin~PluginStaticMembers#pluginName plugin names}.
   * @param pluginsToRemove Names of the plugins or plugin constructors
   * that should not be loaded (despite being specified in the `plugins` array).
   * @param pluginsSubstitutions An array of {@link module:core/plugin~PluginInterface plugin constructors}
   * that will be used to replace plugins of the same names that were passed in `plugins` or that are in their dependency tree.
   * A useful option for replacing built-in plugins while creating tests (for mocking their APIs). Plugins that will be replaced
   * must follow these rules:
   *   * The new plugin must be a class.
   *   * The new plugin must be named.
   *   * Both plugins must not depend on other plugins.
   * @returns A promise which gets resolved once all plugins are loaded and available in the collection.
   */
  init(e, t = [], i = []) {
    const s = this, r = this._context;
    m(e), b(e);
    const o = e.filter((k) => !h(k, t)), a = [...p(o)];
    Me(a, i);
    const l = ke(a);
    return ge(l, "init").then(() => ge(l, "afterInit")).then(() => l);
    function c(k) {
      return typeof k == "function";
    }
    function u(k) {
      return c(k) && !!k.isContextPlugin;
    }
    function h(k, x) {
      return x.some((C) => C === k || f(k) === C || f(C) === k);
    }
    function f(k) {
      return c(k) ? k.pluginName || k.name : k;
    }
    function m(k, x = /* @__PURE__ */ new Set()) {
      k.forEach((C) => {
        c(C) && (x.has(C) || (x.add(C), C.pluginName && !s._availablePlugins.has(C.pluginName) && s._availablePlugins.set(C.pluginName, C), C.requires && m(C.requires, x)));
      });
    }
    function p(k, x = /* @__PURE__ */ new Set()) {
      return k.map((C) => c(C) ? C : s._availablePlugins.get(C)).reduce((C, K) => x.has(K) ? C : (x.add(K), K.requires && (b(K.requires, K), p(K.requires, x).forEach((pt) => C.add(pt))), C.add(K)), /* @__PURE__ */ new Set());
    }
    function b(k, x = null) {
      k.map((C) => c(C) ? C : s._availablePlugins.get(C) || C).forEach((C) => {
        E(C, x), A(C, x), ue(C, x);
      });
    }
    function E(k, x) {
      if (!c(k))
        throw x ? new d("plugincollection-soft-required", r, { missingPlugin: k, requiredBy: f(x) }) : new d("plugincollection-plugin-not-found", r, { plugin: k });
    }
    function A(k, x) {
      if (u(x) && !u(k))
        throw new d("plugincollection-context-required", r, { plugin: f(k), requiredBy: f(x) });
    }
    function ue(k, x) {
      if (x && h(k, t))
        throw new d("plugincollection-required", r, { plugin: f(k), requiredBy: f(x) });
    }
    function ke(k) {
      return k.map((x) => {
        let C = s._contextPlugins.get(x);
        return C = C || new x(r), s._add(x, C), C;
      });
    }
    function ge(k, x) {
      return k.reduce((C, K) => !K[x] || s._contextPlugins.has(K) ? C : C.then(K[x].bind(K)), Promise.resolve());
    }
    function Me(k, x) {
      for (const C of x) {
        if (typeof C != "function")
          throw new d("plugincollection-replace-plugin-invalid-type", null, { pluginItem: C });
        const K = C.pluginName;
        if (!K)
          throw new d("plugincollection-replace-plugin-missing-name", null, { pluginItem: C });
        if (C.requires && C.requires.length)
          throw new d("plugincollection-plugin-for-replacing-cannot-have-dependencies", null, { pluginName: K });
        const pt = s._availablePlugins.get(K);
        if (!pt)
          throw new d("plugincollection-plugin-for-replacing-not-exist", null, { pluginName: K });
        const co = k.indexOf(pt);
        if (co === -1) {
          if (s._contextPlugins.has(pt))
            return;
          throw new d("plugincollection-plugin-for-replacing-not-loaded", null, { pluginName: K });
        }
        if (pt.requires && pt.requires.length)
          throw new d("plugincollection-replaced-plugin-cannot-have-dependencies", null, { pluginName: K });
        k.splice(co, 1, C), s._availablePlugins.set(K, C);
      }
    }
  }
  /**
   * Destroys all loaded plugins.
   */
  destroy() {
    const e = [];
    for (const [, t] of this)
      typeof t.destroy == "function" && !this._contextPlugins.has(t) && e.push(t.destroy());
    return Promise.all(e);
  }
  /**
   * Adds the plugin to the collection. Exposed mainly for testing purposes.
   *
   * @param PluginConstructor The plugin constructor.
   * @param plugin The instance of the plugin.
   */
  _add(e, t) {
    this._plugins.set(e, t);
    const i = e.pluginName;
    if (i) {
      if (this._plugins.has(i))
        throw new d("plugincollection-plugin-name-conflict", null, { pluginName: i, plugin1: this._plugins.get(i).constructor, plugin2: e });
      this._plugins.set(i, t);
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Su {
  /**
   * Creates a context instance with a given configuration.
   *
   * Usually not to be used directly. See the static {@link module:core/context~Context.create `create()`} method.
   *
   * @param config The context configuration.
   */
  constructor(e) {
    this._contextOwner = null, this.config = new hu(e, this.constructor.defaultConfig);
    const t = this.constructor.builtinPlugins;
    this.config.define("plugins", t), this.plugins = new xu(this, t);
    const i = this.config.get("language") || {};
    this.locale = new U_({
      uiLanguage: typeof i == "string" ? i : i.ui,
      contentLanguage: this.config.get("language.content")
    }), this.t = this.locale.t, this.editors = new He();
  }
  /**
   * Loads and initializes plugins specified in the configuration.
   *
   * @returns A promise which resolves once the initialization is completed, providing an array of loaded plugins.
   */
  initPlugins() {
    const e = this.config.get("plugins") || [], t = this.config.get("substitutePlugins") || [];
    for (const i of e.concat(t)) {
      if (typeof i != "function")
        throw new d("context-initplugins-constructor-only", null, { Plugin: i });
      if (i.isContextPlugin !== !0)
        throw new d("context-initplugins-invalid-plugin", null, { Plugin: i });
    }
    return this.plugins.init(e, [], t);
  }
  /**
   * Destroys the context instance and all editors used with the context,
   * releasing all resources used by the context.
   *
   * @returns A promise that resolves once the context instance is fully destroyed.
   */
  destroy() {
    return Promise.all(Array.from(this.editors, (e) => e.destroy())).then(() => this.plugins.destroy());
  }
  /**
   * Adds a reference to the editor which is used with this context.
   *
   * When the given editor has created the context, the reference to this editor will be stored
   * as a {@link ~Context#_contextOwner}.
   *
   * This method should only be used by the editor.
   *
   * @internal
   * @param isContextOwner Stores the given editor as a context owner.
   */
  _addEditor(e, t) {
    if (this._contextOwner)
      throw new d("context-addeditor-private-context");
    this.editors.add(e), t && (this._contextOwner = e);
  }
  /**
   * Removes a reference to the editor which was used with this context.
   * When the context was created by the given editor, the context will be destroyed.
   *
   * This method should only be used by the editor.
   *
   * @internal
   * @return A promise that resolves once the editor is removed from the context or when the context was destroyed.
   */
  _removeEditor(e) {
    return this.editors.has(e) && this.editors.remove(e), this._contextOwner === e ? this.destroy() : Promise.resolve();
  }
  /**
   * Returns the context configuration which will be copied to the editors created using this context.
   *
   * The configuration returned by this method has the plugins configuration removed &mdash; plugins are shared with all editors
   * through another mechanism.
   *
   * This method should only be used by the editor.
   *
   * @internal
   * @returns Configuration as a plain object.
   */
  _getEditorConfig() {
    const e = {};
    for (const t of this.config.names())
      ["plugins", "removePlugins", "extraPlugins"].includes(t) || (e[t] = this.config.get(t));
    return e;
  }
  /**
   * Creates and initializes a new context instance.
   *
   * ```ts
   * const commonConfig = { ... }; // Configuration for all the plugins and editors.
   * const editorPlugins = [ ... ]; // Regular plugins here.
   *
   * Context
   * 	.create( {
   * 		// Only context plugins here.
   * 		plugins: [ ... ],
   *
   * 		// Configure the language for all the editors (it cannot be overwritten).
   * 		language: { ... },
   *
   * 		// Configuration for context plugins.
   * 		comments: { ... },
   * 		...
   *
   * 		// Default configuration for editor plugins.
   * 		toolbar: { ... },
   * 		image: { ... },
   * 		...
   * 	} )
   * 	.then( context => {
   * 		const promises = [];
   *
   * 		promises.push( ClassicEditor.create(
   * 			document.getElementById( 'editor1' ),
   * 			{
   * 				editorPlugins,
   * 				context
   * 			}
   * 		) );
   *
   * 		promises.push( ClassicEditor.create(
   * 			document.getElementById( 'editor2' ),
   * 			{
   * 				editorPlugins,
   * 				context,
   * 				toolbar: { ... } // You can overwrite the configuration of the context.
   * 			}
   * 		) );
   *
   * 		return Promise.all( promises );
   * 	} );
   * ```
   *
   * @param config The context configuration.
   * @returns A promise resolved once the context is ready. The promise resolves with the created context instance.
   */
  static create(e) {
    return new Promise((t) => {
      const i = new this(e);
      t(i.initPlugins().then(() => i));
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const rn = /* @__PURE__ */ new WeakMap();
function t1({ view: n, element: e, text: t, isDirectHost: i = !0, keepOnFocus: s = !1 }) {
  const r = n.document;
  rn.has(r) || (rn.set(r, /* @__PURE__ */ new Map()), r.registerPostFixer((o) => Xn(r, o)), r.on("change:isComposing", () => {
    n.change((o) => Xn(r, o));
  }, { priority: "high" })), rn.get(r).set(e, {
    text: t,
    isDirectHost: i,
    keepOnFocus: s,
    hostElement: i ? e : null
  }), n.change((o) => Xn(r, o));
}
function i1(n, e) {
  return e.hasClass("ck-placeholder") ? !1 : (n.addClass("ck-placeholder", e), !0);
}
function n1(n, e) {
  return e.hasClass("ck-placeholder") ? (n.removeClass("ck-placeholder", e), !0) : !1;
}
function s1(n, e) {
  if (!n.isAttached() || Array.from(n.getChildren()).some((o) => !o.is("uiElement")))
    return !1;
  const i = n.document, r = i.selection.anchor;
  return i.isComposing && r && r.parent === n ? !1 : e || !i.isFocused ? !0 : !!r && r.parent !== n;
}
function Xn(n, e) {
  const t = rn.get(n), i = [];
  let s = !1;
  for (const [r, o] of t)
    o.isDirectHost && (i.push(r), ua(e, r, o) && (s = !0));
  for (const [r, o] of t) {
    if (o.isDirectHost)
      continue;
    const a = r1(r);
    a && (i.includes(a) || (o.hostElement = a, ua(e, r, o) && (s = !0)));
  }
  return s;
}
function ua(n, e, t) {
  const { text: i, isDirectHost: s, hostElement: r } = t;
  let o = !1;
  return r.getAttribute("data-placeholder") !== i && (n.setAttribute("data-placeholder", i, r), o = !0), (s || e.childCount == 1) && s1(r, t.keepOnFocus) ? i1(n, r) && (o = !0) : n1(n, r) && (o = !0), o;
}
function r1(n) {
  if (n.childCount) {
    const e = n.getChild(0);
    if (e.is("element") && !e.is("uiElement") && !e.is("attributeElement"))
      return e;
  }
  return null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Mt = class {
  /* istanbul ignore next -- @preserve */
  is() {
    throw new Error("is() method is abstract");
  }
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Vt = class extends N(Mt) {
  /**
   * Creates a tree view node.
   *
   * @param document The document instance to which this node belongs.
   */
  constructor(e) {
    super(), this.document = e, this.parent = null;
  }
  /**
   * Index of the node in the parent element or null if the node has no parent.
   *
   * Accessing this property throws an error if this node's parent element does not contain it.
   * This means that view tree got broken.
   */
  get index() {
    let e;
    if (!this.parent)
      return null;
    if ((e = this.parent.getChildIndex(this)) == -1)
      throw new d("view-node-not-found-in-parent", this);
    return e;
  }
  /**
   * Node's next sibling, or `null` if it is the last child.
   */
  get nextSibling() {
    const e = this.index;
    return e !== null && this.parent.getChild(e + 1) || null;
  }
  /**
   * Node's previous sibling, or `null` if it is the first child.
   */
  get previousSibling() {
    const e = this.index;
    return e !== null && this.parent.getChild(e - 1) || null;
  }
  /**
   * Top-most ancestor of the node. If the node has no parent it is the root itself.
   */
  get root() {
    let e = this;
    for (; e.parent; )
      e = e.parent;
    return e;
  }
  /**
   * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).
   */
  isAttached() {
    return this.root.is("rootElement");
  }
  /**
   * Gets a path to the node. The path is an array containing indices of consecutive ancestors of this node,
   * beginning from {@link module:engine/view/node~Node#root root}, down to this node's index.
   *
   * ```ts
   * const abc = downcastWriter.createText( 'abc' );
   * const foo = downcastWriter.createText( 'foo' );
   * const h1 = downcastWriter.createElement( 'h1', null, downcastWriter.createText( 'header' ) );
   * const p = downcastWriter.createElement( 'p', null, [ abc, foo ] );
   * const div = downcastWriter.createElement( 'div', null, [ h1, p ] );
   * foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
   * h1.getPath(); // Returns [ 0 ].
   * div.getPath(); // Returns [].
   * ```
   *
   * @returns The path.
   */
  getPath() {
    const e = [];
    let t = this;
    for (; t.parent; )
      e.unshift(t.index), t = t.parent;
    return e;
  }
  /**
   * Returns ancestors array of this node.
   *
   * @param options Options object.
   * @param options.includeSelf When set to `true` this node will be also included in parent's array.
   * @param options.parentFirst When set to `true`, array will be sorted from node's parent to root element,
   * otherwise root element will be the first item in the array.
   * @returns Array with ancestors.
   */
  getAncestors(e = {}) {
    const t = [];
    let i = e.includeSelf ? this : this.parent;
    for (; i; )
      t[e.parentFirst ? "push" : "unshift"](i), i = i.parent;
    return t;
  }
  /**
   * Returns a {@link module:engine/view/element~Element} or {@link module:engine/view/documentfragment~DocumentFragment}
   * which is a common ancestor of both nodes.
   *
   * @param node The second node.
   * @param options Options object.
   * @param options.includeSelf When set to `true` both nodes will be considered "ancestors" too.
   * Which means that if e.g. node A is inside B, then their common ancestor will be B.
   */
  getCommonAncestor(e, t = {}) {
    const i = this.getAncestors(t), s = e.getAncestors(t);
    let r = 0;
    for (; i[r] == s[r] && i[r]; )
      r++;
    return r === 0 ? null : i[r - 1];
  }
  /**
   * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,
   * in different {@link module:engine/view/documentfragment~DocumentFragment}s).
   *
   * @param node Node to compare with.
   */
  isBefore(e) {
    if (this == e || this.root !== e.root)
      return !1;
    const t = this.getPath(), i = e.getPath(), s = ce(t, i);
    switch (s) {
      case "prefix":
        return !0;
      case "extension":
        return !1;
      default:
        return t[s] < i[s];
    }
  }
  /**
   * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,
   * in different {@link module:engine/view/documentfragment~DocumentFragment}s).
   *
   * @param node Node to compare with.
   */
  isAfter(e) {
    return this == e || this.root !== e.root ? !1 : !this.isBefore(e);
  }
  /**
   * Removes node from parent.
   *
   * @internal
   */
  _remove() {
    this.parent._removeChildren(this.index);
  }
  /**
   * @internal
   * @param type Type of the change.
   * @param node Changed node.
   * @fires change
   */
  _fireChange(e, t) {
    this.fire(`change:${e}`, t), this.parent && this.parent._fireChange(e, t);
  }
  /**
   * Custom toJSON method to solve child-parent circular dependencies.
   *
   * @returns Clone of this object with the parent property removed.
   */
  toJSON() {
    const e = ou(this);
    return delete e.parent, e;
  }
};
Vt.prototype.is = function(n) {
  return n === "node" || n === "view:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let j = class Us extends Vt {
  /**
   * Creates a tree view text node.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createText
   * @internal
   * @param document The document instance to which this text node belongs.
   * @param data The text's data.
   */
  constructor(e, t) {
    super(e), this._textData = t;
  }
  /**
   * The text content.
   */
  get data() {
    return this._textData;
  }
  /**
   * The `_data` property is controlled by a getter and a setter.
   *
   * The getter is required when using the addition assignment operator on protected property:
   *
   * ```ts
   * const foo = downcastWriter.createText( 'foo' );
   * const bar = downcastWriter.createText( 'bar' );
   *
   * foo._data += bar.data;   // executes: `foo._data = foo._data + bar.data`
   * console.log( foo.data ); // prints: 'foobar'
   * ```
   *
   * If the protected getter didn't exist, `foo._data` will return `undefined` and result of the merge will be invalid.
   *
   * The setter sets data and fires the {@link module:engine/view/node~Node#event:change:text change event}.
   *
   * @internal
   */
  get _data() {
    return this.data;
  }
  set _data(e) {
    this._fireChange("text", this), this._textData = e;
  }
  /**
   * Checks if this text node is similar to other text node.
   * Both nodes should have the same data to be considered as similar.
   *
   * @param otherNode Node to check if it is same as this node.
   */
  isSimilar(e) {
    return e instanceof Us ? this === e || this.data === e.data : !1;
  }
  /**
   * Clones this node.
   *
   * @internal
   * @returns Text node that is a clone of this node.
   */
  _clone() {
    return new Us(this.document, this.data);
  }
};
j.prototype.is = function(n) {
  return n === "$text" || n === "view:$text" || // This are legacy values kept for backward compatibility.
  n === "text" || n === "view:text" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "node" || n === "view:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let De = class extends Mt {
  /**
   * Creates a text proxy.
   *
   * @internal
   * @param textNode Text node which part is represented by this text proxy.
   * @param offsetInText Offset in {@link module:engine/view/textproxy~TextProxy#textNode text node}
   * from which the text proxy starts.
   * @param length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.
   * @constructor
   */
  constructor(e, t, i) {
    if (super(), this.textNode = e, t < 0 || t > e.data.length)
      throw new d("view-textproxy-wrong-offsetintext", this);
    if (i < 0 || t + i > e.data.length)
      throw new d("view-textproxy-wrong-length", this);
    this.data = e.data.substring(t, t + i), this.offsetInText = t;
  }
  /**
   * Offset size of this node.
   */
  get offsetSize() {
    return this.data.length;
  }
  /**
   * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/view/text~Text text node}
   * (`true`) or the whole text node (`false`).
   *
   * This is `false` when text proxy starts at the very beginning of {@link module:engine/view/textproxy~TextProxy#textNode textNode}
   * ({@link module:engine/view/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to
   * text node size.
   */
  get isPartial() {
    return this.data.length !== this.textNode.data.length;
  }
  /**
   * Parent of this text proxy, which is same as parent of text node represented by this text proxy.
   */
  get parent() {
    return this.textNode.parent;
  }
  /**
   * Root of this text proxy, which is same as root of text node represented by this text proxy.
   */
  get root() {
    return this.textNode.root;
  }
  /**
   * {@link module:engine/view/document~Document View document} that owns this text proxy, or `null` if the text proxy is inside
   * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.
   */
  get document() {
    return this.textNode.document;
  }
  /**
   * Returns ancestors array of this text proxy.
   *
   * @param options Options object.
   * @param options.includeSelf When set to `true`, textNode will be also included in parent's array.
   * @param options.parentFirst When set to `true`, array will be sorted from text proxy parent to
   * root element, otherwise root element will be the first item in the array.
   * @returns Array with ancestors.
   */
  getAncestors(e = {}) {
    const t = [];
    let i = e.includeSelf ? this.textNode : this.parent;
    for (; i !== null; )
      t[e.parentFirst ? "push" : "unshift"](i), i = i.parent;
    return t;
  }
};
De.prototype.is = function(n) {
  return n === "$textProxy" || n === "view:$textProxy" || // This are legacy values kept for backward compatibility.
  n === "textProxy" || n === "view:textProxy";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ni {
  /**
   * Creates new instance of Matcher.
   *
   * @param pattern Match patterns. See {@link module:engine/view/matcher~Matcher#add add method} for more information.
   */
  constructor(...e) {
    this._patterns = [], this.add(...e);
  }
  /**
   * Adds pattern or patterns to matcher instance.
   *
   * ```ts
   * // String.
   * matcher.add( 'div' );
   *
   * // Regular expression.
   * matcher.add( /^\w/ );
   *
   * // Single class.
   * matcher.add( {
   * 	classes: 'foobar'
   * } );
   * ```
   *
   * See {@link module:engine/view/matcher~MatcherPattern} for more examples.
   *
   * Multiple patterns can be added in one call:
   *
   * ```ts
   * matcher.add( 'div', { classes: 'foobar' } );
   * ```
   *
   * @param pattern Object describing pattern details. If string or regular expression
   * is provided it will be used to match element's name. Pattern can be also provided in a form
   * of a function - then this function will be called with each {@link module:engine/view/element~Element element} as a parameter.
   * Function's return value will be stored under `match` key of the object returned from
   * {@link module:engine/view/matcher~Matcher#match match} or {@link module:engine/view/matcher~Matcher#matchAll matchAll} methods.
   */
  add(...e) {
    for (let t of e)
      (typeof t == "string" || t instanceof RegExp) && (t = { name: t }), this._patterns.push(t);
  }
  /**
   * Matches elements for currently stored patterns. Returns match information about first found
   * {@link module:engine/view/element~Element element}, otherwise returns `null`.
   *
   * Example of returned object:
   *
   * ```ts
   * {
   * 	element: <instance of found element>,
   * 	pattern: <pattern used to match found element>,
   * 	match: {
   * 		name: true,
   * 		attributes: [ 'title', 'href' ],
   * 		classes: [ 'foo' ],
   * 		styles: [ 'color', 'position' ]
   * 	}
   * }
   * ```
   *
   * @see module:engine/view/matcher~Matcher#add
   * @see module:engine/view/matcher~Matcher#matchAll
   * @param element View element to match against stored patterns.
   */
  match(...e) {
    for (const t of e)
      for (const i of this._patterns) {
        const s = ha(t, i);
        if (s)
          return {
            element: t,
            pattern: i,
            match: s
          };
      }
    return null;
  }
  /**
   * Matches elements for currently stored patterns. Returns array of match information with all found
   * {@link module:engine/view/element~Element elements}. If no element is found - returns `null`.
   *
   * @see module:engine/view/matcher~Matcher#add
   * @see module:engine/view/matcher~Matcher#match
   * @param element View element to match against stored patterns.
   * @returns Array with match information about found elements or `null`. For more information
   * see {@link module:engine/view/matcher~Matcher#match match method} description.
   */
  matchAll(...e) {
    const t = [];
    for (const i of e)
      for (const s of this._patterns) {
        const r = ha(i, s);
        r && t.push({
          element: i,
          pattern: s,
          match: r
        });
      }
    return t.length > 0 ? t : null;
  }
  /**
   * Returns the name of the element to match if there is exactly one pattern added to the matcher instance
   * and it matches element name defined by `string` (not `RegExp`). Otherwise, returns `null`.
   *
   * @returns Element name trying to match.
   */
  getElementName() {
    if (this._patterns.length !== 1)
      return null;
    const e = this._patterns[0], t = e.name;
    return typeof e != "function" && t && !(t instanceof RegExp) ? t : null;
  }
}
function ha(n, e) {
  if (typeof e == "function")
    return e(n);
  const t = {};
  return e.name && (t.name = o1(e.name, n.name), !t.name) || e.attributes && (t.attributes = u1(e.attributes, n), !t.attributes) || e.classes && (t.classes = h1(e.classes, n), !t.classes) || e.styles && (t.styles = d1(e.styles, n), !t.styles) ? null : t;
}
function o1(n, e) {
  return n instanceof RegExp ? !!e.match(n) : n === e;
}
function Vr(n, e, t) {
  const i = a1(n), s = Array.from(e), r = [];
  if (i.forEach(([o, a]) => {
    s.forEach((l) => {
      l1(o, l) && c1(a, l, t) && r.push(l);
    });
  }), !(!i.length || r.length < i.length))
    return r;
}
function a1(n) {
  return Array.isArray(n) ? n.map((e) => de(e) ? ((e.key === void 0 || e.value === void 0) && q("matcher-pattern-missing-key-or-value", e), [e.key, e.value]) : [e, !0]) : de(n) ? Object.entries(n) : [[n, !0]];
}
function l1(n, e) {
  return n === !0 || n === e || n instanceof RegExp && e.match(n);
}
function c1(n, e, t) {
  if (n === !0)
    return !0;
  const i = t(e);
  return n === i || n instanceof RegExp && !!String(i).match(n);
}
function u1(n, e) {
  const t = new Set(e.getAttributeKeys());
  return de(n) ? (n.style !== void 0 && q("matcher-pattern-deprecated-attributes-style-key", n), n.class !== void 0 && q("matcher-pattern-deprecated-attributes-class-key", n)) : (t.delete("style"), t.delete("class")), Vr(n, t, (i) => e.getAttribute(i));
}
function h1(n, e) {
  return Vr(
    n,
    e.getClassNames(),
    /* istanbul ignore next -- @preserve */
    () => {
    }
  );
}
function d1(n, e) {
  return Vr(n, e.getStyleNames(!0), (t) => e.getStyle(t));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class f1 {
  /**
   * Creates Styles instance.
   */
  constructor(e) {
    this._styles = {}, this._styleProcessor = e;
  }
  /**
   * Returns true if style map has no styles set.
   */
  get isEmpty() {
    const e = Object.entries(this._styles);
    return !Array.from(e).length;
  }
  /**
   * Number of styles defined.
   */
  get size() {
    return this.isEmpty ? 0 : this.getStyleNames().length;
  }
  /**
   * Set styles map to a new value.
   *
   * ```ts
   * styles.setTo( 'border:1px solid blue;margin-top:1px;' );
   * ```
   */
  setTo(e) {
    this.clear();
    const t = Array.from(g1(e).entries());
    for (const [i, s] of t)
      this._styleProcessor.toNormalizedForm(i, s, this._styles);
  }
  /**
   * Checks if a given style is set.
   *
   * ```ts
   * styles.setTo( 'margin-left:1px;' );
   *
   * styles.has( 'margin-left' );    // -> true
   * styles.has( 'padding' );        // -> false
   * ```
   *
   * **Note**: This check supports normalized style names.
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * styles.setTo( 'margin:2px;' );
   *
   * styles.has( 'margin' );         // -> true
   * styles.has( 'margin-top' );     // -> true
   * styles.has( 'margin-left' );    // -> true
   *
   * styles.remove( 'margin-top' );
   *
   * styles.has( 'margin' );         // -> false
   * styles.has( 'margin-top' );     // -> false
   * styles.has( 'margin-left' );    // -> true
   * ```
   *
   * @param name Style name.
   */
  has(e) {
    if (this.isEmpty)
      return !1;
    const i = this._styleProcessor.getReducedForm(e, this._styles).find(([s]) => s === e);
    return Array.isArray(i);
  }
  set(e, t) {
    if (G(e))
      for (const [i, s] of Object.entries(e))
        this._styleProcessor.toNormalizedForm(i, s, this._styles);
    else
      this._styleProcessor.toNormalizedForm(e, t, this._styles);
  }
  /**
   * Removes given style.
   *
   * ```ts
   * styles.setTo( 'background:#f00;margin-right:2px;' );
   *
   * styles.remove( 'background' );
   *
   * styles.toString();   // -> 'margin-right:2px;'
   * ```
   *
   * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules
   * enabled style processor rules} to normalize passed values.
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * styles.setTo( 'margin:1px' );
   *
   * styles.remove( 'margin-top' );
   * styles.remove( 'margin-right' );
   *
   * styles.toString(); // -> 'margin-bottom:1px;margin-left:1px;'
   * ```
   *
   * @param name Style name.
   */
  remove(e) {
    const t = js(e);
    c_(this._styles, t), delete this._styles[e], this._cleanEmptyObjectsOnPath(t);
  }
  /**
   * Returns a normalized style object or a single value.
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * const styles = new Styles();
   * styles.setTo( 'margin:1px 2px 3em;' );
   *
   * styles.getNormalized( 'margin' );
   * // will log:
   * // {
   * //     top: '1px',
   * //     right: '2px',
   * //     bottom: '3em',
   * //     left: '2px'     // normalized value from margin shorthand
   * // }
   *
   * styles.getNormalized( 'margin-left' ); // -> '2px'
   * ```
   *
   * **Note**: This method will only return normalized styles if a style processor was defined.
   *
   * @param name Style name.
   */
  getNormalized(e) {
    return this._styleProcessor.getNormalized(e, this._styles);
  }
  /**
   * Returns a normalized style string. Styles are sorted by name.
   *
   * ```ts
   * styles.set( 'margin' , '1px' );
   * styles.set( 'background', '#f00' );
   *
   * styles.toString(); // -> 'background:#f00;margin:1px;'
   * ```
   *
   * **Note**: This method supports normalized styles if defined.
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * styles.set( 'margin' , '1px' );
   * styles.set( 'background', '#f00' );
   * styles.remove( 'margin-top' );
   * styles.remove( 'margin-right' );
   *
   * styles.toString(); // -> 'background:#f00;margin-bottom:1px;margin-left:1px;'
   * ```
   */
  toString() {
    return this.isEmpty ? "" : this._getStylesEntries().map((e) => e.join(":")).sort().join(";") + ";";
  }
  /**
   * Returns property as a value string or undefined if property is not set.
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * const styles = new Styles();
   * styles.setTo( 'margin:1px;' );
   * styles.set( 'margin-bottom', '3em' );
   *
   * styles.getAsString( 'margin' ); // -> 'margin: 1px 1px 3em;'
   * ```
   *
   * Note, however, that all sub-values must be set for the longhand property name to return a value:
   *
   * ```ts
   * const styles = new Styles();
   * styles.setTo( 'margin:1px;' );
   * styles.remove( 'margin-bottom' );
   *
   * styles.getAsString( 'margin' ); // -> undefined
   * ```
   *
   * In the above scenario, it is not possible to return a `margin` value, so `undefined` is returned.
   * Instead, you should use:
   *
   * ```ts
   * const styles = new Styles();
   * styles.setTo( 'margin:1px;' );
   * styles.remove( 'margin-bottom' );
   *
   * for ( const styleName of styles.getStyleNames() ) {
   * 	console.log( styleName, styles.getAsString( styleName ) );
   * }
   * // 'margin-top', '1px'
   * // 'margin-right', '1px'
   * // 'margin-left', '1px'
   * ```
   *
   * In general, it is recommend to iterate over style names like in the example above. This way, you will always get all
   * the currently set style values. So, if all the 4 margin values would be set
   * the for-of loop above would yield only `'margin'`, `'1px'`:
   *
   * ```ts
   * const styles = new Styles();
   * styles.setTo( 'margin:1px;' );
   *
   * for ( const styleName of styles.getStyleNames() ) {
   * 	console.log( styleName, styles.getAsString( styleName ) );
   * }
   * // 'margin', '1px'
   * ```
   *
   * **Note**: To get a normalized version of a longhand property use the {@link #getNormalized `#getNormalized()`} method.
   */
  getAsString(e) {
    if (this.isEmpty)
      return;
    if (this._styles[e] && !G(this._styles[e]))
      return this._styles[e];
    const i = this._styleProcessor.getReducedForm(e, this._styles).find(([s]) => s === e);
    if (Array.isArray(i))
      return i[1];
  }
  /**
   * Returns all style properties names as they would appear when using {@link #toString `#toString()`}.
   *
   * When `expand` is set to true and there's a shorthand style property set, it will also return all equivalent styles:
   *
   * ```ts
   * stylesMap.setTo( 'margin: 1em' )
   * ```
   *
   * will be expanded to:
   *
   * ```ts
   * [ 'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ]
   * ```
   *
   * @param expand Expand shorthand style properties and all return equivalent style representations.
   */
  getStyleNames(e = !1) {
    return this.isEmpty ? [] : e ? this._styleProcessor.getStyleNames(this._styles) : this._getStylesEntries().map(([i]) => i);
  }
  /**
   * Removes all styles.
   */
  clear() {
    this._styles = {};
  }
  /**
   * Returns normalized styles entries for further processing.
   */
  _getStylesEntries() {
    const e = [], t = Object.keys(this._styles);
    for (const i of t)
      e.push(...this._styleProcessor.getReducedForm(i, this._styles));
    return e;
  }
  /**
   * Removes empty objects upon removing an entry from internal object.
   */
  _cleanEmptyObjectsOnPath(e) {
    const t = e.split(".");
    if (!(t.length > 1))
      return;
    const s = t.splice(0, t.length - 1).join("."), r = dn(this._styles, s);
    if (!r)
      return;
    !Array.from(Object.keys(r)).length && this.remove(s);
  }
}
class m1 {
  /**
   * Creates StylesProcessor instance.
   *
   * @internal
   */
  constructor() {
    this._normalizers = /* @__PURE__ */ new Map(), this._extractors = /* @__PURE__ */ new Map(), this._reducers = /* @__PURE__ */ new Map(), this._consumables = /* @__PURE__ */ new Map();
  }
  /**
   * Parse style string value to a normalized object and appends it to styles object.
   *
   * ```ts
   * const styles = {};
   *
   * stylesProcessor.toNormalizedForm( 'margin', '1px', styles );
   *
   * // styles will consist: { margin: { top: '1px', right: '1px', bottom: '1px', left: '1px; } }
   * ```
   *
   * **Note**: To define normalizer callbacks use {@link #setNormalizer}.
   *
   * @param name Name of style property.
   * @param propertyValue Value of style property.
   * @param styles Object holding normalized styles.
   */
  toNormalizedForm(e, t, i) {
    if (G(t)) {
      Qn(i, js(e), t);
      return;
    }
    if (this._normalizers.has(e)) {
      const s = this._normalizers.get(e), { path: r, value: o } = s(t);
      Qn(i, r, o);
    } else
      Qn(i, e, t);
  }
  /**
   * Returns a normalized version of a style property.
   *
   * ```ts
   * const styles = {
   * 	margin: { top: '1px', right: '1px', bottom: '1px', left: '1px; },
   * 	background: { color: '#f00' }
   * };
   *
   * stylesProcessor.getNormalized( 'background' );
   * // will return: { color: '#f00' }
   *
   * stylesProcessor.getNormalized( 'margin-top' );
   * // will return: '1px'
   * ```
   *
   * **Note**: In some cases extracting single value requires defining an extractor callback {@link #setExtractor}.
   *
   * @param name Name of style property.
   * @param styles Object holding normalized styles.
   */
  getNormalized(e, t) {
    if (!e)
      return lu({}, t);
    if (t[e] !== void 0)
      return t[e];
    if (this._extractors.has(e)) {
      const i = this._extractors.get(e);
      if (typeof i == "string")
        return dn(t, i);
      const s = i(e, t);
      if (s)
        return s;
    }
    return dn(t, js(e));
  }
  /**
   * Returns a reduced form of style property form normalized object.
   *
   * For default margin reducer, the below code:
   *
   * ```ts
   * stylesProcessor.getReducedForm( 'margin', {
   * 	margin: { top: '1px', right: '1px', bottom: '2px', left: '1px; }
   * } );
   * ```
   *
   * will return:
   *
   * ```ts
   * [
   * 	[ 'margin', '1px 1px 2px' ]
   * ]
   * ```
   *
   * because it might be represented as a shorthand 'margin' value. However if one of margin long hand values is missing it should return:
   *
   * ```ts
   * [
   * 	[ 'margin-top', '1px' ],
   * 	[ 'margin-right', '1px' ],
   * 	[ 'margin-bottom', '2px' ]
   * 	// the 'left' value is missing - cannot use 'margin' shorthand.
   * ]
   * ```
   *
   * **Note**: To define reducer callbacks use {@link #setReducer}.
   *
   * @param name Name of style property.
   */
  getReducedForm(e, t) {
    const i = this.getNormalized(e, t);
    return i === void 0 ? [] : this._reducers.has(e) ? this._reducers.get(e)(i) : [[e, i]];
  }
  /**
   * Return all style properties. Also expand shorthand properties (e.g. `margin`, `background`) if respective extractor is available.
   *
   * @param styles Object holding normalized styles.
   */
  getStyleNames(e) {
    const t = Array.from(this._consumables.keys()).filter((s) => {
      const r = this.getNormalized(s, e);
      return r && typeof r == "object" ? Object.keys(r).length : r;
    }), i = /* @__PURE__ */ new Set([
      ...t,
      ...Object.keys(e)
    ]);
    return Array.from(i.values());
  }
  /**
   * Returns related style names.
   *
   * ```ts
   * stylesProcessor.getRelatedStyles( 'margin' );
   * // will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ];
   *
   * stylesProcessor.getRelatedStyles( 'margin-top' );
   * // will return: [ 'margin' ];
   * ```
   *
   * **Note**: To define new style relations load an existing style processor or use
   * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}.
   */
  getRelatedStyles(e) {
    return this._consumables.get(e) || [];
  }
  /**
   * Adds a normalizer method for a style property.
   *
   * A normalizer returns describing how the value should be normalized.
   *
   * For instance 'margin' style is a shorthand for four margin values:
   *
   * - 'margin-top'
   * - 'margin-right'
   * - 'margin-bottom'
   * - 'margin-left'
   *
   * and can be written in various ways if some values are equal to others. For instance `'margin: 1px 2em;'` is a shorthand for
   * `'margin-top: 1px;margin-right: 2em;margin-bottom: 1px;margin-left: 2em'`.
   *
   * A normalizer should parse various margin notations as a single object:
   *
   * ```ts
   * const styles = {
   * 	margin: {
   * 		top: '1px',
   * 		right: '2em',
   * 		bottom: '1px',
   * 		left: '2em'
   * 	}
   * };
   * ```
   *
   * Thus a normalizer for 'margin' style should return an object defining style path and value to store:
   *
   * ```ts
   * const returnValue = {
   * 	path: 'margin',
   * 	value: {
   * 		top: '1px',
   * 		right: '2em',
   * 		bottom: '1px',
   * 		left: '2em'
   * 	}
   * };
   * ```
   *
   * Additionally to fully support all margin notations there should be also defined 4 normalizers for longhand margin notations. Below
   * is an example for 'margin-top' style property normalizer:
   *
   * ```ts
   * stylesProcessor.setNormalizer( 'margin-top', valueString => {
   * 	return {
   * 		path: 'margin.top',
   * 		value: valueString
   * 	}
   * } );
   * ```
   */
  setNormalizer(e, t) {
    this._normalizers.set(e, t);
  }
  /**
   * Adds a extractor callback for a style property.
   *
   * Most normalized style values are stored as one level objects. It is assumed that `'margin-top'` style will be stored as:
   *
   * ```ts
   * const styles = {
   * 	margin: {
   * 		top: 'value'
   * 	}
   * }
   * ```
   *
   * However, some styles can have conflicting notations and thus it might be harder to extract a style value from shorthand. For instance
   * the 'border-top-style' can be defined using `'border-top:solid'`, `'border-style:solid none none none'` or by `'border:solid'`
   * shorthands. The default border styles processors stores styles as:
   *
   * ```ts
   * const styles = {
   * 	border: {
   * 		style: {
   * 			top: 'solid'
   * 		}
   * 	}
   * }
   * ```
   *
   * as it is better to modify border style independently from other values. On the other part the output of the border might be
   * desired as `border-top`, `border-left`, etc notation.
   *
   * In the above example an extractor should return a side border value that combines style, color and width:
   *
   * ```ts
   * styleProcessor.setExtractor( 'border-top', styles => {
   * 	return {
   * 		color: styles.border.color.top,
   * 		style: styles.border.style.top,
   * 		width: styles.border.width.top
   * 	}
   * } );
   * ```
   *
   * @param callbackOrPath Callback that return a requested value or path string for single values.
   */
  setExtractor(e, t) {
    this._extractors.set(e, t);
  }
  /**
   * Adds a reducer callback for a style property.
   *
   * Reducer returns a minimal notation for given style name. For longhand properties it is not required to write a reducer as
   * by default the direct value from style path is taken.
   *
   * For shorthand styles a reducer should return minimal style notation either by returning single name-value tuple or multiple tuples
   * if a shorthand cannot be used. For instance for a margin shorthand a reducer might return:
   *
   * ```ts
   * const marginShortHandTuple = [
   * 	[ 'margin', '1px 1px 2px' ]
   * ];
   * ```
   *
   * or a longhand tuples for defined values:
   *
   * ```ts
   * // Considering margin.bottom and margin.left are undefined.
   * const marginLonghandsTuples = [
   * 	[ 'margin-top', '1px' ],
   * 	[ 'margin-right', '1px' ]
   * ];
   * ```
   *
   * A reducer obtains a normalized style value:
   *
   * ```ts
   * // Simplified reducer that always outputs 4 values which are always present:
   * stylesProcessor.setReducer( 'margin', margin => {
   * 	return [
   * 		[ 'margin', `${ margin.top } ${ margin.right } ${ margin.bottom } ${ margin.left }` ]
   * 	]
   * } );
   * ```
   */
  setReducer(e, t) {
    this._reducers.set(e, t);
  }
  /**
   * Defines a style shorthand relation to other style notations.
   *
   * ```ts
   * stylesProcessor.setStyleRelation( 'margin', [
   * 	'margin-top',
   * 	'margin-right',
   * 	'margin-bottom',
   * 	'margin-left'
   * ] );
   * ```
   *
   * This enables expanding of style names for shorthands. For instance, if defined,
   * {@link module:engine/conversion/viewconsumable~ViewConsumable view consumable} items are automatically created
   * for long-hand margin style notation alongside the `'margin'` item.
   *
   * This means that when an element being converted has a style `margin`, a converter for `margin-left` will work just
   * fine since the view consumable will contain a consumable `margin-left` item (thanks to the relation) and
   * `element.getStyle( 'margin-left' )` will work as well assuming that the style processor was correctly configured.
   * However, once `margin-left` is consumed, `margin` will not be consumable anymore.
   */
  setStyleRelation(e, t) {
    this._mapStyleNames(e, t);
    for (const i of t)
      this._mapStyleNames(i, [e]);
  }
  /**
   * Set two-way binding of style names.
   */
  _mapStyleNames(e, t) {
    this._consumables.has(e) || this._consumables.set(e, []), this._consumables.get(e).push(...t);
  }
}
function g1(n) {
  let e = null, t = 0, i = 0, s = null;
  const r = /* @__PURE__ */ new Map();
  if (n === "")
    return r;
  n.charAt(n.length - 1) != ";" && (n = n + ";");
  for (let o = 0; o < n.length; o++) {
    const a = n.charAt(o);
    if (e === null)
      switch (a) {
        case ":":
          s || (s = n.substr(t, o - t), i = o + 1);
          break;
        case '"':
        case "'":
          e = a;
          break;
        case ";": {
          const l = n.substr(i, o - i);
          s && r.set(s.trim(), l.trim()), s = null, t = o + 1;
          break;
        }
      }
    else
      a === e && (e = null);
  }
  return r;
}
function js(n) {
  return n.replace("-", ".");
}
function Qn(n, e, t) {
  let i = t;
  G(t) && (i = lu({}, dn(n, e), t)), r_(n, e, i);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Se = class Iu extends Vt {
  /**
   * Creates a view element.
   *
   * Attributes can be passed in various formats:
   *
   * ```ts
   * new Element( viewDocument, 'div', { class: 'editor', contentEditable: 'true' } ); // object
   * new Element( viewDocument, 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator
   * new Element( viewDocument, 'div', mapOfAttributes ); // map
   * ```
   *
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    if (super(e), this._unsafeAttributesToRender = [], this._customProperties = /* @__PURE__ */ new Map(), this.name = t, this._attrs = p1(i), this._children = [], s && this._insertChild(0, s), this._classes = /* @__PURE__ */ new Set(), this._attrs.has("class")) {
      const r = this._attrs.get("class");
      da(this._classes, r), this._attrs.delete("class");
    }
    this._styles = new f1(this.document.stylesProcessor), this._attrs.has("style") && (this._styles.setTo(this._attrs.get("style")), this._attrs.delete("style"));
  }
  /**
   * Number of element's children.
   */
  get childCount() {
    return this._children.length;
  }
  /**
   * Is `true` if there are no nodes inside this element, `false` otherwise.
   */
  get isEmpty() {
    return this._children.length === 0;
  }
  /**
   * Gets child at the given index.
   *
   * @param index Index of child.
   * @returns Child node.
   */
  getChild(e) {
    return this._children[e];
  }
  /**
   * Gets index of the given child node. Returns `-1` if child node is not found.
   *
   * @param node Child node.
   * @returns Index of the child node.
   */
  getChildIndex(e) {
    return this._children.indexOf(e);
  }
  /**
   * Gets child nodes iterator.
   *
   * @returns Child nodes iterator.
   */
  getChildren() {
    return this._children[Symbol.iterator]();
  }
  /**
   * Returns an iterator that contains the keys for attributes. Order of inserting attributes is not preserved.
   *
   * @returns Keys for attributes.
   */
  *getAttributeKeys() {
    this._classes.size > 0 && (yield "class"), this._styles.isEmpty || (yield "style"), yield* this._attrs.keys();
  }
  /**
   * Returns iterator that iterates over this element's attributes.
   *
   * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
   * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
   */
  *getAttributes() {
    yield* this._attrs.entries(), this._classes.size > 0 && (yield ["class", this.getAttribute("class")]), this._styles.isEmpty || (yield ["style", this.getAttribute("style")]);
  }
  /**
   * Gets attribute by key. If attribute is not present - returns undefined.
   *
   * @param key Attribute key.
   * @returns Attribute value.
   */
  getAttribute(e) {
    if (e == "class")
      return this._classes.size > 0 ? [...this._classes].join(" ") : void 0;
    if (e == "style") {
      const t = this._styles.toString();
      return t == "" ? void 0 : t;
    }
    return this._attrs.get(e);
  }
  /**
   * Returns a boolean indicating whether an attribute with the specified key exists in the element.
   *
   * @param key Attribute key.
   * @returns `true` if attribute with the specified key exists in the element, `false` otherwise.
   */
  hasAttribute(e) {
    return e == "class" ? this._classes.size > 0 : e == "style" ? !this._styles.isEmpty : this._attrs.has(e);
  }
  /**
   * Checks if this element is similar to other element.
   * Both elements should have the same name and attributes to be considered as similar. Two similar elements
   * can contain different set of children nodes.
   */
  isSimilar(e) {
    if (!(e instanceof Iu))
      return !1;
    if (this === e)
      return !0;
    if (this.name != e.name || this._attrs.size !== e._attrs.size || this._classes.size !== e._classes.size || this._styles.size !== e._styles.size)
      return !1;
    for (const [t, i] of this._attrs)
      if (!e._attrs.has(t) || e._attrs.get(t) !== i)
        return !1;
    for (const t of this._classes)
      if (!e._classes.has(t))
        return !1;
    for (const t of this._styles.getStyleNames())
      if (!e._styles.has(t) || e._styles.getAsString(t) !== this._styles.getAsString(t))
        return !1;
    return !0;
  }
  /**
   * Returns true if class is present.
   * If more then one class is provided - returns true only when all classes are present.
   *
   * ```ts
   * element.hasClass( 'foo' ); // Returns true if 'foo' class is present.
   * element.hasClass( 'foo', 'bar' ); // Returns true if 'foo' and 'bar' classes are both present.
   * ```
   */
  hasClass(...e) {
    for (const t of e)
      if (!this._classes.has(t))
        return !1;
    return !0;
  }
  /**
   * Returns iterator that contains all class names.
   */
  getClassNames() {
    return this._classes.keys();
  }
  /**
   * Returns style value for the given property mae.
   * If the style does not exist `undefined` is returned.
   *
   * **Note**: This method can work with normalized style names if
   * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.
   * See {@link module:engine/view/stylesmap~StylesMap#getAsString `StylesMap#getAsString()`} for details.
   *
   * For an element with style set to `'margin:1px'`:
   *
   * ```ts
   * // Enable 'margin' shorthand processing:
   * editor.data.addStyleProcessorRules( addMarginRules );
   *
   * const element = view.change( writer => {
   * 	const element = writer.createElement();
   * 	writer.setStyle( 'margin', '1px' );
   * 	writer.setStyle( 'margin-bottom', '3em' );
   *
   * 	return element;
   * } );
   *
   * element.getStyle( 'margin' ); // -> 'margin: 1px 1px 3em;'
   * ```
   */
  getStyle(e) {
    return this._styles.getAsString(e);
  }
  /**
   * Returns a normalized style object or single style value.
   *
   * For an element with style set to: margin:1px 2px 3em;
   *
   * ```ts
   * element.getNormalizedStyle( 'margin' ) );
   * ```
   *
   * will return:
   *
   * ```ts
   * {
   * 	top: '1px',
   * 	right: '2px',
   * 	bottom: '3em',
   * 	left: '2px'    // a normalized value from margin shorthand
   * }
   * ```
   *
   * and reading for single style value:
   *
   * ```ts
   * styles.getNormalizedStyle( 'margin-left' );
   * ```
   *
   * Will return a `2px` string.
   *
   * **Note**: This method will return normalized values only if
   * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.
   * See {@link module:engine/view/stylesmap~StylesMap#getNormalized `StylesMap#getNormalized()`} for details.
   *
   * @param property Name of CSS property
   */
  getNormalizedStyle(e) {
    return this._styles.getNormalized(e);
  }
  /**
   * Returns iterator that contains all style names.
   *
   * @param expand Expand shorthand style properties and return all equivalent style representations.
   */
  getStyleNames(e) {
    return this._styles.getStyleNames(e);
  }
  /**
   * Returns true if style keys are present.
   * If more then one style property is provided - returns true only when all properties are present.
   *
   * ```ts
   * element.hasStyle( 'color' ); // Returns true if 'border-top' style is present.
   * element.hasStyle( 'color', 'border-top' ); // Returns true if 'color' and 'border-top' styles are both present.
   * ```
   */
  hasStyle(...e) {
    for (const t of e)
      if (!this._styles.has(t))
        return !1;
    return !0;
  }
  /**
   * Returns ancestor element that match specified pattern.
   * Provided patterns should be compatible with {@link module:engine/view/matcher~Matcher Matcher} as it is used internally.
   *
   * @see module:engine/view/matcher~Matcher
   * @param patterns Patterns used to match correct ancestor. See {@link module:engine/view/matcher~Matcher}.
   * @returns Found element or `null` if no matching ancestor was found.
   */
  findAncestor(...e) {
    const t = new ni(...e);
    let i = this.parent;
    for (; i && !i.is("documentFragment"); ) {
      if (t.match(i))
        return i;
      i = i.parent;
    }
    return null;
  }
  /**
   * Returns the custom property value for the given key.
   */
  getCustomProperty(e) {
    return this._customProperties.get(e);
  }
  /**
   * Returns an iterator which iterates over this element's custom properties.
   * Iterator provides `[ key, value ]` pairs for each stored property.
   */
  *getCustomProperties() {
    yield* this._customProperties.entries();
  }
  /**
   * Returns identity string based on element's name, styles, classes and other attributes.
   * Two elements that {@link #isSimilar are similar} will have same identity string.
   * It has the following format:
   *
   * ```ts
   * 'name class="class1,class2" style="style1:value1;style2:value2" attr1="val1" attr2="val2"'
   * ```
   *
   * For example:
   *
   * ```ts
   * const element = writer.createContainerElement( 'foo', {
   * 	banana: '10',
   * 	apple: '20',
   * 	style: 'color: red; border-color: white;',
   * 	class: 'baz'
   * } );
   *
   * // returns 'foo class="baz" style="border-color:white;color:red" apple="20" banana="10"'
   * element.getIdentity();
   * ```
   *
   * **Note**: Classes, styles and other attributes are sorted alphabetically.
   */
  getIdentity() {
    const e = Array.from(this._classes).sort().join(","), t = this._styles.toString(), i = Array.from(this._attrs).map((s) => `${s[0]}="${s[1]}"`).sort().join(" ");
    return this.name + (e == "" ? "" : ` class="${e}"`) + (t ? ` style="${t}"` : "") + (i == "" ? "" : ` ${i}`);
  }
  /**
   * Decides whether an unsafe attribute is whitelisted and should be rendered in the editing pipeline even though filtering mechanisms
   * like {@link module:engine/view/domconverter~DomConverter#shouldRenderAttribute} say it should not.
   *
   * Unsafe attribute names can be specified when creating an element via {@link module:engine/view/downcastwriter~DowncastWriter}.
   *
   * @param attributeName The name of the attribute to be checked.
   */
  shouldRenderUnsafeAttribute(e) {
    return this._unsafeAttributesToRender.includes(e);
  }
  /**
   * Clones provided element.
   *
   * @internal
   * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
   * element will be cloned without any children.
   * @returns Clone of this element.
   */
  _clone(e = !1) {
    const t = [];
    if (e)
      for (const s of this.getChildren())
        t.push(s._clone(e));
    const i = new this.constructor(this.document, this.name, this._attrs, t);
    return i._classes = new Set(this._classes), i._styles.set(this._styles.getNormalized()), i._customProperties = new Map(this._customProperties), i.getFillerOffset = this.getFillerOffset, i._unsafeAttributesToRender = this._unsafeAttributesToRender, i;
  }
  /**
   * {@link module:engine/view/element~Element#_insertChild Insert} a child node or a list of child nodes at the end of this node
   * and sets the parent of these nodes to this element.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#insert
   * @internal
   * @param items Items to be inserted.
   * @fires change
   * @returns Number of appended nodes.
   */
  _appendChild(e) {
    return this._insertChild(this.childCount, e);
  }
  /**
   * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
   * this element.
   *
   * @internal
   * @see module:engine/view/downcastwriter~DowncastWriter#insert
   * @param index Position where nodes should be inserted.
   * @param items Items to be inserted.
   * @fires change
   * @returns Number of inserted nodes.
   */
  _insertChild(e, t) {
    this._fireChange("children", this);
    let i = 0;
    const s = w1(this.document, t);
    for (const r of s)
      r.parent !== null && r._remove(), r.parent = this, r.document = this.document, this._children.splice(e, 0, r), e++, i++;
    return i;
  }
  /**
   * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#remove
   * @internal
   * @param index Number of the first node to remove.
   * @param howMany Number of nodes to remove.
   * @fires change
   * @returns The array of removed nodes.
   */
  _removeChildren(e, t = 1) {
    this._fireChange("children", this);
    for (let i = e; i < e + t; i++)
      this._children[i].parent = null;
    return this._children.splice(e, t);
  }
  /**
   * Adds or overwrite attribute with a specified key and value.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#setAttribute
   * @internal
   * @param key Attribute key.
   * @param value Attribute value.
   * @fires change
   */
  _setAttribute(e, t) {
    const i = String(t);
    this._fireChange("attributes", this), e == "class" ? da(this._classes, i) : e == "style" ? this._styles.setTo(i) : this._attrs.set(e, i);
  }
  /**
   * Removes attribute from the element.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#removeAttribute
   * @internal
   * @param key Attribute key.
   * @returns Returns true if an attribute existed and has been removed.
   * @fires change
   */
  _removeAttribute(e) {
    return this._fireChange("attributes", this), e == "class" ? this._classes.size > 0 ? (this._classes.clear(), !0) : !1 : e == "style" ? this._styles.isEmpty ? !1 : (this._styles.clear(), !0) : this._attrs.delete(e);
  }
  /**
   * Adds specified class.
   *
   * ```ts
   * element._addClass( 'foo' ); // Adds 'foo' class.
   * element._addClass( [ 'foo', 'bar' ] ); // Adds 'foo' and 'bar' classes.
   * ```
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#addClass
   * @internal
   * @fires change
   */
  _addClass(e) {
    this._fireChange("attributes", this);
    for (const t of X(e))
      this._classes.add(t);
  }
  /**
   * Removes specified class.
   *
   * ```ts
   * element._removeClass( 'foo' );  // Removes 'foo' class.
   * element._removeClass( [ 'foo', 'bar' ] ); // Removes both 'foo' and 'bar' classes.
   * ```
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#removeClass
   * @internal
   * @fires change
   */
  _removeClass(e) {
    this._fireChange("attributes", this);
    for (const t of X(e))
      this._classes.delete(t);
  }
  _setStyle(e, t) {
    this._fireChange("attributes", this), typeof e != "string" ? this._styles.set(e) : this._styles.set(e, t);
  }
  /**
   * Removes specified style.
   *
   * ```ts
   * element._removeStyle( 'color' );  // Removes 'color' style.
   * element._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.
   * ```
   *
   * **Note**: This method can work with normalized style names if
   * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.
   * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#removeStyle
   * @internal
   * @fires change
   */
  _removeStyle(e) {
    this._fireChange("attributes", this);
    for (const t of X(e))
      this._styles.remove(t);
  }
  /**
   * Sets a custom property. Unlike attributes, custom properties are not rendered to the DOM,
   * so they can be used to add special data to elements.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty
   * @internal
   */
  _setCustomProperty(e, t) {
    this._customProperties.set(e, t);
  }
  /**
   * Removes the custom property stored under the given key.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty
   * @internal
   * @returns Returns true if property was removed.
   */
  _removeCustomProperty(e) {
    return this._customProperties.delete(e);
  }
};
Se.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "element" || n === "view:element") : n === "element" || n === "view:element" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "node" || n === "view:node";
};
function p1(n) {
  const e = Xe(n);
  for (const [t, i] of e)
    i === null ? e.delete(t) : typeof i != "string" && e.set(t, String(i));
  return e;
}
function da(n, e) {
  const t = e.split(/\s+/);
  n.clear(), t.forEach((i) => n.add(i));
}
function w1(n, e) {
  return typeof e == "string" ? [new j(n, e)] : (_e(e) || (e = [e]), Array.from(e).map((t) => typeof t == "string" ? new j(n, t) : t instanceof De ? new j(n, t.data) : t));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ri extends Se {
  /**
   * Creates a container element.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement
   * @see module:engine/view/element~Element
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this.getFillerOffset = b1;
  }
}
Ri.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "containerElement" || n === "view:containerElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element") : n === "containerElement" || n === "view:containerElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
function b1() {
  const n = [...this.getChildren()], e = n[this.childCount - 1];
  if (e && e.is("element", "br"))
    return this.childCount;
  for (const t of n)
    if (!t.is("uiElement"))
      return null;
  return this.childCount;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Fn extends z(Ri) {
  /**
   * Creates an editable element.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this.set("isReadOnly", !1), this.set("isFocused", !1), this.bind("isReadOnly").to(e), this.bind("isFocused").to(e, "isFocused", (r) => r && e.selection.editableElement == this), this.listenTo(e.selection, "change", () => {
      this.isFocused = e.isFocused && e.selection.editableElement == this;
    });
  }
  destroy() {
    this.stopListening();
  }
}
Fn.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "editableElement" || n === "view:editableElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "containerElement" || n === "view:containerElement" || n === "element" || n === "view:element") : n === "editableElement" || n === "view:editableElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "containerElement" || n === "view:containerElement" || n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const fa = Symbol("rootName");
class Ru extends Fn {
  /**
   * Creates root editable element.
   *
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   */
  constructor(e, t) {
    super(e, t), this.rootName = "main";
  }
  /**
   * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no
   * other name is set, `main` name is used.
   *
   * @readonly
   */
  get rootName() {
    return this.getCustomProperty(fa);
  }
  set rootName(e) {
    this._setCustomProperty(fa, e);
  }
  /**
   * Overrides old element name and sets new one.
   * This is needed because view roots are created before they are attached to the DOM.
   * The name of the root element is temporary at this stage. It has to be changed when the
   * view root element is attached to the DOM element.
   *
   * @internal
   * @param name The new name of element.
   */
  set _name(e) {
    this.name = e;
  }
}
Ru.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "rootElement" || n === "view:rootElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "editableElement" || n === "view:editableElement" || n === "containerElement" || n === "view:containerElement" || n === "element" || n === "view:element") : n === "rootElement" || n === "view:rootElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "editableElement" || n === "view:editableElement" || n === "containerElement" || n === "view:containerElement" || n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Ct = class {
  /**
   * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.
   *
   * @param options Object with configuration.
   */
  constructor(e = {}) {
    if (!e.boundaries && !e.startPosition)
      throw new d("view-tree-walker-no-start-position", null);
    if (e.direction && e.direction != "forward" && e.direction != "backward")
      throw new d("view-tree-walker-unknown-direction", e.startPosition, { direction: e.direction });
    this.boundaries = e.boundaries || null, e.startPosition ? this._position = v._createAt(e.startPosition) : this._position = v._createAt(e.boundaries[e.direction == "backward" ? "end" : "start"]), this.direction = e.direction || "forward", this.singleCharacters = !!e.singleCharacters, this.shallow = !!e.shallow, this.ignoreElementEnd = !!e.ignoreElementEnd, this._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null, this._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;
  }
  /**
   * Iterable interface.
   */
  [Symbol.iterator]() {
    return this;
  }
  /**
   * Iterator position. If start position is not defined then position depends on {@link #direction}. If direction is
   * `'forward'` position starts form the beginning, when direction is `'backward'` position starts from the end.
   */
  get position() {
    return this._position;
  }
  /**
   * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.
   *
   * For example:
   *
   * ```ts
   * walker.skip( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>
   * walker.skip( value => true ); // Move the position to the end: <p>{}foo</p> -> <p>foo</p>[]
   * walker.skip( value => false ); // Do not move the position.
   * ```
   *
   * @param skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should
   * return `true` if the value should be skipped or `false` if not.
   */
  skip(e) {
    let t, i;
    do
      i = this.position, t = this.next();
    while (!t.done && e(t.value));
    t.done || (this._position = i);
  }
  /**
   * Gets the next tree walker's value.
   *
   * @returns Object implementing iterator interface, returning
   * information about taken step.
   */
  next() {
    return this.direction == "forward" ? this._next() : this._previous();
  }
  /**
   * Makes a step forward in view. Moves the {@link #position} to the next position and returns the encountered value.
   */
  _next() {
    let e = this.position.clone();
    const t = this.position, i = e.parent;
    if (i.parent === null && e.offset === i.childCount)
      return { done: !0, value: void 0 };
    if (i === this._boundaryEndParent && e.offset == this.boundaries.end.offset)
      return { done: !0, value: void 0 };
    let s;
    if (i instanceof j) {
      if (e.isAtEnd)
        return this._position = v._createAfter(i), this._next();
      s = i.data[e.offset];
    } else
      s = i.getChild(e.offset);
    if (s instanceof Se) {
      if (!this.shallow)
        e = new v(s, 0);
      else {
        if (this.boundaries && this.boundaries.end.isBefore(e))
          return { done: !0, value: void 0 };
        e.offset++;
      }
      return this._position = e, this._formatReturnValue("elementStart", s, t, e, 1);
    }
    if (s instanceof j) {
      if (this.singleCharacters)
        return e = new v(s, 0), this._position = e, this._next();
      let r = s.data.length, o;
      return s == this._boundaryEndParent ? (r = this.boundaries.end.offset, o = new De(s, 0, r), e = v._createAfter(o)) : (o = new De(s, 0, s.data.length), e.offset++), this._position = e, this._formatReturnValue("text", o, t, e, r);
    }
    if (typeof s == "string") {
      let r;
      this.singleCharacters ? r = 1 : r = (i === this._boundaryEndParent ? this.boundaries.end.offset : i.data.length) - e.offset;
      const o = new De(i, e.offset, r);
      return e.offset += r, this._position = e, this._formatReturnValue("text", o, t, e, r);
    }
    return e = v._createAfter(i), this._position = e, this.ignoreElementEnd ? this._next() : this._formatReturnValue("elementEnd", i, t, e);
  }
  /**
   * Makes a step backward in view. Moves the {@link #position} to the previous position and returns the encountered value.
   */
  _previous() {
    let e = this.position.clone();
    const t = this.position, i = e.parent;
    if (i.parent === null && e.offset === 0)
      return { done: !0, value: void 0 };
    if (i == this._boundaryStartParent && e.offset == this.boundaries.start.offset)
      return { done: !0, value: void 0 };
    let s;
    if (i instanceof j) {
      if (e.isAtStart)
        return this._position = v._createBefore(i), this._previous();
      s = i.data[e.offset - 1];
    } else
      s = i.getChild(e.offset - 1);
    if (s instanceof Se)
      return this.shallow ? (e.offset--, this._position = e, this._formatReturnValue("elementStart", s, t, e, 1)) : (e = new v(s, s.childCount), this._position = e, this.ignoreElementEnd ? this._previous() : this._formatReturnValue("elementEnd", s, t, e));
    if (s instanceof j) {
      if (this.singleCharacters)
        return e = new v(s, s.data.length), this._position = e, this._previous();
      let r = s.data.length, o;
      if (s == this._boundaryStartParent) {
        const a = this.boundaries.start.offset;
        o = new De(s, a, s.data.length - a), r = o.data.length, e = v._createBefore(o);
      } else
        o = new De(s, 0, s.data.length), e.offset--;
      return this._position = e, this._formatReturnValue("text", o, t, e, r);
    }
    if (typeof s == "string") {
      let r;
      if (this.singleCharacters)
        r = 1;
      else {
        const a = i === this._boundaryStartParent ? this.boundaries.start.offset : 0;
        r = e.offset - a;
      }
      e.offset -= r;
      const o = new De(i, e.offset, r);
      return this._position = e, this._formatReturnValue("text", o, t, e, r);
    }
    return e = v._createBefore(i), this._position = e, this._formatReturnValue("elementStart", i, t, e, 1);
  }
  /**
   * Format returned data and adjust `previousPosition` and `nextPosition` if reach the bound of the {@link module:engine/view/text~Text}.
   *
   * @param type Type of step.
   * @param item Item between old and new position.
   * @param previousPosition Previous position of iterator.
   * @param nextPosition Next position of iterator.
   * @param length Length of the item.
   */
  _formatReturnValue(e, t, i, s, r) {
    return t instanceof De && (t.offsetInText + t.data.length == t.textNode.data.length && (this.direction == "forward" && !(this.boundaries && this.boundaries.end.isEqual(this.position)) ? (s = v._createAfter(t.textNode), this._position = s) : i = v._createAfter(t.textNode)), t.offsetInText === 0 && (this.direction == "backward" && !(this.boundaries && this.boundaries.start.isEqual(this.position)) ? (s = v._createBefore(t.textNode), this._position = s) : i = v._createBefore(t.textNode))), {
      done: !1,
      value: {
        type: e,
        item: t,
        previousPosition: i,
        nextPosition: s,
        length: r
      }
    };
  }
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let v = class je extends Mt {
  /**
   * Creates a position.
   *
   * @param parent Position parent.
   * @param offset Position offset.
   */
  constructor(e, t) {
    super(), this.parent = e, this.offset = t;
  }
  /**
   * Node directly after the position. Equals `null` when there is no node after position or position is located
   * inside text node.
   */
  get nodeAfter() {
    return this.parent.is("$text") ? null : this.parent.getChild(this.offset) || null;
  }
  /**
   * Node directly before the position. Equals `null` when there is no node before position or position is located
   * inside text node.
   */
  get nodeBefore() {
    return this.parent.is("$text") ? null : this.parent.getChild(this.offset - 1) || null;
  }
  /**
   * Is `true` if position is at the beginning of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.
   */
  get isAtStart() {
    return this.offset === 0;
  }
  /**
   * Is `true` if position is at the end of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.
   */
  get isAtEnd() {
    const e = this.parent.is("$text") ? this.parent.data.length : this.parent.childCount;
    return this.offset === e;
  }
  /**
   * Position's root, that is the root of the position's parent element.
   */
  get root() {
    return this.parent.root;
  }
  /**
   * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this position, or `null` if
   * position is not inside an editable element.
   */
  get editableElement() {
    let e = this.parent;
    for (; !(e instanceof Fn); )
      if (e.parent)
        e = e.parent;
      else
        return null;
    return e;
  }
  /**
   * Returns a new instance of Position with offset incremented by `shift` value.
   *
   * @param shift How position offset should get changed. Accepts negative values.
   * @returns Shifted position.
   */
  getShiftedBy(e) {
    const t = je._createAt(this), i = t.offset + e;
    return t.offset = i < 0 ? 0 : i, t;
  }
  /**
   * Gets the farthest position which matches the callback using
   * {@link module:engine/view/treewalker~TreeWalker TreeWalker}.
   *
   * For example:
   *
   * ```ts
   * getLastMatchingPosition( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>
   * getLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } ); // <p>foo[]</p> -> <p>{}foo</p>
   * getLastMatchingPosition( value => false ); // Do not move the position.
   * ```
   *
   * @param skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should
   * return `true` if the value should be skipped or `false` if not.
   * @param options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.
   * @returns The position after the last item which matches the `skip` callback test.
   */
  getLastMatchingPosition(e, t = {}) {
    t.startPosition = this;
    const i = new Ct(t);
    return i.skip(e), i.position;
  }
  /**
   * Returns ancestors array of this position, that is this position's parent and it's ancestors.
   *
   * @returns Array with ancestors.
   */
  getAncestors() {
    return this.parent.is("documentFragment") ? [this.parent] : this.parent.getAncestors({ includeSelf: !0 });
  }
  /**
   * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}
   * which is a common ancestor of both positions.
   */
  getCommonAncestor(e) {
    const t = this.getAncestors(), i = e.getAncestors();
    let s = 0;
    for (; t[s] == i[s] && t[s]; )
      s++;
    return s === 0 ? null : t[s - 1];
  }
  /**
   * Checks whether this position equals given position.
   *
   * @param otherPosition Position to compare with.
   * @returns True if positions are same.
   */
  isEqual(e) {
    return this.parent == e.parent && this.offset == e.offset;
  }
  /**
   * Checks whether this position is located before given position. When method returns `false` it does not mean that
   * this position is after give one. Two positions may be located inside separate roots and in that situation this
   * method will still return `false`.
   *
   * @see module:engine/view/position~Position#isAfter
   * @see module:engine/view/position~Position#compareWith
   * @param otherPosition Position to compare with.
   * @returns Returns `true` if this position is before given position.
   */
  isBefore(e) {
    return this.compareWith(e) == "before";
  }
  /**
   * Checks whether this position is located after given position. When method returns `false` it does not mean that
   * this position is before give one. Two positions may be located inside separate roots and in that situation this
   * method will still return `false`.
   *
   * @see module:engine/view/position~Position#isBefore
   * @see module:engine/view/position~Position#compareWith
   * @param otherPosition Position to compare with.
   * @returns Returns `true` if this position is after given position.
   */
  isAfter(e) {
    return this.compareWith(e) == "after";
  }
  /**
   * Checks whether this position is before, after or in same position that other position. Two positions may be also
   * different when they are located in separate roots.
   *
   * @param otherPosition Position to compare with.
   */
  compareWith(e) {
    if (this.root !== e.root)
      return "different";
    if (this.isEqual(e))
      return "same";
    const t = this.parent.is("node") ? this.parent.getPath() : [], i = e.parent.is("node") ? e.parent.getPath() : [];
    t.push(this.offset), i.push(e.offset);
    const s = ce(t, i);
    switch (s) {
      case "prefix":
        return "before";
      case "extension":
        return "after";
      default:
        return t[s] < i[s] ? "before" : "after";
    }
  }
  /**
   * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.
   *
   * @param options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}
   */
  getWalker(e = {}) {
    return e.startPosition = this, new Ct(e);
  }
  /**
   * Clones this position.
   */
  clone() {
    return new je(this.parent, this.offset);
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/view/position~Position position},
   * * parent element and offset (offset defaults to `0`),
   * * parent element and `'end'` (sets position at the end of that element),
   * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
   *
   * This method is a shortcut to other constructors such as:
   *
   * * {@link module:engine/view/position~Position._createBefore},
   * * {@link module:engine/view/position~Position._createAfter}.
   *
   * @internal
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/view/item~Item view item}.
   */
  static _createAt(e, t) {
    if (e instanceof je)
      return new this(e.parent, e.offset);
    {
      const i = e;
      if (t == "end")
        t = i.is("$text") ? i.data.length : i.childCount;
      else {
        if (t == "before")
          return this._createBefore(i);
        if (t == "after")
          return this._createAfter(i);
        if (t !== 0 && !t)
          throw new d("view-createpositionat-offset-required", i);
      }
      return new je(i, t);
    }
  }
  /**
   * Creates a new position after given view item.
   *
   * @internal
   * @param item View item after which the position should be located.
   */
  static _createAfter(e) {
    if (e.is("$textProxy"))
      return new je(e.textNode, e.offsetInText + e.data.length);
    if (!e.parent)
      throw new d("view-position-after-root", e, { root: e });
    return new je(e.parent, e.index + 1);
  }
  /**
   * Creates a new position before given view item.
   *
   * @internal
   * @param item View item before which the position should be located.
   */
  static _createBefore(e) {
    if (e.is("$textProxy"))
      return new je(e.textNode, e.offsetInText);
    if (!e.parent)
      throw new d("view-position-before-root", e, { root: e });
    return new je(e.parent, e.index);
  }
};
v.prototype.is = function(n) {
  return n === "position" || n === "view:position";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let P = class st extends Mt {
  /**
   * Creates a range spanning from `start` position to `end` position.
   *
   * **Note:** Constructor creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
   *
   * @param start Start position.
   * @param end End position. If not set, range will be collapsed at the `start` position.
   */
  constructor(e, t = null) {
    super(), this.start = e.clone(), this.end = t ? t.clone() : e.clone();
  }
  /**
   * Iterable interface.
   *
   * Iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns
   * them together with additional information like length or {@link module:engine/view/position~Position positions},
   * grouped as {@link module:engine/view/treewalker~TreeWalkerValue}.
   *
   * This iterator uses {@link module:engine/view/treewalker~TreeWalker TreeWalker} with `boundaries` set to this range and
   * `ignoreElementEnd` option
   * set to `true`.
   */
  *[Symbol.iterator]() {
    yield* new Ct({ boundaries: this, ignoreElementEnd: !0 });
  }
  /**
   * Returns whether the range is collapsed, that is it start and end positions are equal.
   */
  get isCollapsed() {
    return this.start.isEqual(this.end);
  }
  /**
   * Returns whether this range is flat, that is if {@link module:engine/view/range~Range#start start} position and
   * {@link module:engine/view/range~Range#end end} position are in the same {@link module:engine/view/position~Position#parent parent}.
   */
  get isFlat() {
    return this.start.parent === this.end.parent;
  }
  /**
   * Range root element.
   */
  get root() {
    return this.start.root;
  }
  /**
   * Creates a maximal range that has the same content as this range but is expanded in both ways (at the beginning
   * and at the end).
   *
   * For example:
   *
   * ```html
   * <p>Foo</p><p><b>{Bar}</b></p> -> <p>Foo</p>[<p><b>Bar</b>]</p>
   * <p><b>foo</b>{bar}<span></span></p> -> <p><b>foo[</b>bar<span></span>]</p>
   * ```
   *
   * Note that in the sample above:
   *
   * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},
   * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},
   * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.
   *
   * @returns Enlarged range.
   */
  getEnlarged() {
    let e = this.start.getLastMatchingPosition(Gi, { direction: "backward" }), t = this.end.getLastMatchingPosition(Gi);
    return e.parent.is("$text") && e.isAtStart && (e = v._createBefore(e.parent)), t.parent.is("$text") && t.isAtEnd && (t = v._createAfter(t.parent)), new st(e, t);
  }
  /**
   * Creates a minimum range that has the same content as this range but is trimmed in both ways (at the beginning
   * and at the end).
   *
   * For example:
   *
   * ```html
   * <p>Foo</p>[<p><b>Bar</b>]</p> -> <p>Foo</p><p><b>{Bar}</b></p>
   * <p><b>foo[</b>bar<span></span>]</p> -> <p><b>foo</b>{bar}<span></span></p>
   * ```
   *
   * Note that in the sample above:
   *
   * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},
   * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},
   * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.
   *
   * @returns Shrunk range.
   */
  getTrimmed() {
    let e = this.start.getLastMatchingPosition(Gi);
    if (e.isAfter(this.end) || e.isEqual(this.end))
      return new st(e, e);
    let t = this.end.getLastMatchingPosition(Gi, { direction: "backward" });
    const i = e.nodeAfter, s = t.nodeBefore;
    return i && i.is("$text") && (e = new v(i, 0)), s && s.is("$text") && (t = new v(s, s.data.length)), new st(e, t);
  }
  /**
   * Two ranges are equal if their start and end positions are equal.
   *
   * @param otherRange Range to compare with.
   * @returns `true` if ranges are equal, `false` otherwise
   */
  isEqual(e) {
    return this == e || this.start.isEqual(e.start) && this.end.isEqual(e.end);
  }
  /**
   * Checks whether this range contains given {@link module:engine/view/position~Position position}.
   *
   * @param position Position to check.
   * @returns `true` if given {@link module:engine/view/position~Position position} is contained in this range, `false` otherwise.
   */
  containsPosition(e) {
    return e.isAfter(this.start) && e.isBefore(this.end);
  }
  /**
   * Checks whether this range contains given {@link module:engine/view/range~Range range}.
   *
   * @param otherRange Range to check.
   * @param loose Whether the check is loose or strict. If the check is strict (`false`), compared range cannot
   * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or
   * even be equal to this range. Note that collapsed ranges are always compared in strict mode.
   * @returns `true` if given {@link module:engine/view/range~Range range} boundaries are contained by this range, `false`
   * otherwise.
   */
  containsRange(e, t = !1) {
    e.isCollapsed && (t = !1);
    const i = this.containsPosition(e.start) || t && this.start.isEqual(e.start), s = this.containsPosition(e.end) || t && this.end.isEqual(e.end);
    return i && s;
  }
  /**
   * Computes which part(s) of this {@link module:engine/view/range~Range range} is not a part of given
   * {@link module:engine/view/range~Range range}.
   * Returned array contains zero, one or two {@link module:engine/view/range~Range ranges}.
   *
   * Examples:
   *
   * ```ts
   * let foo = downcastWriter.createText( 'foo' );
   * let img = downcastWriter.createContainerElement( 'img' );
   * let bar = downcastWriter.createText( 'bar' );
   * let p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );
   *
   * let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range.
   * let otherRange = view.createRange( // "oo", img, "ba" are in range.
   * 	view.createPositionAt( foo, 1 ),
   * 	view.createPositionAt( bar, 2 )
   * );
   * let transformed = range.getDifference( otherRange );
   * // transformed array has no ranges because `otherRange` contains `range`
   *
   * otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // "oo", img are in range.
   * transformed = range.getDifference( otherRange );
   * // transformed array has one range: from ( p, 2 ) to ( bar, 1 )
   *
   * otherRange = view.createRange( view.createPositionAt( p, 1 ), view.createPositionAt( p, 2 ) ); // img is in range.
   * transformed = range.getDifference( otherRange );
   * // transformed array has two ranges: from ( foo, 1 ) to ( p, 1 ) and from ( p, 2 ) to ( bar, 1 )
   * ```
   *
   * @param otherRange Range to differentiate against.
   * @returns The difference between ranges.
   */
  getDifference(e) {
    const t = [];
    return this.isIntersecting(e) ? (this.containsPosition(e.start) && t.push(new st(this.start, e.start)), this.containsPosition(e.end) && t.push(new st(e.end, this.end))) : t.push(this.clone()), t;
  }
  /**
   * Returns an intersection of this {@link module:engine/view/range~Range range} and given {@link module:engine/view/range~Range range}.
   * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.
   *
   * Examples:
   *
   * ```ts
   * let foo = downcastWriter.createText( 'foo' );
   * let img = downcastWriter.createContainerElement( 'img' );
   * let bar = downcastWriter.createText( 'bar' );
   * let p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );
   *
   * let range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // "o", img, "b" are in range.
   * let otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // "oo", img are in range.
   * let transformed = range.getIntersection( otherRange ); // range from ( foo, 1 ) to ( p, 2 ).
   *
   * otherRange = view.createRange( view.createPositionAt( bar, 1 ), view.createPositionAt( bar, 3 ); "ar" is in range.
   * transformed = range.getIntersection( otherRange ); // null - no common part.
   * ```
   *
   * @param otherRange Range to check for intersection.
   * @returns A common part of given ranges or `null` if ranges have no common part.
   */
  getIntersection(e) {
    if (this.isIntersecting(e)) {
      let t = this.start, i = this.end;
      return this.containsPosition(e.start) && (t = e.start), this.containsPosition(e.end) && (i = e.end), new st(t, i);
    }
    return null;
  }
  /**
   * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.
   *
   * @param options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.
   */
  getWalker(e = {}) {
    return e.boundaries = this, new Ct(e);
  }
  /**
   * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}
   * which is a common ancestor of range's both ends (in which the entire range is contained).
   */
  getCommonAncestor() {
    return this.start.getCommonAncestor(this.end);
  }
  /**
   * Returns an {@link module:engine/view/element~Element Element} contained by the range.
   * The element will be returned when it is the **only** node within the range and **fully–contained**
   * at the same time.
   */
  getContainedElement() {
    if (this.isCollapsed)
      return null;
    let e = this.start.nodeAfter, t = this.end.nodeBefore;
    return this.start.parent.is("$text") && this.start.isAtEnd && this.start.parent.nextSibling && (e = this.start.parent.nextSibling), this.end.parent.is("$text") && this.end.isAtStart && this.end.parent.previousSibling && (t = this.end.parent.previousSibling), e && e.is("element") && e === t ? e : null;
  }
  /**
   * Clones this range.
   */
  clone() {
    return new st(this.start, this.end);
  }
  /**
   * Returns an iterator that iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns
   * them.
   *
   * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option
   * set to `true`. However it returns only {@link module:engine/view/item~Item items},
   * not {@link module:engine/view/treewalker~TreeWalkerValue}.
   *
   * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for
   * a full list of available options.
   *
   * @param options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.
   */
  *getItems(e = {}) {
    e.boundaries = this, e.ignoreElementEnd = !0;
    const t = new Ct(e);
    for (const i of t)
      yield i.item;
  }
  /**
   * Returns an iterator that iterates over all {@link module:engine/view/position~Position positions} that are boundaries or
   * contained in this range.
   *
   * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only
   * {@link module:engine/view/position~Position positions}, not {@link module:engine/view/treewalker~TreeWalkerValue}.
   *
   * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for
   * a full list of available options.
   *
   * @param options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.
   */
  *getPositions(e = {}) {
    e.boundaries = this;
    const t = new Ct(e);
    yield t.position;
    for (const i of t)
      yield i.nextPosition;
  }
  /**
   * Checks and returns whether this range intersects with the given range.
   *
   * @param otherRange Range to compare with.
   * @returns True if ranges intersect.
   */
  isIntersecting(e) {
    return this.start.isBefore(e.end) && this.end.isAfter(e.start);
  }
  /**
   * Creates a range from the given parents and offsets.
   *
   * @internal
   * @param startElement Start position parent element.
   * @param startOffset Start position offset.
   * @param endElement End position parent element.
   * @param endOffset End position offset.
   * @returns Created range.
   */
  static _createFromParentsAndOffsets(e, t, i, s) {
    return new this(new v(e, t), new v(i, s));
  }
  /**
   * Creates a new range, spreading from specified {@link module:engine/view/position~Position position} to a position moved by
   * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.
   *
   * @internal
   * @param position Beginning of the range.
   * @param shift How long the range should be.
   */
  static _createFromPositionAndShift(e, t) {
    const i = e, s = e.getShiftedBy(t);
    return t > 0 ? new this(i, s) : new this(s, i);
  }
  /**
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * @internal
   * @param element Element which is a parent for the range.
   */
  static _createIn(e) {
    return this._createFromParentsAndOffsets(e, 0, e, e.childCount);
  }
  /**
   * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
   *
   * @internal
   */
  static _createOn(e) {
    const t = e.is("$textProxy") ? e.offsetSize : 1;
    return this._createFromPositionAndShift(v._createBefore(e), t);
  }
};
P.prototype.is = function(n) {
  return n === "range" || n === "view:range";
};
function Gi(n) {
  return !!(n.item.is("attributeElement") || n.item.is("uiElement"));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let ct = class Ou extends N(Mt) {
  /**
   * Creates new selection instance.
   *
   * **Note**: The selection constructor is available as a factory method:
   *
   * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},
   * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.
   *
   * ```ts
   * // Creates empty selection without ranges.
   * const selection = writer.createSelection();
   *
   * // Creates selection at the given range.
   * const range = writer.createRange( start, end );
   * const selection = writer.createSelection( range );
   *
   * // Creates selection at the given ranges
   * const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
   * const selection = writer.createSelection( ranges );
   *
   * // Creates selection from the other selection.
   * const otherSelection = writer.createSelection();
   * const selection = writer.createSelection( otherSelection );
   *
   * // Creates selection from the document selection.
   * const selection = writer.createSelection( editor.editing.view.document.selection );
   *
   * // Creates selection at the given position.
   * const position = writer.createPositionFromPath( root, path );
   * const selection = writer.createSelection( position );
   *
   * // Creates collapsed selection at the position of given item and offset.
   * const paragraph = writer.createContainerElement( 'paragraph' );
   * const selection = writer.createSelection( paragraph, offset );
   *
   * // Creates a range inside an {@link module:engine/view/element~Element element} which starts before the
   * // first child of that element and ends after the last child of that element.
   * const selection = writer.createSelection( paragraph, 'in' );
   *
   * // Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends
   * // just after the item.
   * const selection = writer.createSelection( paragraph, 'on' );
   * ```
   *
   * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.
   *
   * ```ts
   * // Creates backward selection.
   * const selection = writer.createSelection( range, { backward: true } );
   * ```
   *
   * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
   * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
   * represented in other way, for example by applying proper CSS class.
   *
   * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM
   * (and be  properly handled by screen readers).
   *
   * ```ts
   * // Creates fake selection with label.
   * const selection = writer.createSelection( range, { fake: true, label: 'foo' } );
   * ```
   *
   * @internal
   */
  constructor(...e) {
    super(), this._ranges = [], this._lastRangeBackward = !1, this._isFake = !1, this._fakeSelectionLabel = "", e.length && this.setTo(...e);
  }
  /**
   * Returns true if selection instance is marked as `fake`.
   *
   * @see #setTo
   */
  get isFake() {
    return this._isFake;
  }
  /**
   * Returns fake selection label.
   *
   * @see #setTo
   */
  get fakeSelectionLabel() {
    return this._fakeSelectionLabel;
  }
  /**
   * Selection anchor. Anchor may be described as a position where the selection starts. Together with
   * {@link #focus focus} they define the direction of selection, which is important
   * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.
   * It may be a bit unintuitive when there are multiple ranges in selection.
   *
   * @see #focus
   */
  get anchor() {
    if (!this._ranges.length)
      return null;
    const e = this._ranges[this._ranges.length - 1];
    return (this._lastRangeBackward ? e.end : e.start).clone();
  }
  /**
   * Selection focus. Focus is a position where the selection ends.
   *
   * @see #anchor
   */
  get focus() {
    if (!this._ranges.length)
      return null;
    const e = this._ranges[this._ranges.length - 1];
    return (this._lastRangeBackward ? e.start : e.end).clone();
  }
  /**
   * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is
   * collapsed.
   */
  get isCollapsed() {
    return this.rangeCount === 1 && this._ranges[0].isCollapsed;
  }
  /**
   * Returns number of ranges in selection.
   */
  get rangeCount() {
    return this._ranges.length;
  }
  /**
   * Specifies whether the {@link #focus} precedes {@link #anchor}.
   */
  get isBackward() {
    return !this.isCollapsed && this._lastRangeBackward;
  }
  /**
   * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`
   * if the selection is not inside an editable element.
   */
  get editableElement() {
    return this.anchor ? this.anchor.editableElement : null;
  }
  /**
   * Returns an iterable that contains copies of all ranges added to the selection.
   */
  *getRanges() {
    for (const e of this._ranges)
      yield e.clone();
  }
  /**
   * Returns copy of the first range in the selection. First range is the one which
   * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start
   * position of all other ranges (not to confuse with the first range added to the selection).
   * Returns `null` if no ranges are added to selection.
   */
  getFirstRange() {
    let e = null;
    for (const t of this._ranges)
      (!e || t.start.isBefore(e.start)) && (e = t);
    return e ? e.clone() : null;
  }
  /**
   * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}
   * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse
   * with the last range added to the selection). Returns `null` if no ranges are added to selection.
   */
  getLastRange() {
    let e = null;
    for (const t of this._ranges)
      (!e || t.end.isAfter(e.end)) && (e = t);
    return e ? e.clone() : null;
  }
  /**
   * Returns copy of the first position in the selection. First position is the position that
   * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.
   * Returns `null` if no ranges are added to selection.
   */
  getFirstPosition() {
    const e = this.getFirstRange();
    return e ? e.start.clone() : null;
  }
  /**
   * Returns copy of the last position in the selection. Last position is the position that
   * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.
   * Returns `null` if no ranges are added to selection.
   */
  getLastPosition() {
    const e = this.getLastRange();
    return e ? e.end.clone() : null;
  }
  /**
   * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,
   * same number of ranges and all ranges from one selection equal to a range from other selection.
   *
   * @param otherSelection Selection to compare with.
   * @returns `true` if selections are equal, `false` otherwise.
   */
  isEqual(e) {
    if (this.isFake != e.isFake || this.isFake && this.fakeSelectionLabel != e.fakeSelectionLabel || this.rangeCount != e.rangeCount)
      return !1;
    if (this.rangeCount === 0)
      return !0;
    if (!this.anchor.isEqual(e.anchor) || !this.focus.isEqual(e.focus))
      return !1;
    for (const t of this._ranges) {
      let i = !1;
      for (const s of e._ranges)
        if (t.isEqual(s)) {
          i = !0;
          break;
        }
      if (!i)
        return !1;
    }
    return !0;
  }
  /**
   * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same
   * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are
   * equal to any trimmed range from other selection.
   *
   * @param otherSelection Selection to compare with.
   * @returns `true` if selections are similar, `false` otherwise.
   */
  isSimilar(e) {
    if (this.isBackward != e.isBackward)
      return !1;
    const t = $s(this.getRanges()), i = $s(e.getRanges());
    if (t != i)
      return !1;
    if (t == 0)
      return !0;
    for (let s of this.getRanges()) {
      s = s.getTrimmed();
      let r = !1;
      for (let o of e.getRanges())
        if (o = o.getTrimmed(), s.start.isEqual(o.start) && s.end.isEqual(o.end)) {
          r = !0;
          break;
        }
      if (!r)
        return !1;
    }
    return !0;
  }
  /**
   * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only
   * one range in the selection, and that range contains exactly one element.
   * Returns `null` if there is no selected element.
   */
  getSelectedElement() {
    return this.rangeCount !== 1 ? null : this.getFirstRange().getContainedElement();
  }
  /**
   * Sets this selection's ranges and direction to the specified location based on the given
   * {@link module:engine/view/selection~Selectable selectable}.
   *
   * ```ts
   * // Sets selection to the given range.
   * const range = writer.createRange( start, end );
   * selection.setTo( range );
   *
   * // Sets selection to given ranges.
   * const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
   * selection.setTo( range );
   *
   * // Sets selection to the other selection.
   * const otherSelection = writer.createSelection();
   * selection.setTo( otherSelection );
   *
   * // Sets selection to contents of DocumentSelection.
   * selection.setTo( editor.editing.view.document.selection );
   *
   * // Sets collapsed selection at the given position.
   * const position = writer.createPositionAt( root, path );
   * selection.setTo( position );
   *
   * // Sets collapsed selection at the position of given item and offset.
   * selection.setTo( paragraph, offset );
   * ```
   *
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * ```ts
   * selection.setTo( paragraph, 'in' );
   * ```
   *
   * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.
   *
   * ```ts
   * selection.setTo( paragraph, 'on' );
   *
   * // Clears selection. Removes all ranges.
   * selection.setTo( null );
   * ```
   *
   * `Selection#setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.
   *
   * ```ts
   * // Sets selection as backward.
   * selection.setTo( range, { backward: true } );
   * ```
   *
   * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
   * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
   * represented in other way, for example by applying proper CSS class.
   *
   * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM
   * (and be  properly handled by screen readers).
   *
   * ```ts
   * // Creates fake selection with label.
   * selection.setTo( range, { fake: true, label: 'foo' } );
   * ```
   *
   * @fires change
   */
  setTo(...e) {
    let [t, i, s] = e;
    if (typeof i == "object" && (s = i, i = void 0), t === null)
      this._setRanges([]), this._setFakeOptions(s);
    else if (t instanceof Ou || t instanceof Dr)
      this._setRanges(t.getRanges(), t.isBackward), this._setFakeOptions({ fake: t.isFake, label: t.fakeSelectionLabel });
    else if (t instanceof P)
      this._setRanges([t], s && s.backward), this._setFakeOptions(s);
    else if (t instanceof v)
      this._setRanges([new P(t)]), this._setFakeOptions(s);
    else if (t instanceof Vt) {
      const r = !!s && !!s.backward;
      let o;
      if (i === void 0)
        throw new d("view-selection-setto-required-second-parameter", this);
      i == "in" ? o = P._createIn(t) : i == "on" ? o = P._createOn(t) : o = new P(v._createAt(t, i)), this._setRanges([o], r), this._setFakeOptions(s);
    } else if (_e(t))
      this._setRanges(t, s && s.backward), this._setFakeOptions(s);
    else
      throw new d("view-selection-setto-not-selectable", this);
    this.fire("change");
  }
  /**
   * Moves {@link #focus} to the specified location.
   *
   * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
   * parameters.
   *
   * @fires change
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/view/item~Item view item}.
   */
  setFocus(e, t) {
    if (this.anchor === null)
      throw new d("view-selection-setfocus-no-ranges", this);
    const i = v._createAt(e, t);
    if (i.compareWith(this.focus) == "same")
      return;
    const s = this.anchor;
    this._ranges.pop(), i.compareWith(s) == "before" ? this._addRange(new P(i, s), !0) : this._addRange(new P(s, i)), this.fire("change");
  }
  /**
   * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array
   * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.
   * Accepts a flag describing in which way the selection is made.
   *
   * @param newRanges Iterable object of ranges to set.
   * @param isLastBackward Flag describing if last added range was selected forward - from start to end
   * (`false`) or backward - from end to start (`true`). Defaults to `false`.
   */
  _setRanges(e, t = !1) {
    e = Array.from(e), this._ranges = [];
    for (const i of e)
      this._addRange(i);
    this._lastRangeBackward = !!t;
  }
  /**
   * Sets this selection instance to be marked as `fake`. A fake selection does not render as browser native selection
   * over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to
   * the user and selection over elements can be represented in other way, for example by applying proper CSS class.
   *
   * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be
   * properly handled by screen readers).
   */
  _setFakeOptions(e = {}) {
    this._isFake = !!e.fake, this._fakeSelectionLabel = e.fake && e.label || "";
  }
  /**
   * Adds a range to the selection. Added range is copied. This means that passed range is not saved in the
   * selection instance and you can safely operate on it.
   *
   * Accepts a flag describing in which way the selection is made - passed range might be selected from
   * {@link module:engine/view/range~Range#start start} to {@link module:engine/view/range~Range#end end}
   * or from {@link module:engine/view/range~Range#end end} to {@link module:engine/view/range~Range#start start}.
   * The flag is used to set {@link #anchor anchor} and {@link #focus focus} properties.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects
   * with ranges already stored in Selection instance.
   */
  _addRange(e, t = !1) {
    if (!(e instanceof P))
      throw new d("view-selection-add-range-not-range", this);
    this._pushRange(e), this._lastRangeBackward = !!t;
  }
  /**
   * Adds range to selection - creates copy of given range so it can be safely used and modified.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects
   * with ranges already stored in selection instance.
   */
  _pushRange(e) {
    for (const t of this._ranges)
      if (e.isIntersecting(t))
        throw new d("view-selection-range-intersects", this, { addedRange: e, intersectingRange: t });
    this._ranges.push(new P(e.start, e.end));
  }
};
ct.prototype.is = function(n) {
  return n === "selection" || n === "view:selection";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Dr = class extends N(Mt) {
  constructor(...e) {
    super(), this._selection = new ct(), this._selection.delegate("change").to(this), e.length && this._selection.setTo(...e);
  }
  /**
   * Returns true if selection instance is marked as `fake`.
   *
   * @see #_setTo
   */
  get isFake() {
    return this._selection.isFake;
  }
  /**
   * Returns fake selection label.
   *
   * @see #_setTo
   */
  get fakeSelectionLabel() {
    return this._selection.fakeSelectionLabel;
  }
  /**
   * Selection anchor. Anchor may be described as a position where the selection starts. Together with
   * {@link #focus focus} they define the direction of selection, which is important
   * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.
   * It may be a bit unintuitive when there are multiple ranges in selection.
   *
   * @see #focus
   */
  get anchor() {
    return this._selection.anchor;
  }
  /**
   * Selection focus. Focus is a position where the selection ends.
   *
   * @see #anchor
   */
  get focus() {
    return this._selection.focus;
  }
  /**
   * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is
   * collapsed.
   */
  get isCollapsed() {
    return this._selection.isCollapsed;
  }
  /**
   * Returns number of ranges in selection.
   */
  get rangeCount() {
    return this._selection.rangeCount;
  }
  /**
   * Specifies whether the {@link #focus} precedes {@link #anchor}.
   */
  get isBackward() {
    return this._selection.isBackward;
  }
  /**
   * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`
   * if the selection is not inside an editable element.
   */
  get editableElement() {
    return this._selection.editableElement;
  }
  /**
   * Used for the compatibility with the {@link module:engine/view/selection~Selection#isEqual} method.
   *
   * @internal
   */
  get _ranges() {
    return this._selection._ranges;
  }
  /**
   * Returns an iterable that contains copies of all ranges added to the selection.
   */
  *getRanges() {
    yield* this._selection.getRanges();
  }
  /**
   * Returns copy of the first range in the selection. First range is the one which
   * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start
   * position of all other ranges (not to confuse with the first range added to the selection).
   * Returns `null` if no ranges are added to selection.
   */
  getFirstRange() {
    return this._selection.getFirstRange();
  }
  /**
   * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}
   * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse
   * with the last range added to the selection). Returns `null` if no ranges are added to selection.
   */
  getLastRange() {
    return this._selection.getLastRange();
  }
  /**
   * Returns copy of the first position in the selection. First position is the position that
   * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.
   * Returns `null` if no ranges are added to selection.
   */
  getFirstPosition() {
    return this._selection.getFirstPosition();
  }
  /**
   * Returns copy of the last position in the selection. Last position is the position that
   * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.
   * Returns `null` if no ranges are added to selection.
   */
  getLastPosition() {
    return this._selection.getLastPosition();
  }
  /**
   * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only
   * one range in the selection, and that range contains exactly one element.
   * Returns `null` if there is no selected element.
   */
  getSelectedElement() {
    return this._selection.getSelectedElement();
  }
  /**
   * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,
   * same number of ranges and all ranges from one selection equal to a range from other selection.
   *
   * @param otherSelection Selection to compare with.
   * @returns `true` if selections are equal, `false` otherwise.
   */
  isEqual(e) {
    return this._selection.isEqual(e);
  }
  /**
   * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same
   * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are
   * equal to any trimmed range from other selection.
   *
   * @param otherSelection Selection to compare with.
   * @returns `true` if selections are similar, `false` otherwise.
   */
  isSimilar(e) {
    return this._selection.isSimilar(e);
  }
  /**
   * Sets this selection's ranges and direction to the specified location based on the given
   * {@link module:engine/view/selection~Selectable selectable}.
   *
   * ```ts
   * // Sets selection to the given range.
   * const range = writer.createRange( start, end );
   * documentSelection._setTo( range );
   *
   * // Sets selection to given ranges.
   * const ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];
   * documentSelection._setTo( range );
   *
   * // Sets selection to the other selection.
   * const otherSelection = writer.createSelection();
   * documentSelection._setTo( otherSelection );
   *
   * // Sets collapsed selection at the given position.
   * const position = writer.createPositionAt( root, offset );
   * documentSelection._setTo( position );
   *
   * // Sets collapsed selection at the position of given item and offset.
   * documentSelection._setTo( paragraph, offset );
   * ```
   *
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * ```ts
   * documentSelection._setTo( paragraph, 'in' );
   * ```
   *
   * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.
   *
   * ```ts
   * documentSelection._setTo( paragraph, 'on' );
   *
   * // Clears selection. Removes all ranges.
   * documentSelection._setTo( null );
   * ```
   *
   * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.
   *
   * ```ts
   * // Sets selection as backward.
   * documentSelection._setTo( range, { backward: true } );
   * ```
   *
   * Fake selection does not render as browser native selection over selected elements and is hidden to the user.
   * This way, no native selection UI artifacts are displayed to the user and selection over elements can be
   * represented in other way, for example by applying proper CSS class.
   *
   * Additionally fake's selection label can be provided. It will be used to des cribe fake selection in DOM
   * (and be  properly handled by screen readers).
   *
   * ```ts
   * // Creates fake selection with label.
   * documentSelection._setTo( range, { fake: true, label: 'foo' } );
   * ```
   *
   * @internal
   * @fires change
   */
  _setTo(...e) {
    this._selection.setTo(...e);
  }
  /**
   * Moves {@link #focus} to the specified location.
   *
   * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
   * parameters.
   *
   * @internal
   * @fires change
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/view/item~Item view item}.
   */
  _setFocus(e, t) {
    this._selection.setFocus(e, t);
  }
};
Dr.prototype.is = function(n) {
  return n === "selection" || n == "documentSelection" || n == "view:selection" || n == "view:documentSelection";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class fi extends Ze {
  /**
   * @param source The emitter.
   * @param name The event name.
   * @param startRange The view range that the bubbling should start from.
   */
  constructor(e, t, i) {
    super(e, t), this.startRange = i, this._eventPhase = "none", this._currentTarget = null;
  }
  /**
   * The current event phase.
   */
  get eventPhase() {
    return this._eventPhase;
  }
  /**
   * The current bubbling target.
   */
  get currentTarget() {
    return this._currentTarget;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const es = Symbol("bubbling contexts");
function qs(n) {
  class e extends n {
    fire(i, ...s) {
      try {
        const r = i instanceof Ze ? i : new Ze(this, i), o = ts(this);
        if (!o.size)
          return;
        if (gi(r, "capturing", this), Lt(o, "$capture", r, ...s))
          return r.return;
        const a = r.startRange || this.selection.getFirstRange(), l = a ? a.getContainedElement() : null, c = l ? !!Mu(o, l) : !1;
        let u = l || _1(a);
        if (gi(r, "atTarget", u), !c) {
          if (Lt(o, "$text", r, ...s))
            return r.return;
          gi(r, "bubbling", u);
        }
        for (; u; ) {
          if (u.is("rootElement")) {
            if (Lt(o, "$root", r, ...s))
              return r.return;
          } else if (u.is("element") && Lt(o, u.name, r, ...s))
            return r.return;
          if (Lt(o, u, r, ...s))
            return r.return;
          u = u.parent, gi(r, "bubbling", u);
        }
        return gi(r, "bubbling", this), Lt(o, "$document", r, ...s), r.return;
      } catch (r) {
        /* istanbul ignore next -- @preserve */
        d.rethrowUnexpectedError(r, this);
      }
    }
    _addEventListener(i, s, r) {
      const o = X(r.context || "$document"), a = ts(this);
      for (const l of o) {
        let c = a.get(l);
        c || (c = new (N())(), a.set(l, c)), this.listenTo(c, i, s, r);
      }
    }
    _removeEventListener(i, s) {
      const r = ts(this);
      for (const o of r.values())
        this.stopListening(o, i, s);
    }
  }
  return e;
}
{
  const n = qs(Object);
  ["fire", "_addEventListener", "_removeEventListener"].forEach((e) => {
    qs[e] = n.prototype[e];
  });
}
function gi(n, e, t) {
  n instanceof fi && (n._eventPhase = e, n._currentTarget = t);
}
function Lt(n, e, t, ...i) {
  const s = typeof e == "string" ? n.get(e) : Mu(n, e);
  return s ? (s.fire(t, ...i), t.stop.called) : !1;
}
function Mu(n, e) {
  for (const [t, i] of n)
    if (typeof t == "function" && t(e))
      return i;
  return null;
}
function ts(n) {
  return n[es] || (n[es] = /* @__PURE__ */ new Map()), n[es];
}
function _1(n) {
  if (!n)
    return null;
  const e = n.start.parent, t = n.end.parent, i = e.getPath(), s = t.getPath();
  return i.length > s.length ? e : t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Vu = class extends qs(z()) {
  /**
   * Creates a Document instance.
   *
   * @param stylesProcessor The styles processor instance.
   */
  constructor(e) {
    super(), this._postFixers = /* @__PURE__ */ new Set(), this.selection = new Dr(), this.roots = new He({ idProperty: "rootName" }), this.stylesProcessor = e, this.set("isReadOnly", !1), this.set("isFocused", !1), this.set("isSelecting", !1), this.set("isComposing", !1);
  }
  /**
   * Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not
   * specific "main" root is returned.
   *
   * @param name Name of the root.
   * @returns The view root element with the specified name or null when there is no root of given name.
   */
  getRoot(e = "main") {
    return this.roots.get(e);
  }
  /**
   * Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered
   * to the DOM.
   *
   * Post-fixers are executed right after all changes from the outermost change block were applied but
   * before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made
   * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should
   * not be fixed in the new document tree state.
   *
   * View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that
   * changes executed in a view post-fixer should not break model-view mapping.
   *
   * The types of changes which should be safe:
   *
   * * adding or removing attribute from elements,
   * * changes inside of {@link module:engine/view/uielement~UIElement UI elements},
   * * {@link module:engine/controller/editingcontroller~EditingController#reconvertItem marking some of the model elements to be
   * re-converted}.
   *
   * Try to avoid changes which touch view structure:
   *
   * * you should not add or remove nor wrap or unwrap any view elements,
   * * you should not change the editor data model in a view post-fixer.
   *
   * As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.
   *
   * Typically, a post-fixer will look like this:
   *
   * ```ts
   * editor.editing.view.document.registerPostFixer( writer => {
   * 	if ( checkSomeCondition() ) {
   * 		writer.doSomething();
   *
   * 		// Let other post-fixers know that something changed.
   * 		return true;
   * 	}
   * } );
   * ```
   *
   * Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console).
   * That is because adding a post-fixer does not execute it.
   * The post-fixer will be executed as soon as any change in the document needs to cause its rendering.
   * If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling
   * {@link module:engine/view/view~View#forceRender `view.forceRender()`}.
   *
   * If you need to register a callback which is executed when DOM elements are already updated,
   * use {@link module:engine/view/view~View#event:render render event}.
   */
  registerPostFixer(e) {
    this._postFixers.add(e);
  }
  /**
   * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.
   */
  destroy() {
    this.roots.map((e) => e.destroy()), this.stopListening();
  }
  /**
   * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.
   *
   * @internal
   */
  _callPostFixers(e) {
    let t = !1;
    do
      for (const i of this._postFixers)
        if (t = i(e), t)
          break;
    while (t);
  }
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Du = 10;
class Et extends Se {
  /**
   * Creates an attribute element.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement
   * @see module:engine/view/element~Element
   * @protected
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this._priority = Du, this._id = null, this._clonesGroup = null, this.getFillerOffset = v1;
  }
  /**
   * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.
   */
  get priority() {
    return this._priority;
  }
  /**
   * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},
   * and then two elements are considered similar if, and only if they have the same `id`.
   */
  get id() {
    return this._id;
  }
  /**
   * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the
   * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).
   *
   * Note: If this element has been removed from the tree, returned set will not include it.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}
   * if this element has no `id`.
   *
   * @returns Set containing all the attribute elements
   * with the same `id` that were added and not removed from the view tree.
   */
  getElementsWithSameId() {
    if (this.id === null)
      throw new d("attribute-element-get-elements-with-same-id-no-id", this);
    return new Set(this._clonesGroup);
  }
  /**
   * Checks if this element is similar to other element.
   *
   * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements
   * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain
   * different set of children nodes.
   *
   * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both
   * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be
   * considered similar.
   *
   * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:
   *
   * * two following similar elements can be merged together into one, longer element,
   * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to
   * decide whether processed element should be unwrapped,
   * * etc.
   */
  isSimilar(e) {
    return this.id !== null || e.id !== null ? this.id === e.id : super.isSimilar(e) && this.priority == e.priority;
  }
  /**
   * Clones provided element with priority.
   *
   * @internal
   * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
   * element will be cloned without any children.
   * @returns Clone of this element.
   */
  _clone(e = !1) {
    const t = super._clone(e);
    return t._priority = this._priority, t._id = this._id, t;
  }
}
Et.DEFAULT_PRIORITY = Du;
Et.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "attributeElement" || n === "view:attributeElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element") : n === "attributeElement" || n === "view:attributeElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
function v1() {
  if (is(this))
    return null;
  let n = this.parent;
  for (; n && n.is("attributeElement"); ) {
    if (is(n) > 1)
      return null;
    n = n.parent;
  }
  return !n || is(n) > 1 ? null : this.childCount;
}
function is(n) {
  return Array.from(n.getChildren()).filter((e) => !e.is("uiElement")).length;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Br extends Se {
  /**
   * Creates new instance of EmptyElement.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` when third parameter is passed,
   * to inform that usage of EmptyElement is incorrect (adding child nodes to EmptyElement is forbidden).
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createEmptyElement
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this.getFillerOffset = y1;
  }
  /**
   * Overrides {@link module:engine/view/element~Element#_insertChild} method.
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` to prevent
   * adding any child nodes to EmptyElement.
   *
   * @internal
   */
  _insertChild(e, t) {
    if (t && (t instanceof Vt || Array.from(t).length > 0))
      throw new d("view-emptyelement-cannot-add", [this, t]);
    return 0;
  }
}
Br.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "emptyElement" || n === "view:emptyElement" || n === "element" || n === "view:element") : n === "emptyElement" || n === "view:emptyElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
function y1() {
  return null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Nn extends Se {
  /**
   * Creates new instance of UIElement.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` when third parameter is passed,
   * to inform that usage of UIElement is incorrect (adding child nodes to UIElement is forbidden).
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createUIElement
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this.getFillerOffset = C1;
  }
  /**
   * Overrides {@link module:engine/view/element~Element#_insertChild} method.
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` to prevent adding any child nodes
   * to UIElement.
   *
   * @internal
   */
  _insertChild(e, t) {
    if (t && (t instanceof Vt || Array.from(t).length > 0))
      throw new d("view-uielement-cannot-add", [this, t]);
    return 0;
  }
  /**
   * Renders this {@link module:engine/view/uielement~UIElement} to DOM. This method is called by
   * {@link module:engine/view/domconverter~DomConverter}.
   * Do not use inheritance to create custom rendering method, replace `render()` method instead:
   *
   * ```ts
   * const myUIElement = downcastWriter.createUIElement( 'span' );
   * myUIElement.render = function( domDocument, domConverter ) {
   * 	const domElement = this.toDomElement( domDocument );
   *
   * 	domConverter.setContentOf( domElement, '<b>this is ui element</b>' );
   *
   * 	return domElement;
   * };
   * ```
   *
   * If changes in your UI element should trigger some editor UI update you should call
   * the {@link module:ui/editorui/editorui~EditorUI#update `editor.ui.update()`} method
   * after rendering your UI element.
   *
   * @param domConverter Instance of the DomConverter used to optimize the output.
   */
  render(e, t) {
    return this.toDomElement(e);
  }
  /**
   * Creates DOM element based on this view UIElement.
   * Note that each time this method is called new DOM element is created.
   */
  toDomElement(e) {
    const t = e.createElement(this.name);
    for (const i of this.getAttributeKeys())
      t.setAttribute(i, this.getAttribute(i));
    return t;
  }
}
Nn.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "uiElement" || n === "view:uiElement" || n === "element" || n === "view:element") : n === "uiElement" || n === "view:uiElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
function k1(n) {
  n.document.on("arrowKey", (e, t) => E1(e, t, n.domConverter), { priority: "low" });
}
function C1() {
  return null;
}
function E1(n, e, t) {
  if (e.keyCode == R.arrowright) {
    const i = e.domTarget.ownerDocument.defaultView.getSelection(), s = i.rangeCount == 1 && i.getRangeAt(0).collapsed;
    if (s || e.shiftKey) {
      const r = i.focusNode, o = i.focusOffset, a = t.domPositionToView(r, o);
      if (a === null)
        return;
      let l = !1;
      const c = a.getLastMatchingPosition((u) => (u.item.is("uiElement") && (l = !0), !!(u.item.is("uiElement") || u.item.is("attributeElement"))));
      if (l) {
        const u = t.viewPositionToDom(c);
        s ? i.collapse(u.parent, u.offset) : i.extend(u.parent, u.offset);
      }
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Fr extends Se {
  /**
   * Creates a new instance of a raw element.
   *
   * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} when the `children`
   * parameter is passed to inform that the usage of `RawElement` is incorrect (adding child nodes to `RawElement` is forbidden).
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#createRawElement
   * @internal
   * @param document The document instance to which this element belongs.
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   */
  constructor(e, t, i, s) {
    super(e, t, i, s), this.getFillerOffset = A1;
  }
  /**
   * Overrides the {@link module:engine/view/element~Element#_insertChild} method.
   * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} to prevent
   * adding any child nodes to a raw element.
   *
   * @internal
   */
  _insertChild(e, t) {
    if (t && (t instanceof Vt || Array.from(t).length > 0))
      throw new d("view-rawelement-cannot-add", [this, t]);
    return 0;
  }
  /**
   * This allows rendering the children of a {@link module:engine/view/rawelement~RawElement} on the DOM level.
   * This method is called by the {@link module:engine/view/domconverter~DomConverter} with the raw DOM element
   * passed as an argument, leaving the number and shape of the children up to the integrator.
   *
   * This method **must be defined** for the raw element to work:
   *
   * ```ts
   * const myRawElement = downcastWriter.createRawElement( 'div' );
   *
   * myRawElement.render = function( domElement, domConverter ) {
   * 	domConverter.setContentOf( domElement, '<b>This is the raw content of myRawElement.</b>' );
   * };
   * ```
   *
   * @param domElement The native DOM element representing the raw view element.
   * @param domConverter Instance of the DomConverter used to optimize the output.
   */
  render(e, t) {
  }
}
Fr.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "rawElement" || n === "view:rawElement" || n === "element" || n === "view:element") : n === "rawElement" || n === "view:rawElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === this.name || n === "view:" + this.name || n === "element" || n === "view:element" || n === "node" || n === "view:node";
};
function A1() {
  return null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let At = class extends N(Mt) {
  /**
   * Creates new DocumentFragment instance.
   *
   * @internal
   * @param document The document to which this document fragment belongs.
   * @param children A list of nodes to be inserted into the created document fragment.
   */
  constructor(e, t) {
    super(), this._children = [], this._customProperties = /* @__PURE__ */ new Map(), this.document = e, t && this._insertChild(0, t);
  }
  /**
   * Iterable interface.
   *
   * Iterates over nodes added to this document fragment.
   */
  [Symbol.iterator]() {
    return this._children[Symbol.iterator]();
  }
  /**
   * Number of child nodes in this document fragment.
   */
  get childCount() {
    return this._children.length;
  }
  /**
   * Is `true` if there are no nodes inside this document fragment, `false` otherwise.
   */
  get isEmpty() {
    return this.childCount === 0;
  }
  /**
   * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.
   */
  get root() {
    return this;
  }
  /**
   * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.
   */
  get parent() {
    return null;
  }
  /**
   * Artificial element name. Returns `undefined`. Added for compatibility reasons.
   */
  get name() {
  }
  /**
   * Returns the custom property value for the given key.
   */
  getCustomProperty(e) {
    return this._customProperties.get(e);
  }
  /**
   * Returns an iterator which iterates over this document fragment's custom properties.
   * Iterator provides `[ key, value ]` pairs for each stored property.
   */
  *getCustomProperties() {
    yield* this._customProperties.entries();
  }
  /**
   * {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end
   * and sets the parent of these nodes to this fragment.
   *
   * @internal
   * @param items Items to be inserted.
   * @returns Number of appended nodes.
   */
  _appendChild(e) {
    return this._insertChild(this.childCount, e);
  }
  /**
   * Gets child at the given index.
   *
   * @param index Index of child.
   * @returns Child node.
   */
  getChild(e) {
    return this._children[e];
  }
  /**
   * Gets index of the given child node. Returns `-1` if child node is not found.
   *
   * @param node Child node.
   * @returns Index of the child node.
   */
  getChildIndex(e) {
    return this._children.indexOf(e);
  }
  /**
   * Gets child nodes iterator.
   *
   * @returns Child nodes iterator.
   */
  getChildren() {
    return this._children[Symbol.iterator]();
  }
  /**
   * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
   * this fragment.
   *
   * @internal
   * @param index Position where nodes should be inserted.
   * @param items Items to be inserted.
   * @returns Number of inserted nodes.
   */
  _insertChild(e, t) {
    this._fireChange("children", this);
    let i = 0;
    const s = T1(this.document, t);
    for (const r of s)
      r.parent !== null && r._remove(), r.parent = this, this._children.splice(e, 0, r), e++, i++;
    return i;
  }
  /**
   * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.
   *
   * @internal
   * @param index Number of the first node to remove.
   * @param howMany Number of nodes to remove.
   * @returns The array of removed nodes.
   */
  _removeChildren(e, t = 1) {
    this._fireChange("children", this);
    for (let i = e; i < e + t; i++)
      this._children[i].parent = null;
    return this._children.splice(e, t);
  }
  /**
   * Fires `change` event with given type of the change.
   *
   * @internal
   * @param type Type of the change.
   * @param node Changed node.
   */
  _fireChange(e, t) {
    this.fire("change:" + e, t);
  }
  /**
   * Sets a custom property. They can be used to add special data to elements.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty
   * @internal
   */
  _setCustomProperty(e, t) {
    this._customProperties.set(e, t);
  }
  /**
   * Removes the custom property stored under the given key.
   *
   * @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty
   * @internal
   * @returns Returns true if property was removed.
   */
  _removeCustomProperty(e) {
    return this._customProperties.delete(e);
  }
};
At.prototype.is = function(n) {
  return n === "documentFragment" || n === "view:documentFragment";
};
function T1(n, e) {
  return typeof e == "string" ? [new j(n, e)] : (_e(e) || (e = [e]), Array.from(e).map((t) => typeof t == "string" ? new j(n, t) : t instanceof De ? new j(n, t.data) : t));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Bu {
  /**
   * @param document The view document instance.
   */
  constructor(e) {
    this._cloneGroups = /* @__PURE__ */ new Map(), this._slotFactory = null, this.document = e;
  }
  setSelection(...e) {
    this.document.selection._setTo(...e);
  }
  /**
   * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.
   *
   * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}
   * parameters.
   *
   * @param Offset or one of the flags. Used only when the first parameter is a {@link module:engine/view/item~Item view item}.
   */
  setSelectionFocus(e, t) {
    this.document.selection._setFocus(e, t);
  }
  /**
   * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.
   *
   * @param children A list of nodes to be inserted into the created document fragment.
   * @returns The created document fragment.
   */
  createDocumentFragment(e) {
    return new At(this.document, e);
  }
  /**
   * Creates a new {@link module:engine/view/text~Text text node}.
   *
   * ```ts
   * writer.createText( 'foo' );
   * ```
   *
   * @param data The text's data.
   * @returns The created text node.
   */
  createText(e) {
    return new j(this.document, e);
  }
  /**
   * Creates a new {@link module:engine/view/attributeelement~AttributeElement}.
   *
   * ```ts
   * writer.createAttributeElement( 'strong' );
   * writer.createAttributeElement( 'a', { href: 'foo.bar' } );
   *
   * // Make `<a>` element contain other attributes element so the `<a>` element is not broken.
   * writer.createAttributeElement( 'a', { href: 'foo.bar' }, { priority: 5 } );
   *
   * // Set `id` of a marker element so it is not joined or merged with "normal" elements.
   * writer.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );
   * ```
   *
   * @param name Name of the element.
   * @param attributes Element's attributes.
   * @param options Element's options.
   * @param options.priority Element's {@link module:engine/view/attributeelement~AttributeElement#priority priority}.
   * @param options.id Element's {@link module:engine/view/attributeelement~AttributeElement#id id}.
   * @param options.renderUnsafeAttributes A list of attribute names that should be rendered in the editing
   * pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
   * @returns Created element.
   */
  createAttributeElement(e, t, i = {}) {
    const s = new Et(this.document, e, t);
    return typeof i.priority == "number" && (s._priority = i.priority), i.id && (s._id = i.id), i.renderUnsafeAttributes && s._unsafeAttributesToRender.push(...i.renderUnsafeAttributes), s;
  }
  createContainerElement(e, t, i = {}, s = {}) {
    let r = null;
    de(i) ? s = i : r = i;
    const o = new Ri(this.document, e, t, r);
    return s.renderUnsafeAttributes && o._unsafeAttributesToRender.push(...s.renderUnsafeAttributes), o;
  }
  /**
   * Creates a new {@link module:engine/view/editableelement~EditableElement}.
   *
   * ```ts
   * writer.createEditableElement( 'div' );
   * writer.createEditableElement( 'div', { id: 'foo-1234' } );
   * ```
   *
   * Note: The editable element is to be used in the editing pipeline. Usually, together with
   * {@link module:widget/utils~toWidgetEditable `toWidgetEditable()`}.
   *
   * @param name Name of the element.
   * @param attributes Elements attributes.
   * @param options Element's options.
   * @param options.renderUnsafeAttributes A list of attribute names that should be rendered in the editing
   * pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
   * @returns Created element.
   */
  createEditableElement(e, t, i = {}) {
    const s = new Fn(this.document, e, t);
    return i.renderUnsafeAttributes && s._unsafeAttributesToRender.push(...i.renderUnsafeAttributes), s;
  }
  /**
   * Creates a new {@link module:engine/view/emptyelement~EmptyElement}.
   *
   * ```ts
   * writer.createEmptyElement( 'img' );
   * writer.createEmptyElement( 'img', { id: 'foo-1234' } );
   * ```
   *
   * @param name Name of the element.
   * @param attributes Elements attributes.
   * @param options Element's options.
   * @param options.renderUnsafeAttributes A list of attribute names that should be rendered in the editing
   * pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
   * @returns Created element.
   */
  createEmptyElement(e, t, i = {}) {
    const s = new Br(this.document, e, t);
    return i.renderUnsafeAttributes && s._unsafeAttributesToRender.push(...i.renderUnsafeAttributes), s;
  }
  /**
   * Creates a new {@link module:engine/view/uielement~UIElement}.
   *
   * ```ts
   * writer.createUIElement( 'span' );
   * writer.createUIElement( 'span', { id: 'foo-1234' } );
   * ```
   *
   * A custom render function can be provided as the third parameter:
   *
   * ```ts
   * writer.createUIElement( 'span', null, function( domDocument ) {
   * 	const domElement = this.toDomElement( domDocument );
   * 	domElement.innerHTML = '<b>this is ui element</b>';
   *
   * 	return domElement;
   * } );
   * ```
   *
   * Unlike {@link #createRawElement raw elements}, UI elements are by no means editor content, for instance,
   * they are ignored by the editor selection system.
   *
   * You should not use UI elements as data containers. Check out {@link #createRawElement} instead.
   *
   * @param name The name of the element.
   * @param attributes Element attributes.
   * @param renderFunction A custom render function.
   * @returns The created element.
   */
  createUIElement(e, t, i) {
    const s = new Nn(this.document, e, t);
    return i && (s.render = i), s;
  }
  /**
   * Creates a new {@link module:engine/view/rawelement~RawElement}.
   *
   * ```ts
   * writer.createRawElement( 'span', { id: 'foo-1234' }, function( domElement ) {
   * 	domElement.innerHTML = '<b>This is the raw content of the raw element.</b>';
   * } );
   * ```
   *
   * Raw elements work as data containers ("wrappers", "sandboxes") but their children are not managed or
   * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures
   * in the editor content without, for instance, worrying about compatibility with other editor features.
   * Raw elements are a perfect tool for integration with external frameworks and data sources.
   *
   * Unlike {@link #createUIElement UI elements}, raw elements act like "real" editor content (similar to
   * {@link module:engine/view/containerelement~ContainerElement} or {@link module:engine/view/emptyelement~EmptyElement}),
   * and they are considered by the editor selection.
   *
   * You should not use raw elements to render the UI in the editor content. Check out {@link #createUIElement `#createUIElement()`}
   * instead.
   *
   * @param name The name of the element.
   * @param attributes Element attributes.
   * @param renderFunction A custom render function.
   * @param options Element's options.
   * @param options.renderUnsafeAttributes A list of attribute names that should be rendered in the editing
   * pipeline even though they would normally be filtered out by unsafe attribute detection mechanisms.
   * @returns The created element.
   */
  createRawElement(e, t, i, s = {}) {
    const r = new Fr(this.document, e, t);
    return i && (r.render = i), s.renderUnsafeAttributes && r._unsafeAttributesToRender.push(...s.renderUnsafeAttributes), r;
  }
  /**
   * Adds or overwrites the element's attribute with a specified key and value.
   *
   * ```ts
   * writer.setAttribute( 'href', 'http://ckeditor.com', linkElement );
   * ```
   *
   * @param key The attribute key.
   * @param value The attribute value.
   */
  setAttribute(e, t, i) {
    i._setAttribute(e, t);
  }
  /**
   * Removes attribute from the element.
   *
   * ```ts
   * writer.removeAttribute( 'href', linkElement );
   * ```
   *
   * @param key Attribute key.
   */
  removeAttribute(e, t) {
    t._removeAttribute(e);
  }
  /**
   * Adds specified class to the element.
   *
   * ```ts
   * writer.addClass( 'foo', linkElement );
   * writer.addClass( [ 'foo', 'bar' ], linkElement );
   * ```
   */
  addClass(e, t) {
    t._addClass(e);
  }
  /**
   * Removes specified class from the element.
   *
   * ```ts
   * writer.removeClass( 'foo', linkElement );
   * writer.removeClass( [ 'foo', 'bar' ], linkElement );
   * ```
   */
  removeClass(e, t) {
    t._removeClass(e);
  }
  setStyle(e, t, i) {
    de(e) && i === void 0 ? t._setStyle(e) : i._setStyle(e, t);
  }
  /**
   * Removes specified style from the element.
   *
   * ```ts
   * writer.removeStyle( 'color', element ); // Removes 'color' style.
   * writer.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.
   * ```
   *
   * **Note**: This method can work with normalized style names if
   * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.
   * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.
   */
  removeStyle(e, t) {
    t._removeStyle(e);
  }
  /**
   * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,
   * so they can be used to add special data to elements.
   */
  setCustomProperty(e, t, i) {
    i._setCustomProperty(e, t);
  }
  /**
   * Removes a custom property stored under the given key.
   *
   * @returns Returns true if property was removed.
   */
  removeCustomProperty(e, t) {
    return t._removeCustomProperty(e);
  }
  /**
   * Breaks attribute elements at the provided position or at the boundaries of a provided range. It breaks attribute elements
   * up to their first ancestor that is a container element.
   *
   * In following examples `<p>` is a container, `<b>` and `<u>` are attribute elements:
   *
   * ```html
   * <p>foo<b><u>bar{}</u></b></p> -> <p>foo<b><u>bar</u></b>[]</p>
   * <p>foo<b><u>{}bar</u></b></p> -> <p>foo{}<b><u>bar</u></b></p>
   * <p>foo<b><u>b{}ar</u></b></p> -> <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>
   * <p><b>fo{o</b><u>ba}r</u></p> -> <p><b>fo</b><b>o</b><u>ba</u><u>r</u></b></p>
   * ```
   *
   * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.
   *
   * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and
   * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all
   * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,
   * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.
   * `breakContainer()` assumes that a given `position` is directly in the container element and breaks that container element.
   *
   * Throws the `view-writer-invalid-range-container` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
   * when the {@link module:engine/view/range~Range#start start}
   * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.
   *
   * Throws the `view-writer-cannot-break-empty-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
   * when trying to break attributes inside an {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.
   *
   * Throws the `view-writer-cannot-break-ui-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
   * when trying to break attributes inside a {@link module:engine/view/uielement~UIElement UIElement}.
   *
   * @see module:engine/view/attributeelement~AttributeElement
   * @see module:engine/view/containerelement~ContainerElement
   * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer
   * @param positionOrRange The position where to break attribute elements.
   * @returns The new position or range, after breaking the attribute elements.
   */
  breakAttributes(e) {
    return e instanceof v ? this._breakAttributes(e) : this._breakAttributesRange(e);
  }
  /**
   * Breaks a {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position.
   * The position has to be directly inside the container element and cannot be in the root. It does not break the conrainer view element
   * if the position is at the beginning or at the end of its parent element.
   *
   * ```html
   * <p>foo^bar</p> -> <p>foo</p><p>bar</p>
   * <div><p>foo</p>^<p>bar</p></div> -> <div><p>foo</p></div><div><p>bar</p></div>
   * <p>^foobar</p> -> ^<p>foobar</p>
   * <p>foobar^</p> -> <p>foobar</p>^
   * ```
   *
   * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and
   * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all
   * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,
   * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.
   * `breakContainer()` assumes that the given `position` is directly in the container element and breaks that container element.
   *
   * @see module:engine/view/attributeelement~AttributeElement
   * @see module:engine/view/containerelement~ContainerElement
   * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes
   * @param position The position where to break the element.
   * @returns The position between broken elements. If an element has not been broken,
   * the returned position is placed either before or after it.
   */
  breakContainer(e) {
    const t = e.parent;
    if (!t.is("containerElement"))
      throw new d("view-writer-break-non-container-element", this.document);
    if (!t.parent)
      throw new d("view-writer-break-root", this.document);
    if (e.isAtStart)
      return v._createBefore(t);
    if (!e.isAtEnd) {
      const i = t._clone(!1);
      this.insert(v._createAfter(t), i);
      const s = new P(e, v._createAt(t, "end")), r = new v(i, 0);
      this.move(s, r);
    }
    return v._createAfter(t);
  }
  /**
   * Merges {@link module:engine/view/attributeelement~AttributeElement attribute elements}. It also merges text nodes if needed.
   * Only {@link module:engine/view/attributeelement~AttributeElement#isSimilar similar} attribute elements can be merged.
   *
   * In following examples `<p>` is a container and `<b>` is an attribute element:
   *
   * ```html
   * <p>foo[]bar</p> -> <p>foo{}bar</p>
   * <p><b>foo</b>[]<b>bar</b></p> -> <p><b>foo{}bar</b></p>
   * <p><b foo="bar">a</b>[]<b foo="baz">b</b></p> -> <p><b foo="bar">a</b>[]<b foo="baz">b</b></p>
   * ```
   *
   * It will also take care about empty attributes when merging:
   *
   * ```html
   * <p><b>[]</b></p> -> <p>[]</p>
   * <p><b>foo</b><i>[]</i><b>bar</b></p> -> <p><b>foo{}bar</b></p>
   * ```
   *
   * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and
   * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two
   * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}
   * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.
   *
   * @see module:engine/view/attributeelement~AttributeElement
   * @see module:engine/view/containerelement~ContainerElement
   * @see module:engine/view/downcastwriter~DowncastWriter#mergeContainers
   * @param position Merge position.
   * @returns Position after merge.
   */
  mergeAttributes(e) {
    const t = e.offset, i = e.parent;
    if (i.is("$text"))
      return e;
    if (i.is("attributeElement") && i.childCount === 0) {
      const o = i.parent, a = i.index;
      return i._remove(), this._removeFromClonedElementsGroup(i), this.mergeAttributes(new v(o, a));
    }
    const s = i.getChild(t - 1), r = i.getChild(t);
    if (!s || !r)
      return e;
    if (s.is("$text") && r.is("$text"))
      return ga(s, r);
    if (s.is("attributeElement") && r.is("attributeElement") && s.isSimilar(r)) {
      const o = s.childCount;
      return s._appendChild(r.getChildren()), r._remove(), this._removeFromClonedElementsGroup(r), this.mergeAttributes(new v(s, o));
    }
    return e;
  }
  /**
   * Merges two {@link module:engine/view/containerelement~ContainerElement container elements} that are before and after given position.
   * Precisely, the element after the position is removed and it's contents are moved to element before the position.
   *
   * ```html
   * <p>foo</p>^<p>bar</p> -> <p>foo^bar</p>
   * <div>foo</div>^<p>bar</p> -> <div>foo^bar</div>
   * ```
   *
   * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and
   * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two
   * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}
   * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.
   *
   * @see module:engine/view/attributeelement~AttributeElement
   * @see module:engine/view/containerelement~ContainerElement
   * @see module:engine/view/downcastwriter~DowncastWriter#mergeAttributes
   * @param position Merge position.
   * @returns Position after merge.
   */
  mergeContainers(e) {
    const t = e.nodeBefore, i = e.nodeAfter;
    if (!t || !i || !t.is("containerElement") || !i.is("containerElement"))
      throw new d("view-writer-merge-containers-invalid-position", this.document);
    const s = t.getChild(t.childCount - 1), r = s instanceof j ? v._createAt(s, "end") : v._createAt(t, "end");
    return this.move(P._createIn(i), v._createAt(t, "end")), this.remove(P._createOn(i)), r;
  }
  /**
   * Inserts a node or nodes at specified position. Takes care about breaking attributes before insertion
   * and merging them afterwards.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert
   * contains instances that are not {@link module:engine/view/text~Text Texts},
   * {@link module:engine/view/attributeelement~AttributeElement AttributeElements},
   * {@link module:engine/view/containerelement~ContainerElement ContainerElements},
   * {@link module:engine/view/emptyelement~EmptyElement EmptyElements},
   * {@link module:engine/view/rawelement~RawElement RawElements} or
   * {@link module:engine/view/uielement~UIElement UIElements}.
   *
   * @param position Insertion position.
   * @param nodes Node or nodes to insert.
   * @returns Range around inserted nodes.
   */
  insert(e, t) {
    t = _e(t) ? [...t] : [t], Fu(t, this.document);
    const i = t.reduce((o, a) => {
      const l = o[o.length - 1], c = !a.is("uiElement");
      return !l || l.breakAttributes != c ? o.push({
        breakAttributes: c,
        nodes: [a]
      }) : l.nodes.push(a), o;
    }, []);
    let s = null, r = e;
    for (const { nodes: o, breakAttributes: a } of i) {
      const l = this._insertNodes(r, o, a);
      s || (s = l.start), r = l.end;
    }
    return s ? new P(s, r) : new P(e);
  }
  /**
   * Removes provided range from the container.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when
   * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside
   * same parent container.
   *
   * @param rangeOrItem Range to remove from container
   * or an {@link module:engine/view/item~Item item} to remove. If range is provided, after removing, it will be updated
   * to a collapsed range showing the new position.
   * @returns Document fragment containing removed nodes.
   */
  remove(e) {
    const t = e instanceof P ? e : P._createOn(e);
    if (pi(t, this.document), t.isCollapsed)
      return new At(this.document);
    const { start: i, end: s } = this._breakAttributesRange(t, !0), r = i.parent, o = s.offset - i.offset, a = r._removeChildren(i.offset, o);
    for (const c of a)
      this._removeFromClonedElementsGroup(c);
    const l = this.mergeAttributes(i);
    return t.start = l, t.end = l.clone(), new At(this.document, a);
  }
  /**
   * Removes matching elements from given range.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when
   * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside
   * same parent container.
   *
   * @param range Range to clear.
   * @param element Element to remove.
   */
  clear(e, t) {
    pi(e, this.document);
    const i = e.getWalker({
      direction: "backward",
      ignoreElementEnd: !0
    });
    for (const s of i) {
      const r = s.item;
      let o;
      if (r.is("element") && t.isSimilar(r))
        o = P._createOn(r);
      else if (!s.nextPosition.isAfter(e.start) && r.is("$textProxy")) {
        const a = r.getAncestors().find((l) => l.is("element") && t.isSimilar(l));
        a && (o = P._createIn(a));
      }
      o && (o.end.isAfter(e.end) && (o.end = e.end), o.start.isBefore(e.start) && (o.start = e.start), this.remove(o));
    }
  }
  /**
   * Moves nodes from provided range to target position.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when
   * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside
   * same parent container.
   *
   * @param sourceRange Range containing nodes to move.
   * @param targetPosition Position to insert.
   * @returns Range in target container. Inserted nodes are placed between
   * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions.
   */
  move(e, t) {
    let i;
    if (t.isAfter(e.end)) {
      t = this._breakAttributes(t, !0);
      const s = t.parent, r = s.childCount;
      e = this._breakAttributesRange(e, !0), i = this.remove(e), t.offset += s.childCount - r;
    } else
      i = this.remove(e);
    return this.insert(t, i);
  }
  /**
   * Wraps elements within range with provided {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.
   * If a collapsed range is provided, it will be wrapped only if it is equal to view selection.
   *
   * If a collapsed range was passed and is same as selection, the selection
   * will be moved to the inside of the wrapped attribute element.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-invalid-range-container`
   * when {@link module:engine/view/range~Range#start}
   * and {@link module:engine/view/range~Range#end} positions are not placed inside same parent container.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not
   * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range
   * is collapsed and different than view selection.
   *
   * @param range Range to wrap.
   * @param attribute Attribute element to use as wrapper.
   * @returns range Range after wrapping, spanning over wrapping attribute element.
   */
  wrap(e, t) {
    if (!(t instanceof Et))
      throw new d("view-writer-wrap-invalid-attribute", this.document);
    if (pi(e, this.document), e.isCollapsed) {
      let i = e.start;
      i.parent.is("element") && !P1(i.parent) && (i = i.getLastMatchingPosition((r) => r.item.is("uiElement"))), i = this._wrapPosition(i, t);
      const s = this.document.selection;
      return s.isCollapsed && s.getFirstPosition().isEqual(e.start) && this.setSelection(i), new P(i);
    } else
      return this._wrapRange(e, t);
  }
  /**
   * Unwraps nodes within provided range from attribute element.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when
   * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside
   * same parent container.
   */
  unwrap(e, t) {
    if (!(t instanceof Et))
      throw new d("view-writer-unwrap-invalid-attribute", this.document);
    if (pi(e, this.document), e.isCollapsed)
      return e;
    const { start: i, end: s } = this._breakAttributesRange(e, !0), r = i.parent, o = this._unwrapChildren(r, i.offset, s.offset, t), a = this.mergeAttributes(o.start);
    a.isEqual(o.start) || o.end.offset--;
    const l = this.mergeAttributes(o.end);
    return new P(a, l);
  }
  /**
   * Renames element by creating a copy of renamed element but with changed name and then moving contents of the
   * old element to the new one. Keep in mind that this will invalidate all {@link module:engine/view/position~Position positions} which
   * has renamed element as {@link module:engine/view/position~Position#parent a parent}.
   *
   * New element has to be created because `Element#tagName` property in DOM is readonly.
   *
   * Since this function creates a new element and removes the given one, the new element is returned to keep reference.
   *
   * @param newName New name for element.
   * @param viewElement Element to be renamed.
   * @returns Element created due to rename.
   */
  rename(e, t) {
    const i = new Ri(this.document, e, t.getAttributes());
    return this.insert(v._createAfter(t), i), this.move(P._createIn(t), v._createAt(i, 0)), this.remove(P._createOn(t)), i;
  }
  /**
   * Cleans up memory by removing obsolete cloned elements group from the writer.
   *
   * Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}
   * with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and
   * the group will no longer be needed.
   *
   * Cloned elements group are not removed automatically in case if the group is still needed after all its elements
   * were removed from the view.
   *
   * Keep in mind that group names are equal to the `id` property of the attribute element.
   *
   * @param groupName Name of the group to clear.
   */
  clearClonedElementsGroup(e) {
    this._cloneGroups.delete(e);
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/view/position~Position position},
   * * parent element and offset (offset defaults to `0`),
   * * parent element and `'end'` (sets position at the end of that element),
   * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
   *
   * This method is a shortcut to other constructors such as:
   *
   * * {@link #createPositionBefore},
   * * {@link #createPositionAfter},
   *
   * @param offset Offset or one of the flags. Used only when the first parameter is a {@link module:engine/view/item~Item view item}.
   */
  createPositionAt(e, t) {
    return v._createAt(e, t);
  }
  /**
   * Creates a new position after given view item.
   *
   * @param item View item after which the position should be located.
   */
  createPositionAfter(e) {
    return v._createAfter(e);
  }
  /**
   * Creates a new position before given view item.
   *
   * @param item View item before which the position should be located.
   */
  createPositionBefore(e) {
    return v._createBefore(e);
  }
  /**
   * Creates a range spanning from `start` position to `end` position.
   *
   * **Note:** This factory method creates its own {@link module:engine/view/position~Position} instances basing on passed values.
   *
   * @param start Start position.
   * @param end End position. If not set, range will be collapsed at `start` position.
   */
  createRange(e, t) {
    return new P(e, t);
  }
  /**
   * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
   */
  createRangeOn(e) {
    return P._createOn(e);
  }
  /**
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * @param element Element which is a parent for the range.
   */
  createRangeIn(e) {
    return P._createIn(e);
  }
  createSelection(...e) {
    return new ct(...e);
  }
  /**
   * Creates placeholders for child elements of the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
   * `elementToStructure()`} conversion helper.
   *
   * ```ts
   * const viewSlot = conversionApi.writer.createSlot();
   * const viewPosition = conversionApi.writer.createPositionAt( viewElement, 0 );
   *
   * conversionApi.writer.insert( viewPosition, viewSlot );
   * ```
   *
   * It could be filtered down to a specific subset of children (only `<foo>` model elements in this case):
   *
   * ```ts
   * const viewSlot = conversionApi.writer.createSlot( node => node.is( 'element', 'foo' ) );
   * const viewPosition = conversionApi.writer.createPositionAt( viewElement, 0 );
   *
   * conversionApi.writer.insert( viewPosition, viewSlot );
   * ```
   *
   * While providing a filtered slot, make sure to provide slots for all child nodes. A single node can not be downcasted into
   * multiple slots.
   *
   * **Note**: You should not change the order of nodes. View elements should be in the same order as model nodes.
   *
   * @param modeOrFilter The filter for child nodes.
   * @returns The slot element to be placed in to the view structure while processing
   * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure `elementToStructure()`}.
   */
  createSlot(e = "children") {
    if (!this._slotFactory)
      throw new d("view-writer-invalid-create-slot-context", this.document);
    return this._slotFactory(this, e);
  }
  /**
   * Registers a slot factory.
   *
   * @internal
   * @param slotFactory The slot factory.
   */
  _registerSlotFactory(e) {
    this._slotFactory = e;
  }
  /**
   * Clears the registered slot factory.
   *
   * @internal
   */
  _clearSlotFactory() {
    this._slotFactory = null;
  }
  /**
   * Inserts a node or nodes at the specified position. Takes care of breaking attributes before insertion
   * and merging them afterwards if requested by the breakAttributes param.
   *
   * @param position Insertion position.
   * @param nodes Node or nodes to insert.
   * @param breakAttributes Whether attributes should be broken.
   * @returns Range around inserted nodes.
   */
  _insertNodes(e, t, i) {
    let s;
    if (i ? s = Gs(e) : s = e.parent.is("$text") ? e.parent.parent : e.parent, !s)
      throw new d("view-writer-invalid-position-container", this.document);
    let r;
    i ? r = this._breakAttributes(e, !0) : r = e.parent.is("$text") ? ns(e) : e;
    const o = s._insertChild(r.offset, t);
    for (const u of t)
      this._addToClonedElementsGroup(u);
    const a = r.getShiftedBy(o), l = this.mergeAttributes(r);
    l.isEqual(r) || a.offset--;
    const c = this.mergeAttributes(a);
    return new P(l, c);
  }
  /**
   * Wraps children with provided `wrapElement`. Only children contained in `parent` element between
   * `startOffset` and `endOffset` will be wrapped.
   */
  _wrapChildren(e, t, i, s) {
    let r = t;
    const o = [];
    for (; r < i; ) {
      const l = e.getChild(r), c = l.is("$text"), u = l.is("attributeElement");
      if (u && this._wrapAttributeElement(s, l))
        o.push(new v(e, r));
      else if (c || !u || x1(s, l)) {
        const h = s._clone();
        l._remove(), h._appendChild(l), e._insertChild(r, h), this._addToClonedElementsGroup(h), o.push(new v(e, r));
      } else
        this._wrapChildren(l, 0, l.childCount, s);
      r++;
    }
    let a = 0;
    for (const l of o) {
      if (l.offset -= a, l.offset == t)
        continue;
      this.mergeAttributes(l).isEqual(l) || (a++, i--);
    }
    return P._createFromParentsAndOffsets(e, t, e, i);
  }
  /**
   * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between
   * `startOffset` and `endOffset` will be unwrapped.
   */
  _unwrapChildren(e, t, i, s) {
    let r = t;
    const o = [];
    for (; r < i; ) {
      const l = e.getChild(r);
      if (!l.is("attributeElement")) {
        r++;
        continue;
      }
      if (l.isSimilar(s)) {
        const c = l.getChildren(), u = l.childCount;
        l._remove(), e._insertChild(r, c), this._removeFromClonedElementsGroup(l), o.push(new v(e, r), new v(e, r + u)), r += u, i += u - 1;
        continue;
      }
      if (this._unwrapAttributeElement(s, l)) {
        o.push(new v(e, r), new v(e, r + 1)), r++;
        continue;
      }
      this._unwrapChildren(l, 0, l.childCount, s), r++;
    }
    let a = 0;
    for (const l of o) {
      if (l.offset -= a, l.offset == t || l.offset == i)
        continue;
      this.mergeAttributes(l).isEqual(l) || (a++, i--);
    }
    return P._createFromParentsAndOffsets(e, t, e, i);
  }
  /**
   * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.
   * This method will also merge newly added attribute element with its siblings whenever possible.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not
   * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.
   *
   * @returns New range after wrapping, spanning over wrapping attribute element.
   */
  _wrapRange(e, t) {
    const { start: i, end: s } = this._breakAttributesRange(e, !0), r = i.parent, o = this._wrapChildren(r, i.offset, s.offset, t), a = this.mergeAttributes(o.start);
    a.isEqual(o.start) || o.end.offset--;
    const l = this.mergeAttributes(o.end);
    return new P(a, l);
  }
  /**
   * Helper function for {@link #wrap}. Wraps position with provided attribute element.
   * This method will also merge newly added attribute element with its siblings whenever possible.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not
   * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.
   *
   * @returns New position after wrapping.
   */
  _wrapPosition(e, t) {
    if (t.isSimilar(e.parent))
      return ma(e.clone());
    e.parent.is("$text") && (e = ns(e));
    const i = this.createAttributeElement("_wrapPosition-fake-element");
    i._priority = Number.POSITIVE_INFINITY, i.isSimilar = () => !1, e.parent._insertChild(e.offset, i);
    const s = new P(e, e.getShiftedBy(1));
    this.wrap(s, t);
    const r = new v(i.parent, i.index);
    i._remove();
    const o = r.nodeBefore, a = r.nodeAfter;
    return o instanceof j && a instanceof j ? ga(o, a) : ma(r);
  }
  /**
   * Wraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by
   * merging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper
   * element to element being wrapped.
   *
   * @param wrapper Wrapper AttributeElement.
   * @param toWrap AttributeElement to wrap using wrapper element.
   * @returns Returns `true` if elements are merged.
   */
  _wrapAttributeElement(e, t) {
    if (!pa(e, t) || e.name !== t.name || e.priority !== t.priority)
      return !1;
    for (const i of e.getAttributeKeys())
      if (!(i === "class" || i === "style") && t.hasAttribute(i) && t.getAttribute(i) !== e.getAttribute(i))
        return !1;
    for (const i of e.getStyleNames())
      if (t.hasStyle(i) && t.getStyle(i) !== e.getStyle(i))
        return !1;
    for (const i of e.getAttributeKeys())
      i === "class" || i === "style" || t.hasAttribute(i) || this.setAttribute(i, e.getAttribute(i), t);
    for (const i of e.getStyleNames())
      t.hasStyle(i) || this.setStyle(i, e.getStyle(i), t);
    for (const i of e.getClassNames())
      t.hasClass(i) || this.addClass(i, t);
    return !0;
  }
  /**
   * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing
   * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present
   * inside element being unwrapped.
   *
   * @param wrapper Wrapper AttributeElement.
   * @param toUnwrap AttributeElement to unwrap using wrapper element.
   * @returns Returns `true` if elements are unwrapped.
   **/
  _unwrapAttributeElement(e, t) {
    if (!pa(e, t) || e.name !== t.name || e.priority !== t.priority)
      return !1;
    for (const i of e.getAttributeKeys())
      if (!(i === "class" || i === "style") && (!t.hasAttribute(i) || t.getAttribute(i) !== e.getAttribute(i)))
        return !1;
    if (!t.hasClass(...e.getClassNames()))
      return !1;
    for (const i of e.getStyleNames())
      if (!t.hasStyle(i) || t.getStyle(i) !== e.getStyle(i))
        return !1;
    for (const i of e.getAttributeKeys())
      i === "class" || i === "style" || this.removeAttribute(i, t);
    return this.removeClass(Array.from(e.getClassNames()), t), this.removeStyle(Array.from(e.getStyleNames()), t), !0;
  }
  /**
   * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.
   *
   * @param range Range which `start` and `end` positions will be used to break attributes.
   * @param forceSplitText If set to `true`, will break text nodes even if they are directly in container element.
   * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.
   * @returns New range with located at break positions.
   */
  _breakAttributesRange(e, t = !1) {
    const i = e.start, s = e.end;
    if (pi(e, this.document), e.isCollapsed) {
      const l = this._breakAttributes(e.start, t);
      return new P(l, l);
    }
    const r = this._breakAttributes(s, t), o = r.parent.childCount, a = this._breakAttributes(i, t);
    return r.offset += r.parent.childCount - o, new P(a, r);
  }
  /**
   * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position
   * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position
   * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.
   *
   * @param position Position where to break attributes.
   * @param forceSplitText If set to `true`, will break text nodes even if they are directly in container element.
   * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.
   * @returns New position after breaking the attributes.
   */
  _breakAttributes(e, t = !1) {
    const i = e.offset, s = e.parent;
    if (e.parent.is("emptyElement"))
      throw new d("view-writer-cannot-break-empty-element", this.document);
    if (e.parent.is("uiElement"))
      throw new d("view-writer-cannot-break-ui-element", this.document);
    if (e.parent.is("rawElement"))
      throw new d("view-writer-cannot-break-raw-element", this.document);
    if (!t && s.is("$text") && Ks(s.parent) || Ks(s))
      return e.clone();
    if (s.is("$text"))
      return this._breakAttributes(ns(e), t);
    const r = s.childCount;
    if (i == r) {
      const o = new v(s.parent, s.index + 1);
      return this._breakAttributes(o, t);
    } else if (i === 0) {
      const o = new v(s.parent, s.index);
      return this._breakAttributes(o, t);
    } else {
      const o = s.index + 1, a = s._clone();
      s.parent._insertChild(o, a), this._addToClonedElementsGroup(a);
      const l = s.childCount - i, c = s._removeChildren(i, l);
      a._appendChild(c);
      const u = new v(s.parent, o);
      return this._breakAttributes(u, t);
    }
  }
  /**
   * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was
   * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements
   * from the group now keep a reference to the given attribute element.
   *
   * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.
   *
   * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.
   *
   * @param element Attribute element to save.
   */
  _addToClonedElementsGroup(e) {
    if (!e.root.is("rootElement"))
      return;
    if (e.is("element"))
      for (const s of e.getChildren())
        this._addToClonedElementsGroup(s);
    const t = e.id;
    if (!t)
      return;
    let i = this._cloneGroups.get(t);
    i || (i = /* @__PURE__ */ new Set(), this._cloneGroups.set(t, i)), i.add(e), e._clonesGroup = i;
  }
  /**
   * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}
   * from its clones group.
   *
   * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).
   * This allows to reference the whole group even if the element was already removed from the tree.
   *
   * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.
   *
   * @param element Attribute element to remove.
   */
  _removeFromClonedElementsGroup(e) {
    if (e.is("element"))
      for (const s of e.getChildren())
        this._removeFromClonedElementsGroup(s);
    const t = e.id;
    if (!t)
      return;
    const i = this._cloneGroups.get(t);
    i && i.delete(e);
  }
}
function P1(n) {
  return Array.from(n.getChildren()).some((e) => !e.is("uiElement"));
}
function Gs(n) {
  let e = n.parent;
  for (; !Ks(e); ) {
    if (!e)
      return;
    e = e.parent;
  }
  return e;
}
function x1(n, e) {
  return n.priority < e.priority ? !0 : n.priority > e.priority ? !1 : n.getIdentity() < e.getIdentity();
}
function ma(n) {
  const e = n.nodeBefore;
  if (e && e.is("$text"))
    return new v(e, e.data.length);
  const t = n.nodeAfter;
  return t && t.is("$text") ? new v(t, 0) : n;
}
function ns(n) {
  if (n.offset == n.parent.data.length)
    return new v(n.parent.parent, n.parent.index + 1);
  if (n.offset === 0)
    return new v(n.parent.parent, n.parent.index);
  const e = n.parent.data.slice(n.offset);
  return n.parent._data = n.parent.data.slice(0, n.offset), n.parent.parent._insertChild(n.parent.index + 1, new j(n.root.document, e)), new v(n.parent.parent, n.parent.index + 1);
}
function ga(n, e) {
  const t = n.data.length;
  return n._data += e.data, e._remove(), new v(n, t);
}
const S1 = [j, Et, Ri, Br, Fr, Nn];
function Fu(n, e) {
  for (const t of n) {
    if (!S1.some((i) => t instanceof i))
      throw new d("view-writer-insert-invalid-node-type", e);
    t.is("$text") || Fu(t.getChildren(), e);
  }
}
function Ks(n) {
  return n && (n.is("containerElement") || n.is("documentFragment"));
}
function pi(n, e) {
  const t = Gs(n.start), i = Gs(n.end);
  if (!t || !i || t !== i)
    throw new d("view-writer-invalid-range-container", e);
}
function pa(n, e) {
  return n.id === null && e.id === null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Nu = (n) => n.createTextNode(" "), Lu = (n) => {
  const e = n.createElement("span");
  return e.dataset.ckeFiller = "true", e.innerText = " ", e;
}, $u = (n) => {
  const e = n.createElement("br");
  return e.dataset.ckeFiller = "true", e;
}, Fe = 7, _n = "⁠".repeat(Fe);
function pe(n) {
  return J(n) && n.data.substr(0, Fe) === _n;
}
function _i(n) {
  return n.data.length == Fe && pe(n);
}
function wa(n) {
  return pe(n) ? n.data.slice(Fe) : n.data;
}
function I1(n) {
  n.document.on("arrowKey", R1, { priority: "low" });
}
function R1(n, e) {
  if (e.keyCode == R.arrowleft) {
    const t = e.domTarget.ownerDocument.defaultView.getSelection();
    if (t.rangeCount == 1 && t.getRangeAt(0).collapsed) {
      const i = t.getRangeAt(0).startContainer, s = t.getRangeAt(0).startOffset;
      pe(i) && s <= Fe && t.collapse(i, 0);
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class O1 extends z() {
  /**
   * Creates a renderer instance.
   *
   * @param domConverter Converter instance.
   * @param selection View selection.
   */
  constructor(e, t) {
    super(), this.domDocuments = /* @__PURE__ */ new Set(), this.markedAttributes = /* @__PURE__ */ new Set(), this.markedChildren = /* @__PURE__ */ new Set(), this.markedTexts = /* @__PURE__ */ new Set(), this._inlineFiller = null, this._fakeSelectionContainer = null, this.domConverter = e, this.selection = t, this.set("isFocused", !1), this.set("isSelecting", !1), S.isBlink && !S.isAndroid && this.on("change:isSelecting", () => {
      this.isSelecting || this.render();
    }), this.set("isComposing", !1), this.on("change:isComposing", () => {
      this.isComposing || this.render();
    });
  }
  /**
   * Marks a view node to be updated in the DOM by {@link #render `render()`}.
   *
   * Note that only view nodes whose parents have corresponding DOM elements need to be marked to be synchronized.
   *
   * @see #markedAttributes
   * @see #markedChildren
   * @see #markedTexts
   *
   * @param type Type of the change.
   * @param node ViewNode to be marked.
   */
  markToSync(e, t) {
    if (e === "text")
      this.domConverter.mapViewToDom(t.parent) && this.markedTexts.add(t);
    else {
      if (!this.domConverter.mapViewToDom(t))
        return;
      if (e === "attributes")
        this.markedAttributes.add(t);
      else if (e === "children")
        this.markedChildren.add(t);
      else
        throw new d("view-renderer-unknown-type", this);
    }
  }
  /**
   * Renders all buffered changes ({@link #markedAttributes}, {@link #markedChildren} and {@link #markedTexts}) and
   * the current view selection (if needed) to the DOM by applying a minimal set of changes to it.
   *
   * Renderer tries not to break the text composition (e.g. IME) and x-index of the selection,
   * so it does as little as it is needed to update the DOM.
   *
   * Renderer also handles {@link module:engine/view/filler fillers}. Especially, it checks if the inline filler is needed
   * at the selection position and adds or removes it. To prevent breaking text composition inline filler will not be
   * removed as long as the selection is in the text node which needed it at first.
   */
  render() {
    if (this.isComposing && !S.isAndroid)
      return;
    let e = null;
    const t = S.isBlink && !S.isAndroid ? !this.isSelecting : !0;
    for (const i of this.markedChildren)
      this._updateChildrenMappings(i);
    t ? (this._inlineFiller && !this._isSelectionInInlineFiller() && this._removeInlineFiller(), this._inlineFiller ? e = this._getInlineFillerPosition() : this._needsInlineFillerAtSelection() && (e = this.selection.getFirstPosition(), this.markedChildren.add(e.parent))) : this._inlineFiller && this._inlineFiller.parentNode && (e = this.domConverter.domPositionToView(this._inlineFiller), e && e.parent.is("$text") && (e = v._createBefore(e.parent)));
    for (const i of this.markedAttributes)
      this._updateAttrs(i);
    for (const i of this.markedChildren)
      this._updateChildren(i, { inlineFillerPosition: e });
    for (const i of this.markedTexts)
      !this.markedChildren.has(i.parent) && this.domConverter.mapViewToDom(i.parent) && this._updateText(i, { inlineFillerPosition: e });
    if (t)
      if (e) {
        const i = this.domConverter.viewPositionToDom(e), s = i.parent.ownerDocument;
        pe(i.parent) ? this._inlineFiller = i.parent : this._inlineFiller = ba(s, i.parent, i.offset);
      } else
        this._inlineFiller = null;
    this._updateFocus(), this._updateSelection(), this.markedTexts.clear(), this.markedAttributes.clear(), this.markedChildren.clear();
  }
  /**
   * Updates mappings of view element's children.
   *
   * Children that were replaced in the view structure by similar elements (same tag name) are treated as 'replaced'.
   * This means that their mappings can be updated so the new view elements are mapped to the existing DOM elements.
   * Thanks to that these elements do not need to be re-rendered completely.
   *
   * @param viewElement The view element whose children mappings will be updated.
   */
  _updateChildrenMappings(e) {
    if (!this.domConverter.mapViewToDom(e))
      return;
    const i = Array.from(this.domConverter.mapViewToDom(e).childNodes), s = Array.from(this.domConverter.viewChildrenToDom(e, { withChildren: !1 })), r = this._diffNodeLists(i, s), o = this._findUpdateActions(r, i, s, V1);
    if (o.indexOf("update") !== -1) {
      const a = { equal: 0, insert: 0, delete: 0 };
      for (const l of o)
        if (l === "update") {
          const c = a.equal + a.insert, u = a.equal + a.delete, h = e.getChild(c);
          h && !(h.is("uiElement") || h.is("rawElement")) && this._updateElementMappings(h, i[u]), na(s[c]), a.equal++;
        } else
          a[l]++;
    }
  }
  /**
   * Updates mappings of a given view element.
   *
   * @param viewElement The view element whose mappings will be updated.
   * @param domElement The DOM element representing the given view element.
   */
  _updateElementMappings(e, t) {
    this.domConverter.unbindDomElement(t), this.domConverter.bindElements(t, e), this.markedChildren.add(e), this.markedAttributes.add(e);
  }
  /**
   * Gets the position of the inline filler based on the current selection.
   * Here, we assume that we know that the filler is needed and
   * {@link #_isSelectionInInlineFiller is at the selection position}, and, since it is needed,
   * it is somewhere at the selection position.
   *
   * Note: The filler position cannot be restored based on the filler's DOM text node, because
   * when this method is called (before rendering), the bindings will often be broken. View-to-DOM
   * bindings are only dependable after rendering.
   */
  _getInlineFillerPosition() {
    const e = this.selection.getFirstPosition();
    return e.parent.is("$text") ? v._createBefore(e.parent) : e;
  }
  /**
   * Returns `true` if the selection has not left the inline filler's text node.
   * If it is `true`, it means that the filler had been added for a reason and the selection did not
   * leave the filler's text node. For example, the user can be in the middle of a composition so it should not be touched.
   *
   * @returns `true` if the inline filler and selection are in the same place.
   */
  _isSelectionInInlineFiller() {
    if (this.selection.rangeCount != 1 || !this.selection.isCollapsed)
      return !1;
    const e = this.selection.getFirstPosition(), t = this.domConverter.viewPositionToDom(e);
    return !!(t && J(t.parent) && pe(t.parent));
  }
  /**
   * Removes the inline filler.
   */
  _removeInlineFiller() {
    const e = this._inlineFiller;
    if (!pe(e))
      throw new d("view-renderer-filler-was-lost", this);
    _i(e) ? e.remove() : e.data = e.data.substr(Fe), this._inlineFiller = null;
  }
  /**
   * Checks if the inline {@link module:engine/view/filler filler} should be added.
   *
   * @returns `true` if the inline filler should be added.
   */
  _needsInlineFillerAtSelection() {
    if (this.selection.rangeCount != 1 || !this.selection.isCollapsed)
      return !1;
    const e = this.selection.getFirstPosition(), t = e.parent, i = e.offset;
    if (!this.domConverter.mapViewToDom(t.root) || !t.is("element") || !M1(t) || i === t.getFillerOffset())
      return !1;
    const s = e.nodeBefore, r = e.nodeAfter;
    return !(s instanceof j || r instanceof j || S.isAndroid && (s || r));
  }
  /**
   * Checks if text needs to be updated and possibly updates it.
   *
   * @param viewText View text to update.
   * @param options.inlineFillerPosition The position where the inline filler should be rendered.
   */
  _updateText(e, t) {
    const i = this.domConverter.findCorrespondingDomText(e);
    let r = this.domConverter.viewToDom(e).data;
    const o = t.inlineFillerPosition;
    o && o.parent == e.parent && o.offset == e.index && (r = _n + r), _a(i, r);
  }
  /**
   * Checks if attribute list needs to be updated and possibly updates it.
   *
   * @param viewElement The view element to update.
   */
  _updateAttrs(e) {
    const t = this.domConverter.mapViewToDom(e);
    if (!t)
      return;
    const i = Array.from(t.attributes).map((r) => r.name), s = e.getAttributeKeys();
    for (const r of s)
      this.domConverter.setDomElementAttribute(t, r, e.getAttribute(r), e);
    for (const r of i)
      e.hasAttribute(r) || this.domConverter.removeDomElementAttribute(t, r);
  }
  /**
   * Checks if elements child list needs to be updated and possibly updates it.
   *
   * Note that on Android, to reduce the risk of composition breaks, it tries to update data of an existing
   * child text nodes instead of replacing them completely.
   *
   * @param viewElement View element to update.
   * @param options.inlineFillerPosition The position where the inline filler should be rendered.
   */
  _updateChildren(e, t) {
    const i = this.domConverter.mapViewToDom(e);
    if (!i)
      return;
    if (S.isAndroid) {
      let h = null;
      for (const f of Array.from(i.childNodes)) {
        if (h && J(h) && J(f)) {
          i.normalize();
          break;
        }
        h = f;
      }
    }
    const s = t.inlineFillerPosition, r = i.childNodes, o = Array.from(this.domConverter.viewChildrenToDom(e, { bind: !0 }));
    s && s.parent === e && ba(i.ownerDocument, o, s.offset);
    const a = this._diffNodeLists(r, o), l = this._findUpdateActions(a, r, o, D1);
    let c = 0;
    const u = /* @__PURE__ */ new Set();
    for (const h of l)
      h === "delete" ? (u.add(r[c]), na(r[c])) : (h === "equal" || h === "update") && c++;
    c = 0;
    for (const h of l)
      h === "insert" ? (bu(i, c, o[c]), c++) : h === "update" ? (_a(r[c], o[c].data), c++) : h === "equal" && (this._markDescendantTextToSync(this.domConverter.domToView(o[c])), c++);
    for (const h of u)
      h.parentNode || this.domConverter.unbindDomElement(h);
  }
  /**
   * Shorthand for diffing two arrays or node lists of DOM nodes.
   *
   * @param actualDomChildren Actual DOM children
   * @param expectedDomChildren Expected DOM children.
   * @returns The list of actions based on the {@link module:utils/diff~diff} function.
   */
  _diffNodeLists(e, t) {
    return e = N1(e, this._fakeSelectionContainer), yi(e, t, B1.bind(null, this.domConverter));
  }
  /**
   * Finds DOM nodes that were replaced with the similar nodes (same tag name) in the view. All nodes are compared
   * within one `insert`/`delete` action group, for example:
   *
   * ```
   * Actual DOM:		<p><b>Foo</b>Bar<i>Baz</i><b>Bax</b></p>
   * Expected DOM:	<p>Bar<b>123</b><i>Baz</i><b>456</b></p>
   * Input actions:	[ insert, insert, delete, delete, equal, insert, delete ]
   * Output actions:	[ insert, replace, delete, equal, replace ]
   * ```
   *
   * @param actions Actions array which is a result of the {@link module:utils/diff~diff} function.
   * @param actualDom Actual DOM children
   * @param expectedDom Expected DOM children.
   * @param comparator A comparator function that should return `true` if the given node should be reused
   * (either by the update of a text node data or an element children list for similar elements).
   * @returns Actions array modified with the `update` actions.
   */
  _findUpdateActions(e, t, i, s) {
    if (e.indexOf("insert") === -1 || e.indexOf("delete") === -1)
      return e;
    let r = [], o = [], a = [];
    const l = { equal: 0, insert: 0, delete: 0 };
    for (const c of e)
      c === "insert" ? a.push(i[l.equal + l.insert]) : c === "delete" ? o.push(t[l.equal + l.delete]) : (r = r.concat(yi(o, a, s).map((u) => u === "equal" ? "update" : u)), r.push("equal"), o = [], a = []), l[c]++;
    return r.concat(yi(o, a, s).map((c) => c === "equal" ? "update" : c));
  }
  /**
   * Marks text nodes to be synchronized.
   *
   * If a text node is passed, it will be marked. If an element is passed, all descendant text nodes inside it will be marked.
   *
   * @param viewNode View node to sync.
   */
  _markDescendantTextToSync(e) {
    if (e) {
      if (e.is("$text"))
        this.markedTexts.add(e);
      else if (e.is("element"))
        for (const t of e.getChildren())
          this._markDescendantTextToSync(t);
    }
  }
  /**
   * Checks if the selection needs to be updated and possibly updates it.
   */
  _updateSelection() {
    if (S.isBlink && !S.isAndroid && this.isSelecting && !this.markedChildren.size)
      return;
    if (this.selection.rangeCount === 0) {
      this._removeDomSelection(), this._removeFakeSelection();
      return;
    }
    const e = this.domConverter.mapViewToDom(this.selection.editableElement);
    !this.isFocused || !e || (this.selection.isFake ? this._updateFakeSelection(e) : this._fakeSelectionContainer && this._fakeSelectionContainer.isConnected ? (this._removeFakeSelection(), this._updateDomSelection(e)) : this.isComposing && S.isAndroid || this._updateDomSelection(e));
  }
  /**
   * Updates the fake selection.
   *
   * @param domRoot A valid DOM root where the fake selection container should be added.
   */
  _updateFakeSelection(e) {
    const t = e.ownerDocument;
    this._fakeSelectionContainer || (this._fakeSelectionContainer = L1(t));
    const i = this._fakeSelectionContainer;
    if (this.domConverter.bindFakeSelection(i, this.selection), !this._fakeSelectionNeedsUpdate(e))
      return;
    (!i.parentElement || i.parentElement != e) && e.appendChild(i), i.textContent = this.selection.fakeSelectionLabel || " ";
    const s = t.getSelection(), r = t.createRange();
    s.removeAllRanges(), r.selectNodeContents(i), s.addRange(r);
  }
  /**
   * Updates the DOM selection.
   *
   * @param domRoot A valid DOM root where the DOM selection should be rendered.
   */
  _updateDomSelection(e) {
    const t = e.ownerDocument.defaultView.getSelection();
    if (!this._domSelectionNeedsUpdate(t))
      return;
    const i = this.domConverter.viewPositionToDom(this.selection.anchor), s = this.domConverter.viewPositionToDom(this.selection.focus);
    t.collapse(i.parent, i.offset), t.extend(s.parent, s.offset), S.isGecko && F1(s, t);
  }
  /**
   * Checks whether a given DOM selection needs to be updated.
   *
   * @param domSelection The DOM selection to check.
   */
  _domSelectionNeedsUpdate(e) {
    if (!this.domConverter.isDomSelectionCorrect(e))
      return !0;
    const t = e && this.domConverter.domSelectionToView(e);
    return !(t && this.selection.isEqual(t) || !this.selection.isCollapsed && this.selection.isSimilar(t));
  }
  /**
   * Checks whether the fake selection needs to be updated.
   *
   * @param domRoot A valid DOM root where a new fake selection container should be added.
   */
  _fakeSelectionNeedsUpdate(e) {
    const t = this._fakeSelectionContainer, i = e.ownerDocument.getSelection();
    return !t || t.parentElement !== e || i.anchorNode !== t && !t.contains(i.anchorNode) ? !0 : t.textContent !== this.selection.fakeSelectionLabel;
  }
  /**
   * Removes the DOM selection.
   */
  _removeDomSelection() {
    for (const e of this.domDocuments) {
      const t = e.getSelection();
      if (t.rangeCount) {
        const i = e.activeElement, s = this.domConverter.mapDomToView(i);
        i && s && t.removeAllRanges();
      }
    }
  }
  /**
   * Removes the fake selection.
   */
  _removeFakeSelection() {
    const e = this._fakeSelectionContainer;
    e && e.remove();
  }
  /**
   * Checks if focus needs to be updated and possibly updates it.
   */
  _updateFocus() {
    if (this.isFocused) {
      const e = this.selection.editableElement;
      e && this.domConverter.focus(e);
    }
  }
}
function M1(n) {
  if (n.getAttribute("contenteditable") == "false")
    return !1;
  const e = n.findAncestor((t) => t.hasAttribute("contenteditable"));
  return !e || e.getAttribute("contenteditable") == "true";
}
function ba(n, e, t) {
  const i = e instanceof Array ? e : e.childNodes, s = i[t];
  if (J(s))
    return s.data = _n + s.data, s;
  {
    const r = n.createTextNode(_n);
    return Array.isArray(e) ? i.splice(t, 0, r) : bu(e, t, r), r;
  }
}
function V1(n, e) {
  return lt(n) && lt(e) && !J(n) && !J(e) && !Zt(n) && !Zt(e) && n.tagName.toLowerCase() === e.tagName.toLowerCase();
}
function D1(n, e) {
  return lt(n) && lt(e) && J(n) && J(e);
}
function B1(n, e, t) {
  return e === t ? !0 : J(e) && J(t) ? e.data === t.data : !!(n.isBlockFiller(e) && n.isBlockFiller(t));
}
function F1(n, e) {
  const t = n.parent;
  if (t.nodeType != Node.ELEMENT_NODE || n.offset != t.childNodes.length - 1)
    return;
  const i = t.childNodes[n.offset];
  i && i.tagName == "BR" && e.addRange(e.getRangeAt(0));
}
function N1(n, e) {
  const t = Array.from(n);
  return t.length == 0 || !e || t[t.length - 1] == e && t.pop(), t;
}
function L1(n) {
  const e = n.createElement("div");
  return e.className = "ck-fake-selection-container", Object.assign(e.style, {
    position: "fixed",
    top: 0,
    left: "-9999px",
    // See https://github.com/ckeditor/ckeditor5/issues/752.
    width: "42px"
  }), e.textContent = " ", e;
}
function _a(n, e) {
  const t = n.data;
  if (t == e)
    return;
  const i = ac(t, e);
  for (const s of i)
    s.type === "insert" ? n.insertData(s.index, s.values.join("")) : n.deleteData(s.index, s.howMany);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const $1 = $u(I.document), z1 = Nu(I.document), H1 = Lu(I.document), Ki = "data-ck-unsafe-attribute-", va = "data-ck-unsafe-element";
class zu {
  /**
   * Creates a DOM converter.
   *
   * @param document The view document instance.
   * @param options An object with configuration options.
   * @param options.blockFillerMode The type of the block filler to use.
   * Default value depends on the options.renderingMode:
   *  'nbsp' when options.renderingMode == 'data',
   *  'br' when options.renderingMode == 'editing'.
   * @param options.renderingMode Whether to leave the View-to-DOM conversion result unchanged
   * or improve editing experience by filtering out interactive data.
   */
  constructor(e, { blockFillerMode: t, renderingMode: i = "editing" } = {}) {
    this._domToViewMapping = /* @__PURE__ */ new WeakMap(), this._viewToDomMapping = /* @__PURE__ */ new WeakMap(), this._fakeSelectionMapping = /* @__PURE__ */ new WeakMap(), this._rawContentElementMatcher = new ni(), this._encounteredRawContentDomNodes = /* @__PURE__ */ new WeakSet(), this.document = e, this.renderingMode = i, this.blockFillerMode = t || (i === "editing" ? "br" : "nbsp"), this.preElements = ["pre"], this.blockElements = [
      "address",
      "article",
      "aside",
      "blockquote",
      "caption",
      "center",
      "dd",
      "details",
      "dir",
      "div",
      "dl",
      "dt",
      "fieldset",
      "figcaption",
      "figure",
      "footer",
      "form",
      "h1",
      "h2",
      "h3",
      "h4",
      "h5",
      "h6",
      "header",
      "hgroup",
      "legend",
      "li",
      "main",
      "menu",
      "nav",
      "ol",
      "p",
      "pre",
      "section",
      "summary",
      "table",
      "tbody",
      "td",
      "tfoot",
      "th",
      "thead",
      "tr",
      "ul"
    ], this.inlineObjectElements = [
      "object",
      "iframe",
      "input",
      "button",
      "textarea",
      "select",
      "option",
      "video",
      "embed",
      "audio",
      "img",
      "canvas"
    ], this.unsafeElements = ["script", "style"], this._domDocument = this.renderingMode === "editing" ? I.document : I.document.implementation.createHTMLDocument("");
  }
  /**
   * Binds a given DOM element that represents fake selection to a **position** of a
   * {@link module:engine/view/documentselection~DocumentSelection document selection}.
   * Document selection copy is stored and can be retrieved by the
   * {@link module:engine/view/domconverter~DomConverter#fakeSelectionToView} method.
   */
  bindFakeSelection(e, t) {
    this._fakeSelectionMapping.set(e, new ct(t));
  }
  /**
   * Returns a {@link module:engine/view/selection~Selection view selection} instance corresponding to a given
   * DOM element that represents fake selection. Returns `undefined` if binding to the given DOM element does not exist.
   */
  fakeSelectionToView(e) {
    return this._fakeSelectionMapping.get(e);
  }
  /**
   * Binds DOM and view elements, so it will be possible to get corresponding elements using
   * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and
   * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.
   *
   * @param domElement The DOM element to bind.
   * @param viewElement The view element to bind.
   */
  bindElements(e, t) {
    this._domToViewMapping.set(e, t), this._viewToDomMapping.set(t, e);
  }
  /**
   * Unbinds a given DOM element from the view element it was bound to. Unbinding is deep, meaning that all children of
   * the DOM element will be unbound too.
   *
   * @param domElement The DOM element to unbind.
   */
  unbindDomElement(e) {
    const t = this._domToViewMapping.get(e);
    if (t) {
      this._domToViewMapping.delete(e), this._viewToDomMapping.delete(t);
      for (const i of Array.from(e.children))
        this.unbindDomElement(i);
    }
  }
  /**
   * Binds DOM and view document fragments, so it will be possible to get corresponding document fragments using
   * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and
   * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.
   *
   * @param domFragment The DOM document fragment to bind.
   * @param viewFragment The view document fragment to bind.
   */
  bindDocumentFragments(e, t) {
    this._domToViewMapping.set(e, t), this._viewToDomMapping.set(t, e);
  }
  /**
   * Decides whether a given pair of attribute key and value should be passed further down the pipeline.
   *
   * @param elementName Element name in lower case.
   */
  shouldRenderAttribute(e, t, i) {
    return this.renderingMode === "data" ? !0 : (e = e.toLowerCase(), e.startsWith("on") || e === "srcdoc" && t.match(/\bon\S+\s*=|javascript:|<\s*\/*script/i) ? !1 : i === "img" && (e === "src" || e === "srcset") || i === "source" && e === "srcset" ? !0 : !t.match(/^\s*(javascript:|data:(image\/svg|text\/x?html))/i));
  }
  /**
   * Set `domElement`'s content using provided `html` argument. Apply necessary filtering for the editing pipeline.
   *
   * @param domElement DOM element that should have `html` set as its content.
   * @param html Textual representation of the HTML that will be set on `domElement`.
   */
  setContentOf(e, t) {
    if (this.renderingMode === "data") {
      e.innerHTML = t;
      return;
    }
    const i = new DOMParser().parseFromString(t, "text/html"), s = i.createDocumentFragment(), r = i.body.childNodes;
    for (; r.length > 0; )
      s.appendChild(r[0]);
    const o = i.createTreeWalker(s, NodeFilter.SHOW_ELEMENT), a = [];
    let l;
    for (; l = o.nextNode(); )
      a.push(l);
    for (const c of a) {
      for (const h of c.getAttributeNames())
        this.setDomElementAttribute(c, h, c.getAttribute(h));
      const u = c.tagName.toLowerCase();
      this._shouldRenameElement(u) && (ka(u), c.replaceWith(this._createReplacementDomElement(u, c)));
    }
    for (; e.firstChild; )
      e.firstChild.remove();
    e.append(s);
  }
  /**
   * Converts the view to the DOM. For all text nodes, not bound elements and document fragments new items will
   * be created. For bound elements and document fragments the method will return corresponding items.
   *
   * @param viewNode View node or document fragment to transform.
   * @param options Conversion options.
   * @param options.bind Determines whether new elements will be bound.
   * @param options.withChildren If `false`, node's and document fragment's children will not be converted.
   * @returns Converted node or DocumentFragment.
   */
  viewToDom(e, t = {}) {
    if (e.is("$text")) {
      const i = this._processDataFromViewText(e);
      return this._domDocument.createTextNode(i);
    } else {
      if (this.mapViewToDom(e))
        return this.mapViewToDom(e);
      let i;
      if (e.is("documentFragment"))
        i = this._domDocument.createDocumentFragment(), t.bind && this.bindDocumentFragments(i, e);
      else {
        if (e.is("uiElement"))
          return e.name === "$comment" ? i = this._domDocument.createComment(e.getCustomProperty("$rawContent")) : i = e.render(this._domDocument, this), t.bind && this.bindElements(i, e), i;
        this._shouldRenameElement(e.name) ? (ka(e.name), i = this._createReplacementDomElement(e.name)) : e.hasAttribute("xmlns") ? i = this._domDocument.createElementNS(e.getAttribute("xmlns"), e.name) : i = this._domDocument.createElement(e.name), e.is("rawElement") && e.render(i, this), t.bind && this.bindElements(i, e);
        for (const s of e.getAttributeKeys())
          this.setDomElementAttribute(i, s, e.getAttribute(s), e);
      }
      if (t.withChildren !== !1)
        for (const s of this.viewChildrenToDom(e, t))
          i.appendChild(s);
      return i;
    }
  }
  /**
   * Sets the attribute on a DOM element.
   *
   * **Note**: To remove the attribute, use {@link #removeDomElementAttribute}.
   *
   * @param domElement The DOM element the attribute should be set on.
   * @param key The name of the attribute.
   * @param value The value of the attribute.
   * @param relatedViewElement The view element related to the `domElement` (if there is any).
   * It helps decide whether the attribute set is unsafe. For instance, view elements created via the
   * {@link module:engine/view/downcastwriter~DowncastWriter} methods can allow certain attributes that would normally be filtered out.
   */
  setDomElementAttribute(e, t, i, s) {
    const r = this.shouldRenderAttribute(t, i, e.tagName.toLowerCase()) || s && s.shouldRenderUnsafeAttribute(t);
    if (r || q("domconverter-unsafe-attribute-detected", { domElement: e, key: t, value: i }), !_u(t)) {
      q("domconverter-invalid-attribute-detected", { domElement: e, key: t, value: i });
      return;
    }
    e.hasAttribute(t) && !r ? e.removeAttribute(t) : e.hasAttribute(Ki + t) && r && e.removeAttribute(Ki + t), e.setAttribute(r ? t : Ki + t, i);
  }
  /**
   * Removes an attribute from a DOM element.
   *
   * **Note**: To set the attribute, use {@link #setDomElementAttribute}.
   *
   * @param domElement The DOM element the attribute should be removed from.
   * @param key The name of the attribute.
   */
  removeDomElementAttribute(e, t) {
    t != va && (e.removeAttribute(t), e.removeAttribute(Ki + t));
  }
  /**
   * Converts children of the view element to DOM using the
   * {@link module:engine/view/domconverter~DomConverter#viewToDom} method.
   * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.
   *
   * @param viewElement Parent view element.
   * @param options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.
   * @returns DOM nodes.
   */
  *viewChildrenToDom(e, t = {}) {
    const i = e.getFillerOffset && e.getFillerOffset();
    let s = 0;
    for (const r of e.getChildren()) {
      i === s && (yield this._getBlockFiller());
      const o = r.is("element") && !!r.getCustomProperty("dataPipeline:transparentRendering") && !Te(r.getAttributes());
      o && this.renderingMode == "data" ? yield* this.viewChildrenToDom(r, t) : (o && q("domconverter-transparent-rendering-unsupported-in-editing-pipeline", { viewElement: r }), yield this.viewToDom(r, t)), s++;
    }
    i === s && (yield this._getBlockFiller());
  }
  /**
   * Converts view {@link module:engine/view/range~Range} to DOM range.
   * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.
   *
   * @param viewRange View range.
   * @returns DOM range.
   */
  viewRangeToDom(e) {
    const t = this.viewPositionToDom(e.start), i = this.viewPositionToDom(e.end), s = this._domDocument.createRange();
    return s.setStart(t.parent, t.offset), s.setEnd(i.parent, i.offset), s;
  }
  /**
   * Converts view {@link module:engine/view/position~Position} to DOM parent and offset.
   *
   * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.
   * If the converted position is directly before inline filler it is moved inside the filler.
   *
   * @param viewPosition View position.
   * @returns DOM position or `null` if view position could not be converted to DOM.
   * DOM position has two properties:
   * * `parent` - DOM position parent.
   * * `offset` - DOM position offset.
   */
  viewPositionToDom(e) {
    const t = e.parent;
    if (t.is("$text")) {
      const i = this.findCorrespondingDomText(t);
      if (!i)
        return null;
      let s = e.offset;
      return pe(i) && (s += Fe), { parent: i, offset: s };
    } else {
      let i, s, r;
      if (e.offset === 0) {
        if (i = this.mapViewToDom(t), !i)
          return null;
        r = i.childNodes[0];
      } else {
        const a = e.nodeBefore;
        if (s = a.is("$text") ? this.findCorrespondingDomText(a) : this.mapViewToDom(a), !s)
          return null;
        i = s.parentNode, r = s.nextSibling;
      }
      if (J(r) && pe(r))
        return { parent: r, offset: Fe };
      const o = s ? qi(s) + 1 : 0;
      return { parent: i, offset: o };
    }
  }
  /**
   * Converts DOM to view. For all text nodes, not bound elements and document fragments new items will
   * be created. For bound elements and document fragments function will return corresponding items. For
   * {@link module:engine/view/filler fillers} `null` will be returned.
   * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.
   *
   * @param domNode DOM node or document fragment to transform.
   * @param options Conversion options.
   * @param options.bind Determines whether new elements will be bound. False by default.
   * @param options.withChildren If `true`, node's and document fragment's children will be converted too. True by default.
   * @param options.keepOriginalCase If `false`, node's tag name will be converted to lower case. False by default.
   * @param options.skipComments If `false`, comment nodes will be converted to `$comment`
   * {@link module:engine/view/uielement~UIElement view UI elements}. False by default.
   * @returns Converted node or document fragment or `null` if DOM node is a {@link module:engine/view/filler filler}
   * or the given node is an empty text node.
   */
  domToView(e, t = {}) {
    if (this.isBlockFiller(e))
      return null;
    const i = this.getHostViewElement(e);
    if (i)
      return i;
    if (Zt(e) && t.skipComments)
      return null;
    if (J(e)) {
      if (_i(e))
        return null;
      {
        const s = this._processDataFromDomText(e);
        return s === "" ? null : new j(this.document, s);
      }
    } else {
      if (this.mapDomToView(e))
        return this.mapDomToView(e);
      let s;
      if (this.isDocumentFragment(e))
        s = new At(this.document), t.bind && this.bindDocumentFragments(e, s);
      else {
        s = this._createViewElement(e, t), t.bind && this.bindElements(e, s);
        const r = e.attributes;
        if (r)
          for (let o = r.length, a = 0; a < o; a++)
            s._setAttribute(r[a].name, r[a].value);
        if (this._isViewElementWithRawContent(s, t) || Zt(e)) {
          const o = Zt(e) ? e.data : e.innerHTML;
          return s._setCustomProperty("$rawContent", o), this._encounteredRawContentDomNodes.add(e), s;
        }
      }
      if (t.withChildren !== !1)
        for (const r of this.domChildrenToView(e, t))
          s._appendChild(r);
      return s;
    }
  }
  /**
   * Converts children of the DOM element to view nodes using
   * the {@link module:engine/view/domconverter~DomConverter#domToView} method.
   * Additionally this method omits block {@link module:engine/view/filler filler}, if it exists in the DOM parent.
   *
   * @param domElement Parent DOM element.
   * @param options See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.
   * @returns View nodes.
   */
  *domChildrenToView(e, t) {
    for (let i = 0; i < e.childNodes.length; i++) {
      const s = e.childNodes[i], r = this.domToView(s, t);
      r !== null && (yield r);
    }
  }
  /**
   * Converts DOM selection to view {@link module:engine/view/selection~Selection}.
   * Ranges which cannot be converted will be omitted.
   *
   * @param domSelection DOM selection.
   * @returns View selection.
   */
  domSelectionToView(e) {
    if (e.rangeCount === 1) {
      let s = e.getRangeAt(0).startContainer;
      J(s) && (s = s.parentNode);
      const r = this.fakeSelectionToView(s);
      if (r)
        return r;
    }
    const t = this.isDomSelectionBackward(e), i = [];
    for (let s = 0; s < e.rangeCount; s++) {
      const r = e.getRangeAt(s), o = this.domRangeToView(r);
      o && i.push(o);
    }
    return new ct(i, { backward: t });
  }
  /**
   * Converts DOM Range to view {@link module:engine/view/range~Range}.
   * If the start or end position can not be converted `null` is returned.
   *
   * @param domRange DOM range.
   * @returns View range.
   */
  domRangeToView(e) {
    const t = this.domPositionToView(e.startContainer, e.startOffset), i = this.domPositionToView(e.endContainer, e.endOffset);
    return t && i ? new P(t, i) : null;
  }
  /**
   * Converts DOM parent and offset to view {@link module:engine/view/position~Position}.
   *
   * If the position is inside a {@link module:engine/view/filler filler} which has no corresponding view node,
   * position of the filler will be converted and returned.
   *
   * If the position is inside DOM element rendered by {@link module:engine/view/uielement~UIElement}
   * that position will be converted to view position before that UIElement.
   *
   * If structures are too different and it is not possible to find corresponding position then `null` will be returned.
   *
   * @param domParent DOM position parent.
   * @param domOffset DOM position offset. You can skip it when converting the inline filler node.
   * @returns View position.
   */
  domPositionToView(e, t = 0) {
    if (this.isBlockFiller(e))
      return this.domPositionToView(e.parentNode, qi(e));
    const i = this.mapDomToView(e);
    if (i && (i.is("uiElement") || i.is("rawElement")))
      return v._createBefore(i);
    if (J(e)) {
      if (_i(e))
        return this.domPositionToView(e.parentNode, qi(e));
      const s = this.findCorrespondingViewText(e);
      let r = t;
      return s ? (pe(e) && (r -= Fe, r = r < 0 ? 0 : r), new v(s, r)) : null;
    } else {
      if (t === 0) {
        const s = this.mapDomToView(e);
        if (s)
          return new v(s, 0);
      } else {
        const s = e.childNodes[t - 1];
        if (J(s) && _i(s) || s && this.isBlockFiller(s))
          return this.domPositionToView(s.parentNode, qi(s));
        const r = J(s) ? this.findCorrespondingViewText(s) : this.mapDomToView(s);
        if (r && r.parent)
          return new v(r.parent, r.index + 1);
      }
      return null;
    }
  }
  /**
   * Returns corresponding view {@link module:engine/view/element~Element Element} or
   * {@link module:engine/view/documentfragment~DocumentFragment} for provided DOM element or
   * document fragment. If there is no view item {@link module:engine/view/domconverter~DomConverter#bindElements bound}
   * to the given DOM - `undefined` is returned.
   *
   * For all DOM elements rendered by a {@link module:engine/view/uielement~UIElement} or
   * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.
   *
   * @param domElementOrDocumentFragment DOM element or document fragment.
   * @returns Corresponding view element, document fragment or `undefined` if no element was bound.
   */
  mapDomToView(e) {
    return this.getHostViewElement(e) || this._domToViewMapping.get(e);
  }
  /**
   * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},
   * corresponding text node is returned based on the sibling or parent.
   *
   * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used
   * to find the corresponding text node.
   *
   * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}
   * element, it is used to find the corresponding text node.
   *
   * For all text nodes rendered by a {@link module:engine/view/uielement~UIElement} or
   * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.
   *
   * Otherwise `null` is returned.
   *
   * Note that for the block or inline {@link module:engine/view/filler filler} this method returns `null`.
   *
   * @param domText DOM text node.
   * @returns Corresponding view text node or `null`, if it was not possible to find a corresponding node.
   */
  findCorrespondingViewText(e) {
    if (_i(e))
      return null;
    const t = this.getHostViewElement(e);
    if (t)
      return t;
    const i = e.previousSibling;
    if (i) {
      if (!this.isElement(i))
        return null;
      const s = this.mapDomToView(i);
      if (s) {
        const r = s.nextSibling;
        return r instanceof j ? r : null;
      }
    } else {
      const s = this.mapDomToView(e.parentNode);
      if (s) {
        const r = s.getChild(0);
        return r instanceof j ? r : null;
      }
    }
    return null;
  }
  mapViewToDom(e) {
    return this._viewToDomMapping.get(e);
  }
  /**
   * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},
   * corresponding text node is returned based on the sibling or parent.
   *
   * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used
   * to find the corresponding text node.
   *
   * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}
   * element, it is used to find the corresponding text node.
   *
   * Otherwise `null` is returned.
   *
   * @param viewText View text node.
   * @returns Corresponding DOM text node or `null`, if it was not possible to find a corresponding node.
   */
  findCorrespondingDomText(e) {
    const t = e.previousSibling;
    return t && this.mapViewToDom(t) ? this.mapViewToDom(t).nextSibling : !t && e.parent && this.mapViewToDom(e.parent) ? this.mapViewToDom(e.parent).childNodes[0] : null;
  }
  /**
   * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.
   */
  focus(e) {
    const t = this.mapViewToDom(e);
    if (t && t.ownerDocument.activeElement !== t) {
      const { scrollX: i, scrollY: s } = I.window, r = [];
      ya(t, (o) => {
        const { scrollLeft: a, scrollTop: l } = o;
        r.push([a, l]);
      }), t.focus(), ya(t, (o) => {
        const [a, l] = r.shift();
        o.scrollLeft = a, o.scrollTop = l;
      }), I.window.scrollTo(i, s);
    }
  }
  /**
   * Returns `true` when `node.nodeType` equals `Node.ELEMENT_NODE`.
   *
   * @param node Node to check.
   */
  isElement(e) {
    return e && e.nodeType == Node.ELEMENT_NODE;
  }
  /**
   * Returns `true` when `node.nodeType` equals `Node.DOCUMENT_FRAGMENT_NODE`.
   *
   * @param node Node to check.
   */
  isDocumentFragment(e) {
    return e && e.nodeType == Node.DOCUMENT_FRAGMENT_NODE;
  }
  /**
   * Checks if the node is an instance of the block filler for this DOM converter.
   *
   * ```ts
   * const converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } );
   *
   * converter.isBlockFiller( BR_FILLER( document ) ); // true
   * converter.isBlockFiller( NBSP_FILLER( document ) ); // false
   * ```
   *
   * **Note:**: For the `'nbsp'` mode the method also checks context of a node so it cannot be a detached node.
   *
   * **Note:** A special case in the `'nbsp'` mode exists where the `<br>` in `<p><br></p>` is treated as a block filler.
   *
   * @param domNode DOM node to check.
   * @returns True if a node is considered a block filler for given mode.
   */
  isBlockFiller(e) {
    return this.blockFillerMode == "br" ? e.isEqualNode($1) : e.tagName === "BR" && Hu(e, this.blockElements) && e.parentNode.childNodes.length === 1 ? !0 : e.isEqualNode(H1) || U1(e, this.blockElements);
  }
  /**
   * Returns `true` if given selection is a backward selection, that is, if it's `focus` is before `anchor`.
   *
   * @param DOM Selection instance to check.
   */
  isDomSelectionBackward(e) {
    if (e.isCollapsed)
      return !1;
    const t = this._domDocument.createRange();
    try {
      t.setStart(e.anchorNode, e.anchorOffset), t.setEnd(e.focusNode, e.focusOffset);
    } catch {
      return !1;
    }
    const i = t.collapsed;
    return t.detach(), i;
  }
  /**
   * Returns a parent {@link module:engine/view/uielement~UIElement} or {@link module:engine/view/rawelement~RawElement}
   * that hosts the provided DOM node. Returns `null` if there is no such parent.
   */
  getHostViewElement(e) {
    const t = mu(e);
    for (t.pop(); t.length; ) {
      const i = t.pop(), s = this._domToViewMapping.get(i);
      if (s && (s.is("uiElement") || s.is("rawElement")))
        return s;
    }
    return null;
  }
  /**
   * Checks if the given selection's boundaries are at correct places.
   *
   * The following places are considered as incorrect for selection boundaries:
   *
   * * before or in the middle of an inline filler sequence,
   * * inside a DOM element which represents {@link module:engine/view/uielement~UIElement a view UI element},
   * * inside a DOM element which represents {@link module:engine/view/rawelement~RawElement a view raw element}.
   *
   * @param domSelection The DOM selection object to be checked.
   * @returns `true` if the given selection is at a correct place, `false` otherwise.
   */
  isDomSelectionCorrect(e) {
    return this._isDomSelectionPositionCorrect(e.anchorNode, e.anchorOffset) && this._isDomSelectionPositionCorrect(e.focusNode, e.focusOffset);
  }
  /**
   * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data
   * and not processed during the conversion from DOM nodes to view elements.
   *
   * This is affecting how {@link module:engine/view/domconverter~DomConverter#domToView} and
   * {@link module:engine/view/domconverter~DomConverter#domChildrenToView} process DOM nodes.
   *
   * The raw data can be later accessed by a
   * {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `"$rawContent"`.
   *
   * @param pattern Pattern matching a view element whose content should
   * be treated as raw data.
   */
  registerRawContentMatcher(e) {
    this._rawContentElementMatcher.add(e);
  }
  /**
   * Returns the block {@link module:engine/view/filler filler} node based on the current {@link #blockFillerMode} setting.
   */
  _getBlockFiller() {
    switch (this.blockFillerMode) {
      case "nbsp":
        return Nu(this._domDocument);
      case "markedNbsp":
        return Lu(this._domDocument);
      case "br":
        return $u(this._domDocument);
    }
  }
  /**
   * Checks if the given DOM position is a correct place for selection boundary. See {@link #isDomSelectionCorrect}.
   *
   * @param domParent Position parent.
   * @param offset Position offset.
   * @returns `true` if given position is at a correct place for selection boundary, `false` otherwise.
   */
  _isDomSelectionPositionCorrect(e, t) {
    if (J(e) && pe(e) && t < Fe || this.isElement(e) && pe(e.childNodes[t]))
      return !1;
    const i = this.mapDomToView(e);
    return !(i && (i.is("uiElement") || i.is("rawElement")));
  }
  /**
   * Takes text data from a given {@link module:engine/view/text~Text#data} and processes it so
   * it is correctly displayed in the DOM.
   *
   * Following changes are done:
   *
   * * a space at the beginning is changed to `&nbsp;` if this is the first text node in its container
   * element or if a previous text node ends with a space character,
   * * space at the end of the text node is changed to `&nbsp;` if there are two spaces at the end of a node or if next node
   * starts with a space or if it is the last text node in its container,
   * * remaining spaces are replaced to a chain of spaces and `&nbsp;` (e.g. `'x   x'` becomes `'x &nbsp; x'`).
   *
   * Content of {@link #preElements} is not processed.
   *
   * @param node View text node to process.
   * @returns Processed text data.
   */
  _processDataFromViewText(e) {
    let t = e.data;
    if (e.getAncestors().some((i) => this.preElements.includes(i.name)))
      return t;
    if (t.charAt(0) == " ") {
      const i = this._getTouchingInlineViewNode(e, !1);
      (i && i.is("$textProxy") && this._nodeEndsWithSpace(i) || !i) && (t = " " + t.substr(1));
    }
    if (t.charAt(t.length - 1) == " ") {
      const i = this._getTouchingInlineViewNode(e, !0), s = i && i.is("$textProxy") && i.data.charAt(0) == " ";
      (t.charAt(t.length - 2) == " " || !i || s) && (t = t.substr(0, t.length - 1) + " ");
    }
    return t.replace(/ {2}/g, "  ");
  }
  /**
   * Checks whether given node ends with a space character after changing appropriate space characters to `&nbsp;`s.
   *
   * @param  node Node to check.
   * @returns `true` if given `node` ends with space, `false` otherwise.
   */
  _nodeEndsWithSpace(e) {
    if (e.getAncestors().some((i) => this.preElements.includes(i.name)))
      return !1;
    const t = this._processDataFromViewText(e);
    return t.charAt(t.length - 1) == " ";
  }
  /**
   * Takes text data from native `Text` node and processes it to a correct {@link module:engine/view/text~Text view text node} data.
   *
   * Following changes are done:
   *
   * * multiple whitespaces are replaced to a single space,
   * * space at the beginning of a text node is removed if it is the first text node in its container
   * element or if the previous text node ends with a space character,
   * * space at the end of the text node is removed if there are two spaces at the end of a node or if next node
   * starts with a space or if it is the last text node in its container
   * * nbsps are converted to spaces.
   *
   * @param node DOM text node to process.
   * @returns Processed data.
   */
  _processDataFromDomText(e) {
    let t = e.data;
    if (W1(e, this.preElements))
      return wa(e);
    t = t.replace(/[ \n\t\r]{1,}/g, " ");
    const i = this._getTouchingInlineDomNode(e, !1), s = this._getTouchingInlineDomNode(e, !0), r = this._checkShouldLeftTrimDomText(e, i), o = this._checkShouldRightTrimDomText(e, s);
    r && (t = t.replace(/^ /, "")), o && (t = t.replace(/ $/, "")), t = wa(new Text(t)), t = t.replace(/ \u00A0/g, "  ");
    const a = s && this.isElement(s) && s.tagName != "BR", l = s && J(s) && s.data.charAt(0) == " ";
    return (/( |\u00A0)\u00A0$/.test(t) || !s || a || l) && (t = t.replace(/\u00A0$/, " ")), (r || i && this.isElement(i) && i.tagName != "BR") && (t = t.replace(/^\u00A0/, " ")), t;
  }
  /**
   * Helper function which checks if a DOM text node, preceded by the given `prevNode` should
   * be trimmed from the left side.
   *
   * @param prevNode Either DOM text or `<br>` or one of `#inlineObjectElements`.
   */
  _checkShouldLeftTrimDomText(e, t) {
    return t ? this.isElement(t) ? t.tagName === "BR" : this._encounteredRawContentDomNodes.has(e.previousSibling) ? !1 : /[^\S\u00A0]/.test(t.data.charAt(t.data.length - 1)) : !0;
  }
  /**
   * Helper function which checks if a DOM text node, succeeded by the given `nextNode` should
   * be trimmed from the right side.
   *
   * @param nextNode Either DOM text or `<br>` or one of `#inlineObjectElements`.
   */
  _checkShouldRightTrimDomText(e, t) {
    return t ? !1 : !pe(e);
  }
  /**
   * Helper function. For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling
   * that is contained in the same container element. If there is no such sibling, `null` is returned.
   *
   * @param node Reference node.
   * @returns Touching text node, an inline object
   * or `null` if there is no next or previous touching text node.
   */
  _getTouchingInlineViewNode(e, t) {
    const i = new Ct({
      startPosition: t ? v._createAfter(e) : v._createBefore(e),
      direction: t ? "forward" : "backward"
    });
    for (const s of i) {
      if (s.item.is("element") && this.inlineObjectElements.includes(s.item.name))
        return s.item;
      if (s.item.is("containerElement"))
        return null;
      if (s.item.is("element", "br"))
        return null;
      if (s.item.is("$textProxy"))
        return s.item;
    }
    return null;
  }
  /**
   * Helper function. For the given text node, it finds the closest touching node which is either
   * a text, `<br>` or an {@link #inlineObjectElements inline object}.
   *
   * If no such node is found, `null` is returned.
   *
   * For instance, in the following DOM structure:
   *
   * ```html
   * <p>foo<b>bar</b><br>bom</p>
   * ```
   *
   * * `foo` doesn't have its previous touching inline node (`null` is returned),
   * * `foo`'s next touching inline node is `bar`
   * * `bar`'s next touching inline node is `<br>`
   *
   * This method returns text nodes and `<br>` elements because these types of nodes affect how
   * spaces in the given text node need to be converted.
   */
  _getTouchingInlineDomNode(e, t) {
    if (!e.parentNode)
      return null;
    const i = t ? "firstChild" : "lastChild", s = t ? "nextSibling" : "previousSibling";
    let r = !0, o = e;
    do
      if (!r && o[i] ? o = o[i] : o[s] ? (o = o[s], r = !1) : (o = o.parentNode, r = !0), !o || this._isBlockElement(o))
        return null;
    while (!(J(o) || o.tagName == "BR" || this._isInlineObjectElement(o)));
    return o;
  }
  /**
   * Returns `true` if a DOM node belongs to {@link #blockElements}. `false` otherwise.
   */
  _isBlockElement(e) {
    return this.isElement(e) && this.blockElements.includes(e.tagName.toLowerCase());
  }
  /**
   * Returns `true` if a DOM node belongs to {@link #inlineObjectElements}. `false` otherwise.
   */
  _isInlineObjectElement(e) {
    return this.isElement(e) && this.inlineObjectElements.includes(e.tagName.toLowerCase());
  }
  /**
   * Creates view element basing on the node type.
   *
   * @param node DOM node to check.
   * @param options Conversion options. See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.
   */
  _createViewElement(e, t) {
    if (Zt(e))
      return new Nn(this.document, "$comment");
    const i = t.keepOriginalCase ? e.tagName : e.tagName.toLowerCase();
    return new Se(this.document, i);
  }
  /**
   * Checks if view element's content should be treated as a raw data.
   *
   * @param viewElement View element to check.
   * @param options Conversion options. See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.
   */
  _isViewElementWithRawContent(e, t) {
    return t.withChildren !== !1 && !!this._rawContentElementMatcher.match(e);
  }
  /**
   * Checks whether a given element name should be renamed in a current rendering mode.
   *
   * @param elementName The name of view element.
   */
  _shouldRenameElement(e) {
    const t = e.toLowerCase();
    return this.renderingMode === "editing" && this.unsafeElements.includes(t);
  }
  /**
   * Return a <span> element with a special attribute holding the name of the original element.
   * Optionally, copy all the attributes of the original element if that element is provided.
   *
   * @param elementName The name of view element.
   * @param originalDomElement The original DOM element to copy attributes and content from.
   */
  _createReplacementDomElement(e, t) {
    const i = this._domDocument.createElement("span");
    if (i.setAttribute(va, e), t) {
      for (; t.firstChild; )
        i.appendChild(t.firstChild);
      for (const s of t.getAttributeNames())
        i.setAttribute(s, t.getAttribute(s));
    }
    return i;
  }
}
function W1(n, e) {
  return mu(n).some((i) => i.tagName && e.includes(i.tagName.toLowerCase()));
}
function ya(n, e) {
  let t = n;
  for (; t; )
    e(t), t = t.parentElement;
}
function U1(n, e) {
  return n.isEqualNode(z1) && Hu(n, e) && n.parentNode.childNodes.length === 1;
}
function Hu(n, e) {
  const t = n.parentNode;
  return !!t && !!t.tagName && e.includes(t.tagName.toLowerCase());
}
function ka(n) {
  n === "script" && q("domconverter-unsafe-script-element-detected"), n === "style" && q("domconverter-unsafe-style-element-detected");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class We extends it() {
  /**
   * Creates an instance of the observer.
   */
  constructor(e) {
    super(), this._isEnabled = !1, this.view = e, this.document = e.document;
  }
  /**
   * The state of the observer. If it is disabled, no events will be fired.
   */
  get isEnabled() {
    return this._isEnabled;
  }
  /**
   * Enables the observer. This method is called when the observer is registered to the
   * {@link module:engine/view/view~View} and after {@link module:engine/view/view~View#forceRender rendering}
   * (all observers are {@link #disable disabled} before rendering).
   *
   * A typical use case for disabling observers is that mutation observers need to be disabled for the rendering.
   * However, a child class may not need to be disabled, so it can implement an empty method.
   *
   * @see module:engine/view/observer/observer~Observer#disable
   */
  enable() {
    this._isEnabled = !0;
  }
  /**
   * Disables the observer. This method is called before
   * {@link module:engine/view/view~View#forceRender rendering} to prevent firing events during rendering.
   *
   * @see module:engine/view/observer/observer~Observer#enable
   */
  disable() {
    this._isEnabled = !1;
  }
  /**
   * Disables and destroys the observer, among others removes event listeners created by the observer.
   */
  destroy() {
    this.disable(), this.stopListening();
  }
  /**
   * Checks whether a given DOM event should be ignored (should not be turned into a synthetic view document event).
   *
   * Currently, an event will be ignored only if its target or any of its ancestors has the `data-cke-ignore-events` attribute.
   * This attribute can be used inside the structures generated by
   * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `DowncastWriter#createUIElement()`} to ignore events
   * fired within a UI that should be excluded from CKEditor 5's realms.
   *
   * @param domTarget The DOM event target to check (usually an element, sometimes a text node and
   * potentially sometimes a document, too).
   * @returns Whether this event should be ignored by the observer.
   */
  checkShouldIgnoreEventFromTarget(e) {
    return e && e.nodeType === 3 && (e = e.parentNode), !e || e.nodeType !== 1 ? !1 : e.matches("[data-cke-ignore-events], [data-cke-ignore-events] *");
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class si {
  /**
   * @param view The instance of the view controller.
   * @param domEvent The DOM event.
   * @param additionalData Additional properties that the instance should contain.
   */
  constructor(e, t, i) {
    this.view = e, this.document = e.document, this.domEvent = t, this.domTarget = t.target, Ec(this, i);
  }
  /**
   * The tree view element representing the target.
   */
  get target() {
    return this.view.domConverter.mapDomToView(this.domTarget);
  }
  /**
   * Prevents the native's event default action.
   */
  preventDefault() {
    this.domEvent.preventDefault();
  }
  /**
   * Stops native event propagation.
   */
  stopPropagation() {
    this.domEvent.stopPropagation();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Dt extends We {
  constructor() {
    super(...arguments), this.useCapture = !1;
  }
  /**
   * @inheritDoc
   */
  observe(e) {
    (typeof this.domEventType == "string" ? [this.domEventType] : this.domEventType).forEach((i) => {
      this.listenTo(e, i, (s, r) => {
        this.isEnabled && !this.checkShouldIgnoreEventFromTarget(r.target) && this.onDomEvent(r);
      }, { useCapture: this.useCapture });
    });
  }
  /**
   * @inheritDoc
   */
  stopObserving(e) {
    this.stopListening(e);
  }
  /**
   * Calls `Document#fire()` if observer {@link #isEnabled is enabled}.
   *
   * @see module:utils/emittermixin~Emitter#fire
   * @param eventType The event type (name).
   * @param domEvent The DOM event.
   * @param additionalData The additional data which should extend the
   * {@link module:engine/view/observer/domeventdata~DomEventData event data} object.
   */
  fire(e, t, i) {
    this.isEnabled && this.document.fire(e, new si(this.view, t, i));
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class j1 extends Dt {
  constructor() {
    super(...arguments), this.domEventType = ["keydown", "keyup"];
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    const t = {
      keyCode: e.keyCode,
      altKey: e.altKey,
      ctrlKey: e.ctrlKey,
      shiftKey: e.shiftKey,
      metaKey: e.metaKey,
      get keystroke() {
        return ii(this);
      }
    };
    this.fire(e.type, e, t);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class q1 extends We {
  /**
   * Creates new FakeSelectionObserver instance.
   */
  constructor(e) {
    super(e), this._fireSelectionChangeDoneDebounced = ti((t) => {
      this.document.fire("selectionChangeDone", t);
    }, 200);
  }
  /**
   * @inheritDoc
   */
  observe() {
    const e = this.document;
    e.on("arrowKey", (t, i) => {
      e.selection.isFake && this.isEnabled && i.preventDefault();
    }, { context: "$capture" }), e.on("arrowKey", (t, i) => {
      e.selection.isFake && this.isEnabled && this._handleSelectionMove(i.keyCode);
    }, { priority: "lowest" });
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._fireSelectionChangeDoneDebounced.cancel();
  }
  /**
   * Handles collapsing view selection according to given key code. If left or up key is provided - new selection will be
   * collapsed to left. If right or down key is pressed - new selection will be collapsed to right.
   *
   * This method fires {@link module:engine/view/document~Document#event:selectionChange} and
   * {@link module:engine/view/document~Document#event:selectionChangeDone} events imitating behaviour of
   * {@link module:engine/view/observer/selectionobserver~SelectionObserver}.
   */
  _handleSelectionMove(e) {
    const t = this.document.selection, i = new ct(t.getRanges(), { backward: t.isBackward, fake: !1 });
    (e == R.arrowleft || e == R.arrowup) && i.setTo(i.getFirstPosition()), (e == R.arrowright || e == R.arrowdown) && i.setTo(i.getLastPosition());
    const s = {
      oldSelection: t,
      newSelection: i,
      domSelection: null
    };
    this.document.fire("selectionChange", s), this._fireSelectionChangeDoneDebounced(s);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Wu extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._config = {
      childList: !0,
      characterData: !0,
      subtree: !0
    }, this.domConverter = e.domConverter, this.renderer = e._renderer, this._domElements = /* @__PURE__ */ new Set(), this._mutationObserver = new window.MutationObserver(this._onMutations.bind(this));
  }
  /**
   * Synchronously handles mutations and empties the queue.
   */
  flush() {
    this._onMutations(this._mutationObserver.takeRecords());
  }
  /**
   * @inheritDoc
   */
  observe(e) {
    this._domElements.add(e), this.isEnabled && this._mutationObserver.observe(e, this._config);
  }
  /**
   * @inheritDoc
   */
  stopObserving(e) {
    if (this._domElements.delete(e), this.isEnabled) {
      this._mutationObserver.disconnect();
      for (const t of this._domElements)
        this._mutationObserver.observe(t, this._config);
    }
  }
  /**
   * @inheritDoc
   */
  enable() {
    super.enable();
    for (const e of this._domElements)
      this._mutationObserver.observe(e, this._config);
  }
  /**
   * @inheritDoc
   */
  disable() {
    super.disable(), this._mutationObserver.disconnect();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._mutationObserver.disconnect();
  }
  /**
   * Handles mutations. Mark view elements to sync and call render.
   *
   * @param domMutations Array of native mutations.
   */
  _onMutations(e) {
    if (e.length === 0)
      return;
    const t = this.domConverter, i = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set();
    for (const o of e) {
      const a = t.mapDomToView(o.target);
      a && (a.is("uiElement") || a.is("rawElement") || o.type === "childList" && !this._isBogusBrMutation(o) && s.add(a));
    }
    for (const o of e) {
      const a = t.mapDomToView(o.target);
      if (!(a && (a.is("uiElement") || a.is("rawElement"))) && o.type === "characterData") {
        const l = t.findCorrespondingViewText(o.target);
        l && !s.has(l.parent) ? i.add(l) : !l && pe(o.target) && s.add(t.mapDomToView(o.target.parentNode));
      }
    }
    let r = !1;
    for (const o of i)
      r = !0, this.renderer.markToSync("text", o);
    for (const o of s) {
      const a = t.mapViewToDom(o), l = Array.from(o.getChildren()), c = Array.from(t.domChildrenToView(a, { withChildren: !1 }));
      J0(l, c, G1) || (r = !0, this.renderer.markToSync("children", o));
    }
    r && this.view.forceRender();
  }
  /**
   * Checks if mutation was generated by the browser inserting bogus br on the end of the block element.
   * Such mutations are generated while pressing space or performing native spellchecker correction
   * on the end of the block element in Firefox browser.
   *
   * @param mutation Native mutation object.
   */
  _isBogusBrMutation(e) {
    let t = null;
    return e.nextSibling === null && e.removedNodes.length === 0 && e.addedNodes.length == 1 && (t = this.domConverter.domToView(e.addedNodes[0], {
      withChildren: !1
    })), t && t.is("element", "br");
  }
}
function G1(n, e) {
  if (!Array.isArray(n))
    return n === e ? !0 : n.is("$text") && e.is("$text") ? n.data === e.data : !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Js extends Dt {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._isFocusChanging = !1, this.domEventType = ["focus", "blur"], this.useCapture = !0;
    const t = this.document;
    t.on("focus", () => {
      this._isFocusChanging = !0, this._renderTimeoutId = setTimeout(() => {
        this.flush(), e.change(() => {
        });
      }, 50);
    }), t.on("blur", (i, s) => {
      const r = t.selection.editableElement;
      (r === null || r === s.target) && (t.isFocused = !1, this._isFocusChanging = !1, e.change(() => {
      }));
    });
  }
  /**
   * Finishes setting the document focus state.
   */
  flush() {
    this._isFocusChanging && (this._isFocusChanging = !1, this.document.isFocused = !0);
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    this.fire(e.type, e);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    this._renderTimeoutId && clearTimeout(this._renderTimeoutId), super.destroy();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class K1 extends We {
  constructor(e) {
    super(e), this.mutationObserver = e.getObserver(Wu), this.focusObserver = e.getObserver(Js), this.selection = this.document.selection, this.domConverter = e.domConverter, this._documents = /* @__PURE__ */ new WeakSet(), this._fireSelectionChangeDoneDebounced = ti((t) => {
      this.document.fire("selectionChangeDone", t);
    }, 200), this._clearInfiniteLoopInterval = setInterval(() => this._clearInfiniteLoop(), 1e3), this._documentIsSelectingInactivityTimeoutDebounced = ti(() => this.document.isSelecting = !1, 5e3), this._loopbackCounter = 0;
  }
  /**
   * @inheritDoc
   */
  observe(e) {
    const t = e.ownerDocument, i = () => {
      this.document.isSelecting = !0, this._documentIsSelectingInactivityTimeoutDebounced();
    }, s = () => {
      this.document.isSelecting && (this._handleSelectionChange(null, t), this.document.isSelecting = !1, this._documentIsSelectingInactivityTimeoutDebounced.cancel());
    };
    this.listenTo(e, "selectstart", i, { priority: "highest" }), this.listenTo(e, "keydown", s, { priority: "highest", useCapture: !0 }), this.listenTo(e, "keyup", s, { priority: "highest", useCapture: !0 }), !this._documents.has(t) && (this.listenTo(t, "mouseup", s, { priority: "highest", useCapture: !0 }), this.listenTo(t, "selectionchange", (r, o) => {
      this.document.isComposing && !S.isAndroid || (this._handleSelectionChange(o, t), this._documentIsSelectingInactivityTimeoutDebounced());
    }), this._documents.add(t));
  }
  /**
   * @inheritDoc
   */
  stopObserving(e) {
    this.stopListening(e);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), clearInterval(this._clearInfiniteLoopInterval), this._fireSelectionChangeDoneDebounced.cancel(), this._documentIsSelectingInactivityTimeoutDebounced.cancel();
  }
  /* istanbul ignore next -- @preserve */
  _reportInfiniteLoop() {
  }
  /**
   * Selection change listener. {@link module:engine/view/observer/mutationobserver~MutationObserver#flush Flush} mutations, check if
   * a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change
   * and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.
   *
   * @param domEvent DOM event.
   * @param domDocument DOM document.
   */
  _handleSelectionChange(e, t) {
    if (!this.isEnabled)
      return;
    const i = t.defaultView.getSelection();
    if (this.checkShouldIgnoreEventFromTarget(i.anchorNode))
      return;
    this.mutationObserver.flush();
    const s = this.domConverter.domSelectionToView(i);
    if (s.rangeCount == 0) {
      this.view.hasDomSelection = !1;
      return;
    }
    if (this.view.hasDomSelection = !0, !(this.selection.isEqual(s) && this.domConverter.isDomSelectionCorrect(i))) {
      if (++this._loopbackCounter > 60) {
        this._reportInfiniteLoop();
        return;
      }
      if (this.focusObserver.flush(), this.selection.isSimilar(s))
        this.view.forceRender();
      else {
        const r = {
          oldSelection: this.selection,
          newSelection: s,
          domSelection: i
        };
        this.document.fire("selectionChange", r), this._fireSelectionChangeDoneDebounced(r);
      }
    }
  }
  /**
   * Clears `SelectionObserver` internal properties connected with preventing infinite loop.
   */
  _clearInfiniteLoop() {
    this._loopbackCounter = 0;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class J1 extends Dt {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.domEventType = ["compositionstart", "compositionupdate", "compositionend"];
    const t = this.document;
    t.on("compositionstart", () => {
      t.isComposing = !0;
    }, { priority: "low" }), t.on("compositionend", () => {
      t.isComposing = !1;
    }, { priority: "low" });
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    this.fire(e.type, e, {
      data: e.data
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Uu {
  /**
   * @param nativeDataTransfer The native [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object.
   * @param options.cacheFiles Whether `files` list should be initialized in the constructor.
   */
  constructor(e, t = {}) {
    this._files = t.cacheFiles ? Ca(e) : null, this._native = e;
  }
  /**
   * The array of files created from the native `DataTransfer#files` or `DataTransfer#items`.
   */
  get files() {
    return this._files || (this._files = Ca(this._native)), this._files;
  }
  /**
   * Returns an array of available native content types.
   */
  get types() {
    return this._native.types;
  }
  /**
   * Gets the data from the data transfer by its MIME type.
   *
   * ```ts
   * dataTransfer.getData( 'text/plain' );
   * ```
   *
   * @param type The MIME type. E.g. `text/html` or `text/plain`.
   */
  getData(e) {
    return this._native.getData(e);
  }
  /**
   * Sets the data in the data transfer.
   *
   * @param type The MIME type. E.g. `text/html` or `text/plain`.
   */
  setData(e, t) {
    this._native.setData(e, t);
  }
  /**
   * The effect that is allowed for a drag operation.
   */
  set effectAllowed(e) {
    this._native.effectAllowed = e;
  }
  get effectAllowed() {
    return this._native.effectAllowed;
  }
  /**
   * The actual drop effect.
   */
  set dropEffect(e) {
    this._native.dropEffect = e;
  }
  get dropEffect() {
    return this._native.dropEffect;
  }
  /**
   * Set a preview image of the dragged content.
   */
  setDragImage(e, t, i) {
    this._native.setDragImage(e, t, i);
  }
  /**
   * Whether the dragging operation was canceled.
   */
  get isCanceled() {
    return this._native.dropEffect == "none" || !!this._native.mozUserCancelled;
  }
}
function Ca(n) {
  const e = Array.from(n.files || []), t = Array.from(n.items || []);
  return e.length ? e : t.filter((i) => i.kind === "file").map((i) => i.getAsFile());
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Z1 extends Dt {
  constructor() {
    super(...arguments), this.domEventType = "beforeinput";
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    const t = e.getTargetRanges(), i = this.view, s = i.document;
    let r = null, o = null, a = [];
    if (e.dataTransfer && (r = new Uu(e.dataTransfer)), e.data !== null ? o = e.data : r && (o = r.getData("text/plain")), s.selection.isFake)
      a = Array.from(s.selection.getRanges());
    else if (t.length)
      a = t.map((l) => {
        const c = i.domConverter.domPositionToView(l.startContainer, l.startOffset), u = i.domConverter.domPositionToView(l.endContainer, l.endOffset);
        if (c)
          return i.createRange(c, u);
        if (u)
          return i.createRange(u);
      }).filter((l) => !!l);
    else if (S.isAndroid) {
      const l = e.target.ownerDocument.defaultView.getSelection();
      a = Array.from(i.domConverter.domSelectionToView(l).getRanges());
    }
    if (S.isAndroid && e.inputType == "insertCompositionText" && o && o.endsWith(`
`)) {
      this.fire(e.type, e, {
        inputType: "insertParagraph",
        targetRanges: [i.createRange(a[0].end)]
      });
      return;
    }
    if (e.inputType == "insertText" && o && o.includes(`
`)) {
      const l = o.split(/\n{1,2}/g);
      let c = a;
      for (let u = 0; u < l.length; u++) {
        const h = l[u];
        h != "" && (this.fire(e.type, e, {
          data: h,
          dataTransfer: r,
          targetRanges: c,
          inputType: e.inputType,
          isComposing: e.isComposing
        }), c = [s.selection.getFirstRange()]), u + 1 < l.length && (this.fire(e.type, e, {
          inputType: "insertParagraph",
          targetRanges: c
        }), c = [s.selection.getFirstRange()]);
      }
      return;
    }
    this.fire(e.type, e, {
      data: o,
      dataTransfer: r,
      targetRanges: a,
      inputType: e.inputType,
      isComposing: e.isComposing
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Y1 extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.document.on("keydown", (t, i) => {
      if (this.isEnabled && D_(i.keyCode)) {
        const s = new fi(this.document, "arrowKey", this.document.selection.getFirstRange());
        this.document.fire(s, i), s.stop.called && t.stop();
      }
    });
  }
  /**
   * @inheritDoc
   */
  observe() {
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class X1 extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.document;
    t.on("keydown", (i, s) => {
      if (!this.isEnabled || s.keyCode != R.tab || s.ctrlKey)
        return;
      const r = new fi(t, "tab", t.selection.getFirstRange());
      t.fire(r, s), r.stop.called && i.stop();
    });
  }
  /**
   * @inheritDoc
   */
  observe() {
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Q1 = class extends z() {
  /**
   * @param stylesProcessor The styles processor instance.
   */
  constructor(e) {
    super(), this.domRoots = /* @__PURE__ */ new Map(), this._initialDomRootAttributes = /* @__PURE__ */ new WeakMap(), this._observers = /* @__PURE__ */ new Map(), this._ongoingChange = !1, this._postFixersInProgress = !1, this._renderingDisabled = !1, this._hasChangedSinceTheLastRendering = !1, this.document = new Vu(e), this.domConverter = new zu(this.document), this.set("isRenderingInProgress", !1), this.set("hasDomSelection", !1), this._renderer = new O1(this.domConverter, this.document.selection), this._renderer.bind("isFocused", "isSelecting", "isComposing").to(this.document, "isFocused", "isSelecting", "isComposing"), this._writer = new Bu(this.document), this.addObserver(Wu), this.addObserver(Js), this.addObserver(K1), this.addObserver(j1), this.addObserver(q1), this.addObserver(J1), this.addObserver(Y1), this.addObserver(Z1), this.addObserver(X1), I1(this), k1(this), this.on("render", () => {
      this._render(), this.document.fire("layoutChanged"), this._hasChangedSinceTheLastRendering = !1;
    }), this.listenTo(this.document.selection, "change", () => {
      this._hasChangedSinceTheLastRendering = !0;
    }), this.listenTo(this.document, "change:isFocused", () => {
      this._hasChangedSinceTheLastRendering = !0;
    });
  }
  /**
   * Attaches a DOM root element to the view element and enable all observers on that element.
   * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized
   * with the view what means that all child nodes will be removed and replaced with content of the view root.
   *
   * This method also will change view element name as the same as tag name of given dom root.
   * Name is always transformed to lower case.
   *
   * **Note:** Use {@link #detachDomRoot `detachDomRoot()`} to revert this action.
   *
   * @param domRoot DOM root element.
   * @param name Name of the root.
   */
  attachDomRoot(e, t = "main") {
    const i = this.document.getRoot(t);
    i._name = e.tagName.toLowerCase();
    const s = {};
    for (const { name: o, value: a } of Array.from(e.attributes))
      s[o] = a, o === "class" ? this._writer.addClass(a.split(" "), i) : this._writer.setAttribute(o, a, i);
    this._initialDomRootAttributes.set(e, s);
    const r = () => {
      this._writer.setAttribute("contenteditable", (!i.isReadOnly).toString(), i), i.isReadOnly ? this._writer.addClass("ck-read-only", i) : this._writer.removeClass("ck-read-only", i);
    };
    r(), this.domRoots.set(t, e), this.domConverter.bindElements(e, i), this._renderer.markToSync("children", i), this._renderer.markToSync("attributes", i), this._renderer.domDocuments.add(e.ownerDocument), i.on("change:children", (o, a) => this._renderer.markToSync("children", a)), i.on("change:attributes", (o, a) => this._renderer.markToSync("attributes", a)), i.on("change:text", (o, a) => this._renderer.markToSync("text", a)), i.on("change:isReadOnly", () => this.change(r)), i.on("change", () => {
      this._hasChangedSinceTheLastRendering = !0;
    });
    for (const o of this._observers.values())
      o.observe(e, t);
  }
  /**
   * Detaches a DOM root element from the view element and restores its attributes to the state before
   * {@link #attachDomRoot `attachDomRoot()`}.
   *
   * @param name Name of the root to detach.
   */
  detachDomRoot(e) {
    const t = this.domRoots.get(e);
    Array.from(t.attributes).forEach(({ name: s }) => t.removeAttribute(s));
    const i = this._initialDomRootAttributes.get(t);
    for (const s in i)
      t.setAttribute(s, i[s]);
    this.domRoots.delete(e), this.domConverter.unbindDomElement(t);
    for (const s of this._observers.values())
      s.stopObserving(t);
  }
  /**
   * Gets DOM root element.
   *
   * @param name  Name of the root.
   * @returns DOM root element instance.
   */
  getDomRoot(e = "main") {
    return this.domRoots.get(e);
  }
  /**
   * Creates observer of the given type if not yet created, {@link module:engine/view/observer/observer~Observer#enable enables} it
   * and {@link module:engine/view/observer/observer~Observer#observe attaches} to all existing and future
   * {@link #domRoots DOM roots}.
   *
   * Note: Observers are recognized by their constructor (classes). A single observer will be instantiated and used only
   * when registered for the first time. This means that features and other components can register a single observer
   * multiple times without caring whether it has been already added or not.
   *
   * @param ObserverConstructor The constructor of an observer to add.
   * Should create an instance inheriting from {@link module:engine/view/observer/observer~Observer}.
   * @returns Added observer instance.
   */
  addObserver(e) {
    let t = this._observers.get(e);
    if (t)
      return t;
    t = new e(this), this._observers.set(e, t);
    for (const [i, s] of this.domRoots)
      t.observe(s, i);
    return t.enable(), t;
  }
  /**
   * Returns observer of the given type or `undefined` if such observer has not been added yet.
   *
   * @param ObserverConstructor The constructor of an observer to get.
   * @returns Observer instance or undefined.
   */
  getObserver(e) {
    return this._observers.get(e);
  }
  /**
   * Disables all added observers.
   */
  disableObservers() {
    for (const e of this._observers.values())
      e.disable();
  }
  /**
   * Enables all added observers.
   */
  enableObservers() {
    for (const e of this._observers.values())
      e.enable();
  }
  /**
   * Scrolls the page viewport and {@link #domRoots} with their ancestors to reveal the
   * caret, **if not already visible to the user**.
   *
   * **Note**: Calling this method fires the {@link module:engine/view/view~ViewScrollToTheSelectionEvent} event that
   * allows custom behaviors.
   *
   * @param options Additional configuration of the scrolling behavior.
   * @param options.viewportOffset A distance between the DOM selection and the viewport boundary to be maintained
   * while scrolling to the selection (default is 20px). Setting this value to `0` will reveal the selection precisely at
   * the viewport boundary.
   * @param options.ancestorOffset A distance between the DOM selection and scrollable DOM root ancestor(s) to be maintained
   * while scrolling to the selection (default is 20px). Setting this value to `0` will reveal the selection precisely at
   * the scrollable ancestor(s) boundary.
   * @param options.alignToTop When set `true`, the DOM selection will be aligned to the top of the viewport if not already visible
   * (see `forceScroll` to learn more).
   * @param options.forceScroll When set `true`, the DOM selection will be aligned to the top of the viewport and scrollable ancestors
   * whether it is already visible or not. This option will only work when `alignToTop` is `true`.
   */
  scrollToTheSelection({ alignToTop: e, forceScroll: t, viewportOffset: i = 20, ancestorOffset: s = 20 } = {}) {
    const r = this.document.selection.getFirstRange();
    if (!r)
      return;
    const o = tt({ alignToTop: e, forceScroll: t, viewportOffset: i, ancestorOffset: s });
    typeof i == "number" && (i = {
      top: i,
      bottom: i,
      left: i,
      right: i
    });
    const a = {
      target: this.domConverter.viewRangeToDom(r),
      viewportOffset: i,
      ancestorOffset: s,
      alignToTop: e,
      forceScroll: t
    };
    this.fire("scrollToTheSelection", a, o), x_(a);
  }
  /**
   * It will focus DOM element representing {@link module:engine/view/editableelement~EditableElement EditableElement}
   * that is currently having selection inside.
   */
  focus() {
    if (!this.document.isFocused) {
      const e = this.document.selection.editableElement;
      e && (this.domConverter.focus(e), this.forceRender());
    }
  }
  /**
   * The `change()` method is the primary way of changing the view. You should use it to modify any node in the view tree.
   * It makes sure that after all changes are made the view is rendered to the DOM (assuming that the view will be changed
   * inside the callback). It prevents situations when the DOM is updated when the view state is not yet correct. It allows
   * to nest calls one inside another and still performs a single rendering after all those changes are made.
   * It also returns the return value of its callback.
   *
   * ```ts
   * const text = view.change( writer => {
   * 	const newText = writer.createText( 'foo' );
   * 	writer.insert( position1, newText );
   *
   * 	view.change( writer => {
   * 		writer.insert( position2, writer.createText( 'bar' ) );
   * 	} );
   *
   * 	writer.remove( range );
   *
   * 	return newText;
   * } );
   * ```
   *
   * When the outermost change block is done and rendering to the DOM is over the
   * {@link module:engine/view/view~View#event:render `View#render`} event is fired.
   *
   * This method throws a `applying-view-changes-on-rendering` error when
   * the change block is used after rendering to the DOM has started.
   *
   * @param callback Callback function which may modify the view.
   * @returns Value returned by the callback.
   */
  change(e) {
    if (this.isRenderingInProgress || this._postFixersInProgress)
      throw new d("cannot-change-view-tree", this);
    try {
      if (this._ongoingChange)
        return e(this._writer);
      this._ongoingChange = !0;
      const t = e(this._writer);
      return this._ongoingChange = !1, !this._renderingDisabled && this._hasChangedSinceTheLastRendering && (this._postFixersInProgress = !0, this.document._callPostFixers(this._writer), this._postFixersInProgress = !1, this.fire("render")), t;
    } catch (t) {
      /* istanbul ignore next -- @preserve */
      d.rethrowUnexpectedError(t, this);
    }
  }
  /**
   * Forces rendering {@link module:engine/view/document~Document view document} to DOM. If any view changes are
   * currently in progress, rendering will start after all {@link #change change blocks} are processed.
   *
   * Note that this method is dedicated for special cases. All view changes should be wrapped in the {@link #change}
   * block and the view will automatically check whether it needs to render DOM or not.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `applying-view-changes-on-rendering` when
   * trying to re-render when rendering to DOM has already started.
   */
  forceRender() {
    this._hasChangedSinceTheLastRendering = !0, this.getObserver(Js).flush(), this.change(() => {
    });
  }
  /**
   * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.
   */
  destroy() {
    for (const e of this._observers.values())
      e.destroy();
    this.document.destroy(), this.stopListening();
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/view/position~Position position},
   * * parent element and offset (offset defaults to `0`),
   * * parent element and `'end'` (sets position at the end of that element),
   * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
   *
   * This method is a shortcut to other constructors such as:
   *
   * * {@link #createPositionBefore},
   * * {@link #createPositionAfter},
   *
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/view/item~Item view item}.
   */
  createPositionAt(e, t) {
    return v._createAt(e, t);
  }
  /**
   * Creates a new position after given view item.
   *
   * @param item View item after which the position should be located.
   */
  createPositionAfter(e) {
    return v._createAfter(e);
  }
  /**
   * Creates a new position before given view item.
   *
   * @param item View item before which the position should be located.
   */
  createPositionBefore(e) {
    return v._createBefore(e);
  }
  /**
   * Creates a range spanning from `start` position to `end` position.
   *
   * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
   *
   * @param start Start position.
   * @param end End position. If not set, range will be collapsed at `start` position.
   */
  createRange(e, t) {
    return new P(e, t);
  }
  /**
   * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
   */
  createRangeOn(e) {
    return P._createOn(e);
  }
  /**
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * @param element Element which is a parent for the range.
   */
  createRangeIn(e) {
    return P._createIn(e);
  }
  createSelection(...e) {
    return new ct(...e);
  }
  /**
   * Disables or enables rendering. If the flag is set to `true` then the rendering will be disabled.
   * If the flag is set to `false` and if there was some change in the meantime, then the rendering action will be performed.
   *
   * @internal
   * @param flag A flag indicates whether the rendering should be disabled.
   */
  _disableRendering(e) {
    this._renderingDisabled = e, e == !1 && this.change(() => {
    });
  }
  /**
   * Renders all changes. In order to avoid triggering the observers (e.g. selection) all observers are disabled
   * before rendering and re-enabled after that.
   */
  _render() {
    this.isRenderingInProgress = !0, this.disableObservers(), this._renderer.render(), this.enableObservers(), this.isRenderingInProgress = !1;
  }
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ft {
  /* istanbul ignore next -- @preserve */
  is() {
    throw new Error("is() method is abstract");
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Bt = class extends ft {
  /**
   * Creates a model node.
   *
   * This is an abstract class, so this constructor should not be used directly.
   *
   * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
   */
  constructor(e) {
    super(), this.parent = null, this._attrs = Xe(e);
  }
  /**
   * {@link module:engine/model/document~Document Document} that owns this root element.
   */
  get document() {
    return null;
  }
  /**
   * Index of this node in its parent or `null` if the node has no parent.
   *
   * Accessing this property throws an error if this node's parent element does not contain it.
   * This means that model tree got broken.
   */
  get index() {
    let e;
    if (!this.parent)
      return null;
    if ((e = this.parent.getChildIndex(this)) === null)
      throw new d("model-node-not-found-in-parent", this);
    return e;
  }
  /**
   * Offset at which this node starts in its parent. It is equal to the sum of {@link #offsetSize offsetSize}
   * of all its previous siblings. Equals to `null` if node has no parent.
   *
   * Accessing this property throws an error if this node's parent element does not contain it.
   * This means that model tree got broken.
   */
  get startOffset() {
    let e;
    if (!this.parent)
      return null;
    if ((e = this.parent.getChildStartOffset(this)) === null)
      throw new d("model-node-not-found-in-parent", this);
    return e;
  }
  /**
   * Offset size of this node. Represents how much "offset space" is occupied by the node in it's parent.
   * It is important for {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position
   * can be placed between that node start and end. `offsetSize` greater than `1` is for nodes that represents more
   * than one entity, i.e. {@link module:engine/model/text~Text text node}.
   */
  get offsetSize() {
    return 1;
  }
  /**
   * Offset at which this node ends in it's parent. It is equal to the sum of this node's
   * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.
   * Equals to `null` if the node has no parent.
   */
  get endOffset() {
    return this.parent ? this.startOffset + this.offsetSize : null;
  }
  /**
   * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.
   */
  get nextSibling() {
    const e = this.index;
    return e !== null && this.parent.getChild(e + 1) || null;
  }
  /**
   * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.
   */
  get previousSibling() {
    const e = this.index;
    return e !== null && this.parent.getChild(e - 1) || null;
  }
  /**
   * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part
   * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.
   */
  get root() {
    let e = this;
    for (; e.parent; )
      e = e.parent;
    return e;
  }
  /**
   * Returns `true` if the node is inside a document root that is attached to the document.
   */
  isAttached() {
    return this.parent === null ? !1 : this.root.isAttached();
  }
  /**
   * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,
   * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to
   * create {@link module:engine/model/position~Position Position} instance.
   *
   * ```ts
   * const abc = new Text( 'abc' );
   * const foo = new Text( 'foo' );
   * const h1 = new Element( 'h1', null, new Text( 'header' ) );
   * const p = new Element( 'p', null, [ abc, foo ] );
   * const div = new Element( 'div', null, [ h1, p ] );
   * foo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.
   * h1.getPath(); // Returns [ 0 ].
   * div.getPath(); // Returns [].
   * ```
   */
  getPath() {
    const e = [];
    let t = this;
    for (; t.parent; )
      e.unshift(t.startOffset), t = t.parent;
    return e;
  }
  /**
   * Returns ancestors array of this node.
   *
   * @param options Options object.
   * @param options.includeSelf When set to `true` this node will be also included in parent's array.
   * @param options.parentFirst When set to `true`, array will be sorted from node's parent to root element,
   * otherwise root element will be the first item in the array.
   * @returns Array with ancestors.
   */
  getAncestors(e = {}) {
    const t = [];
    let i = e.includeSelf ? this : this.parent;
    for (; i; )
      t[e.parentFirst ? "push" : "unshift"](i), i = i.parent;
    return t;
  }
  /**
   * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
   * which is a common ancestor of both nodes.
   *
   * @param node The second node.
   * @param options Options object.
   * @param options.includeSelf When set to `true` both nodes will be considered "ancestors" too.
   * Which means that if e.g. node A is inside B, then their common ancestor will be B.
   */
  getCommonAncestor(e, t = {}) {
    const i = this.getAncestors(t), s = e.getAncestors(t);
    let r = 0;
    for (; i[r] == s[r] && i[r]; )
      r++;
    return r === 0 ? null : i[r - 1];
  }
  /**
   * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,
   * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
   *
   * @param node Node to compare with.
   */
  isBefore(e) {
    if (this == e || this.root !== e.root)
      return !1;
    const t = this.getPath(), i = e.getPath(), s = ce(t, i);
    switch (s) {
      case "prefix":
        return !0;
      case "extension":
        return !1;
      default:
        return t[s] < i[s];
    }
  }
  /**
   * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,
   * in different {@link module:engine/model/documentfragment~DocumentFragment}s).
   *
   * @param node Node to compare with.
   */
  isAfter(e) {
    return this == e || this.root !== e.root ? !1 : !this.isBefore(e);
  }
  /**
   * Checks if the node has an attribute with given key.
   *
   * @param key Key of attribute to check.
   * @returns `true` if attribute with given key is set on node, `false` otherwise.
   */
  hasAttribute(e) {
    return this._attrs.has(e);
  }
  /**
   * Gets an attribute value for given key or `undefined` if that attribute is not set on node.
   *
   * @param key Key of attribute to look for.
   * @returns Attribute value or `undefined`.
   */
  getAttribute(e) {
    return this._attrs.get(e);
  }
  /**
   * Returns iterator that iterates over this node's attributes.
   *
   * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
   * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
   */
  getAttributes() {
    return this._attrs.entries();
  }
  /**
   * Returns iterator that iterates over this node's attribute keys.
   */
  getAttributeKeys() {
    return this._attrs.keys();
  }
  /**
   * Converts `Node` to plain object and returns it.
   *
   * @returns `Node` converted to plain object.
   */
  toJSON() {
    const e = {};
    return this._attrs.size && (e.attributes = Array.from(this._attrs).reduce((t, i) => (t[i[0]] = i[1], t), {})), e;
  }
  /**
   * Creates a copy of this node, that is a node with exactly same attributes, and returns it.
   *
   * @internal
   * @returns Node with same attributes as this node.
   */
  _clone(e) {
    return new this.constructor(this._attrs);
  }
  /**
   * Removes this node from it's parent.
   *
   * @internal
   * @see module:engine/model/writer~Writer#remove
   */
  _remove() {
    this.parent._removeChildren(this.index);
  }
  /**
   * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.
   *
   * @see module:engine/model/writer~Writer#setAttribute
   * @internal
   * @param key Key of attribute to set.
   * @param value Attribute value.
   */
  _setAttribute(e, t) {
    this._attrs.set(e, t);
  }
  /**
   * Removes all attributes from the node and sets given attributes.
   *
   * @see module:engine/model/writer~Writer#setAttributes
   * @internal
   * @param attrs Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.
   */
  _setAttributesTo(e) {
    this._attrs = Xe(e);
  }
  /**
   * Removes an attribute with given key from the node.
   *
   * @see module:engine/model/writer~Writer#removeAttribute
   * @internal
   * @param key Key of attribute to remove.
   * @returns `true` if the attribute was set on the element, `false` otherwise.
   */
  _removeAttribute(e) {
    return this._attrs.delete(e);
  }
  /**
   * Removes all attributes from the node.
   *
   * @see module:engine/model/writer~Writer#clearAttributes
   * @internal
   */
  _clearAttributes() {
    this._attrs.clear();
  }
};
Bt.prototype.is = function(n) {
  return n === "node" || n === "model:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ci {
  /**
   * Creates an empty node list.
   *
   * @internal
   * @param nodes Nodes contained in this node list.
   */
  constructor(e) {
    this._nodes = [], e && this._insertNodes(0, e);
  }
  /**
   * Iterable interface.
   *
   * Iterates over all nodes contained inside this node list.
   */
  [Symbol.iterator]() {
    return this._nodes[Symbol.iterator]();
  }
  /**
   * Number of nodes contained inside this node list.
   */
  get length() {
    return this._nodes.length;
  }
  /**
   * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.
   */
  get maxOffset() {
    return this._nodes.reduce((e, t) => e + t.offsetSize, 0);
  }
  /**
   * Gets the node at the given index. Returns `null` if incorrect index was passed.
   */
  getNode(e) {
    return this._nodes[e] || null;
  }
  /**
   * Returns an index of the given node. Returns `null` if given node is not inside this node list.
   */
  getNodeIndex(e) {
    const t = this._nodes.indexOf(e);
    return t == -1 ? null : t;
  }
  /**
   * Returns the starting offset of given node. Starting offset is equal to the sum of
   * {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes that are before this node in this node list.
   */
  getNodeStartOffset(e) {
    const t = this.getNodeIndex(e);
    return t === null ? null : this._nodes.slice(0, t).reduce((i, s) => i + s.offsetSize, 0);
  }
  /**
   * Converts index to offset in node list.
   *
   * Returns starting offset of a node that is at given index. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
   * `model-nodelist-index-out-of-bounds` if given index is less than `0` or more than {@link #length}.
   */
  indexToOffset(e) {
    if (e == this._nodes.length)
      return this.maxOffset;
    const t = this._nodes[e];
    if (!t)
      throw new d("model-nodelist-index-out-of-bounds", this);
    return this.getNodeStartOffset(t);
  }
  /**
   * Converts offset in node list to index.
   *
   * Returns index of a node that occupies given offset. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
   * `model-nodelist-offset-out-of-bounds` if given offset is less than `0` or more than {@link #maxOffset}.
   */
  offsetToIndex(e) {
    let t = 0;
    for (const i of this._nodes) {
      if (e >= t && e < t + i.offsetSize)
        return this.getNodeIndex(i);
      t += i.offsetSize;
    }
    if (t != e)
      throw new d("model-nodelist-offset-out-of-bounds", this, {
        offset: e,
        nodeList: this
      });
    return this.length;
  }
  /**
   * Inserts given nodes at given index.
   *
   * @internal
   * @param index Index at which nodes should be inserted.
   * @param nodes Nodes to be inserted.
   */
  _insertNodes(e, t) {
    for (const i of t)
      if (!(i instanceof Bt))
        throw new d("model-nodelist-insertnodes-not-node", this);
    this._nodes = K_(this._nodes, Array.from(t), e, 0);
  }
  /**
   * Removes one or more nodes starting at the given index.
   *
   * @internal
   * @param indexStart Index of the first node to remove.
   * @param howMany Number of nodes to remove.
   * @returns Array containing removed nodes.
   */
  _removeNodes(e, t = 1) {
    return this._nodes.splice(e, t);
  }
  /**
   * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes
   * are also converted to their plain object representation.
   *
   * @returns `NodeList` instance converted to `Array`.
   */
  toJSON() {
    return this._nodes.map((e) => e.toJSON());
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let U = class Zs extends Bt {
  /**
   * Creates a text node.
   *
   * **Note:** Constructor of this class shouldn't be used directly in the code.
   * Use the {@link module:engine/model/writer~Writer#createText} method instead.
   *
   * @internal
   * @param data Node's text.
   * @param attrs Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
   */
  constructor(e, t) {
    super(t), this._data = e || "";
  }
  /**
   * @inheritDoc
   */
  get offsetSize() {
    return this.data.length;
  }
  /**
   * Returns a text data contained in the node.
   */
  get data() {
    return this._data;
  }
  /**
   * Converts `Text` instance to plain object and returns it.
   *
   * @returns`Text` instance converted to plain object.
   */
  toJSON() {
    const e = super.toJSON();
    return e.data = this.data, e;
  }
  /**
   * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.
   *
   * @internal
   * @returns `Text` instance created using given plain object.
   */
  _clone() {
    return new Zs(this.data, this.getAttributes());
  }
  /**
   * Creates a `Text` instance from given plain object (i.e. parsed JSON string).
   *
   * @param json Plain object to be converted to `Text`.
   * @returns `Text` instance created using given plain object.
   */
  static fromJSON(e) {
    return new Zs(e.data, e.attributes);
  }
};
U.prototype.is = function(n) {
  return n === "$text" || n === "model:$text" || // This are legacy values kept for backward compatibility.
  n === "text" || n === "model:text" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "node" || n === "model:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class xe extends ft {
  /**
   * Creates a text proxy.
   *
   * @internal
   * @param textNode Text node which part is represented by this text proxy.
   * @param offsetInText Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy
   * starts.
   * @param length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.
   */
  constructor(e, t, i) {
    if (super(), this.textNode = e, t < 0 || t > e.offsetSize)
      throw new d("model-textproxy-wrong-offsetintext", this);
    if (i < 0 || t + i > e.offsetSize)
      throw new d("model-textproxy-wrong-length", this);
    this.data = e.data.substring(t, t + i), this.offsetInText = t;
  }
  /**
   * Offset at which this text proxy starts in it's parent.
   *
   * @see module:engine/model/node~Node#startOffset
   */
  get startOffset() {
    return this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;
  }
  /**
   * Offset size of this text proxy. Equal to the number of characters represented by the text proxy.
   *
   * @see module:engine/model/node~Node#offsetSize
   */
  get offsetSize() {
    return this.data.length;
  }
  /**
   * Offset at which this text proxy ends in it's parent.
   *
   * @see module:engine/model/node~Node#endOffset
   */
  get endOffset() {
    return this.startOffset !== null ? this.startOffset + this.offsetSize : null;
  }
  /**
   * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/model/text~Text text node}
   * (`true`) or the whole text node (`false`).
   *
   * This is `false` when text proxy starts at the very beginning of {@link module:engine/model/textproxy~TextProxy#textNode textNode}
   * ({@link module:engine/model/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to
   * text node size.
   */
  get isPartial() {
    return this.offsetSize !== this.textNode.offsetSize;
  }
  /**
   * Parent of this text proxy, which is same as parent of text node represented by this text proxy.
   */
  get parent() {
    return this.textNode.parent;
  }
  /**
   * Root of this text proxy, which is same as root of text node represented by this text proxy.
   */
  get root() {
    return this.textNode.root;
  }
  /**
   * Gets path to this text proxy.
   *
   * @see module:engine/model/node~Node#getPath
   */
  getPath() {
    const e = this.textNode.getPath();
    return e.length > 0 && (e[e.length - 1] += this.offsetInText), e;
  }
  /**
   * Returns ancestors array of this text proxy.
   *
   * @param options Options object.
   * @param options.includeSelf When set to `true` this text proxy will be also included in parent's array.
   * @param options.parentFirst When set to `true`, array will be sorted from text proxy parent to root element,
   * otherwise root element will be the first item in the array.
   * @returns Array with ancestors.
   */
  getAncestors(e = {}) {
    const t = [];
    let i = e.includeSelf ? this : this.parent;
    for (; i; )
      t[e.parentFirst ? "push" : "unshift"](i), i = i.parent;
    return t;
  }
  /**
   * Checks if this text proxy has an attribute for given key.
   *
   * @param key Key of attribute to check.
   * @returns `true` if attribute with given key is set on text proxy, `false` otherwise.
   */
  hasAttribute(e) {
    return this.textNode.hasAttribute(e);
  }
  /**
   * Gets an attribute value for given key or `undefined` if that attribute is not set on text proxy.
   *
   * @param key Key of attribute to look for.
   * @returns Attribute value or `undefined`.
   */
  getAttribute(e) {
    return this.textNode.getAttribute(e);
  }
  /**
   * Returns iterator that iterates over this node's attributes. Attributes are returned as arrays containing two
   * items. First one is attribute key and second is attribute value.
   *
   * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
   */
  getAttributes() {
    return this.textNode.getAttributes();
  }
  /**
   * Returns iterator that iterates over this node's attribute keys.
   */
  getAttributeKeys() {
    return this.textNode.getAttributeKeys();
  }
}
xe.prototype.is = function(n) {
  return n === "$textProxy" || n === "model:$textProxy" || // This are legacy values kept for backward compatibility.
  n === "textProxy" || n === "model:textProxy";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class B extends Bt {
  /**
   * Creates a model element.
   *
   * **Note:** Constructor of this class shouldn't be used directly in the code.
   * Use the {@link module:engine/model/writer~Writer#createElement} method instead.
   *
   * @internal
   * @param name Element's name.
   * @param attrs Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.
   * @param children One or more nodes to be inserted as children of created element.
   */
  constructor(e, t, i) {
    super(t), this._children = new Ci(), this.name = e, i && this._insertChild(0, i);
  }
  /**
   * Number of this element's children.
   */
  get childCount() {
    return this._children.length;
  }
  /**
   * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.
   */
  get maxOffset() {
    return this._children.maxOffset;
  }
  /**
   * Is `true` if there are no nodes inside this element, `false` otherwise.
   */
  get isEmpty() {
    return this.childCount === 0;
  }
  /**
   * Gets the child at the given index.
   */
  getChild(e) {
    return this._children.getNode(e);
  }
  /**
   * Returns an iterator that iterates over all of this element's children.
   */
  getChildren() {
    return this._children[Symbol.iterator]();
  }
  /**
   * Returns an index of the given child node. Returns `null` if given node is not a child of this element.
   *
   * @param node Child node to look for.
   * @returns Child node's index in this element.
   */
  getChildIndex(e) {
    return this._children.getNodeIndex(e);
  }
  /**
   * Returns the starting offset of given child. Starting offset is equal to the sum of
   * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if
   * given node is not a child of this element.
   *
   * @param node Child node to look for.
   * @returns Child node's starting offset.
   */
  getChildStartOffset(e) {
    return this._children.getNodeStartOffset(e);
  }
  /**
   * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
   * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.
   *
   * ```ts
   * const textNode = new Text( 'foo' );
   * const pElement = new Element( 'p' );
   * const divElement = new Element( [ textNode, pElement ] );
   * divElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.
   * divElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.
   * divElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.
   * divElement.offsetToIndex( 2 ); // Returns 0.
   * divElement.offsetToIndex( 3 ); // Returns 1.
   * divElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.
   * ```
   */
  offsetToIndex(e) {
    return this._children.offsetToIndex(e);
  }
  /**
   * Returns a descendant node by its path relative to this element.
   *
   * ```ts
   * // <this>a<b>c</b></this>
   * this.getNodeByPath( [ 0 ] );     // -> "a"
   * this.getNodeByPath( [ 1 ] );     // -> <b>
   * this.getNodeByPath( [ 1, 0 ] );  // -> "c"
   * ```
   *
   * @param relativePath Path of the node to find, relative to this element.
   */
  getNodeByPath(e) {
    let t = this;
    for (const i of e)
      t = t.getChild(t.offsetToIndex(i));
    return t;
  }
  /**
   * Returns the parent element of the given name. Returns null if the element is not inside the desired parent.
   *
   * @param parentName The name of the parent element to find.
   * @param options Options object.
   * @param options.includeSelf When set to `true` this node will be also included while searching.
   */
  findAncestor(e, t = {}) {
    let i = t.includeSelf ? this : this.parent;
    for (; i; ) {
      if (i.name === e)
        return i;
      i = i.parent;
    }
    return null;
  }
  /**
   * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.
   *
   * @returns `Element` instance converted to plain object.
   */
  toJSON() {
    const e = super.toJSON();
    if (e.name = this.name, this._children.length > 0) {
      e.children = [];
      for (const t of this._children)
        e.children.push(t.toJSON());
    }
    return e;
  }
  /**
   * Creates a copy of this element and returns it. Created element has the same name and attributes as the original element.
   * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.
   *
   * @internal
   * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
   * element will be cloned without any child.
   */
  _clone(e = !1) {
    const t = e ? Array.from(this._children).map((i) => i._clone(!0)) : void 0;
    return new B(this.name, this.getAttributes(), t);
  }
  /**
   * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.
   *
   * @see module:engine/model/writer~Writer#append
   * @internal
   * @param nodes Nodes to be inserted.
   */
  _appendChild(e) {
    this._insertChild(this.childCount, e);
  }
  /**
   * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
   * to this element.
   *
   * @see module:engine/model/writer~Writer#insert
   * @internal
   * @param index Index at which nodes should be inserted.
   * @param items Items to be inserted.
   */
  _insertChild(e, t) {
    const i = ev(t);
    for (const s of i)
      s.parent !== null && s._remove(), s.parent = this;
    this._children._insertNodes(e, i);
  }
  /**
   * Removes one or more nodes starting at the given index and sets
   * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
   *
   * @see module:engine/model/writer~Writer#remove
   * @internal
   * @param index Index of the first node to remove.
   * @param howMany Number of nodes to remove.
   * @returns Array containing removed nodes.
   */
  _removeChildren(e, t = 1) {
    const i = this._children._removeNodes(e, t);
    for (const s of i)
      s.parent = null;
    return i;
  }
  /**
   * Creates an `Element` instance from given plain object (i.e. parsed JSON string).
   * Converts `Element` children to proper nodes.
   *
   * @param json Plain object to be converted to `Element`.
   * @returns `Element` instance created using given plain object.
   */
  static fromJSON(e) {
    let t;
    if (e.children) {
      t = [];
      for (const i of e.children)
        i.name ? t.push(B.fromJSON(i)) : t.push(U.fromJSON(i));
    }
    return new B(e.name, e.attributes, t);
  }
}
B.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "element" || n === "model:element") : n === "element" || n === "model:element" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "node" || n === "model:node";
};
function ev(n) {
  return typeof n == "string" ? [new U(n)] : (_e(n) || (n = [n]), Array.from(n).map((e) => typeof e == "string" ? new U(e) : e instanceof xe ? new U(e.data, e.getAttributes()) : e));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class at {
  /**
   * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.
   *
   * @param options Object with configuration.
   */
  constructor(e) {
    if (!e || !e.boundaries && !e.startPosition)
      throw new d("model-tree-walker-no-start-position", null);
    const t = e.direction || "forward";
    if (t != "forward" && t != "backward")
      throw new d("model-tree-walker-unknown-direction", e, { direction: t });
    this.direction = t, this.boundaries = e.boundaries || null, e.startPosition ? this._position = e.startPosition.clone() : this._position = w._createAt(this.boundaries[this.direction == "backward" ? "end" : "start"]), this.position.stickiness = "toNone", this.singleCharacters = !!e.singleCharacters, this.shallow = !!e.shallow, this.ignoreElementEnd = !!e.ignoreElementEnd, this._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null, this._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null, this._visitedParent = this.position.parent;
  }
  /**
   * Iterable interface.
   *
   * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}
   */
  [Symbol.iterator]() {
    return this;
  }
  /**
   * Iterator position. This is always static position, even if the initial position was a
   * {@link module:engine/model/liveposition~LivePosition live position}. If start position is not defined then position depends
   * on {@link #direction}. If direction is `'forward'` position starts form the beginning, when direction
   * is `'backward'` position starts from the end.
   */
  get position() {
    return this._position;
  }
  /**
   * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.
   *
   * For example:
   *
   * ```ts
   * walker.skip( value => value.type == 'text' ); // <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>
   * walker.skip( () => true ); // Move the position to the end: <paragraph>[]foo</paragraph> -> <paragraph>foo</paragraph>[]
   * walker.skip( () => false ); // Do not move the position.
   * ```
   *
   * @param skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should
   * return `true` if the value should be skipped or `false` if not.
   */
  skip(e) {
    let t, i, s, r;
    do
      s = this.position, r = this._visitedParent, { done: t, value: i } = this.next();
    while (!t && e(i));
    t || (this._position = s, this._visitedParent = r);
  }
  /**
   * Gets the next tree walker's value.
   */
  next() {
    return this.direction == "forward" ? this._next() : this._previous();
  }
  /**
   * Makes a step forward in model. Moves the {@link #position} to the next position and returns the encountered value.
   */
  _next() {
    const e = this.position, t = this.position.clone(), i = this._visitedParent;
    if (i.parent === null && t.offset === i.maxOffset)
      return { done: !0, value: void 0 };
    if (i === this._boundaryEndParent && t.offset == this.boundaries.end.offset)
      return { done: !0, value: void 0 };
    const s = Ei(t, i), r = s || ju(t, i, s);
    if (r instanceof B) {
      if (!this.shallow)
        t.path.push(0), this._visitedParent = r;
      else {
        if (this.boundaries && this.boundaries.end.isBefore(t))
          return { done: !0, value: void 0 };
        t.offset++;
      }
      return this._position = t, bt("elementStart", r, e, t, 1);
    }
    if (r instanceof U) {
      let o;
      if (this.singleCharacters)
        o = 1;
      else {
        let c = r.endOffset;
        this._boundaryEndParent == i && this.boundaries.end.offset < c && (c = this.boundaries.end.offset), o = c - t.offset;
      }
      const a = t.offset - r.startOffset, l = new xe(r, a, o);
      return t.offset += o, this._position = t, bt("text", l, e, t, o);
    }
    return t.path.pop(), t.offset++, this._position = t, this._visitedParent = i.parent, this.ignoreElementEnd ? this._next() : bt("elementEnd", i, e, t);
  }
  /**
   * Makes a step backward in model. Moves the {@link #position} to the previous position and returns the encountered value.
   */
  _previous() {
    const e = this.position, t = this.position.clone(), i = this._visitedParent;
    if (i.parent === null && t.offset === 0)
      return { done: !0, value: void 0 };
    if (i == this._boundaryStartParent && t.offset == this.boundaries.start.offset)
      return { done: !0, value: void 0 };
    const s = t.parent, r = Ei(t, s), o = r || qu(t, s, r);
    if (o instanceof B)
      return t.offset--, this.shallow ? (this._position = t, bt("elementStart", o, e, t, 1)) : (t.path.push(o.maxOffset), this._position = t, this._visitedParent = o, this.ignoreElementEnd ? this._previous() : bt("elementEnd", o, e, t));
    if (o instanceof U) {
      let a;
      if (this.singleCharacters)
        a = 1;
      else {
        let u = o.startOffset;
        this._boundaryStartParent == i && this.boundaries.start.offset > u && (u = this.boundaries.start.offset), a = t.offset - u;
      }
      const l = t.offset - o.startOffset, c = new xe(o, l - a, a);
      return t.offset -= a, this._position = t, bt("text", c, e, t, a);
    }
    return t.path.pop(), this._position = t, this._visitedParent = i.parent, bt("elementStart", i, e, t, 1);
  }
}
function bt(n, e, t, i, s) {
  return {
    done: !1,
    value: {
      type: n,
      item: e,
      previousPosition: t,
      nextPosition: i,
      length: s
    }
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class w extends ft {
  /**
   * Creates a position.
   *
   * @param root Root of the position.
   * @param path Position path. See {@link module:engine/model/position~Position#path}.
   * @param stickiness Position stickiness. See {@link module:engine/model/position~PositionStickiness}.
   */
  constructor(e, t, i = "toNone") {
    if (super(), !e.is("element") && !e.is("documentFragment"))
      throw new d("model-position-root-invalid", e);
    if (!(t instanceof Array) || t.length === 0)
      throw new d("model-position-path-incorrect-format", e, { path: t });
    e.is("rootElement") ? t = t.slice() : (t = [...e.getPath(), ...t], e = e.root), this.root = e, this.path = t, this.stickiness = i;
  }
  /**
   * Offset at which this position is located in its {@link module:engine/model/position~Position#parent parent}. It is equal
   * to the last item in position {@link module:engine/model/position~Position#path path}.
   *
   * @type {Number}
   */
  get offset() {
    return this.path[this.path.length - 1];
  }
  set offset(e) {
    this.path[this.path.length - 1] = e;
  }
  /**
   * Parent element of this position.
   *
   * Keep in mind that `parent` value is calculated when the property is accessed.
   * If {@link module:engine/model/position~Position#path position path}
   * leads to a non-existing element, `parent` property will throw error.
   *
   * Also it is a good idea to cache `parent` property if it is used frequently in an algorithm (i.e. in a long loop).
   */
  get parent() {
    let e = this.root;
    for (let t = 0; t < this.path.length - 1; t++)
      if (e = e.getChild(e.offsetToIndex(this.path[t])), !e)
        throw new d("model-position-path-incorrect", this, { position: this });
    if (e.is("$text"))
      throw new d("model-position-path-incorrect", this, { position: this });
    return e;
  }
  /**
   * Position {@link module:engine/model/position~Position#offset offset} converted to an index in position's parent node. It is
   * equal to the {@link module:engine/model/node~Node#index index} of a node after this position. If position is placed
   * in text node, position index is equal to the index of that text node.
   */
  get index() {
    return this.parent.offsetToIndex(this.offset);
  }
  /**
   * Returns {@link module:engine/model/text~Text text node} instance in which this position is placed or `null` if this
   * position is not in a text node.
   */
  get textNode() {
    return Ei(this, this.parent);
  }
  /**
   * Node directly after this position or `null` if this position is in text node.
   */
  get nodeAfter() {
    const e = this.parent;
    return ju(this, e, Ei(this, e));
  }
  /**
   * Node directly before this position or `null` if this position is in text node.
   */
  get nodeBefore() {
    const e = this.parent;
    return qu(this, e, Ei(this, e));
  }
  /**
   * Is `true` if position is at the beginning of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.
   */
  get isAtStart() {
    return this.offset === 0;
  }
  /**
   * Is `true` if position is at the end of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.
   */
  get isAtEnd() {
    return this.offset == this.parent.maxOffset;
  }
  /**
   * Checks whether this position is before or after given position.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   */
  compareWith(e) {
    if (this.root != e.root)
      return "different";
    const t = ce(this.path, e.path);
    switch (t) {
      case "same":
        return "same";
      case "prefix":
        return "before";
      case "extension":
        return "after";
      default:
        return this.path[t] < e.path[t] ? "before" : "after";
    }
  }
  /**
   * Gets the farthest position which matches the callback using
   * {@link module:engine/model/treewalker~TreeWalker TreeWalker}.
   *
   * For example:
   *
   * ```ts
   * getLastMatchingPosition( value => value.type == 'text' );
   * // <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>
   *
   * getLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } );
   * // <paragraph>foo[]</paragraph> -> <paragraph>[]foo</paragraph>
   *
   * getLastMatchingPosition( value => false );
   * // Do not move the position.
   * ```
   *
   * @param skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should
   * return `true` if the value should be skipped or `false` if not.
   * @param options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.
   *
   * @returns The position after the last item which matches the `skip` callback test.
   */
  getLastMatchingPosition(e, t = {}) {
    t.startPosition = this;
    const i = new at(t);
    return i.skip(e), i.position;
  }
  /**
   * Returns a path to this position's parent. Parent path is equal to position {@link module:engine/model/position~Position#path path}
   * but without the last item.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @returns Path to the parent.
   */
  getParentPath() {
    return this.path.slice(0, -1);
  }
  /**
   * Returns ancestors array of this position, that is this position's parent and its ancestors.
   *
   * @returns Array with ancestors.
   */
  getAncestors() {
    const e = this.parent;
    return e.is("documentFragment") ? [e] : e.getAncestors({ includeSelf: !0 });
  }
  /**
   * Returns the parent element of the given name. Returns null if the position is not inside the desired parent.
   *
   * @param parentName The name of the parent element to find.
   */
  findAncestor(e) {
    const t = this.parent;
    return t.is("element") ? t.findAncestor(e, { includeSelf: !0 }) : null;
  }
  /**
   * Returns the slice of two position {@link #path paths} which is identical. The {@link #root roots}
   * of these two paths must be identical.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param position The second position.
   * @returns The common path.
   */
  getCommonPath(e) {
    if (this.root != e.root)
      return [];
    const t = ce(this.path, e.path), i = typeof t == "string" ? Math.min(this.path.length, e.path.length) : t;
    return this.path.slice(0, i);
  }
  /**
   * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
   * which is a common ancestor of both positions. The {@link #root roots} of these two positions must be identical.
   *
   * @param position The second position.
   */
  getCommonAncestor(e) {
    const t = this.getAncestors(), i = e.getAncestors();
    let s = 0;
    for (; t[s] == i[s] && t[s]; )
      s++;
    return s === 0 ? null : t[s - 1];
  }
  /**
   * Returns a new instance of `Position`, that has same {@link #parent parent} but it's offset
   * is shifted by `shift` value (can be a negative value).
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param shift Offset shift. Can be a negative value.
   * @returns Shifted position.
   */
  getShiftedBy(e) {
    const t = this.clone(), i = t.offset + e;
    return t.offset = i < 0 ? 0 : i, t;
  }
  /**
   * Checks whether this position is after given position.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @see module:engine/model/position~Position#isBefore
   * @param  otherPosition Position to compare with.
   * @returns True if this position is after given position.
   */
  isAfter(e) {
    return this.compareWith(e) == "after";
  }
  /**
   * Checks whether this position is before given position.
   *
   * **Note:** watch out when using negation of the value returned by this method, because the negation will also
   * be `true` if positions are in different roots and you might not expect this. You should probably use
   * `a.isAfter( b ) || a.isEqual( b )` or `!a.isBefore( p ) && a.root == b.root` in most scenarios. If your
   * condition uses multiple `isAfter` and `isBefore` checks, build them so they do not use negated values, i.e.:
   *
   * ```ts
   * if ( a.isBefore( b ) && c.isAfter( d ) ) {
   * 	// do A.
   * } else {
   * 	// do B.
   * }
   * ```
   *
   * or, if you have only one if-branch:
   *
   * ```ts
   * if ( !( a.isBefore( b ) && c.isAfter( d ) ) {
   * 	// do B.
   * }
   * ```
   *
   * rather than:
   *
   * ```ts
   * if ( !a.isBefore( b ) || && !c.isAfter( d ) ) {
   * 	// do B.
   * } else {
   * 	// do A.
   * }
   * ```
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param otherPosition Position to compare with.
   * @returns True if this position is before given position.
   */
  isBefore(e) {
    return this.compareWith(e) == "before";
  }
  /**
   * Checks whether this position is equal to given position.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param otherPosition Position to compare with.
   * @returns True if positions are same.
   */
  isEqual(e) {
    return this.compareWith(e) == "same";
  }
  /**
   * Checks whether this position is touching given position. Positions touch when there are no text nodes
   * or empty nodes in a range between them. Technically, those positions are not equal but in many cases
   * they are very similar or even indistinguishable.
   *
   * @param otherPosition Position to compare with.
   * @returns True if positions touch.
   */
  isTouching(e) {
    if (this.root !== e.root)
      return !1;
    const t = Math.min(this.path.length, e.path.length);
    for (let i = 0; i < t; i++) {
      const s = this.path[i] - e.path[i];
      if (s < -1 || s > 1)
        return !1;
      if (s === 1)
        return Ea(e, this, i);
      if (s === -1)
        return Ea(this, e, i);
    }
    return this.path.length === e.path.length ? !0 : this.path.length > e.path.length ? Ys(this.path, t) : Ys(e.path, t);
  }
  /**
   * Checks if two positions are in the same parent.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param position Position to compare with.
   * @returns `true` if positions have the same parent, `false` otherwise.
   */
  hasSameParentAs(e) {
    if (this.root !== e.root)
      return !1;
    const t = this.getParentPath(), i = e.getParentPath();
    return ce(t, i) == "same";
  }
  /**
   * Returns a copy of this position that is transformed by given `operation`.
   *
   * The new position's parameters are updated accordingly to the effect of the `operation`.
   *
   * For example, if `n` nodes are inserted before the position, the returned position {@link ~Position#offset} will be
   * increased by `n`. If the position was in a merged element, it will be accordingly moved to the new element, etc.
   *
   * This method is safe to use it on non-existing positions (for example during operational transformation).
   *
   * @param operation Operation to transform by.
   * @returns Transformed position.
   */
  getTransformedByOperation(e) {
    let t;
    switch (e.type) {
      case "insert":
        t = this._getTransformedByInsertOperation(e);
        break;
      case "move":
      case "remove":
      case "reinsert":
        t = this._getTransformedByMoveOperation(e);
        break;
      case "split":
        t = this._getTransformedBySplitOperation(e);
        break;
      case "merge":
        t = this._getTransformedByMergeOperation(e);
        break;
      default:
        t = w._createAt(this);
        break;
    }
    return t;
  }
  /**
   * Returns a copy of this position transformed by an insert operation.
   *
   * @internal
   */
  _getTransformedByInsertOperation(e) {
    return this._getTransformedByInsertion(e.position, e.howMany);
  }
  /**
   * Returns a copy of this position transformed by a move operation.
   *
   * @internal
   */
  _getTransformedByMoveOperation(e) {
    return this._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany);
  }
  /**
   * Returns a copy of this position transformed by a split operation.
   *
   * @internal
   */
  _getTransformedBySplitOperation(e) {
    const t = e.movedRange;
    return t.containsPosition(this) || t.start.isEqual(this) && this.stickiness == "toNext" ? this._getCombined(e.splitPosition, e.moveTargetPosition) : e.graveyardPosition ? this._getTransformedByMove(e.graveyardPosition, e.insertionPosition, 1) : this._getTransformedByInsertion(e.insertionPosition, 1);
  }
  /**
   * Returns a copy of this position transformed by merge operation.
   *
   * @internal
   */
  _getTransformedByMergeOperation(e) {
    const t = e.movedRange, i = t.containsPosition(this) || t.start.isEqual(this);
    let s;
    return i ? (s = this._getCombined(e.sourcePosition, e.targetPosition), e.sourcePosition.isBefore(e.targetPosition) && (s = s._getTransformedByDeletion(e.deletionPosition, 1))) : this.isEqual(e.deletionPosition) ? s = w._createAt(e.deletionPosition) : s = this._getTransformedByMove(e.deletionPosition, e.graveyardPosition, 1), s;
  }
  /**
   * Returns a copy of this position that is updated by removing `howMany` nodes starting from `deletePosition`.
   * It may happen that this position is in a removed node. If that is the case, `null` is returned instead.
   *
   * @internal
   * @param deletePosition Position before the first removed node.
   * @param howMany How many nodes are removed.
   * @returns Transformed position or `null`.
   */
  _getTransformedByDeletion(e, t) {
    const i = w._createAt(this);
    if (this.root != e.root)
      return i;
    if (ce(e.getParentPath(), this.getParentPath()) == "same") {
      if (e.offset < this.offset) {
        if (e.offset + t > this.offset)
          return null;
        i.offset -= t;
      }
    } else if (ce(e.getParentPath(), this.getParentPath()) == "prefix") {
      const s = e.path.length - 1;
      if (e.offset <= this.path[s]) {
        if (e.offset + t > this.path[s])
          return null;
        i.path[s] -= t;
      }
    }
    return i;
  }
  /**
   * Returns a copy of this position that is updated by inserting `howMany` nodes at `insertPosition`.
   *
   * @internal
   * @param insertPosition Position where nodes are inserted.
   * @param howMany How many nodes are inserted.
   * @returns Transformed position.
   */
  _getTransformedByInsertion(e, t) {
    const i = w._createAt(this);
    if (this.root != e.root)
      return i;
    if (ce(e.getParentPath(), this.getParentPath()) == "same")
      (e.offset < this.offset || e.offset == this.offset && this.stickiness != "toPrevious") && (i.offset += t);
    else if (ce(e.getParentPath(), this.getParentPath()) == "prefix") {
      const s = e.path.length - 1;
      e.offset <= this.path[s] && (i.path[s] += t);
    }
    return i;
  }
  /**
   * Returns a copy of this position that is updated by moving `howMany` nodes from `sourcePosition` to `targetPosition`.
   *
   * @internal
   * @param sourcePosition Position before the first element to move.
   * @param targetPosition Position where moved elements will be inserted.
   * @param howMany How many consecutive nodes to move, starting from `sourcePosition`.
   * @returns Transformed position.
   */
  _getTransformedByMove(e, t, i) {
    if (t = t._getTransformedByDeletion(e, i), e.isEqual(t))
      return w._createAt(this);
    const s = this._getTransformedByDeletion(e, i);
    return s === null || e.isEqual(this) && this.stickiness == "toNext" || e.getShiftedBy(i).isEqual(this) && this.stickiness == "toPrevious" ? this._getCombined(e, t) : s._getTransformedByInsertion(t, i);
  }
  /**
   * Returns a new position that is a combination of this position and given positions.
   *
   * The combined position is a copy of this position transformed by moving a range starting at `source` position
   * to the `target` position. It is expected that this position is inside the moved range.
   *
   * Example:
   *
   * ```ts
   * let original = model.createPositionFromPath( root, [ 2, 3, 1 ] );
   * let source = model.createPositionFromPath( root, [ 2, 2 ] );
   * let target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );
   * original._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`
   * ```
   *
   * Explanation:
   *
   * We have a position `[ 2, 3, 1 ]` and move some nodes from `[ 2, 2 ]` to `[ 1, 1, 3 ]`. The original position
   * was inside moved nodes and now should point to the new place. The moved nodes will be after
   * positions `[ 1, 1, 3 ]`, `[ 1, 1, 4 ]`, `[ 1, 1, 5 ]`. Since our position was in the second moved node,
   * the transformed position will be in a sub-tree of a node at `[ 1, 1, 4 ]`. Looking at original path, we
   * took care of `[ 2, 3 ]` part of it. Now we have to add the rest of the original path to the transformed path.
   * Finally, the transformed position will point to `[ 1, 1, 4, 1 ]`.
   *
   * @internal
   * @param source Beginning of the moved range.
   * @param target Position where the range is moved.
   * @returns Combined position.
   */
  _getCombined(e, t) {
    const i = e.path.length - 1, s = w._createAt(t);
    return s.stickiness = this.stickiness, s.offset = s.offset + this.path[i] - e.offset, s.path = [...s.path, ...this.path.slice(i + 1)], s;
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    return {
      root: this.root.toJSON(),
      path: Array.from(this.path),
      stickiness: this.stickiness
    };
  }
  /**
   * Returns a new position that is equal to current position.
   */
  clone() {
    return new this.constructor(this.root, this.path, this.stickiness);
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/model/position~Position position},
   * * parent element and offset (offset defaults to `0`),
   * * parent element and `'end'` (sets position at the end of that element),
   * * {@link module:engine/model/item~Item model item} and `'before'` or `'after'` (sets position before or after given model item).
   *
   * This method is a shortcut to other factory methods such as:
   *
   * * {@link module:engine/model/position~Position._createBefore},
   * * {@link module:engine/model/position~Position._createAfter}.
   *
   * @internal
   * @param offset Offset or one of the flags. Used only when the first parameter is a {@link module:engine/model/item~Item model item}.
   * @param stickiness Position stickiness. Used only when the first parameter is a {@link module:engine/model/item~Item model item}.
   */
  static _createAt(e, t, i = "toNone") {
    if (e instanceof w)
      return new w(e.root, e.path, e.stickiness);
    {
      const s = e;
      if (t == "end")
        t = s.maxOffset;
      else {
        if (t == "before")
          return this._createBefore(s, i);
        if (t == "after")
          return this._createAfter(s, i);
        if (t !== 0 && !t)
          throw new d("model-createpositionat-offset-required", [this, e]);
      }
      if (!s.is("element") && !s.is("documentFragment"))
        throw new d("model-position-parent-incorrect", [this, e]);
      const r = s.getPath();
      return r.push(t), new this(s.root, r, i);
    }
  }
  /**
   * Creates a new position, after given {@link module:engine/model/item~Item model item}.
   *
   * @internal
   * @param item Item after which the position should be placed.
   * @param stickiness Position stickiness.
   */
  static _createAfter(e, t) {
    if (!e.parent)
      throw new d("model-position-after-root", [this, e], { root: e });
    return this._createAt(e.parent, e.endOffset, t);
  }
  /**
   * Creates a new position, before the given {@link module:engine/model/item~Item model item}.
   *
   * @internal
   * @param item Item before which the position should be placed.
   * @param stickiness Position stickiness.
   */
  static _createBefore(e, t) {
    if (!e.parent)
      throw new d("model-position-before-root", e, { root: e });
    return this._createAt(e.parent, e.startOffset, t);
  }
  /**
   * Creates a `Position` instance from given plain object (i.e. parsed JSON string).
   *
   * @param json Plain object to be converted to `Position`.
   * @param doc Document object that will be position owner.
   * @returns `Position` instance created using given plain object.
   */
  static fromJSON(e, t) {
    if (e.root === "$graveyard") {
      const i = new w(t.graveyard, e.path);
      return i.stickiness = e.stickiness, i;
    }
    if (!t.getRoot(e.root))
      throw new d("model-position-fromjson-no-root", t, { rootName: e.root });
    return new w(t.getRoot(e.root), e.path, e.stickiness);
  }
}
w.prototype.is = function(n) {
  return n === "position" || n === "model:position";
};
function Ei(n, e) {
  const t = e.getChild(e.offsetToIndex(n.offset));
  return t && t.is("$text") && t.startOffset < n.offset ? t : null;
}
function ju(n, e, t) {
  return t !== null ? null : e.getChild(e.offsetToIndex(n.offset));
}
function qu(n, e, t) {
  return t !== null ? null : e.getChild(e.offsetToIndex(n.offset) - 1);
}
function Ea(n, e, t) {
  return !(t + 1 === n.path.length || !Ys(e.path, t + 1) || !tv(n, t + 1));
}
function Ys(n, e) {
  for (; e < n.length; ) {
    if (n[e] !== 0)
      return !1;
    e++;
  }
  return !0;
}
function tv(n, e) {
  let t = n.parent, i = n.path.length - 1, s = 0;
  for (; i >= e; ) {
    if (n.path[i] + s !== t.maxOffset)
      return !1;
    s = 1, i--, t = t.parent;
  }
  return !0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class g extends ft {
  /**
   * Creates a range spanning from `start` position to `end` position.
   *
   * @param start The start position.
   * @param end The end position. If not set, the range will be collapsed at the `start` position.
   */
  constructor(e, t) {
    super(), this.start = w._createAt(e), this.end = t ? w._createAt(t) : w._createAt(e), this.start.stickiness = this.isCollapsed ? "toNone" : "toNext", this.end.stickiness = this.isCollapsed ? "toNone" : "toPrevious";
  }
  /**
   * Iterable interface.
   *
   * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns
   * them together with additional information like length or {@link module:engine/model/position~Position positions},
   * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.
   * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range
   * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.
   *
   * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range
   * and `ignoreElementEnd` option set to `true`.
   */
  *[Symbol.iterator]() {
    yield* new at({ boundaries: this, ignoreElementEnd: !0 });
  }
  /**
   * Describes whether the range is collapsed, that is if {@link #start} and
   * {@link #end} positions are equal.
   */
  get isCollapsed() {
    return this.start.isEqual(this.end);
  }
  /**
   * Describes whether this range is flat, that is if {@link #start} position and
   * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.
   */
  get isFlat() {
    const e = this.start.getParentPath(), t = this.end.getParentPath();
    return ce(e, t) == "same";
  }
  /**
   * Range root element.
   */
  get root() {
    return this.start.root;
  }
  /**
   * Checks whether this range contains given {@link module:engine/model/position~Position position}.
   *
   * @param position Position to check.
   * @returns `true` if given {@link module:engine/model/position~Position position} is contained
   * in this range,`false` otherwise.
   */
  containsPosition(e) {
    return e.isAfter(this.start) && e.isBefore(this.end);
  }
  /**
   * Checks whether this range contains given {@link ~Range range}.
   *
   * @param otherRange Range to check.
   * @param loose Whether the check is loose or strict. If the check is strict (`false`), compared range cannot
   * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or
   * even be equal to this range. Note that collapsed ranges are always compared in strict mode.
   * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.
   */
  containsRange(e, t = !1) {
    e.isCollapsed && (t = !1);
    const i = this.containsPosition(e.start) || t && this.start.isEqual(e.start), s = this.containsPosition(e.end) || t && this.end.isEqual(e.end);
    return i && s;
  }
  /**
   * Checks whether given {@link module:engine/model/item~Item} is inside this range.
   */
  containsItem(e) {
    const t = w._createBefore(e);
    return this.containsPosition(t) || this.start.isEqual(t);
  }
  /**
   * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.
   *
   * @param otherRange Range to compare with.
   * @returns `true` if ranges are equal, `false` otherwise.
   */
  isEqual(e) {
    return this.start.isEqual(e.start) && this.end.isEqual(e.end);
  }
  /**
   * Checks and returns whether this range intersects with given range.
   *
   * @param otherRange Range to compare with.
   * @returns `true` if ranges intersect, `false` otherwise.
   */
  isIntersecting(e) {
    return this.start.isBefore(e.end) && this.end.isAfter(e.start);
  }
  /**
   * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.
   * Returned array contains zero, one or two {@link ~Range ranges}.
   *
   * Examples:
   *
   * ```ts
   * let range = model.createRange(
   * 	model.createPositionFromPath( root, [ 2, 7 ] ),
   * 	model.createPositionFromPath( root, [ 4, 0, 1 ] )
   * );
   * let otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );
   * let transformed = range.getDifference( otherRange );
   * // transformed array has no ranges because `otherRange` contains `range`
   *
   * otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );
   * transformed = range.getDifference( otherRange );
   * // transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]
   *
   * otherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );
   * transformed = range.getDifference( otherRange );
   * // transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]
   * ```
   *
   * @param otherRange Range to differentiate against.
   * @returns The difference between ranges.
   */
  getDifference(e) {
    const t = [];
    return this.isIntersecting(e) ? (this.containsPosition(e.start) && t.push(new g(this.start, e.start)), this.containsPosition(e.end) && t.push(new g(e.end, this.end))) : t.push(new g(this.start, this.end)), t;
  }
  /**
   * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.
   * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.
   *
   * Examples:
   *
   * ```ts
   * let range = model.createRange(
   * 	model.createPositionFromPath( root, [ 2, 7 ] ),
   * 	model.createPositionFromPath( root, [ 4, 0, 1 ] )
   * );
   * let otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );
   * let transformed = range.getIntersection( otherRange ); // null - ranges have no common part
   *
   * otherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );
   * transformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]
   * ```
   *
   * @param otherRange Range to check for intersection.
   * @returns A common part of given ranges or `null` if ranges have no common part.
   */
  getIntersection(e) {
    if (this.isIntersecting(e)) {
      let t = this.start, i = this.end;
      return this.containsPosition(e.start) && (t = e.start), this.containsPosition(e.end) && (i = e.end), new g(t, i);
    }
    return null;
  }
  /**
   * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.
   * If ranges have no common part, returns `null`.
   *
   * Examples:
   *
   * ```ts
   * let range = model.createRange(
   * 	model.createPositionFromPath( root, [ 2, 7 ] ),
   * 	model.createPositionFromPath( root, [ 4, 0, 1 ] )
   * );
   * let otherRange = model.createRange(
   * 	model.createPositionFromPath( root, [ 1 ] ),
   * 	model.createPositionFromPath( root, [ 2 ] )
   * );
   * let transformed = range.getJoined( otherRange ); // null - ranges have no common part
   *
   * otherRange = model.createRange(
   * 	model.createPositionFromPath( root, [ 3 ] ),
   * 	model.createPositionFromPath( root, [ 5 ] )
   * );
   * transformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]
   * ```
   *
   * @param otherRange Range to be joined.
   * @param loose Whether the intersection check is loose or strict. If the check is strict (`false`),
   * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),
   * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.
   * @returns A sum of given ranges or `null` if ranges have no common part.
   */
  getJoined(e, t = !1) {
    let i = this.isIntersecting(e);
    if (i || (this.start.isBefore(e.start) ? i = t ? this.end.isTouching(e.start) : this.end.isEqual(e.start) : i = t ? e.end.isTouching(this.start) : e.end.isEqual(this.start)), !i)
      return null;
    let s = this.start, r = this.end;
    return e.start.isBefore(s) && (s = e.start), e.end.isAfter(r) && (r = e.end), new g(s, r);
  }
  /**
   * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.
   *
   * See an example of a model structure (`[` and `]` are range boundaries):
   *
   * ```
   * root                                                            root
   *  |- element DIV                         DIV             P2              P3             DIV
   *  |   |- element H                   H        P1        f o o           b a r       H         P4
   *  |   |   |- "fir[st"             fir[st     lorem                               se]cond     ipsum
   *  |   |- element P1
   *  |   |   |- "lorem"                                              ||
   *  |- element P2                                                   ||
   *  |   |- "foo"                                                    VV
   *  |- element P3
   *  |   |- "bar"                                                   root
   *  |- element DIV                         DIV             [P2             P3]             DIV
   *  |   |- element H                   H       [P1]       f o o           b a r        H         P4
   *  |   |   |- "se]cond"            fir[st]    lorem                               [se]cond     ipsum
   *  |   |- element P4
   *  |   |   |- "ipsum"
   * ```
   *
   * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.
   * We are looking for minimal set of flat ranges that contains the same nodes.
   *
   * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:
   *
   * ```
   * ( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = "st"
   * ( [ 0, 1 ], [ 0, 2 ] ) = element P1 ("lorem")
   * ( [ 1 ], [ 3 ] ) = element P2, element P3 ("foobar")
   * ( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = "se"
   * ```
   *
   * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned
   * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range
   * were omitted. Only their parts that were wholly in the range were returned.
   *
   * **Note:** this method is not returning flat ranges that contain no nodes.
   *
   * @returns Array of flat ranges covering this range.
   */
  getMinimalFlatRanges() {
    const e = [], t = this.start.getCommonPath(this.end).length, i = w._createAt(this.start);
    let s = i.parent;
    for (; i.path.length > t + 1; ) {
      const r = s.maxOffset - i.offset;
      r !== 0 && e.push(new g(i, i.getShiftedBy(r))), i.path = i.path.slice(0, -1), i.offset++, s = s.parent;
    }
    for (; i.path.length <= this.end.path.length; ) {
      const r = this.end.path[i.path.length - 1], o = r - i.offset;
      o !== 0 && e.push(new g(i, i.getShiftedBy(o))), i.offset = r, i.path.push(0);
    }
    return e;
  }
  /**
   * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.
   *
   * For example, to iterate over all items in the entire document root:
   *
   * ```ts
   * // Create a range spanning over the entire root content:
   * const range = editor.model.createRangeIn( editor.model.document.getRoot() );
   *
   * // Iterate over all items in this range:
   * for ( const value of range.getWalker() ) {
   * 	console.log( value.item );
   * }
   * ```
   *
   * @param options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.
   */
  getWalker(e = {}) {
    return e.boundaries = this, new at(e);
  }
  /**
   * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns
   * them.
   *
   * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option
   * set to `true`. However it returns only {@link module:engine/model/item~Item model items},
   * not {@link module:engine/model/treewalker~TreeWalkerValue}.
   *
   * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for
   * a full list of available options.
   *
   * @param options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.
   */
  *getItems(e = {}) {
    e.boundaries = this, e.ignoreElementEnd = !0;
    const t = new at(e);
    for (const i of t)
      yield i.item;
  }
  /**
   * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or
   * contained in this range.
   *
   * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only
   * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.
   *
   * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for
   * a full list of available options.
   *
   * @param options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.
   */
  *getPositions(e = {}) {
    e.boundaries = this;
    const t = new at(e);
    yield t.position;
    for (const i of t)
      yield i.nextPosition;
  }
  /**
   * Returns a range that is a result of transforming this range by given `operation`.
   *
   * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is
   * moved to a different part of document tree). For this reason, an array is returned by this method and it
   * may contain one or more `Range` instances.
   *
   * @param operation Operation to transform range by.
   * @returns Range which is the result of transformation.
   */
  getTransformedByOperation(e) {
    switch (e.type) {
      case "insert":
        return this._getTransformedByInsertOperation(e);
      case "move":
      case "remove":
      case "reinsert":
        return this._getTransformedByMoveOperation(e);
      case "split":
        return [this._getTransformedBySplitOperation(e)];
      case "merge":
        return [this._getTransformedByMergeOperation(e)];
    }
    return [new g(this.start, this.end)];
  }
  /**
   * Returns a range that is a result of transforming this range by multiple `operations`.
   *
   * @see ~Range#getTransformedByOperation
   * @param operations Operations to transform the range by.
   * @returns Range which is the result of transformation.
   */
  getTransformedByOperations(e) {
    const t = [new g(this.start, this.end)];
    for (const i of e)
      for (let s = 0; s < t.length; s++) {
        const r = t[s].getTransformedByOperation(i);
        t.splice(s, 1, ...r), s += r.length - 1;
      }
    for (let i = 0; i < t.length; i++) {
      const s = t[i];
      for (let r = i + 1; r < t.length; r++) {
        const o = t[r];
        (s.containsRange(o) || o.containsRange(s) || s.isEqual(o)) && t.splice(r, 1);
      }
    }
    return t;
  }
  /**
   * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}
   * which is a common ancestor of the range's both ends (in which the entire range is contained).
   */
  getCommonAncestor() {
    return this.start.getCommonAncestor(this.end);
  }
  /**
   * Returns an {@link module:engine/model/element~Element Element} contained by the range.
   * The element will be returned when it is the **only** node within the range and **fully–contained**
   * at the same time.
   */
  getContainedElement() {
    if (this.isCollapsed)
      return null;
    const e = this.start.nodeAfter, t = this.end.nodeBefore;
    return e && e.is("element") && e === t ? e : null;
  }
  /**
   * Converts `Range` to plain object and returns it.
   *
   * @returns `Node` converted to plain object.
   */
  toJSON() {
    return {
      start: this.start.toJSON(),
      end: this.end.toJSON()
    };
  }
  /**
   * Returns a new range that is equal to current range.
   */
  clone() {
    return new this.constructor(this.start, this.end);
  }
  /**
   * Returns a result of transforming a copy of this range by insert operation.
   *
   * One or more ranges may be returned as a result of this transformation.
   *
   * @internal
   */
  _getTransformedByInsertOperation(e, t = !1) {
    return this._getTransformedByInsertion(e.position, e.howMany, t);
  }
  /**
   * Returns a result of transforming a copy of this range by move operation.
   *
   * One or more ranges may be returned as a result of this transformation.
   *
   * @internal
   */
  _getTransformedByMoveOperation(e, t = !1) {
    const i = e.sourcePosition, s = e.howMany, r = e.targetPosition;
    return this._getTransformedByMove(i, r, s, t);
  }
  /**
   * Returns a result of transforming a copy of this range by split operation.
   *
   * Always one range is returned. The transformation is done in a way to not break the range.
   *
   * @internal
   */
  _getTransformedBySplitOperation(e) {
    const t = this.start._getTransformedBySplitOperation(e);
    let i = this.end._getTransformedBySplitOperation(e);
    return this.end.isEqual(e.insertionPosition) && (i = this.end.getShiftedBy(1)), t.root != i.root && (i = this.end.getShiftedBy(-1)), new g(t, i);
  }
  /**
   * Returns a result of transforming a copy of this range by merge operation.
   *
   * Always one range is returned. The transformation is done in a way to not break the range.
   *
   * @internal
   */
  _getTransformedByMergeOperation(e) {
    if (this.start.isEqual(e.targetPosition) && this.end.isEqual(e.deletionPosition))
      return new g(this.start);
    let t = this.start._getTransformedByMergeOperation(e), i = this.end._getTransformedByMergeOperation(e);
    return t.root != i.root && (i = this.end.getShiftedBy(-1)), t.isAfter(i) ? (e.sourcePosition.isBefore(e.targetPosition) ? (t = w._createAt(i), t.offset = 0) : (e.deletionPosition.isEqual(t) || (i = e.deletionPosition), t = e.targetPosition), new g(t, i)) : new g(t, i);
  }
  /**
   * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this
   * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are
   * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.
   *
   * Examples:
   *
   * ```ts
   * let range = model.createRange(
   * 	model.createPositionFromPath( root, [ 2, 7 ] ),
   * 	model.createPositionFromPath( root, [ 4, 0, 1 ] )
   * );
   * let transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );
   * // transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]
   *
   * transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );
   * // transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]
   *
   * transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );
   * // transformed array has one range, which is equal to original range
   *
   * transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );
   * // transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]
   * ```
   *
   * @internal
   * @param insertPosition Position where nodes are inserted.
   * @param howMany How many nodes are inserted.
   * @param spread Flag indicating whether this range should be spread if insertion
   * was inside the range. Defaults to `false`.
   * @returns Result of the transformation.
   */
  _getTransformedByInsertion(e, t, i = !1) {
    if (i && this.containsPosition(e))
      return [
        new g(this.start, e),
        new g(e.getShiftedBy(t), this.end._getTransformedByInsertion(e, t))
      ];
    {
      const s = new g(this.start, this.end);
      return s.start = s.start._getTransformedByInsertion(e, t), s.end = s.end._getTransformedByInsertion(e, t), [s];
    }
  }
  /**
   * Returns an array containing {@link ~Range ranges} that are a result of transforming this
   * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.
   *
   * @internal
   * @param sourcePosition Position from which nodes are moved.
   * @param targetPosition Position to where nodes are moved.
   * @param howMany How many nodes are moved.
   * @param spread Whether the range should be spread if the move points inside the range.
   * @returns  Result of the transformation.
   */
  _getTransformedByMove(e, t, i, s = !1) {
    if (this.isCollapsed) {
      const h = this.start._getTransformedByMove(e, t, i);
      return [new g(h)];
    }
    const r = g._createFromPositionAndShift(e, i), o = t._getTransformedByDeletion(e, i);
    if (this.containsPosition(t) && !s && (r.containsPosition(this.start) || r.containsPosition(this.end))) {
      const h = this.start._getTransformedByMove(e, t, i), f = this.end._getTransformedByMove(e, t, i);
      return [new g(h, f)];
    }
    let a;
    const l = this.getDifference(r);
    let c = null;
    const u = this.getIntersection(r);
    if (l.length == 1 ? c = new g(l[0].start._getTransformedByDeletion(e, i), l[0].end._getTransformedByDeletion(e, i)) : l.length == 2 && (c = new g(this.start, this.end._getTransformedByDeletion(e, i))), c ? a = c._getTransformedByInsertion(o, i, u !== null || s) : a = [], u) {
      const h = new g(u.start._getCombined(r.start, o), u.end._getCombined(r.start, o));
      a.length == 2 ? a.splice(1, 0, h) : a.push(h);
    }
    return a;
  }
  /**
   * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.
   *
   * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.
   *
   * If the deleted range contains transformed range, `null` will be returned.
   *
   * @internal
   * @param deletionPosition Position from which nodes are removed.
   * @param howMany How many nodes are removed.
   * @returns Result of the transformation.
   */
  _getTransformedByDeletion(e, t) {
    let i = this.start._getTransformedByDeletion(e, t), s = this.end._getTransformedByDeletion(e, t);
    return i == null && s == null ? null : (i == null && (i = e), s == null && (s = e), new g(i, s));
  }
  /**
   * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by
   * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.
   *
   * @internal
   * @param position Beginning of the range.
   * @param shift How long the range should be.
   */
  static _createFromPositionAndShift(e, t) {
    const i = e, s = e.getShiftedBy(t);
    return t > 0 ? new this(i, s) : new this(s, i);
  }
  /**
   * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * @internal
   * @param element Element which is a parent for the range.
   */
  static _createIn(e) {
    return new this(w._createAt(e, 0), w._createAt(e, e.maxOffset));
  }
  /**
   * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.
   *
   * @internal
   */
  static _createOn(e) {
    return this._createFromPositionAndShift(w._createBefore(e), e.offsetSize);
  }
  /**
   * Combines all ranges from the passed array into a one range. At least one range has to be passed.
   * Passed ranges must not have common parts.
   *
   * The first range from the array is a reference range. If other ranges start or end on the exactly same position where
   * the reference range, they get combined into one range.
   *
   * ```
   * [  ][]  [    ][ ][             ][ ][]  [  ]  // Passed ranges, shown sorted
   * [    ]                                       // The result of the function if the first range was a reference range.
   *         [                           ]        // The result of the function if the third-to-seventh range was a reference range.
   *                                        [  ]  // The result of the function if the last range was a reference range.
   * ```
   *
   * @internal
   * @param ranges Ranges to combine.
   * @returns Combined range.
   */
  static _createFromRanges(e) {
    if (e.length === 0)
      throw new d("range-create-from-ranges-empty-array", null);
    if (e.length == 1)
      return e[0].clone();
    const t = e[0];
    e.sort((r, o) => r.start.isAfter(o.start) ? 1 : -1);
    const i = e.indexOf(t), s = new this(t.start, t.end);
    if (i > 0)
      for (let r = i - 1; e[r].end.isEqual(s.start); r++)
        s.start = w._createAt(e[r].start);
    for (let r = i + 1; r < e.length && e[r].start.isEqual(s.end); r++)
      s.end = w._createAt(e[r].end);
    return s;
  }
  /**
   * Creates a `Range` instance from given plain object (i.e. parsed JSON string).
   *
   * @param json Plain object to be converted to `Range`.
   * @param doc Document object that will be range owner.
   * @returns `Range` instance created using given plain object.
   */
  static fromJSON(e, t) {
    return new this(w.fromJSON(e.start, t), w.fromJSON(e.end, t));
  }
}
g.prototype.is = function(n) {
  return n === "range" || n === "model:range";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Gu extends N() {
  /**
   * Creates an instance of the mapper.
   */
  constructor() {
    super(), this._modelToViewMapping = /* @__PURE__ */ new WeakMap(), this._viewToModelMapping = /* @__PURE__ */ new WeakMap(), this._viewToModelLengthCallbacks = /* @__PURE__ */ new Map(), this._markerNameToElements = /* @__PURE__ */ new Map(), this._elementToMarkerNames = /* @__PURE__ */ new Map(), this._deferredBindingRemovals = /* @__PURE__ */ new Map(), this._unboundMarkerNames = /* @__PURE__ */ new Set(), this.on("modelToViewPosition", (e, t) => {
      if (t.viewPosition)
        return;
      const i = this._modelToViewMapping.get(t.modelPosition.parent);
      if (!i)
        throw new d("mapping-model-position-view-parent-not-found", this, { modelPosition: t.modelPosition });
      t.viewPosition = this.findPositionIn(i, t.modelPosition.offset);
    }, { priority: "low" }), this.on("viewToModelPosition", (e, t) => {
      if (t.modelPosition)
        return;
      const i = this.findMappedViewAncestor(t.viewPosition), s = this._viewToModelMapping.get(i), r = this._toModelOffset(t.viewPosition.parent, t.viewPosition.offset, i);
      t.modelPosition = w._createAt(s, r);
    }, { priority: "low" });
  }
  /**
   * Marks model and view elements as corresponding. Corresponding elements can be retrieved by using
   * the {@link module:engine/conversion/mapper~Mapper#toModelElement toModelElement} and
   * {@link module:engine/conversion/mapper~Mapper#toViewElement toViewElement} methods.
   * The information that elements are bound is also used to translate positions.
   *
   * @param modelElement Model element.
   * @param viewElement View element.
   */
  bindElements(e, t) {
    this._modelToViewMapping.set(e, t), this._viewToModelMapping.set(t, e);
  }
  /**
   * Unbinds the given {@link module:engine/view/element~Element view element} from the map.
   *
   * **Note:** view-to-model binding will be removed, if it existed. However, corresponding model-to-view binding
   * will be removed only if model element is still bound to the passed `viewElement`.
   *
   * This behavior allows for re-binding model element to another view element without fear of losing the new binding
   * when the previously bound view element is unbound.
   *
   * @param viewElement View element to unbind.
   * @param options The options object.
   * @param options.defer Controls whether the binding should be removed immediately or deferred until a
   * {@link #flushDeferredBindings `flushDeferredBindings()`} call.
   */
  unbindViewElement(e, t = {}) {
    const i = this.toModelElement(e);
    if (this._elementToMarkerNames.has(e))
      for (const s of this._elementToMarkerNames.get(e))
        this._unboundMarkerNames.add(s);
    t.defer ? this._deferredBindingRemovals.set(e, e.root) : (this._viewToModelMapping.delete(e), this._modelToViewMapping.get(i) == e && this._modelToViewMapping.delete(i));
  }
  /**
   * Unbinds the given {@link module:engine/model/element~Element model element} from the map.
   *
   * **Note:** the model-to-view binding will be removed, if it existed. However, the corresponding view-to-model binding
   * will be removed only if the view element is still bound to the passed `modelElement`.
   *
   * This behavior lets for re-binding view element to another model element without fear of losing the new binding
   * when the previously bound model element is unbound.
   *
   * @param modelElement Model element to unbind.
   */
  unbindModelElement(e) {
    const t = this.toViewElement(e);
    this._modelToViewMapping.delete(e), this._viewToModelMapping.get(t) == e && this._viewToModelMapping.delete(t);
  }
  /**
   * Binds the given marker name with the given {@link module:engine/view/element~Element view element}. The element
   * will be added to the current set of elements bound with the given marker name.
   *
   * @param element Element to bind.
   * @param name Marker name.
   */
  bindElementToMarker(e, t) {
    const i = this._markerNameToElements.get(t) || /* @__PURE__ */ new Set();
    i.add(e);
    const s = this._elementToMarkerNames.get(e) || /* @__PURE__ */ new Set();
    s.add(t), this._markerNameToElements.set(t, i), this._elementToMarkerNames.set(e, s);
  }
  /**
   * Unbinds an element from given marker name.
   *
   * @param element Element to unbind.
   * @param name Marker name.
   */
  unbindElementFromMarkerName(e, t) {
    const i = this._markerNameToElements.get(t);
    i && (i.delete(e), i.size == 0 && this._markerNameToElements.delete(t));
    const s = this._elementToMarkerNames.get(e);
    s && (s.delete(t), s.size == 0 && this._elementToMarkerNames.delete(e));
  }
  /**
   * Returns all marker names of markers which have changed due to unbinding a view element (so it is assumed that the view element
   * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.
   */
  flushUnboundMarkerNames() {
    const e = Array.from(this._unboundMarkerNames);
    return this._unboundMarkerNames.clear(), e;
  }
  /**
   * Unbinds all deferred binding removals of view elements that in the meantime were not re-attached to some root or document fragment.
   *
   * See: {@link #unbindViewElement `unbindViewElement()`}.
   */
  flushDeferredBindings() {
    for (const [e, t] of this._deferredBindingRemovals)
      e.root == t && this.unbindViewElement(e);
    this._deferredBindingRemovals = /* @__PURE__ */ new Map();
  }
  /**
   * Removes all model to view and view to model bindings.
   */
  clearBindings() {
    this._modelToViewMapping = /* @__PURE__ */ new WeakMap(), this._viewToModelMapping = /* @__PURE__ */ new WeakMap(), this._markerNameToElements = /* @__PURE__ */ new Map(), this._elementToMarkerNames = /* @__PURE__ */ new Map(), this._unboundMarkerNames = /* @__PURE__ */ new Set(), this._deferredBindingRemovals = /* @__PURE__ */ new Map();
  }
  toModelElement(e) {
    return this._viewToModelMapping.get(e);
  }
  toViewElement(e) {
    return this._modelToViewMapping.get(e);
  }
  /**
   * Gets the corresponding model range.
   *
   * @param viewRange View range.
   * @returns Corresponding model range.
   */
  toModelRange(e) {
    return new g(this.toModelPosition(e.start), this.toModelPosition(e.end));
  }
  /**
   * Gets the corresponding view range.
   *
   * @param modelRange Model range.
   * @returns Corresponding view range.
   */
  toViewRange(e) {
    return new P(this.toViewPosition(e.start), this.toViewPosition(e.end));
  }
  /**
   * Gets the corresponding model position.
   *
   * @fires viewToModelPosition
   * @param viewPosition View position.
   * @returns Corresponding model position.
   */
  toModelPosition(e) {
    const t = {
      viewPosition: e,
      mapper: this
    };
    return this.fire("viewToModelPosition", t), t.modelPosition;
  }
  /**
   * Gets the corresponding view position.
   *
   * @fires modelToViewPosition
   * @param modelPosition Model position.
   * @param options Additional options for position mapping process.
   * @param options.isPhantom Should be set to `true` if the model position to map is pointing to a place
   * in model tree which no longer exists. For example, it could be an end of a removed model range.
   * @returns Corresponding view position.
   */
  toViewPosition(e, t = {}) {
    const i = {
      modelPosition: e,
      mapper: this,
      isPhantom: t.isPhantom
    };
    return this.fire("modelToViewPosition", i), i.viewPosition;
  }
  /**
   * Gets all view elements bound to the given marker name.
   *
   * @param name Marker name.
   * @returns View elements bound with the given marker name or `null`
   * if no elements are bound to the given marker name.
   */
  markerNameToElements(e) {
    const t = this._markerNameToElements.get(e);
    if (!t)
      return null;
    const i = /* @__PURE__ */ new Set();
    for (const s of t)
      if (s.is("attributeElement"))
        for (const r of s.getElementsWithSameId())
          i.add(r);
      else
        i.add(s);
    return i;
  }
  /**
   * Registers a callback that evaluates the length in the model of a view element with the given name.
   *
   * The callback is fired with one argument, which is a view element instance. The callback is expected to return
   * a number representing the length of the view element in the model.
   *
   * ```ts
   * // List item in view may contain nested list, which have other list items. In model though,
   * // the lists are represented by flat structure. Because of those differences, length of list view element
   * // may be greater than one. In the callback it's checked how many nested list items are in evaluated list item.
   *
   * function getViewListItemLength( element ) {
   * 	let length = 1;
   *
   * 	for ( let child of element.getChildren() ) {
   * 		if ( child.name == 'ul' || child.name == 'ol' ) {
   * 			for ( let item of child.getChildren() ) {
   * 				length += getViewListItemLength( item );
   * 			}
   * 		}
   * 	}
   *
   * 	return length;
   * }
   *
   * mapper.registerViewToModelLength( 'li', getViewListItemLength );
   * ```
   *
   * @param viewElementName Name of view element for which callback is registered.
   * @param lengthCallback Function return a length of view element instance in model.
   */
  registerViewToModelLength(e, t) {
    this._viewToModelLengthCallbacks.set(e, t);
  }
  /**
   * For the given `viewPosition`, finds and returns the closest ancestor of this position that has a mapping to
   * the model.
   *
   * @param viewPosition Position for which a mapped ancestor should be found.
   */
  findMappedViewAncestor(e) {
    let t = e.parent;
    for (; !this._viewToModelMapping.has(t); )
      t = t.parent;
    return t;
  }
  /**
   * Calculates model offset based on the view position and the block element.
   *
   * Example:
   *
   * ```html
   * <p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, p ) -> 5
   * ```
   *
   * Is a sum of:
   *
   * ```html
   * <p>foo|<b>bar</b></p> // _toModelOffset( p, 3, p ) -> 3
   * <p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2
   * ```
   *
   * @param viewParent Position parent.
   * @param viewOffset Position offset.
   * @param viewBlock Block used as a base to calculate offset.
   * @returns Offset in the model.
   */
  _toModelOffset(e, t, i) {
    if (i != e) {
      const r = this._toModelOffset(e.parent, e.index, i), o = this._toModelOffset(e, t, e);
      return r + o;
    }
    if (e.is("$text"))
      return t;
    let s = 0;
    for (let r = 0; r < t; r++)
      s += this.getModelLength(e.getChild(r));
    return s;
  }
  /**
   * Gets the length of the view element in the model.
   *
   * The length is calculated as follows:
   * * if a {@link #registerViewToModelLength length mapping callback} is provided for the given `viewNode`, it is used to
   * evaluate the model length (`viewNode` is used as first and only parameter passed to the callback),
   * * length of a {@link module:engine/view/text~Text text node} is equal to the length of its
   * {@link module:engine/view/text~Text#data data},
   * * length of a {@link module:engine/view/uielement~UIElement ui element} is equal to 0,
   * * length of a mapped {@link module:engine/view/element~Element element} is equal to 1,
   * * length of a non-mapped {@link module:engine/view/element~Element element} is equal to the length of its children.
   *
   * Examples:
   *
   * ```
   * foo                          -> 3 // Text length is equal to its data length.
   * <p>foo</p>                   -> 1 // Length of an element which is mapped is by default equal to 1.
   * <b>foo</b>                   -> 3 // Length of an element which is not mapped is a length of its children.
   * <div><p>x</p><p>y</p></div>  -> 2 // Assuming that <div> is not mapped and <p> are mapped.
   * ```
   *
   * @param viewNode View node.
   * @returns Length of the node in the tree model.
   */
  getModelLength(e) {
    if (this._viewToModelLengthCallbacks.get(e.name))
      return this._viewToModelLengthCallbacks.get(e.name)(e);
    if (this._viewToModelMapping.has(e))
      return 1;
    if (e.is("$text"))
      return e.data.length;
    if (e.is("uiElement"))
      return 0;
    {
      let t = 0;
      for (const i of e.getChildren())
        t += this.getModelLength(i);
      return t;
    }
  }
  /**
   * Finds the position in the view node (or in its children) with the expected model offset.
   *
   * Example:
   *
   * ```
   * <p>fo<b>bar</b>bom</p> -> expected offset: 4
   *
   * findPositionIn( p, 4 ):
   * <p>|fo<b>bar</b>bom</p> -> expected offset: 4, actual offset: 0
   * <p>fo|<b>bar</b>bom</p> -> expected offset: 4, actual offset: 2
   * <p>fo<b>bar</b>|bom</p> -> expected offset: 4, actual offset: 5 -> we are too far
   *
   * findPositionIn( b, 4 - ( 5 - 3 ) ):
   * <p>fo<b>|bar</b>bom</p> -> expected offset: 2, actual offset: 0
   * <p>fo<b>bar|</b>bom</p> -> expected offset: 2, actual offset: 3 -> we are too far
   *
   * findPositionIn( bar, 2 - ( 3 - 3 ) ):
   * We are in the text node so we can simple find the offset.
   * <p>fo<b>ba|r</b>bom</p> -> expected offset: 2, actual offset: 2 -> position found
   * ```
   *
   * @param viewParent Tree view element in which we are looking for the position.
   * @param expectedOffset Expected offset.
   * @returns Found position.
   */
  findPositionIn(e, t) {
    let i, s = 0, r = 0, o = 0;
    if (e.is("$text"))
      return new v(e, t);
    for (; r < t; )
      i = e.getChild(o), s = this.getModelLength(i), r += s, o++;
    return r == t ? this._moveViewPositionToTextNode(new v(e, o)) : this.findPositionIn(i, t - (r - s));
  }
  /**
   * Because we prefer positions in the text nodes over positions next to text nodes, if the view position was next to a text node,
   * it moves it into the text node instead.
   *
   * ```
   * <p>[]<b>foo</b></p> -> <p>[]<b>foo</b></p> // do not touch if position is not directly next to text
   * <p>foo[]<b>foo</b></p> -> <p>foo{}<b>foo</b></p> // move to text node
   * <p><b>[]foo</b></p> -> <p><b>{}foo</b></p> // move to text node
   * ```
   *
   * @param viewPosition Position potentially next to the text node.
   * @returns Position in the text node if possible.
   */
  _moveViewPositionToTextNode(e) {
    const t = e.nodeBefore, i = e.nodeAfter;
    return t instanceof j ? new v(t, t.data.length) : i instanceof j ? new v(i, 0) : e;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class iv {
  constructor() {
    this._consumable = /* @__PURE__ */ new Map(), this._textProxyRegistry = /* @__PURE__ */ new Map();
  }
  /**
   * Adds a consumable value to the consumables list and links it with a given model item.
   *
   * ```ts
   * modelConsumable.add( modelElement, 'insert' ); // Add `modelElement` insertion change to consumable values.
   * modelConsumable.add( modelElement, 'addAttribute:bold' ); // Add `bold` attribute insertion on `modelElement` change.
   * modelConsumable.add( modelElement, 'removeAttribute:bold' ); // Add `bold` attribute removal on `modelElement` change.
   * modelConsumable.add( modelSelection, 'selection' ); // Add `modelSelection` to consumable values.
   * modelConsumable.add( modelRange, 'range' ); // Add `modelRange` to consumable values.
   * ```
   *
   * @param item Model item, range or selection that has the consumable.
   * @param type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.
   * Second colon and everything after will be cut. Passing event name is a safe and good practice.
   */
  add(e, t) {
    t = Ji(t), e instanceof xe && (e = this._getSymbolForTextProxy(e)), this._consumable.has(e) || this._consumable.set(e, /* @__PURE__ */ new Map()), this._consumable.get(e).set(t, !0);
  }
  /**
   * Removes a given consumable value from a given model item.
   *
   * ```ts
   * modelConsumable.consume( modelElement, 'insert' ); // Remove `modelElement` insertion change from consumable values.
   * modelConsumable.consume( modelElement, 'addAttribute:bold' ); // Remove `bold` attribute insertion on `modelElement` change.
   * modelConsumable.consume( modelElement, 'removeAttribute:bold' ); // Remove `bold` attribute removal on `modelElement` change.
   * modelConsumable.consume( modelSelection, 'selection' ); // Remove `modelSelection` from consumable values.
   * modelConsumable.consume( modelRange, 'range' ); // Remove 'modelRange' from consumable values.
   * ```
   *
   * @param item Model item, range or selection from which consumable will be consumed.
   * @param type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.
   * Second colon and everything after will be cut. Passing event name is a safe and good practice.
   * @returns `true` if consumable value was available and was consumed, `false` otherwise.
   */
  consume(e, t) {
    return t = Ji(t), e instanceof xe && (e = this._getSymbolForTextProxy(e)), this.test(e, t) ? (this._consumable.get(e).set(t, !1), !0) : !1;
  }
  /**
   * Tests whether there is a consumable value of a given type connected with a given model item.
   *
   * ```ts
   * modelConsumable.test( modelElement, 'insert' ); // Check for `modelElement` insertion change.
   * modelConsumable.test( modelElement, 'addAttribute:bold' ); // Check for `bold` attribute insertion on `modelElement` change.
   * modelConsumable.test( modelElement, 'removeAttribute:bold' ); // Check for `bold` attribute removal on `modelElement` change.
   * modelConsumable.test( modelSelection, 'selection' ); // Check if `modelSelection` is consumable.
   * modelConsumable.test( modelRange, 'range' ); // Check if `modelRange` is consumable.
   * ```
   *
   * @param item Model item, range or selection to be tested.
   * @param type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.
   * Second colon and everything after will be cut. Passing event name is a safe and good practice.
   * @returns `null` if such consumable was never added, `false` if the consumable values was
   * already consumed or `true` if it was added and not consumed yet.
   */
  test(e, t) {
    t = Ji(t), e instanceof xe && (e = this._getSymbolForTextProxy(e));
    const i = this._consumable.get(e);
    if (i === void 0)
      return null;
    const s = i.get(t);
    return s === void 0 ? null : s;
  }
  /**
   * Reverts consuming of a consumable value.
   *
   * ```ts
   * modelConsumable.revert( modelElement, 'insert' ); // Revert consuming `modelElement` insertion change.
   * modelConsumable.revert( modelElement, 'addAttribute:bold' ); // Revert consuming `bold` attribute insert from `modelElement`.
   * modelConsumable.revert( modelElement, 'removeAttribute:bold' ); // Revert consuming `bold` attribute remove from `modelElement`.
   * modelConsumable.revert( modelSelection, 'selection' ); // Revert consuming `modelSelection`.
   * modelConsumable.revert( modelRange, 'range' ); // Revert consuming `modelRange`.
   * ```
   *
   * @param item Model item, range or selection to be reverted.
   * @param type Consumable type.
   * @returns `true` if consumable has been reversed, `false` otherwise. `null` if the consumable has
   * never been added.
   */
  revert(e, t) {
    t = Ji(t), e instanceof xe && (e = this._getSymbolForTextProxy(e));
    const i = this.test(e, t);
    return i === !1 ? (this._consumable.get(e).set(t, !0), !0) : i === !0 ? !1 : null;
  }
  /**
   * Verifies if all events from the specified group were consumed.
   *
   * @param eventGroup The events group to verify.
   */
  verifyAllConsumed(e) {
    const t = [];
    for (const [i, s] of this._consumable)
      for (const [r, o] of s) {
        const a = r.split(":")[0];
        o && e == a && t.push({
          event: r,
          item: i.name || i.description
        });
      }
    if (t.length)
      throw new d("conversion-model-consumable-not-consumed", null, { items: t });
  }
  /**
   * Gets a unique symbol for the passed {@link module:engine/model/textproxy~TextProxy} instance. All `TextProxy` instances that
   * have same parent, same start index and same end index will get the same symbol.
   *
   * Used internally to correctly consume `TextProxy` instances.
   *
   * @internal
   * @param textProxy `TextProxy` instance to get a symbol for.
   * @returns Symbol representing all equal instances of `TextProxy`.
   */
  _getSymbolForTextProxy(e) {
    let t = null;
    const i = this._textProxyRegistry.get(e.startOffset);
    if (i) {
      const s = i.get(e.endOffset);
      s && (t = s.get(e.parent));
    }
    return t || (t = this._addSymbolForTextProxy(e)), t;
  }
  /**
   * Adds a symbol for the given {@link module:engine/model/textproxy~TextProxy} instance.
   *
   * Used internally to correctly consume `TextProxy` instances.
   *
   * @param textProxy Text proxy instance.
   * @returns Symbol generated for given `TextProxy`.
   */
  _addSymbolForTextProxy(e) {
    const t = e.startOffset, i = e.endOffset, s = e.parent, r = Symbol("$textProxy:" + e.data);
    let o, a;
    return o = this._textProxyRegistry.get(t), o || (o = /* @__PURE__ */ new Map(), this._textProxyRegistry.set(t, o)), a = o.get(i), a || (a = /* @__PURE__ */ new Map(), o.set(i, a)), a.set(s, r), r;
  }
}
function Ji(n) {
  const e = n.split(":");
  return e[0] == "insert" ? e[0] : e[0] == "addMarker" || e[0] == "removeMarker" ? n : e.length > 1 ? e[0] + ":" + e[1] : e[0];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ku extends N() {
  /**
   * Creates a downcast dispatcher instance.
   *
   * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi
   *
   * @param conversionApi Additional properties for an interface that will be passed to events fired
   * by the downcast dispatcher.
   */
  constructor(e) {
    super(), this._conversionApi = { dispatcher: this, ...e }, this._firedEventsMap = /* @__PURE__ */ new WeakMap();
  }
  /**
   * Converts changes buffered in the given {@link module:engine/model/differ~Differ model differ}
   * and fires conversion events based on it.
   *
   * @fires insert
   * @fires remove
   * @fires attribute
   * @fires addMarker
   * @fires removeMarker
   * @fires reduceChanges
   * @param differ The differ object with buffered changes.
   * @param markers Markers related to the model fragment to convert.
   * @param writer The view writer that should be used to modify the view document.
   */
  convertChanges(e, t, i) {
    const s = this._createConversionApi(i, e.getRefreshedItems());
    for (const o of e.getMarkersToRemove())
      this._convertMarkerRemove(o.name, o.range, s);
    const r = this._reduceChanges(e.getChanges());
    for (const o of r)
      o.type === "insert" ? this._convertInsert(g._createFromPositionAndShift(o.position, o.length), s) : o.type === "reinsert" ? this._convertReinsert(g._createFromPositionAndShift(o.position, o.length), s) : o.type === "remove" ? this._convertRemove(o.position, o.length, o.name, s) : this._convertAttribute(o.range, o.attributeKey, o.attributeOldValue, o.attributeNewValue, s);
    for (const o of s.mapper.flushUnboundMarkerNames()) {
      const a = t.get(o).getRange();
      this._convertMarkerRemove(o, a, s), this._convertMarkerAdd(o, a, s);
    }
    for (const o of e.getMarkersToAdd())
      this._convertMarkerAdd(o.name, o.range, s);
    s.mapper.flushDeferredBindings(), s.consumable.verifyAllConsumed("insert");
  }
  /**
   * Starts a conversion of a model range and the provided markers.
   *
   * @fires insert
   * @fires attribute
   * @fires addMarker
   * @param range The inserted range.
   * @param markers The map of markers that should be down-casted.
   * @param writer The view writer that should be used to modify the view document.
   * @param options Optional options object passed to `convertionApi.options`.
   */
  convert(e, t, i, s = {}) {
    const r = this._createConversionApi(i, void 0, s);
    this._convertInsert(e, r);
    for (const [o, a] of t)
      this._convertMarkerAdd(o, a, r);
    r.consumable.verifyAllConsumed("insert");
  }
  /**
   * Starts the model selection conversion.
   *
   * Fires events for a given {@link module:engine/model/selection~Selection selection} to start the selection conversion.
   *
   * @fires selection
   * @fires addMarker
   * @fires attribute
   * @param selection The selection to convert.
   * @param markers Markers connected with the converted model.
   * @param writer View writer that should be used to modify the view document.
   */
  convertSelection(e, t, i) {
    const s = Array.from(t.getMarkersAtPosition(e.getFirstPosition())), r = this._createConversionApi(i);
    if (this._addConsumablesForSelection(r.consumable, e, s), this.fire("selection", { selection: e }, r), !!e.isCollapsed) {
      for (const o of s) {
        const a = o.getRange();
        if (!nv(e.getFirstPosition(), o, r.mapper))
          continue;
        const l = {
          item: e,
          markerName: o.name,
          markerRange: a
        };
        r.consumable.test(e, "addMarker:" + o.name) && this.fire(`addMarker:${o.name}`, l, r);
      }
      for (const o of e.getAttributeKeys()) {
        const a = {
          item: e,
          range: e.getFirstRange(),
          attributeKey: o,
          attributeOldValue: null,
          attributeNewValue: e.getAttribute(o)
        };
        r.consumable.test(e, "attribute:" + a.attributeKey) && this.fire(`attribute:${a.attributeKey}:$text`, a, r);
      }
    }
  }
  /**
   * Fires insertion conversion of a range of nodes.
   *
   * For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,
   * {@link #event:attribute `attribute` event is fired}.
   *
   * @fires insert
   * @fires attribute
   * @param range The inserted range.
   * @param conversionApi The conversion API object.
   * @param options.doNotAddConsumables Whether the ModelConsumable should not get populated
   * for items in the provided range.
   */
  _convertInsert(e, t, i = {}) {
    i.doNotAddConsumables || this._addConsumablesForInsert(t.consumable, Array.from(e));
    for (const s of Array.from(e.getWalker({ shallow: !0 })).map(Aa))
      this._testAndFire("insert", s, t);
  }
  /**
   * Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.
   *
   * @param position Position from which node was removed.
   * @param length Offset size of removed node.
   * @param name Name of removed node.
   * @param conversionApi The conversion API object.
   */
  _convertRemove(e, t, i, s) {
    this.fire(`remove:${i}`, { position: e, length: t }, s);
  }
  /**
   * Starts a conversion of an attribute change on a given `range`.
   *
   * For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.
   *
   * @fires attribute
   * @param range Changed range.
   * @param key Key of the attribute that has changed.
   * @param oldValue Attribute value before the change or `null` if the attribute has not been set before.
   * @param newValue New attribute value or `null` if the attribute has been removed.
   * @param conversionApi The conversion API object.
   */
  _convertAttribute(e, t, i, s, r) {
    this._addConsumablesForRange(r.consumable, e, `attribute:${t}`);
    for (const o of e) {
      const a = {
        item: o.item,
        range: g._createFromPositionAndShift(o.previousPosition, o.length),
        attributeKey: t,
        attributeOldValue: i,
        attributeNewValue: s
      };
      this._testAndFire(`attribute:${t}`, a, r);
    }
  }
  /**
   * Fires re-insertion conversion (with a `reconversion` flag passed to `insert` events)
   * of a range of elements (only elements on the range depth, without children).
   *
   * For each node in the range on its depth (without children), {@link #event:insert `insert` event} is fired.
   * For each attribute on each node, {@link #event:attribute `attribute` event} is fired.
   *
   * @fires insert
   * @fires attribute
   * @param range The range to reinsert.
   * @param conversionApi The conversion API object.
   */
  _convertReinsert(e, t) {
    const i = Array.from(e.getWalker({ shallow: !0 }));
    this._addConsumablesForInsert(t.consumable, i);
    for (const s of i.map(Aa))
      this._testAndFire("insert", { ...s, reconversion: !0 }, t);
  }
  /**
   * Converts the added marker. Fires the {@link #event:addMarker `addMarker`} event for each item
   * in the marker's range. If the range is collapsed, a single event is dispatched. See the event description for more details.
   *
   * @fires addMarker
   * @param markerName Marker name.
   * @param markerRange The marker range.
   * @param conversionApi The conversion API object.
   */
  _convertMarkerAdd(e, t, i) {
    if (t.root.rootName == "$graveyard")
      return;
    const s = `addMarker:${e}`;
    if (i.consumable.add(t, s), this.fire(s, { markerName: e, markerRange: t }, i), !!i.consumable.consume(t, s)) {
      this._addConsumablesForRange(i.consumable, t, s);
      for (const r of t.getItems()) {
        if (!i.consumable.test(r, s))
          continue;
        const o = { item: r, range: g._createOn(r), markerName: e, markerRange: t };
        this.fire(s, o, i);
      }
    }
  }
  /**
   * Fires the conversion of the marker removal. Fires the {@link #event:removeMarker `removeMarker`} event with the provided data.
   *
   * @fires removeMarker
   * @param markerName Marker name.
   * @param markerRange The marker range.
   * @param conversionApi The conversion API object.
   */
  _convertMarkerRemove(e, t, i) {
    t.root.rootName != "$graveyard" && this.fire(`removeMarker:${e}`, { markerName: e, markerRange: t }, i);
  }
  /**
   * Fires the reduction of changes buffered in the {@link module:engine/model/differ~Differ `Differ`}.
   *
   * Features can replace selected {@link module:engine/model/differ~DiffItem `DiffItem`}s with `reinsert` entries to trigger
   * reconversion. The {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToStructure
   * `DowncastHelpers.elementToStructure()`} is using this event to trigger reconversion.
   *
   * @fires reduceChanges
   */
  _reduceChanges(e) {
    const t = { changes: e };
    return this.fire("reduceChanges", t), t.changes;
  }
  /**
   * Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from a given range,
   * assuming that the range has just been inserted to the model.
   *
   * @param consumable The consumable.
   * @param walkerValues The walker values for the inserted range.
   * @returns The values to consume.
   */
  _addConsumablesForInsert(e, t) {
    for (const i of t) {
      const s = i.item;
      if (e.test(s, "insert") === null) {
        e.add(s, "insert");
        for (const r of s.getAttributeKeys())
          e.add(s, "attribute:" + r);
      }
    }
    return e;
  }
  /**
   * Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for a given range.
   *
   * @param consumable The consumable.
   * @param range The affected range.
   * @param type Consumable type.
   * @returns The values to consume.
   */
  _addConsumablesForRange(e, t, i) {
    for (const s of t.getItems())
      e.add(s, i);
    return e;
  }
  /**
   * Populates provided {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.
   *
   * @param consumable The consumable.
   * @param selection The selection to create the consumable from.
   * @param markers Markers that contain the selection.
   * @returns The values to consume.
   */
  _addConsumablesForSelection(e, t, i) {
    e.add(t, "selection");
    for (const s of i)
      e.add(t, "addMarker:" + s.name);
    for (const s of t.getAttributeKeys())
      e.add(t, "attribute:" + s);
    return e;
  }
  /**
   * Tests whether given event wasn't already fired and if so, fires it.
   *
   * @fires insert
   * @fires attribute
   * @param type Event type.
   * @param data Event data.
   * @param conversionApi The conversion API object.
   */
  _testAndFire(e, t, i) {
    const s = sv(e, t), r = t.item.is("$textProxy") ? i.consumable._getSymbolForTextProxy(t.item) : t.item, o = this._firedEventsMap.get(i), a = o.get(r);
    if (!a)
      o.set(r, /* @__PURE__ */ new Set([s]));
    else if (!a.has(s))
      a.add(s);
    else
      return;
    this.fire(s, t, i);
  }
  /**
   * Fires not already fired events for setting attributes on just inserted item.
   *
   * @param item The model item to convert attributes for.
   * @param conversionApi The conversion API object.
   */
  _testAndFireAddAttributes(e, t) {
    const i = {
      item: e,
      range: g._createOn(e)
    };
    for (const s of i.item.getAttributeKeys())
      i.attributeKey = s, i.attributeOldValue = null, i.attributeNewValue = i.item.getAttribute(s), this._testAndFire(`attribute:${s}`, i, t);
  }
  /**
   * Builds an instance of the {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi} from a template and a given
   * {@link module:engine/view/downcastwriter~DowncastWriter `DowncastWriter`} and options object.
   *
   * @param writer View writer that should be used to modify the view document.
   * @param refreshedItems A set of model elements that should not reuse their
   * previous view representations.
   * @param options Optional options passed to `convertionApi.options`.
   * @return The conversion API object.
   */
  _createConversionApi(e, t = /* @__PURE__ */ new Set(), i = {}) {
    const s = {
      ...this._conversionApi,
      consumable: new iv(),
      writer: e,
      options: i,
      convertItem: (r) => this._convertInsert(g._createOn(r), s),
      convertChildren: (r) => this._convertInsert(g._createIn(r), s, { doNotAddConsumables: !0 }),
      convertAttributes: (r) => this._testAndFireAddAttributes(r, s),
      canReuseView: (r) => !t.has(s.mapper.toModelElement(r))
    };
    return this._firedEventsMap.set(s, /* @__PURE__ */ new Map()), s;
  }
}
function nv(n, e, t) {
  const i = e.getRange(), s = Array.from(n.getAncestors());
  return s.shift(), s.reverse(), !s.some((o) => {
    if (i.containsItem(o))
      return !!t.toViewElement(o).getCustomProperty("addHighlight");
  });
}
function sv(n, e) {
  const t = e.item.is("element") ? e.item.name : "$text";
  return `${n}:${t}`;
}
function Aa(n) {
  const e = n.item, t = g._createFromPositionAndShift(n.previousPosition, n.length);
  return {
    item: e,
    range: t
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class we extends N(ft) {
  /**
   * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}
   * or creates an empty selection if no arguments were passed.
   *
   * ```ts
   * // Creates empty selection without ranges.
   * const selection = writer.createSelection();
   *
   * // Creates selection at the given range.
   * const range = writer.createRange( start, end );
   * const selection = writer.createSelection( range );
   *
   * // Creates selection at the given ranges
   * const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
   * const selection = writer.createSelection( ranges );
   *
   * // Creates selection from the other selection.
   * // Note: It doesn't copy selection attributes.
   * const otherSelection = writer.createSelection();
   * const selection = writer.createSelection( otherSelection );
   *
   * // Creates selection from the given document selection.
   * // Note: It doesn't copy selection attributes.
   * const documentSelection = model.document.selection;
   * const selection = writer.createSelection( documentSelection );
   *
   * // Creates selection at the given position.
   * const position = writer.createPositionFromPath( root, path );
   * const selection = writer.createSelection( position );
   *
   * // Creates selection at the given offset in the given element.
   * const paragraph = writer.createElement( 'paragraph' );
   * const selection = writer.createSelection( paragraph, offset );
   *
   * // Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
   * // first child of that element and ends after the last child of that element.
   * const selection = writer.createSelection( paragraph, 'in' );
   *
   * // Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
   * // just after the item.
   * const selection = writer.createSelection( paragraph, 'on' );
   * ```
   *
   * Selection's constructor allow passing additional options (`'backward'`) as the last argument.
   *
   * ```ts
   * // Creates backward selection.
   * const selection = writer.createSelection( range, { backward: true } );
   * ```
   *
   * @internal
   */
  constructor(...e) {
    super(), this._lastRangeBackward = !1, this._attrs = /* @__PURE__ */ new Map(), this._ranges = [], e.length && this.setTo(...e);
  }
  /**
   * Selection anchor. Anchor is the position from which the selection was started. If a user is making a selection
   * by dragging the mouse, the anchor is where the user pressed the mouse button (the beginning of the selection).
   *
   * Anchor and {@link #focus} define the direction of the selection, which is important
   * when expanding/shrinking selection. The focus moves, while the anchor should remain in the same place.
   *
   * Anchor is always set to the {@link module:engine/model/range~Range#start start} or
   * {@link module:engine/model/range~Range#end end} position of the last of selection's ranges. Whether it is
   * the `start` or `end` depends on the specified `options.backward`. See the {@link #setTo `setTo()`} method.
   *
   * May be set to `null` if there are no ranges in the selection.
   *
   * @see #focus
   */
  get anchor() {
    if (this._ranges.length > 0) {
      const e = this._ranges[this._ranges.length - 1];
      return this._lastRangeBackward ? e.end : e.start;
    }
    return null;
  }
  /**
   * Selection focus. Focus is the position where the selection ends. If a user is making a selection
   * by dragging the mouse, the focus is where the mouse cursor is.
   *
   * May be set to `null` if there are no ranges in the selection.
   *
   * @see #anchor
   */
  get focus() {
    if (this._ranges.length > 0) {
      const e = this._ranges[this._ranges.length - 1];
      return this._lastRangeBackward ? e.start : e.end;
    }
    return null;
  }
  /**
   * Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it
   * and it is collapsed.
   */
  get isCollapsed() {
    return this._ranges.length === 1 ? this._ranges[0].isCollapsed : !1;
  }
  /**
   * Returns the number of ranges in the selection.
   */
  get rangeCount() {
    return this._ranges.length;
  }
  /**
   * Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.
   */
  get isBackward() {
    return !this.isCollapsed && this._lastRangeBackward;
  }
  /**
   * Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,
   * the same number of ranges and all ranges from one selection equal to ranges from the another selection.
   *
   * @param otherSelection Selection to compare with.
   * @returns `true` if selections are equal, `false` otherwise.
   */
  isEqual(e) {
    if (this.rangeCount != e.rangeCount)
      return !1;
    if (this.rangeCount === 0)
      return !0;
    if (!this.anchor.isEqual(e.anchor) || !this.focus.isEqual(e.focus))
      return !1;
    for (const t of this._ranges) {
      let i = !1;
      for (const s of e._ranges)
        if (t.isEqual(s)) {
          i = !0;
          break;
        }
      if (!i)
        return !1;
    }
    return !0;
  }
  /**
   * Returns an iterable object that iterates over copies of selection ranges.
   */
  *getRanges() {
    for (const e of this._ranges)
      yield new g(e.start, e.end);
  }
  /**
   * Returns a copy of the first range in the selection.
   * First range is the one which {@link module:engine/model/range~Range#start start} position
   * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges
   * (not to confuse with the first range added to the selection).
   *
   * Returns `null` if there are no ranges in selection.
   */
  getFirstRange() {
    let e = null;
    for (const t of this._ranges)
      (!e || t.start.isBefore(e.start)) && (e = t);
    return e ? new g(e.start, e.end) : null;
  }
  /**
   * Returns a copy of the last range in the selection.
   * Last range is the one which {@link module:engine/model/range~Range#end end} position
   * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most
   * recently added to the selection).
   *
   * Returns `null` if there are no ranges in selection.
   */
  getLastRange() {
    let e = null;
    for (const t of this._ranges)
      (!e || t.end.isAfter(e.end)) && (e = t);
    return e ? new g(e.start, e.end) : null;
  }
  /**
   * Returns the first position in the selection.
   * First position is the position that {@link module:engine/model/position~Position#isBefore is before}
   * any other position in the selection.
   *
   * Returns `null` if there are no ranges in selection.
   */
  getFirstPosition() {
    const e = this.getFirstRange();
    return e ? e.start.clone() : null;
  }
  /**
   * Returns the last position in the selection.
   * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}
   * any other position in the selection.
   *
   * Returns `null` if there are no ranges in selection.
   */
  getLastPosition() {
    const e = this.getLastRange();
    return e ? e.end.clone() : null;
  }
  /**
   * Sets this selection's ranges and direction to the specified location based on the given
   * {@link module:engine/model/selection~Selectable selectable}.
   *
   * ```ts
   * // Removes all selection's ranges.
   * selection.setTo( null );
   *
   * // Sets selection to the given range.
   * const range = writer.createRange( start, end );
   * selection.setTo( range );
   *
   * // Sets selection to given ranges.
   * const ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];
   * selection.setTo( ranges );
   *
   * // Sets selection to other selection.
   * // Note: It doesn't copy selection attributes.
   * const otherSelection = writer.createSelection();
   * selection.setTo( otherSelection );
   *
   * // Sets selection to the given document selection.
   * // Note: It doesn't copy selection attributes.
   * const documentSelection = new DocumentSelection( doc );
   * selection.setTo( documentSelection );
   *
   * // Sets collapsed selection at the given position.
   * const position = writer.createPositionFromPath( root, path );
   * selection.setTo( position );
   *
   * // Sets collapsed selection at the position of the given node and an offset.
   * selection.setTo( paragraph, offset );
   * ```
   *
   * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * ```ts
   * selection.setTo( paragraph, 'in' );
   * ```
   *
   * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.
   *
   * ```ts
   * selection.setTo( paragraph, 'on' );
   * ```
   *
   * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.
   *
   * ```ts
   * // Sets backward selection.
   * const selection = writer.createSelection( range, { backward: true } );
   * ```
   */
  setTo(...e) {
    let [t, i, s] = e;
    if (typeof i == "object" && (s = i, i = void 0), t === null)
      this._setRanges([]);
    else if (t instanceof we)
      this._setRanges(t.getRanges(), t.isBackward);
    else if (t && typeof t.getRanges == "function")
      this._setRanges(t.getRanges(), t.isBackward);
    else if (t instanceof g)
      this._setRanges([t], !!s && !!s.backward);
    else if (t instanceof w)
      this._setRanges([new g(t)]);
    else if (t instanceof Bt) {
      const r = !!s && !!s.backward;
      let o;
      if (i == "in")
        o = g._createIn(t);
      else if (i == "on")
        o = g._createOn(t);
      else if (i !== void 0)
        o = new g(w._createAt(t, i));
      else
        throw new d("model-selection-setto-required-second-parameter", [this, t]);
      this._setRanges([o], r);
    } else if (_e(t))
      this._setRanges(t, s && !!s.backward);
    else
      throw new d("model-selection-setto-not-selectable", [this, t]);
  }
  /**
   * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array
   * is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and
   * {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.
   *
   * @fires change:range
   * @param newRanges Ranges to set.
   * @param isLastBackward Flag describing if last added range was selected forward - from start to end (`false`)
   * or backward - from end to start (`true`).
   */
  _setRanges(e, t = !1) {
    const i = Array.from(e), s = i.some((r) => {
      if (!(r instanceof g))
        throw new d("model-selection-set-ranges-not-range", [this, e]);
      return this._ranges.every((o) => !o.isEqual(r));
    });
    i.length === this._ranges.length && !s || (this._replaceAllRanges(i), this._lastRangeBackward = !!t, this.fire("change:range", { directChange: !0 }));
  }
  /**
   * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.
   *
   * The location can be specified in the same form as
   * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.
   *
   * @fires change:range
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/model/item~Item model item}.
   */
  setFocus(e, t) {
    if (this.anchor === null)
      throw new d("model-selection-setfocus-no-ranges", [this, e]);
    const i = w._createAt(e, t);
    if (i.compareWith(this.focus) == "same")
      return;
    const s = this.anchor;
    this._ranges.length && this._popRange(), i.compareWith(s) == "before" ? (this._pushRange(new g(i, s)), this._lastRangeBackward = !0) : (this._pushRange(new g(s, i)), this._lastRangeBackward = !1), this.fire("change:range", { directChange: !0 });
  }
  /**
   * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.
   *
   * @param key Key of attribute to look for.
   * @returns Attribute value or `undefined`.
   */
  getAttribute(e) {
    return this._attrs.get(e);
  }
  /**
   * Returns iterable that iterates over this selection's attributes.
   *
   * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
   * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
   */
  getAttributes() {
    return this._attrs.entries();
  }
  /**
   * Returns iterable that iterates over this selection's attribute keys.
   */
  getAttributeKeys() {
    return this._attrs.keys();
  }
  /**
   * Checks if the selection has an attribute for given key.
   *
   * @param key Key of attribute to check.
   * @returns `true` if attribute with given key is set on selection, `false` otherwise.
   */
  hasAttribute(e) {
    return this._attrs.has(e);
  }
  /**
   * Removes an attribute with given key from the selection.
   *
   * If given attribute was set on the selection, fires the {@link #event:change:range} event with
   * removed attribute key.
   *
   * @fires change:attribute
   * @param key Key of attribute to remove.
   */
  removeAttribute(e) {
    this.hasAttribute(e) && (this._attrs.delete(e), this.fire("change:attribute", { attributeKeys: [e], directChange: !0 }));
  }
  /**
   * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.
   *
   * If the attribute value has changed, fires the {@link #event:change:range} event with
   * the attribute key.
   *
   * @fires change:attribute
   * @param key Key of attribute to set.
   * @param value Attribute value.
   */
  setAttribute(e, t) {
    this.getAttribute(e) !== t && (this._attrs.set(e, t), this.fire("change:attribute", { attributeKeys: [e], directChange: !0 }));
  }
  /**
   * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only
   * one range in the selection, and that range contains exactly one element.
   * Returns `null` if there is no selected element.
   */
  getSelectedElement() {
    return this.rangeCount !== 1 ? null : this.getFirstRange().getContainedElement();
  }
  /**
   * Gets elements of type {@link module:engine/model/schema~Schema#isBlock "block"} touched by the selection.
   *
   * This method's result can be used for example to apply block styling to all blocks covered by this selection.
   *
   * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements
   * but will not return blocks nested in other blocks.
   *
   * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):
   *
   * ```xml
   * <paragraph>[a</paragraph>
   * <blockQuote>
   * 	<paragraph>b</paragraph>
   * </blockQuote>
   * <paragraph>c]d</paragraph>
   * ```
   *
   * In this case the paragraph will also be returned, despite the collapsed selection:
   *
   * ```xml
   * <paragraph>[]a</paragraph>
   * ```
   *
   * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:
   *
   * ```xml
   * [<blockA></blockA>
   * <blockB>
   * 	<blockC></blockC>
   * 	<blockD></blockD>
   * </blockB>
   * <blockE></blockE>]
   * ```
   *
   * If the selection is inside a block all the inner blocks (A & B) are returned:
   *
   * ```xml
   * <block>
   * 	<blockA>[a</blockA>
   * 	<blockB>b]</blockB>
   * </block>
   * ```
   *
   * **Special case**: Selection ignores first and/or last blocks if nothing (from user perspective) is selected in them.
   *
   * ```xml
   * // Selection ends and the beginning of the last block.
   * <paragraph>[a</paragraph>
   * <paragraph>b</paragraph>
   * <paragraph>]c</paragraph> // This block will not be returned
   *
   * // Selection begins at the end of the first block.
   * <paragraph>a[</paragraph> // This block will not be returned
   * <paragraph>b</paragraph>
   * <paragraph>c]</paragraph>
   *
   * // Selection begings at the end of the first block and ends at the beginning of the last block.
   * <paragraph>a[</paragraph> // This block will not be returned
   * <paragraph>b</paragraph>
   * <paragraph>]c</paragraph> // This block will not be returned
   * ```
   */
  *getSelectedBlocks() {
    const e = /* @__PURE__ */ new WeakSet();
    for (const t of this.getRanges()) {
      const i = Ta(t.start, e);
      ov(i, t) && (yield i);
      for (const r of t.getWalker()) {
        const o = r.item;
        r.type == "elementEnd" && rv(o, e, t) && (yield o);
      }
      const s = Ta(t.end, e);
      av(s, t) && (yield s);
    }
  }
  /**
   * Checks whether the selection contains the entire content of the given element. This means that selection must start
   * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position
   * touching the element's end.
   *
   * By default, this method will check whether the entire content of the selection's current root is selected.
   * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.
   */
  containsEntireContent(e = this.anchor.root) {
    const t = w._createAt(e, 0), i = w._createAt(e, "end");
    return t.isTouching(this.getFirstPosition()) && i.isTouching(this.getLastPosition());
  }
  /**
   * Adds given range to internal {@link #_ranges ranges array}. Throws an error
   * if given range is intersecting with any range that is already stored in this selection.
   */
  _pushRange(e) {
    this._checkRange(e), this._ranges.push(new g(e.start, e.end));
  }
  /**
   * Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.
   */
  _checkRange(e) {
    for (let t = 0; t < this._ranges.length; t++)
      if (e.isIntersecting(this._ranges[t]))
        throw new d("model-selection-range-intersects", [this, e], { addedRange: e, intersectingRange: this._ranges[t] });
  }
  /**
   * Replaces all the ranges by the given ones.
   * Uses {@link #_popRange _popRange} and {@link #_pushRange _pushRange} to ensure proper ranges removal and addition.
   */
  _replaceAllRanges(e) {
    this._removeAllRanges();
    for (const t of e)
      this._pushRange(t);
  }
  /**
   * Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to
   * ensure proper ranges removal.
   */
  _removeAllRanges() {
    for (; this._ranges.length > 0; )
      this._popRange();
  }
  /**
   * Removes most recently added range from the selection.
   */
  _popRange() {
    this._ranges.pop();
  }
}
we.prototype.is = function(n) {
  return n === "selection" || n === "model:selection";
};
function Ju(n, e) {
  return e.has(n) ? !1 : (e.add(n), n.root.document.model.schema.isBlock(n) && !!n.parent);
}
function rv(n, e, t) {
  return Ju(n, e) && Nr(n, t);
}
function Ta(n, e) {
  const i = n.parent.root.document.model.schema, s = n.parent.getAncestors({ parentFirst: !0, includeSelf: !0 });
  let r = !1;
  const o = s.find((a) => r ? !1 : (r = i.isLimit(a), !r && Ju(a, e)));
  return s.forEach((a) => e.add(a)), o;
}
function Nr(n, e) {
  const t = lv(n);
  return t ? !e.containsRange(g._createOn(t), !0) : !0;
}
function ov(n, e) {
  return n ? e.isCollapsed || n.isEmpty ? !0 : e.start.isTouching(w._createAt(n, n.maxOffset)) ? !1 : Nr(n, e) : !1;
}
function av(n, e) {
  return n ? e.isCollapsed || n.isEmpty ? !0 : e.end.isTouching(w._createAt(n, 0)) ? !1 : Nr(n, e) : !1;
}
function lv(n) {
  const e = n.root.document.model.schema;
  let t = n.parent;
  for (; t; ) {
    if (e.isBlock(t))
      return t;
    t = t.parent;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ze extends N(g) {
  /**
   * Creates a live range.
   *
   * @see module:engine/model/range~Range
   */
  constructor(e, t) {
    super(e, t), cv.call(this);
  }
  /**
   * Unbinds all events previously bound by `LiveRange`. Use it whenever you don't need `LiveRange` instance
   * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was
   * referring to it).
   */
  detach() {
    this.stopListening();
  }
  /**
   * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.
   */
  toRange() {
    return new g(this.start, this.end);
  }
  /**
   * Creates a `LiveRange` instance that is equal to the given range.
   */
  static fromRange(e) {
    return new ze(e.start, e.end);
  }
}
ze.prototype.is = function(n) {
  return n === "liveRange" || n === "model:liveRange" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n == "range" || n === "model:range";
};
function cv() {
  this.listenTo(this.root.document.model, "applyOperation", (n, e) => {
    const t = e[0];
    t.isDocumentOperation && uv.call(this, t);
  }, { priority: "low" });
}
function uv(n) {
  const e = this.getTransformedByOperation(n), t = g._createFromRanges(e), i = !t.isEqual(this), s = hv(this, n);
  let r = null;
  if (i) {
    t.root.rootName == "$graveyard" && (n.type == "remove" ? r = n.sourcePosition : r = n.deletionPosition);
    const o = this.toRange();
    this.start = t.start, this.end = t.end, this.fire("change:range", o, { deletionPosition: r });
  } else
    s && this.fire("change:content", this.toRange(), { deletionPosition: r });
}
function hv(n, e) {
  switch (e.type) {
    case "insert":
      return n.containsPosition(e.position);
    case "move":
    case "remove":
    case "reinsert":
    case "merge":
      return n.containsPosition(e.sourcePosition) || n.start.isEqual(e.sourcePosition) || n.containsPosition(e.targetPosition);
    case "split":
      return n.containsPosition(e.splitPosition) || n.containsPosition(e.insertionPosition);
  }
  return !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Oi = "selection:";
class Ie extends N(ft) {
  /**
   * Creates an empty live selection for given {@link module:engine/model/document~Document}.
   *
   * @param doc Document which owns this selection.
   */
  constructor(e) {
    super(), this._selection = new dv(e), this._selection.delegate("change:range").to(this), this._selection.delegate("change:attribute").to(this), this._selection.delegate("change:marker").to(this);
  }
  /**
   * Describes whether the selection is collapsed. Selection is collapsed when there is exactly one range which is
   * collapsed.
   */
  get isCollapsed() {
    return this._selection.isCollapsed;
  }
  /**
   * Selection anchor. Anchor may be described as a position where the most recent part of the selection starts.
   * Together with {@link #focus} they define the direction of selection, which is important
   * when expanding/shrinking selection. Anchor is always {@link module:engine/model/range~Range#start start} or
   * {@link module:engine/model/range~Range#end end} position of the most recently added range.
   *
   * Is set to `null` if there are no ranges in selection.
   *
   * @see #focus
   */
  get anchor() {
    return this._selection.anchor;
  }
  /**
   * Selection focus. Focus is a position where the selection ends.
   *
   * Is set to `null` if there are no ranges in selection.
   *
   * @see #anchor
   */
  get focus() {
    return this._selection.focus;
  }
  /**
   * Number of ranges in selection.
   */
  get rangeCount() {
    return this._selection.rangeCount;
  }
  /**
   * Describes whether `Documentselection` has own range(s) set, or if it is defaulted to
   * {@link module:engine/model/document~Document#_getDefaultRange document's default range}.
   */
  get hasOwnRange() {
    return this._selection.hasOwnRange;
  }
  /**
   * Specifies whether the {@link #focus}
   * precedes {@link #anchor}.
   *
   * @readonly
   * @type {Boolean}
   */
  get isBackward() {
    return this._selection.isBackward;
  }
  /**
   * Describes whether the gravity is overridden (using {@link module:engine/model/writer~Writer#overrideSelectionGravity}) or not.
   *
   * Note that the gravity remains overridden as long as will not be restored the same number of times as it was overridden.
   */
  get isGravityOverridden() {
    return this._selection.isGravityOverridden;
  }
  /**
   * A collection of selection {@link module:engine/model/markercollection~Marker markers}.
   * Marker is a selection marker when selection range is inside the marker range.
   *
   * **Note**: Only markers from {@link ~DocumentSelection#observeMarkers observed markers groups} are collected.
   */
  get markers() {
    return this._selection.markers;
  }
  /**
   * Used for the compatibility with the {@link module:engine/model/selection~Selection#isEqual} method.
   *
   * @internal
   */
  get _ranges() {
    return this._selection._ranges;
  }
  /**
   * Returns an iterable that iterates over copies of selection ranges.
   */
  getRanges() {
    return this._selection.getRanges();
  }
  /**
   * Returns the first position in the selection.
   * First position is the position that {@link module:engine/model/position~Position#isBefore is before}
   * any other position in the selection.
   *
   * Returns `null` if there are no ranges in selection.
   */
  getFirstPosition() {
    return this._selection.getFirstPosition();
  }
  /**
   * Returns the last position in the selection.
   * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}
   * any other position in the selection.
   *
   * Returns `null` if there are no ranges in selection.
   */
  getLastPosition() {
    return this._selection.getLastPosition();
  }
  /**
   * Returns a copy of the first range in the selection.
   * First range is the one which {@link module:engine/model/range~Range#start start} position
   * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges
   * (not to confuse with the first range added to the selection).
   *
   * Returns `null` if there are no ranges in selection.
   */
  getFirstRange() {
    return this._selection.getFirstRange();
  }
  /**
   * Returns a copy of the last range in the selection.
   * Last range is the one which {@link module:engine/model/range~Range#end end} position
   * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most
   * recently added to the selection).
   *
   * Returns `null` if there are no ranges in selection.
   */
  getLastRange() {
    return this._selection.getLastRange();
  }
  /**
   * Gets elements of type {@link module:engine/model/schema~Schema#isBlock "block"} touched by the selection.
   *
   * This method's result can be used for example to apply block styling to all blocks covered by this selection.
   *
   * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements
   * but will not return blocks nested in other blocks.
   *
   * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):
   *
   * ```
   * <paragraph>[a</paragraph>
   * <blockQuote>
   * 	<paragraph>b</paragraph>
   * </blockQuote>
   * <paragraph>c]d</paragraph>
   * ```
   *
   * In this case the paragraph will also be returned, despite the collapsed selection:
   *
   * ```
   * <paragraph>[]a</paragraph>
   * ```
   *
   * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:
   *
   * ```
   * [<blockA></blockA>
   * <blockB>
   * 	<blockC></blockC>
   * 	<blockD></blockD>
   * </blockB>
   * <blockE></blockE>]
   * ```
   *
   * If the selection is inside a block all the inner blocks (A & B) are returned:
   *
   * ```
   * <block>
   * 	<blockA>[a</blockA>
   * 	<blockB>b]</blockB>
   * </block>
   * ```
   *
   * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective
   * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.
   *
   * ```
   * <paragraph>[a</paragraph>
   * <paragraph>b</paragraph>
   * <paragraph>]c</paragraph> // this block will not be returned
   * ```
   */
  getSelectedBlocks() {
    return this._selection.getSelectedBlocks();
  }
  /**
   * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only
   * one range in the selection, and that range contains exactly one element.
   * Returns `null` if there is no selected element.
   */
  getSelectedElement() {
    return this._selection.getSelectedElement();
  }
  /**
   * Checks whether the selection contains the entire content of the given element. This means that selection must start
   * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position
   * touching the element's end.
   *
   * By default, this method will check whether the entire content of the selection's current root is selected.
   * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.
   */
  containsEntireContent(e) {
    return this._selection.containsEntireContent(e);
  }
  /**
   * Unbinds all events previously bound by document selection.
   */
  destroy() {
    this._selection.destroy();
  }
  /**
   * Returns iterable that iterates over this selection's attribute keys.
   */
  getAttributeKeys() {
    return this._selection.getAttributeKeys();
  }
  /**
   * Returns iterable that iterates over this selection's attributes.
   *
   * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.
   * This format is accepted by native `Map` object and also can be passed in `Node` constructor.
   */
  getAttributes() {
    return this._selection.getAttributes();
  }
  /**
   * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.
   *
   * @param key Key of attribute to look for.
   * @returns Attribute value or `undefined`.
   */
  getAttribute(e) {
    return this._selection.getAttribute(e);
  }
  /**
   * Checks if the selection has an attribute for given key.
   *
   * @param key Key of attribute to check.
   * @returns `true` if attribute with given key is set on selection, `false` otherwise.
   */
  hasAttribute(e) {
    return this._selection.hasAttribute(e);
  }
  /**
   * Refreshes selection attributes and markers according to the current position in the model.
   */
  refresh() {
    this._selection.updateMarkers(), this._selection._updateAttributes(!1);
  }
  /**
   * Registers a marker group prefix or a marker name to be collected in the
   * {@link ~DocumentSelection#markers selection markers collection}.
   *
   * See also {@link module:engine/model/markercollection~MarkerCollection#getMarkersGroup `MarkerCollection#getMarkersGroup()`}.
   *
   * @param prefixOrName The marker group prefix or marker name.
   */
  observeMarkers(e) {
    this._selection.observeMarkers(e);
  }
  /**
   * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.
   * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionFocus} method.
   *
   * The location can be specified in the same form as
   * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.
   *
   * @see module:engine/model/writer~Writer#setSelectionFocus
   * @internal
   * @param offset Offset or one of the flags. Used only when
   * first parameter is a {@link module:engine/model/item~Item model item}.
   */
  _setFocus(e, t) {
    this._selection.setFocus(e, t);
  }
  /**
   * Sets this selection's ranges and direction to the specified location based on the given
   * {@link module:engine/model/selection~Selectable selectable}.
   * Should be used only within the {@link module:engine/model/writer~Writer#setSelection} method.
   *
   * @see module:engine/model/writer~Writer#setSelection
   * @internal
   */
  _setTo(...e) {
    this._selection.setTo(...e);
  }
  /**
   * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.
   * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionAttribute} method.
   *
   * @see module:engine/model/writer~Writer#setSelectionAttribute
   * @internal
   * @param key Key of the attribute to set.
   * @param value Attribute value.
   */
  _setAttribute(e, t) {
    this._selection.setAttribute(e, t);
  }
  /**
   * Removes an attribute with given key from the selection.
   * If the given attribute was set on the selection, fires the {@link module:engine/model/selection~Selection#event:change:range}
   * event with removed attribute key.
   * Should be used only within the {@link module:engine/model/writer~Writer#removeSelectionAttribute} method.
   *
   * @see module:engine/model/writer~Writer#removeSelectionAttribute
   * @internal
   * @param key Key of the attribute to remove.
   */
  _removeAttribute(e) {
    this._selection.removeAttribute(e);
  }
  /**
   * Returns an iterable that iterates through all selection attributes stored in current selection's parent.
   *
   * @internal
   */
  _getStoredAttributes() {
    return this._selection.getStoredAttributes();
  }
  /**
   * Temporarily changes the gravity of the selection from the left to the right.
   *
   * The gravity defines from which direction the selection inherits its attributes. If it's the default left
   * gravity, the selection (after being moved by the the user) inherits attributes from its left hand side.
   * This method allows to temporarily override this behavior by forcing the gravity to the right.
   *
   * It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry
   * of the process.
   *
   * @see module:engine/model/writer~Writer#overrideSelectionGravity
   * @internal
   * @returns The unique id which allows restoring the gravity.
   */
  _overrideGravity() {
    return this._selection.overrideGravity();
  }
  /**
   * Restores the {@link ~DocumentSelection#_overrideGravity overridden gravity}.
   *
   * Restoring the gravity is only possible using the unique identifier returned by
   * {@link ~DocumentSelection#_overrideGravity}. Note that the gravity remains overridden as long as won't be restored
   * the same number of times it was overridden.
   *
   * @see module:engine/model/writer~Writer#restoreSelectionGravity
   * @internal
   * @param uid The unique id returned by {@link #_overrideGravity}.
   */
  _restoreGravity(e) {
    this._selection.restoreGravity(e);
  }
  /**
   * Generates and returns an attribute key for selection attributes store, basing on original attribute key.
   *
   * @internal
   * @param key Attribute key to convert.
   * @returns Converted attribute key, applicable for selection store.
   */
  static _getStoreAttributeKey(e) {
    return Oi + e;
  }
  /**
   * Checks whether the given attribute key is an attribute stored on an element.
   *
   * @internal
   */
  static _isStoreAttributeKey(e) {
    return e.startsWith(Oi);
  }
}
Ie.prototype.is = function(n) {
  return n === "selection" || n == "model:selection" || n == "documentSelection" || n == "model:documentSelection";
};
class dv extends we {
  /**
   * Creates an empty live selection for given {@link module:engine/model/document~Document}.
   *
   * @param doc Document which owns this selection.
   */
  constructor(e) {
    super(), this.markers = new He({ idProperty: "name" }), this._attributePriority = /* @__PURE__ */ new Map(), this._selectionRestorePosition = null, this._hasChangedRange = !1, this._overriddenGravityRegister = /* @__PURE__ */ new Set(), this._observedMarkers = /* @__PURE__ */ new Set(), this._model = e.model, this._document = e, this.listenTo(this._model, "applyOperation", (t, i) => {
      const s = i[0];
      !s.isDocumentOperation || s.type == "marker" || s.type == "rename" || s.type == "noop" || (this._ranges.length == 0 && this._selectionRestorePosition && this._fixGraveyardSelection(this._selectionRestorePosition), this._selectionRestorePosition = null, this._hasChangedRange && (this._hasChangedRange = !1, this.fire("change:range", { directChange: !1 })));
    }, { priority: "lowest" }), this.on("change:range", () => {
      this._validateSelectionRanges(this.getRanges());
    }), this.listenTo(this._model.markers, "update", (t, i, s, r) => {
      this._updateMarker(i, r);
    }), this.listenTo(this._document, "change", (t, i) => {
      fv(this._model, i);
    });
  }
  get isCollapsed() {
    return this._ranges.length === 0 ? this._document._getDefaultRange().isCollapsed : super.isCollapsed;
  }
  get anchor() {
    return super.anchor || this._document._getDefaultRange().start;
  }
  get focus() {
    return super.focus || this._document._getDefaultRange().end;
  }
  get rangeCount() {
    return this._ranges.length ? this._ranges.length : 1;
  }
  /**
   * Describes whether `LiveSelection` has own range(s) set, or if it is defaulted to
   * {@link module:engine/model/document~Document#_getDefaultRange document's default range}.
   */
  get hasOwnRange() {
    return this._ranges.length > 0;
  }
  /**
   * When set to `true` then selection attributes on node before the caret won't be taken
   * into consideration while updating selection attributes.
   */
  get isGravityOverridden() {
    return !!this._overriddenGravityRegister.size;
  }
  /**
   * Unbinds all events previously bound by live selection.
   */
  destroy() {
    for (let e = 0; e < this._ranges.length; e++)
      this._ranges[e].detach();
    this.stopListening();
  }
  *getRanges() {
    this._ranges.length ? yield* super.getRanges() : yield this._document._getDefaultRange();
  }
  getFirstRange() {
    return super.getFirstRange() || this._document._getDefaultRange();
  }
  getLastRange() {
    return super.getLastRange() || this._document._getDefaultRange();
  }
  setTo(...e) {
    super.setTo(...e), this._updateAttributes(!0), this.updateMarkers();
  }
  setFocus(e, t) {
    super.setFocus(e, t), this._updateAttributes(!0), this.updateMarkers();
  }
  setAttribute(e, t) {
    if (this._setAttribute(e, t)) {
      const i = [e];
      this.fire("change:attribute", { attributeKeys: i, directChange: !0 });
    }
  }
  removeAttribute(e) {
    if (this._removeAttribute(e)) {
      const t = [e];
      this.fire("change:attribute", { attributeKeys: t, directChange: !0 });
    }
  }
  overrideGravity() {
    const e = Ye();
    return this._overriddenGravityRegister.add(e), this._overriddenGravityRegister.size === 1 && this._updateAttributes(!0), e;
  }
  restoreGravity(e) {
    if (!this._overriddenGravityRegister.has(e))
      throw new d("document-selection-gravity-wrong-restore", this, { uid: e });
    this._overriddenGravityRegister.delete(e), this.isGravityOverridden || this._updateAttributes(!0);
  }
  observeMarkers(e) {
    this._observedMarkers.add(e), this.updateMarkers();
  }
  _replaceAllRanges(e) {
    this._validateSelectionRanges(e), super._replaceAllRanges(e);
  }
  _popRange() {
    this._ranges.pop().detach();
  }
  _pushRange(e) {
    const t = this._prepareRange(e);
    t && this._ranges.push(t);
  }
  _validateSelectionRanges(e) {
    for (const t of e)
      if (!this._document._validateSelectionRange(t))
        throw new d("document-selection-wrong-position", this, { range: t });
  }
  /**
   * Prepares given range to be added to selection. Checks if it is correct,
   * converts it to {@link module:engine/model/liverange~LiveRange LiveRange}
   * and sets listeners listening to the range's change event.
   */
  _prepareRange(e) {
    if (this._checkRange(e), e.root == this._document.graveyard)
      return;
    const t = ze.fromRange(e);
    return t.on("change:range", (i, s, r) => {
      if (this._hasChangedRange = !0, t.root == this._document.graveyard) {
        this._selectionRestorePosition = r.deletionPosition;
        const o = this._ranges.indexOf(t);
        this._ranges.splice(o, 1), t.detach();
      }
    }), t;
  }
  updateMarkers() {
    if (!this._observedMarkers.size)
      return;
    const e = [];
    let t = !1;
    for (const s of this._model.markers) {
      const r = s.name.split(":", 1)[0];
      if (!this._observedMarkers.has(r))
        continue;
      const o = s.getRange();
      for (const a of this.getRanges())
        o.containsRange(a, !a.isCollapsed) && e.push(s);
    }
    const i = Array.from(this.markers);
    for (const s of e)
      this.markers.has(s) || (this.markers.add(s), t = !0);
    for (const s of Array.from(this.markers))
      e.includes(s) || (this.markers.remove(s), t = !0);
    t && this.fire("change:marker", { oldMarkers: i, directChange: !1 });
  }
  _updateMarker(e, t) {
    const i = e.name.split(":", 1)[0];
    if (!this._observedMarkers.has(i))
      return;
    let s = !1;
    const r = Array.from(this.markers), o = this.markers.has(e);
    if (!t)
      o && (this.markers.remove(e), s = !0);
    else {
      let a = !1;
      for (const l of this.getRanges())
        if (t.containsRange(l, !l.isCollapsed)) {
          a = !0;
          break;
        }
      a && !o ? (this.markers.add(e), s = !0) : !a && o && (this.markers.remove(e), s = !0);
    }
    s && this.fire("change:marker", { oldMarkers: r, directChange: !1 });
  }
  /**
   * Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.
   */
  _updateAttributes(e) {
    const t = Xe(this._getSurroundingAttributes()), i = Xe(this.getAttributes());
    if (e)
      this._attributePriority = /* @__PURE__ */ new Map(), this._attrs = /* @__PURE__ */ new Map();
    else
      for (const [r, o] of this._attributePriority)
        o == "low" && (this._attrs.delete(r), this._attributePriority.delete(r));
    this._setAttributesTo(t);
    const s = [];
    for (const [r, o] of this.getAttributes())
      (!i.has(r) || i.get(r) !== o) && s.push(r);
    for (const [r] of i)
      this.hasAttribute(r) || s.push(r);
    s.length > 0 && this.fire("change:attribute", { attributeKeys: s, directChange: !1 });
  }
  /**
   * Internal method for setting `LiveSelection` attribute. Supports attribute priorities (through `directChange`
   * parameter).
   */
  _setAttribute(e, t, i = !0) {
    const s = i ? "normal" : "low";
    return s == "low" && this._attributePriority.get(e) == "normal" || super.getAttribute(e) === t ? !1 : (this._attrs.set(e, t), this._attributePriority.set(e, s), !0);
  }
  /**
   * Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`
   * parameter).
   *
   * NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will
   * be changed according to `directChange` parameter.
   */
  _removeAttribute(e, t = !0) {
    const i = t ? "normal" : "low";
    return i == "low" && this._attributePriority.get(e) == "normal" || (this._attributePriority.set(e, i), !super.hasAttribute(e)) ? !1 : (this._attrs.delete(e), !0);
  }
  /**
   * Internal method for setting multiple `LiveSelection` attributes. Supports attribute priorities (through
   * `directChange` parameter).
   */
  _setAttributesTo(e) {
    const t = /* @__PURE__ */ new Set();
    for (const [i, s] of this.getAttributes())
      e.get(i) !== s && this._removeAttribute(i, !1);
    for (const [i, s] of e)
      this._setAttribute(i, s, !1) && t.add(i);
    return t;
  }
  /**
   * Returns an iterable that iterates through all selection attributes stored in current selection's parent.
   */
  *getStoredAttributes() {
    const e = this.getFirstPosition().parent;
    if (this.isCollapsed && e.isEmpty)
      for (const t of e.getAttributeKeys())
        t.startsWith(Oi) && (yield [t.substr(Oi.length), e.getAttribute(t)]);
  }
  /**
   * Checks model text nodes that are closest to the selection's first position and returns attributes of first
   * found element. If there are no text nodes in selection's first position parent, it returns selection
   * attributes stored in that parent.
   */
  _getSurroundingAttributes() {
    const e = this.getFirstPosition(), t = this._model.schema;
    let i = null;
    if (this.isCollapsed) {
      const s = e.textNode ? e.textNode : e.nodeBefore, r = e.textNode ? e.textNode : e.nodeAfter;
      if (this.isGravityOverridden || (i = Zi(s, t)), i || (i = Zi(r, t)), !this.isGravityOverridden && !i) {
        let o = s;
        for (; o && !i; )
          o = o.previousSibling, i = Zi(o, t);
      }
      if (!i) {
        let o = r;
        for (; o && !i; )
          o = o.nextSibling, i = Zi(o, t);
      }
      i || (i = this.getStoredAttributes());
    } else {
      const s = this.getFirstRange();
      for (const r of s) {
        if (r.item.is("element") && t.isObject(r.item))
          break;
        if (r.type == "text") {
          i = r.item.getAttributes();
          break;
        }
      }
    }
    return i;
  }
  /**
   * Fixes the selection after all its ranges got removed.
   * @param deletionPosition Position where the deletion happened.
   */
  _fixGraveyardSelection(e) {
    const t = this._model.schema.getNearestSelectionRange(e);
    t && this._pushRange(t);
  }
}
function Zi(n, e) {
  if (!n)
    return null;
  if (n instanceof xe || n instanceof U)
    return n.getAttributes();
  if (!e.isInline(n))
    return null;
  if (!e.isObject(n))
    return [];
  const t = [];
  for (const [i, s] of n.getAttributes())
    e.checkAttribute("$text", i) && t.push([i, s]);
  return t;
}
function fv(n, e) {
  const t = n.document.differ;
  for (const i of t.getChanges()) {
    if (i.type != "insert")
      continue;
    const s = i.position.parent;
    i.length === s.maxOffset && n.enqueueChange(e, (o) => {
      const a = Array.from(s.getAttributeKeys()).filter((l) => l.startsWith(Oi));
      for (const l of a)
        o.removeAttribute(l, s);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Zu {
  /**
   * Creates a conversion helpers instance.
   */
  constructor(e) {
    this._dispatchers = e;
  }
  /**
   * Registers a conversion helper.
   *
   * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`
   * method description.
   *
   * @param conversionHelper The function to be called on event.
   */
  add(e) {
    for (const t of this._dispatchers)
      e(t);
    return this;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class mv extends Zu {
  /**
   * Model element to view element conversion helper.
   *
   * This conversion results in creating a view element. For example, model `<paragraph>Foo</paragraph>` becomes `<p>Foo</p>` in the view.
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: 'paragraph',
   * 	view: 'p'
   * } );
   *
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: 'paragraph',
   * 	view: 'div',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: 'fancyParagraph',
   * 	view: {
   * 		name: 'p',
   * 		classes: 'fancy'
   * 	}
   * } );
   *
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: 'heading',
   * 	view: ( modelElement, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );
   * 	}
   * } );
   * ```
   *
   * The element-to-element conversion supports the reconversion mechanism. It can be enabled by using either the `attributes` or
   * the `children` props on a model description. You will find a couple examples below.
   *
   * In order to reconvert an element if any of its direct children have been added or removed, use the `children` property on a `model`
   * description. For example, this model:
   *
   * ```xml
   * <box>
   * 	<paragraph>Some text.</paragraph>
   * </box>
   * ```
   *
   * will be converted into this structure in the view:
   *
   * ```html
   * <div class="box" data-type="single">
   * 	<p>Some text.</p>
   * </div>
   * ```
   *
   * But if more items were inserted in the model:
   *
   * ```xml
   * <box>
   * 	<paragraph>Some text.</paragraph>
   * 	<paragraph>Other item.</paragraph>
   * </box>
   * ```
   *
   * it will be converted into this structure in the view (note the element `data-type` change):
   *
   * ```html
   * <div class="box" data-type="multiple">
   * 	<p>Some text.</p>
   * 	<p>Other item.</p>
   * </div>
   * ```
   *
   * Such a converter would look like this (note that the `paragraph` elements are converted separately):
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: {
   * 		name: 'box',
   * 		children: true
   * 	},
   * 	view: ( modelElement, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createContainerElement( 'div', {
   * 			class: 'box',
   * 			'data-type': modelElement.childCount == 1 ? 'single' : 'multiple'
   * 		} );
   * 	}
   * } );
   * ```
   *
   * In order to reconvert element if any of its attributes have been updated, use the `attributes` property on a `model`
   * description. For example, this model:
   *
   * ```xml
   * <heading level="2">Some text.</heading>
   * ```
   *
   * will be converted into this structure in the view:
   *
   * ```html
   * <h2>Some text.</h2>
   * ```
   *
   * But if the `heading` element's `level` attribute has been updated to `3` for example, then
   * it will be converted into this structure in the view:
   *
   * ```html
   * <h3>Some text.</h3>
   * ```
   *
   * Such a converter would look as follows:
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).elementToElement( {
   * 	model: {
   * 		name: 'heading',
   * 		attributes: 'level'
   * 	},
   * 	view: ( modelElement, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );
   * 	}
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * You can read more about the element-to-element conversion in the
   * {@glink framework/deep-dive/conversion/downcast downcast conversion} guide.
   *
   * @param config Conversion configuration.
   * @param config.model The description or a name of the model element to convert.
   * @param config.model.attributes The list of attribute names that should be consumed while creating
   * the view element. Note that the view will be reconverted if any of the listed attributes changes.
   * @param config.model.children Specifies whether the view element requires reconversion if the list
   * of the model child nodes changed.
   * @param config.view A view element definition or a function that takes the model element and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
   * as parameters and returns a view container element.
   */
  elementToElement(e) {
    return this.add(Ov(e));
  }
  /**
   * The model element to view structure (several elements) conversion helper.
   *
   * This conversion results in creating a view structure with one or more slots defined for the child nodes.
   * For example, a model `<table>` may become this structure in the view:
   *
   * ```html
   * <figure class="table">
   * 	<table>
   * 		<tbody>${ slot for table rows }</tbody>
   * 	</table>
   * </figure>
   * ```
   *
   * The children of the model's `<table>` element will be inserted into the `<tbody>` element.
   * If the `elementToElement()` helper was used, the children would be inserted into the `<figure>`.
   *
   * An example converter that converts the following model structure:
   *
   * ```xml
   * <wrappedParagraph>Some text.</wrappedParagraph>
   * ```
   *
   * into this structure in the view:
   *
   * ```html
   * <div class="wrapper">
   * 	<p>Some text.</p>
   * </div>
   * ```
   *
   * would look like this:
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).elementToStructure( {
   * 	model: 'wrappedParagraph',
   * 	view: ( modelElement, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		const wrapperViewElement = writer.createContainerElement( 'div', { class: 'wrapper' } );
   * 		const paragraphViewElement = writer.createContainerElement( 'p' );
   *
   * 		writer.insert( writer.createPositionAt( wrapperViewElement, 0 ), paragraphViewElement );
   * 		writer.insert( writer.createPositionAt( paragraphViewElement, 0 ), writer.createSlot() );
   *
   * 		return wrapperViewElement;
   * 	}
   * } );
   * ```
   *
   * The `createSlot()` function can also take a callback that allows filtering which children of the model element
   * should be converted into this slot.
   *
   * Imagine a table feature where for this model structure:
   *
   * ```xml
   * <table headingRows="1">
   * 	<tableRow> ... table cells 1 ... </tableRow>
   * 	<tableRow> ... table cells 2 ... </tableRow>
   * 	<tableRow> ... table cells 3 ... </tableRow>
   * 	<caption>Caption text</caption>
   * </table>
   * ```
   *
   * we want to generate this view structure:
   *
   * ```html
   * <figure class="table">
   * 	<table>
   * 		<thead>
   * 			<tr> ... table cells 1 ... </tr>
   * 		</thead>
   * 		<tbody>
   * 			<tr> ... table cells 2 ... </tr>
   * 			<tr> ... table cells 3 ... </tr>
   * 		</tbody>
   * 	</table>
   * 	<figcaption>Caption text</figcaption>
   * </figure>
   * ```
   *
   * The converter has to take the `headingRows` attribute into consideration when allocating the `<tableRow>` elements
   * into the `<tbody>` and `<thead>` elements. Hence, we need two slots and need to define proper filter callbacks for them.
   *
   * Additionally, all elements other than `<tableRow>` should be placed outside the `<table>` tag.
   * In the example above, this will handle the table caption.
   *
   * Such a converter would look like this:
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).elementToStructure( {
   * 	model: {
   * 		name: 'table',
   * 		attributes: [ 'headingRows' ]
   * 	},
   * 	view: ( modelElement, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		const figureElement = writer.createContainerElement( 'figure', { class: 'table' } );
   * 		const tableElement = writer.createContainerElement( 'table' );
   *
   * 		writer.insert( writer.createPositionAt( figureElement, 0 ), tableElement );
   *
   * 		const headingRows = modelElement.getAttribute( 'headingRows' ) || 0;
   *
   * 		if ( headingRows > 0 ) {
   * 			const tableHead = writer.createContainerElement( 'thead' );
   *
   * 			const headSlot = writer.createSlot( node => node.is( 'element', 'tableRow' ) && node.index < headingRows );
   *
   * 			writer.insert( writer.createPositionAt( tableElement, 'end' ), tableHead );
   * 			writer.insert( writer.createPositionAt( tableHead, 0 ), headSlot );
   * 		}
   *
   * 		if ( headingRows < tableUtils.getRows( table ) ) {
   * 			const tableBody = writer.createContainerElement( 'tbody' );
   *
   * 			const bodySlot = writer.createSlot( node => node.is( 'element', 'tableRow' ) && node.index >= headingRows );
   *
   * 			writer.insert( writer.createPositionAt( tableElement, 'end' ), tableBody );
   * 			writer.insert( writer.createPositionAt( tableBody, 0 ), bodySlot );
   * 		}
   *
   * 		const restSlot = writer.createSlot( node => !node.is( 'element', 'tableRow' ) );
   *
   * 		writer.insert( writer.createPositionAt( figureElement, 'end' ), restSlot );
   *
   * 		return figureElement;
   * 	}
   * } );
   * ```
   *
   * Note: The children of a model element that's being converted must be allocated in the same order in the view
   * in which they are placed in the model.
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The description or a name of the model element to convert.
   * @param config.model.name The name of the model element to convert.
   * @param config.model.attributes The list of attribute names that should be consumed while creating
   * the view structure. Note that the view will be reconverted if any of the listed attributes will change.
   * @param config.view A function that takes the model element and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters
   * and returns a view container element with slots for model child nodes to be converted into.
   */
  elementToStructure(e) {
    return this.add(Mv(e));
  }
  /**
   * Model attribute to view element conversion helper.
   *
   * This conversion results in wrapping view nodes with a view attribute element. For example, a model text node with
   * `"Foo"` as data and the `bold` attribute becomes `<strong>Foo</strong>` in the view.
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: 'bold',
   * 	view: 'strong'
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: 'bold',
   * 	view: 'b',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: 'invert',
   * 	view: {
   * 		name: 'span',
   * 		classes: [ 'font-light', 'bg-dark' ]
   * 	}
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: {
   * 		key: 'fontSize',
   * 		values: [ 'big', 'small' ]
   * 	},
   * 	view: {
   * 		big: {
   * 			name: 'span',
   * 			styles: {
   * 				'font-size': '1.2em'
   * 			}
   * 		},
   * 		small: {
   * 			name: 'span',
   * 			styles: {
   * 				'font-size': '0.8em'
   * 			}
   * 		}
   * 	}
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: 'bold',
   * 	view: ( modelAttributeValue, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createAttributeElement( 'span', {
   * 			style: 'font-weight:' + modelAttributeValue
   * 		} );
   * 	}
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToElement( {
   * 	model: {
   * 		key: 'color',
   * 		name: '$text'
   * 	},
   * 	view: ( modelAttributeValue, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createAttributeElement( 'span', {
   * 			style: 'color:' + modelAttributeValue
   * 		} );
   * 	}
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array
   * of `String`s with possible values if the model attribute is an enumerable.
   * @param config.view A view element definition or a function
   * that takes the model attribute value and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view
   * attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`
   * to view element definitions or functions.
   * @param config.converterPriority Converter priority.
   */
  attributeToElement(e) {
    return this.add(Vv(e));
  }
  /**
   * Model attribute to view attribute conversion helper.
   *
   * This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,
   * `<imageInline src='foo.jpg'></imageInline>` is converted to `<img src='foo.jpg'></img>`.
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: 'source',
   * 	view: 'src'
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: 'source',
   * 	view: 'href',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: {
   * 		name: 'imageInline',
   * 		key: 'source'
   * 	},
   * 	view: 'src'
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: {
   * 		name: 'styled',
   * 		values: [ 'dark', 'light' ]
   * 	},
   * 	view: {
   * 		dark: {
   * 			key: 'class',
   * 			value: [ 'styled', 'styled-dark' ]
   * 		},
   * 		light: {
   * 			key: 'class',
   * 			value: [ 'styled', 'styled-light' ]
   * 		}
   * 	}
   * } );
   *
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: 'styled',
   * 	view: modelAttributeValue => ( {
   * 		key: 'class',
   * 		value: 'styled-' + modelAttributeValue
   * 	} )
   * } );
   * ```
   *
   * **Note**: Downcasting to a style property requires providing `value` as an object:
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).attributeToAttribute( {
   * 	model: 'lineHeight',
   * 	view: modelAttributeValue => ( {
   * 		key: 'style',
   * 		value: {
   * 			'line-height': modelAttributeValue,
   * 			'border-bottom': '1px dotted #ba2'
   * 		}
   * 	} )
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing
   * the attribute key, possible values and, optionally, an element name to convert from.
   * @param config.view A view attribute key, or a `{ key, value }` object or a function that takes the model attribute value and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
   * as parameters and returns a `{ key, value }` object. If the `key` is `'class'`, the `value` can be a `String` or an
   * array of `String`s. If the `key` is `'style'`, the `value` is an object with key-value pairs. In other cases, `value` is a `String`.
   * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to
   * `{ key, value }` objects or a functions.
   * @param config.converterPriority Converter priority.
   */
  attributeToAttribute(e) {
    return this.add(Dv(e));
  }
  /**
   * Model marker to view element conversion helper.
   *
   * **Note**: This method should be used mainly for editing the downcast and it is recommended
   * to use the {@link #markerToData `#markerToData()`} helper instead.
   *
   * This helper may produce invalid HTML code (e.g. a span between table cells).
   * It should only be used when you are sure that the produced HTML will be semantically correct.
   *
   * This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker
   * is collapsed, only one element is created. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>`
   * becomes `<p>F<span data-marker="search"></span>oo b<span data-marker="search"></span>ar</p>` in the view.
   *
   * ```ts
   * editor.conversion.for( 'editingDowncast' ).markerToElement( {
   * 	model: 'search',
   * 	view: 'marker-search'
   * } );
   *
   * editor.conversion.for( 'editingDowncast' ).markerToElement( {
   * 	model: 'search',
   * 	view: 'search-result',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'editingDowncast' ).markerToElement( {
   * 	model: 'search',
   * 	view: {
   * 		name: 'span',
   * 		attributes: {
   * 			'data-marker': 'search'
   * 		}
   * 	}
   * } );
   *
   * editor.conversion.for( 'editingDowncast' ).markerToElement( {
   * 	model: 'search',
   * 	view: ( markerData, conversionApi ) => {
   * 		const { writer } = conversionApi;
   *
   * 		return writer.createUIElement( 'span', {
   * 			'data-marker': 'search',
   * 			'data-start': markerData.isOpening
   * 		} );
   * 	}
   * } );
   * ```
   *
   * If a function is passed as the `config.view` parameter, it will be used to generate both boundary elements. The function
   * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
   * as a parameters and should return an instance of the
   * {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from
   * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,
   * the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` for
   * the marker end boundary element.
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The name of the model marker (or model marker group) to convert.
   * @param config.view A view element definition or a function that takes the model marker data and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters
   * and returns a view UI element.
   * @param config.converterPriority Converter priority.
   */
  markerToElement(e) {
    return this.add(Bv(e));
  }
  /**
   * Model marker to highlight conversion helper.
   *
   * This conversion results in creating a highlight on view nodes. For this kind of conversion,
   * the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.
   *
   * For text nodes, a `<span>` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes
   * in the converted marker range. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>` becomes
   * `<p>F<span class="comment">oo b</span>ar</p>` in the view.
   *
   * {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,
   * the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in `<span>`).
   * For example, a model marker set like this:
   * `[<imageInline src="foo.jpg"></imageInline>]` becomes `<img src="foo.jpg" class="comment"></img>` in the view.
   *
   * For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it
   * to a container element, it is the container element instance itself that applies values from the highlight descriptor.
   * So, in a sense, the converter takes care of stating what should be applied on what, while the element decides how to apply that.
   *
   * ```ts
   * editor.conversion.for( 'downcast' ).markerToHighlight( { model: 'comment', view: { classes: 'comment' } } );
   *
   * editor.conversion.for( 'downcast' ).markerToHighlight( {
   * 	model: 'comment',
   * 	view: { classes: 'comment' },
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'downcast' ).markerToHighlight( {
   * 	model: 'comment',
   * 	view: ( data, conversionApi ) => {
   * 		// Assuming that the marker name is in a form of comment:commentType:commentId.
   * 		const [ , commentType, commentId ] = data.markerName.split( ':' );
   *
   * 		return {
   * 			classes: [ 'comment', 'comment-' + commentType ],
   * 			attributes: { 'data-comment-id': commentId }
   * 		};
   * 	}
   * } );
   * ```
   *
   * If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function
   * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}
   * as the parameters and should return a
   * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.
   * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The name of the model marker (or model marker group) to convert.
   * @param config.view A highlight descriptor that will be used for highlighting or a function that takes the model marker data and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters
   * and returns a highlight descriptor.
   * @param config.converterPriority Converter priority.
   */
  markerToHighlight(e) {
    return this.add(Nv(e));
  }
  /**
   * Model marker converter for data downcast.
   *
   * This conversion creates a representation for model marker boundaries in the view:
   *
   * * If the marker boundary is before or after a model element, a view attribute is set on a corresponding view element.
   * * In other cases, a view element with the specified tag name is inserted at the corresponding view position.
   *
   * Typically, the marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.
   * The default configuration for this conversion is that the first part is the `group` part and the rest of
   * the marker name becomes the `name` part.
   *
   * Tag and attribute names and values are generated from the marker name:
   *
   * * The templates for attributes are `data-[group]-start-before="[name]"`, `data-[group]-start-after="[name]"`,
   * `data-[group]-end-before="[name]"` and `data-[group]-end-after="[name]"`.
   * * The templates for view elements are `<[group]-start name="[name]">` and `<[group]-end name="[name]">`.
   *
   * Attributes mark whether the given marker's start or end boundary is before or after the given element.
   * The `data-[group]-start-before` and `data-[group]-end-after` attributes are favored.
   * The other two are used when the former two cannot be used.
   *
   * The conversion configuration can take a function that will generate different group and name parts.
   * If such a function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two
   * properties: `group` and `name`. If the function returns a falsy value, the conversion will not take place.
   *
   * Basic usage:
   *
   * ```ts
   * // Using the default conversion.
   * // In this case, all markers with names starting with 'comment:' will be converted.
   * // The `group` parameter will be set to `comment`.
   * // The `name` parameter will be the rest of the marker name (without the `:`).
   * editor.conversion.for( 'dataDowncast' ).markerToData( {
   * 	model: 'comment'
   * } );
   * ```
   *
   * An example of a view that may be generated by this conversion (assuming a marker with the name `comment:commentId:uid` marked
   * by `[]`):
   *
   * ```
   * // Model:
   * <paragraph>Foo[bar</paragraph>
   * <imageBlock src="abc.jpg"></imageBlock>]
   *
   * // View:
   * <p>Foo<comment-start name="commentId:uid"></comment-start>bar</p>
   * <figure data-comment-end-after="commentId:uid" class="image"><img src="abc.jpg" /></figure>
   * ```
   *
   * In the example above, the comment starts before "bar" and ends after the image.
   *
   * If the `name` part is empty, the following view may be generated:
   *
   * ```html
   * <p>Foo <myMarker-start></myMarker-start>bar</p>
   * <figure data-myMarker-end-after="" class="image"><img src="abc.jpg" /></figure>
   * ```
   *
   * **Note:** A situation where some markers have the `name` part and some do not, is incorrect and should be avoided.
   *
   * Examples where `data-group-start-after` and `data-group-end-before` are used:
   *
   * ```
   * // Model:
   * <blockQuote>[]<paragraph>Foo</paragraph></blockQuote>
   *
   * // View:
   * <blockquote><p data-group-end-before="name" data-group-start-before="name">Foo</p></blockquote>
   * ```
   *
   * Similarly, when a marker is collapsed after the last element:
   *
   * ```
   * // Model:
   * <blockQuote><paragraph>Foo</paragraph>[]</blockQuote>
   *
   * // View:
   * <blockquote><p data-group-end-after="name" data-group-start-after="name">Foo</p></blockquote>
   * ```
   *
   * When there are multiple markers from the same group stored in the same attribute of the same element, their
   * name parts are put together in the attribute value, for example: `data-group-start-before="name1,name2,name3"`.
   *
   * Other examples of usage:
   *
   * ```ts
   * // Using a custom function which is the same as the default conversion:
   * editor.conversion.for( 'dataDowncast' ).markerToData( {
   * 	model: 'comment'
   * 	view: markerName => ( {
   * 		group: 'comment',
   * 		name: markerName.substr( 8 ) // Removes 'comment:' part.
   * 	} )
   * } );
   *
   * // Using the converter priority:
   * editor.conversion.for( 'dataDowncast' ).markerToData( {
   * 	model: 'comment'
   * 	view: markerName => ( {
   * 		group: 'comment',
   * 		name: markerName.substr( 8 ) // Removes 'comment:' part.
   * 	} ),
   * 	converterPriority: 'high'
   * } );
   * ```
   *
   * This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.
   *
   * See the {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} API guide to learn how to
   * add a converter to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.model The name of the model marker (or the model marker group) to convert.
   * @param config.view A function that takes the model marker name and
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as the parameters
   * and returns an object with the `group` and `name` properties.
   * @param config.converterPriority Converter priority.
   */
  markerToData(e) {
    return this.add(Fv(e));
  }
}
function Yu() {
  return (n, e, t) => {
    if (!t.consumable.consume(e.item, n.name))
      return;
    const i = t.writer, s = t.mapper.toViewPosition(e.range.start), r = i.createText(e.item.data);
    i.insert(s, r);
  };
}
function Xu() {
  return (n, e, t) => {
    t.convertAttributes(e.item), !e.reconversion && e.item.is("element") && !e.item.isEmpty && t.convertChildren(e.item);
  };
}
function gv() {
  return (n, e, t) => {
    const i = t.mapper.toViewPosition(e.position), s = e.position.getShiftedBy(e.length), r = t.mapper.toViewPosition(s, { isPhantom: !0 }), o = t.writer.createRange(i, r), a = t.writer.remove(o.getTrimmed());
    for (const l of t.writer.createRangeIn(a).getItems())
      t.mapper.unbindViewElement(l, { defer: !0 });
  };
}
function Qu(n, e) {
  const t = n.createAttributeElement("span", e.attributes);
  return e.classes && t._addClass(e.classes), typeof e.priority == "number" && (t._priority = e.priority), t._id = e.id, t;
}
function pv() {
  return (n, e, t) => {
    const i = e.selection;
    if (i.isCollapsed || !t.consumable.consume(i, "selection"))
      return;
    const s = [];
    for (const r of i.getRanges())
      s.push(t.mapper.toViewRange(r));
    t.writer.setSelection(s, { backward: i.isBackward });
  };
}
function wv() {
  return (n, e, t) => {
    const i = e.selection;
    if (!i.isCollapsed || !t.consumable.consume(i, "selection"))
      return;
    const s = t.writer, r = i.getFirstPosition(), o = t.mapper.toViewPosition(r), a = s.breakAttributes(o);
    s.setSelection(a);
  };
}
function bv() {
  return (n, e, t) => {
    const i = t.writer, s = i.document.selection;
    for (const r of s.getRanges())
      r.isCollapsed && r.end.parent.isAttached() && t.writer.mergeAttributes(r.start);
    i.setSelection(null);
  };
}
function _v(n) {
  return (e, t, i) => {
    if (!i.consumable.test(t.item, e.name))
      return;
    const s = n(t.attributeOldValue, i, t), r = n(t.attributeNewValue, i, t);
    if (!s && !r)
      return;
    i.consumable.consume(t.item, e.name);
    const o = i.writer, a = o.document.selection;
    if (t.item instanceof we || t.item instanceof Ie)
      o.wrap(a.getFirstRange(), r);
    else {
      let l = i.mapper.toViewRange(t.range);
      t.attributeOldValue !== null && s && (l = o.unwrap(l, s)), t.attributeNewValue !== null && r && o.wrap(l, r);
    }
  };
}
function vv(n, e = jv) {
  return (t, i, s) => {
    if (!e(i.item, s.consumable, { preflight: !0 }))
      return;
    const r = n(i.item, s, i);
    if (!r)
      return;
    e(i.item, s.consumable);
    const o = s.mapper.toViewPosition(i.range.start);
    s.mapper.bindElements(i.item, r), s.writer.insert(o, r), s.convertAttributes(i.item), sh(r, i.item.getChildren(), s, { reconversion: i.reconversion });
  };
}
function yv(n, e) {
  return (t, i, s) => {
    if (!e(i.item, s.consumable, { preflight: !0 }))
      return;
    const r = /* @__PURE__ */ new Map();
    s.writer._registerSlotFactory(zv(i.item, r, s));
    const o = n(i.item, s, i);
    if (s.writer._clearSlotFactory(), !o)
      return;
    Hv(i.item, r, s), e(i.item, s.consumable);
    const a = s.mapper.toViewPosition(i.range.start);
    s.mapper.bindElements(i.item, o), s.writer.insert(a, o), s.convertAttributes(i.item), Wv(o, r, s, { reconversion: i.reconversion });
  };
}
function kv(n) {
  return (e, t, i) => {
    t.isOpening = !0;
    const s = n(t, i);
    t.isOpening = !1;
    const r = n(t, i);
    if (!s || !r)
      return;
    const o = t.markerRange;
    if (o.isCollapsed && !i.consumable.consume(o, e.name))
      return;
    for (const c of o)
      if (!i.consumable.consume(c.item, e.name))
        return;
    const a = i.mapper, l = i.writer;
    l.insert(a.toViewPosition(o.start), s), i.mapper.bindElementToMarker(s, t.markerName), o.isCollapsed || (l.insert(a.toViewPosition(o.end), r), i.mapper.bindElementToMarker(r, t.markerName)), e.stop();
  };
}
function Cv() {
  return (n, e, t) => {
    const i = t.mapper.markerNameToElements(e.markerName);
    if (i) {
      for (const s of i)
        t.mapper.unbindElementFromMarkerName(s, e.markerName), t.writer.clear(t.writer.createRangeOn(s), s);
      t.writer.clearClonedElementsGroup(e.markerName), n.stop();
    }
  };
}
function Ev(n) {
  return (e, t, i) => {
    const s = n(t.markerName, i);
    if (!s)
      return;
    const r = t.markerRange;
    i.consumable.consume(r, e.name) && (Pa(r, !1, i, t, s), Pa(r, !0, i, t, s), e.stop());
  };
}
function Pa(n, e, t, i, s) {
  const r = e ? n.start : n.end, o = r.nodeAfter && r.nodeAfter.is("element") ? r.nodeAfter : null, a = r.nodeBefore && r.nodeBefore.is("element") ? r.nodeBefore : null;
  if (o || a) {
    let c, u;
    e && o || !e && !a ? (c = o, u = !0) : (c = a, u = !1);
    const h = t.mapper.toViewElement(c);
    if (h) {
      Av(h, e, u, t, i, s);
      return;
    }
  }
  const l = t.mapper.toViewPosition(r);
  Tv(l, e, t, i, s);
}
function Av(n, e, t, i, s, r) {
  const o = `data-${r.group}-${e ? "start" : "end"}-${t ? "before" : "after"}`, a = n.hasAttribute(o) ? n.getAttribute(o).split(",") : [];
  a.unshift(r.name), i.writer.setAttribute(o, a.join(","), n), i.mapper.bindElementToMarker(n, s.markerName);
}
function Tv(n, e, t, i, s) {
  const r = `${s.group}-${e ? "start" : "end"}`, o = s.name ? { name: s.name } : null, a = t.writer.createUIElement(r, o);
  t.writer.insert(n, a), t.mapper.bindElementToMarker(a, i.markerName);
}
function Pv(n) {
  return (e, t, i) => {
    const s = n(t.markerName, i);
    if (!s)
      return;
    const r = i.mapper.markerNameToElements(t.markerName);
    if (!r)
      return;
    for (const a of r)
      i.mapper.unbindElementFromMarkerName(a, t.markerName), a.is("containerElement") ? (o(`data-${s.group}-start-before`, a), o(`data-${s.group}-start-after`, a), o(`data-${s.group}-end-before`, a), o(`data-${s.group}-end-after`, a)) : i.writer.clear(i.writer.createRangeOn(a), a);
    i.writer.clearClonedElementsGroup(t.markerName), e.stop();
    function o(a, l) {
      if (l.hasAttribute(a)) {
        const c = new Set(l.getAttribute(a).split(","));
        c.delete(s.name), c.size == 0 ? i.writer.removeAttribute(a, l) : i.writer.setAttribute(a, Array.from(c).join(","), l);
      }
    }
  };
}
function xv(n) {
  return (e, t, i) => {
    if (!i.consumable.test(t.item, e.name))
      return;
    const s = n(t.attributeOldValue, i, t), r = n(t.attributeNewValue, i, t);
    if (!s && !r)
      return;
    i.consumable.consume(t.item, e.name);
    const o = i.mapper.toViewElement(t.item), a = i.writer;
    if (!o)
      throw new d("conversion-attribute-to-attribute-on-text", i.dispatcher, t);
    if (t.attributeOldValue !== null && s)
      if (s.key == "class") {
        const l = X(s.value);
        for (const c of l)
          a.removeClass(c, o);
      } else if (s.key == "style") {
        const l = Object.keys(s.value);
        for (const c of l)
          a.removeStyle(c, o);
      } else
        a.removeAttribute(s.key, o);
    if (t.attributeNewValue !== null && r)
      if (r.key == "class") {
        const l = X(r.value);
        for (const c of l)
          a.addClass(c, o);
      } else if (r.key == "style") {
        const l = Object.keys(r.value);
        for (const c of l)
          a.setStyle(c, r.value[c], o);
      } else
        a.setAttribute(r.key, r.value, o);
  };
}
function Sv(n) {
  return (e, t, i) => {
    if (!t.item || !(t.item instanceof we || t.item instanceof Ie) && !t.item.is("$textProxy"))
      return;
    const s = Lr(n, t, i);
    if (!s || !i.consumable.consume(t.item, e.name))
      return;
    const r = i.writer, o = Qu(r, s), a = r.document.selection;
    if (t.item instanceof we || t.item instanceof Ie)
      r.wrap(a.getFirstRange(), o);
    else {
      const l = i.mapper.toViewRange(t.range), c = r.wrap(l, o);
      for (const u of c.getItems())
        if (u.is("attributeElement") && u.isSimilar(o)) {
          i.mapper.bindElementToMarker(u, t.markerName);
          break;
        }
    }
  };
}
function Iv(n) {
  return (e, t, i) => {
    if (!t.item || !(t.item instanceof B))
      return;
    const s = Lr(n, t, i);
    if (!s || !i.consumable.test(t.item, e.name))
      return;
    const r = i.mapper.toViewElement(t.item);
    if (r && r.getCustomProperty("addHighlight")) {
      i.consumable.consume(t.item, e.name);
      for (const a of g._createIn(t.item))
        i.consumable.consume(a.item, e.name);
      r.getCustomProperty("addHighlight")(r, s, i.writer), i.mapper.bindElementToMarker(r, t.markerName);
    }
  };
}
function Rv(n) {
  return (e, t, i) => {
    if (t.markerRange.isCollapsed)
      return;
    const s = Lr(n, t, i);
    if (!s)
      return;
    const r = Qu(i.writer, s), o = i.mapper.markerNameToElements(t.markerName);
    if (o) {
      for (const a of o)
        i.mapper.unbindElementFromMarkerName(a, t.markerName), a.is("attributeElement") ? i.writer.unwrap(i.writer.createRangeOn(a), r) : a.getCustomProperty("removeHighlight")(a, s.id, i.writer);
      i.writer.clearClonedElementsGroup(t.markerName), e.stop();
    }
  };
}
function Ov(n) {
  const e = eh(n.model), t = Mi(n.view, "container");
  return e.attributes.length && (e.children = !0), (i) => {
    i.on(`insert:${e.name}`, vv(t, nh(e)), { priority: n.converterPriority || "normal" }), (e.children || e.attributes.length) && i.on("reduceChanges", ih(e), { priority: "low" });
  };
}
function Mv(n) {
  const e = eh(n.model), t = Mi(n.view, "container");
  return e.children = !0, (i) => {
    if (i._conversionApi.schema.checkChild(e.name, "$text"))
      throw new d("conversion-element-to-structure-disallowed-text", i, { elementName: e.name });
    i.on(`insert:${e.name}`, yv(t, nh(e)), { priority: n.converterPriority || "normal" }), i.on("reduceChanges", ih(e), { priority: "low" });
  };
}
function Vv(n) {
  n = tt(n);
  let e = n.model;
  typeof e == "string" && (e = { key: e });
  let t = `attribute:${e.key}`;
  if (e.name && (t += ":" + e.name), e.values)
    for (const s of e.values)
      n.view[s] = Mi(n.view[s], "attribute");
  else
    n.view = Mi(n.view, "attribute");
  const i = th(n);
  return (s) => {
    s.on(t, _v(i), { priority: n.converterPriority || "normal" });
  };
}
function Dv(n) {
  n = tt(n);
  let e = n.model;
  typeof e == "string" && (e = { key: e });
  let t = `attribute:${e.key}`;
  if (e.name && (t += ":" + e.name), e.values)
    for (const s of e.values)
      n.view[s] = xa(n.view[s]);
  else
    n.view = xa(n.view);
  const i = th(n);
  return (s) => {
    s.on(t, xv(i), { priority: n.converterPriority || "normal" });
  };
}
function Bv(n) {
  const e = Mi(n.view, "ui");
  return (t) => {
    t.on(`addMarker:${n.model}`, kv(e), { priority: n.converterPriority || "normal" }), t.on(`removeMarker:${n.model}`, Cv(), { priority: n.converterPriority || "normal" });
  };
}
function Fv(n) {
  n = tt(n);
  const e = n.model;
  let t = n.view;
  return t || (t = (i) => ({
    group: e,
    name: i.substr(n.model.length + 1)
  })), (i) => {
    i.on(`addMarker:${e}`, Ev(t), { priority: n.converterPriority || "normal" }), i.on(`removeMarker:${e}`, Pv(t), { priority: n.converterPriority || "normal" });
  };
}
function Nv(n) {
  return (e) => {
    e.on(`addMarker:${n.model}`, Sv(n.view), { priority: n.converterPriority || "normal" }), e.on(`addMarker:${n.model}`, Iv(n.view), { priority: n.converterPriority || "normal" }), e.on(`removeMarker:${n.model}`, Rv(n.view), { priority: n.converterPriority || "normal" });
  };
}
function eh(n) {
  return typeof n == "string" && (n = { name: n }), n.attributes ? Array.isArray(n.attributes) || (n.attributes = [n.attributes]) : n.attributes = [], n.children = !!n.children, n;
}
function Mi(n, e) {
  return typeof n == "function" ? n : (t, i) => Lv(n, i, e);
}
function Lv(n, e, t) {
  typeof n == "string" && (n = { name: n });
  let i;
  const s = e.writer, r = Object.assign({}, n.attributes);
  if (t == "container")
    i = s.createContainerElement(n.name, r);
  else if (t == "attribute") {
    const o = {
      priority: n.priority || Et.DEFAULT_PRIORITY
    };
    i = s.createAttributeElement(n.name, r, o);
  } else
    i = s.createUIElement(n.name, r);
  if (n.styles) {
    const o = Object.keys(n.styles);
    for (const a of o)
      s.setStyle(a, n.styles[a], i);
  }
  if (n.classes) {
    const o = n.classes;
    if (typeof o == "string")
      s.addClass(o, i);
    else
      for (const a of o)
        s.addClass(a, i);
  }
  return i;
}
function th(n) {
  return n.model.values ? (e, t, i) => {
    const s = n.view[e];
    return s ? s(e, t, i) : null;
  } : n.view;
}
function xa(n) {
  return typeof n == "string" ? (e) => ({ key: n, value: e }) : typeof n == "object" ? n.value ? () => n : (e) => ({ key: n.key, value: e }) : n;
}
function Lr(n, e, t) {
  const i = typeof n == "function" ? n(e, t) : n;
  return i ? (i.priority || (i.priority = 10), i.id || (i.id = e.markerName), i) : null;
}
function $v(n) {
  return (e, t) => {
    if (!e.is("element", n.name))
      return !1;
    if (t.type == "attribute") {
      if (n.attributes.includes(t.attributeKey))
        return !0;
    } else {
      /* istanbul ignore else: This is always true because otherwise it would not register a reducer callback. -- @preserve */
      if (n.children)
        return !0;
    }
    return !1;
  };
}
function ih(n) {
  const e = $v(n);
  return (t, i) => {
    const s = [];
    i.reconvertedElements || (i.reconvertedElements = /* @__PURE__ */ new Set());
    for (const r of i.changes) {
      const o = r.type == "attribute" ? r.range.start.nodeAfter : r.position.parent;
      if (!o || !e(o, r)) {
        s.push(r);
        continue;
      }
      if (!i.reconvertedElements.has(o)) {
        i.reconvertedElements.add(o);
        const a = w._createBefore(o);
        let l = s.length;
        for (let c = s.length - 1; c >= 0; c--) {
          const u = s[c], f = (u.type == "attribute" ? u.range.start : u.position).compareWith(a);
          if (f == "before" || u.type == "remove" && f == "same")
            break;
          l = c;
        }
        s.splice(l, 0, {
          type: "remove",
          name: o.name,
          position: a,
          length: 1
        }, {
          type: "reinsert",
          name: o.name,
          position: a,
          length: 1
        });
      }
    }
    i.changes = s;
  };
}
function nh(n) {
  return (e, t, i = {}) => {
    const s = ["insert"];
    for (const r of n.attributes)
      e.hasAttribute(r) && s.push(`attribute:${r}`);
    return s.every((r) => t.test(e, r)) ? (i.preflight || s.forEach((r) => t.consume(e, r)), !0) : !1;
  };
}
function zv(n, e, t) {
  return (i, s) => {
    const r = i.createContainerElement("$slot");
    let o = null;
    if (s === "children")
      o = Array.from(n.getChildren());
    else if (typeof s == "function")
      o = Array.from(n.getChildren()).filter((a) => s(a));
    else
      throw new d("conversion-slot-mode-unknown", t.dispatcher, { modeOrFilter: s });
    return e.set(r, o), r;
  };
}
function Hv(n, e, t) {
  const i = Array.from(e.values()).flat(), s = new Set(i);
  if (s.size != i.length)
    throw new d("conversion-slot-filter-overlap", t.dispatcher, { element: n });
  if (s.size != n.childCount)
    throw new d("conversion-slot-filter-incomplete", t.dispatcher, { element: n });
}
function Wv(n, e, t, i) {
  t.mapper.on("modelToViewPosition", o, { priority: "highest" });
  let s = null, r = null;
  for ([s, r] of e)
    sh(n, r, t, i), t.writer.move(t.writer.createRangeIn(s), t.writer.createPositionBefore(s)), t.writer.remove(s);
  t.mapper.off("modelToViewPosition", o);
  function o(a, l) {
    const c = l.modelPosition.nodeAfter, u = r.indexOf(c);
    u < 0 || (l.viewPosition = l.mapper.findPositionIn(s, u));
  }
}
function sh(n, e, t, i) {
  for (const s of e)
    Uv(n.root, s, t, i) || t.convertItem(s);
}
function Uv(n, e, t, i) {
  const { writer: s, mapper: r } = t;
  if (!i.reconversion)
    return !1;
  const o = r.toViewElement(e);
  return !o || o.root == n || !t.canReuseView(o) ? !1 : (s.move(s.createRangeOn(o), r.toViewPosition(w._createBefore(e))), !0);
}
function jv(n, e, { preflight: t } = {}) {
  return t ? e.test(n, "insert") : e.consume(n, "insert");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function rh(n) {
  const { schema: e, document: t } = n.model;
  for (const i of t.getRootNames()) {
    const s = t.getRoot(i);
    if (s.isEmpty && !e.checkChild(s, "$text") && e.checkChild(s, "paragraph"))
      return n.insertElement("paragraph", s), !0;
  }
  return !1;
}
function oh(n, e, t) {
  const i = t.createContext(n);
  return !(!t.checkChild(i, "paragraph") || !t.checkChild(i.push("paragraph"), e));
}
function ah(n, e) {
  const t = e.createElement("paragraph");
  return e.insert(t, n), e.createPositionAt(t, 0);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class qv extends Zu {
  /**
   * View element to model element conversion helper.
   *
   * This conversion results in creating a model element. For example,
   * view `<p>Foo</p>` becomes `<paragraph>Foo</paragraph>` in the model.
   *
   * Keep in mind that the element will be inserted only if it is allowed
   * by {@link module:engine/model/schema~Schema schema} configuration.
   *
   * ```ts
   * editor.conversion.for( 'upcast' ).elementToElement( {
   * 	view: 'p',
   * 	model: 'paragraph'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToElement( {
   * 	view: 'p',
   * 	model: 'paragraph',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToElement( {
   * 	view: {
   * 		name: 'p',
   * 		classes: 'fancy'
   * 	},
   * 	model: 'fancyParagraph'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToElement( {
   * 	view: {
   * 		name: 'p',
   * 		classes: 'heading'
   * 	},
   * 	model: ( viewElement, conversionApi ) => {
   * 		const modelWriter = conversionApi.writer;
   *
   * 		return modelWriter.createElement( 'heading', { level: viewElement.getAttribute( 'data-level' ) } );
   * 	}
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.view Pattern matching all view elements which should be converted. If not set, the converter
   * will fire for every view element.
   * @param config.model Name of the model element, a model element instance or a function that takes a view element
   * and {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API}
   * and returns a model element. The model element will be inserted in the model.
   * @param config.converterPriority Converter priority.
   */
  elementToElement(e) {
    return this.add(lh(e));
  }
  /**
   * View element to model attribute conversion helper.
   *
   * This conversion results in setting an attribute on a model node. For example, view `<strong>Foo</strong>` becomes
   * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.
   *
   * This helper is meant to set a model attribute on all the elements that are inside the converted element:
   *
   * ```
   * <strong>Foo</strong>   -->   <strong><p>Foo</p></strong>   -->   <paragraph><$text bold="true">Foo</$text></paragraph>
   * ```
   *
   * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).
   * Even though `<strong>` is over `<p>` element, `bold="true"` was added to the text. See
   * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute} for comparison.
   *
   * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.
   *
   * ```ts
   * editor.conversion.for( 'upcast' ).elementToAttribute( {
   * 	view: 'strong',
   * 	model: 'bold'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToAttribute( {
   * 	view: 'strong',
   * 	model: 'bold',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToAttribute( {
   * 	view: {
   * 		name: 'span',
   * 		classes: 'bold'
   * 	},
   * 	model: 'bold'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToAttribute( {
   * 	view: {
   * 		name: 'span',
   * 		classes: [ 'styled', 'styled-dark' ]
   * 	},
   * 	model: {
   * 		key: 'styled',
   * 		value: 'dark'
   * 	}
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToAttribute( {
   * 	view: {
   * 		name: 'span',
   * 		styles: {
   * 			'font-size': /[\s\S]+/
   * 		}
   * 	},
   * 	model: {
   * 		key: 'fontSize',
   * 		value: ( viewElement, conversionApi ) => {
   * 			const fontSize = viewElement.getStyle( 'font-size' );
   * 			const value = fontSize.substr( 0, fontSize.length - 2 );
   *
   * 			if ( value <= 10 ) {
   * 				return 'small';
   * 			} else if ( value > 12 ) {
   * 				return 'big';
   * 			}
   *
   * 			return null;
   * 		}
   * 	}
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.view Pattern matching all view elements which should be converted.
   * @param config.model Model attribute key or an object with `key` and `value` properties, describing
   * the model attribute. `value` property may be set as a function that takes a view element and
   * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.
   * If `String` is given, the model attribute value will be set to `true`.
   * @param config.converterPriority Converter priority. Defaults to `low`.
   */
  elementToAttribute(e) {
    return this.add(Jv(e));
  }
  /**
   * View attribute to model attribute conversion helper.
   *
   * This conversion results in setting an attribute on a model node. For example, view `<img src="foo.jpg"></img>` becomes
   * `<imageBlock source="foo.jpg"></imageBlock>` in the model.
   *
   * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute
   * is set only on the corresponding model node:
   *
   * ```
   * <div class="dark"><div>foo</div></div>    -->    <div dark="true"><div>foo</div></div>
   * ```
   *
   * Above, `class="dark"` attribute is added only to the `<div>` elements that has it. This is in contrary to
   * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute} which sets attributes for
   * all the children in the model:
   *
   * ```
   * <strong>Foo</strong>   -->   <strong><p>Foo</p></strong>   -->   <paragraph><$text bold="true">Foo</$text></paragraph>
   * ```
   *
   * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).
   * Even though `<strong>` is over `<p>` element, `bold="true"` was added to the text.
   *
   * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.
   *
   * ```ts
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: 'src',
   * 	model: 'source'
   * } );
   *
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: { key: 'src' },
   * 	model: 'source'
   * } );
   *
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: { key: 'src' },
   * 	model: 'source',
   * 	converterPriority: 'normal'
   * } );
   *
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: {
   * 		key: 'data-style',
   * 		value: /[\s\S]+/
   * 	},
   * 	model: 'styled'
   * } );
   *
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: {
   * 		name: 'img',
   * 		key: 'class',
   * 		value: 'styled-dark'
   * 	},
   * 	model: {
   * 		key: 'styled',
   * 		value: 'dark'
   * 	}
   * } );
   *
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: {
   * 		key: 'class',
   * 		value: /styled-[\S]+/
   * 	},
   * 	model: {
   * 		key: 'styled'
   * 		value: ( viewElement, conversionApi ) => {
   * 			const regexp = /styled-([\S]+)/;
   * 			const match = viewElement.getAttribute( 'class' ).match( regexp );
   *
   * 			return match[ 1 ];
   * 		}
   * 	}
   * } );
   * ```
   *
   * Converting styles works a bit differently as it requires `view.styles` to be an object and by default
   * a model attribute will be set to `true` by such a converter. You can set the model attribute to any value by providing the `value`
   * callback that returns the desired value.
   *
   * ```ts
   * // Default conversion of font-weight style will result in setting bold attribute to true.
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: {
   * 		styles: {
   * 			'font-weight': 'bold'
   * 		}
   * 	},
   * 	model: 'bold'
   * } );
   *
   * // This converter will pass any style value to the `lineHeight` model attribute.
   * editor.conversion.for( 'upcast' ).attributeToAttribute( {
   * 	view: {
   * 		styles: {
   * 			'line-height': /[\s\S]+/
   * 		}
   * 	},
   * 	model: {
   * 		key: 'lineHeight',
   * 		value: ( viewElement, conversionApi ) => viewElement.getStyle( 'line-height' )
   * 	}
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.view Specifies which view attribute will be converted. If a `String` is passed,
   * attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,
   * specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`
   * property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,
   * a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.
   * @param config.model Model attribute key or an object with `key` and `value` properties, describing
   * the model attribute. `value` property may be set as a function that takes a view element and
   * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.
   * If `String` is given, the model attribute value will be same as view attribute value.
   * @param config.converterPriority Converter priority. Defaults to `low`.
   */
  attributeToAttribute(e) {
    return this.add(Zv(e));
  }
  /**
   * View element to model marker conversion helper.
   *
   * This conversion results in creating a model marker. For example, if the marker was stored in a view as an element:
   * `<p>Fo<span data-marker="comment" data-comment-id="7"></span>o</p><p>B<span data-marker="comment" data-comment-id="7"></span>ar</p>`,
   * after the conversion is done, the marker will be available in
   * {@link module:engine/model/model~Model#markers model document markers}.
   *
   * **Note**: When this helper is used in the data upcast in combination with
   * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} in the data downcast,
   * then invalid HTML code (e.g. a span between table cells) may be produced by the latter converter.
   *
   * In most of the cases, the {@link #dataToMarker} should be used instead.
   *
   * ```ts
   * editor.conversion.for( 'upcast' ).elementToMarker( {
   * 	view: 'marker-search',
   * 	model: 'search'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToMarker( {
   * 	view: 'marker-search',
   * 	model: 'search',
   * 	converterPriority: 'high'
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToMarker( {
   * 	view: 'marker-search',
   * 	model: ( viewElement, conversionApi ) => 'comment:' + viewElement.getAttribute( 'data-comment-id' )
   * } );
   *
   * editor.conversion.for( 'upcast' ).elementToMarker( {
   * 	view: {
   * 		name: 'span',
   * 		attributes: {
   * 			'data-marker': 'search'
   * 		}
   * 	},
   * 	model: 'search'
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.view Pattern matching all view elements which should be converted.
   * @param config.model Name of the model marker, or a function that takes a view element and returns
   * a model marker name.
   * @param config.converterPriority Converter priority.
   */
  elementToMarker(e) {
    return this.add(Yv(e));
  }
  /**
   * View-to-model marker conversion helper.
   *
   * Converts view data created by {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`}
   * back to a model marker.
   *
   * This converter looks for specific view elements and view attributes that mark marker boundaries. See
   * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} to learn what view data
   * is expected by this converter.
   *
   * The `config.view` property is equal to the marker group name to convert.
   *
   * By default, this converter creates markers with the `group:name` name convention (to match the default `markerToData` conversion).
   *
   * The conversion configuration can take a function that will generate a marker name.
   * If such function is set as the `config.model` parameter, it is passed the `name` part from the view element or attribute and it is
   * expected to return a string with the marker name.
   *
   * Basic usage:
   *
   * ```ts
   * // Using the default conversion.
   * // In this case, all markers from the `comment` group will be converted.
   * // The conversion will look for `<comment-start>` and `<comment-end>` tags and
   * // `data-comment-start-before`, `data-comment-start-after`,
   * // `data-comment-end-before` and `data-comment-end-after` attributes.
   * editor.conversion.for( 'upcast' ).dataToMarker( {
   * 	view: 'comment'
   * } );
   * ```
   *
   * An example of a model that may be generated by this conversion:
   *
   * ```
   * // View:
   * <p>Foo<comment-start name="commentId:uid"></comment-start>bar</p>
   * <figure data-comment-end-after="commentId:uid" class="image"><img src="abc.jpg" /></figure>
   *
   * // Model:
   * <paragraph>Foo[bar</paragraph>
   * <imageBlock src="abc.jpg"></imageBlock>]
   * ```
   *
   * Where `[]` are boundaries of a marker that will receive the `comment:commentId:uid` name.
   *
   * Other examples of usage:
   *
   * ```ts
   * // Using a custom function which is the same as the default conversion:
   * editor.conversion.for( 'upcast' ).dataToMarker( {
   * 	view: 'comment',
   * 	model: ( name, conversionApi ) => 'comment:' + name,
   * } );
   *
   * // Using the converter priority:
   * editor.conversion.for( 'upcast' ).dataToMarker( {
   * 	view: 'comment',
   * 	model: ( name, conversionApi ) => 'comment:' + name,
   * 	converterPriority: 'high'
   * } );
   * ```
   *
   * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
   * to the conversion process.
   *
   * @param config Conversion configuration.
   * @param config.view The marker group name to convert.
   * @param config.model A function that takes the `name` part from the view element or attribute and
   * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the marker name.
   * @param config.converterPriority Converter priority.
   */
  dataToMarker(e) {
    return this.add(Xv(e));
  }
}
function Sa() {
  return (n, e, t) => {
    if (!e.modelRange && t.consumable.consume(e.viewItem, { name: !0 })) {
      const { modelRange: i, modelCursor: s } = t.convertChildren(e.viewItem, e.modelCursor);
      e.modelRange = i, e.modelCursor = s;
    }
  };
}
function Gv() {
  return (n, e, { schema: t, consumable: i, writer: s }) => {
    let r = e.modelCursor;
    if (!i.test(e.viewItem))
      return;
    if (!t.checkChild(r, "$text")) {
      if (!oh(r, "$text", t) || e.viewItem.data.trim().length == 0)
        return;
      const a = r.nodeBefore;
      r = ah(r, s), a && a.is("element", "$marker") && (s.move(s.createRangeOn(a), r), r = s.createPositionAfter(a));
    }
    i.consume(e.viewItem);
    const o = s.createText(e.viewItem.data);
    s.insert(o, r), e.modelRange = s.createRange(r, r.getShiftedBy(o.offsetSize)), e.modelCursor = e.modelRange.end;
  };
}
function Kv(n, e) {
  return (t, i) => {
    const s = i.newSelection, r = [];
    for (const a of s.getRanges())
      r.push(e.toModelRange(a));
    const o = n.createSelection(r, { backward: s.isBackward });
    o.isEqual(n.document.selection) || n.change((a) => {
      a.setSelection(o);
    });
  };
}
function lh(n) {
  n = tt(n);
  const e = Xs(n), t = $r(n.view), i = t ? `element:${t}` : "element";
  return (s) => {
    s.on(i, e, { priority: n.converterPriority || "normal" });
  };
}
function Jv(n) {
  n = tt(n), ch(n);
  const e = uh(n, !1), t = $r(n.view), i = t ? `element:${t}` : "element";
  return (s) => {
    s.on(i, e, { priority: n.converterPriority || "low" });
  };
}
function Zv(n) {
  n = tt(n);
  let e = null;
  (typeof n.view == "string" || n.view.key) && (e = ty(n)), ch(n, e);
  const t = uh(n, !0);
  return (i) => {
    i.on("element", t, { priority: n.converterPriority || "low" });
  };
}
function Yv(n) {
  const e = sy(n.model);
  return lh({ ...n, model: e });
}
function Xv(n) {
  n = tt(n), n.model || (n.model = (s) => s ? n.view + ":" + s : n.view);
  const e = {
    view: n.view,
    model: n.model
  }, t = Xs(Ia(e, "start")), i = Xs(Ia(e, "end"));
  return (s) => {
    s.on(`element:${n.view}-start`, t, { priority: n.converterPriority || "normal" }), s.on(`element:${n.view}-end`, i, { priority: n.converterPriority || "normal" });
    const r = be.low, o = be.highest, a = be.get(n.converterPriority) / o;
    s.on("element", Qv(e), { priority: r + a });
  };
}
function Qv(n) {
  return (e, t, i) => {
    const s = `data-${n.view}`;
    if (!i.consumable.test(t.viewItem, { attributes: s + "-end-after" }) && !i.consumable.test(t.viewItem, { attributes: s + "-start-after" }) && !i.consumable.test(t.viewItem, { attributes: s + "-end-before" }) && !i.consumable.test(t.viewItem, { attributes: s + "-start-before" }))
      return;
    t.modelRange || Object.assign(t, i.convertChildren(t.viewItem, t.modelCursor)), i.consumable.consume(t.viewItem, { attributes: s + "-end-after" }) && r(t.modelRange.end, t.viewItem.getAttribute(s + "-end-after").split(",")), i.consumable.consume(t.viewItem, { attributes: s + "-start-after" }) && r(t.modelRange.end, t.viewItem.getAttribute(s + "-start-after").split(",")), i.consumable.consume(t.viewItem, { attributes: s + "-end-before" }) && r(t.modelRange.start, t.viewItem.getAttribute(s + "-end-before").split(",")), i.consumable.consume(t.viewItem, { attributes: s + "-start-before" }) && r(t.modelRange.start, t.viewItem.getAttribute(s + "-start-before").split(","));
    function r(o, a) {
      for (const l of a) {
        const c = n.model(l, i), u = i.writer.createElement("$marker", { "data-name": c });
        i.writer.insert(u, o), t.modelCursor.isEqual(o) ? t.modelCursor = t.modelCursor.getShiftedBy(1) : t.modelCursor = t.modelCursor._getTransformedByInsertion(o, 1), t.modelRange = t.modelRange._getTransformedByInsertion(o, 1)[0];
      }
    }
  };
}
function $r(n) {
  return typeof n == "string" ? n : typeof n == "object" && typeof n.name == "string" ? n.name : null;
}
function Xs(n) {
  const e = new ni(n.view);
  return (t, i, s) => {
    const r = e.match(i.viewItem);
    if (!r)
      return;
    const o = r.match;
    if (o.name = !0, !s.consumable.test(i.viewItem, o))
      return;
    const a = ey(n.model, i.viewItem, s);
    a && s.safeInsert(a, i.modelCursor) && (s.consumable.consume(i.viewItem, o), s.convertChildren(i.viewItem, a), s.updateConversionResult(a, i));
  };
}
function ey(n, e, t) {
  return n instanceof Function ? n(e, t) : t.writer.createElement(n);
}
function ty(n) {
  typeof n.view == "string" && (n.view = { key: n.view });
  const e = n.view.key;
  let t;
  if (e == "class" || e == "style")
    t = {
      [e == "class" ? "classes" : "styles"]: n.view.value
    };
  else {
    const i = typeof n.view.value > "u" ? /[\s\S]*/ : n.view.value;
    t = {
      attributes: {
        [e]: i
      }
    };
  }
  return n.view.name && (t.name = n.view.name), n.view = t, e;
}
function ch(n, e = null) {
  const t = e === null ? !0 : (r) => r.getAttribute(e), i = typeof n.model != "object" ? n.model : n.model.key, s = typeof n.model != "object" || typeof n.model.value > "u" ? t : n.model.value;
  n.model = { key: i, value: s };
}
function uh(n, e) {
  const t = new ni(n.view);
  return (i, s, r) => {
    if (!s.modelRange && e)
      return;
    const o = t.match(s.viewItem);
    if (!o || (iy(n.view, s.viewItem) ? o.match.name = !0 : delete o.match.name, !r.consumable.test(s.viewItem, o.match)))
      return;
    const a = n.model.key, l = typeof n.model.value == "function" ? n.model.value(s.viewItem, r) : n.model.value;
    if (l === null)
      return;
    s.modelRange || Object.assign(s, r.convertChildren(s.viewItem, s.modelCursor)), ny(s.modelRange, { key: a, value: l }, e, r) && (r.consumable.test(s.viewItem, { name: !0 }) && (o.match.name = !0), r.consumable.consume(s.viewItem, o.match));
  };
}
function iy(n, e) {
  const t = typeof n == "function" ? n(e) : n;
  return typeof t == "object" && !$r(t) ? !1 : !t.classes && !t.attributes && !t.styles;
}
function ny(n, e, t, i) {
  let s = !1;
  for (const r of Array.from(n.getItems({ shallow: t })))
    i.schema.checkAttribute(r, e.key) && (s = !0, !r.hasAttribute(e.key) && i.writer.setAttribute(e.key, e.value, r));
  return s;
}
function sy(n) {
  return (e, t) => {
    const i = typeof n == "string" ? n : n(e, t);
    return t.writer.createElement("$marker", { "data-name": i });
  };
}
function Ia(n, e) {
  const t = (i, s) => {
    const r = i.getAttribute("name"), o = n.model(r, s);
    return s.writer.createElement("$marker", { "data-name": o });
  };
  return {
    // Upcast <markerGroup-start> and <markerGroup-end> elements.
    view: `${n.view}-${e}`,
    model: t
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function ry(n) {
  n.document.registerPostFixer((e) => oy(e, n));
}
function oy(n, e) {
  const t = e.document.selection, i = e.schema, s = [];
  let r = !1;
  for (const o of t.getRanges()) {
    const a = hh(o, i);
    a && !a.isEqual(o) ? (s.push(a), r = !0) : s.push(o);
  }
  return r && n.setSelection(uy(s), { backward: t.isBackward }), !1;
}
function hh(n, e) {
  return n.isCollapsed ? ay(n, e) : ly(n, e);
}
function ay(n, e) {
  const t = n.start, i = e.getNearestSelectionRange(t);
  if (!i) {
    const r = t.getAncestors().reverse().find((o) => e.isObject(o));
    return r ? g._createOn(r) : null;
  }
  if (!i.isCollapsed)
    return i;
  const s = i.start;
  return t.isEqual(s) ? null : new g(s);
}
function ly(n, e) {
  const { start: t, end: i } = n, s = e.checkChild(t, "$text"), r = e.checkChild(i, "$text"), o = e.getLimitElement(t), a = e.getLimitElement(i);
  if (o === a) {
    if (s && r)
      return null;
    if (cy(t, i, e)) {
      const h = t.nodeAfter && e.isSelectable(t.nodeAfter) ? null : e.getNearestSelectionRange(t, "forward"), m = i.nodeBefore && e.isSelectable(i.nodeBefore) ? null : e.getNearestSelectionRange(i, "backward"), p = h ? h.start : t, b = m ? m.end : i;
      return new g(p, b);
    }
  }
  const l = o && !o.is("rootElement"), c = a && !a.is("rootElement");
  if (l || c) {
    const u = t.nodeAfter && i.nodeBefore && t.nodeAfter.parent === i.nodeBefore.parent, h = l && (!u || !Oa(t.nodeAfter, e)), f = c && (!u || !Oa(i.nodeBefore, e));
    let m = t, p = i;
    return h && (m = w._createBefore(Ra(o, e))), f && (p = w._createAfter(Ra(a, e))), new g(m, p);
  }
  return null;
}
function Ra(n, e) {
  let t = n, i = t;
  for (; e.isLimit(i) && i.parent; )
    t = i, i = i.parent;
  return t;
}
function cy(n, e, t) {
  const i = n.nodeAfter && !t.isLimit(n.nodeAfter) || t.checkChild(n, "$text"), s = e.nodeBefore && !t.isLimit(e.nodeBefore) || t.checkChild(e, "$text");
  return i || s;
}
function uy(n) {
  const e = [...n], t = /* @__PURE__ */ new Set();
  let i = 1;
  for (; i < e.length; ) {
    const r = e[i], o = e.slice(0, i);
    for (const [a, l] of o.entries())
      if (!t.has(a)) {
        if (r.isEqual(l))
          t.add(a);
        else if (r.isIntersecting(l)) {
          t.add(a), t.add(i);
          const c = r.getJoined(l);
          e.push(c);
        }
      }
    i++;
  }
  return e.filter((r, o) => !t.has(o));
}
function Oa(n, e) {
  return n && e.isSelectable(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class hy extends z() {
  /**
   * Creates an editing controller instance.
   *
   * @param model Editing model.
   * @param stylesProcessor The styles processor instance.
   */
  constructor(e, t) {
    super(), this.model = e, this.view = new Q1(t), this.mapper = new Gu(), this.downcastDispatcher = new Ku({
      mapper: this.mapper,
      schema: e.schema
    });
    const i = this.model.document, s = i.selection, r = this.model.markers;
    this.listenTo(this.model, "_beforeChanges", () => {
      this.view._disableRendering(!0);
    }, { priority: "highest" }), this.listenTo(this.model, "_afterChanges", () => {
      this.view._disableRendering(!1);
    }, { priority: "lowest" }), this.listenTo(i, "change", () => {
      this.view.change((o) => {
        this.downcastDispatcher.convertChanges(i.differ, r, o), this.downcastDispatcher.convertSelection(s, r, o);
      });
    }, { priority: "low" }), this.listenTo(this.view.document, "selectionChange", Kv(this.model, this.mapper)), this.listenTo(this.view.document, "beforeinput", dy(this.mapper, this.model.schema, this.view), { priority: "high" }), this.downcastDispatcher.on("insert:$text", Yu(), { priority: "lowest" }), this.downcastDispatcher.on("insert", Xu(), { priority: "lowest" }), this.downcastDispatcher.on("remove", gv(), { priority: "low" }), this.downcastDispatcher.on("selection", bv(), { priority: "high" }), this.downcastDispatcher.on("selection", pv(), { priority: "low" }), this.downcastDispatcher.on("selection", wv(), { priority: "low" }), this.view.document.roots.bindTo(this.model.document.roots).using((o) => {
      if (o.rootName == "$graveyard")
        return null;
      const a = new Ru(this.view.document, o.name);
      return a.rootName = o.rootName, this.mapper.bindElements(o, a), a;
    });
  }
  /**
   * Removes all event listeners attached to the `EditingController`. Destroys all objects created
   * by `EditingController` that need to be destroyed.
   */
  destroy() {
    this.view.destroy(), this.stopListening();
  }
  /**
   * Calling this method will refresh the marker by triggering the downcast conversion for it.
   *
   * Reconverting the marker is useful when you want to change its {@link module:engine/view/element~Element view element}
   * without changing any marker data. For instance:
   *
   * ```ts
   * let isCommentActive = false;
   *
   * model.conversion.markerToHighlight( {
   * 	model: 'comment',
   * 	view: data => {
   * 		const classes = [ 'comment-marker' ];
   *
   * 		if ( isCommentActive ) {
   * 			classes.push( 'comment-marker--active' );
   * 		}
   *
   * 		return { classes };
   * 	}
   * } );
   *
   * // ...
   *
   * // Change the property that indicates if marker is displayed as active or not.
   * isCommentActive = true;
   *
   * // Reconverting will downcast and synchronize the marker with the new isCommentActive state value.
   * editor.editing.reconvertMarker( 'comment' );
   * ```
   *
   * **Note**: If you want to reconvert a model item, use {@link #reconvertItem} instead.
   *
   * @param markerOrName Name of a marker to update, or a marker instance.
   */
  reconvertMarker(e) {
    const t = typeof e == "string" ? e : e.name, i = this.model.markers.get(t);
    if (!i)
      throw new d("editingcontroller-reconvertmarker-marker-not-exist", this, { markerName: t });
    this.model.change(() => {
      this.model.markers._refresh(i);
    });
  }
  /**
   * Calling this method will downcast a model item on demand (by requesting a refresh in the {@link module:engine/model/differ~Differ}).
   *
   * You can use it if you want the view representation of a specific item updated as a response to external modifications. For instance,
   * when the view structure depends not only on the associated model data but also on some external state.
   *
   * **Note**: If you want to reconvert a model marker, use {@link #reconvertMarker} instead.
   *
   * @param item Item to refresh.
   */
  reconvertItem(e) {
    this.model.change(() => {
      this.model.document.differ._refreshItem(e);
    });
  }
}
function dy(n, e, t) {
  return (i, s) => {
    if (!(t.document.isComposing && !S.isAndroid))
      for (let r = 0; r < s.targetRanges.length; r++) {
        const o = s.targetRanges[r], a = n.toModelRange(o), l = hh(a, e);
        !l || l.isEqual(a) || (s.targetRanges[r] = n.toViewRange(l));
      }
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ai {
  constructor() {
    this._consumables = /* @__PURE__ */ new Map();
  }
  add(e, t) {
    let i;
    if (e.is("$text") || e.is("documentFragment")) {
      this._consumables.set(e, !0);
      return;
    }
    this._consumables.has(e) ? i = this._consumables.get(e) : (i = new fy(e), this._consumables.set(e, i)), i.add(t);
  }
  /**
   * Tests if {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or
   * {@link module:engine/view/documentfragment~DocumentFragment document fragment} can be consumed.
   * It returns `true` when all items included in method's call can be consumed. Returns `false` when
   * first already consumed item is found and `null` when first non-consumable item is found.
   *
   * ```ts
   * viewConsumable.test( p, { name: true } ); // Tests element's name.
   * viewConsumable.test( p, { attributes: 'name' } ); // Tests attribute.
   * viewConsumable.test( p, { classes: 'foobar' } ); // Tests class.
   * viewConsumable.test( p, { styles: 'color' } ); // Tests style.
   * viewConsumable.test( p, { attributes: 'name', styles: 'color' } ); // Tests attribute and style.
   * viewConsumable.test( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be tested.
   * viewConsumable.test( textNode ); // Tests text node.
   * viewConsumable.test( docFragment ); // Tests document fragment.
   * ```
   *
   * Testing classes and styles as attribute will test if all added classes/styles can be consumed.
   *
   * ```ts
   * viewConsumable.test( p, { attributes: 'class' } ); // Tests if all added classes can be consumed.
   * viewConsumable.test( p, { attributes: 'style' } ); // Tests if all added styles can be consumed.
   * ```
   *
   * @param consumables Used only if first parameter is {@link module:engine/view/element~Element view element} instance.
   * @param consumables.name If set to true element's name will be included.
   * @param consumables.attributes Attribute name or array of attribute names.
   * @param consumables.classes Class name or array of class names.
   * @param consumables.styles Style name or array of style names.
   * @returns Returns `true` when all items included in method's call can be consumed. Returns `false`
   * when first already consumed item is found and `null` when first non-consumable item is found.
   */
  test(e, t) {
    const i = this._consumables.get(e);
    return i === void 0 ? null : e.is("$text") || e.is("documentFragment") ? i : i.test(t);
  }
  /**
   * Consumes {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or
   * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.
   * It returns `true` when all items included in method's call can be consumed, otherwise returns `false`.
   *
   * ```ts
   * viewConsumable.consume( p, { name: true } ); // Consumes element's name.
   * viewConsumable.consume( p, { attributes: 'name' } ); // Consumes element's attribute.
   * viewConsumable.consume( p, { classes: 'foobar' } ); // Consumes element's class.
   * viewConsumable.consume( p, { styles: 'color' } ); // Consumes element's style.
   * viewConsumable.consume( p, { attributes: 'name', styles: 'color' } ); // Consumes attribute and style.
   * viewConsumable.consume( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be consumed.
   * viewConsumable.consume( textNode ); // Consumes text node.
   * viewConsumable.consume( docFragment ); // Consumes document fragment.
   * ```
   *
   * Consuming classes and styles as attribute will test if all added classes/styles can be consumed.
   *
   * ```ts
   * viewConsumable.consume( p, { attributes: 'class' } ); // Consume only if all added classes can be consumed.
   * viewConsumable.consume( p, { attributes: 'style' } ); // Consume only if all added styles can be consumed.
   * ```
   *
   * @param consumables Used only if first parameter is {@link module:engine/view/element~Element view element} instance.
   * @param consumables.name If set to true element's name will be included.
   * @param consumables.attributes Attribute name or array of attribute names.
   * @param consumables.classes Class name or array of class names.
   * @param consumables.styles Style name or array of style names.
   * @returns Returns `true` when all items included in method's call can be consumed,
   * otherwise returns `false`.
   */
  consume(e, t) {
    return this.test(e, t) ? (e.is("$text") || e.is("documentFragment") ? this._consumables.set(e, !1) : this._consumables.get(e).consume(t), !0) : !1;
  }
  /**
   * Reverts {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or
   * {@link module:engine/view/documentfragment~DocumentFragment document fragment} so they can be consumed once again.
   * Method does not revert items that were never previously added for consumption, even if they are included in
   * method's call.
   *
   * ```ts
   * viewConsumable.revert( p, { name: true } ); // Reverts element's name.
   * viewConsumable.revert( p, { attributes: 'name' } ); // Reverts element's attribute.
   * viewConsumable.revert( p, { classes: 'foobar' } ); // Reverts element's class.
   * viewConsumable.revert( p, { styles: 'color' } ); // Reverts element's style.
   * viewConsumable.revert( p, { attributes: 'name', styles: 'color' } ); // Reverts attribute and style.
   * viewConsumable.revert( p, { classes: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.
   * viewConsumable.revert( textNode ); // Reverts text node.
   * viewConsumable.revert( docFragment ); // Reverts document fragment.
   * ```
   *
   * Reverting classes and styles as attribute will revert all classes/styles that were previously added for
   * consumption.
   *
   * ```ts
   * viewConsumable.revert( p, { attributes: 'class' } ); // Reverts all classes added for consumption.
   * viewConsumable.revert( p, { attributes: 'style' } ); // Reverts all styles added for consumption.
   * ```
   *
   * @param consumables Used only if first parameter is {@link module:engine/view/element~Element view element} instance.
   * @param consumables.name If set to true element's name will be included.
   * @param consumables.attributes Attribute name or array of attribute names.
   * @param consumables.classes Class name or array of class names.
   * @param consumables.styles Style name or array of style names.
   */
  revert(e, t) {
    const i = this._consumables.get(e);
    i !== void 0 && (e.is("$text") || e.is("documentFragment") ? this._consumables.set(e, !0) : i.revert(t));
  }
  /**
   * Creates consumable object from {@link module:engine/view/element~Element view element}. Consumable object will include
   * element's name and all its attributes, classes and styles.
   */
  static consumablesFromElement(e) {
    const t = {
      element: e,
      name: !0,
      attributes: [],
      classes: [],
      styles: []
    }, i = e.getAttributeKeys();
    for (const o of i)
      o == "style" || o == "class" || t.attributes.push(o);
    const s = e.getClassNames();
    for (const o of s)
      t.classes.push(o);
    const r = e.getStyleNames();
    for (const o of r)
      t.styles.push(o);
    return t;
  }
  /**
   * Creates {@link module:engine/conversion/viewconsumable~ViewConsumable ViewConsumable} instance from
   * {@link module:engine/view/node~Node node} or {@link module:engine/view/documentfragment~DocumentFragment document fragment}.
   * Instance will contain all elements, child nodes, attributes, styles and classes added for consumption.
   *
   * @param from View node or document fragment from which `ViewConsumable` will be created.
   * @param instance If provided, given `ViewConsumable` instance will be used
   * to add all consumables. It will be returned instead of a new instance.
   */
  static createFrom(e, t) {
    if (t || (t = new Ai()), e.is("$text"))
      return t.add(e), t;
    e.is("element") && t.add(e, Ai.consumablesFromElement(e)), e.is("documentFragment") && t.add(e);
    for (const i of e.getChildren())
      t = Ai.createFrom(i, t);
    return t;
  }
}
const Yi = ["attributes", "classes", "styles"];
class fy {
  /**
   * Creates ViewElementConsumables instance.
   *
   * @param from View node or document fragment from which `ViewElementConsumables` is being created.
   */
  constructor(e) {
    this.element = e, this._canConsumeName = null, this._consumables = {
      attributes: /* @__PURE__ */ new Map(),
      styles: /* @__PURE__ */ new Map(),
      classes: /* @__PURE__ */ new Map()
    };
  }
  /**
   * Adds consumable parts of the {@link module:engine/view/element~Element view element}.
   * Element's name itself can be marked to be consumed (when element's name is consumed its attributes, classes and
   * styles still could be consumed):
   *
   * ```ts
   * consumables.add( { name: true } );
   * ```
   *
   * Attributes classes and styles:
   *
   * ```ts
   * consumables.add( { attributes: 'title', classes: 'foo', styles: 'color' } );
   * consumables.add( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );
   * ```
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
   * attribute is provided - it should be handled separately by providing `style` and `class` in consumables object.
   *
   * @param consumables Object describing which parts of the element can be consumed.
   * @param consumables.name If set to `true` element's name will be added as consumable.
   * @param consumables.attributes Attribute name or array of attribute names to add as consumable.
   * @param consumables.classes Class name or array of class names to add as consumable.
   * @param consumables.styles Style name or array of style names to add as consumable.
   */
  add(e) {
    e.name && (this._canConsumeName = !0);
    for (const t of Yi)
      t in e && this._add(t, e[t]);
  }
  /**
   * Tests if parts of the {@link module:engine/view/node~Node view node} can be consumed.
   *
   * Element's name can be tested:
   *
   * ```ts
   * consumables.test( { name: true } );
   * ```
   *
   * Attributes classes and styles:
   *
   * ```ts
   * consumables.test( { attributes: 'title', classes: 'foo', styles: 'color' } );
   * consumables.test( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );
   * ```
   *
   * @param consumables Object describing which parts of the element should be tested.
   * @param consumables.name If set to `true` element's name will be tested.
   * @param consumables.attributes Attribute name or array of attribute names to test.
   * @param consumables.classes Class name or array of class names to test.
   * @param consumables.styles Style name or array of style names to test.
   * @returns `true` when all tested items can be consumed, `null` when even one of the items
   * was never marked for consumption and `false` when even one of the items was already consumed.
   */
  test(e) {
    if (e.name && !this._canConsumeName)
      return this._canConsumeName;
    for (const t of Yi)
      if (t in e) {
        const i = this._test(t, e[t]);
        if (i !== !0)
          return i;
      }
    return !0;
  }
  /**
   * Consumes parts of {@link module:engine/view/element~Element view element}. This function does not check if consumable item
   * is already consumed - it consumes all consumable items provided.
   * Element's name can be consumed:
   *
   * ```ts
   * consumables.consume( { name: true } );
   * ```
   *
   * Attributes classes and styles:
   *
   * ```ts
   * consumables.consume( { attributes: 'title', classes: 'foo', styles: 'color' } );
   * consumables.consume( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );
   * ```
   *
   * @param consumables Object describing which parts of the element should be consumed.
   * @param consumables.name If set to `true` element's name will be consumed.
   * @param consumables.attributes Attribute name or array of attribute names to consume.
   * @param consumables.classes Class name or array of class names to consume.
   * @param consumables.styles Style name or array of style names to consume.
   */
  consume(e) {
    e.name && (this._canConsumeName = !1);
    for (const t of Yi)
      t in e && this._consume(t, e[t]);
  }
  /**
   * Revert already consumed parts of {@link module:engine/view/element~Element view Element}, so they can be consumed once again.
   * Element's name can be reverted:
   *
   * ```ts
   * consumables.revert( { name: true } );
   * ```
   *
   * Attributes classes and styles:
   *
   * ```ts
   * consumables.revert( { attributes: 'title', classes: 'foo', styles: 'color' } );
   * consumables.revert( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );
   * ```
   *
   * @param consumables Object describing which parts of the element should be reverted.
   * @param consumables.name If set to `true` element's name will be reverted.
   * @param consumables.attributes Attribute name or array of attribute names to revert.
   * @param consumables.classes Class name or array of class names to revert.
   * @param consumables.styles Style name or array of style names to revert.
   */
  revert(e) {
    e.name && (this._canConsumeName = !0);
    for (const t of Yi)
      t in e && this._revert(t, e[t]);
  }
  /**
   * Helper method that adds consumables of a given type: attribute, class or style.
   *
   * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`
   * type is provided - it should be handled separately by providing actual style/class type.
   *
   * @param type Type of the consumable item: `attributes`, `classes` or `styles`.
   * @param item Consumable item or array of items.
   */
  _add(e, t) {
    const i = he(t) ? t : [t], s = this._consumables[e];
    for (const r of i) {
      if (e === "attributes" && (r === "class" || r === "style"))
        throw new d("viewconsumable-invalid-attribute", this);
      if (s.set(r, !0), e === "styles")
        for (const o of this.element.document.stylesProcessor.getRelatedStyles(r))
          s.set(o, !0);
    }
  }
  /**
   * Helper method that tests consumables of a given type: attribute, class or style.
   *
   * @param type Type of the consumable item: `attributes`, `classes` or `styles`.
   * @param item Consumable item or array of items.
   * @returns Returns `true` if all items can be consumed, `null` when one of the items cannot be
   * consumed and `false` when one of the items is already consumed.
   */
  _test(e, t) {
    const i = he(t) ? t : [t], s = this._consumables[e];
    for (const r of i)
      if (e === "attributes" && (r === "class" || r === "style")) {
        const o = r == "class" ? "classes" : "styles", a = this._test(o, [...this._consumables[o].keys()]);
        if (a !== !0)
          return a;
      } else {
        const o = s.get(r);
        if (o === void 0)
          return null;
        if (!o)
          return !1;
      }
    return !0;
  }
  /**
   * Helper method that consumes items of a given type: attribute, class or style.
   *
   * @param type Type of the consumable item: `attributes`, `classes` or `styles`.
   * @param item Consumable item or array of items.
   */
  _consume(e, t) {
    const i = he(t) ? t : [t], s = this._consumables[e];
    for (const r of i)
      if (e === "attributes" && (r === "class" || r === "style")) {
        const o = r == "class" ? "classes" : "styles";
        this._consume(o, [...this._consumables[o].keys()]);
      } else if (s.set(r, !1), e == "styles")
        for (const o of this.element.document.stylesProcessor.getRelatedStyles(r))
          s.set(o, !1);
  }
  /**
   * Helper method that reverts items of a given type: attribute, class or style.
   *
   * @param type Type of the consumable item: `attributes`, `classes` or , `styles`.
   * @param item Consumable item or array of items.
   */
  _revert(e, t) {
    const i = he(t) ? t : [t], s = this._consumables[e];
    for (const r of i)
      if (e === "attributes" && (r === "class" || r === "style")) {
        const o = r == "class" ? "classes" : "styles";
        this._revert(o, [...this._consumables[o].keys()]);
      } else
        s.get(r) === !1 && s.set(r, !0);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class my extends z() {
  /**
   * Creates a schema instance.
   */
  constructor() {
    super(), this._sourceDefinitions = {}, this._attributeProperties = {}, this.decorate("checkChild"), this.decorate("checkAttribute"), this.on("checkAttribute", (e, t) => {
      t[0] = new Tt(t[0]);
    }, { priority: "highest" }), this.on("checkChild", (e, t) => {
      t[0] = new Tt(t[0]), t[1] = this.getDefinition(t[1]);
    }, { priority: "highest" });
  }
  /**
   * Registers a schema item. Can only be called once for every item name.
   *
   * ```ts
   * schema.register( 'paragraph', {
   * 	inheritAllFrom: '$block'
   * } );
   * ```
   */
  register(e, t) {
    if (this._sourceDefinitions[e])
      throw new d("schema-cannot-register-item-twice", this, {
        itemName: e
      });
    this._sourceDefinitions[e] = [
      Object.assign({}, t)
    ], this._clearCache();
  }
  /**
   * Extends a {@link #register registered} item's definition.
   *
   * Extending properties such as `allowIn` will add more items to the existing properties,
   * while redefining properties such as `isBlock` will override the previously defined ones.
   *
   * ```ts
   * schema.register( 'foo', {
   * 	allowIn: '$root',
   * 	isBlock: true;
   * } );
   * schema.extend( 'foo', {
   * 	allowIn: 'blockQuote',
   * 	isBlock: false
   * } );
   *
   * schema.getDefinition( 'foo' );
   * //	{
   * //		allowIn: [ '$root', 'blockQuote' ],
   * // 		isBlock: false
   * //	}
   * ```
   */
  extend(e, t) {
    if (!this._sourceDefinitions[e])
      throw new d("schema-cannot-extend-missing-item", this, {
        itemName: e
      });
    this._sourceDefinitions[e].push(Object.assign({}, t)), this._clearCache();
  }
  /**
   * Returns data of all registered items.
   *
   * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,
   * checking a list of all block elements, etc).
   * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})
   * in other cases.
   */
  getDefinitions() {
    return this._compiledDefinitions || this._compile(), this._compiledDefinitions;
  }
  /**
   * Returns a definition of the given item or `undefined` if an item is not registered.
   *
   * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,
   * checking a list of all block elements, etc).
   * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})
   * in other cases.
   */
  getDefinition(e) {
    let t;
    return typeof e == "string" ? t = e : "is" in e && (e.is("$text") || e.is("$textProxy")) ? t = "$text" : t = e.name, this.getDefinitions()[t];
  }
  /**
   * Returns `true` if the given item is registered in the schema.
   *
   * ```ts
   * schema.isRegistered( 'paragraph' ); // -> true
   * schema.isRegistered( editor.model.document.getRoot() ); // -> true
   * schema.isRegistered( 'foo' ); // -> false
   * ```
   */
  isRegistered(e) {
    return !!this.getDefinition(e);
  }
  /**
   * Returns `true` if the given item is defined to be
   * a block by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isBlock` property.
   *
   * ```ts
   * schema.isBlock( 'paragraph' ); // -> true
   * schema.isBlock( '$root' ); // -> false
   *
   * const paragraphElement = writer.createElement( 'paragraph' );
   * schema.isBlock( paragraphElement ); // -> true
   * ```
   *
   * See the {@glink framework/deep-dive/schema#block-elements Block elements} section of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isBlock(e) {
    const t = this.getDefinition(e);
    return !!(t && t.isBlock);
  }
  /**
   * Returns `true` if the given item should be treated as a limit element.
   *
   * It considers an item to be a limit element if its
   * {@link module:engine/model/schema~SchemaItemDefinition}'s
   * {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} or
   * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property
   * was set to `true`.
   *
   * ```ts
   * schema.isLimit( 'paragraph' ); // -> false
   * schema.isLimit( '$root' ); // -> true
   * schema.isLimit( editor.model.document.getRoot() ); // -> true
   * schema.isLimit( 'imageBlock' ); // -> true
   * ```
   *
   * See the {@glink framework/deep-dive/schema#limit-elements Limit elements} section of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isLimit(e) {
    const t = this.getDefinition(e);
    return t ? !!(t.isLimit || t.isObject) : !1;
  }
  /**
   * Returns `true` if the given item should be treated as an object element.
   *
   * It considers an item to be an object element if its
   * {@link module:engine/model/schema~SchemaItemDefinition}'s
   * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property
   * was set to `true`.
   *
   * ```ts
   * schema.isObject( 'paragraph' ); // -> false
   * schema.isObject( 'imageBlock' ); // -> true
   *
   * const imageElement = writer.createElement( 'imageBlock' );
   * schema.isObject( imageElement ); // -> true
   * ```
   *
   * See the {@glink framework/deep-dive/schema#object-elements Object elements} section of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isObject(e) {
    const t = this.getDefinition(e);
    return t ? !!(t.isObject || t.isLimit && t.isSelectable && t.isContent) : !1;
  }
  /**
   * Returns `true` if the given item is defined to be
   * an inline element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isInline` property.
   *
   * ```ts
   * schema.isInline( 'paragraph' ); // -> false
   * schema.isInline( 'softBreak' ); // -> true
   *
   * const text = writer.createText( 'foo' );
   * schema.isInline( text ); // -> true
   * ```
   *
   * See the {@glink framework/deep-dive/schema#inline-elements Inline elements} section of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isInline(e) {
    const t = this.getDefinition(e);
    return !!(t && t.isInline);
  }
  /**
   * Returns `true` if the given item is defined to be
   * a selectable element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isSelectable` property.
   *
   * ```ts
   * schema.isSelectable( 'paragraph' ); // -> false
   * schema.isSelectable( 'heading1' ); // -> false
   * schema.isSelectable( 'imageBlock' ); // -> true
   * schema.isSelectable( 'tableCell' ); // -> true
   *
   * const text = writer.createText( 'foo' );
   * schema.isSelectable( text ); // -> false
   * ```
   *
   * See the {@glink framework/deep-dive/schema#selectable-elements Selectable elements section} of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isSelectable(e) {
    const t = this.getDefinition(e);
    return t ? !!(t.isSelectable || t.isObject) : !1;
  }
  /**
   * Returns `true` if the given item is defined to be
   * a content by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isContent` property.
   *
   * ```ts
   * schema.isContent( 'paragraph' ); // -> false
   * schema.isContent( 'heading1' ); // -> false
   * schema.isContent( 'imageBlock' ); // -> true
   * schema.isContent( 'horizontalLine' ); // -> true
   *
   * const text = writer.createText( 'foo' );
   * schema.isContent( text ); // -> true
   * ```
   *
   * See the {@glink framework/deep-dive/schema#content-elements Content elements section} of
   * the {@glink framework/deep-dive/schema Schema deep-dive} guide for more details.
   */
  isContent(e) {
    const t = this.getDefinition(e);
    return t ? !!(t.isContent || t.isObject) : !1;
  }
  /**
   * Checks whether the given node (`child`) can be a child of the given context.
   *
   * ```ts
   * schema.checkChild( model.document.getRoot(), paragraph ); // -> false
   *
   * schema.register( 'paragraph', {
   * 	allowIn: '$root'
   * } );
   * schema.checkChild( model.document.getRoot(), paragraph ); // -> true
   * ```
   *
   * Note: When verifying whether the given node can be a child of the given context, the
   * schema also verifies the entire context &mdash; from its root to its last element. Therefore, it is possible
   * for `checkChild()` to return `false` even though the context's last element can contain the checked child.
   * It happens if one of the context's elements does not allow its child.
   *
   * @fires checkChild
   * @param context The context in which the child will be checked.
   * @param def The child to check.
   */
  checkChild(e, t) {
    return t ? this._checkContextMatch(t, e) : !1;
  }
  /**
   * Checks whether the given attribute can be applied in the given context (on the last
   * item of the context).
   *
   * ```ts
   * schema.checkAttribute( textNode, 'bold' ); // -> false
   *
   * schema.extend( '$text', {
   * 	allowAttributes: 'bold'
   * } );
   * schema.checkAttribute( textNode, 'bold' ); // -> true
   * ```
   *
   * @fires checkAttribute
   * @param context The context in which the attribute will be checked.
   */
  checkAttribute(e, t) {
    const i = this.getDefinition(e.last);
    return i ? i.allowAttributes.includes(t) : !1;
  }
  /**
   * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).
   *
   * In other words &mdash; whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.
   *
   * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}
   * will be valid.
   *
   * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the
   * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.
   *
   * @param positionOrBaseElement The position or base element to which the `elementToMerge` will be merged.
   * @param elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.
   */
  checkMerge(e, t) {
    if (e instanceof w) {
      const i = e.nodeBefore, s = e.nodeAfter;
      if (!(i instanceof B))
        throw new d("schema-check-merge-no-element-before", this);
      if (!(s instanceof B))
        throw new d("schema-check-merge-no-element-after", this);
      return this.checkMerge(i, s);
    }
    for (const i of t.getChildren())
      if (!this.checkChild(e, i))
        return !1;
    return !0;
  }
  /**
   * Allows registering a callback to the {@link #checkChild} method calls.
   *
   * Callbacks allow you to implement rules which are not otherwise possible to achieve
   * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.
   * For example, by using this method you can disallow elements in specific contexts.
   *
   * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,
   * you can use that event instead.
   *
   * Example:
   *
   * ```ts
   * // Disallow heading1 directly inside a blockQuote.
   * schema.addChildCheck( ( context, childDefinition ) => {
   * 	if ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {
   * 		return false;
   * 	}
   * } );
   * ```
   *
   * Which translates to:
   *
   * ```ts
   * schema.on( 'checkChild', ( evt, args ) => {
   * 	const context = args[ 0 ];
   * 	const childDefinition = args[ 1 ];
   *
   * 	if ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {
   * 		// Prevent next listeners from being called.
   * 		evt.stop();
   * 		// Set the checkChild()'s return value.
   * 		evt.return = false;
   * 	}
   * }, { priority: 'high' } );
   * ```
   *
   * @param callback The callback to be called. It is called with two parameters:
   * {@link module:engine/model/schema~SchemaContext} (context) instance and
   * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).
   * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return
   * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.
   */
  addChildCheck(e) {
    this.on("checkChild", (t, [i, s]) => {
      if (!s)
        return;
      const r = e(i, s);
      typeof r == "boolean" && (t.stop(), t.return = r);
    }, { priority: "high" });
  }
  /**
   * Allows registering a callback to the {@link #checkAttribute} method calls.
   *
   * Callbacks allow you to implement rules which are not otherwise possible to achieve
   * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.
   * For example, by using this method you can disallow attribute if node to which it is applied
   * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).
   *
   * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,
   * you can use that event instead.
   *
   * Example:
   *
   * ```ts
   * // Disallow bold on $text inside heading1.
   * schema.addAttributeCheck( ( context, attributeName ) => {
   * 	if ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {
   * 		return false;
   * 	}
   * } );
   * ```
   *
   * Which translates to:
   *
   * ```ts
   * schema.on( 'checkAttribute', ( evt, args ) => {
   * 	const context = args[ 0 ];
   * 	const attributeName = args[ 1 ];
   *
   * 	if ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {
   * 		// Prevent next listeners from being called.
   * 		evt.stop();
   * 		// Set the checkAttribute()'s return value.
   * 		evt.return = false;
   * 	}
   * }, { priority: 'high' } );
   * ```
   *
   * @param callback The callback to be called. It is called with two parameters:
   * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.
   * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return
   * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.
   */
  addAttributeCheck(e) {
    this.on("checkAttribute", (t, [i, s]) => {
      const r = e(i, s);
      typeof r == "boolean" && (t.stop(), t.return = r);
    }, { priority: "high" });
  }
  /**
   * This method allows assigning additional metadata to the model attributes. For example,
   * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is
   * used to mark formatting attributes (like `bold` or `italic`).
   *
   * ```ts
   * // Mark bold as a formatting attribute.
   * schema.setAttributeProperties( 'bold', {
   * 	isFormatting: true
   * } );
   *
   * // Override code not to be considered a formatting markup.
   * schema.setAttributeProperties( 'code', {
   * 	isFormatting: false
   * } );
   * ```
   *
   * Properties are not limited to members defined in the
   * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:
   *
   * ```ts
   * schema.setAttributeProperties( 'blockQuote', {
   * 	customProperty: 'value'
   * } );
   * ```
   *
   * Subsequent calls with the same attribute will extend its custom properties:
   *
   * ```ts
   * schema.setAttributeProperties( 'blockQuote', {
   * 	one: 1
   * } );
   *
   * schema.setAttributeProperties( 'blockQuote', {
   * 	two: 2
   * } );
   *
   * console.log( schema.getAttributeProperties( 'blockQuote' ) );
   * // Logs: { one: 1, two: 2 }
   * ```
   *
   * @param attributeName A name of the attribute to receive the properties.
   * @param properties A dictionary of properties.
   */
  setAttributeProperties(e, t) {
    this._attributeProperties[e] = Object.assign(this.getAttributeProperties(e), t);
  }
  /**
   * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.
   *
   * @param attributeName A name of the attribute.
   */
  getAttributeProperties(e) {
    return this._attributeProperties[e] || {};
  }
  /**
   * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire
   * selection/range/position or the root otherwise.
   *
   * @param selectionOrRangeOrPosition The selection/range/position to check.
   * @returns The lowest limit element containing the entire `selectionOrRangeOrPosition`.
   */
  getLimitElement(e) {
    let t;
    for (e instanceof w ? t = e.parent : t = (e instanceof g ? [e] : Array.from(e.getRanges())).reduce((s, r) => {
      const o = r.getCommonAncestor();
      return s ? s.getCommonAncestor(o, { includeSelf: !0 }) : o;
    }, null); !this.isLimit(t) && t.parent; )
      t = t.parent;
    return t;
  }
  /**
   * Checks whether the attribute is allowed in selection:
   *
   * * if the selection is not collapsed, then checks if the attribute is allowed on any of nodes in that range,
   * * if the selection is collapsed, then checks if on the selection position there's a text with the
   * specified attribute allowed.
   *
   * @param selection Selection which will be checked.
   * @param attribute The name of the attribute to check.
   */
  checkAttributeInSelection(e, t) {
    if (e.isCollapsed) {
      const s = [
        ...e.getFirstPosition().getAncestors(),
        new U("", e.getAttributes())
      ];
      return this.checkAttribute(s, t);
    } else {
      const i = e.getRanges();
      for (const s of i)
        for (const r of s)
          if (this.checkAttribute(r.item, t))
            return !0;
    }
    return !1;
  }
  /**
   * Transforms the given set of ranges into a set of ranges where the given attribute is allowed (and can be applied).
   *
   * @param ranges Ranges to be validated.
   * @param attribute The name of the attribute to check.
   * @returns Ranges in which the attribute is allowed.
   */
  *getValidRanges(e, t) {
    e = Iy(e);
    for (const i of e)
      yield* this._getValidRangesForRange(i, t);
  }
  /**
   * Basing on given `position`, finds and returns a {@link module:engine/model/range~Range range} which is
   * nearest to that `position` and is a correct range for selection.
   *
   * The correct selection range might be collapsed when it is located in a position where the text node can be placed.
   * Non-collapsed range is returned when selection can be placed around element marked as an "object" in
   * the {@link module:engine/model/schema~Schema schema}.
   *
   * Direction of searching for the nearest correct selection range can be specified as:
   *
   * * `both` - searching will be performed in both ways,
   * * `forward` - searching will be performed only forward,
   * * `backward` - searching will be performed only backward.
   *
   * When valid selection range cannot be found, `null` is returned.
   *
   * @param position Reference position where new selection range should be looked for.
   * @param direction Search direction.
   * @returns Nearest selection range or `null` if one cannot be found.
   */
  getNearestSelectionRange(e, t = "both") {
    if (this.checkChild(e, "$text"))
      return new g(e);
    let i, s;
    const r = e.getAncestors().reverse().find((o) => this.isLimit(o)) || e.root;
    (t == "both" || t == "backward") && (i = new at({
      boundaries: g._createIn(r),
      startPosition: e,
      direction: "backward"
    })), (t == "both" || t == "forward") && (s = new at({
      boundaries: g._createIn(r),
      startPosition: e
    }));
    for (const o of Sy(i, s)) {
      const a = o.walker == i ? "elementEnd" : "elementStart", l = o.value;
      if (l.type == a && this.isObject(l.item))
        return g._createOn(l.item);
      if (this.checkChild(l.nextPosition, "$text"))
        return new g(l.nextPosition);
    }
    return null;
  }
  /**
   * Tries to find position ancestors that allow to insert a given node.
   * It starts searching from the given position and goes node by node to the top of the model tree
   * as long as a {@link module:engine/model/schema~Schema#isLimit limit element}, an
   * {@link module:engine/model/schema~Schema#isObject object element} or a topmost ancestor is not reached.
   *
   * @param position The position that the search will start from.
   * @param node The node for which an allowed parent should be found or its name.
   * @returns Allowed parent or null if nothing was found.
   */
  findAllowedParent(e, t) {
    let i = e.parent;
    for (; i; ) {
      if (this.checkChild(i, t))
        return i;
      if (this.isLimit(i))
        return null;
      i = i.parent;
    }
    return null;
  }
  /**
   * Sets attributes allowed by the schema on a given node.
   *
   * @param node A node to set attributes on.
   * @param attributes Attributes keys and values.
   * @param writer An instance of the model writer.
   */
  setAllowedAttributes(e, t, i) {
    const s = i.model;
    for (const [r, o] of Object.entries(t))
      s.schema.checkAttribute(e, r) && i.setAttribute(r, o, e);
  }
  /**
   * Removes attributes disallowed by the schema.
   *
   * @param nodes Nodes that will be filtered.
   */
  removeDisallowedAttributes(e, t) {
    for (const i of e)
      if (i.is("$text"))
        Ma(this, i, t);
      else {
        const r = g._createIn(i).getPositions();
        for (const o of r) {
          const a = o.nodeBefore || o.parent;
          Ma(this, a, t);
        }
      }
  }
  /**
   * Gets attributes of a node that have a given property.
   *
   * @param node Node to get attributes from.
   * @param propertyName Name of the property that attribute must have to return it.
   * @param propertyValue Desired value of the property that we want to check.
   * When `undefined` attributes will be returned if they have set a given property no matter what the value is. If specified it will
   * return attributes which given property's value is equal to this parameter.
   * @returns Object with attributes' names as key and attributes' values as value.
   */
  getAttributesWithProperty(e, t, i) {
    const s = {};
    for (const [r, o] of e.getAttributes()) {
      const a = this.getAttributeProperties(r);
      a[t] !== void 0 && (i === void 0 || i === a[t]) && (s[r] = o);
    }
    return s;
  }
  /**
   * Creates an instance of the schema context.
   */
  createContext(e) {
    return new Tt(e);
  }
  _clearCache() {
    this._compiledDefinitions = null;
  }
  _compile() {
    const e = {}, t = this._sourceDefinitions, i = Object.keys(t);
    for (const s of i)
      e[s] = gy(t[s], s);
    for (const s of i)
      py(e, s);
    for (const s of i)
      wy(e, s);
    for (const s of i)
      by(e, s);
    for (const s of i)
      _y(e, s), vy(e, s);
    for (const s of i)
      yy(e, s), ky(e, s), Cy(e, s);
    this._compiledDefinitions = e;
  }
  _checkContextMatch(e, t, i = t.length - 1) {
    const s = t.getItem(i);
    if (e.allowIn.includes(s.name)) {
      if (i == 0)
        return !0;
      {
        const r = this.getDefinition(s);
        return this._checkContextMatch(r, t, i - 1);
      }
    } else
      return !1;
  }
  /**
   * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges
   * inside the given range on which the attribute can be applied.
   *
   * This is a helper function for {@link ~Schema#getValidRanges}.
   *
   * @param range The range to process.
   * @param attribute The name of the attribute to check.
   * @returns Ranges in which the attribute is allowed.
   */
  *_getValidRangesForRange(e, t) {
    let i = e.start, s = e.start;
    for (const r of e.getItems({ shallow: !0 }))
      r.is("element") && (yield* this._getValidRangesForRange(g._createIn(r), t)), this.checkAttribute(r, t) || (i.isEqual(s) || (yield new g(i, s)), i = w._createAfter(r)), s = w._createAfter(r);
    i.isEqual(s) || (yield new g(i, s));
  }
}
class Tt {
  /**
   * Creates an instance of the context.
   */
  constructor(e) {
    if (e instanceof Tt)
      return e;
    let t;
    typeof e == "string" ? t = [e] : Array.isArray(e) ? t = e : t = e.getAncestors({ includeSelf: !0 }), this._items = t.map(xy);
  }
  /**
   * The number of items.
   */
  get length() {
    return this._items.length;
  }
  /**
   * The last item (the lowest node).
   */
  get last() {
    return this._items[this._items.length - 1];
  }
  /**
   * Iterable interface.
   *
   * Iterates over all context items.
   */
  [Symbol.iterator]() {
    return this._items[Symbol.iterator]();
  }
  /**
   * Returns a new schema context instance with an additional item.
   *
   * Item can be added as:
   *
   * ```ts
   * const context = new SchemaContext( [ '$root' ] );
   *
   * // An element.
   * const fooElement = writer.createElement( 'fooElement' );
   * const newContext = context.push( fooElement ); // [ '$root', 'fooElement' ]
   *
   * // A text node.
   * const text = writer.createText( 'foobar' );
   * const newContext = context.push( text ); // [ '$root', '$text' ]
   *
   * // A string (element name).
   * const newContext = context.push( 'barElement' ); // [ '$root', 'barElement' ]
   * ```
   *
   * **Note** {@link module:engine/model/node~Node} that is already in the model tree will be added as the only item
   * (without ancestors).
   *
   * @param item An item that will be added to the current context.
   * @returns A new schema context instance with an additional item.
   */
  push(e) {
    const t = new Tt([e]);
    return t._items = [...this._items, ...t._items], t;
  }
  /**
   * Gets an item on the given index.
   */
  getItem(e) {
    return this._items[e];
  }
  /**
   * Returns the names of items.
   */
  *getNames() {
    yield* this._items.map((e) => e.name);
  }
  /**
   * Checks whether the context ends with the given nodes.
   *
   * ```ts
   * const ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );
   *
   * ctx.endsWith( '$text' ); // -> true
   * ctx.endsWith( 'paragraph $text' ); // -> true
   * ctx.endsWith( '$root' ); // -> false
   * ctx.endsWith( 'paragraph' ); // -> false
   * ```
   */
  endsWith(e) {
    return Array.from(this.getNames()).join(" ").endsWith(e);
  }
  /**
   * Checks whether the context starts with the given nodes.
   *
   * ```ts
   * const ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );
   *
   * ctx.endsWith( '$root' ); // -> true
   * ctx.endsWith( '$root paragraph' ); // -> true
   * ctx.endsWith( '$text' ); // -> false
   * ctx.endsWith( 'paragraph' ); // -> false
   * ```
   */
  startsWith(e) {
    return Array.from(this.getNames()).join(" ").startsWith(e);
  }
}
function gy(n, e) {
  const t = {
    name: e,
    allowIn: [],
    allowContentOf: [],
    allowWhere: [],
    allowAttributes: [],
    allowAttributesOf: [],
    allowChildren: [],
    inheritTypesFrom: []
  };
  return Ey(n, t), _t(n, t, "allowIn"), _t(n, t, "allowContentOf"), _t(n, t, "allowWhere"), _t(n, t, "allowAttributes"), _t(n, t, "allowAttributesOf"), _t(n, t, "allowChildren"), _t(n, t, "inheritTypesFrom"), Ay(n, t), t;
}
function py(n, e) {
  const t = n[e];
  for (const i of t.allowChildren) {
    const s = n[i];
    s && s.allowIn.push(e);
  }
  t.allowChildren.length = 0;
}
function wy(n, e) {
  for (const t of n[e].allowContentOf)
    n[t] && Ty(n, t).forEach((s) => {
      s.allowIn.push(e);
    });
  delete n[e].allowContentOf;
}
function by(n, e) {
  for (const t of n[e].allowWhere) {
    const i = n[t];
    if (i) {
      const s = i.allowIn;
      n[e].allowIn.push(...s);
    }
  }
  delete n[e].allowWhere;
}
function _y(n, e) {
  for (const t of n[e].allowAttributesOf) {
    const i = n[t];
    if (i) {
      const s = i.allowAttributes;
      n[e].allowAttributes.push(...s);
    }
  }
  delete n[e].allowAttributesOf;
}
function vy(n, e) {
  const t = n[e];
  for (const i of t.inheritTypesFrom) {
    const s = n[i];
    if (s) {
      const r = Object.keys(s).filter((o) => o.startsWith("is"));
      for (const o of r)
        o in t || (t[o] = s[o]);
    }
  }
  delete t.inheritTypesFrom;
}
function yy(n, e) {
  const t = n[e], i = t.allowIn.filter((s) => n[s]);
  t.allowIn = Array.from(new Set(i));
}
function ky(n, e) {
  const t = n[e];
  for (const i of t.allowIn)
    n[i].allowChildren.push(e);
}
function Cy(n, e) {
  const t = n[e];
  t.allowAttributes = Array.from(new Set(t.allowAttributes));
}
function Ey(n, e) {
  for (const t of n) {
    const i = Object.keys(t).filter((s) => s.startsWith("is"));
    for (const s of i)
      e[s] = !!t[s];
  }
}
function _t(n, e, t) {
  for (const i of n) {
    const s = i[t];
    typeof s == "string" ? e[t].push(s) : Array.isArray(s) && e[t].push(...s);
  }
}
function Ay(n, e) {
  for (const t of n) {
    const i = t.inheritAllFrom;
    i && (e.allowContentOf.push(i), e.allowWhere.push(i), e.allowAttributesOf.push(i), e.inheritTypesFrom.push(i));
  }
}
function Ty(n, e) {
  const t = n[e];
  return Py(n).filter((i) => i.allowIn.includes(t.name));
}
function Py(n) {
  return Object.keys(n).map((e) => n[e]);
}
function xy(n) {
  return typeof n == "string" || n.is("documentFragment") ? {
    name: typeof n == "string" ? n : "$documentFragment",
    *getAttributeKeys() {
    },
    getAttribute() {
    }
  } : {
    // '$text' means text nodes and text proxies.
    name: n.is("element") ? n.name : "$text",
    *getAttributeKeys() {
      yield* n.getAttributeKeys();
    },
    getAttribute(e) {
      return n.getAttribute(e);
    }
  };
}
function* Sy(n, e) {
  let t = !1;
  for (; !t; ) {
    if (t = !0, n) {
      const i = n.next();
      i.done || (t = !1, yield {
        walker: n,
        value: i.value
      });
    }
    if (e) {
      const i = e.next();
      i.done || (t = !1, yield {
        walker: e,
        value: i.value
      });
    }
  }
}
function* Iy(n) {
  for (const e of n)
    yield* e.getMinimalFlatRanges();
}
function Ma(n, e, t) {
  for (const i of e.getAttributeKeys())
    n.checkAttribute(e, i) || t.removeAttribute(i, e);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ry extends N() {
  /**
   * Creates an upcast dispatcher that operates using the passed API.
   *
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi
   * @param conversionApi Additional properties for an interface that will be passed to events fired
   * by the upcast dispatcher.
   */
  constructor(e) {
    super(), this._splitParts = /* @__PURE__ */ new Map(), this._cursorParents = /* @__PURE__ */ new Map(), this._modelCursor = null, this._emptyElementsToKeep = /* @__PURE__ */ new Set(), this.conversionApi = {
      ...e,
      consumable: null,
      writer: null,
      store: null,
      convertItem: (t, i) => this._convertItem(t, i),
      convertChildren: (t, i) => this._convertChildren(t, i),
      safeInsert: (t, i) => this._safeInsert(t, i),
      updateConversionResult: (t, i) => this._updateConversionResult(t, i),
      // Advanced API - use only if custom position handling is needed.
      splitToAllowedParent: (t, i) => this._splitToAllowedParent(t, i),
      getSplitParts: (t) => this._getSplitParts(t),
      keepEmptyElement: (t) => this._keepEmptyElement(t)
    };
  }
  /**
   * Starts the conversion process. The entry point for the conversion.
   *
   * @fires element
   * @fires text
   * @fires documentFragment
   * @param viewElement The part of the view to be converted.
   * @param writer An instance of the model writer.
   * @param context Elements will be converted according to this context.
   * @returns Model data that is the result of the conversion process
   * wrapped in `DocumentFragment`. Converted marker elements will be set as the document fragment's
   * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.
   */
  convert(e, t, i = ["$root"]) {
    this.fire("viewCleanup", e), this._modelCursor = My(i, t), this.conversionApi.writer = t, this.conversionApi.consumable = Ai.createFrom(e), this.conversionApi.store = {};
    const { modelRange: s } = this._convertItem(e, this._modelCursor), r = t.createDocumentFragment();
    if (s) {
      this._removeEmptyElements();
      for (const o of Array.from(this._modelCursor.parent.getChildren()))
        t.append(o, r);
      r.markers = Oy(r, t);
    }
    return this._modelCursor = null, this._splitParts.clear(), this._cursorParents.clear(), this._emptyElementsToKeep.clear(), this.conversionApi.writer = null, this.conversionApi.store = null, r;
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertItem
   */
  _convertItem(e, t) {
    const i = { viewItem: e, modelCursor: t, modelRange: null };
    if (e.is("element") ? this.fire(`element:${e.name}`, i, this.conversionApi) : e.is("$text") ? this.fire("text", i, this.conversionApi) : this.fire("documentFragment", i, this.conversionApi), i.modelRange && !(i.modelRange instanceof g))
      throw new d("view-conversion-dispatcher-incorrect-result", this);
    return { modelRange: i.modelRange, modelCursor: i.modelCursor };
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertChildren
   */
  _convertChildren(e, t) {
    let i = t.is("position") ? t : w._createAt(t, 0);
    const s = new g(i);
    for (const r of Array.from(e.getChildren())) {
      const o = this._convertItem(r, i);
      o.modelRange instanceof g && (s.end = o.modelRange.end, i = o.modelCursor);
    }
    return { modelRange: s, modelCursor: i };
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#safeInsert
   */
  _safeInsert(e, t) {
    const i = this._splitToAllowedParent(e, t);
    return i ? (this.conversionApi.writer.insert(e, i.position), !0) : !1;
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#updateConversionResult
   */
  _updateConversionResult(e, t) {
    const i = this._getSplitParts(e), s = this.conversionApi.writer;
    t.modelRange || (t.modelRange = s.createRange(s.createPositionBefore(e), s.createPositionAfter(i[i.length - 1])));
    const r = this._cursorParents.get(e);
    r ? t.modelCursor = s.createPositionAt(r, 0) : t.modelCursor = t.modelRange.end;
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#splitToAllowedParent
   */
  _splitToAllowedParent(e, t) {
    const { schema: i, writer: s } = this.conversionApi;
    let r = i.findAllowedParent(t, e);
    if (r) {
      if (r === t.parent)
        return { position: t };
      this._modelCursor.parent.getAncestors().includes(r) && (r = null);
    }
    if (!r)
      return oh(t, e, i) ? {
        position: ah(t, s)
      } : null;
    const o = this.conversionApi.writer.split(t, r), a = [];
    for (const c of o.range.getWalker())
      if (c.type == "elementEnd")
        a.push(c.item);
      else {
        const u = a.pop(), h = c.item;
        this._registerSplitPair(u, h);
      }
    const l = o.range.end.parent;
    return this._cursorParents.set(e, l), {
      position: o.position,
      cursorParent: l
    };
  }
  /**
   * Registers that a `splitPart` element is a split part of the `originalPart` element.
   *
   * The data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.
   */
  _registerSplitPair(e, t) {
    this._splitParts.has(e) || this._splitParts.set(e, [e]);
    const i = this._splitParts.get(e);
    this._splitParts.set(t, i), i.push(t);
  }
  /**
   * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#getSplitParts
   */
  _getSplitParts(e) {
    let t;
    return this._splitParts.has(e) ? t = this._splitParts.get(e) : t = [e], t;
  }
  /**
   * Mark an element that were created during the splitting to not get removed on conversion end even if it is empty.
   */
  _keepEmptyElement(e) {
    this._emptyElementsToKeep.add(e);
  }
  /**
   * Checks if there are any empty elements created while splitting and removes them.
   *
   * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,
   * as some elements might have become empty after other empty elements were removed from them.
   */
  _removeEmptyElements() {
    let e = !1;
    for (const t of this._splitParts.keys())
      t.isEmpty && !this._emptyElementsToKeep.has(t) && (this.conversionApi.writer.remove(t), this._splitParts.delete(t), e = !0);
    e && this._removeEmptyElements();
  }
}
function Oy(n, e) {
  const t = /* @__PURE__ */ new Set(), i = /* @__PURE__ */ new Map(), s = g._createIn(n).getItems();
  for (const r of s)
    r.is("element", "$marker") && t.add(r);
  for (const r of t) {
    const o = r.getAttribute("data-name"), a = e.createPositionBefore(r);
    i.has(o) ? i.get(o).end = a.clone() : i.set(o, new g(a.clone())), e.remove(r);
  }
  return i;
}
function My(n, e) {
  let t;
  for (const i of new Tt(n)) {
    const s = {};
    for (const o of i.getAttributeKeys())
      s[o] = i.getAttribute(o);
    const r = e.createElement(i.name, s);
    t && e.insert(r, t), t = w._createAt(r, 0);
  }
  return t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Vy {
  /**
   * Returns an HTML string created from the document fragment.
   */
  getHtml(e) {
    const i = document.implementation.createHTMLDocument("").createElement("div");
    return i.appendChild(e), i.innerHTML;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Dy {
  /**
   * Creates a new instance of the HTML data processor class.
   *
   * @param document The view document instance.
   */
  constructor(e) {
    this.skipComments = !0, this.domParser = new DOMParser(), this.domConverter = new zu(e, { renderingMode: "data" }), this.htmlWriter = new Vy();
  }
  /**
   * Converts a provided {@link module:engine/view/documentfragment~DocumentFragment document fragment}
   * to data format &mdash; in this case to an HTML string.
   *
   * @returns HTML string.
   */
  toData(e) {
    const t = this.domConverter.viewToDom(e);
    return this.htmlWriter.getHtml(t);
  }
  /**
   * Converts the provided HTML string to a view tree.
   *
   * @param data An HTML string.
   * @returns A converted view element.
   */
  toView(e) {
    const t = this._toDom(e);
    return this.domConverter.domToView(t, { skipComments: this.skipComments });
  }
  /**
   * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data
   * and not processed during the conversion from the DOM to the view elements.
   *
   * The raw data can be later accessed by a
   * {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `"$rawContent"`.
   *
   * @param pattern Pattern matching all view elements whose content should be treated as raw data.
   */
  registerRawContentMatcher(e) {
    this.domConverter.registerRawContentMatcher(e);
  }
  /**
   * If the processor is set to use marked fillers, it will insert `&nbsp;` fillers wrapped in `<span>` elements
   * (`<span data-cke-filler="true">&nbsp;</span>`) instead of regular `&nbsp;` characters.
   *
   * This mode allows for a more precise handling of the block fillers (so they do not leak into the editor content) but
   * bloats the editor data with additional markup.
   *
   * This mode may be required by some features and will be turned on by them automatically.
   *
   * @param type Whether to use the default or the marked `&nbsp;` block fillers.
   */
  useFillerType(e) {
    this.domConverter.blockFillerMode = e == "marked" ? "markedNbsp" : "nbsp";
  }
  /**
   * Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from
   * the provided data.
   */
  _toDom(e) {
    e.match(/<(?:html|body|head|meta)(?:\s[^>]*)?>/i) || (e = `<body>${e}</body>`);
    const t = this.domParser.parseFromString(e, "text/html"), i = t.createDocumentFragment(), s = t.body.childNodes;
    for (; s.length > 0; )
      i.appendChild(s[0]);
    return i;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class By extends N() {
  /**
   * Creates a data controller instance.
   *
   * @param model Data model.
   * @param stylesProcessor The styles processor instance.
   */
  constructor(e, t) {
    super(), this.model = e, this.mapper = new Gu(), this.downcastDispatcher = new Ku({
      mapper: this.mapper,
      schema: e.schema
    }), this.downcastDispatcher.on("insert:$text", Yu(), { priority: "lowest" }), this.downcastDispatcher.on("insert", Xu(), { priority: "lowest" }), this.upcastDispatcher = new Ry({
      schema: e.schema
    }), this.viewDocument = new Vu(t), this.stylesProcessor = t, this.htmlProcessor = new Dy(this.viewDocument), this.processor = this.htmlProcessor, this._viewWriter = new Bu(this.viewDocument), this.upcastDispatcher.on("text", Gv(), { priority: "lowest" }), this.upcastDispatcher.on("element", Sa(), { priority: "lowest" }), this.upcastDispatcher.on("documentFragment", Sa(), { priority: "lowest" }), z().prototype.decorate.call(this, "init"), z().prototype.decorate.call(this, "set"), z().prototype.decorate.call(this, "get"), z().prototype.decorate.call(this, "toView"), z().prototype.decorate.call(this, "toModel"), this.on("init", () => {
      this.fire("ready");
    }, { priority: "lowest" }), this.on("ready", () => {
      this.model.enqueueChange({ isUndoable: !1 }, rh);
    }, { priority: "lowest" });
  }
  /**
   * Returns the model's data converted by downcast dispatchers attached to {@link #downcastDispatcher} and
   * formatted by the {@link #processor data processor}.
   *
   * A warning is logged when you try to retrieve data for a detached root, as most probably this is a mistake. A detached root should
   * be treated like it is removed, and you should not save its data. Note, that the detached root data is always an empty string.
   *
   * @fires get
   * @param options Additional configuration for the retrieved data. `DataController` provides two optional
   * properties: `rootName` and `trim`. Other properties of this object are specified by various editor features.
   * @param options.rootName Root name. Default 'main'.
   * @param options.trim Whether returned data should be trimmed. This option is set to `empty` by default,
   * which means whenever editor content is considered empty, an empty string will be returned. To turn off trimming completely
   * use `'none'`. In such cases the exact content will be returned (for example a `<p>&nbsp;</p>` for an empty editor).
   * @returns Output data.
   */
  get(e = {}) {
    const { rootName: t = "main", trim: i = "empty" } = e;
    if (!this._checkIfRootsExists([t]))
      throw new d("datacontroller-get-non-existent-root", this);
    const s = this.model.document.getRoot(t);
    return s.isAttached() || q("datacontroller-get-detached-root", this), i === "empty" && !this.model.hasContent(s, { ignoreWhitespaces: !0 }) ? "" : this.stringify(s, e);
  }
  /**
   * Returns the content of the given {@link module:engine/model/element~Element model's element} or
   * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast converters
   * attached to the {@link #downcastDispatcher} and formatted by the {@link #processor data processor}.
   *
   * @param modelElementOrFragment The element whose content will be stringified.
   * @param options Additional configuration passed to the conversion process.
   * @returns Output data.
   */
  stringify(e, t = {}) {
    const i = this.toView(e, t);
    return this.processor.toData(i);
  }
  /**
   * Returns the content of the given {@link module:engine/model/element~Element model element} or
   * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast
   * converters attached to {@link #downcastDispatcher} into a
   * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.
   *
   * @fires toView
   * @param modelElementOrFragment Element or document fragment whose content will be converted.
   * @param options Additional configuration that will be available through the
   * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi#options} during the conversion process.
   * @returns Output view DocumentFragment.
   */
  toView(e, t = {}) {
    const i = this.viewDocument, s = this._viewWriter;
    this.mapper.clearBindings();
    const r = g._createIn(e), o = new At(i);
    this.mapper.bindElements(e, o);
    const a = e.is("documentFragment") ? e.markers : Fy(e);
    return this.downcastDispatcher.convert(r, a, s, t), o;
  }
  /**
   * Sets the initial input data parsed by the {@link #processor data processor} and
   * converted by the {@link #upcastDispatcher view-to-model converters}.
   * Initial data can be only set to a document whose {@link module:engine/model/document~Document#version} is equal 0.
   *
   * **Note** This method is {@link module:utils/observablemixin~Observable#decorate decorated} which is
   * used by e.g. collaborative editing plugin that syncs remote data on init.
   *
   * When data is passed as a string, it is initialized on the default `main` root:
   *
   * ```ts
   * dataController.init( '<p>Foo</p>' ); // Initializes data on the `main` root only, as no other is specified.
   * ```
   *
   * To initialize data on a different root or multiple roots at once, an object containing `rootName` - `data` pairs should be passed:
   *
   * ```ts
   * dataController.init( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Initializes data on both the `main` and `title` roots.
   * ```
   *
   * @fires init
   * @param data Input data as a string or an object containing the `rootName` - `data`
   * pairs to initialize data on multiple roots at once.
   * @returns Promise that is resolved after the data is set on the editor.
   */
  init(e) {
    if (this.model.document.version)
      throw new d("datacontroller-init-document-not-empty", this);
    let t = {};
    if (typeof e == "string" ? t.main = e : t = e, !this._checkIfRootsExists(Object.keys(t)))
      throw new d("datacontroller-init-non-existent-root", this);
    return this.model.enqueueChange({ isUndoable: !1 }, (i) => {
      for (const s of Object.keys(t)) {
        const r = this.model.document.getRoot(s);
        i.insert(this.parse(t[s], r), r, 0);
      }
    }), Promise.resolve();
  }
  /**
   * Sets the input data parsed by the {@link #processor data processor} and
   * converted by the {@link #upcastDispatcher view-to-model converters}.
   * This method can be used any time to replace existing editor data with the new one without clearing the
   * {@link module:engine/model/document~Document#history document history}.
   *
   * This method also creates a batch with all the changes applied. If all you need is to parse data, use
   * the {@link #parse} method.
   *
   * When data is passed as a string it is set on the default `main` root:
   *
   * ```ts
   * dataController.set( '<p>Foo</p>' ); // Sets data on the `main` root, as no other is specified.
   * ```
   *
   * To set data on a different root or multiple roots at once, an object containing `rootName` - `data` pairs should be passed:
   *
   * ```ts
   * dataController.set( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Sets data on the `main` and `title` roots as specified.
   * ```
   *
   * To set the data with a preserved undo stack and add the change to the undo stack, set `{ isUndoable: true }` as a `batchType` option.
   *
   * ```ts
   * dataController.set( '<p>Foo</p>', { batchType: { isUndoable: true } } );
   * ```
   *
   * @fires set
   * @param data Input data as a string or an object containing the `rootName` - `data`
   * pairs to set data on multiple roots at once.
   * @param options Options for setting data.
   * @param options.batchType The batch type that will be used to create a batch for the changes applied by this method.
   * By default, the batch will be set as {@link module:engine/model/batch~Batch#isUndoable not undoable} and the undo stack will be
   * cleared after the new data is applied (all undo steps will be removed). If the batch type `isUndoable` flag is be set to `true`,
   * the undo stack will be preserved instead and not cleared when new data is applied.
   */
  set(e, t = {}) {
    let i = {};
    if (typeof e == "string" ? i.main = e : i = e, !this._checkIfRootsExists(Object.keys(i)))
      throw new d("datacontroller-set-non-existent-root", this);
    this.model.enqueueChange(t.batchType || {}, (s) => {
      s.setSelection(null), s.removeSelectionAttribute(this.model.document.selection.getAttributeKeys());
      for (const r of Object.keys(i)) {
        const o = this.model.document.getRoot(r);
        s.remove(s.createRangeIn(o)), s.insert(this.parse(i[r], o), o, 0);
      }
    });
  }
  /**
   * Returns the data parsed by the {@link #processor data processor} and then converted by upcast converters
   * attached to the {@link #upcastDispatcher}.
   *
   * @see #set
   * @param data Data to parse.
   * @param context Base context in which the view will be converted to the model.
   * See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.
   * @returns Parsed data.
   */
  parse(e, t = "$root") {
    const i = this.processor.toView(e);
    return this.toModel(i, t);
  }
  /**
   * Returns the result of the given {@link module:engine/view/element~Element view element} or
   * {@link module:engine/view/documentfragment~DocumentFragment view document fragment} converted by the
   * {@link #upcastDispatcher view-to-model converters}, wrapped by {@link module:engine/model/documentfragment~DocumentFragment}.
   *
   * When marker elements were converted during the conversion process, it will be set as a document fragment's
   * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.
   *
   * @fires toModel
   * @param viewElementOrFragment The element or document fragment whose content will be converted.
   * @param context Base context in which the view will be converted to the model.
   * See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.
   * @returns Output document fragment.
   */
  toModel(e, t = "$root") {
    return this.model.change((i) => this.upcastDispatcher.convert(e, i, t));
  }
  /**
   * Adds the style processor normalization rules.
   *
   * You can implement your own rules as well as use one of the available processor rules:
   *
   * * background: {@link module:engine/view/styles/background~addBackgroundRules}
   * * border: {@link module:engine/view/styles/border~addBorderRules}
   * * margin: {@link module:engine/view/styles/margin~addMarginRules}
   * * padding: {@link module:engine/view/styles/padding~addPaddingRules}
   */
  addStyleProcessorRules(e) {
    e(this.stylesProcessor);
  }
  /**
   * Registers a {@link module:engine/view/matcher~MatcherPattern} on an {@link #htmlProcessor htmlProcessor}
   * and a {@link #processor processor} for view elements whose content should be treated as raw data
   * and not processed during the conversion from DOM to view elements.
   *
   * The raw data can be later accessed by the {@link module:engine/view/element~Element#getCustomProperty view element custom property}
   * `"$rawContent"`.
   *
   * @param pattern Pattern matching all view elements whose content should be treated as a raw data.
   */
  registerRawContentMatcher(e) {
    this.processor && this.processor !== this.htmlProcessor && this.processor.registerRawContentMatcher(e), this.htmlProcessor.registerRawContentMatcher(e);
  }
  /**
   * Removes all event listeners set by the DataController.
   */
  destroy() {
    this.stopListening();
  }
  /**
   * Checks whether all provided root names are actually existing editor roots.
   *
   * @param rootNames Root names to check.
   * @returns Whether all provided root names are existing editor roots.
   */
  _checkIfRootsExists(e) {
    for (const t of e)
      if (!this.model.document.getRoot(t))
        return !1;
    return !0;
  }
}
function Fy(n) {
  const e = [], t = n.root.document;
  if (!t)
    return /* @__PURE__ */ new Map();
  const i = g._createIn(n);
  for (const s of t.model.markers) {
    const r = s.getRange(), o = r.isCollapsed, a = r.start.isEqual(i.start) || r.end.isEqual(i.end);
    if (o && a)
      e.push([s.name, r]);
    else {
      const l = i.getIntersection(r);
      l && e.push([s.name, l]);
    }
  }
  return e.sort(([s, r], [o, a]) => {
    if (r.end.compareWith(a.start) !== "after")
      return 1;
    if (r.start.compareWith(a.end) !== "before")
      return -1;
    switch (r.start.compareWith(a.start)) {
      case "before":
        return 1;
      case "after":
        return -1;
      default:
        switch (r.end.compareWith(a.end)) {
          case "before":
            return 1;
          case "after":
            return -1;
          default:
            return o.localeCompare(s);
        }
    }
  }), new Map(e);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ny {
  /**
   * Creates a new conversion instance.
   */
  constructor(e, t) {
    this._helpers = /* @__PURE__ */ new Map(), this._downcast = X(e), this._createConversionHelpers({ name: "downcast", dispatchers: this._downcast, isDowncast: !0 }), this._upcast = X(t), this._createConversionHelpers({ name: "upcast", dispatchers: this._upcast, isDowncast: !1 });
  }
  /**
   * Define an alias for registered dispatcher.
   *
   * ```ts
   * const conversion = new Conversion(
   * 	[ dataDowncastDispatcher, editingDowncastDispatcher ],
   * 	upcastDispatcher
   * );
   *
   * conversion.addAlias( 'dataDowncast', dataDowncastDispatcher );
   * ```
   *
   * @param alias An alias of a dispatcher.
   * @param dispatcher Dispatcher which should have an alias.
   */
  addAlias(e, t) {
    const i = this._downcast.includes(t);
    if (!this._upcast.includes(t) && !i)
      throw new d("conversion-add-alias-dispatcher-not-registered", this);
    this._createConversionHelpers({ name: e, dispatchers: [t], isDowncast: i });
  }
  /**
   * Provides a chainable API to assign converters to a conversion dispatchers group.
   *
   * If the given group name has not been registered, the
   * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.
   *
   * You can use conversion helpers available directly in the `for()` chain or your custom ones via
   * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method.
   *
   * # Using built-in conversion helpers
   *
   * The `for()` chain comes with a set of conversion helpers which you can use like this:
   *
   * ```ts
   * editor.conversion.for( 'downcast' )
   * 	.elementToElement( config1 )        // Adds an element-to-element downcast converter.
   * 	.attributeToElement( config2 );     // Adds an attribute-to-element downcast converter.
   *
   * editor.conversion.for( 'upcast' )
   * 	.elementToAttribute( config3 );     // Adds an element-to-attribute upcast converter.
   * ```
   *
   * Refer to the documentation of built-in conversion helpers to learn about their configuration options.
   *
   * * downcast (model-to-view) conversion helpers:
   *
   *	* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`},
   *	* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement `attributeToElement()`},
   *	* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute `attributeToAttribute()`}.
   *	* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement `markerToElement()`}.
   *	* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight `markerToHighlight()`}.
   *
   * * upcast (view-to-model) conversion helpers:
   *
   *	* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `elementToElement()`},
   *	* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute `elementToAttribute()`},
   *	* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute `attributeToAttribute()`}.
   *	* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `elementToMarker()`}.
   *
   * # Using custom conversion helpers
   *
   * If you need to implement an atypical converter, you can do so by calling:
   *
   * ```ts
   * editor.conversion.for( direction ).add( customHelper );
   * ```
   *
   * The `.add()` method takes exactly one parameter, which is a function. This function should accept one parameter that
   * is a dispatcher instance. The function should add an actual converter to the passed dispatcher instance.
   *
   * Example:
   *
   * ```ts
   * editor.conversion.for( 'upcast' ).add( dispatcher => {
   * 	dispatcher.on( 'element:a',  ( evt, data, conversionApi ) => {
   * 		// Do something with a view <a> element.
   * 	} );
   * } );
   * ```
   *
   * Refer to the documentation of {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}
   * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} to learn how to write
   * custom converters.
   *
   * @param groupName The name of dispatchers group to add the converters to.
   */
  for(e) {
    if (!this._helpers.has(e))
      throw new d("conversion-for-unknown-group", this);
    return this._helpers.get(e);
  }
  /**
   * Sets up converters between the model and the view that convert a model element to a view element (and vice versa).
   * For example, the model `<paragraph>Foo</paragraph>` is turned into `<p>Foo</p>` in the view.
   *
   * ```ts
   * // A simple conversion from the `paragraph` model element to the `<p>` view element (and vice versa).
   * editor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );
   *
   * // Override other converters by specifying a converter definition with a higher priority.
   * editor.conversion.elementToElement( { model: 'paragraph', view: 'div', converterPriority: 'high' } );
   *
   * // View specified as an object instead of a string.
   * editor.conversion.elementToElement( {
   * 	model: 'fancyParagraph',
   * 	view: {
   * 		name: 'p',
   * 		classes: 'fancy'
   * 	}
   * } );
   *
   * // Use `upcastAlso` to define other view elements that should also be converted to a `paragraph` element.
   * editor.conversion.elementToElement( {
   * 	model: 'paragraph',
   * 	view: 'p',
   * 	upcastAlso: [
   * 		'div',
   * 		{
   * 			// Any element with the `display: block` style.
   * 			styles: {
   * 				display: 'block'
   * 			}
   * 		}
   * 	]
   * } );
   *
   * // `upcastAlso` set as callback enables a conversion of a wide range of different view elements.
   * editor.conversion.elementToElement( {
   * 	model: 'heading',
   * 	view: 'h2',
   * 	// Convert "heading-like" paragraphs to headings.
   * 	upcastAlso: viewElement => {
   * 		const fontSize = viewElement.getStyle( 'font-size' );
   *
   * 		if ( !fontSize ) {
   * 			return null;
   * 		}
   *
   * 		const match = fontSize.match( /(\d+)\s*px/ );
   *
   * 		if ( !match ) {
   * 			return null;
   * 		}
   *
   * 		const size = Number( match[ 1 ] );
   *
   * 		if ( size > 26 ) {
   * 			// Returned value can be an object with the matched properties.
   * 			// These properties will be "consumed" during the conversion.
   * 			// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.
   *
   * 			return { name: true, styles: [ 'font-size' ] };
   * 		}
   *
   * 		return null;
   * 	}
   * } );
   * ```
   *
   * `definition.model` is a `String` with a model element name to convert from or to.
   *
   * @param definition The converter definition.
   */
  elementToElement(e) {
    this.for("downcast").elementToElement(e);
    for (const { model: t, view: i } of ss(e))
      this.for("upcast").elementToElement({
        model: t,
        view: i,
        converterPriority: e.converterPriority
      });
  }
  /**
   * Sets up converters between the model and the view that convert a model attribute to a view element (and vice versa).
   * For example, a model text node with `"Foo"` as data and the `bold` attribute will be turned to `<strong>Foo</strong>` in the view.
   *
   * ```ts
   * // A simple conversion from the `bold=true` attribute to the `<strong>` view element (and vice versa).
   * editor.conversion.attributeToElement( { model: 'bold', view: 'strong' } );
   *
   * // Override other converters by specifying a converter definition with a higher priority.
   * editor.conversion.attributeToElement( { model: 'bold', view: 'b', converterPriority: 'high' } );
   *
   * // View specified as an object instead of a string.
   * editor.conversion.attributeToElement( {
   * 	model: 'bold',
   * 	view: {
   * 		name: 'span',
   * 		classes: 'bold'
   * 	}
   * } );
   *
   * // Use `config.model.name` to define the conversion only from a given node type, `$text` in this case.
   * // The same attribute on different elements may then be handled by a different converter.
   * editor.conversion.attributeToElement( {
   * 	model: {
   * 		key: 'textDecoration',
   * 		values: [ 'underline', 'lineThrough' ],
   * 		name: '$text'
   * 	},
   * 	view: {
   * 		underline: {
   * 			name: 'span',
   * 			styles: {
   * 				'text-decoration': 'underline'
   * 			}
   * 		},
   * 		lineThrough: {
   * 			name: 'span',
   * 			styles: {
   * 				'text-decoration': 'line-through'
   * 			}
   * 		}
   * 	}
   * } );
   *
   * // Use `upcastAlso` to define other view elements that should also be converted to the `bold` attribute.
   * editor.conversion.attributeToElement( {
   * 	model: 'bold',
   * 	view: 'strong',
   * 	upcastAlso: [
   * 		'b',
   * 		{
   * 			name: 'span',
   * 			classes: 'bold'
   * 		},
   * 		{
   * 			name: 'span',
   * 			styles: {
   * 				'font-weight': 'bold'
   * 			}
   * 		},
   * 		viewElement => {
   * 			const fontWeight = viewElement.getStyle( 'font-weight' );
   *
   * 			if ( viewElement.is( 'element', 'span' ) && fontWeight && /\d+/.test() && Number( fontWeight ) > 500 ) {
   * 				// Returned value can be an object with the matched properties.
   * 				// These properties will be "consumed" during the conversion.
   * 				// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.
   *
   * 				return {
   * 					name: true,
   * 					styles: [ 'font-weight' ]
   * 				};
   * 			}
   * 		}
   * 	]
   * } );
   *
   * // Conversion from and to a model attribute key whose value is an enum (`fontSize=big|small`).
   * // `upcastAlso` set as callback enables a conversion of a wide range of different view elements.
   * editor.conversion.attributeToElement( {
   * 	model: {
   * 		key: 'fontSize',
   * 		values: [ 'big', 'small' ]
   * 	},
   * 	view: {
   * 		big: {
   * 			name: 'span',
   * 			styles: {
   * 				'font-size': '1.2em'
   * 			}
   * 		},
   * 		small: {
   * 			name: 'span',
   * 			styles: {
   * 				'font-size': '0.8em'
   * 			}
   * 		}
   * 	},
   * 	upcastAlso: {
   * 		big: viewElement => {
   * 			const fontSize = viewElement.getStyle( 'font-size' );
   *
   * 			if ( !fontSize ) {
   * 				return null;
   * 			}
   *
   * 			const match = fontSize.match( /(\d+)\s*px/ );
   *
   * 			if ( !match ) {
   * 				return null;
   * 			}
   *
   * 			const size = Number( match[ 1 ] );
   *
   * 			if ( viewElement.is( 'element', 'span' ) && size > 10 ) {
   * 				// Returned value can be an object with the matched properties.
   * 				// These properties will be "consumed" during the conversion.
   * 				// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.
   *
   * 				return { name: true, styles: [ 'font-size' ] };
   * 			}
   *
   * 			return null;
   * 		},
   * 		small: viewElement => {
   * 			const fontSize = viewElement.getStyle( 'font-size' );
   *
   * 			if ( !fontSize ) {
   * 				return null;
   * 			}
   *
   * 			const match = fontSize.match( /(\d+)\s*px/ );
   *
   * 			if ( !match ) {
   * 				return null;
   * 			}
   *
   * 			const size = Number( match[ 1 ] );
   *
   * 			if ( viewElement.is( 'element', 'span' ) && size < 10 ) {
   * 				// Returned value can be an object with the matched properties.
   * 				// These properties will be "consumed" during the conversion.
   * 				// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.
   *
   * 				return { name: true, styles: [ 'font-size' ] };
   * 			}
   *
   * 			return null;
   * 		}
   * 	}
   * } );
   * ```
   *
   * The `definition.model` parameter specifies which model attribute should be converted from or to. It can be a `{ key, value }` object
   * describing the attribute key and value to convert or a `String` specifying just the attribute key (in such a case
   * `value` is set to `true`).
   *
   * @param definition The converter definition.
   */
  attributeToElement(e) {
    this.for("downcast").attributeToElement(e);
    for (const { model: t, view: i } of ss(e))
      this.for("upcast").elementToAttribute({
        view: i,
        model: t,
        converterPriority: e.converterPriority
      });
  }
  /**
   * Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa). For example,
   * `<imageBlock src='foo.jpg'></imageBlock>` is converted to `<img src='foo.jpg'></img>` (the same attribute key and value).
   * This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.
   * To convert the text attributes,
   * the {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}should be set up.
   *
   * ```ts
   * // A simple conversion from the `source` model attribute to the `src` view attribute (and vice versa).
   * editor.conversion.attributeToAttribute( { model: 'source', view: 'src' } );
   *
   * // Attribute values are strictly specified.
   * editor.conversion.attributeToAttribute( {
   * 	model: {
   * 		name: 'imageInline',
   * 		key: 'aside',
   * 		values: [ 'aside' ]
   * 	},
   * 	view: {
   * 		aside: {
   * 			name: 'img',
   * 			key: 'class',
   * 			value: [ 'aside', 'half-size' ]
   * 		}
   * 	}
   * } );
   *
   * // Set the style attribute.
   * editor.conversion.attributeToAttribute( {
   * 	model: {
   * 		name: 'imageInline',
   * 		key: 'aside',
   * 		values: [ 'aside' ]
   * 	},
   * 	view: {
   * 		aside: {
   * 			name: 'img',
   * 			key: 'style',
   * 			value: {
   * 				float: 'right',
   * 				width: '50%',
   * 				margin: '5px'
   * 			}
   * 		}
   * 	}
   * } );
   *
   * // Conversion from and to a model attribute key whose value is an enum (`align=right|center`).
   * // Use `upcastAlso` to define other view elements that should also be converted to the `align=right` attribute.
   * editor.conversion.attributeToAttribute( {
   * 	model: {
   * 		key: 'align',
   * 		values: [ 'right', 'center' ]
   * 	},
   * 	view: {
   * 		right: {
   * 			key: 'class',
   * 			value: 'align-right'
   * 		},
   * 		center: {
   * 			key: 'class',
   * 			value: 'align-center'
   * 		}
   * 	},
   * 	upcastAlso: {
   * 		right: {
   * 			styles: {
   * 				'text-align': 'right'
   * 			}
   * 		},
   * 		center: {
   * 			styles: {
   * 				'text-align': 'center'
   * 			}
   * 		}
   * 	}
   * } );
   * ```
   *
   * The `definition.model` parameter specifies which model attribute should be converted from and to.
   * It can be a `{ key, [ values ], [ name ] }` object or a `String`, which will be treated like `{ key: definition.model }`.
   * The `key` property is the model attribute key to convert from and to.
   * The `values` are the possible model attribute values. If the `values` parameter is not set, the model attribute value
   * will be the same as the view attribute value.
   * If `name` is set, the conversion will be set up only for model elements with the given name.
   *
   * The `definition.view` parameter specifies which view attribute should be converted from and to.
   * It can be a `{ key, value, [ name ] }` object or a `String`, which will be treated like `{ key: definition.view }`.
   * The `key` property is the view attribute key to convert from and to.
   * The `value` is the view attribute value to convert from and to. If `definition.value` is not set, the view attribute value will be
   * the same as the model attribute value.
   * If `key` is `'class'`, `value` can be a `String` or an array of `String`s.
   * If `key` is `'style'`, `value` is an object with key-value pairs.
   * In other cases, `value` is a `String`.
   * If `name` is set, the conversion will be set up only for model elements with the given name.
   * If `definition.model.values` is set, `definition.view` is an object that assigns values from `definition.model.values`
   * to `{ key, value, [ name ] }` objects.
   *
   * `definition.upcastAlso` specifies which other matching view elements should also be upcast to the given model configuration.
   * If `definition.model.values` is set, `definition.upcastAlso` should be an object assigning values from `definition.model.values`
   * to {@link module:engine/view/matcher~MatcherPattern}s or arrays of {@link module:engine/view/matcher~MatcherPattern}s.
   *
   * **Note:** `definition.model` and `definition.view` form should be mirrored, so the same types of parameters should
   * be given in both parameters.
   *
   * @param definition The converter definition.
   * @param definition.model The model attribute to convert from and to.
   * @param definition.view The view attribute to convert from and to.
   * @param definition.upcastAlso Any view element matching `definition.upcastAlso` will also be converted to the given model attribute.
   * `definition.upcastAlso` is used only if `config.model.values` is specified.
   */
  attributeToAttribute(e) {
    this.for("downcast").attributeToAttribute(e);
    for (const { model: t, view: i } of ss(e))
      this.for("upcast").attributeToAttribute({
        view: i,
        model: t
      });
  }
  /**
   * Creates and caches conversion helpers for given dispatchers group.
   *
   * @param options.name Group name.
   */
  _createConversionHelpers({ name: e, dispatchers: t, isDowncast: i }) {
    if (this._helpers.has(e))
      throw new d("conversion-group-exists", this);
    const s = i ? new mv(t) : new qv(t);
    this._helpers.set(e, s);
  }
}
function* ss(n) {
  if (n.model.values)
    for (const e of n.model.values) {
      const t = { key: n.model.key, value: e }, i = n.view[e], s = n.upcastAlso ? n.upcastAlso[e] : void 0;
      yield* Va(t, i, s);
    }
  else
    yield* Va(n.model, n.view, n.upcastAlso);
}
function* Va(n, e, t) {
  if (yield { model: n, view: e }, t)
    for (const i of X(t))
      yield { model: n, view: i };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ve {
  /**
   * Base operation constructor.
   *
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e) {
    this.baseVersion = e, this.isDocumentOperation = this.baseVersion !== null, this.batch = null;
  }
  /**
   * Checks whether the operation's parameters are correct and the operation can be correctly executed. Throws
   * an error if operation is not valid.
   *
   * @internal
   */
  _validate() {
  }
  /**
   * Custom toJSON method to solve child-parent circular dependencies.
   *
   * @returns Clone of this object with the operation property replaced with string.
   */
  toJSON() {
    const e = Object.assign({}, this);
    return e.__className = this.constructor.className, delete e.batch, delete e.isDocumentOperation, e;
  }
  /**
   * Name of the operation class used for serialization.
   */
  static get className() {
    return "Operation";
  }
  /**
   * Creates `Operation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param doc Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return new this(e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function zr(n, e) {
  const t = fh(e), i = t.reduce((o, a) => o + a.offsetSize, 0), s = n.parent;
  Bi(n);
  const r = n.index;
  return s._insertChild(r, t), Di(s, r + t.length), Di(s, r), new g(n, n.getShiftedBy(i));
}
function dh(n) {
  if (!n.isFlat)
    throw new d("operation-utils-remove-range-not-flat", this);
  const e = n.start.parent;
  Bi(n.start), Bi(n.end);
  const t = e._removeChildren(n.start.index, n.end.index - n.start.index);
  return Di(e, n.start.index), t;
}
function Vi(n, e) {
  if (!n.isFlat)
    throw new d("operation-utils-move-range-not-flat", this);
  const t = dh(n);
  return e = e._getTransformedByDeletion(n.start, n.end.offset - n.start.offset), zr(e, t);
}
function Ly(n, e, t) {
  Bi(n.start), Bi(n.end);
  for (const i of n.getItems({ shallow: !0 })) {
    const s = i.is("$textProxy") ? i.textNode : i;
    t !== null ? s._setAttribute(e, t) : s._removeAttribute(e), Di(s.parent, s.index);
  }
  Di(n.end.parent, n.end.index);
}
function fh(n) {
  const e = [];
  function t(i) {
    if (typeof i == "string")
      e.push(new U(i));
    else if (i instanceof xe)
      e.push(new U(i.data, i.getAttributes()));
    else if (i instanceof Bt)
      e.push(i);
    else if (_e(i))
      for (const s of i)
        t(s);
  }
  t(n);
  for (let i = 1; i < e.length; i++) {
    const s = e[i], r = e[i - 1];
    s instanceof U && r instanceof U && mh(s, r) && (e.splice(i - 1, 2, new U(r.data + s.data, r.getAttributes())), i--);
  }
  return e;
}
function Di(n, e) {
  const t = n.getChild(e - 1), i = n.getChild(e);
  if (t && i && t.is("$text") && i.is("$text") && mh(t, i)) {
    const s = new U(t.data + i.data, t.getAttributes());
    n._removeChildren(e - 1, 2), n._insertChild(e - 1, s);
  }
}
function Bi(n) {
  const e = n.textNode, t = n.parent;
  if (e) {
    const i = n.offset - e.startOffset, s = e.index;
    t._removeChildren(s, 1);
    const r = new U(e.data.substr(0, i), e.getAttributes()), o = new U(e.data.substr(i), e.getAttributes());
    t._insertChild(s, [r, o]);
  }
}
function mh(n, e) {
  const t = n.getAttributes(), i = e.getAttributes();
  for (const s of t) {
    if (s[1] !== e.getAttribute(s[0]))
      return !1;
    i.next();
  }
  return i.next().done;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class M extends ve {
  /**
   * Creates a move operation.
   *
   * @param sourcePosition Position before the first {@link module:engine/model/item~Item model item} to move.
   * @param howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at
   * `sourcePosition` with offset shifted by `howMany`.
   * @param targetPosition Position at which moved nodes will be inserted.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s) {
    super(s), this.sourcePosition = e.clone(), this.sourcePosition.stickiness = "toNext", this.howMany = t, this.targetPosition = i.clone(), this.targetPosition.stickiness = "toNone";
  }
  /**
   * @inheritDoc
   */
  get type() {
    return this.targetPosition.root.rootName == "$graveyard" ? "remove" : this.sourcePosition.root.rootName == "$graveyard" ? "reinsert" : "move";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return [
      g._createFromPositionAndShift(this.sourcePosition, this.howMany),
      g._createFromPositionAndShift(this.targetPosition, 0)
    ];
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    return new M(this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion);
  }
  /**
   * Returns the start position of the moved range after it got moved. This may be different than
   * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved
   * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}
   * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.
   *
   * ```
   *  vv              vv
   * abcdefg ===> adefbcg
   *      ^          ^
   *      targetPos  movedRangeStart
   *      offset 6   offset 4
   *```
   */
  getMovedRangeStart() {
    return this.targetPosition._getTransformedByDeletion(this.sourcePosition, this.howMany);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    const e = this.sourcePosition._getTransformedByInsertion(this.targetPosition, this.howMany);
    return new M(this.getMovedRangeStart(), this.howMany, e, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    const e = this.sourcePosition.parent, t = this.targetPosition.parent, i = this.sourcePosition.offset, s = this.targetPosition.offset;
    if (i + this.howMany > e.maxOffset)
      throw new d("move-operation-nodes-do-not-exist", this);
    if (e === t && i < s && s < i + this.howMany)
      throw new d("move-operation-range-into-itself", this);
    if (this.sourcePosition.root == this.targetPosition.root && ce(this.sourcePosition.getParentPath(), this.targetPosition.getParentPath()) == "prefix") {
      const r = this.sourcePosition.path.length - 1;
      if (this.targetPosition.path[r] >= i && this.targetPosition.path[r] < i + this.howMany)
        throw new d("move-operation-node-into-itself", this);
    }
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    Vi(g._createFromPositionAndShift(this.sourcePosition, this.howMany), this.targetPosition);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.sourcePosition = this.sourcePosition.toJSON(), e.targetPosition = this.targetPosition.toJSON(), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "MoveOperation";
  }
  /**
   * Creates `MoveOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    const i = w.fromJSON(e.sourcePosition, t), s = w.fromJSON(e.targetPosition, t);
    return new this(i, e.howMany, s, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class se extends ve {
  /**
   * Creates an insert operation.
   *
   * @param position Position of insertion.
   * @param nodes The list of nodes to be inserted.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i) {
    super(i), this.position = e.clone(), this.position.stickiness = "toNone", this.nodes = new Ci(fh(t)), this.shouldReceiveAttributes = !1;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "insert";
  }
  /**
   * Total offset size of inserted nodes.
   */
  get howMany() {
    return this.nodes.maxOffset;
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return this.position.clone();
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    const e = new Ci([...this.nodes].map((i) => i._clone(!0))), t = new se(this.position, e, this.baseVersion);
    return t.shouldReceiveAttributes = this.shouldReceiveAttributes, t;
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    const e = this.position.root.document.graveyard, t = new w(e, [0]);
    return new M(this.position, this.nodes.maxOffset, t, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    const e = this.position.parent;
    if (!e || e.maxOffset < this.position.offset)
      throw new d("insert-operation-position-invalid", this);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    const e = this.nodes;
    this.nodes = new Ci([...e].map((t) => t._clone(!0))), zr(this.position, e);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.position = this.position.toJSON(), e.nodes = this.nodes.toJSON(), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "InsertOperation";
  }
  /**
   * Creates `InsertOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    const i = [];
    for (const r of e.nodes)
      r.name ? i.push(B.fromJSON(r)) : i.push(U.fromJSON(r));
    const s = new se(w.fromJSON(e.position, t), i, e.baseVersion);
    return s.shouldReceiveAttributes = e.shouldReceiveAttributes, s;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class F extends ve {
  /**
   * Creates a split operation.
   *
   * @param splitPosition Position at which an element should be split.
   * @param howMany Total offset size of elements that are in the split element after `position`.
   * @param insertionPosition Position at which the clone of split element (or element from graveyard) will be inserted.
   * @param graveyardPosition Position in the graveyard root before the element which
   * should be used as a parent of the nodes after `position`. If it is not set, a copy of the the `position` parent will be used.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s, r) {
    super(r), this.splitPosition = e.clone(), this.splitPosition.stickiness = "toNext", this.howMany = t, this.insertionPosition = i, this.graveyardPosition = s ? s.clone() : null, this.graveyardPosition && (this.graveyardPosition.stickiness = "toNext");
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "split";
  }
  /**
   * Position inside the new clone of a split element.
   *
   * This is a position where nodes that are after the split position will be moved to.
   */
  get moveTargetPosition() {
    const e = this.insertionPosition.path.slice();
    return e.push(0), new w(this.insertionPosition.root, e);
  }
  /**
   * Artificial range that contains all the nodes from the split element that will be moved to the new element.
   * The range starts at {@link #splitPosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.
   */
  get movedRange() {
    const e = this.splitPosition.getShiftedBy(Number.POSITIVE_INFINITY);
    return new g(this.splitPosition, e);
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    const e = [
      g._createFromPositionAndShift(this.splitPosition, 0),
      g._createFromPositionAndShift(this.insertionPosition, 0)
    ];
    return this.graveyardPosition && e.push(g._createFromPositionAndShift(this.graveyardPosition, 0)), e;
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   *
   * @returns Clone of this operation.
   */
  clone() {
    return new F(this.splitPosition, this.howMany, this.insertionPosition, this.graveyardPosition, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    const e = this.splitPosition.root.document.graveyard, t = new w(e, [0]);
    return new Z(this.moveTargetPosition, this.howMany, this.splitPosition, t, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    const e = this.splitPosition.parent, t = this.splitPosition.offset;
    if (!e || e.maxOffset < t)
      throw new d("split-operation-position-invalid", this);
    if (e.parent) {
      if (this.howMany != e.maxOffset - this.splitPosition.offset)
        throw new d("split-operation-how-many-invalid", this);
      if (this.graveyardPosition && !this.graveyardPosition.nodeAfter)
        throw new d("split-operation-graveyard-position-invalid", this);
    } else
      throw new d("split-operation-split-in-root", this);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    const e = this.splitPosition.parent;
    if (this.graveyardPosition)
      Vi(g._createFromPositionAndShift(this.graveyardPosition, 1), this.insertionPosition);
    else {
      const i = e._clone();
      zr(this.insertionPosition, i);
    }
    const t = new g(w._createAt(e, this.splitPosition.offset), w._createAt(e, e.maxOffset));
    Vi(t, this.moveTargetPosition);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.splitPosition = this.splitPosition.toJSON(), e.insertionPosition = this.insertionPosition.toJSON(), this.graveyardPosition && (e.graveyardPosition = this.graveyardPosition.toJSON()), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "SplitOperation";
  }
  /**
   * Helper function that returns a default insertion position basing on given `splitPosition`. The default insertion
   * position is after the split element.
   */
  static getInsertionPosition(e) {
    const t = e.path.slice(0, -1);
    return t[t.length - 1]++, new w(e.root, t, "toPrevious");
  }
  /**
   * Creates `SplitOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    const i = w.fromJSON(e.splitPosition, t), s = w.fromJSON(e.insertionPosition, t), r = e.graveyardPosition ? w.fromJSON(e.graveyardPosition, t) : null;
    return new this(i, e.howMany, s, r, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Z extends ve {
  /**
   * Creates a merge operation.
   *
   * @param sourcePosition Position inside the merged element. All nodes from that
   * element after that position will be moved to {@link #targetPosition}.
   * @param howMany Summary offset size of nodes which will be moved from the merged element to the new parent.
   * @param targetPosition Position which the nodes from the merged elements will be moved to.
   * @param graveyardPosition Position in graveyard to which the merged element will be moved.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s, r) {
    super(r), this.sourcePosition = e.clone(), this.sourcePosition.stickiness = "toPrevious", this.howMany = t, this.targetPosition = i.clone(), this.targetPosition.stickiness = "toNext", this.graveyardPosition = s.clone();
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "merge";
  }
  /**
   * Position before the merged element (which will be deleted).
   */
  get deletionPosition() {
    return new w(this.sourcePosition.root, this.sourcePosition.path.slice(0, -1));
  }
  /**
   * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.
   * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.
   */
  get movedRange() {
    const e = this.sourcePosition.getShiftedBy(Number.POSITIVE_INFINITY);
    return new g(this.sourcePosition, e);
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    const e = this.sourcePosition.parent;
    return [
      g._createOn(e),
      // These could be positions but `Selectable` type only supports `Iterable<Range>`.
      g._createFromPositionAndShift(this.targetPosition, 0),
      g._createFromPositionAndShift(this.graveyardPosition, 0)
    ];
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    return new Z(this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    const e = this.targetPosition._getTransformedByMergeOperation(this), t = this.sourcePosition.path.slice(0, -1), i = new w(this.sourcePosition.root, t)._getTransformedByMergeOperation(this);
    return new F(e, this.howMany, i, this.graveyardPosition, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    const e = this.sourcePosition.parent, t = this.targetPosition.parent;
    if (e.parent)
      if (t.parent) {
        if (this.howMany != e.maxOffset)
          throw new d("merge-operation-how-many-invalid", this);
      } else
        throw new d("merge-operation-target-position-invalid", this);
    else
      throw new d("merge-operation-source-position-invalid", this);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    const e = this.sourcePosition.parent, t = g._createIn(e);
    Vi(t, this.targetPosition), Vi(g._createOn(e), this.graveyardPosition);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.sourcePosition = e.sourcePosition.toJSON(), e.targetPosition = e.targetPosition.toJSON(), e.graveyardPosition = e.graveyardPosition.toJSON(), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "MergeOperation";
  }
  /**
   * Creates `MergeOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    const i = w.fromJSON(e.sourcePosition, t), s = w.fromJSON(e.targetPosition, t), r = w.fromJSON(e.graveyardPosition, t);
    return new this(i, e.howMany, s, r, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class fe extends ve {
  /**
   * @param name Marker name.
   * @param oldRange Marker range before the change.
   * @param newRange Marker range after the change.
   * @param markers Marker collection on which change should be executed.
   * @param affectsData Specifies whether the marker operation affects the data produced by the data pipeline
   * (is persisted in the editor's data).
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s, r, o) {
    super(o), this.name = e, this.oldRange = t ? t.clone() : null, this.newRange = i ? i.clone() : null, this.affectsData = r, this._markers = s;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "marker";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    const e = [];
    return this.oldRange && e.push(this.oldRange.clone()), this.newRange && (this.oldRange ? e.push(...this.newRange.getDifference(this.oldRange)) : e.push(this.newRange.clone())), e;
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    return new fe(this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    return new fe(this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    this.newRange ? this._markers._set(this.name, this.newRange, !0, this.affectsData) : this._markers._remove(this.name);
  }
  /**
   * @inheritDoc
   * @internal
   */
  toJSON() {
    const e = super.toJSON();
    return this.oldRange && (e.oldRange = this.oldRange.toJSON()), this.newRange && (e.newRange = this.newRange.toJSON()), delete e._markers, e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "MarkerOperation";
  }
  /**
   * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return new fe(e.name, e.oldRange ? g.fromJSON(e.oldRange, t) : null, e.newRange ? g.fromJSON(e.newRange, t) : null, t.model.markers, e.affectsData, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Q extends ve {
  /**
   * Creates an operation that changes, removes or adds attributes.
   *
   * If only `newValue` is set, attribute will be added on a node. Note that all nodes in operation's range must not
   * have an attribute with the same key as the added attribute.
   *
   * If only `oldValue` is set, then attribute with given key will be removed. Note that all nodes in operation's range
   * must have an attribute with that key added.
   *
   * If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in
   * operation's ranges must already have an attribute with given key and `oldValue` as value
   *
   * @param range Range on which the operation should be applied. Must be a flat range.
   * @param key Key of an attribute to change or remove.
   * @param oldValue Old value of the attribute with given key or `null`, if attribute was not set before.
   * @param newValue New value of the attribute with given key or `null`, if operation should remove attribute.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s, r) {
    super(r), this.range = e.clone(), this.key = t, this.oldValue = i === void 0 ? null : i, this.newValue = s === void 0 ? null : s;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return this.oldValue === null ? "addAttribute" : this.newValue === null ? "removeAttribute" : "changeAttribute";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return this.range.clone();
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    return new Q(this.range, this.key, this.oldValue, this.newValue, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    return new Q(this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.range = this.range.toJSON(), e;
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    if (!this.range.isFlat)
      throw new d("attribute-operation-range-not-flat", this);
    for (const e of this.range.getItems({ shallow: !0 })) {
      if (this.oldValue !== null && !gn(e.getAttribute(this.key), this.oldValue))
        throw new d("attribute-operation-wrong-old-value", this, { item: e, key: this.key, value: this.oldValue });
      if (this.oldValue === null && this.newValue !== null && e.hasAttribute(this.key))
        throw new d("attribute-operation-attribute-exists", this, { node: e, key: this.key });
    }
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    gn(this.oldValue, this.newValue) || Ly(this.range, this.key, this.newValue);
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "AttributeOperation";
  }
  /**
   * Creates `AttributeOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return new Q(g.fromJSON(e.range, t), e.key, e.oldValue, e.newValue, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ie extends ve {
  get type() {
    return "noop";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return null;
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   */
  clone() {
    return new ie(this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    return new ie(this.baseVersion + 1);
  }
  /** @internal */
  _execute() {
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "NoOperation";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class me extends ve {
  /**
   * Creates an operation that changes element's name.
   *
   * @param position Position before an element to change.
   * @param oldName Current name of the element.
   * @param newName New name for the element.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s) {
    super(s), this.position = e, this.position.stickiness = "toNext", this.oldName = t, this.newName = i;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "rename";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return this.position.nodeAfter;
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   *
   * @returns Clone of this operation.
   */
  clone() {
    return new me(this.position.clone(), this.oldName, this.newName, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    return new me(this.position.clone(), this.newName, this.oldName, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    const e = this.position.nodeAfter;
    if (e instanceof B) {
      if (e.name !== this.oldName)
        throw new d("rename-operation-wrong-name", this);
    } else
      throw new d("rename-operation-wrong-position", this);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    const e = this.position.nodeAfter;
    e.name = this.newName;
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.position = this.position.toJSON(), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "RenameOperation";
  }
  /**
   * Creates `RenameOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return new me(w.fromJSON(e.position, t), e.oldName, e.newName, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ke extends ve {
  /**
   * Creates an operation that changes, removes or adds attributes on root element.
   *
   * @see module:engine/model/operation/attributeoperation~AttributeOperation
   * @param root Root element to change.
   * @param key Key of an attribute to change or remove.
   * @param oldValue Old value of the attribute with given key or `null`, if attribute was not set before.
   * @param newValue New value of the attribute with given key or `null`, if operation should remove attribute.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation
   * can be applied or `null` if the operation operates on detached (non-document) tree.
   */
  constructor(e, t, i, s, r) {
    super(r), this.root = e, this.key = t, this.oldValue = i === void 0 ? null : i, this.newValue = s === void 0 ? null : s;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return this.oldValue === null ? "addRootAttribute" : this.newValue === null ? "removeRootAttribute" : "changeRootAttribute";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return this.root;
  }
  /**
   * Creates and returns an operation that has the same parameters as this operation.
   *
   * @returns Clone of this operation.
   */
  clone() {
    return new Ke(this.root, this.key, this.oldValue, this.newValue, this.baseVersion);
  }
  /**
   * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.
   */
  getReversed() {
    return new Ke(this.root, this.key, this.newValue, this.oldValue, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    if (this.root != this.root.root || this.root.is("documentFragment"))
      throw new d("rootattribute-operation-not-a-root", this, { root: this.root, key: this.key });
    if (this.oldValue !== null && this.root.getAttribute(this.key) !== this.oldValue)
      throw new d("rootattribute-operation-wrong-old-value", this, { root: this.root, key: this.key });
    if (this.oldValue === null && this.newValue !== null && this.root.hasAttribute(this.key))
      throw new d("rootattribute-operation-attribute-exists", this, { root: this.root, key: this.key });
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    this.newValue !== null ? this.root._setAttribute(this.key, this.newValue) : this.root._removeAttribute(this.key);
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.root = this.root.toJSON(), e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "RootAttributeOperation";
  }
  /**
   * Creates `RootAttributeOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    if (!t.getRoot(e.root))
      throw new d("rootattribute-operation-fromjson-no-root", this, { rootName: e.root });
    return new Ke(t.getRoot(e.root), e.key, e.oldValue, e.newValue, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Le extends ve {
  /**
   * Creates an operation that creates or removes a root element.
   *
   * @param rootName Root name to create or detach.
   * @param elementName Root element name.
   * @param isAdd Specifies whether the operation adds (`true`) or detaches the root (`false`).
   * @param document Document which owns the root.
   * @param baseVersion Document {@link module:engine/model/document~Document#version} on which operation can be applied.
   */
  constructor(e, t, i, s, r) {
    if (super(r), this.rootName = e, this.elementName = t, this.isAdd = i, this._document = s, !this._document.getRoot(this.rootName)) {
      const o = this._document.createRoot(this.elementName, this.rootName);
      o._isAttached = !1;
    }
  }
  /**
   * @inheritDoc
   */
  get type() {
    return this.isAdd ? "addRoot" : "detachRoot";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return this._document.getRoot(this.rootName);
  }
  /**
   * @inheritDoc
   */
  clone() {
    return new Le(this.rootName, this.elementName, this.isAdd, this._document, this.baseVersion);
  }
  /**
   * @inheritDoc
   */
  getReversed() {
    return new Le(this.rootName, this.elementName, !this.isAdd, this._document, this.baseVersion + 1);
  }
  /**
   * @inheritDoc
   */
  _validate() {
    const e = this._document.getRoot(this.rootName);
    if (e.isAttached() && this.isAdd)
      throw new d("root-operation-root-attached", this);
    if (!e.isAttached() && !this.isAdd)
      throw new d("root-operation-root-detached", this);
  }
  /**
   * @inheritDoc
   */
  _execute() {
    this._document.getRoot(this.rootName)._isAttached = this.isAdd;
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return delete e._document, e;
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "RootOperation";
  }
  /**
   * Creates `RootOperation` object from deserialized object, i.e. from parsed JSON string.
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return new Le(e.rootName, e.elementName, e.isAdd, t, e.baseVersion);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Pe = {};
Pe[Q.className] = Q;
Pe[se.className] = se;
Pe[fe.className] = fe;
Pe[M.className] = M;
Pe[ie.className] = ie;
Pe[ve.className] = ve;
Pe[me.className] = me;
Pe[Ke.className] = Ke;
Pe[Le.className] = Le;
Pe[F.className] = F;
Pe[Z.className] = Z;
class $y {
  /**
   * Creates an operation instance from a JSON object (parsed JSON string).
   *
   * @param json Deserialized JSON object.
   * @param document Document on which this operation will be applied.
   */
  static fromJSON(e, t) {
    return Pe[e.__className].fromJSON(e, t);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Qs = /* @__PURE__ */ new Map();
function O(n, e, t) {
  let i = Qs.get(n);
  i || (i = /* @__PURE__ */ new Map(), Qs.set(n, i)), i.set(e, t);
}
function zy(n, e) {
  const t = Qs.get(n);
  return t && t.has(e) ? t.get(e) : Hy;
}
function Hy(n) {
  return [n];
}
function Da(n, e, t = {}) {
  const i = zy(n.constructor, e.constructor);
  try {
    return n = n.clone(), i(n, e, t);
  } catch (s) {
    throw s;
  }
}
function Wy(n, e, t) {
  n = n.slice(), e = e.slice();
  const i = new Uy(t.document, t.useRelations, t.forceWeakRemove);
  i.setOriginalOperations(n), i.setOriginalOperations(e);
  const s = i.originalOperations;
  if (n.length == 0 || e.length == 0)
    return { operationsA: n, operationsB: e, originalOperations: s };
  const r = /* @__PURE__ */ new WeakMap();
  for (const l of n)
    r.set(l, 0);
  const o = {
    nextBaseVersionA: n[n.length - 1].baseVersion + 1,
    nextBaseVersionB: e[e.length - 1].baseVersion + 1,
    originalOperationsACount: n.length,
    originalOperationsBCount: e.length
  };
  let a = 0;
  for (; a < n.length; ) {
    const l = n[a], c = r.get(l);
    if (c == e.length) {
      a++;
      continue;
    }
    const u = e[c], h = Da(l, u, i.getContext(l, u, !0)), f = Da(u, l, i.getContext(u, l, !1));
    i.updateRelation(l, u), i.setOriginalOperations(h, l), i.setOriginalOperations(f, u);
    for (const m of h)
      r.set(m, c + f.length);
    n.splice(a, 1, ...h), e.splice(c, 1, ...f);
  }
  if (t.padWithNoOps) {
    const l = n.length - o.originalOperationsACount, c = e.length - o.originalOperationsBCount;
    Fa(n, c - l), Fa(e, l - c);
  }
  return Ba(n, o.nextBaseVersionB), Ba(e, o.nextBaseVersionA), { operationsA: n, operationsB: e, originalOperations: s };
}
class Uy {
  /**
   * Creates `ContextFactory` instance.
   *
   * @param document Document which the operations change.
   * @param useRelations Whether during transformation relations should be used (used during undo for
   * better conflict resolution).
   * @param forceWeakRemove If set to `false`, remove operation will be always stronger than move operation,
   * so the removed nodes won't end up back in the document root. When set to `true`, context data will be used.
   */
  constructor(e, t, i = !1) {
    this.originalOperations = /* @__PURE__ */ new Map(), this._history = e.history, this._useRelations = t, this._forceWeakRemove = !!i, this._relations = /* @__PURE__ */ new Map();
  }
  /**
   * Sets "original operation" for given operations.
   *
   * During transformation process, operations are cloned, then changed, then processed again, sometimes broken into two
   * or multiple operations. When gathering additional data it is important that all operations can be somehow linked
   * so a cloned and transformed "version" still kept track of the data assigned earlier to it.
   *
   * The original operation object will be used as such an universal linking id. Throughout the transformation process
   * all cloned operations will refer to "the original operation" when storing and reading additional data.
   *
   * If `takeFrom` is not set, each operation from `operations` array will be assigned itself as "the original operation".
   * This should be used as an initialization step.
   *
   * If `takeFrom` is set, each operation from `operations` will be assigned the same original operation as assigned
   * for `takeFrom` operation. This should be used to update original operations. It should be used in a way that
   * `operations` are the result of `takeFrom` transformation to ensure proper "original operation propagation".
   */
  setOriginalOperations(e, t = null) {
    const i = t ? this.originalOperations.get(t) : null;
    for (const s of e)
      this.originalOperations.set(s, i || s);
  }
  /**
   * Saves a relation between operations `opA` and `opB`.
   *
   * Relations are then later used to help solve conflicts when operations are transformed.
   */
  updateRelation(e, t) {
    if (e instanceof M)
      t instanceof Z ? e.targetPosition.isEqual(t.sourcePosition) || t.movedRange.containsPosition(e.targetPosition) ? this._setRelation(e, t, "insertAtSource") : e.targetPosition.isEqual(t.deletionPosition) ? this._setRelation(e, t, "insertBetween") : e.targetPosition.isAfter(t.sourcePosition) && this._setRelation(e, t, "moveTargetAfter") : t instanceof M && (e.targetPosition.isEqual(t.sourcePosition) || e.targetPosition.isBefore(t.sourcePosition) ? this._setRelation(e, t, "insertBefore") : this._setRelation(e, t, "insertAfter"));
    else if (e instanceof F) {
      if (t instanceof Z)
        e.splitPosition.isBefore(t.sourcePosition) && this._setRelation(e, t, "splitBefore");
      else if (t instanceof M)
        if (e.splitPosition.isEqual(t.sourcePosition) || e.splitPosition.isBefore(t.sourcePosition))
          this._setRelation(e, t, "splitBefore");
        else {
          const i = g._createFromPositionAndShift(t.sourcePosition, t.howMany);
          if (e.splitPosition.hasSameParentAs(t.sourcePosition) && i.containsPosition(e.splitPosition)) {
            const s = i.end.offset - e.splitPosition.offset, r = e.splitPosition.offset - i.start.offset;
            this._setRelation(e, t, { howMany: s, offset: r });
          }
        }
    } else if (e instanceof Z)
      t instanceof Z ? (e.targetPosition.isEqual(t.sourcePosition) || this._setRelation(e, t, "mergeTargetNotMoved"), e.sourcePosition.isEqual(t.targetPosition) && this._setRelation(e, t, "mergeSourceNotMoved"), e.sourcePosition.isEqual(t.sourcePosition) && this._setRelation(e, t, "mergeSameElement")) : t instanceof F && e.sourcePosition.isEqual(t.splitPosition) && this._setRelation(e, t, "splitAtSource");
    else if (e instanceof fe) {
      const i = e.newRange;
      if (!i)
        return;
      if (t instanceof M) {
        const s = g._createFromPositionAndShift(t.sourcePosition, t.howMany), r = s.containsPosition(i.start) || s.start.isEqual(i.start), o = s.containsPosition(i.end) || s.end.isEqual(i.end);
        (r || o) && !s.containsRange(i) && this._setRelation(e, t, {
          side: r ? "left" : "right",
          path: r ? i.start.path.slice() : i.end.path.slice()
        });
      } else if (t instanceof Z) {
        const s = i.start.isEqual(t.targetPosition), r = i.start.isEqual(t.deletionPosition), o = i.end.isEqual(t.deletionPosition), a = i.end.isEqual(t.sourcePosition);
        (s || r || o || a) && this._setRelation(e, t, {
          wasInLeftElement: s,
          wasStartBeforeMergedElement: r,
          wasEndBeforeMergedElement: o,
          wasInRightElement: a
        });
      }
    }
  }
  /**
   * Evaluates and returns contextual information about two given operations `opA` and `opB` which are about to be transformed.
   */
  getContext(e, t, i) {
    return {
      aIsStrong: i,
      aWasUndone: this._wasUndone(e),
      bWasUndone: this._wasUndone(t),
      abRelation: this._useRelations ? this._getRelation(e, t) : null,
      baRelation: this._useRelations ? this._getRelation(t, e) : null,
      forceWeakRemove: this._forceWeakRemove
    };
  }
  /**
   * Returns whether given operation `op` has already been undone.
   *
   * Information whether an operation was undone gives more context when making a decision when two operations are in conflict.
   */
  _wasUndone(e) {
    const t = this.originalOperations.get(e);
    return t.wasUndone || this._history.isUndoneOperation(t);
  }
  /**
   * Returns a relation between `opA` and an operation which is undone by `opB`. This can be `String` value if a relation
   * was set earlier or `null` if there was no relation between those operations.
   *
   * This is a little tricky to understand, so let's compare it to `ContextFactory#_wasUndone`.
   *
   * When `wasUndone( opB )` is used, we check if the `opB` has already been undone. It is obvious, that the
   * undoing operation must happen after the undone operation. So, essentially, we have `opB`, we take document history,
   * we look forward in the future and ask if in that future `opB` was undone.
   *
   * Relations is a backward process to `wasUndone()`.
   *
   * Long story short - using relations is asking what happened in the past. Looking back. This time we have an undoing
   * operation `opB` which has undone some other operation. When there is a transformation `opA` x `opB` and there is
   * a conflict to solve and `opB` is an undoing operation, we can look back in the history and see what was a relation
   * between `opA` and the operation which `opB` undone. Basing on that relation from the past, we can now make
   * a better decision when resolving a conflict between two operations, because we know more about the context of
   * those two operations.
   *
   * This is why this function does not return a relation directly between `opA` and `opB` because we need to look
   * back to search for a meaningful contextual information.
   */
  _getRelation(e, t) {
    const i = this.originalOperations.get(t), s = this._history.getUndoneOperation(i);
    if (!s)
      return null;
    const r = this.originalOperations.get(e), o = this._relations.get(r);
    return o && o.get(s) || null;
  }
  /**
   * Helper function for `ContextFactory#updateRelations`.
   */
  _setRelation(e, t, i) {
    const s = this.originalOperations.get(e), r = this.originalOperations.get(t);
    let o = this._relations.get(s);
    o || (o = /* @__PURE__ */ new Map(), this._relations.set(s, o)), o.set(r, i);
  }
}
function Ba(n, e) {
  for (const t of n)
    t.baseVersion = e++;
}
function Fa(n, e) {
  for (let t = 0; t < e; t++)
    n.push(new ie(0));
}
O(Q, Q, (n, e, t) => {
  if (n.key === e.key && n.range.start.hasSameParentAs(e.range.start)) {
    const i = n.range.getDifference(e.range).map((r) => new Q(r, n.key, n.oldValue, n.newValue, 0)), s = n.range.getIntersection(e.range);
    return s && t.aIsStrong && i.push(new Q(s, e.key, e.newValue, n.newValue, 0)), i.length == 0 ? [new ie(0)] : i;
  } else
    return [n];
});
O(Q, se, (n, e) => {
  if (n.range.start.hasSameParentAs(e.position) && n.range.containsPosition(e.position)) {
    const i = n.range._getTransformedByInsertion(e.position, e.howMany, !e.shouldReceiveAttributes).map((s) => new Q(s, n.key, n.oldValue, n.newValue, n.baseVersion));
    if (e.shouldReceiveAttributes) {
      const s = gh(e, n.key, n.oldValue);
      s && i.unshift(s);
    }
    return i;
  }
  return n.range = n.range._getTransformedByInsertion(e.position, e.howMany, !1)[0], [n];
});
function gh(n, e, t) {
  const s = n.nodes.getNode(0).getAttribute(e);
  if (s == t)
    return null;
  const r = new g(n.position, n.position.getShiftedBy(n.howMany));
  return new Q(r, e, s, t, 0);
}
O(Q, Z, (n, e) => {
  const t = [];
  n.range.start.hasSameParentAs(e.deletionPosition) && (n.range.containsPosition(e.deletionPosition) || n.range.start.isEqual(e.deletionPosition)) && t.push(g._createFromPositionAndShift(e.graveyardPosition, 1));
  const i = n.range._getTransformedByMergeOperation(e);
  return i.isCollapsed || t.push(i), t.map((s) => new Q(s, n.key, n.oldValue, n.newValue, n.baseVersion));
});
O(Q, M, (n, e) => jy(n.range, e).map((i) => new Q(i, n.key, n.oldValue, n.newValue, n.baseVersion)));
function jy(n, e) {
  const t = g._createFromPositionAndShift(e.sourcePosition, e.howMany);
  let i = null, s = [];
  t.containsRange(n, !0) ? i = n : n.start.hasSameParentAs(t.start) ? (s = n.getDifference(t), i = n.getIntersection(t)) : s = [n];
  const r = [];
  for (let o of s) {
    o = o._getTransformedByDeletion(e.sourcePosition, e.howMany);
    const a = e.getMovedRangeStart(), l = o.start.hasSameParentAs(a), c = o._getTransformedByInsertion(a, e.howMany, l);
    r.push(...c);
  }
  return i && r.push(i._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany, !1)[0]), r;
}
O(Q, F, (n, e) => {
  if (n.range.end.isEqual(e.insertionPosition))
    return e.graveyardPosition || n.range.end.offset++, [n];
  if (n.range.start.hasSameParentAs(e.splitPosition) && n.range.containsPosition(e.splitPosition)) {
    const t = n.clone();
    return t.range = new g(e.moveTargetPosition.clone(), n.range.end._getCombined(e.splitPosition, e.moveTargetPosition)), n.range.end = e.splitPosition.clone(), n.range.end.stickiness = "toPrevious", [n, t];
  }
  return n.range = n.range._getTransformedBySplitOperation(e), [n];
});
O(se, Q, (n, e) => {
  const t = [n];
  if (n.shouldReceiveAttributes && n.position.hasSameParentAs(e.range.start) && e.range.containsPosition(n.position)) {
    const i = gh(n, e.key, e.newValue);
    i && t.push(i);
  }
  return t;
});
O(se, se, (n, e, t) => n.position.isEqual(e.position) && t.aIsStrong ? [n] : (n.position = n.position._getTransformedByInsertOperation(e), [n]));
O(se, M, (n, e) => (n.position = n.position._getTransformedByMoveOperation(e), [n]));
O(se, F, (n, e) => (n.position = n.position._getTransformedBySplitOperation(e), [n]));
O(se, Z, (n, e) => (n.position = n.position._getTransformedByMergeOperation(e), [n]));
O(fe, se, (n, e) => (n.oldRange && (n.oldRange = n.oldRange._getTransformedByInsertOperation(e)[0]), n.newRange && (n.newRange = n.newRange._getTransformedByInsertOperation(e)[0]), [n]));
O(fe, fe, (n, e, t) => {
  if (n.name == e.name)
    if (t.aIsStrong)
      n.oldRange = e.newRange ? e.newRange.clone() : null;
    else
      return [new ie(0)];
  return [n];
});
O(fe, Z, (n, e) => (n.oldRange && (n.oldRange = n.oldRange._getTransformedByMergeOperation(e)), n.newRange && (n.newRange = n.newRange._getTransformedByMergeOperation(e)), [n]));
O(fe, M, (n, e, t) => {
  if (n.oldRange && (n.oldRange = g._createFromRanges(n.oldRange._getTransformedByMoveOperation(e))), n.newRange) {
    if (t.abRelation) {
      const i = g._createFromRanges(n.newRange._getTransformedByMoveOperation(e));
      if (t.abRelation.side == "left" && e.targetPosition.isEqual(n.newRange.start))
        return n.newRange.end = i.end, n.newRange.start.path = t.abRelation.path, [n];
      if (t.abRelation.side == "right" && e.targetPosition.isEqual(n.newRange.end))
        return n.newRange.start = i.start, n.newRange.end.path = t.abRelation.path, [n];
    }
    n.newRange = g._createFromRanges(n.newRange._getTransformedByMoveOperation(e));
  }
  return [n];
});
O(fe, F, (n, e, t) => {
  if (n.oldRange && (n.oldRange = n.oldRange._getTransformedBySplitOperation(e)), n.newRange) {
    if (t.abRelation) {
      const i = n.newRange._getTransformedBySplitOperation(e);
      return n.newRange.start.isEqual(e.splitPosition) && t.abRelation.wasStartBeforeMergedElement ? n.newRange.start = w._createAt(e.insertionPosition) : n.newRange.start.isEqual(e.splitPosition) && !t.abRelation.wasInLeftElement && (n.newRange.start = w._createAt(e.moveTargetPosition)), n.newRange.end.isEqual(e.splitPosition) && t.abRelation.wasInRightElement ? n.newRange.end = w._createAt(e.moveTargetPosition) : n.newRange.end.isEqual(e.splitPosition) && t.abRelation.wasEndBeforeMergedElement ? n.newRange.end = w._createAt(e.insertionPosition) : n.newRange.end = i.end, [n];
    }
    n.newRange = n.newRange._getTransformedBySplitOperation(e);
  }
  return [n];
});
O(Z, se, (n, e) => (n.sourcePosition.hasSameParentAs(e.position) && (n.howMany += e.howMany), n.sourcePosition = n.sourcePosition._getTransformedByInsertOperation(e), n.targetPosition = n.targetPosition._getTransformedByInsertOperation(e), [n]));
O(Z, Z, (n, e, t) => {
  if (n.sourcePosition.isEqual(e.sourcePosition) && n.targetPosition.isEqual(e.targetPosition))
    if (t.bWasUndone) {
      const i = e.graveyardPosition.path.slice();
      return i.push(0), n.sourcePosition = new w(e.graveyardPosition.root, i), n.howMany = 0, [n];
    } else
      return [new ie(0)];
  if (n.sourcePosition.isEqual(e.sourcePosition) && !n.targetPosition.isEqual(e.targetPosition) && !t.bWasUndone && t.abRelation != "splitAtSource") {
    const i = n.targetPosition.root.rootName == "$graveyard", s = e.targetPosition.root.rootName == "$graveyard";
    if (s && !i || !(i && !s) && t.aIsStrong) {
      const l = e.targetPosition._getTransformedByMergeOperation(e), c = n.targetPosition._getTransformedByMergeOperation(e);
      return [new M(l, n.howMany, c, 0)];
    } else
      return [new ie(0)];
  }
  return n.sourcePosition.hasSameParentAs(e.targetPosition) && (n.howMany += e.howMany), n.sourcePosition = n.sourcePosition._getTransformedByMergeOperation(e), n.targetPosition = n.targetPosition._getTransformedByMergeOperation(e), (!n.graveyardPosition.isEqual(e.graveyardPosition) || !t.aIsStrong) && (n.graveyardPosition = n.graveyardPosition._getTransformedByMergeOperation(e)), [n];
});
O(Z, M, (n, e, t) => {
  const i = g._createFromPositionAndShift(e.sourcePosition, e.howMany);
  return e.type == "remove" && !t.bWasUndone && !t.forceWeakRemove && n.deletionPosition.hasSameParentAs(e.sourcePosition) && i.containsPosition(n.sourcePosition) ? [new ie(0)] : (n.sourcePosition.hasSameParentAs(e.targetPosition) && (n.howMany += e.howMany), n.sourcePosition.hasSameParentAs(e.sourcePosition) && (n.howMany -= e.howMany), n.sourcePosition = n.sourcePosition._getTransformedByMoveOperation(e), n.targetPosition = n.targetPosition._getTransformedByMoveOperation(e), n.graveyardPosition.isEqual(e.targetPosition) || (n.graveyardPosition = n.graveyardPosition._getTransformedByMoveOperation(e)), [n]);
});
O(Z, F, (n, e, t) => {
  if (e.graveyardPosition && (n.graveyardPosition = n.graveyardPosition._getTransformedByDeletion(e.graveyardPosition, 1), n.deletionPosition.isEqual(e.graveyardPosition) && (n.howMany = e.howMany)), n.targetPosition.isEqual(e.splitPosition)) {
    const i = e.howMany != 0, s = e.graveyardPosition && n.deletionPosition.isEqual(e.graveyardPosition);
    if (i || s || t.abRelation == "mergeTargetNotMoved")
      return n.sourcePosition = n.sourcePosition._getTransformedBySplitOperation(e), [n];
  }
  if (n.sourcePosition.isEqual(e.splitPosition)) {
    if (t.abRelation == "mergeSourceNotMoved")
      return n.howMany = 0, n.targetPosition = n.targetPosition._getTransformedBySplitOperation(e), [n];
    if (t.abRelation == "mergeSameElement" || n.sourcePosition.offset > 0)
      return n.sourcePosition = e.moveTargetPosition.clone(), n.targetPosition = n.targetPosition._getTransformedBySplitOperation(e), [n];
  }
  return n.sourcePosition.hasSameParentAs(e.splitPosition) && (n.howMany = e.splitPosition.offset), n.sourcePosition = n.sourcePosition._getTransformedBySplitOperation(e), n.targetPosition = n.targetPosition._getTransformedBySplitOperation(e), [n];
});
O(M, se, (n, e) => {
  const i = g._createFromPositionAndShift(n.sourcePosition, n.howMany)._getTransformedByInsertOperation(e, !1)[0];
  return n.sourcePosition = i.start, n.howMany = i.end.offset - i.start.offset, n.targetPosition.isEqual(e.position) || (n.targetPosition = n.targetPosition._getTransformedByInsertOperation(e)), [n];
});
O(M, M, (n, e, t) => {
  const i = g._createFromPositionAndShift(n.sourcePosition, n.howMany), s = g._createFromPositionAndShift(e.sourcePosition, e.howMany);
  let r = t.aIsStrong, o = !t.aIsStrong;
  t.abRelation == "insertBefore" || t.baRelation == "insertAfter" ? o = !0 : (t.abRelation == "insertAfter" || t.baRelation == "insertBefore") && (o = !1);
  let a;
  if (n.targetPosition.isEqual(e.targetPosition) && o ? a = n.targetPosition._getTransformedByDeletion(e.sourcePosition, e.howMany) : a = n.targetPosition._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany), Na(n, e) && Na(e, n))
    return [e.getReversed()];
  if (i.containsPosition(e.targetPosition) && i.containsRange(s, !0))
    return i.start = i.start._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany), i.end = i.end._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany), Yt([i], a);
  if (s.containsPosition(n.targetPosition) && s.containsRange(i, !0))
    return i.start = i.start._getCombined(e.sourcePosition, e.getMovedRangeStart()), i.end = i.end._getCombined(e.sourcePosition, e.getMovedRangeStart()), Yt([i], a);
  const u = ce(n.sourcePosition.getParentPath(), e.sourcePosition.getParentPath());
  if (u == "prefix" || u == "extension")
    return i.start = i.start._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany), i.end = i.end._getTransformedByMove(e.sourcePosition, e.targetPosition, e.howMany), Yt([i], a);
  n.type == "remove" && e.type != "remove" && !t.aWasUndone && !t.forceWeakRemove ? r = !0 : n.type != "remove" && e.type == "remove" && !t.bWasUndone && !t.forceWeakRemove && (r = !1);
  const h = [], f = i.getDifference(s);
  for (const p of f) {
    p.start = p.start._getTransformedByDeletion(e.sourcePosition, e.howMany), p.end = p.end._getTransformedByDeletion(e.sourcePosition, e.howMany);
    const b = ce(p.start.getParentPath(), e.getMovedRangeStart().getParentPath()) == "same", E = p._getTransformedByInsertion(e.getMovedRangeStart(), e.howMany, b);
    h.push(...E);
  }
  const m = i.getIntersection(s);
  return m !== null && r && (m.start = m.start._getCombined(e.sourcePosition, e.getMovedRangeStart()), m.end = m.end._getCombined(e.sourcePosition, e.getMovedRangeStart()), h.length === 0 ? h.push(m) : h.length == 1 ? s.start.isBefore(i.start) || s.start.isEqual(i.start) ? h.unshift(m) : h.push(m) : h.splice(1, 0, m)), h.length === 0 ? [new ie(n.baseVersion)] : Yt(h, a);
});
O(M, F, (n, e, t) => {
  let i = n.targetPosition.clone();
  (!n.targetPosition.isEqual(e.insertionPosition) || !e.graveyardPosition || t.abRelation == "moveTargetAfter") && (i = n.targetPosition._getTransformedBySplitOperation(e));
  const s = g._createFromPositionAndShift(n.sourcePosition, n.howMany);
  if (s.end.isEqual(e.insertionPosition))
    return e.graveyardPosition || n.howMany++, n.targetPosition = i, [n];
  if (s.start.hasSameParentAs(e.splitPosition) && s.containsPosition(e.splitPosition)) {
    let a = new g(e.splitPosition, s.end);
    a = a._getTransformedBySplitOperation(e);
    const l = [
      new g(s.start, e.splitPosition),
      a
    ];
    return Yt(l, i);
  }
  n.targetPosition.isEqual(e.splitPosition) && t.abRelation == "insertAtSource" && (i = e.moveTargetPosition), n.targetPosition.isEqual(e.insertionPosition) && t.abRelation == "insertBetween" && (i = n.targetPosition);
  const o = [s._getTransformedBySplitOperation(e)];
  if (e.graveyardPosition) {
    const a = s.start.isEqual(e.graveyardPosition) || s.containsPosition(e.graveyardPosition);
    n.howMany > 1 && a && !t.aWasUndone && o.push(g._createFromPositionAndShift(e.insertionPosition, 1));
  }
  return Yt(o, i);
});
O(M, Z, (n, e, t) => {
  const i = g._createFromPositionAndShift(n.sourcePosition, n.howMany);
  if (e.deletionPosition.hasSameParentAs(n.sourcePosition) && i.containsPosition(e.sourcePosition)) {
    if (n.type == "remove" && !t.forceWeakRemove) {
      if (!t.aWasUndone) {
        const o = [];
        let a = e.graveyardPosition.clone(), l = e.targetPosition._getTransformedByMergeOperation(e);
        n.howMany > 1 && (o.push(new M(n.sourcePosition, n.howMany - 1, n.targetPosition, 0)), a = a._getTransformedByMove(n.sourcePosition, n.targetPosition, n.howMany - 1), l = l._getTransformedByMove(n.sourcePosition, n.targetPosition, n.howMany - 1));
        const c = e.deletionPosition._getCombined(n.sourcePosition, n.targetPosition), u = new M(a, 1, c, 0), h = u.getMovedRangeStart().path.slice();
        h.push(0);
        const f = new w(u.targetPosition.root, h);
        l = l._getTransformedByMove(a, c, 1);
        const m = new M(l, e.howMany, f, 0);
        return o.push(u), o.push(m), o;
      }
    } else if (n.howMany == 1)
      return t.bWasUndone ? (n.sourcePosition = e.graveyardPosition.clone(), n.targetPosition = n.targetPosition._getTransformedByMergeOperation(e), [n]) : [new ie(0)];
  }
  const r = g._createFromPositionAndShift(n.sourcePosition, n.howMany)._getTransformedByMergeOperation(e);
  return n.sourcePosition = r.start, n.howMany = r.end.offset - r.start.offset, n.targetPosition = n.targetPosition._getTransformedByMergeOperation(e), [n];
});
O(me, se, (n, e) => (n.position = n.position._getTransformedByInsertOperation(e), [n]));
O(me, Z, (n, e) => n.position.isEqual(e.deletionPosition) ? (n.position = e.graveyardPosition.clone(), n.position.stickiness = "toNext", [n]) : (n.position = n.position._getTransformedByMergeOperation(e), [n]));
O(me, M, (n, e) => (n.position = n.position._getTransformedByMoveOperation(e), [n]));
O(me, me, (n, e, t) => {
  if (n.position.isEqual(e.position))
    if (t.aIsStrong)
      n.oldName = e.newName;
    else
      return [new ie(0)];
  return [n];
});
O(me, F, (n, e) => {
  const t = n.position.path, i = e.splitPosition.getParentPath();
  if (ce(t, i) == "same" && !e.graveyardPosition) {
    const s = new me(n.position.getShiftedBy(1), n.oldName, n.newName, 0);
    return [n, s];
  }
  return n.position = n.position._getTransformedBySplitOperation(e), [n];
});
O(Ke, Ke, (n, e, t) => {
  if (n.root === e.root && n.key === e.key) {
    if (!t.aIsStrong || n.newValue === e.newValue)
      return [new ie(0)];
    n.oldValue = e.newValue;
  }
  return [n];
});
O(Le, Le, (n, e, t) => n.rootName === e.rootName && n.isAdd === e.isAdd && !t.bWasUndone ? [new ie(0)] : [n]);
O(F, se, (n, e) => (n.splitPosition.hasSameParentAs(e.position) && n.splitPosition.offset < e.position.offset && (n.howMany += e.howMany), n.splitPosition = n.splitPosition._getTransformedByInsertOperation(e), n.insertionPosition = n.insertionPosition._getTransformedByInsertOperation(e), [n]));
O(F, Z, (n, e, t) => {
  if (!n.graveyardPosition && !t.bWasUndone && n.splitPosition.hasSameParentAs(e.sourcePosition)) {
    const i = e.graveyardPosition.path.slice();
    i.push(0);
    const s = new w(e.graveyardPosition.root, i), r = F.getInsertionPosition(new w(e.graveyardPosition.root, i)), o = new F(s, 0, r, null, 0);
    return n.splitPosition = n.splitPosition._getTransformedByMergeOperation(e), n.insertionPosition = F.getInsertionPosition(n.splitPosition), n.graveyardPosition = o.insertionPosition.clone(), n.graveyardPosition.stickiness = "toNext", [o, n];
  }
  return n.splitPosition.hasSameParentAs(e.deletionPosition) && !n.splitPosition.isAfter(e.deletionPosition) && n.howMany--, n.splitPosition.hasSameParentAs(e.targetPosition) && (n.howMany += e.howMany), n.splitPosition = n.splitPosition._getTransformedByMergeOperation(e), n.insertionPosition = F.getInsertionPosition(n.splitPosition), n.graveyardPosition && (n.graveyardPosition = n.graveyardPosition._getTransformedByMergeOperation(e)), [n];
});
O(F, M, (n, e, t) => {
  const i = g._createFromPositionAndShift(e.sourcePosition, e.howMany);
  if (n.graveyardPosition) {
    const r = i.start.isEqual(n.graveyardPosition) || i.containsPosition(n.graveyardPosition);
    if (!t.bWasUndone && r) {
      const o = n.splitPosition._getTransformedByMoveOperation(e), a = n.graveyardPosition._getTransformedByMoveOperation(e), l = a.path.slice();
      l.push(0);
      const c = new w(a.root, l);
      return [new M(o, n.howMany, c, 0)];
    }
    n.graveyardPosition = n.graveyardPosition._getTransformedByMoveOperation(e);
  }
  const s = n.splitPosition.isEqual(e.targetPosition);
  if (s && (t.baRelation == "insertAtSource" || t.abRelation == "splitBefore"))
    return n.howMany += e.howMany, n.splitPosition = n.splitPosition._getTransformedByDeletion(e.sourcePosition, e.howMany), n.insertionPosition = F.getInsertionPosition(n.splitPosition), [n];
  if (s && t.abRelation && t.abRelation.howMany) {
    const { howMany: r, offset: o } = t.abRelation;
    return n.howMany += r, n.splitPosition = n.splitPosition.getShiftedBy(o), [n];
  }
  if (n.splitPosition.hasSameParentAs(e.sourcePosition) && i.containsPosition(n.splitPosition)) {
    const r = e.howMany - (n.splitPosition.offset - e.sourcePosition.offset);
    return n.howMany -= r, n.splitPosition.hasSameParentAs(e.targetPosition) && n.splitPosition.offset < e.targetPosition.offset && (n.howMany += e.howMany), n.splitPosition = e.sourcePosition.clone(), n.insertionPosition = F.getInsertionPosition(n.splitPosition), [n];
  }
  return e.sourcePosition.isEqual(e.targetPosition) || (n.splitPosition.hasSameParentAs(e.sourcePosition) && n.splitPosition.offset <= e.sourcePosition.offset && (n.howMany -= e.howMany), n.splitPosition.hasSameParentAs(e.targetPosition) && n.splitPosition.offset < e.targetPosition.offset && (n.howMany += e.howMany)), n.splitPosition.stickiness = "toNone", n.splitPosition = n.splitPosition._getTransformedByMoveOperation(e), n.splitPosition.stickiness = "toNext", n.graveyardPosition ? n.insertionPosition = n.insertionPosition._getTransformedByMoveOperation(e) : n.insertionPosition = F.getInsertionPosition(n.splitPosition), [n];
});
O(F, F, (n, e, t) => {
  if (n.splitPosition.isEqual(e.splitPosition)) {
    if (!n.graveyardPosition && !e.graveyardPosition)
      return [new ie(0)];
    if (n.graveyardPosition && e.graveyardPosition && n.graveyardPosition.isEqual(e.graveyardPosition))
      return [new ie(0)];
    if (t.abRelation == "splitBefore")
      return n.howMany = 0, n.graveyardPosition = n.graveyardPosition._getTransformedBySplitOperation(e), [n];
  }
  if (n.graveyardPosition && e.graveyardPosition && n.graveyardPosition.isEqual(e.graveyardPosition)) {
    const i = n.splitPosition.root.rootName == "$graveyard", s = e.splitPosition.root.rootName == "$graveyard";
    if (s && !i || !(i && !s) && t.aIsStrong) {
      const l = [];
      return e.howMany && l.push(new M(e.moveTargetPosition, e.howMany, e.splitPosition, 0)), n.howMany && l.push(new M(n.splitPosition, n.howMany, n.moveTargetPosition, 0)), l;
    } else
      return [new ie(0)];
  }
  if (n.graveyardPosition && (n.graveyardPosition = n.graveyardPosition._getTransformedBySplitOperation(e)), n.splitPosition.isEqual(e.insertionPosition) && t.abRelation == "splitBefore")
    return n.howMany++, [n];
  if (e.splitPosition.isEqual(n.insertionPosition) && t.baRelation == "splitBefore") {
    const i = e.insertionPosition.path.slice();
    i.push(0);
    const s = new w(e.insertionPosition.root, i), r = new M(n.insertionPosition, 1, s, 0);
    return [n, r];
  }
  return n.splitPosition.hasSameParentAs(e.splitPosition) && n.splitPosition.offset < e.splitPosition.offset && (n.howMany -= e.howMany), n.splitPosition = n.splitPosition._getTransformedBySplitOperation(e), n.insertionPosition = F.getInsertionPosition(n.splitPosition), [n];
});
function Na(n, e) {
  return n.targetPosition._getTransformedByDeletion(e.sourcePosition, e.howMany) === null;
}
function Yt(n, e) {
  const t = [];
  for (let i = 0; i < n.length; i++) {
    const s = n[i], r = new M(s.start, s.end.offset - s.start.offset, e, 0);
    t.push(r);
    for (let o = i + 1; o < n.length; o++)
      n[o] = n[o]._getTransformedByMove(r.sourcePosition, r.targetPosition, r.howMany)[0];
    e = e._getTransformedByMove(r.sourcePosition, r.targetPosition, r.howMany);
  }
  return t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class re extends N(w) {
  /**
   * Creates a live position.
   *
   * @see module:engine/model/position~Position
   */
  constructor(e, t, i = "toNone") {
    if (super(e, t, i), !this.root.is("rootElement"))
      throw new d("model-liveposition-root-not-rootelement", e);
    qy.call(this);
  }
  /**
   * Unbinds all events previously bound by `LivePosition`. Use it whenever you don't need `LivePosition` instance
   * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was
   * referring to it).
   */
  detach() {
    this.stopListening();
  }
  /**
   * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.
   */
  toPosition() {
    return new w(this.root, this.path.slice(), this.stickiness);
  }
  /**
   * Creates a `LivePosition` instance that is equal to position.
   */
  static fromPosition(e, t) {
    return new this(e.root, e.path.slice(), t || e.stickiness);
  }
}
re.prototype.is = function(n) {
  return n === "livePosition" || n === "model:livePosition" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n == "position" || n === "model:position";
};
function qy() {
  this.listenTo(this.root.document.model, "applyOperation", (n, e) => {
    const t = e[0];
    t.isDocumentOperation && Gy.call(this, t);
  }, { priority: "low" });
}
function Gy(n) {
  const e = this.getTransformedByOperation(n);
  if (!this.isEqual(e)) {
    const t = this.toPosition();
    this.path = e.path, this.root = e.root, this.fire("change", t);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $t {
  /**
   * Creates a batch instance.
   *
   * @see module:engine/model/model~Model#enqueueChange
   * @see module:engine/model/model~Model#change
   * @param type A set of flags that specify the type of the batch. Batch type can alter how some of the features work
   * when encountering a given `Batch` instance (for example, when a feature listens to applied operations).
   */
  constructor(e = {}) {
    typeof e == "string" && (e = e === "transparent" ? { isUndoable: !1 } : {}, q("batch-constructor-deprecated-string-type"));
    const { isUndoable: t = !0, isLocal: i = !0, isUndo: s = !1, isTyping: r = !1 } = e;
    this.operations = [], this.isUndoable = t, this.isLocal = i, this.isUndo = s, this.isTyping = r;
  }
  /**
   * The type of the batch.
   *
   * **This property has been deprecated and is always set to the `'default'` value.**
   *
   * It can be one of the following values:
   * * `'default'` &ndash; All "normal" batches. This is the most commonly used type.
   * * `'transparent'` &ndash; A batch that should be ignored by other features, i.e. an initial batch or collaborative editing
   * changes.
   *
   * @deprecated
   */
  get type() {
    return q("batch-type-deprecated"), "default";
  }
  /**
   * Returns the base version of this batch, which is equal to the base version of the first operation in the batch.
   * If there are no operations in the batch or neither operation has the base version set, it returns `null`.
   */
  get baseVersion() {
    for (const e of this.operations)
      if (e.baseVersion !== null)
        return e.baseVersion;
    return null;
  }
  /**
   * Adds an operation to the batch instance.
   *
   * @param operation An operation to add.
   * @returns The added operation.
   */
  addOperation(e) {
    return e.batch = this, this.operations.push(e), e;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ky {
  /**
   * Creates a `Differ` instance.
   *
   * @param markerCollection Model's marker collection.
   */
  constructor(e) {
    this._changesInElement = /* @__PURE__ */ new Map(), this._elementSnapshots = /* @__PURE__ */ new Map(), this._changedMarkers = /* @__PURE__ */ new Map(), this._changedRoots = /* @__PURE__ */ new Map(), this._changeCount = 0, this._cachedChanges = null, this._cachedChangesWithGraveyard = null, this._refreshedItems = /* @__PURE__ */ new Set(), this._markerCollection = e;
  }
  /**
   * Informs whether there are any changes buffered in `Differ`.
   */
  get isEmpty() {
    return this._changesInElement.size == 0 && this._changedMarkers.size == 0 && this._changedRoots.size == 0;
  }
  /**
   * Buffers the given operation. An operation has to be buffered before it is executed.
   *
   * @param operationToBuffer An operation to buffer.
   */
  bufferOperation(e) {
    const t = e;
    switch (t.type) {
      case "insert": {
        if (this._isInInsertedElement(t.position.parent))
          return;
        this._markInsert(t.position.parent, t.position.offset, t.nodes.maxOffset);
        break;
      }
      case "addAttribute":
      case "removeAttribute":
      case "changeAttribute": {
        for (const i of t.range.getItems({ shallow: !0 }))
          this._isInInsertedElement(i.parent) || this._markAttribute(i);
        break;
      }
      case "remove":
      case "move":
      case "reinsert": {
        if (t.sourcePosition.isEqual(t.targetPosition) || t.sourcePosition.getShiftedBy(t.howMany).isEqual(t.targetPosition))
          return;
        const i = this._isInInsertedElement(t.sourcePosition.parent), s = this._isInInsertedElement(t.targetPosition.parent);
        i || this._markRemove(t.sourcePosition.parent, t.sourcePosition.offset, t.howMany), s || this._markInsert(t.targetPosition.parent, t.getMovedRangeStart().offset, t.howMany);
        break;
      }
      case "rename": {
        if (this._isInInsertedElement(t.position.parent))
          return;
        this._markRemove(t.position.parent, t.position.offset, 1), this._markInsert(t.position.parent, t.position.offset, 1);
        const i = g._createFromPositionAndShift(t.position, 1);
        for (const s of this._markerCollection.getMarkersIntersectingRange(i)) {
          const r = s.getData();
          this.bufferMarkerChange(s.name, r, r);
        }
        break;
      }
      case "split": {
        const i = t.splitPosition.parent;
        this._isInInsertedElement(i) || this._markRemove(i, t.splitPosition.offset, t.howMany), this._isInInsertedElement(t.insertionPosition.parent) || this._markInsert(t.insertionPosition.parent, t.insertionPosition.offset, 1), t.graveyardPosition && this._markRemove(t.graveyardPosition.parent, t.graveyardPosition.offset, 1);
        break;
      }
      case "merge": {
        const i = t.sourcePosition.parent;
        this._isInInsertedElement(i.parent) || this._markRemove(i.parent, i.startOffset, 1);
        const s = t.graveyardPosition.parent;
        this._markInsert(s, t.graveyardPosition.offset, 1);
        const r = t.targetPosition.parent;
        this._isInInsertedElement(r) || this._markInsert(r, t.targetPosition.offset, i.maxOffset);
        break;
      }
      case "detachRoot":
      case "addRoot": {
        this._bufferRootStateChange(t.rootName, t.isAdd);
        break;
      }
      case "addRootAttribute":
      case "removeRootAttribute":
      case "changeRootAttribute": {
        const i = t.root.rootName;
        this._bufferRootAttributeChange(i, t.key, t.oldValue, t.newValue);
        break;
      }
    }
    this._cachedChanges = null;
  }
  /**
   * Buffers a marker change.
   *
   * @param markerName The name of the marker that changed.
   * @param oldMarkerData Marker data before the change.
   * @param newMarkerData Marker data after the change.
   */
  bufferMarkerChange(e, t, i) {
    const s = this._changedMarkers.get(e);
    s ? (s.newMarkerData = i, s.oldMarkerData.range == null && i.range == null && this._changedMarkers.delete(e)) : this._changedMarkers.set(e, {
      newMarkerData: i,
      oldMarkerData: t
    });
  }
  /**
   * Returns all markers that should be removed as a result of buffered changes.
   *
   * @returns Markers to remove. Each array item is an object containing the `name` and `range` properties.
   */
  getMarkersToRemove() {
    const e = [];
    for (const [t, i] of this._changedMarkers)
      i.oldMarkerData.range != null && e.push({ name: t, range: i.oldMarkerData.range });
    return e;
  }
  /**
   * Returns all markers which should be added as a result of buffered changes.
   *
   * @returns Markers to add. Each array item is an object containing the `name` and `range` properties.
   */
  getMarkersToAdd() {
    const e = [];
    for (const [t, i] of this._changedMarkers)
      i.newMarkerData.range != null && e.push({ name: t, range: i.newMarkerData.range });
    return e;
  }
  /**
   * Returns all markers which changed.
   */
  getChangedMarkers() {
    return Array.from(this._changedMarkers).map(([e, t]) => ({
      name: e,
      data: {
        oldRange: t.oldMarkerData.range,
        newRange: t.newMarkerData.range
      }
    }));
  }
  /**
   * Checks whether some of the buffered changes affect the editor data.
   *
   * Types of changes which affect the editor data:
   *
   * * model structure changes,
   * * attribute changes,
   * * a root is added or detached,
   * * changes of markers which were defined as `affectsData`,
   * * changes of markers' `affectsData` property.
   */
  hasDataChanges() {
    if (this._changesInElement.size > 0 || this._changedRoots.size > 0)
      return !0;
    for (const { newMarkerData: e, oldMarkerData: t } of this._changedMarkers.values()) {
      if (e.affectsData !== t.affectsData)
        return !0;
      if (e.affectsData) {
        const i = e.range && !t.range, s = !e.range && t.range, r = e.range && t.range && !e.range.isEqual(t.range);
        if (i || s || r)
          return !0;
      }
    }
    return !1;
  }
  /**
   * Calculates the diff between the old model tree state (the state before the first buffered operations since the last {@link #reset}
   * call) and the new model tree state (actual one). It should be called after all buffered operations are executed.
   *
   * The diff set is returned as an array of {@link module:engine/model/differ~DiffItem diff items}, each describing a change done
   * on the model. The items are sorted by the position on which the change happened. If a position
   * {@link module:engine/model/position~Position#isBefore is before} another one, it will be on an earlier index in the diff set.
   *
   * **Note**: Elements inside inserted element will not have a separate diff item, only the top most element change will be reported.
   *
   * Because calculating the diff is a costly operation, the result is cached. If no new operation was buffered since the
   * previous {@link #getChanges} call, the next call will return the cached value.
   *
   * @param options Additional options.
   * @param options.includeChangesInGraveyard If set to `true`, also changes that happened
   * in the graveyard root will be returned. By default, changes in the graveyard root are not returned.
   * @returns Diff between the old and the new model tree state.
   */
  getChanges(e = {}) {
    if (this._cachedChanges)
      return e.includeChangesInGraveyard ? this._cachedChangesWithGraveyard.slice() : this._cachedChanges.slice();
    let t = [];
    for (const i of this._changesInElement.keys()) {
      const s = this._changesInElement.get(i).sort((u, h) => u.offset === h.offset ? u.type != h.type ? u.type == "remove" ? -1 : 1 : 0 : u.offset < h.offset ? -1 : 1), r = this._elementSnapshots.get(i), o = La(i.getChildren()), a = Jy(r.length, s);
      let l = 0, c = 0;
      for (const u of a)
        if (u === "i")
          t.push(this._getInsertDiff(i, l, o[l])), l++;
        else if (u === "r")
          t.push(this._getRemoveDiff(i, l, r[c])), c++;
        else if (u === "a") {
          const h = o[l].attributes, f = r[c].attributes;
          let m;
          if (o[l].name == "$text")
            m = new g(w._createAt(i, l), w._createAt(i, l + 1));
          else {
            const p = i.offsetToIndex(l);
            m = new g(w._createAt(i, l), w._createAt(i.getChild(p), 0));
          }
          t.push(...this._getAttributesDiff(m, f, h)), l++, c++;
        } else
          l++, c++;
    }
    t.sort((i, s) => i.position.root != s.position.root ? i.position.root.rootName < s.position.root.rootName ? -1 : 1 : i.position.isEqual(s.position) ? i.changeCount - s.changeCount : i.position.isBefore(s.position) ? -1 : 1);
    for (let i = 1, s = 0; i < t.length; i++) {
      const r = t[s], o = t[i], a = r.type == "remove" && o.type == "remove" && r.name == "$text" && o.name == "$text" && r.position.isEqual(o.position), l = r.type == "insert" && o.type == "insert" && r.name == "$text" && o.name == "$text" && r.position.parent == o.position.parent && r.position.offset + r.length == o.position.offset, c = r.type == "attribute" && o.type == "attribute" && r.position.parent == o.position.parent && r.range.isFlat && o.range.isFlat && r.position.offset + r.length == o.position.offset && r.attributeKey == o.attributeKey && r.attributeOldValue == o.attributeOldValue && r.attributeNewValue == o.attributeNewValue;
      a || l || c ? (r.length++, c && (r.range.end = r.range.end.getShiftedBy(1)), t[i] = null) : s = i;
    }
    t = t.filter((i) => i);
    for (const i of t)
      delete i.changeCount, i.type == "attribute" && (delete i.position, delete i.length);
    return this._changeCount = 0, this._cachedChangesWithGraveyard = t, this._cachedChanges = t.filter(Zy), e.includeChangesInGraveyard ? this._cachedChangesWithGraveyard.slice() : this._cachedChanges.slice();
  }
  /**
   * Returns all roots that have changed (either were attached, or detached, or their attributes changed).
   *
   * @returns Diff between the old and the new roots state.
   */
  getChangedRoots() {
    return Array.from(this._changedRoots.values()).map((e) => {
      const t = { ...e };
      return t.state !== void 0 && delete t.attributes, t;
    });
  }
  /**
   * Returns a set of model items that were marked to get refreshed.
   */
  getRefreshedItems() {
    return new Set(this._refreshedItems);
  }
  /**
   * Resets `Differ`. Removes all buffered changes.
   */
  reset() {
    this._changesInElement.clear(), this._elementSnapshots.clear(), this._changedMarkers.clear(), this._changedRoots.clear(), this._refreshedItems = /* @__PURE__ */ new Set(), this._cachedChanges = null;
  }
  /**
   * Buffers the root state change after the root was attached or detached
   */
  _bufferRootStateChange(e, t) {
    if (!this._changedRoots.has(e)) {
      this._changedRoots.set(e, { name: e, state: t ? "attached" : "detached" });
      return;
    }
    const i = this._changedRoots.get(e);
    i.state !== void 0 ? (delete i.state, i.attributes === void 0 && this._changedRoots.delete(e)) : i.state = t ? "attached" : "detached";
  }
  /**
   * Buffers a root attribute change.
   */
  _bufferRootAttributeChange(e, t, i, s) {
    const r = this._changedRoots.get(e) || { name: e }, o = r.attributes || {};
    if (o[t]) {
      const a = o[t];
      s === a.oldValue ? delete o[t] : a.newValue = s;
    } else
      o[t] = { oldValue: i, newValue: s };
    Object.entries(o).length === 0 ? (delete r.attributes, r.state === void 0 && this._changedRoots.delete(e)) : (r.attributes = o, this._changedRoots.set(e, r));
  }
  /**
   * Marks the given `item` in differ to be "refreshed". It means that the item will be marked as removed and inserted
   * in the differ changes set, so it will be effectively re-converted when the differ changes are handled by a dispatcher.
   *
   * @internal
   * @param item Item to refresh.
   */
  _refreshItem(e) {
    if (this._isInInsertedElement(e.parent))
      return;
    this._markRemove(e.parent, e.startOffset, e.offsetSize), this._markInsert(e.parent, e.startOffset, e.offsetSize), this._refreshedItems.add(e);
    const t = g._createOn(e);
    for (const i of this._markerCollection.getMarkersIntersectingRange(t)) {
      const s = i.getData();
      this.bufferMarkerChange(i.name, s, s);
    }
    this._cachedChanges = null;
  }
  /**
   * Saves and handles an insert change.
   */
  _markInsert(e, t, i) {
    const s = { type: "insert", offset: t, howMany: i, count: this._changeCount++ };
    this._markChange(e, s);
  }
  /**
   * Saves and handles a remove change.
   */
  _markRemove(e, t, i) {
    const s = { type: "remove", offset: t, howMany: i, count: this._changeCount++ };
    this._markChange(e, s), this._removeAllNestedChanges(e, t, i);
  }
  /**
   * Saves and handles an attribute change.
   */
  _markAttribute(e) {
    const t = { type: "attribute", offset: e.startOffset, howMany: e.offsetSize, count: this._changeCount++ };
    this._markChange(e.parent, t);
  }
  /**
   * Saves and handles a model change.
   */
  _markChange(e, t) {
    this._makeSnapshot(e);
    const i = this._getChangesForElement(e);
    this._handleChange(t, i), i.push(t);
    for (let s = 0; s < i.length; s++)
      i[s].howMany < 1 && (i.splice(s, 1), s--);
  }
  /**
   * Gets an array of changes that have already been saved for a given element.
   */
  _getChangesForElement(e) {
    let t;
    return this._changesInElement.has(e) ? t = this._changesInElement.get(e) : (t = [], this._changesInElement.set(e, t)), t;
  }
  /**
   * Saves a children snapshot for a given element.
   */
  _makeSnapshot(e) {
    this._elementSnapshots.has(e) || this._elementSnapshots.set(e, La(e.getChildren()));
  }
  /**
   * For a given newly saved change, compares it with a change already done on the element and modifies the incoming
   * change and/or the old change.
   *
   * @param inc Incoming (new) change.
   * @param changes An array containing all the changes done on that element.
   */
  _handleChange(e, t) {
    e.nodesToHandle = e.howMany;
    for (const i of t) {
      const s = e.offset + e.howMany, r = i.offset + i.howMany;
      if (e.type == "insert" && (i.type == "insert" && (e.offset <= i.offset ? i.offset += e.howMany : e.offset < r && (i.howMany += e.nodesToHandle, e.nodesToHandle = 0)), i.type == "remove" && e.offset < i.offset && (i.offset += e.howMany), i.type == "attribute")) {
        if (e.offset <= i.offset)
          i.offset += e.howMany;
        else if (e.offset < r) {
          const o = i.howMany;
          i.howMany = e.offset - i.offset, t.unshift({
            type: "attribute",
            offset: s,
            howMany: o - i.howMany,
            count: this._changeCount++
          });
        }
      }
      if (e.type == "remove") {
        if (i.type == "insert") {
          if (s <= i.offset)
            i.offset -= e.howMany;
          else if (s <= r)
            if (e.offset < i.offset) {
              const o = s - i.offset;
              i.offset = e.offset, i.howMany -= o, e.nodesToHandle -= o;
            } else
              i.howMany -= e.nodesToHandle, e.nodesToHandle = 0;
          else if (e.offset <= i.offset)
            e.nodesToHandle -= i.howMany, i.howMany = 0;
          else if (e.offset < r) {
            const o = r - e.offset;
            i.howMany -= o, e.nodesToHandle -= o;
          }
        }
        if (i.type == "remove" && (s <= i.offset ? i.offset -= e.howMany : e.offset < i.offset && (e.nodesToHandle += i.howMany, i.howMany = 0)), i.type == "attribute") {
          if (s <= i.offset)
            i.offset -= e.howMany;
          else if (e.offset < i.offset) {
            const o = s - i.offset;
            i.offset = e.offset, i.howMany -= o;
          } else if (e.offset < r)
            if (s <= r) {
              const o = i.howMany;
              i.howMany = e.offset - i.offset;
              const a = o - i.howMany - e.nodesToHandle;
              t.unshift({
                type: "attribute",
                offset: e.offset,
                howMany: a,
                count: this._changeCount++
              });
            } else
              i.howMany -= r - e.offset;
        }
      }
      if (e.type == "attribute") {
        if (i.type == "insert")
          if (e.offset < i.offset && s > i.offset) {
            if (s > r) {
              const o = {
                type: "attribute",
                offset: r,
                howMany: s - r,
                count: this._changeCount++
              };
              this._handleChange(o, t), t.push(o);
            }
            e.nodesToHandle = i.offset - e.offset, e.howMany = e.nodesToHandle;
          } else
            e.offset >= i.offset && e.offset < r && (s > r ? (e.nodesToHandle = s - r, e.offset = r) : e.nodesToHandle = 0);
        if (i.type == "remove" && e.offset < i.offset && s > i.offset) {
          const o = {
            type: "attribute",
            offset: i.offset,
            howMany: s - i.offset,
            count: this._changeCount++
          };
          this._handleChange(o, t), t.push(o), e.nodesToHandle = i.offset - e.offset, e.howMany = e.nodesToHandle;
        }
        i.type == "attribute" && (e.offset >= i.offset && s <= r ? (e.nodesToHandle = 0, e.howMany = 0, e.offset = 0) : e.offset <= i.offset && s >= r && (i.howMany = 0));
      }
    }
    e.howMany = e.nodesToHandle, delete e.nodesToHandle;
  }
  /**
   * Returns an object with a single insert change description.
   *
   * @param parent The element in which the change happened.
   * @param offset The offset at which change happened.
   * @param elementSnapshot The snapshot of the removed element a character.
   * @returns The diff item.
   */
  _getInsertDiff(e, t, i) {
    return {
      type: "insert",
      position: w._createAt(e, t),
      name: i.name,
      attributes: new Map(i.attributes),
      length: 1,
      changeCount: this._changeCount++
    };
  }
  /**
   * Returns an object with a single remove change description.
   *
   * @param parent The element in which change happened.
   * @param offset The offset at which change happened.
   * @param elementSnapshot The snapshot of the removed element a character.
   * @returns The diff item.
   */
  _getRemoveDiff(e, t, i) {
    return {
      type: "remove",
      position: w._createAt(e, t),
      name: i.name,
      attributes: new Map(i.attributes),
      length: 1,
      changeCount: this._changeCount++
    };
  }
  /**
   * Returns an array of objects where each one is a single attribute change description.
   *
   * @param range The range where the change happened.
   * @param oldAttributes A map, map iterator or compatible object that contains attributes before the change.
   * @param newAttributes A map, map iterator or compatible object that contains attributes after the change.
   * @returns An array containing one or more diff items.
   */
  _getAttributesDiff(e, t, i) {
    const s = [];
    i = new Map(i);
    for (const [r, o] of t) {
      const a = i.has(r) ? i.get(r) : null;
      a !== o && s.push({
        type: "attribute",
        position: e.start,
        range: e.clone(),
        length: 1,
        attributeKey: r,
        attributeOldValue: o,
        attributeNewValue: a,
        changeCount: this._changeCount++
      }), i.delete(r);
    }
    for (const [r, o] of i)
      s.push({
        type: "attribute",
        position: e.start,
        range: e.clone(),
        length: 1,
        attributeKey: r,
        attributeOldValue: null,
        attributeNewValue: o,
        changeCount: this._changeCount++
      });
    return s;
  }
  /**
   * Checks whether given element or any of its parents is an element that is buffered as an inserted element.
   */
  _isInInsertedElement(e) {
    const t = e.parent;
    if (!t)
      return !1;
    const i = this._changesInElement.get(t), s = e.startOffset;
    if (i) {
      for (const r of i)
        if (r.type == "insert" && s >= r.offset && s < r.offset + r.howMany)
          return !0;
    }
    return this._isInInsertedElement(t);
  }
  /**
   * Removes deeply all buffered changes that are registered in elements from range specified by `parent`, `offset`
   * and `howMany`.
   */
  _removeAllNestedChanges(e, t, i) {
    const s = new g(w._createAt(e, t), w._createAt(e, t + i));
    for (const r of s.getItems({ shallow: !0 }))
      r.is("element") && (this._elementSnapshots.delete(r), this._changesInElement.delete(r), this._removeAllNestedChanges(r, 0, r.maxOffset));
  }
}
function La(n) {
  const e = [];
  for (const t of n)
    if (t.is("$text"))
      for (let i = 0; i < t.data.length; i++)
        e.push({
          name: "$text",
          attributes: new Map(t.getAttributes())
        });
    else
      e.push({
        name: t.name,
        attributes: new Map(t.getAttributes())
      });
  return e;
}
function Jy(n, e) {
  const t = [];
  let i = 0, s = 0;
  for (const r of e) {
    if (r.offset > i) {
      for (let o = 0; o < r.offset - i; o++)
        t.push("e");
      s += r.offset - i;
    }
    if (r.type == "insert") {
      for (let o = 0; o < r.howMany; o++)
        t.push("i");
      i = r.offset + r.howMany;
    } else if (r.type == "remove") {
      for (let o = 0; o < r.howMany; o++)
        t.push("r");
      i = r.offset, s += r.howMany;
    } else
      t.push(..."a".repeat(r.howMany).split("")), i = r.offset + r.howMany, s += r.howMany;
  }
  if (s < n)
    for (let r = 0; r < n - s - i; r++)
      t.push("e");
  return t;
}
function Zy(n) {
  const e = "position" in n && n.position.root.rootName == "$graveyard", t = "range" in n && n.range.root.rootName == "$graveyard";
  return !e && !t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Yy {
  constructor() {
    this._operations = [], this._undoPairs = /* @__PURE__ */ new Map(), this._undoneOperations = /* @__PURE__ */ new Set(), this._baseVersionToOperationIndex = /* @__PURE__ */ new Map(), this._version = 0, this._gaps = /* @__PURE__ */ new Map();
  }
  /**
   * The version of the last operation in the history.
   *
   * The history version is incremented automatically when a new operation is added to the history.
   * Setting the version manually should be done only in rare circumstances when a gap is planned
   * between history versions. When doing so, a gap will be created and the history will accept adding
   * an operation with base version equal to the new history version.
   */
  get version() {
    return this._version;
  }
  set version(e) {
    this._operations.length && e > this._version + 1 && this._gaps.set(this._version, e), this._version = e;
  }
  /**
   * The last history operation.
   */
  get lastOperation() {
    return this._operations[this._operations.length - 1];
  }
  /**
   * Adds an operation to the history and increments the history version.
   *
   * The operation's base version should be equal to the history version. Otherwise an error is thrown.
   */
  addOperation(e) {
    if (e.baseVersion !== this.version)
      throw new d("model-document-history-addoperation-incorrect-version", this, {
        operation: e,
        historyVersion: this.version
      });
    this._operations.push(e), this._version++, this._baseVersionToOperationIndex.set(e.baseVersion, this._operations.length - 1);
  }
  /**
   * Returns operations from the given range of operation base versions that were added to the history.
   *
   * Note that there may be gaps in operations base versions.
   *
   * @param fromBaseVersion Base version from which operations should be returned (inclusive).
   * @param toBaseVersion Base version up to which operations should be returned (exclusive).
   * @returns History operations for the given range, in chronological order.
   */
  getOperations(e, t = this.version) {
    if (!this._operations.length)
      return [];
    const i = this._operations[0];
    e === void 0 && (e = i.baseVersion);
    let s = t - 1;
    for (const [a, l] of this._gaps)
      e > a && e < l && (e = l), s > a && s < l && (s = a - 1);
    if (s < i.baseVersion || e > this.lastOperation.baseVersion)
      return [];
    let r = this._baseVersionToOperationIndex.get(e);
    r === void 0 && (r = 0);
    let o = this._baseVersionToOperationIndex.get(s);
    return o === void 0 && (o = this._operations.length - 1), this._operations.slice(
      r,
      // The `toIndex` should be included in the returned operations, so add `1`.
      o + 1
    );
  }
  /**
   * Returns operation from the history that bases on given `baseVersion`.
   *
   * @param baseVersion Base version of the operation to get.
   * @returns Operation with given base version or `undefined` if there is no such operation in history.
   */
  getOperation(e) {
    const t = this._baseVersionToOperationIndex.get(e);
    if (t !== void 0)
      return this._operations[t];
  }
  /**
   * Marks in history that one operation is an operation that is undoing the other operation. By marking operation this way,
   * history is keeping more context information about operations, which helps in operational transformation.
   *
   * @param undoneOperation Operation which is undone by `undoingOperation`.
   * @param undoingOperation Operation which undoes `undoneOperation`.
   */
  setOperationAsUndone(e, t) {
    this._undoPairs.set(t, e), this._undoneOperations.add(e);
  }
  /**
   * Checks whether given `operation` is undoing any other operation.
   *
   * @param operation Operation to check.
   * @returns `true` if given `operation` is undoing any other operation, `false` otherwise.
   */
  isUndoingOperation(e) {
    return this._undoPairs.has(e);
  }
  /**
   * Checks whether given `operation` has been undone by any other operation.
   *
   * @param operation Operation to check.
   * @returns `true` if given `operation` has been undone any other operation, `false` otherwise.
   */
  isUndoneOperation(e) {
    return this._undoneOperations.has(e);
  }
  /**
   * For given `undoingOperation`, returns the operation which has been undone by it.
   *
   * @returns Operation that has been undone by given `undoingOperation` or `undefined`
   * if given `undoingOperation` is not undoing any other operation.
   */
  getUndoneOperation(e) {
    return this._undoPairs.get(e);
  }
  /**
   * Resets the history of operations.
   */
  reset() {
    this._version = 0, this._undoPairs = /* @__PURE__ */ new Map(), this._operations = [], this._undoneOperations = /* @__PURE__ */ new Set(), this._gaps = /* @__PURE__ */ new Map(), this._baseVersionToOperationIndex = /* @__PURE__ */ new Map();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class vn extends B {
  /**
   * Creates root element.
   *
   * @param document Document that is an owner of this root.
   * @param name Node name.
   * @param rootName Unique root name used to identify this root element by {@link module:engine/model/document~Document}.
   */
  constructor(e, t, i = "main") {
    super(t), this._isAttached = !0, this._document = e, this.rootName = i;
  }
  /**
   * {@link module:engine/model/document~Document Document} that owns this root element.
   */
  get document() {
    return this._document;
  }
  /**
   * Informs if the root element is currently attached to the document, or not.
   *
   * A detached root is equivalent to being removed and cannot contain any children or markers.
   *
   * By default, a newly added root is attached. It can be detached using
   * {@link module:engine/model/writer~Writer#detachRoot `Writer#detachRoot`}. A detached root can be re-attached again using
   * {@link module:engine/model/writer~Writer#addRoot `Writer#addRoot`}.
   */
  isAttached() {
    return this._isAttached;
  }
  /**
   * Converts `RootElement` instance to `string` containing its name.
   *
   * @returns `RootElement` instance converted to `string`.
   */
  toJSON() {
    return this.rootName;
  }
}
vn.prototype.is = function(n, e) {
  return e ? e === this.name && (n === "rootElement" || n === "model:rootElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "model:element") : n === "rootElement" || n === "model:rootElement" || // From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.
  n === "element" || n === "model:element" || n === "node" || n === "model:node";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const rs = "$graveyard";
class Xy extends N() {
  /**
   * Creates an empty document instance with no {@link #roots} (other than
   * the {@link #graveyard graveyard root}).
   */
  constructor(e) {
    super(), this.model = e, this.history = new Yy(), this.selection = new Ie(this), this.roots = new He({ idProperty: "rootName" }), this.differ = new Ky(e.markers), this.isReadOnly = !1, this._postFixers = /* @__PURE__ */ new Set(), this._hasSelectionChangedFromTheLastChangeBlock = !1, this.createRoot("$root", rs), this.listenTo(e, "applyOperation", (t, i) => {
      const s = i[0];
      s.isDocumentOperation && this.differ.bufferOperation(s);
    }, { priority: "high" }), this.listenTo(e, "applyOperation", (t, i) => {
      const s = i[0];
      s.isDocumentOperation && this.history.addOperation(s);
    }, { priority: "low" }), this.listenTo(this.selection, "change", () => {
      this._hasSelectionChangedFromTheLastChangeBlock = !0;
    }), this.listenTo(e.markers, "update", (t, i, s, r, o) => {
      const a = { ...i.getData(), range: r };
      this.differ.bufferMarkerChange(i.name, o, a), s === null && i.on("change", (l, c) => {
        const u = i.getData();
        this.differ.bufferMarkerChange(i.name, { ...u, range: c }, u);
      });
    }), this.registerPostFixer((t) => {
      let i = !1;
      for (const s of this.roots)
        !s.isAttached() && !s.isEmpty && (t.remove(t.createRangeIn(s)), i = !0);
      for (const s of this.model.markers)
        s.getRange().root.isAttached() || (t.removeMarker(s), i = !0);
      return i;
    });
  }
  /**
   * The document version. Every applied operation increases the version number. It is used to
   * ensure that operations are applied on a proper document version.
   *
   * This property is equal to {@link module:engine/model/history~History#version `model.Document#history#version`}.
   *
   * If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,
   * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.
   */
  get version() {
    return this.history.version;
  }
  set version(e) {
    this.history.version = e;
  }
  /**
   * The graveyard tree root. A document always has a graveyard root that stores removed nodes.
   */
  get graveyard() {
    return this.getRoot(rs);
  }
  /**
   * Creates a new root.
   *
   * **Note:** do not use this method after the editor has been initialized! If you want to dynamically add a root, use
   * {@link module:engine/model/writer~Writer#addRoot `model.Writer#addRoot`} instead.
   *
   * @param elementName The element name. Defaults to `'$root'` which also has some basic schema defined
   * (e.g. `$block` elements are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.
   * @param rootName A unique root name.
   * @returns The created root.
   */
  createRoot(e = "$root", t = "main") {
    if (this.roots.get(t))
      throw new d("model-document-createroot-name-exists", this, { name: t });
    const i = new vn(this, e, t);
    return this.roots.add(i), i;
  }
  /**
   * Removes all event listeners set by the document instance.
   */
  destroy() {
    this.selection.destroy(), this.stopListening();
  }
  /**
   * Returns a root by its name.
   *
   * Detached roots are returned by this method. This is to be able to operate on the detached root (for example, to be able to create
   * a position inside such a root for undo feature purposes).
   *
   * @param name The root name of the root to return.
   * @returns The root registered under a given name or `null` when there is no root with the given name.
   */
  getRoot(e = "main") {
    return this.roots.get(e);
  }
  /**
   * Returns an array with names of all roots added to the document (except the {@link #graveyard graveyard root}).
   *
   * Detached roots **are not** returned by this method by default. This is to make sure that all features or algorithms that operate
   * on the document data know which roots are still a part of the document and should be processed.
   *
   * @param includeDetached Specified whether detached roots should be returned as well.
   * @returns Roots names.
   */
  getRootNames(e = !1) {
    return Array.from(this.roots).filter((t) => t.rootName != rs && (e || t.isAttached())).map((t) => t.rootName);
  }
  /**
   * Used to register a post-fixer callback. A post-fixer mechanism guarantees that the features
   * will operate on a correct model state.
   *
   * An execution of a feature may lead to an incorrect document tree state. The callbacks are used to fix the document tree after
   * it has changed. Post-fixers are fired just after all changes from the outermost change block were applied but
   * before the {@link module:engine/model/document~Document#event:change change event} is fired. If a post-fixer callback made
   * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should
   * not be fixed in the new document tree state.
   *
   * As a parameter, a post-fixer callback receives a {@link module:engine/model/writer~Writer writer} instance connected with the
   * executed changes block. Thanks to that, all changes done by the callback will be added to the same
   * {@link module:engine/model/batch~Batch batch} (and undo step) as the original changes. This makes post-fixer changes transparent
   * for the user.
   *
   * An example of a post-fixer is a callback that checks if all the data were removed from the editor. If so, the
   * callback should add an empty paragraph so that the editor is never empty:
   *
   * ```ts
   * document.registerPostFixer( writer => {
   * 	const changes = document.differ.getChanges();
   *
   * 	// Check if the changes lead to an empty root in the editor.
   * 	for ( const entry of changes ) {
   * 		if ( entry.type == 'remove' && entry.position.root.isEmpty ) {
   * 			writer.insertElement( 'paragraph', entry.position.root, 0 );
   *
   * 			// It is fine to return early, even if multiple roots would need to be fixed.
   * 			// All post-fixers will be fired again, so if there are more empty roots, those will be fixed, too.
   * 			return true;
   * 		}
   * 	}
   *
   * 	return false;
   * } );
   * ```
   */
  registerPostFixer(e) {
    this._postFixers.add(e);
  }
  /**
   * A custom `toJSON()` method to solve child-parent circular dependencies.
   *
   * @returns A clone of this object with the document property changed to a string.
   */
  toJSON() {
    const e = ou(this);
    return e.selection = "[engine.model.DocumentSelection]", e.model = "[engine.model.Model]", e;
  }
  /**
   * Check if there were any changes done on document, and if so, call post-fixers,
   * fire `change` event for features and conversion and then reset the differ.
   * Fire `change:data` event when at least one operation or buffered marker changes the data.
   *
   * @internal
   * @fires change
   * @fires change:data
   * @param writer The writer on which post-fixers will be called.
   */
  _handleChangeBlock(e) {
    this._hasDocumentChangedFromTheLastChangeBlock() && (this._callPostFixers(e), this.selection.refresh(), this.differ.hasDataChanges() ? this.fire("change:data", e.batch) : this.fire("change", e.batch), this.selection.refresh(), this.differ.reset()), this._hasSelectionChangedFromTheLastChangeBlock = !1;
  }
  /**
   * Returns whether there is a buffered change or if the selection has changed from the last
   * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block}
   * or {@link module:engine/model/model~Model#change `change()` block}.
   *
   * @returns Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.
   */
  _hasDocumentChangedFromTheLastChangeBlock() {
    return !this.differ.isEmpty || this._hasSelectionChangedFromTheLastChangeBlock;
  }
  /**
   * Returns the default root for this document which is either the first root that was added to the document using
   * {@link #createRoot} or the {@link #graveyard graveyard root} if no other roots were created.
   *
   * @returns The default root for this document.
   */
  _getDefaultRoot() {
    for (const e of this.roots)
      if (e !== this.graveyard)
        return e;
    return this.graveyard;
  }
  /**
   * Returns the default range for this selection. The default range is a collapsed range that starts and ends
   * at the beginning of this selection's document {@link #_getDefaultRoot default root}.
   *
   * @internal
   */
  _getDefaultRange() {
    const e = this._getDefaultRoot(), t = this.model, i = t.schema, s = t.createPositionFromPath(e, [0]);
    return i.getNearestSelectionRange(s) || t.createRange(s);
  }
  /**
   * Checks whether a given {@link module:engine/model/range~Range range} is a valid range for
   * the {@link #selection document's selection}.
   *
   * @internal
   * @param range A range to check.
   * @returns `true` if `range` is valid, `false` otherwise.
   */
  _validateSelectionRange(e) {
    return $a(e.start) && $a(e.end);
  }
  /**
   * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.
   *
   * @param writer The writer on which post-fixer callbacks will be called.
   */
  _callPostFixers(e) {
    let t = !1;
    do
      for (const i of this._postFixers)
        if (this.selection.refresh(), t = i(e), t)
          break;
    while (t);
  }
}
function $a(n) {
  const e = n.textNode;
  if (e) {
    const t = e.data, i = n.offset - e.startOffset;
    return !Or(t, i) && !Mr(t, i);
  }
  return !0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Qy extends N() {
  constructor() {
    super(...arguments), this._markers = /* @__PURE__ */ new Map();
  }
  /**
   * Iterable interface.
   *
   * Iterates over all {@link ~Marker markers} added to the collection.
   */
  [Symbol.iterator]() {
    return this._markers.values();
  }
  /**
   * Checks if given {@link ~Marker marker} or marker name is in the collection.
   *
   * @param markerOrName Name of marker or marker instance to check.
   * @returns `true` if marker is in the collection, `false` otherwise.
   */
  has(e) {
    const t = e instanceof Gt ? e.name : e;
    return this._markers.has(t);
  }
  /**
   * Returns {@link ~Marker marker} with given `markerName`.
   *
   * @param markerName Name of marker to get.
   * @returns Marker with given name or `null` if such marker was
   * not added to the collection.
   */
  get(e) {
    return this._markers.get(e) || null;
  }
  /**
   * Creates and adds a {@link ~Marker marker} to the `MarkerCollection` with given name on given
   * {@link module:engine/model/range~Range range}.
   *
   * If `MarkerCollection` already had a marker with given name (or {@link ~Marker marker} was passed), the marker in
   * collection is updated and {@link module:engine/model/markercollection~MarkerCollection#event:update} event is fired
   * but only if there was a change (marker range or {@link module:engine/model/markercollection~Marker#managedUsingOperations}
   * flag has changed.
   *
   * @internal
   * @fires update
   * @param markerOrName Name of marker to set or marker instance to update.
   * @param range Marker range.
   * @param managedUsingOperations Specifies whether the marker is managed using operations.
   * @param affectsData Specifies whether the marker affects the data produced by the data pipeline
   * (is persisted in the editor's data).
   * @returns `Marker` instance which was added or updated.
   */
  _set(e, t, i = !1, s = !1) {
    const r = e instanceof Gt ? e.name : e;
    if (r.includes(","))
      throw new d("markercollection-incorrect-marker-name", this);
    const o = this._markers.get(r);
    if (o) {
      const c = o.getData(), u = o.getRange();
      let h = !1;
      return u.isEqual(t) || (o._attachLiveRange(ze.fromRange(t)), h = !0), i != o.managedUsingOperations && (o._managedUsingOperations = i, h = !0), typeof s == "boolean" && s != o.affectsData && (o._affectsData = s, h = !0), h && this.fire(`update:${r}`, o, u, t, c), o;
    }
    const a = ze.fromRange(t), l = new Gt(r, a, i, s);
    return this._markers.set(r, l), this.fire(`update:${r}`, l, null, t, { ...l.getData(), range: null }), l;
  }
  /**
   * Removes given {@link ~Marker marker} or a marker with given name from the `MarkerCollection`.
   *
   * @internal
   * @fires update
   * @param markerOrName Marker or name of a marker to remove.
   * @returns `true` if marker was found and removed, `false` otherwise.
   */
  _remove(e) {
    const t = e instanceof Gt ? e.name : e, i = this._markers.get(t);
    return i ? (this._markers.delete(t), this.fire(`update:${t}`, i, i.getRange(), null, i.getData()), this._destroyMarker(i), !0) : !1;
  }
  /**
   * Fires an {@link module:engine/model/markercollection~MarkerCollection#event:update} event for the given {@link ~Marker marker}
   * but does not change the marker. Useful to force {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast
   * conversion} for the marker.
   *
   * @internal
   * @fires update
   * @param markerOrName Marker or name of a marker to refresh.
   */
  _refresh(e) {
    const t = e instanceof Gt ? e.name : e, i = this._markers.get(t);
    if (!i)
      throw new d("markercollection-refresh-marker-not-exists", this);
    const s = i.getRange();
    this.fire(`update:${t}`, i, s, s, i.getData());
  }
  /**
   * Returns iterator that iterates over all markers, which ranges contain given {@link module:engine/model/position~Position position}.
   */
  *getMarkersAtPosition(e) {
    for (const t of this)
      t.getRange().containsPosition(e) && (yield t);
  }
  /**
   * Returns iterator that iterates over all markers, which intersects with given {@link module:engine/model/range~Range range}.
   */
  *getMarkersIntersectingRange(e) {
    for (const t of this)
      t.getRange().getIntersection(e) !== null && (yield t);
  }
  /**
   * Destroys marker collection and all markers inside it.
   */
  destroy() {
    for (const e of this._markers.values())
      this._destroyMarker(e);
    this._markers = null, this.stopListening();
  }
  /**
   * Iterates over all markers that starts with given `prefix`.
   *
   * ```ts
   * const markerFooA = markersCollection.set( 'foo:a', rangeFooA );
   * const markerFooB = markersCollection.set( 'foo:b', rangeFooB );
   * const markerBarA = markersCollection.set( 'bar:a', rangeBarA );
   * const markerFooBarA = markersCollection.set( 'foobar:a', rangeFooBarA );
   * Array.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]
   * Array.from( markersCollection.getMarkersGroup( 'a' ) ); // []
   * ```
   */
  *getMarkersGroup(e) {
    for (const t of this._markers.values())
      t.name.startsWith(e + ":") && (yield t);
  }
  /**
   * Destroys the marker.
   */
  _destroyMarker(e) {
    e.stopListening(), e._detachLiveRange();
  }
}
class Gt extends N(ft) {
  /**
   * Creates a marker instance.
   *
   * @param name Marker name.
   * @param liveRange Range marked by the marker.
   * @param managedUsingOperations Specifies whether the marker is managed using operations.
   * @param affectsData Specifies whether the marker affects the data produced by the data pipeline (is persisted in the editor's data).
   */
  constructor(e, t, i, s) {
    super(), this.name = e, this._liveRange = this._attachLiveRange(t), this._managedUsingOperations = i, this._affectsData = s;
  }
  /**
   * A value indicating if the marker is managed using operations.
   * See {@link ~Marker marker class description} to learn more about marker types.
   * See {@link module:engine/model/writer~Writer#addMarker}.
   */
  get managedUsingOperations() {
    if (!this._liveRange)
      throw new d("marker-destroyed", this);
    return this._managedUsingOperations;
  }
  /**
   * A value indicating if the marker changes the data.
   */
  get affectsData() {
    if (!this._liveRange)
      throw new d("marker-destroyed", this);
    return this._affectsData;
  }
  /**
   * Returns the marker data (properties defining the marker).
   */
  getData() {
    return {
      range: this.getRange(),
      affectsData: this.affectsData,
      managedUsingOperations: this.managedUsingOperations
    };
  }
  /**
   * Returns current marker start position.
   */
  getStart() {
    if (!this._liveRange)
      throw new d("marker-destroyed", this);
    return this._liveRange.start.clone();
  }
  /**
   * Returns current marker end position.
   */
  getEnd() {
    if (!this._liveRange)
      throw new d("marker-destroyed", this);
    return this._liveRange.end.clone();
  }
  /**
   * Returns a range that represents the current state of the marker.
   *
   * Keep in mind that returned value is a {@link module:engine/model/range~Range Range}, not a
   * {@link module:engine/model/liverange~LiveRange LiveRange}. This means that it is up-to-date and relevant only
   * until next model document change. Do not store values returned by this method. Instead, store {@link ~Marker#name}
   * and get `Marker` instance from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection} every
   * time there is a need to read marker properties. This will guarantee that the marker has not been removed and
   * that it's data is up-to-date.
   */
  getRange() {
    if (!this._liveRange)
      throw new d("marker-destroyed", this);
    return this._liveRange.toRange();
  }
  /**
   * Binds new live range to the marker and detach the old one if is attached.
   *
   * @internal
   * @param liveRange Live range to attach
   * @returns Attached live range.
   */
  _attachLiveRange(e) {
    return this._liveRange && this._detachLiveRange(), e.delegate("change:range").to(this), e.delegate("change:content").to(this), this._liveRange = e, e;
  }
  /**
   * Unbinds and destroys currently attached live range.
   *
   * @internal
   */
  _detachLiveRange() {
    this._liveRange.stopDelegating("change:range", this), this._liveRange.stopDelegating("change:content", this), this._liveRange.detach(), this._liveRange = null;
  }
}
Gt.prototype.is = function(n) {
  return n === "marker" || n === "model:marker";
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ek extends ve {
  /**
   * Creates an insert operation.
   *
   * @param sourcePosition Position before the first {@link module:engine/model/item~Item model item} to move.
   * @param howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at
   * `sourcePosition` with offset shifted by `howMany`.
   */
  constructor(e, t) {
    super(null), this.sourcePosition = e.clone(), this.howMany = t;
  }
  /**
   * @inheritDoc
   */
  get type() {
    return "detach";
  }
  /**
   * @inheritDoc
   */
  get affectedSelectable() {
    return null;
  }
  /**
   * @inheritDoc
   */
  toJSON() {
    const e = super.toJSON();
    return e.sourcePosition = this.sourcePosition.toJSON(), e;
  }
  /**
   * @inheritDoc
   * @internal
   */
  _validate() {
    if (this.sourcePosition.root.document)
      throw new d("detach-operation-on-document-node", this);
  }
  /**
   * @inheritDoc
   * @internal
   */
  _execute() {
    dh(g._createFromPositionAndShift(this.sourcePosition, this.howMany));
  }
  /**
   * @inheritDoc
   */
  static get className() {
    return "DetachOperation";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ge extends ft {
  /**
   * Creates an empty `DocumentFragment`.
   *
   * **Note:** Constructor of this class shouldn't be used directly in the code.
   * Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.
   *
   * @internal
   * @param children Nodes to be contained inside the `DocumentFragment`.
   */
  constructor(e) {
    super(), this.markers = /* @__PURE__ */ new Map(), this._children = new Ci(), e && this._insertChild(0, e);
  }
  /**
   * Returns an iterator that iterates over all nodes contained inside this document fragment.
   */
  [Symbol.iterator]() {
    return this.getChildren();
  }
  /**
   * Number of this document fragment's children.
   */
  get childCount() {
    return this._children.length;
  }
  /**
   * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this document fragment's children.
   */
  get maxOffset() {
    return this._children.maxOffset;
  }
  /**
   * Is `true` if there are no nodes inside this document fragment, `false` otherwise.
   */
  get isEmpty() {
    return this.childCount === 0;
  }
  /**
   * Artificial next sibling. Returns `null`. Added for compatibility reasons.
   */
  get nextSibling() {
    return null;
  }
  /**
   * Artificial previous sibling. Returns `null`. Added for compatibility reasons.
   */
  get previousSibling() {
    return null;
  }
  /**
   * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.
   */
  get root() {
    return this;
  }
  /**
   * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.
   */
  get parent() {
    return null;
  }
  /**
   * Artificial owner of `DocumentFragment`. Returns `null`. Added for compatibility reasons.
   */
  get document() {
    return null;
  }
  /**
   * Returns `false` as `DocumentFragment` by definition is not attached to a document. Added for compatibility reasons.
   */
  isAttached() {
    return !1;
  }
  /**
   * Returns empty array. Added for compatibility reasons.
   */
  getAncestors() {
    return [];
  }
  /**
   * Gets the child at the given index. Returns `null` if incorrect index was passed.
   *
   * @param index Index of child.
   * @returns Child node.
   */
  getChild(e) {
    return this._children.getNode(e);
  }
  /**
   * Returns an iterator that iterates over all of this document fragment's children.
   */
  getChildren() {
    return this._children[Symbol.iterator]();
  }
  /**
   * Returns an index of the given child node. Returns `null` if given node is not a child of this document fragment.
   *
   * @param node Child node to look for.
   * @returns Child node's index.
   */
  getChildIndex(e) {
    return this._children.getNodeIndex(e);
  }
  /**
   * Returns the starting offset of given child. Starting offset is equal to the sum of
   * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if
   * given node is not a child of this document fragment.
   *
   * @param node Child node to look for.
   * @returns Child node's starting offset.
   */
  getChildStartOffset(e) {
    return this._children.getNodeStartOffset(e);
  }
  /**
   * Returns path to a `DocumentFragment`, which is an empty array. Added for compatibility reasons.
   */
  getPath() {
    return [];
  }
  /**
   * Returns a descendant node by its path relative to this element.
   *
   * ```ts
   * // <this>a<b>c</b></this>
   * this.getNodeByPath( [ 0 ] );     // -> "a"
   * this.getNodeByPath( [ 1 ] );     // -> <b>
   * this.getNodeByPath( [ 1, 0 ] );  // -> "c"
   * ```
   *
   * @param relativePath Path of the node to find, relative to this element.
   */
  getNodeByPath(e) {
    let t = this;
    for (const i of e)
      t = t.getChild(t.offsetToIndex(i));
    return t;
  }
  /**
   * Converts offset "position" to index "position".
   *
   * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is
   * too high, returns index after last child.
   *
   * ```ts
   * const textNode = new Text( 'foo' );
   * const pElement = new Element( 'p' );
   * const docFrag = new DocumentFragment( [ textNode, pElement ] );
   * docFrag.offsetToIndex( -1 ); // Returns 0, because offset is too low.
   * docFrag.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.
   * docFrag.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.
   * docFrag.offsetToIndex( 2 ); // Returns 0.
   * docFrag.offsetToIndex( 3 ); // Returns 1.
   * docFrag.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.
   * ```
   *
   * @param offset Offset to look for.
   * @returns Index of a node that occupies given offset.
   */
  offsetToIndex(e) {
    return this._children.offsetToIndex(e);
  }
  /**
   * Converts `DocumentFragment` instance to plain object and returns it.
   * Takes care of converting all of this document fragment's children.
   *
   * @returns `DocumentFragment` instance converted to plain object.
   */
  toJSON() {
    const e = [];
    for (const t of this._children)
      e.push(t.toJSON());
    return e;
  }
  /**
   * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).
   * Converts `DocumentFragment` children to proper nodes.
   *
   * @param json Plain object to be converted to `DocumentFragment`.
   * @returns `DocumentFragment` instance created using given plain object.
   */
  static fromJSON(e) {
    const t = [];
    for (const i of e)
      i.name ? t.push(B.fromJSON(i)) : t.push(U.fromJSON(i));
    return new Ge(t);
  }
  /**
   * {@link #_insertChild Inserts} one or more nodes at the end of this document fragment.
   *
   * @internal
   * @param items Items to be inserted.
   */
  _appendChild(e) {
    this._insertChild(this.childCount, e);
  }
  /**
   * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes
   * to this document fragment.
   *
   * @internal
   * @param index Index at which nodes should be inserted.
   * @param items Items to be inserted.
   */
  _insertChild(e, t) {
    const i = tk(t);
    for (const s of i)
      s.parent !== null && s._remove(), s.parent = this;
    this._children._insertNodes(e, i);
  }
  /**
   * Removes one or more nodes starting at the given index
   * and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.
   *
   * @internal
   * @param index Index of the first node to remove.
   * @param howMany Number of nodes to remove.
   * @returns Array containing removed nodes.
   */
  _removeChildren(e, t = 1) {
    const i = this._children._removeNodes(e, t);
    for (const s of i)
      s.parent = null;
    return i;
  }
}
Ge.prototype.is = function(n) {
  return n === "documentFragment" || n === "model:documentFragment";
};
function tk(n) {
  return typeof n == "string" ? [new U(n)] : (_e(n) || (n = [n]), Array.from(n).map((e) => typeof e == "string" ? new U(e) : e instanceof xe ? new U(e.data, e.getAttributes()) : e));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ik {
  /**
   * Creates a writer instance.
   *
   * **Note:** It is not recommended to use it directly. Use {@link module:engine/model/model~Model#change `Model#change()`} or
   * {@link module:engine/model/model~Model#enqueueChange `Model#enqueueChange()`} instead.
   *
   * @internal
   */
  constructor(e, t) {
    this.model = e, this.batch = t;
  }
  /**
   * Creates a new {@link module:engine/model/text~Text text node}.
   *
   * ```ts
   * writer.createText( 'foo' );
   * writer.createText( 'foo', { bold: true } );
   * ```
   *
   * @param data Text data.
   * @param attributes Text attributes.
   * @returns {module:engine/model/text~Text} Created text node.
   */
  createText(e, t) {
    return new U(e, t);
  }
  /**
   * Creates a new {@link module:engine/model/element~Element element}.
   *
   * ```ts
   * writer.createElement( 'paragraph' );
   * writer.createElement( 'paragraph', { alignment: 'center' } );
   * ```
   *
   * @param name Name of the element.
   * @param attributes Elements attributes.
   * @returns Created element.
   */
  createElement(e, t) {
    return new B(e, t);
  }
  /**
   * Creates a new {@link module:engine/model/documentfragment~DocumentFragment document fragment}.
   *
   * @returns Created document fragment.
   */
  createDocumentFragment() {
    return new Ge();
  }
  /**
   * Creates a copy of the element and returns it. Created element has the same name and attributes as the original element.
   * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.
   *
   * @param element The element to clone.
   * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
   * element will be cloned without any child.
   */
  cloneElement(e, t = !0) {
    return e._clone(t);
  }
  /**
   * Inserts item on given position.
   *
   * ```ts
   * const paragraph = writer.createElement( 'paragraph' );
   * writer.insert( paragraph, position );
   * ```
   *
   * Instead of using position you can use parent and offset:
   *
   * ```ts
   * const text = writer.createText( 'foo' );
   * writer.insert( text, paragraph, 5 );
   * ```
   *
   * You can also use `end` instead of the offset to insert at the end:
   *
   * ```ts
   * const text = writer.createText( 'foo' );
   * writer.insert( text, paragraph, 'end' );
   * ```
   *
   * Or insert before or after another element:
   *
   * ```ts
   * const paragraph = writer.createElement( 'paragraph' );
   * writer.insert( paragraph, anotherParagraph, 'after' );
   * ```
   *
   * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.
   *
   * Note that if the item already has parent it will be removed from the previous parent.
   *
   * Note that you cannot re-insert a node from a document to a different document or a document fragment. In this case,
   * `model-writer-insert-forbidden-move` is thrown.
   *
   * If you want to move {@link module:engine/model/range~Range range} instead of an
   * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.
   *
   * **Note:** For a paste-like content insertion mechanism see
   * {@link module:engine/model/model~Model#insertContent `model.insertContent()`}.
   *
   * @param item Item or document fragment to insert.
   * @param offset Offset or one of the flags. Used only when second parameter is a {@link module:engine/model/item~Item model item}.
   */
  insert(e, t, i = 0) {
    if (this._assertWriterUsedCorrectly(), e instanceof U && e.data == "")
      return;
    const s = w._createAt(t, i);
    if (e.parent)
      if (Wa(e.root, s.root)) {
        this.move(g._createOn(e), s);
        return;
      } else {
        if (e.root.document)
          throw new d("model-writer-insert-forbidden-move", this);
        this.remove(e);
      }
    const r = s.root.document ? s.root.document.version : null, o = new se(s, e, r);
    if (e instanceof U && (o.shouldReceiveAttributes = !0), this.batch.addOperation(o), this.model.applyOperation(o), e instanceof Ge)
      for (const [a, l] of e.markers) {
        const c = w._createAt(l.root, 0), h = { range: new g(l.start._getCombined(c, s), l.end._getCombined(c, s)), usingOperation: !0, affectsData: !0 };
        this.model.markers.has(a) ? this.updateMarker(a, h) : this.addMarker(a, h);
      }
  }
  insertText(e, t, i, s) {
    t instanceof Ge || t instanceof B || t instanceof w ? this.insert(this.createText(e), t, i) : this.insert(this.createText(e, t), i, s);
  }
  insertElement(e, t, i, s) {
    t instanceof Ge || t instanceof B || t instanceof w ? this.insert(this.createElement(e), t, i) : this.insert(this.createElement(e, t), i, s);
  }
  /**
   * Inserts item at the end of the given parent.
   *
   * ```ts
   * const paragraph = writer.createElement( 'paragraph' );
   * writer.append( paragraph, root );
   * ```
   *
   * Note that if the item already has parent it will be removed from the previous parent.
   *
   * If you want to move {@link module:engine/model/range~Range range} instead of an
   * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.
   *
   * @param item Item or document fragment to insert.
   */
  append(e, t) {
    this.insert(e, t, "end");
  }
  appendText(e, t, i) {
    t instanceof Ge || t instanceof B ? this.insert(this.createText(e), t, "end") : this.insert(this.createText(e, t), i, "end");
  }
  appendElement(e, t, i) {
    t instanceof Ge || t instanceof B ? this.insert(this.createElement(e), t, "end") : this.insert(this.createElement(e, t), i, "end");
  }
  /**
   * Sets value of the attribute with given key on a {@link module:engine/model/item~Item model item}
   * or on a {@link module:engine/model/range~Range range}.
   *
   * @param key Attribute key.
   * @param value Attribute new value.
   * @param itemOrRange Model item or range on which the attribute will be set.
   */
  setAttribute(e, t, i) {
    if (this._assertWriterUsedCorrectly(), i instanceof g) {
      const s = i.getMinimalFlatRanges();
      for (const r of s)
        za(this, e, t, r);
    } else
      Ha(this, e, t, i);
  }
  /**
   * Sets values of attributes on a {@link module:engine/model/item~Item model item}
   * or on a {@link module:engine/model/range~Range range}.
   *
   * ```ts
   * writer.setAttributes( {
   * 	bold: true,
   * 	italic: true
   * }, range );
   * ```
   *
   * @param attributes Attributes keys and values.
   * @param itemOrRange Model item or range on which the attributes will be set.
   */
  setAttributes(e, t) {
    for (const [i, s] of Xe(e))
      this.setAttribute(i, s, t);
  }
  /**
   * Removes an attribute with given key from a {@link module:engine/model/item~Item model item}
   * or from a {@link module:engine/model/range~Range range}.
   *
   * @param key Attribute key.
   * @param itemOrRange Model item or range from which the attribute will be removed.
   */
  removeAttribute(e, t) {
    if (this._assertWriterUsedCorrectly(), t instanceof g) {
      const i = t.getMinimalFlatRanges();
      for (const s of i)
        za(this, e, null, s);
    } else
      Ha(this, e, null, t);
  }
  /**
   * Removes all attributes from all elements in the range or from the given item.
   *
   * @param itemOrRange Model item or range from which all attributes will be removed.
   */
  clearAttributes(e) {
    this._assertWriterUsedCorrectly();
    const t = (i) => {
      for (const s of i.getAttributeKeys())
        this.removeAttribute(s, i);
    };
    if (!(e instanceof g))
      t(e);
    else
      for (const i of e.getItems())
        t(i);
  }
  /**
   * Moves all items in the source range to the target position.
   *
   * ```ts
   * writer.move( sourceRange, targetPosition );
   * ```
   *
   * Instead of the target position you can use parent and offset or define that range should be moved to the end
   * or before or after chosen item:
   *
   * ```ts
   * // Moves all items in the range to the paragraph at offset 5:
   * writer.move( sourceRange, paragraph, 5 );
   * // Moves all items in the range to the end of a blockquote:
   * writer.move( sourceRange, blockquote, 'end' );
   * // Moves all items in the range to a position after an image:
   * writer.move( sourceRange, image, 'after' );
   * ```
   *
   * These parameters work the same way as {@link #createPositionAt `writer.createPositionAt()`}.
   *
   * Note that items can be moved only within the same tree. It means that you can move items within the same root
   * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},
   * but you can not move items from document fragment to the document or from one detached element to another. Use
   * {@link module:engine/model/writer~Writer#insert} in such cases.
   *
   * @param range Source range.
   * @param offset Offset or one of the flags. Used only when second parameter is a {@link module:engine/model/item~Item model item}.
   */
  move(e, t, i) {
    if (this._assertWriterUsedCorrectly(), !(e instanceof g))
      throw new d("writer-move-invalid-range", this);
    if (!e.isFlat)
      throw new d("writer-move-range-not-flat", this);
    const s = w._createAt(t, i);
    if (s.isEqual(e.start))
      return;
    if (this._addOperationForAffectedMarkers("move", e), !Wa(e.root, s.root))
      throw new d("writer-move-different-document", this);
    const r = e.root.document ? e.root.document.version : null, o = new M(e.start, e.end.offset - e.start.offset, s, r);
    this.batch.addOperation(o), this.model.applyOperation(o);
  }
  /**
   * Removes given model {@link module:engine/model/item~Item item} or {@link module:engine/model/range~Range range}.
   *
   * @param itemOrRange Model item or range to remove.
   */
  remove(e) {
    this._assertWriterUsedCorrectly();
    const i = (e instanceof g ? e : g._createOn(e)).getMinimalFlatRanges().reverse();
    for (const s of i)
      this._addOperationForAffectedMarkers("move", s), nk(s.start, s.end.offset - s.start.offset, this.batch, this.model);
  }
  /**
   * Merges two siblings at the given position.
   *
   * Node before and after the position have to be an element. Otherwise `writer-merge-no-element-before` or
   * `writer-merge-no-element-after` error will be thrown.
   *
   * @param position Position between merged elements.
   */
  merge(e) {
    this._assertWriterUsedCorrectly();
    const t = e.nodeBefore, i = e.nodeAfter;
    if (this._addOperationForAffectedMarkers("merge", e), !(t instanceof B))
      throw new d("writer-merge-no-element-before", this);
    if (!(i instanceof B))
      throw new d("writer-merge-no-element-after", this);
    e.root.document ? this._merge(e) : this._mergeDetached(e);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createPositionFromPath `Model#createPositionFromPath()`}.
   *
   * @param root Root of the position.
   * @param path Position path. See {@link module:engine/model/position~Position#path}.
   * @param stickiness Position stickiness. See {@link module:engine/model/position~PositionStickiness}.
   */
  createPositionFromPath(e, t, i) {
    return this.model.createPositionFromPath(e, t, i);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}.
   *
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/model/item~Item model item}.
   */
  createPositionAt(e, t) {
    return this.model.createPositionAt(e, t);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createPositionAfter `Model#createPositionAfter()`}.
   *
   * @param item Item after which the position should be placed.
   */
  createPositionAfter(e) {
    return this.model.createPositionAfter(e);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createPositionBefore `Model#createPositionBefore()`}.
   *
   * @param item Item after which the position should be placed.
   */
  createPositionBefore(e) {
    return this.model.createPositionBefore(e);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createRange `Model#createRange()`}.
   *
   * @param start Start position.
   * @param end End position. If not set, range will be collapsed at `start` position.
   */
  createRange(e, t) {
    return this.model.createRange(e, t);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createRangeIn `Model#createRangeIn()`}.
   *
   * @param element Element which is a parent for the range.
   */
  createRangeIn(e) {
    return this.model.createRangeIn(e);
  }
  /**
   * Shortcut for {@link module:engine/model/model~Model#createRangeOn `Model#createRangeOn()`}.
   *
   * @param element Element which is a parent for the range.
   */
  createRangeOn(e) {
    return this.model.createRangeOn(e);
  }
  createSelection(...e) {
    return this.model.createSelection(...e);
  }
  /**
   * Performs merge action in a detached tree.
   *
   * @param position Position between merged elements.
   */
  _mergeDetached(e) {
    const t = e.nodeBefore, i = e.nodeAfter;
    this.move(g._createIn(i), w._createAt(t, "end")), this.remove(i);
  }
  /**
   * Performs merge action in a non-detached tree.
   *
   * @param position Position between merged elements.
   */
  _merge(e) {
    const t = w._createAt(e.nodeBefore, "end"), i = w._createAt(e.nodeAfter, 0), s = e.root.document.graveyard, r = new w(s, [0]), o = e.root.document.version, a = new Z(i, e.nodeAfter.maxOffset, t, r, o);
    this.batch.addOperation(a), this.model.applyOperation(a);
  }
  /**
   * Renames the given element.
   *
   * @param element The element to rename.
   * @param newName New element name.
   */
  rename(e, t) {
    if (this._assertWriterUsedCorrectly(), !(e instanceof B))
      throw new d("writer-rename-not-element-instance", this);
    const i = e.root.document ? e.root.document.version : null, s = new me(w._createBefore(e), e.name, t, i);
    this.batch.addOperation(s), this.model.applyOperation(s);
  }
  /**
   * Splits elements starting from the given position and going to the top of the model tree as long as given
   * `limitElement` is reached. When `limitElement` is not defined then only the parent of the given position will be split.
   *
   * The element needs to have a parent. It cannot be a root element nor a document fragment.
   * The `writer-split-element-no-parent` error will be thrown if you try to split an element with no parent.
   *
   * @param position Position of split.
   * @param limitElement Stop splitting when this element will be reached.
   * @returns Split result with properties:
   * * `position` - Position between split elements.
   * * `range` - Range that stars from the end of the first split element and ends at the beginning of the first copy element.
   */
  split(e, t) {
    this._assertWriterUsedCorrectly();
    let i = e.parent;
    if (!i.parent)
      throw new d("writer-split-element-no-parent", this);
    if (t || (t = i.parent), !e.parent.getAncestors({ includeSelf: !0 }).includes(t))
      throw new d("writer-split-invalid-limit-element", this);
    let s, r;
    do {
      const o = i.root.document ? i.root.document.version : null, a = i.maxOffset - e.offset, l = F.getInsertionPosition(e), c = new F(e, a, l, null, o);
      this.batch.addOperation(c), this.model.applyOperation(c), !s && !r && (s = i, r = e.parent.nextSibling), e = this.createPositionAfter(e.parent), i = e.parent;
    } while (i !== t);
    return {
      position: e,
      range: new g(w._createAt(s, "end"), w._createAt(r, 0))
    };
  }
  /**
   * Wraps the given range with the given element or with a new element (if a string was passed).
   *
   * **Note:** range to wrap should be a "flat range" (see {@link module:engine/model/range~Range#isFlat `Range#isFlat`}).
   * If not, an error will be thrown.
   *
   * @param range Range to wrap.
   * @param elementOrString Element or name of element to wrap the range with.
   */
  wrap(e, t) {
    if (this._assertWriterUsedCorrectly(), !e.isFlat)
      throw new d("writer-wrap-range-not-flat", this);
    const i = t instanceof B ? t : new B(t);
    if (i.childCount > 0)
      throw new d("writer-wrap-element-not-empty", this);
    if (i.parent !== null)
      throw new d("writer-wrap-element-attached", this);
    this.insert(i, e.start);
    const s = new g(e.start.getShiftedBy(1), e.end.getShiftedBy(1));
    this.move(s, w._createAt(i, 0));
  }
  /**
   * Unwraps children of the given element – all its children are moved before it and then the element is removed.
   * Throws error if you try to unwrap an element which does not have a parent.
   *
   * @param element Element to unwrap.
   */
  unwrap(e) {
    if (this._assertWriterUsedCorrectly(), e.parent === null)
      throw new d("writer-unwrap-element-no-parent", this);
    this.move(g._createIn(e), this.createPositionAfter(e)), this.remove(e);
  }
  /**
   * Adds a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks
   * changes in the document and updates its range automatically, when model tree changes.
   *
   * As the first parameter you can set marker name.
   *
   * The required `options.usingOperation` parameter lets you decide if the marker should be managed by operations or not. See
   * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between
   * markers managed by operations and not-managed by operations.
   *
   * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be
   * `true` when the marker change changes the data returned by the
   * {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.
   * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.
   * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.
   *
   * Create marker directly base on marker's name:
   *
   * ```ts
   * addMarker( markerName, { range, usingOperation: false } );
   * ```
   *
   * Create marker using operation:
   *
   * ```ts
   * addMarker( markerName, { range, usingOperation: true } );
   * ```
   *
   * Create marker that affects the editor data:
   *
   * ```ts
   * addMarker( markerName, { range, usingOperation: false, affectsData: true } );
   * ```
   *
   * Note: For efficiency reasons, it's best to create and keep as little markers as possible.
   *
   * @see module:engine/model/markercollection~Marker
   * @param name Name of a marker to create - must be unique.
   * @param options.usingOperation Flag indicating that the marker should be added by MarkerOperation.
   * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.
   * @param options.range Marker range.
   * @param options.affectsData Flag indicating that the marker changes the editor data.
   * @returns Marker that was set.
   */
  addMarker(e, t) {
    if (this._assertWriterUsedCorrectly(), !t || typeof t.usingOperation != "boolean")
      throw new d("writer-addmarker-no-usingoperation", this);
    const i = t.usingOperation, s = t.range, r = t.affectsData === void 0 ? !1 : t.affectsData;
    if (this.model.markers.has(e))
      throw new d("writer-addmarker-marker-exists", this);
    if (!s)
      throw new d("writer-addmarker-no-range", this);
    return i ? (wi(this, e, null, s, r), this.model.markers.get(e)) : this.model.markers._set(e, s, i, r);
  }
  /**
   * Adds, updates or refreshes a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks
   * changes in the document and updates its range automatically, when model tree changes. Still, it is possible to change the
   * marker's range directly using this method.
   *
   * As the first parameter you can set marker name or instance. If none of them is provided, new marker, with a unique
   * name is created and returned.
   *
   * **Note**: If you want to change the {@link module:engine/view/element~Element view element} of the marker while its data in the model
   * remains the same, use the dedicated {@link module:engine/controller/editingcontroller~EditingController#reconvertMarker} method.
   *
   * The `options.usingOperation` parameter lets you change if the marker should be managed by operations or not. See
   * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between
   * markers managed by operations and not-managed by operations. It is possible to change this option for an existing marker.
   *
   * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be
   * `true` when the marker change changes the data returned by
   * the {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.
   * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.
   * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.
   *
   * Update marker directly base on marker's name:
   *
   * ```ts
   * updateMarker( markerName, { range } );
   * ```
   *
   * Update marker using operation:
   *
   * ```ts
   * updateMarker( marker, { range, usingOperation: true } );
   * updateMarker( markerName, { range, usingOperation: true } );
   * ```
   *
   * Change marker's option (start using operations to manage it):
   *
   * ```ts
   * updateMarker( marker, { usingOperation: true } );
   * ```
   *
   * Change marker's option (inform the engine, that the marker does not affect the data anymore):
   *
   * ```ts
   * updateMarker( markerName, { affectsData: false } );
   * ```
   *
   * @see module:engine/model/markercollection~Marker
   * @param markerOrName Name of a marker to update, or a marker instance.
   * @param options If options object is not defined then marker will be refreshed by triggering
   * downcast conversion for this marker with the same data.
   * @param options.range Marker range to update.
   * @param options.usingOperation Flag indicated whether the marker should be added by MarkerOperation.
   * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.
   * @param options.affectsData Flag indicating that the marker changes the editor data.
   */
  updateMarker(e, t) {
    this._assertWriterUsedCorrectly();
    const i = typeof e == "string" ? e : e.name, s = this.model.markers.get(i);
    if (!s)
      throw new d("writer-updatemarker-marker-not-exists", this);
    if (!t) {
      q("writer-updatemarker-reconvert-using-editingcontroller", { markerName: i }), this.model.markers._refresh(s);
      return;
    }
    const r = typeof t.usingOperation == "boolean", o = typeof t.affectsData == "boolean", a = o ? t.affectsData : s.affectsData;
    if (!r && !t.range && !o)
      throw new d("writer-updatemarker-wrong-options", this);
    const l = s.getRange(), c = t.range ? t.range : l;
    if (r && t.usingOperation !== s.managedUsingOperations) {
      t.usingOperation ? wi(this, i, null, c, a) : (wi(this, i, l, null, a), this.model.markers._set(i, c, void 0, a));
      return;
    }
    s.managedUsingOperations ? wi(this, i, l, c, a) : this.model.markers._set(i, c, void 0, a);
  }
  /**
   * Removes given {@link module:engine/model/markercollection~Marker marker} or marker with given name.
   * The marker is removed accordingly to how it has been created, so if the marker was created using operation,
   * it will be destroyed using operation.
   *
   * @param markerOrName Marker or marker name to remove.
   */
  removeMarker(e) {
    this._assertWriterUsedCorrectly();
    const t = typeof e == "string" ? e : e.name;
    if (!this.model.markers.has(t))
      throw new d("writer-removemarker-no-marker", this);
    const i = this.model.markers.get(t);
    if (!i.managedUsingOperations) {
      this.model.markers._remove(t);
      return;
    }
    const s = i.getRange();
    wi(this, t, s, null, i.affectsData);
  }
  /**
   * Adds a new root to the document (or re-attaches a {@link #detachRoot detached root}).
   *
   * Throws an error, if trying to add a root that is already added and attached.
   *
   * @param rootName Name of the added root.
   * @param elementName The element name. Defaults to `'$root'` which also has some basic schema defined
   * (e.g. `$block` elements are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.
   * @returns The added root element.
   */
  addRoot(e, t = "$root") {
    this._assertWriterUsedCorrectly();
    const i = this.model.document.getRoot(e);
    if (i && i.isAttached())
      throw new d("writer-addroot-root-exists", this);
    const s = this.model.document, r = new Le(e, t, !0, s, s.version);
    return this.batch.addOperation(r), this.model.applyOperation(r), this.model.document.getRoot(e);
  }
  /**
   * Detaches the root from the document.
   *
   * All content and markers are removed from the root upon detaching. New content and new markers cannot be added to the root, as long
   * as it is detached.
   *
   * A root cannot be fully removed from the document, it can be only detached. A root is permanently removed only after you
   * re-initialize the editor and do not specify the root in the initial data.
   *
   * A detached root can be re-attached using {@link #addRoot}.
   *
   * Throws an error if the root does not exist or the root is already detached.
   *
   * @param rootOrName Name of the detached root.
   */
  detachRoot(e) {
    this._assertWriterUsedCorrectly();
    const t = typeof e == "string" ? this.model.document.getRoot(e) : e;
    if (!t || !t.isAttached())
      throw new d("writer-detachroot-no-root", this);
    for (const r of this.model.markers)
      r.getRange().root === t && this.removeMarker(r);
    for (const r of t.getAttributeKeys())
      this.removeAttribute(r, t);
    this.remove(this.createRangeIn(t));
    const i = this.model.document, s = new Le(t.rootName, t.name, !1, i, i.version);
    this.batch.addOperation(s), this.model.applyOperation(s);
  }
  setSelection(...e) {
    this._assertWriterUsedCorrectly(), this.model.document.selection._setTo(...e);
  }
  /**
   * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.
   *
   * The location can be specified in the same form as
   * {@link #createPositionAt `writer.createPositionAt()`} parameters.
   *
   * @param itemOrPosition
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/model/item~Item model item}.
   */
  setSelectionFocus(e, t) {
    this._assertWriterUsedCorrectly(), this.model.document.selection._setFocus(e, t);
  }
  setSelectionAttribute(e, t) {
    if (this._assertWriterUsedCorrectly(), typeof e == "string")
      this._setSelectionAttribute(e, t);
    else
      for (const [i, s] of Xe(e))
        this._setSelectionAttribute(i, s);
  }
  /**
   * Removes attribute(s) with given key(s) from the selection.
   *
   * Remove one attribute:
   *
   * ```ts
   * writer.removeSelectionAttribute( 'italic' );
   * ```
   *
   * Remove multiple attributes:
   *
   * ```ts
   * writer.removeSelectionAttribute( [ 'italic', 'bold' ] );
   * ```
   *
   * @param keyOrIterableOfKeys Key of the attribute to remove or an iterable of attribute keys to remove.
   */
  removeSelectionAttribute(e) {
    if (this._assertWriterUsedCorrectly(), typeof e == "string")
      this._removeSelectionAttribute(e);
    else
      for (const t of e)
        this._removeSelectionAttribute(t);
  }
  /**
   * Temporarily changes the {@link module:engine/model/documentselection~DocumentSelection#isGravityOverridden gravity}
   * of the selection from left to right.
   *
   * The gravity defines from which direction the selection inherits its attributes. If it's the default left gravity,
   * then the selection (after being moved by the user) inherits attributes from its left-hand side.
   * This method allows to temporarily override this behavior by forcing the gravity to the right.
   *
   * For the following model fragment:
   *
   * ```xml
   * <$text bold="true" linkHref="url">bar[]</$text><$text bold="true">biz</$text>
   * ```
   *
   * * Default gravity: selection will have the `bold` and `linkHref` attributes.
   * * Overridden gravity: selection will have `bold` attribute.
   *
   * **Note**: It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry
   * of the process.
   *
   * @returns The unique id which allows restoring the gravity.
   */
  overrideSelectionGravity() {
    return this.model.document.selection._overrideGravity();
  }
  /**
   * Restores {@link ~Writer#overrideSelectionGravity} gravity to default.
   *
   * Restoring the gravity is only possible using the unique identifier returned by
   * {@link ~Writer#overrideSelectionGravity}. Note that the gravity remains overridden as long as won't be restored
   * the same number of times it was overridden.
   *
   * @param uid The unique id returned by {@link ~Writer#overrideSelectionGravity}.
   */
  restoreSelectionGravity(e) {
    this.model.document.selection._restoreGravity(e);
  }
  /**
   * @param key Key of the attribute to remove.
   * @param value Attribute value.
   */
  _setSelectionAttribute(e, t) {
    const i = this.model.document.selection;
    if (i.isCollapsed && i.anchor.parent.isEmpty) {
      const s = Ie._getStoreAttributeKey(e);
      this.setAttribute(s, t, i.anchor.parent);
    }
    i._setAttribute(e, t);
  }
  /**
   * @param key Key of the attribute to remove.
   */
  _removeSelectionAttribute(e) {
    const t = this.model.document.selection;
    if (t.isCollapsed && t.anchor.parent.isEmpty) {
      const i = Ie._getStoreAttributeKey(e);
      this.removeAttribute(i, t.anchor.parent);
    }
    t._removeAttribute(e);
  }
  /**
   * Throws `writer-detached-writer-tries-to-modify-model` error when the writer is used outside of the `change()` block.
   */
  _assertWriterUsedCorrectly() {
    if (this.model._currentWriter !== this)
      throw new d("writer-incorrect-use", this);
  }
  /**
   * For given action `type` and `positionOrRange` where the action happens, this function finds all affected markers
   * and applies a marker operation with the new marker range equal to the current range. Thanks to this, the marker range
   * can be later correctly processed during undo.
   *
   * @param type Writer action type.
   * @param positionOrRange Position or range where the writer action happens.
   */
  _addOperationForAffectedMarkers(e, t) {
    for (const i of this.model.markers) {
      if (!i.managedUsingOperations)
        continue;
      const s = i.getRange();
      let r = !1;
      if (e === "move") {
        const o = t;
        r = o.containsPosition(s.start) || o.start.isEqual(s.start) || o.containsPosition(s.end) || o.end.isEqual(s.end);
      } else {
        const o = t, a = o.nodeBefore, l = o.nodeAfter, c = s.start.parent == a && s.start.isAtEnd, u = s.end.parent == l && s.end.offset == 0, h = s.end.nodeAfter == l, f = s.start.nodeAfter == l;
        r = c || u || h || f;
      }
      r && this.updateMarker(i.name, { range: s });
    }
  }
}
function za(n, e, t, i) {
  const s = n.model, r = s.document;
  let o = i.start, a, l, c;
  for (const h of i.getWalker({ shallow: !0 }))
    c = h.item.getAttribute(e), a && l != c && (l != t && u(), o = a), a = h.nextPosition, l = c;
  a instanceof w && a != o && l != t && u();
  function u() {
    const h = new g(o, a), f = h.root.document ? r.version : null, m = new Q(h, e, l, t, f);
    n.batch.addOperation(m), s.applyOperation(m);
  }
}
function Ha(n, e, t, i) {
  const s = n.model, r = s.document, o = i.getAttribute(e);
  let a, l;
  if (o != t) {
    if (i.root === i) {
      const u = i.document ? r.version : null;
      l = new Ke(i, e, o, t, u);
    } else {
      a = new g(w._createBefore(i), n.createPositionAfter(i));
      const u = a.root.document ? r.version : null;
      l = new Q(a, e, o, t, u);
    }
    n.batch.addOperation(l), s.applyOperation(l);
  }
}
function wi(n, e, t, i, s) {
  const r = n.model, o = r.document, a = new fe(e, t, i, r.markers, !!s, o.version);
  n.batch.addOperation(a), r.applyOperation(a);
}
function nk(n, e, t, i) {
  let s;
  if (n.root.document) {
    const r = i.document, o = new w(r.graveyard, [0]);
    s = new M(n, e, o, r.version);
  } else
    s = new ek(n, e);
  t.addOperation(s), i.applyOperation(s);
}
function Wa(n, e) {
  return n === e || n instanceof vn && e instanceof vn;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function sk(n, e, t = {}) {
  if (e.isCollapsed)
    return;
  const i = e.getFirstRange();
  if (i.root.rootName == "$graveyard")
    return;
  const s = n.schema;
  n.change((r) => {
    if (!t.doNotResetEntireContent && fk(s, e)) {
      dk(r, e);
      return;
    }
    const o = {};
    if (!t.doNotAutoparagraph) {
      const c = e.getSelectedElement();
      c && Object.assign(o, s.getAttributesWithProperty(c, "copyOnReplace", !0));
    }
    const [a, l] = rk(i);
    a.isTouching(l) || r.remove(r.createRange(a, l)), t.leaveUnmerged || (ak(r, a, l), s.removeDisallowedAttributes(a.parent.getChildren(), r)), _h(r, e, a), !t.doNotAutoparagraph && uk(s, a) && bh(r, a, e, o), a.detach(), l.detach();
  });
}
function rk(n) {
  const e = n.root.document.model, t = n.start;
  let i = n.end;
  if (e.hasContent(n, { ignoreMarkers: !0 })) {
    const s = ok(i);
    if (s && i.isTouching(e.createPositionAt(s, 0))) {
      const r = e.createSelection(n);
      e.modifySelection(r, { direction: "backward" });
      const o = r.getLastPosition(), a = e.createRange(o, i);
      e.hasContent(a, { ignoreMarkers: !0 }) || (i = o);
    }
  }
  return [
    re.fromPosition(t, "toPrevious"),
    re.fromPosition(i, "toNext")
  ];
}
function ok(n) {
  const e = n.parent, t = e.root.document.model.schema, i = e.getAncestors({ parentFirst: !0, includeSelf: !0 });
  for (const s of i) {
    if (t.isLimit(s))
      return null;
    if (t.isBlock(s))
      return s;
  }
}
function ak(n, e, t) {
  const i = n.model;
  if (!Hr(n.model.schema, e, t))
    return;
  const [s, r] = ck(e, t);
  !s || !r || (!i.hasContent(s, { ignoreMarkers: !0 }) && i.hasContent(r, { ignoreMarkers: !0 }) ? wh(n, e, t, s.parent) : ph(n, e, t, s.parent));
}
function ph(n, e, t, i) {
  const s = e.parent, r = t.parent;
  if (!(s == i || r == i)) {
    for (e = n.createPositionAfter(s), t = n.createPositionBefore(r), t.isEqual(e) || n.insert(r, e), n.merge(e); t.parent.isEmpty; ) {
      const o = t.parent;
      t = n.createPositionBefore(o), n.remove(o);
    }
    Hr(n.model.schema, e, t) && ph(n, e, t, i);
  }
}
function wh(n, e, t, i) {
  const s = e.parent, r = t.parent;
  if (!(s == i || r == i)) {
    for (e = n.createPositionAfter(s), t = n.createPositionBefore(r), t.isEqual(e) || n.insert(s, t); e.parent.isEmpty; ) {
      const o = e.parent;
      e = n.createPositionBefore(o), n.remove(o);
    }
    t = n.createPositionBefore(r), lk(n, t), Hr(n.model.schema, e, t) && wh(n, e, t, i);
  }
}
function lk(n, e) {
  const t = e.nodeBefore, i = e.nodeAfter;
  t.name != i.name && n.rename(t, i.name), n.clearAttributes(t), n.setAttributes(Object.fromEntries(i.getAttributes()), t), n.merge(e);
}
function Hr(n, e, t) {
  const i = e.parent, s = t.parent;
  return i == s || n.isLimit(i) || n.isLimit(s) ? !1 : hk(e, t, n);
}
function ck(n, e) {
  const t = n.getAncestors(), i = e.getAncestors();
  let s = 0;
  for (; t[s] && t[s] == i[s]; )
    s++;
  return [t[s], i[s]];
}
function uk(n, e) {
  const t = n.checkChild(e, "$text"), i = n.checkChild(e, "paragraph");
  return !t && i;
}
function hk(n, e, t) {
  const i = new g(n, e);
  for (const s of i.getWalker())
    if (t.isLimit(s.item))
      return !1;
  return !0;
}
function bh(n, e, t, i = {}) {
  const s = n.createElement("paragraph");
  n.model.schema.setAllowedAttributes(s, i, n), n.insert(s, e), _h(n, t, n.createPositionAt(s, 0));
}
function dk(n, e) {
  const t = n.model.schema.getLimitElement(e);
  n.remove(n.createRangeIn(t)), bh(n, n.createPositionAt(t, 0), e);
}
function fk(n, e) {
  const t = n.getLimitElement(e);
  if (!e.containsEntireContent(t))
    return !1;
  const i = e.getFirstRange();
  return i.start.parent == i.end.parent ? !1 : n.checkChild(t, "paragraph");
}
function _h(n, e, t) {
  e instanceof Ie ? n.setSelection(t) : e.setTo(t);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function mk(n, e) {
  return n.change((t) => {
    const i = t.createDocumentFragment(), s = e.getFirstRange();
    if (!s || s.isCollapsed)
      return i;
    const r = s.start.root, o = s.start.getCommonPath(s.end), a = r.getNodeByPath(o);
    let l;
    s.start.parent == s.end.parent ? l = s : l = t.createRange(t.createPositionAt(a, s.start.path[o.length]), t.createPositionAt(a, s.end.path[o.length] + 1));
    const c = l.end.offset - l.start.offset;
    for (const u of l.getItems({ shallow: !0 }))
      u.is("$textProxy") ? t.appendText(u.data, u.getAttributes(), i) : t.append(t.cloneElement(u, !0), i);
    if (l != s) {
      const u = s._getTransformedByMove(l.start, t.createPositionAt(i, 0), c)[0], h = t.createRange(t.createPositionAt(i, 0), u.start), f = t.createRange(u.end, t.createPositionAt(i, "end"));
      Ua(f, t), Ua(h, t);
    }
    return i;
  });
}
function Ua(n, e) {
  const t = [];
  Array.from(n.getItems({ direction: "backward" })).map((i) => e.createRangeOn(i)).filter((i) => (i.start.isAfter(n.start) || i.start.isEqual(n.start)) && (i.end.isBefore(n.end) || i.end.isEqual(n.end))).forEach((i) => {
    t.push(i.start.parent), e.remove(i);
  }), t.forEach((i) => {
    let s = i;
    for (; s.parent && s.isEmpty; ) {
      const r = e.createRangeOn(s);
      s = s.parent, e.remove(r);
    }
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function gk(n, e, t) {
  return n.change((i) => {
    const s = t || n.document.selection;
    s.isCollapsed || n.deleteContent(s, { doNotAutoparagraph: !0 });
    const r = new pk(n, i, s.anchor), o = [];
    let a;
    if (e.is("documentFragment")) {
      if (e.markers.size) {
        const u = [];
        for (const [h, f] of e.markers) {
          const { start: m, end: p } = f, b = m.isEqual(p);
          u.push({ position: m, name: h, isCollapsed: b }, { position: p, name: h, isCollapsed: b });
        }
        u.sort(({ position: h }, { position: f }) => h.isBefore(f) ? 1 : -1);
        for (const { position: h, name: f, isCollapsed: m } of u) {
          let p = null, b = null;
          const E = h.parent === e && h.isAtStart, A = h.parent === e && h.isAtEnd;
          !E && !A ? (p = i.createElement("$marker"), i.insert(p, h)) : m && (b = E ? "start" : "end"), o.push({
            name: f,
            element: p,
            collapsed: b
          });
        }
      }
      a = e.getChildren();
    } else
      a = [e];
    r.handleNodes(a);
    let l = r.getSelectionRange();
    if (e.is("documentFragment") && o.length) {
      const u = l ? ze.fromRange(l) : null, h = {};
      for (let f = o.length - 1; f >= 0; f--) {
        const { name: m, element: p, collapsed: b } = o[f], E = !h[m];
        if (E && (h[m] = []), p) {
          const A = i.createPositionAt(p, "before");
          h[m].push(A), i.remove(p);
        } else {
          const A = r.getAffectedRange();
          if (!A) {
            b && h[m].push(r.position);
            continue;
          }
          b ? h[m].push(A[b]) : h[m].push(E ? A.start : A.end);
        }
      }
      for (const [f, [m, p]] of Object.entries(h))
        m && p && m.root === p.root && i.addMarker(f, {
          usingOperation: !0,
          affectsData: !0,
          range: new g(m, p)
        });
      u && (l = u.toRange(), u.detach());
    }
    /* istanbul ignore else -- @preserve */
    l && (s instanceof Ie ? i.setSelection(l) : s.setTo(l));
    const c = r.getAffectedRange() || n.createRange(s.anchor);
    return r.destroy(), c;
  });
}
class pk {
  constructor(e, t, i) {
    this._firstNode = null, this._lastNode = null, this._lastAutoParagraph = null, this._filterAttributesOf = [], this._affectedStart = null, this._affectedEnd = null, this._nodeToSelect = null, this.model = e, this.writer = t, this.position = i, this.canMergeWith = /* @__PURE__ */ new Set([this.position.parent]), this.schema = e.schema, this._documentFragment = t.createDocumentFragment(), this._documentFragmentPosition = t.createPositionAt(this._documentFragment, 0);
  }
  /**
   * Handles insertion of a set of nodes.
   *
   * @param nodes Nodes to insert.
   */
  handleNodes(e) {
    for (const t of Array.from(e))
      this._handleNode(t);
    this._insertPartialFragment(), this._lastAutoParagraph && this._updateLastNodeFromAutoParagraph(this._lastAutoParagraph), this._mergeOnRight(), this.schema.removeDisallowedAttributes(this._filterAttributesOf, this.writer), this._filterAttributesOf = [];
  }
  /**
   * Updates the last node after the auto paragraphing.
   *
   * @param node The last auto paragraphing node.
   */
  _updateLastNodeFromAutoParagraph(e) {
    const t = this.writer.createPositionAfter(this._lastNode), i = this.writer.createPositionAfter(e);
    if (i.isAfter(t)) {
      this._lastNode = e;
      /* istanbul ignore if -- @preserve */
      if (this.position.parent != e || !this.position.isAtEnd)
        throw new d("insertcontent-invalid-insertion-position", this);
      this.position = i, this._setAffectedBoundaries(this.position);
    }
  }
  /**
   * Returns range to be selected after insertion.
   * Returns `null` if there is no valid range to select after insertion.
   */
  getSelectionRange() {
    return this._nodeToSelect ? g._createOn(this._nodeToSelect) : this.model.schema.getNearestSelectionRange(this.position);
  }
  /**
   * Returns a range which contains all the performed changes. This is a range that, if removed, would return the model to the state
   * before the insertion. Returns `null` if no changes were done.
   */
  getAffectedRange() {
    return this._affectedStart ? new g(this._affectedStart, this._affectedEnd) : null;
  }
  /**
   * Destroys `Insertion` instance.
   */
  destroy() {
    this._affectedStart && this._affectedStart.detach(), this._affectedEnd && this._affectedEnd.detach();
  }
  /**
   * Handles insertion of a single node.
   */
  _handleNode(e) {
    if (this.schema.isObject(e)) {
      this._handleObject(e);
      return;
    }
    let t = this._checkAndAutoParagraphToAllowedPosition(e);
    if (!t && (t = this._checkAndSplitToAllowedPosition(e), !t)) {
      this._handleDisallowedNode(e);
      return;
    }
    this._appendToFragment(e), this._firstNode || (this._firstNode = e), this._lastNode = e;
  }
  /**
   * Inserts the temporary DocumentFragment into the model.
   */
  _insertPartialFragment() {
    if (this._documentFragment.isEmpty)
      return;
    const e = re.fromPosition(this.position, "toNext");
    this._setAffectedBoundaries(this.position), this._documentFragment.getChild(0) == this._firstNode && (this.writer.insert(this._firstNode, this.position), this._mergeOnLeft(), this.position = e.toPosition()), this._documentFragment.isEmpty || this.writer.insert(this._documentFragment, this.position), this._documentFragmentPosition = this.writer.createPositionAt(this._documentFragment, 0), this.position = e.toPosition(), e.detach();
  }
  /**
   * @param node The object element.
   */
  _handleObject(e) {
    this._checkAndSplitToAllowedPosition(e) ? this._appendToFragment(e) : this._tryAutoparagraphing(e);
  }
  /**
   * @param node The disallowed node which needs to be handled.
   */
  _handleDisallowedNode(e) {
    e.is("element") ? this.handleNodes(e.getChildren()) : this._tryAutoparagraphing(e);
  }
  /**
   * Append a node to the temporary DocumentFragment.
   *
   * @param node The node to insert.
   */
  _appendToFragment(e) {
    /* istanbul ignore if -- @preserve */
    if (!this.schema.checkChild(this.position, e))
      throw new d("insertcontent-wrong-position", this, { node: e, position: this.position });
    this.writer.insert(e, this._documentFragmentPosition), this._documentFragmentPosition = this._documentFragmentPosition.getShiftedBy(e.offsetSize), this.schema.isObject(e) && !this.schema.checkChild(this.position, "$text") ? this._nodeToSelect = e : this._nodeToSelect = null, this._filterAttributesOf.push(e);
  }
  /**
   * Sets `_affectedStart` and `_affectedEnd` to the given `position`. Should be used before a change is done during insertion process to
   * mark the affected range.
   *
   * This method is used before inserting a node or splitting a parent node. `_affectedStart` and `_affectedEnd` are also changed
   * during merging, but the logic there is more complicated so it is left out of this function.
   */
  _setAffectedBoundaries(e) {
    this._affectedStart || (this._affectedStart = re.fromPosition(e, "toPrevious")), (!this._affectedEnd || this._affectedEnd.isBefore(e)) && (this._affectedEnd && this._affectedEnd.detach(), this._affectedEnd = re.fromPosition(e, "toNext"));
  }
  /**
   * Merges the previous sibling of the first node if it should be merged.
   *
   * After the content was inserted we may try to merge it with its siblings.
   * This should happen only if the selection was in those elements initially.
   */
  _mergeOnLeft() {
    const e = this._firstNode;
    if (!(e instanceof B) || !this._canMergeLeft(e))
      return;
    const t = re._createBefore(e);
    t.stickiness = "toNext";
    const i = re.fromPosition(this.position, "toNext");
    this._affectedStart.isEqual(t) && (this._affectedStart.detach(), this._affectedStart = re._createAt(t.nodeBefore, "end", "toPrevious")), this._firstNode === this._lastNode && (this._firstNode = t.nodeBefore, this._lastNode = t.nodeBefore), this.writer.merge(t), t.isEqual(this._affectedEnd) && this._firstNode === this._lastNode && (this._affectedEnd.detach(), this._affectedEnd = re._createAt(t.nodeBefore, "end", "toNext")), this.position = i.toPosition(), i.detach(), this._filterAttributesOf.push(this.position.parent), t.detach();
  }
  /**
   * Merges the next sibling of the last node if it should be merged.
   *
   * After the content was inserted we may try to merge it with its siblings.
   * This should happen only if the selection was in those elements initially.
   */
  _mergeOnRight() {
    const e = this._lastNode;
    if (!(e instanceof B) || !this._canMergeRight(e))
      return;
    const t = re._createAfter(e);
    t.stickiness = "toNext";
    /* istanbul ignore if -- @preserve */
    if (!this.position.isEqual(t))
      throw new d("insertcontent-invalid-insertion-position", this);
    this.position = w._createAt(t.nodeBefore, "end");
    const i = re.fromPosition(this.position, "toPrevious");
    this._affectedEnd.isEqual(t) && (this._affectedEnd.detach(), this._affectedEnd = re._createAt(t.nodeBefore, "end", "toNext")), this._firstNode === this._lastNode && (this._firstNode = t.nodeBefore, this._lastNode = t.nodeBefore), this.writer.merge(t), t.getShiftedBy(-1).isEqual(this._affectedStart) && this._firstNode === this._lastNode && (this._affectedStart.detach(), this._affectedStart = re._createAt(t.nodeBefore, 0, "toPrevious")), this.position = i.toPosition(), i.detach(), this._filterAttributesOf.push(this.position.parent), t.detach();
  }
  /**
   * Checks whether specified node can be merged with previous sibling element.
   *
   * @param node The node which could potentially be merged.
   */
  _canMergeLeft(e) {
    const t = e.previousSibling;
    return t instanceof B && this.canMergeWith.has(t) && this.model.schema.checkMerge(t, e);
  }
  /**
   * Checks whether specified node can be merged with next sibling element.
   *
   * @param node The node which could potentially be merged.
   */
  _canMergeRight(e) {
    const t = e.nextSibling;
    return t instanceof B && this.canMergeWith.has(t) && this.model.schema.checkMerge(e, t);
  }
  /**
   * Tries wrapping the node in a new paragraph and inserting it this way.
   *
   * @param node The node which needs to be autoparagraphed.
   */
  _tryAutoparagraphing(e) {
    const t = this.writer.createElement("paragraph");
    this._getAllowedIn(this.position.parent, t) && this.schema.checkChild(t, e) && (t._appendChild(e), this._handleNode(t));
  }
  /**
   * Checks if a node can be inserted in the given position or it would be accepted if a paragraph would be inserted.
   * It also handles inserting the paragraph.
   *
   * @returns Whether an allowed position was found.
   * `false` is returned if the node isn't allowed at the current position or in auto paragraph, `true` if was.
   */
  _checkAndAutoParagraphToAllowedPosition(e) {
    if (this.schema.checkChild(this.position.parent, e))
      return !0;
    if (!this.schema.checkChild(this.position.parent, "paragraph") || !this.schema.checkChild("paragraph", e))
      return !1;
    this._insertPartialFragment();
    const t = this.writer.createElement("paragraph");
    return this.writer.insert(t, this.position), this._setAffectedBoundaries(this.position), this._lastAutoParagraph = t, this.position = this.writer.createPositionAt(t, 0), !0;
  }
  /**
   * @returns Whether an allowed position was found.
   * `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.
   */
  _checkAndSplitToAllowedPosition(e) {
    const t = this._getAllowedIn(this.position.parent, e);
    if (!t)
      return !1;
    for (t != this.position.parent && this._insertPartialFragment(); t != this.position.parent; )
      if (this.position.isAtStart) {
        const i = this.position.parent;
        this.position = this.writer.createPositionBefore(i), i.isEmpty && i.parent === t && this.writer.remove(i);
      } else if (this.position.isAtEnd)
        this.position = this.writer.createPositionAfter(this.position.parent);
      else {
        const i = this.writer.createPositionAfter(this.position.parent);
        this._setAffectedBoundaries(this.position), this.writer.split(this.position), this.position = i, this.canMergeWith.add(this.position.nodeAfter);
      }
    return !0;
  }
  /**
   * Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.
   *
   * @param contextElement The element in which context the node should be checked.
   * @param childNode The node to check.
   */
  _getAllowedIn(e, t) {
    return this.schema.checkChild(e, t) ? e : this.schema.isLimit(e) ? null : this._getAllowedIn(e.parent, t);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function vh(n, e, t = "auto") {
  const i = n.getSelectedElement();
  if (i && e.schema.isObject(i) && !e.schema.isInline(i))
    return t == "before" || t == "after" ? e.createRange(e.createPositionAt(i, t)) : e.createRangeOn(i);
  const s = Te(n.getSelectedBlocks());
  if (!s)
    return e.createRange(n.focus);
  if (s.isEmpty)
    return e.createRange(e.createPositionAt(s, 0));
  const r = e.createPositionAfter(s);
  return n.focus.isTouching(r) ? e.createRange(r) : e.createRange(e.createPositionBefore(s));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function wk(n, e, t, i = {}) {
  if (!n.schema.isObject(e))
    throw new d("insertobject-element-not-an-object", n, { object: e });
  const s = t || n.document.selection;
  let r = s;
  i.findOptimalPosition && n.schema.isBlock(e) && (r = n.createSelection(vh(s, n, i.findOptimalPosition)));
  const o = Te(s.getSelectedBlocks()), a = {};
  return o && Object.assign(a, n.schema.getAttributesWithProperty(o, "copyOnReplace", !0)), n.change((l) => {
    r.isCollapsed || n.deleteContent(r, { doNotAutoparagraph: !0 });
    let c = e;
    const u = r.anchor.parent;
    !n.schema.checkChild(u, e) && n.schema.checkChild(u, "paragraph") && n.schema.checkChild("paragraph", e) && (c = l.createElement("paragraph"), l.insert(e, c)), n.schema.setAllowedAttributes(c, a, l);
    const h = n.insertContent(c, r);
    return h.isCollapsed || i.setSelection && bk(l, e, i.setSelection, a), h;
  });
}
function bk(n, e, t, i) {
  const s = n.model;
  if (t == "on") {
    n.setSelection(e, "on");
    return;
  }
  if (t != "after")
    throw new d("insertobject-invalid-place-parameter-value", s);
  let r = e.nextSibling;
  if (s.schema.isInline(e)) {
    n.setSelection(e, "after");
    return;
  }
  !(r && s.schema.checkChild(r, "$text")) && s.schema.checkChild(e.parent, "paragraph") && (r = n.createElement("paragraph"), s.schema.setAllowedAttributes(r, i, n), s.insertContent(r, n.createPositionAfter(e))), r && n.setSelection(r, 0);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const _k = ' ,.?!:;"-()';
function vk(n, e, t = {}) {
  const i = n.schema, s = t.direction != "backward", r = t.unit ? t.unit : "character", o = !!t.treatEmojiAsSingleUnit, a = e.focus, l = new at({
    boundaries: Ek(a, s),
    singleCharacters: !0,
    direction: s ? "forward" : "backward"
  }), c = { walker: l, schema: i, isForward: s, unit: r, treatEmojiAsSingleUnit: o };
  let u;
  for (; u = l.next(); ) {
    if (u.done)
      return;
    const h = yk(c, u.value);
    if (h) {
      e instanceof Ie ? n.change((f) => {
        f.setSelectionFocus(h);
      }) : e.setFocus(h);
      return;
    }
  }
}
function yk(n, e) {
  const { isForward: t, walker: i, unit: s, schema: r, treatEmojiAsSingleUnit: o } = n, { type: a, item: l, nextPosition: c } = e;
  if (a == "text")
    return n.unit === "word" ? Ck(i, t) : kk(i, s, o);
  if (a == (t ? "elementStart" : "elementEnd")) {
    if (r.isSelectable(l))
      return w._createAt(l, t ? "after" : "before");
    if (r.checkChild(c, "$text"))
      return c;
  } else {
    if (r.isLimit(l)) {
      i.skip(() => !0);
      return;
    }
    if (r.checkChild(c, "$text"))
      return c;
  }
}
function kk(n, e, t) {
  const i = n.position.textNode;
  if (i) {
    const s = i.data;
    let r = n.position.offset - i.startOffset;
    for (; Or(s, r) || e == "character" && Mr(s, r) || t && Pu(s, r); )
      n.next(), r = n.position.offset - i.startOffset;
  }
  return n.position;
}
function Ck(n, e) {
  let t = n.position.textNode;
  for (t || (t = e ? n.position.nodeAfter : n.position.nodeBefore); t && t.is("$text"); ) {
    const i = n.position.offset - t.startOffset;
    if (Tk(t, i, e))
      t = e ? n.position.nodeAfter : n.position.nodeBefore;
    else {
      if (Ak(t.data, i, e))
        break;
      n.next();
    }
  }
  return n.position;
}
function Ek(n, e) {
  const t = n.root, i = w._createAt(t, e ? "end" : 0);
  return e ? new g(n, i) : new g(i, n);
}
function Ak(n, e, t) {
  const i = e + (t ? 0 : -1);
  return _k.includes(n.charAt(i));
}
function Tk(n, e, t) {
  return e === (t ? n.offsetSize : 0);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
let Pk = class extends z() {
  // @if CK_DEBUG_ENGINE // private _operationLogs: Array<string>;
  // @if CK_DEBUG_ENGINE // private _appliedOperations: Array<Operation>;
  constructor() {
    super(), this.markers = new Qy(), this.document = new Xy(this), this.schema = new my(), this._pendingChanges = [], this._currentWriter = null, ["deleteContent", "modifySelection", "getSelectedContent", "applyOperation"].forEach((e) => this.decorate(e)), this.on("applyOperation", (e, t) => {
      t[0]._validate();
    }, { priority: "highest" }), this.schema.register("$root", {
      isLimit: !0
    }), this.schema.register("$container", {
      allowIn: ["$root", "$container"]
    }), this.schema.register("$block", {
      allowIn: ["$root", "$container"],
      isBlock: !0
    }), this.schema.register("$blockObject", {
      allowWhere: "$block",
      isBlock: !0,
      isObject: !0
    }), this.schema.register("$inlineObject", {
      allowWhere: "$text",
      allowAttributesOf: "$text",
      isInline: !0,
      isObject: !0
    }), this.schema.register("$text", {
      allowIn: "$block",
      isInline: !0,
      isContent: !0
    }), this.schema.register("$clipboardHolder", {
      allowContentOf: "$root",
      allowChildren: "$text",
      isLimit: !0
    }), this.schema.register("$documentFragment", {
      allowContentOf: "$root",
      allowChildren: "$text",
      isLimit: !0
    }), this.schema.register("$marker"), this.schema.addChildCheck((e, t) => {
      if (t.name === "$marker")
        return !0;
    }), ry(this), this.document.registerPostFixer(rh), this.on("insertContent", (e, [t, i]) => {
      e.return = gk(this, t, i);
    }), this.on("insertObject", (e, [t, i, s]) => {
      e.return = wk(this, t, i, s);
    }), this.on("canEditAt", (e) => {
      const t = !this.document.isReadOnly;
      e.return = t, t || e.stop();
    });
  }
  /**
   * The `change()` method is the primary way of changing the model. You should use it to modify all document nodes
   * (including detached nodes – i.e. nodes not added to the {@link module:engine/model/model~Model#document model document}),
   * the {@link module:engine/model/document~Document#selection document's selection}, and
   * {@link module:engine/model/model~Model#markers model markers}.
   *
   * ```ts
   * model.change( writer => {
   * 	writer.insertText( 'foo', paragraph, 'end' );
   * } );
   * ```
   *
   * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so they are combined
   * into a single undo step.
   *
   * ```ts
   * model.change( writer => {
   * 	writer.insertText( 'foo', paragraph, 'end' ); // foo.
   *
   * 	model.change( writer => {
   * 		writer.insertText( 'bar', paragraph, 'end' ); // foobar.
   * 	} );
   *
   * 	writer.insertText( 'bom', paragraph, 'end' ); // foobarbom.
   * } );
   * ```
   *
   * The callback of the `change()` block is executed synchronously.
   *
   * You can also return a value from the change block.
   *
   * ```ts
   * const img = model.change( writer => {
   * 	return writer.createElement( 'img' );
   * } );
   * ```
   *
   * @see #enqueueChange
   * @typeParam TReturn The return type of the provided callback.
   * @param callback Callback function which may modify the model.
   */
  change(e) {
    try {
      return this._pendingChanges.length === 0 ? (this._pendingChanges.push({ batch: new $t(), callback: e }), this._runPendingChanges()[0]) : e(this._currentWriter);
    } catch (t) {
      /* istanbul ignore next -- @preserve */
      d.rethrowUnexpectedError(t, this);
    }
  }
  enqueueChange(e, t) {
    try {
      e ? typeof e == "function" ? (t = e, e = new $t()) : e instanceof $t || (e = new $t(e)) : e = new $t(), this._pendingChanges.push({ batch: e, callback: t }), this._pendingChanges.length == 1 && this._runPendingChanges();
    } catch (i) {
      /* istanbul ignore next -- @preserve */
      d.rethrowUnexpectedError(i, this);
    }
  }
  /**
   * {@link module:utils/observablemixin~Observable#decorate Decorated} function for applying
   * {@link module:engine/model/operation/operation~Operation operations} to the model.
   *
   * This is a low-level way of changing the model. It is exposed for very specific use cases (like the undo feature).
   * Normally, to modify the model, you will want to use {@link module:engine/model/writer~Writer `Writer`}.
   * See also {@glink framework/architecture/editing-engine#changing-the-model Changing the model} section
   * of the {@glink framework/architecture/editing-engine Editing architecture} guide.
   *
   * @param operation The operation to apply.
   */
  applyOperation(e) {
    e._execute();
  }
  // @if CK_DEBUG_ENGINE // public getAppliedOperation(): string {
  // @if CK_DEBUG_ENGINE // 	if ( !this._appliedOperations ) {
  // @if CK_DEBUG_ENGINE // 		return '';
  // @if CK_DEBUG_ENGINE // 	}
  // @if CK_DEBUG_ENGINE // 	return this._appliedOperations.map( operation => JSON.stringify( operation ) ).join( '-------' );
  // @if CK_DEBUG_ENGINE // }
  // @if CK_DEBUG_ENGINE // public createReplayer( stringifiedOperations: string ): typeof OperationReplayer {
  // @if CK_DEBUG_ENGINE // 	return new OperationReplayer( this, '-------', stringifiedOperations );
  // @if CK_DEBUG_ENGINE // }
  /**
   * Inserts content at the position in the editor specified by the selection, as one would expect the paste
   * functionality to work.
   *
   * **Note**: If you want to insert an {@glink framework/deep-dive/schema#object-elements object element}
   * (e.g. a {@link module:widget/utils~toWidget widget}), see {@link #insertObject} instead.
   *
   * This is a high-level method. It takes the {@link #schema schema} into consideration when inserting
   * the content, clears the given selection's content before inserting nodes and moves the selection
   * to its target position at the end of the process.
   * It can split elements, merge them, wrap bare text nodes with paragraphs, etc. &mdash; just like the
   * pasting feature should do.
   *
   * For lower-level methods see {@link module:engine/model/writer~Writer `Writer`}.
   *
   * This method, unlike {@link module:engine/model/writer~Writer `Writer`}'s methods, does not have to be used
   * inside a {@link #change `change()` block}.
   *
   * # Conversion and schema
   *
   * Inserting elements and text nodes into the model is not enough to make CKEditor 5 render that content
   * to the user. CKEditor 5 implements a model-view-controller architecture and what `model.insertContent()` does
   * is only adding nodes to the model. Additionally, you need to define
   * {@glink framework/architecture/editing-engine#conversion converters} between the model and view
   * and define those nodes in the {@glink framework/architecture/editing-engine#schema schema}.
   *
   * So, while this method may seem similar to CKEditor 4 `editor.insertHtml()` (in fact, both methods
   * are used for paste-like content insertion), the CKEditor 5 method cannot be use to insert arbitrary HTML
   * unless converters are defined for all elements and attributes in that HTML.
   *
   * # Examples
   *
   * Using `insertContent()` with a manually created model structure:
   *
   * ```ts
   * // Let's create a document fragment containing such content as:
   * //
   * // <paragraph>foo</paragraph>
   * // <blockQuote>
   * //    <paragraph>bar</paragraph>
   * // </blockQuote>
   * const docFrag = editor.model.change( writer => {
   * 	const p1 = writer.createElement( 'paragraph' );
   * 	const p2 = writer.createElement( 'paragraph' );
   * 	const blockQuote = writer.createElement( 'blockQuote' );
   * 	const docFrag = writer.createDocumentFragment();
   *
   * 	writer.append( p1, docFrag );
   * 	writer.append( blockQuote, docFrag );
   * 	writer.append( p2, blockQuote );
   * 	writer.insertText( 'foo', p1 );
   * 	writer.insertText( 'bar', p2 );
   *
   * 	return docFrag;
   * } );
   *
   * // insertContent() does not have to be used in a change() block. It can, though,
   * // so this code could be moved to the callback defined above.
   * editor.model.insertContent( docFrag );
   * ```
   *
   * Using `insertContent()` with an HTML string converted to a model document fragment (similar to the pasting mechanism):
   *
   * ```ts
   * // You can create your own HtmlDataProcessor instance or use editor.data.processor
   * // if you have not overridden the default one (which is the HtmlDataProcessor instance).
   * const htmlDP = new HtmlDataProcessor( viewDocument );
   *
   * // Convert an HTML string to a view document fragment:
   * const viewFragment = htmlDP.toView( htmlString );
   *
   * // Convert the view document fragment to a model document fragment
   * // in the context of $root. This conversion takes the schema into
   * // account so if, for example, the view document fragment contained a bare text node,
   * // this text node cannot be a child of $root, so it will be automatically
   * // wrapped with a <paragraph>. You can define the context yourself (in the second parameter),
   * // and e.g. convert the content like it would happen in a <paragraph>.
   * // Note: The clipboard feature uses a custom context called $clipboardHolder
   * // which has a loosened schema.
   * const modelFragment = editor.data.toModel( viewFragment );
   *
   * editor.model.insertContent( modelFragment );
   * ```
   *
   * By default this method will use the document selection but it can also be used with a position, range or selection instance.
   *
   * ```ts
   * // Insert text at the current document selection position.
   * editor.model.change( writer => {
   * 	editor.model.insertContent( writer.createText( 'x' ) );
   * } );
   *
   * // Insert text at a given position - the document selection will not be modified.
   * editor.model.change( writer => {
   * 	editor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );
   *
   * 	// Which is a shorthand for:
   * 	editor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );
   * } );
   * ```
   *
   * If you want the document selection to be moved to the inserted content, use the
   * {@link module:engine/model/writer~Writer#setSelection `setSelection()`} method of the writer after inserting
   * the content:
   *
   * ```ts
   * editor.model.change( writer => {
   * 	const paragraph = writer.createElement( 'paragraph' );
   *
   * 	// Insert an empty paragraph at the beginning of the root.
   * 	editor.model.insertContent( paragraph, writer.createPositionAt( editor.model.document.getRoot(), 0 ) );
   *
   * 	// Move the document selection to the inserted paragraph.
   * 	writer.setSelection( paragraph, 'in' );
   * } );
   * ```
   *
   * If an instance of the {@link module:engine/model/selection~Selection model selection} is passed as `selectable`,
   * the new content will be inserted at the passed selection (instead of document selection):
   *
   * ```ts
   * editor.model.change( writer => {
   * 	// Create a selection in a paragraph that will be used as a place of insertion.
   * 	const selection = writer.createSelection( paragraph, 'in' );
   *
   * 	// Insert the new text at the created selection.
   * 	editor.model.insertContent( writer.createText( 'x' ), selection );
   *
   * 	// insertContent() modifies the passed selection instance so it can be used to set the document selection.
   * 	// Note: This is not necessary when you passed the document selection to insertContent().
   * 	writer.setSelection( selection );
   * } );
   * ```
   *
   * @fires insertContent
   * @param content The content to insert.
   * @param selectable The selection into which the content should be inserted.
   * If not provided the current model document selection will be used.
   * @param placeOrOffset To be used when a model item was passed as `selectable`.
   * This param defines a position in relation to that item.
   * at the insertion position.
   */
  insertContent(e, t, i, ...s) {
    const r = os(t, i);
    return this.fire("insertContent", [e, r, i, ...s]);
  }
  /**
   * Inserts an {@glink framework/deep-dive/schema#object-elements object element} at a specific position in the editor content.
   *
   * This is a high-level API:
   * * It takes the {@link #schema schema} into consideration,
   * * It clears the content of passed `selectable` before inserting,
   * * It can move the selection at the end of the process,
   * * It will copy the selected block's attributes to preserve them upon insertion,
   * * It can split elements or wrap inline objects with paragraphs if they are not allowed in target position,
   * * etc.
   *
   * # Notes
   *
   * * If you want to insert a non-object content, see {@link #insertContent} instead.
   * * For lower-level API, see {@link module:engine/model/writer~Writer `Writer`}.
   * * Unlike {@link module:engine/model/writer~Writer `Writer`}, this method does not have to be used inside
   * a {@link #change `change()` block}.
   * * Inserting object into the model is not enough to make CKEditor 5 render that content to the user.
   * CKEditor 5 implements a model-view-controller architecture and what `model.insertObject()` does
   * is only adding nodes to the model. Additionally, you need to define
   * {@glink framework/architecture/editing-engine#conversion converters} between the model and view
   * and define those nodes in the {@glink framework/architecture/editing-engine#schema schema}.
   *
   * # Examples
   *
   * Use the following code to insert an object at the current selection and keep the selection on the inserted element:
   *
   * ```ts
   * const rawHtmlEmbedElement = writer.createElement( 'rawHtml' );
   *
   * model.insertObject( rawHtmlEmbedElement, null, null, {
   * 	setSelection: 'on'
   * } );
   * ```
   *
   * Use the following code to insert an object at the current selection and nudge the selection after the inserted object:
   *
   * ```ts
   * const pageBreakElement = writer.createElement( 'pageBreak' );
   *
   * model.insertObject( pageBreakElement, null, null, {
   * 	setSelection: 'after'
   * } );
   * ```
   *
   * Use the following code to insert an object at the current selection and avoid splitting the content (non-destructive insertion):
   *
   * ```ts
   * const tableElement = writer.createElement( 'table' );
   *
   * model.insertObject( tableElement, null, null, {
   * 	findOptimalPosition: 'auto'
   * } );
   * ```
   *
   * Use the following code to insert an object at the specific range (also: replace the content of the range):
   *
   * ```ts
   * const tableElement = writer.createElement( 'table' );
   * const range = model.createRangeOn( model.document.getRoot().getChild( 1 ) );
   *
   * model.insertObject( tableElement, range );
   * ```
   *
   * @param element An object to be inserted into the model document.
   * @param selectable A selectable where the content should be inserted. If not specified, the current
   * {@link module:engine/model/document~Document#selection document selection} will be used instead.
   * @param placeOrOffset Specifies the exact place or offset for the insertion to take place, relative to `selectable`.
   * @param options Additional options.
   * @param options.findOptimalPosition An option that, when set, adjusts the insertion position (relative to
   * `selectable` and `placeOrOffset`) so that the content of `selectable` is not split upon insertion (a.k.a. non-destructive insertion).
   * * When `'auto'`, the algorithm will decide whether to insert the object before or after `selectable` to avoid content splitting.
   * * When `'before'`, the closest position before `selectable` will be used that will not result in content splitting.
   * * When `'after'`, the closest position after `selectable` will be used that will not result in content splitting.
   *
   * Note that this option only works for block objects. Inline objects are inserted into text and do not split blocks.
   * @param options.setSelection An option that, when set, moves the
   * {@link module:engine/model/document~Document#selection document selection} after inserting the object.
   * * When `'on'`, the document selection will be set on the inserted object.
   * * When `'after'`, the document selection will move to the closest text node after the inserted object. If there is no
   * such text node, a paragraph will be created and the document selection will be moved inside it.
   * at the insertion position.
   */
  insertObject(e, t, i, s, ...r) {
    const o = os(t, i);
    return this.fire("insertObject", [e, o, s, s, ...r]);
  }
  /**
   * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.
   *
   * **Note:** For the sake of predictability, the resulting selection should always be collapsed.
   * In cases where a feature wants to modify deleting behavior so selection isn't collapsed
   * (e.g. a table feature may want to keep row selection after pressing <kbd>Backspace</kbd>),
   * then that behavior should be implemented in the view's listener. At the same time, the table feature
   * will need to modify this method's behavior too, e.g. to "delete contents and then collapse
   * the selection inside the last selected cell" or "delete the row and collapse selection somewhere near".
   * That needs to be done in order to ensure that other features which use `deleteContent()` will work well with tables.
   *
   * @fires deleteContent
   * @param selection Selection of which the content should be deleted.
   * @param options.leaveUnmerged Whether to merge elements after removing the content of the selection.
   *
   * For example `<heading1>x[x</heading1><paragraph>y]y</paragraph>` will become:
   *
   * * `<heading1>x^y</heading1>` with the option disabled (`leaveUnmerged == false`)
   * * `<heading1>x^</heading1><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).
   *
   * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}
   * elements will not be merged.
   *
   * @param options.doNotResetEntireContent Whether to skip replacing the entire content with a
   * paragraph when the entire content was selected.
   *
   * For example `<heading1>[x</heading1><paragraph>y]</paragraph>` will become:
   *
   * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)
   * * `<heading1>^</heading1>` with enabled (`doNotResetEntireContent == true`)
   *
   * @param options.doNotAutoparagraph Whether to create a paragraph if after content deletion selection is moved
   * to a place where text cannot be inserted.
   *
   * For example `<paragraph>x</paragraph>[<imageBlock src="foo.jpg"></imageBlock>]` will become:
   *
   * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)
   * * `<paragraph>x[]</paragraph>` with the option enabled (`doNotAutoparagraph == true`).
   *
   * **Note:** if there is no valid position for the selection, the paragraph will always be created:
   *
   * `[<imageBlock src="foo.jpg"></imageBlock>]` -> `<paragraph>[]</paragraph>`.
   *
   * @param options.direction The direction in which the content is being consumed.
   * Deleting backward corresponds to using the <kbd>Backspace</kbd> key, while deleting content forward corresponds to
   * the <kbd>Shift</kbd>+<kbd>Backspace</kbd> keystroke.
   */
  deleteContent(e, t) {
    sk(this, e, t);
  }
  /**
   * Modifies the selection. Currently, the supported modifications are:
   *
   * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.
   * Possible values for `unit` are:
   *  * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one
   *  character in `String` sense. However, unicode also defines "combing marks". These are special symbols, that combines
   *  with a symbol before it ("base character") to create one user-perceived character. For example, `q̣̇` is a normal
   *  letter `q` with two "combining marks": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending
   *  selection by one position, it is correct to include both "base character" and all of it's "combining marks". That is
   *  why `'character'` value is most natural and common method of modifying selection.
   *  * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert
   *  selection between "base character" and "combining mark", because "combining marks" have their own unicode code points.
   *  However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by
   *  two characters, called "surrogate pairs". Halves of "surrogate pairs" have a meaning only when placed next to each other.
   *  For example `𨭎` is represented in `String` by `\uD862\uDF4E`. Both `\uD862` and `\uDF4E` do not have any meaning
   *  outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection
   *  extension will include whole "surrogate pair".
   *  * `'word'` - moves selection by a whole word.
   *
   * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.
   *
   * @fires modifySelection
   * @param selection The selection to modify.
   * @param options.direction The direction in which the selection should be modified.
   * @param options.unit The unit by which selection should be modified.
   * @param options.treatEmojiAsSingleUnit Whether multi-characer emoji sequences should be handled as single unit.
   */
  modifySelection(e, t) {
    vk(this, e, t);
  }
  /**
   * Gets a clone of the selected content.
   *
   * For example, for the following selection:
   *
   * ```html
   * <paragraph>x</paragraph>
   * <blockQuote>
   * 	<paragraph>y</paragraph>
   * 	<heading1>fir[st</heading1>
   * </blockQuote>
   * <paragraph>se]cond</paragraph>
   * <paragraph>z</paragraph>
   * ```
   *
   * It will return a document fragment with such a content:
   *
   * ```html
   * <blockQuote>
   * 	<heading1>st</heading1>
   * </blockQuote>
   * <paragraph>se</paragraph>
   * ```
   *
   * @fires getSelectedContent
   * @param selection The selection of which content will be returned.
   */
  getSelectedContent(e) {
    return mk(this, e);
  }
  /**
   * Checks whether the given {@link module:engine/model/range~Range range} or
   * {@link module:engine/model/element~Element element} has any meaningful content.
   *
   * Meaningful content is:
   *
   * * any text node (`options.ignoreWhitespaces` allows controlling whether this text node must also contain
   * any non-whitespace characters),
   * * or any {@link module:engine/model/schema~Schema#isContent content element},
   * * or any {@link module:engine/model/markercollection~Marker marker} which
   * {@link module:engine/model/markercollection~Marker#_affectsData affects data}.
   *
   * This means that a range containing an empty `<paragraph></paragraph>` is not considered to have a meaningful content.
   * However, a range containing an `<imageBlock></imageBlock>` (which would normally be marked in the schema as an object element)
   * is considered non-empty.
   *
   * @param rangeOrElement Range or element to check.
   * @param options.ignoreWhitespaces Whether text node with whitespaces only should be considered empty.
   * @param options.ignoreMarkers Whether markers should be ignored.
   */
  hasContent(e, t = {}) {
    const i = e instanceof g ? e : g._createIn(e);
    if (i.isCollapsed)
      return !1;
    const { ignoreWhitespaces: s = !1, ignoreMarkers: r = !1 } = t;
    if (!r) {
      for (const o of this.markers.getMarkersIntersectingRange(i))
        if (o.affectsData)
          return !0;
    }
    for (const o of i.getItems())
      if (this.schema.isContent(o))
        if (o.is("$textProxy"))
          if (s) {
            if (o.data.search(/\S/) !== -1)
              return !0;
          } else
            return !0;
        else
          return !0;
    return !1;
  }
  /**
   * Check whether given selectable is at a place in the model where it can be edited (returns `true`) or not (returns `false`).
   *
   * Should be used instead of {@link module:core/editor/editor~Editor#isReadOnly} to check whether a user action can happen at
   * given selectable. It may be decorated and used differently in different environment (e.g. multi-root editor can disable
   * a particular root).
   *
   * This method is decorated. Although this method accepts any parameter of `Selectable` type, the
   * {@link ~Model#event:canEditAt `canEditAt` event} is fired with `selectable` normalized to an instance of
   * {@link module:engine/model/selection~Selection} or {@link module:engine/model/documentselection~DocumentSelection}
   *
   * @fires canEditAt
   */
  canEditAt(e) {
    const t = os(e);
    return this.fire("canEditAt", [t]);
  }
  /**
   * Creates a position from the given root and path in that root.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createPositionFromPath `Writer#createPositionFromPath()`}.
   *
   * @param root Root of the position.
   * @param path Position path. See {@link module:engine/model/position~Position#path}.
   * @param stickiness Position stickiness. See {@link module:engine/model/position~PositionStickiness}.
   */
  createPositionFromPath(e, t, i) {
    return new w(e, t, i);
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/model/position~Position position},
   * * a parent element and offset in that element,
   * * a parent element and `'end'` (the position will be set at the end of that element),
   * * a {@link module:engine/model/item~Item model item} and `'before'` or `'after'`
   * (the position will be set before or after the given model item).
   *
   * This method is a shortcut to other factory methods such as:
   *
   * * {@link module:engine/model/model~Model#createPositionBefore `createPositionBefore()`},
   * * {@link module:engine/model/model~Model#createPositionAfter `createPositionAfter()`}.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createPositionAt `Writer#createPositionAt()`},
   *
   * @param itemOrPosition
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/model/item~Item model item}.
   */
  createPositionAt(e, t) {
    return w._createAt(e, t);
  }
  /**
   * Creates a new position after the given {@link module:engine/model/item~Item model item}.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createPositionAfter `Writer#createPositionAfter()`}.
   *
   * @param item Item after which the position should be placed.
   */
  createPositionAfter(e) {
    return w._createAfter(e);
  }
  /**
   * Creates a new position before the given {@link module:engine/model/item~Item model item}.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createPositionBefore `Writer#createPositionBefore()`}.
   *
   * @param item Item before which the position should be placed.
   */
  createPositionBefore(e) {
    return w._createBefore(e);
  }
  /**
   * Creates a range spanning from the `start` position to the `end` position.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createRange `Writer#createRange()`}:
   *
   * ```ts
   * model.change( writer => {
   * 	const range = writer.createRange( start, end );
   * } );
   * ```
   *
   * @param start Start position.
   * @param end End position. If not set, the range will be collapsed to the `start` position.
   */
  createRange(e, t) {
    return new g(e, t);
  }
  /**
   * Creates a range inside the given element which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * Note: This method is also available as
   * {@link module:engine/model/writer~Writer#createRangeIn `Writer#createRangeIn()`}:
   *
   * ```ts
   * model.change( writer => {
   * 	const range = writer.createRangeIn( paragraph );
   * } );
   * ```
   *
   * @param element Element which is a parent for the range.
   */
  createRangeIn(e) {
    return g._createIn(e);
  }
  /**
   * Creates a range that starts before the given {@link module:engine/model/item~Item model item} and ends after it.
   *
   * Note: This method is also available on `writer` instance as
   * {@link module:engine/model/writer~Writer#createRangeOn `Writer.createRangeOn()`}:
   *
   * ```ts
   * model.change( writer => {
   * 	const range = writer.createRangeOn( paragraph );
   * } );
   * ```
   *
   * @param item
   */
  createRangeOn(e) {
    return g._createOn(e);
  }
  createSelection(...e) {
    return new we(...e);
  }
  /**
   * Creates a {@link module:engine/model/batch~Batch} instance.
   *
   * **Note:** In most cases creating a batch instance is not necessary as they are created when using:
   *
   * * {@link #change `change()`},
   * * {@link #enqueueChange `enqueueChange()`}.
   *
   * @param type {@link module:engine/model/batch~Batch#constructor The type} of the batch.
   */
  createBatch(e) {
    return new $t(e);
  }
  /**
   * Creates an operation instance from a JSON object (parsed JSON string).
   *
   * This is an alias for {@link module:engine/model/operation/operationfactory~OperationFactory.fromJSON `OperationFactory.fromJSON()`}.
   *
   * @param json Deserialized JSON object.
   */
  createOperationFromJSON(e) {
    return $y.fromJSON(e, this.document);
  }
  /**
   * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.
   */
  destroy() {
    this.document.destroy(), this.stopListening();
  }
  /**
   * Common part of {@link module:engine/model/model~Model#change} and {@link module:engine/model/model~Model#enqueueChange}
   * which calls callbacks and returns array of values returned by these callbacks.
   *
   */
  _runPendingChanges() {
    const e = [];
    this.fire("_beforeChanges");
    try {
      for (; this._pendingChanges.length; ) {
        const t = this._pendingChanges[0].batch;
        this._currentWriter = new ik(this, t);
        const i = this._pendingChanges[0].callback(this._currentWriter);
        e.push(i), this.document._handleChangeBlock(this._currentWriter), this._pendingChanges.shift(), this._currentWriter = null;
      }
    } finally {
      this._pendingChanges.length = 0, this._currentWriter = null, this.fire("_afterChanges");
    }
    return e;
  }
};
function os(n, e) {
  if (n)
    return n instanceof we || n instanceof Ie ? n : n instanceof Bt ? e || e === 0 ? new we(n, e) : n.is("rootElement") ? new we(n, "in") : new we(n, "on") : new we(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class xk extends Dt {
  constructor() {
    super(...arguments), this.domEventType = "click";
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    this.fire(e.type, e);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ln extends Dt {
  constructor() {
    super(...arguments), this.domEventType = ["mousedown", "mouseup", "mouseover", "mouseout"];
  }
  /**
   * @inheritDoc
   */
  onDomEvent(e) {
    this.fire(e.type, e);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Wr {
  /**
   * @param document The view document instance in which this upcast writer operates.
   */
  constructor(e) {
    this.document = e;
  }
  /**
   * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.
   *
   * @param children A list of nodes to be inserted into the created document fragment.
   * @returns The created document fragment.
   */
  createDocumentFragment(e) {
    return new At(this.document, e);
  }
  /**
   * Creates a new {@link module:engine/view/element~Element} instance.
   *
   * Attributes can be passed in various formats:
   *
   * ```ts
   * upcastWriter.createElement( 'div', { class: 'editor', contentEditable: 'true' } ); // object
   * upcastWriter.createElement( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator
   * upcastWriter.createElement( 'div', mapOfAttributes ); // map
   * ```
   *
   * @param name Node name.
   * @param attrs Collection of attributes.
   * @param children A list of nodes to be inserted into created element.
   * @returns Created element.
   */
  createElement(e, t, i) {
    return new Se(this.document, e, t, i);
  }
  /**
   * Creates a new {@link module:engine/view/text~Text} instance.
   *
   * @param data The text's data.
   * @returns The created text node.
   */
  createText(e) {
    return new j(this.document, e);
  }
  /**
   * Clones the provided element.
   *
   * @see module:engine/view/element~Element#_clone
   * @param element Element to be cloned.
   * @param deep If set to `true` clones element and all its children recursively. When set to `false`,
   * element will be cloned without any children.
   * @returns Clone of this element.
   */
  clone(e, t = !1) {
    return e._clone(t);
  }
  /**
   * Appends a child node or a list of child nodes at the end of this node
   * and sets the parent of these nodes to this element.
   *
   * @see module:engine/view/element~Element#_appendChild
   * @param items Items to be inserted.
   * @param element Element to which items will be appended.
   * @returns Number of appended nodes.
   */
  appendChild(e, t) {
    return t._appendChild(e);
  }
  /**
   * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to
   * this element.
   *
   * @see module:engine/view/element~Element#_insertChild
   * @param index Offset at which nodes should be inserted.
   * @param items Items to be inserted.
   * @param element Element to which items will be inserted.
   * @returns Number of inserted nodes.
   */
  insertChild(e, t, i) {
    return i._insertChild(e, t);
  }
  /**
   * Removes the given number of child nodes starting at the given index and set the parent of these nodes to `null`.
   *
   * @see module:engine/view/element~Element#_removeChildren
   * @param index Offset from which nodes will be removed.
   * @param howMany Number of nodes to remove.
   * @param element Element which children will be removed.
   * @returns The array containing removed nodes.
   */
  removeChildren(e, t, i) {
    return i._removeChildren(e, t);
  }
  /**
   * Removes given element from the view structure. Will not have effect on detached elements.
   *
   * @param element Element which will be removed.
   * @returns The array containing removed nodes.
   */
  remove(e) {
    const t = e.parent;
    return t ? this.removeChildren(t.getChildIndex(e), 1, t) : [];
  }
  /**
   * Replaces given element with the new one in the view structure. Will not have effect on detached elements.
   *
   * @param oldElement Element which will be replaced.
   * @param newElement Element which will be inserted in the place of the old element.
   * @returns Whether old element was successfully replaced.
   */
  replace(e, t) {
    const i = e.parent;
    if (i) {
      const s = i.getChildIndex(e);
      return this.removeChildren(s, 1, i), this.insertChild(s, t, i), !0;
    }
    return !1;
  }
  /**
   * Removes given element from view structure and places its children in its position.
   * It does nothing if element has no parent.
   *
   * @param element Element to unwrap.
   */
  unwrapElement(e) {
    const t = e.parent;
    if (t) {
      const i = t.getChildIndex(e);
      this.remove(e), this.insertChild(i, e.getChildren(), t);
    }
  }
  /**
   * Renames element by creating a copy of a given element but with its name changed and then moving contents of the
   * old element to the new one.
   *
   * Since this function creates a new element and removes the given one, the new element is returned to keep reference.
   *
   * @param newName New element name.
   * @param  element Element to be renamed.
   * @returns New element or null if the old element was not replaced (happens for detached elements).
   */
  rename(e, t) {
    const i = new Se(this.document, e, t.getAttributes(), t.getChildren());
    return this.replace(t, i) ? i : null;
  }
  /**
   * Adds or overwrites element's attribute with a specified key and value.
   *
   * ```ts
   * writer.setAttribute( 'href', 'http://ckeditor.com', linkElement );
   * ```
   *
   * @see module:engine/view/element~Element#_setAttribute
   * @param key Attribute key.
   * @param value Attribute value.
   * @param element Element for which attribute will be set.
   */
  setAttribute(e, t, i) {
    i._setAttribute(e, t);
  }
  /**
   * Removes attribute from the element.
   *
   * ```ts
   * writer.removeAttribute( 'href', linkElement );
   * ```
   *
   * @see module:engine/view/element~Element#_removeAttribute
   * @param key Attribute key.
   * @param element Element from which attribute will be removed.
   */
  removeAttribute(e, t) {
    t._removeAttribute(e);
  }
  /**
   * Adds specified class to the element.
   *
   * ```ts
   * writer.addClass( 'foo', linkElement );
   * writer.addClass( [ 'foo', 'bar' ], linkElement );
   * ```
   *
   * @see module:engine/view/element~Element#_addClass
   * @param className Single class name or array of class names which will be added.
   * @param element Element for which class will be added.
   */
  addClass(e, t) {
    t._addClass(e);
  }
  /**
   * Removes specified class from the element.
   *
   * ```ts
   * writer.removeClass( 'foo', linkElement );
   * writer.removeClass( [ 'foo', 'bar' ], linkElement );
   * ```
   *
   * @see module:engine/view/element~Element#_removeClass
   * @param className Single class name or array of class names which will be removed.
   * @param element Element from which class will be removed.
   */
  removeClass(e, t) {
    t._removeClass(e);
  }
  setStyle(e, t, i) {
    de(e) && i === void 0 ? t._setStyle(e) : i._setStyle(e, t);
  }
  /**
   * Removes specified style from the element.
   *
   * ```ts
   * writer.removeStyle( 'color', element );  // Removes 'color' style.
   * writer.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.
   * ```
   *
   * **Note**: This method can work with normalized style names if
   * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.
   * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.
   *
   * @see module:engine/view/element~Element#_removeStyle
   * @param property Style property name or names to be removed.
   * @param element Element from which style will be removed.
   */
  removeStyle(e, t) {
    t._removeStyle(e);
  }
  /**
   * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,
   * so they can be used to add special data to elements.
   *
   * @see module:engine/view/element~Element#_setCustomProperty
   * @param key Custom property name/key.
   * @param value Custom property value to be stored.
   * @param element Element for which custom property will be set.
   */
  setCustomProperty(e, t, i) {
    i._setCustomProperty(e, t);
  }
  /**
   * Removes a custom property stored under the given key.
   *
   * @see module:engine/view/element~Element#_removeCustomProperty
   * @param key Name/key of the custom property to be removed.
   * @param element Element from which the custom property will be removed.
   * @returns Returns true if property was removed.
   */
  removeCustomProperty(e, t) {
    return t._removeCustomProperty(e);
  }
  /**
   * Creates position at the given location. The location can be specified as:
   *
   * * a {@link module:engine/view/position~Position position},
   * * parent element and offset (offset defaults to `0`),
   * * parent element and `'end'` (sets position at the end of that element),
   * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).
   *
   * This method is a shortcut to other constructors such as:
   *
   * * {@link #createPositionBefore},
   * * {@link #createPositionAfter},
   *
   * @param offset Offset or one of the flags. Used only when first parameter is a {@link module:engine/view/item~Item view item}.
   */
  createPositionAt(e, t) {
    return v._createAt(e, t);
  }
  /**
   * Creates a new position after given view item.
   *
   * @param item View item after which the position should be located.
   */
  createPositionAfter(e) {
    return v._createAfter(e);
  }
  /**
   * Creates a new position before given view item.
   *
   * @param item View item before which the position should be located.
   */
  createPositionBefore(e) {
    return v._createBefore(e);
  }
  /**
   * Creates a range spanning from `start` position to `end` position.
   *
   * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.
   *
   * @param start Start position.
   * @param end End position. If not set, range will be collapsed at `start` position.
   */
  createRange(e, t) {
    return new P(e, t);
  }
  /**
   * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.
   */
  createRangeOn(e) {
    return P._createOn(e);
  }
  /**
   * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of
   * that element and ends after the last child of that element.
   *
   * @param element Element which is a parent for the range.
   */
  createRangeIn(e) {
    return P._createIn(e);
  }
  createSelection(...e) {
    return new ct(...e);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Sk {
  /**
   * Creates collection instance.
   */
  constructor() {
    this._commands = /* @__PURE__ */ new Map();
  }
  /**
   * Registers a new command.
   *
   * @param commandName The name of the command.
   */
  add(e, t) {
    this._commands.set(e, t);
  }
  /**
   * Retrieves a command from the collection.
   *
   * @param commandName The name of the command.
   */
  get(e) {
    return this._commands.get(e);
  }
  /**
   * Executes a command.
   *
   * @param commandName The name of the command.
   * @param commandParams Command parameters.
   * @returns The value returned by the {@link module:core/command~Command#execute `command.execute()`}.
   */
  execute(e, ...t) {
    const i = this.get(e);
    if (!i)
      throw new d("commandcollection-command-not-found", this, { commandName: e });
    return i.execute(...t);
  }
  /**
   * Returns iterator of command names.
   */
  *names() {
    yield* this._commands.keys();
  }
  /**
   * Returns iterator of command instances.
   */
  *commands() {
    yield* this._commands.values();
  }
  /**
   * Iterable interface.
   *
   * Returns `[ commandName, commandInstance ]` pairs.
   */
  [Symbol.iterator]() {
    return this._commands[Symbol.iterator]();
  }
  /**
   * Destroys all collection commands.
   */
  destroy() {
    for (const e of this.commands())
      e.destroy();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ik extends Oe {
  /**
   * Creates an instance of the keystroke handler.
   */
  constructor(e) {
    super(), this.editor = e;
  }
  /**
   * Registers a handler for the specified keystroke.
   *
   * The handler can be specified as a command name or a callback.
   *
   * @param keystroke Keystroke defined in a format accepted by
   * the {@link module:utils/keyboard~parseKeystroke} function.
   * @param callback If a string is passed, then the keystroke will
   * {@link module:core/editor/editor~Editor#execute execute a command}.
   * If a function, then it will be called with the
   * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
   * a `cancel()` helper to both `preventDefault()` and `stopPropagation()` of the event.
   * @param options Additional options.
   * @param options.priority The priority of the keystroke callback. The higher the priority value
   * the sooner the callback will be executed. Keystrokes having the same priority
   * are called in the order they were added.
   */
  set(e, t, i = {}) {
    if (typeof t == "string") {
      const s = t;
      t = (r, o) => {
        this.editor.execute(s), o();
      };
    }
    super.set(e, t, i);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Rk extends z() {
  /**
   * Creates a new instance of the editor class.
   *
   * Usually, not to be used directly. See the static {@link module:core/editor/editor~Editor.create `create()`} method.
   *
   * @param config The editor configuration.
   */
  constructor(e = {}) {
    super();
    const t = this.constructor, i = e.language || t.defaultConfig && t.defaultConfig.language;
    this._context = e.context || new Su({ language: i }), this._context._addEditor(this, !e.context);
    const s = Array.from(t.builtinPlugins || []);
    this.config = new hu(e, t.defaultConfig), this.config.define("plugins", s), this.config.define(this._context._getEditorConfig()), this.plugins = new xu(this, s, this._context.plugins), this.locale = this._context.locale, this.t = this.locale.t, this._readOnlyLocks = /* @__PURE__ */ new Set(), this.commands = new Sk(), this.set("state", "initializing"), this.once("ready", () => this.state = "ready", { priority: "high" }), this.once("destroy", () => this.state = "destroyed", { priority: "high" }), this.model = new Pk(), this.on("change:isReadOnly", () => {
      this.model.document.isReadOnly = this.isReadOnly;
    });
    const r = new m1();
    this.data = new By(this.model, r), this.editing = new hy(this.model, r), this.editing.view.document.bind("isReadOnly").to(this), this.conversion = new Ny([this.editing.downcastDispatcher, this.data.downcastDispatcher], this.data.upcastDispatcher), this.conversion.addAlias("dataDowncast", this.data.downcastDispatcher), this.conversion.addAlias("editingDowncast", this.editing.downcastDispatcher), this.keystrokes = new Ik(this), this.keystrokes.listenTo(this.editing.view.document);
  }
  /**
   * Defines whether the editor is in the read-only mode.
   *
   * In read-only mode the editor {@link #commands commands} are disabled so it is not possible
   * to modify the document by using them. Also, the editable element(s) become non-editable.
   *
   * In order to make the editor read-only, you need to call the {@link #enableReadOnlyMode} method:
   *
   * ```ts
   * editor.enableReadOnlyMode( 'feature-id' );
   * ```
   *
   * Later, to turn off the read-only mode, call {@link #disableReadOnlyMode}:
   *
   * ```ts
   * editor.disableReadOnlyMode( 'feature-id' );
   * ```
   *
   * @readonly
   * @observable
   */
  get isReadOnly() {
    return this._readOnlyLocks.size > 0;
  }
  set isReadOnly(e) {
    throw new d("editor-isreadonly-has-no-setter");
  }
  /**
   * Turns on the read-only mode in the editor.
   *
   * Editor can be switched to or out of the read-only mode by many features, under various circumstances. The editor supports locking
   * mechanism for the read-only mode. It enables easy control over the read-only mode when many features wants to turn it on or off at
   * the same time, without conflicting with each other. It guarantees that you will not make the editor editable accidentally (which
   * could lead to errors).
   *
   * Each read-only mode request is identified by a unique id (also called "lock"). If multiple plugins requested to turn on the
   * read-only mode, then, the editor will become editable only after all these plugins turn the read-only mode off (using the same ids).
   *
   * Note, that you cannot force the editor to disable the read-only mode if other plugins set it.
   *
   * After the first `enableReadOnlyMode()` call, the {@link #isReadOnly `isReadOnly` property} will be set to `true`:
   *
   * ```ts
   * editor.isReadOnly; // `false`.
   * editor.enableReadOnlyMode( 'my-feature-id' );
   * editor.isReadOnly; // `true`.
   * ```
   *
   * You can turn off the read-only mode ("clear the lock") using the {@link #disableReadOnlyMode `disableReadOnlyMode()`} method:
   *
   * ```ts
   * editor.enableReadOnlyMode( 'my-feature-id' );
   * // ...
   * editor.disableReadOnlyMode( 'my-feature-id' );
   * editor.isReadOnly; // `false`.
   * ```
   *
   * All "locks" need to be removed to enable editing:
   *
   * ```ts
   * editor.enableReadOnlyMode( 'my-feature-id' );
   * editor.enableReadOnlyMode( 'my-other-feature-id' );
   * // ...
   * editor.disableReadOnlyMode( 'my-feature-id' );
   * editor.isReadOnly; // `true`.
   * editor.disableReadOnlyMode( 'my-other-feature-id' );
   * editor.isReadOnly; // `false`.
   * ```
   *
   * @param lockId A unique ID for setting the editor to the read-only state.
   */
  enableReadOnlyMode(e) {
    if (typeof e != "string" && typeof e != "symbol")
      throw new d("editor-read-only-lock-id-invalid", null, { lockId: e });
    this._readOnlyLocks.has(e) || (this._readOnlyLocks.add(e), this._readOnlyLocks.size === 1 && this.fire("change:isReadOnly", "isReadOnly", !0, !1));
  }
  /**
   * Removes the read-only lock from the editor with given lock ID.
   *
   * When no lock is present on the editor anymore, then the {@link #isReadOnly `isReadOnly` property} will be set to `false`.
   *
   * @param lockId The lock ID for setting the editor to the read-only state.
   */
  disableReadOnlyMode(e) {
    if (typeof e != "string" && typeof e != "symbol")
      throw new d("editor-read-only-lock-id-invalid", null, { lockId: e });
    this._readOnlyLocks.has(e) && (this._readOnlyLocks.delete(e), this._readOnlyLocks.size === 0 && this.fire("change:isReadOnly", "isReadOnly", !1, !0));
  }
  /**
   * Loads and initializes plugins specified in the configuration.
   *
   * @returns A promise which resolves once the initialization is completed, providing an array of loaded plugins.
   */
  initPlugins() {
    const e = this.config, t = e.get("plugins"), i = e.get("removePlugins") || [], s = e.get("extraPlugins") || [], r = e.get("substitutePlugins") || [];
    return this.plugins.init(t.concat(s), i, r);
  }
  /**
   * Destroys the editor instance, releasing all resources used by it.
   *
   * **Note** The editor cannot be destroyed during the initialization phase so if it is called
   * while the editor {@link #state is being initialized}, it will wait for the editor initialization before destroying it.
   *
   * @fires destroy
   * @returns A promise that resolves once the editor instance is fully destroyed.
   */
  destroy() {
    let e = Promise.resolve();
    return this.state == "initializing" && (e = new Promise((t) => this.once("ready", t))), e.then(() => {
      this.fire("destroy"), this.stopListening(), this.commands.destroy();
    }).then(() => this.plugins.destroy()).then(() => {
      this.model.destroy(), this.data.destroy(), this.editing.destroy(), this.keystrokes.destroy();
    }).then(() => this._context._removeEditor(this));
  }
  /**
   * Executes the specified command with given parameters.
   *
   * Shorthand for:
   *
   * ```ts
   * editor.commands.get( commandName ).execute( ... );
   * ```
   *
   * @param commandName The name of the command to execute.
   * @param commandParams Command parameters.
   * @returns The value returned by the {@link module:core/commandcollection~CommandCollection#execute `commands.execute()`}.
   */
  execute(e, ...t) {
    try {
      return this.commands.execute(e, ...t);
    } catch (i) {
      /* istanbul ignore next -- @preserve */
      d.rethrowUnexpectedError(i, this);
    }
  }
  /**
   * Focuses the editor.
   *
   * **Note** To explicitly focus the editing area of the editor, use the
   * {@link module:engine/view/view~View#focus `editor.editing.view.focus()`} method of the editing view.
   *
   * Check out the {@glink framework/deep-dive/ui/focus-tracking#focus-in-the-editor-ui Focus in the editor UI} section
   * of the {@glink framework/deep-dive/ui/focus-tracking Deep dive into focus tracking} guide to learn more.
   */
  focus() {
    this.editing.view.focus();
  }
  /* istanbul ignore next -- @preserve */
  /**
   * Creates and initializes a new editor instance.
   *
   * This is an abstract method. Every editor type needs to implement its own initialization logic.
   *
   * See the `create()` methods of the existing editor types to learn how to use them:
   *
   * * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}
   * * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}
   * * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}
   * * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}
   */
  static create(...e) {
    throw new Error("This is an abstract method.");
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Ok(n) {
  if (!Pt(n.updateSourceElement))
    throw new d("attachtoform-missing-elementapi-interface", n);
  const e = n.sourceElement;
  if (Mk(e) && e.form) {
    let t;
    const i = e.form, s = () => n.updateSourceElement();
    Pt(i.submit) && (t = i.submit, i.submit = () => {
      s(), t.apply(i);
    }), i.addEventListener("submit", s), n.on("destroy", () => {
      i.removeEventListener("submit", s), t && (i.submit = t);
    });
  }
}
function Mk(n) {
  return !!n && n.tagName.toLowerCase() === "textarea";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function on(n) {
  class e extends n {
    setData(i) {
      this.data.set(i);
    }
    getData(i) {
      return this.data.get(i);
    }
  }
  return e;
}
{
  const n = on(Object);
  on.setData = n.prototype.setData, on.getData = n.prototype.getData;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function er(n) {
  class e extends n {
    updateSourceElement(i = this.data.get()) {
      if (!this.sourceElement)
        throw new d("editor-missing-sourceelement", this);
      const s = this.config.get("updateSourceElementOnDestroy"), r = this.sourceElement instanceof HTMLTextAreaElement;
      if (!s && !r) {
        ia(this.sourceElement, "");
        return;
      }
      ia(this.sourceElement, i);
    }
  }
  return e;
}
er.updateSourceElement = er(Object).prototype.updateSourceElement;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Vk(n, e) {
  if (e.ckeditorInstance)
    throw new d("editor-source-element-already-used", n);
  e.ckeditorInstance = n, n.once("destroy", () => {
    delete e.ckeditorInstance;
  });
}
const Dk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.591 10.177 4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z"/></svg>', Bk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 16h9a1 1 0 0 1 0 2H2a1 1 0 0 1 0-2z"/><path d="M17 1a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h14zm0 1.5H3a.5.5 0 0 0-.492.41L2.5 3v9a.5.5 0 0 0 .41.492L3 12.5h14a.5.5 0 0 0 .492-.41L17.5 12V3a.5.5 0 0 0-.41-.492L17 2.5z" fill-opacity=".6"/></svg>', Fk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z"/></svg>', Nk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.333 2 .19 2.263a5.899 5.899 0 0 1 1.458.604L14.714 3.4 16.6 5.286l-1.467 1.733c.263.452.468.942.605 1.46L18 8.666v2.666l-2.263.19a5.899 5.899 0 0 1-.604 1.458l1.467 1.733-1.886 1.886-1.733-1.467a5.899 5.899 0 0 1-1.46.605L11.334 18H8.667l-.19-2.263a5.899 5.899 0 0 1-1.458-.604L5.286 16.6 3.4 14.714l1.467-1.733a5.899 5.899 0 0 1-.604-1.458L2 11.333V8.667l2.262-.189a5.899 5.899 0 0 1 .605-1.459L3.4 5.286 5.286 3.4l1.733 1.467a5.899 5.899 0 0 1 1.46-.605L8.666 2h2.666zM10 6.267a3.733 3.733 0 1 0 0 7.466 3.733 3.733 0 0 0 0-7.466z"/></svg>', Lk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m8.636 9.531-2.758 3.94a.5.5 0 0 0 .122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 0 1-.491-2.786l6.673-9.53a2 2 0 0 1 2.785-.49l3.742 2.62a2 2 0 0 1 .491 2.785l-7.269 10.053-2.147-.066z"/><path d="M4 18h5.523v-1H4zm-2 0h1v-1H2z"/></svg>', $k = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.085 6.22 2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z"/></svg>', zk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 0 1 .87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 1 1 3.4-1.96 1.96 1.96 0 0 1-3.4 1.96z"/></svg>', Hk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.239 13.938-2.88-1.663a.75.75 0 0 1 .75-1.3L9 12.067V4.75a.75.75 0 1 1 1.5 0v7.318l1.89-1.093a.75.75 0 0 1 .75 1.3l-2.879 1.663a.752.752 0 0 1-.511.187.752.752 0 0 1-.511-.187zM4.25 17a.75.75 0 1 1 0-1.5h10.5a.75.75 0 0 1 0 1.5H4.25z"/></svg>', Wk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.75 11.875a.752.752 0 0 1 .508.184l2.883 1.666a.75.75 0 0 1-.659 1.344l-.091-.044-1.892-1.093.001 4.318a.75.75 0 1 1-1.5 0v-4.317l-1.89 1.092a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .51-.187zM15.25 9a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM9.75.375a.75.75 0 0 1 .75.75v4.318l1.89-1.093.092-.045a.75.75 0 0 1 .659 1.344l-2.883 1.667a.752.752 0 0 1-.508.184.752.752 0 0 1-.511-.187L6.359 5.65a.75.75 0 0 1 .75-1.299L9 5.442V1.125a.75.75 0 0 1 .75-.75z"/></svg>', Uk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m10.261 7.062 2.88 1.663a.75.75 0 0 1-.75 1.3L10.5 8.933v7.317a.75.75 0 1 1-1.5 0V8.932l-1.89 1.093a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .511-.187.752.752 0 0 1 .511.187zM15.25 4a.75.75 0 1 1 0 1.5H4.75a.75.75 0 0 1 0-1.5h10.5z"/></svg>', jk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>', qk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75z"/></svg>', Gk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 3.75a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 8a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 4a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75zm0-8a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75z"/></svg>', Kk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z"/></svg>', Jk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>', Zk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M15.003 7v5.5a1 1 0 0 1-1 1H5.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H6.5V12h6.997V7.5z"/></svg>', Yk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>', Xk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2z"/><path d="M18 7v5.5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1zm-1.505.5H3.504V12h12.991V7.5z"/></svg>', Qk = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>', e2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm11.5 9H18v1.5h-4.5zm0-3H18v1.5h-4.5zm0-3H18v1.5h-4.5zM2 15h16v1.5H2z"/><path d="M12.003 7v5.5a1 1 0 0 1-1 1H2.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H3.5V12h6.997V7.5z"/></svg>', t2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path opacity=".5" d="M2 3h16v1.5H2zm0 12h16v1.5H2zm0-9h5v1.5H2zm0 3h5v1.5H2zm0 3h5v1.5H2z"/><path d="M18.003 7v5.5a1 1 0 0 1-1 1H8.996a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h8.007a1 1 0 0 1 1 1zm-1.506.5H9.5V12h6.997V7.5z"/></svg>', i2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z"/><path d="M18.095 2H1.905C.853 2 0 2.895 0 4v12c0 1.105.853 2 1.905 2h16.19C19.147 18 20 17.105 20 16V4c0-1.105-.853-2-1.905-2zm0 1.5c.263 0 .476.224.476.5v12c0 .276-.213.5-.476.5H1.905a.489.489 0 0 1-.476-.5V4c0-.276.213-.5.476-.5h16.19z"/></svg>', n2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z"/><path d="M13 6H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5V8a.5.5 0 0 1 .5-.5h11z"/></svg>', s2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z"/><path d="M7 10H2a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5h5z"/></svg>', r2 = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z"/><path d="M10 8H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5h8z"/></svg>', o2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m7.3 17.37-.061.088a1.518 1.518 0 0 1-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 0 1 .187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506 13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5 9.375 17H19v1.5H8z"/></svg>', a2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.999 2H15a1 1 0 0 1 0 2h-1.004v13a1 1 0 1 1-2 0V4H8.999v13a1 1 0 1 1-2 0v-7A4 4 0 0 1 3 6a4 4 0 0 1 3.999-4z"/></svg>', l2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 0 1 6.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z"/></svg>', c2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><circle cx="9.5" cy="4.5" r="1.5"/><circle cx="9.5" cy="10.5" r="1.5"/><circle cx="9.5" cy="16.5" r="1.5"/></svg>', u2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 0 1 .808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 0 1-2.296 3.504 6.1 6.1 0 0 1-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 0 0 .91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z"/></svg>', h2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.5 5.5H7v5h3.5a2.5 2.5 0 1 0 0-5zM5 3h6.5v.025a5 5 0 0 1 0 9.95V13H7v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z"/></svg>', d2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10 2a1 1 0 0 0-1 1v6H3a1 1 0 1 0 0 2h6v6a1 1 0 1 0 2 0v-6h6a1 1 0 1 0 0-2h-6V3a1 1 0 0 0-1-1Z"/></svg>', f2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.816 11.5 7.038 4.785 4.261 11.5h5.555Zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13Z"/><path d="m12.09 17-.534-1.292.848-1.971.545 1.319L12.113 17h-.023Zm1.142-5.187.545 1.319L15.5 9.13l1.858 4.316h-3.45l.398.965h3.467L18.887 17H20l-3.873-9h-1.254l-1.641 3.813Z"/></svg>', m2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M19 4.5 14 0H3v12.673l.868-1.041c.185-.222.4-.402.632-.54V1.5h8v5h5v7.626a2.24 2.24 0 0 1 1.5.822V4.5ZM14 5V2l3.3 3H14Zm-3.692 12.5c.062.105.133.206.213.303L11.52 19H8v-.876a2.243 2.243 0 0 0 1.82-.624h.488Zm7.518-.657a.75.75 0 0 0-1.152-.96L15.5 17.29V12H14v5.29l-1.174-1.408a.75.75 0 0 0-1.152.96l2.346 2.816a.95.95 0 0 0 1.46 0l2.346-2.815Zm-15.056-.38a.75.75 0 0 1-.096-1.056l2.346-2.815a.95.95 0 0 1 1.46 0l2.346 2.815a.75.75 0 1 1-1.152.96L6.5 14.96V20H5v-5.04l-1.174 1.408a.75.75 0 0 1-1.056.096Z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const D = {
  bold: u2,
  cancel: Dk,
  caption: Bk,
  check: Fk,
  cog: Nk,
  eraser: Lk,
  image: zk,
  lowVision: $k,
  importExport: m2,
  paragraph: h2,
  plus: d2,
  text: f2,
  alignBottom: Hk,
  alignMiddle: Wk,
  alignTop: Uk,
  alignLeft: jk,
  alignCenter: qk,
  alignRight: Gk,
  alignJustify: Kk,
  objectLeft: e2,
  objectCenter: Zk,
  objectRight: t2,
  objectFullWidth: Xk,
  objectInline: Qk,
  objectBlockLeft: Jk,
  objectBlockRight: Yk,
  objectSizeFull: i2,
  objectSizeLarge: n2,
  objectSizeSmall: s2,
  objectSizeMedium: r2,
  pencil: o2,
  pilcrow: a2,
  quote: l2,
  threeVerticalDots: c2
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class yh {
  /**
   * @param {module:watchdog/watchdog~WatchdogConfig} config The watchdog plugin configuration.
   */
  constructor(e) {
    if (this.crashes = [], this.state = "initializing", this._now = Date.now, this.crashes = [], this._crashNumberLimit = typeof e.crashNumberLimit == "number" ? e.crashNumberLimit : 3, this._minimumNonErrorTimePeriod = typeof e.minimumNonErrorTimePeriod == "number" ? e.minimumNonErrorTimePeriod : 5e3, this._boundErrorHandler = (t) => {
      const i = "error" in t ? t.error : t.reason;
      i instanceof Error && this._handleError(i, t);
    }, this._listeners = {}, !this._restart)
      throw new Error("The Watchdog class was split into the abstract `Watchdog` class and the `EditorWatchdog` class. Please, use `EditorWatchdog` if you have used the `Watchdog` class previously.");
  }
  /**
   * Destroys the watchdog and releases the resources.
   */
  destroy() {
    this._stopErrorHandling(), this._listeners = {};
  }
  /**
   * Starts listening to a specific event name by registering a callback that will be executed
   * whenever an event with a given name fires.
   *
   * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
   *
   * @param eventName The event name.
   * @param callback A callback which will be added to event listeners.
   */
  on(e, t) {
    this._listeners[e] || (this._listeners[e] = []), this._listeners[e].push(t);
  }
  /**
   * Stops listening to the specified event name by removing the callback from event listeners.
   *
   * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
   *
   * @param eventName The event name.
   * @param callback A callback which will be removed from event listeners.
   */
  off(e, t) {
    this._listeners[e] = this._listeners[e].filter((i) => i !== t);
  }
  /**
   * Fires an event with a given event name and arguments.
   *
   * Note that this method differs from the CKEditor 5's default `EventEmitterMixin` implementation.
   */
  _fire(e, ...t) {
    const i = this._listeners[e] || [];
    for (const s of i)
      s.apply(this, [null, ...t]);
  }
  /**
   * Starts error handling by attaching global error handlers.
   */
  _startErrorHandling() {
    window.addEventListener("error", this._boundErrorHandler), window.addEventListener("unhandledrejection", this._boundErrorHandler);
  }
  /**
   * Stops error handling by detaching global error handlers.
   */
  _stopErrorHandling() {
    window.removeEventListener("error", this._boundErrorHandler), window.removeEventListener("unhandledrejection", this._boundErrorHandler);
  }
  /**
   * Checks if an error comes from the watched item and restarts it.
   * It reacts to {@link module:utils/ckeditorerror~CKEditorError `CKEditorError` errors} only.
   *
   * @fires error
   * @param error Error.
   * @param evt An error event.
   */
  _handleError(e, t) {
    if (this._shouldReactToError(e)) {
      this.crashes.push({
        message: e.message,
        stack: e.stack,
        // `evt.filename`, `evt.lineno` and `evt.colno` are available only in ErrorEvent events
        filename: t instanceof ErrorEvent ? t.filename : void 0,
        lineno: t instanceof ErrorEvent ? t.lineno : void 0,
        colno: t instanceof ErrorEvent ? t.colno : void 0,
        date: this._now()
      });
      const i = this._shouldRestart();
      this.state = "crashed", this._fire("stateChange"), this._fire("error", { error: e, causesRestart: i }), i ? this._restart() : (this.state = "crashedPermanently", this._fire("stateChange"));
    }
  }
  /**
   * Checks whether an error should be handled by the watchdog.
   *
   * @param error An error that was caught by the error handling process.
   */
  _shouldReactToError(e) {
    return e.is && e.is("CKEditorError") && e.context !== void 0 && // In some cases the watched item should not be restarted - e.g. during the item initialization.
    // That's why the `null` was introduced as a correct error context which does cause restarting.
    e.context !== null && // Do not react to errors if the watchdog is in states other than `ready`.
    this.state === "ready" && this._isErrorComingFromThisItem(e);
  }
  /**
   * Checks if the watchdog should restart the underlying item.
   */
  _shouldRestart() {
    if (this.crashes.length <= this._crashNumberLimit)
      return !0;
    const e = this.crashes[this.crashes.length - 1].date, t = this.crashes[this.crashes.length - 1 - this._crashNumberLimit].date;
    return (e - t) / this._crashNumberLimit > this._minimumNonErrorTimePeriod;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function tr(n, e = /* @__PURE__ */ new Set()) {
  const t = [n], i = /* @__PURE__ */ new Set();
  let s = 0;
  for (; t.length > s; ) {
    const r = t[s++];
    if (!(i.has(r) || !g2(r) || e.has(r)))
      if (i.add(r), Symbol.iterator in r)
        try {
          for (const o of r)
            t.push(o);
        } catch {
        }
      else
        for (const o in r)
          o !== "defaultValue" && t.push(r[o]);
  }
  return i;
}
function g2(n) {
  const e = Object.prototype.toString.call(n), t = typeof n;
  return !(t === "number" || t === "boolean" || t === "string" || t === "symbol" || t === "function" || e === "[object Date]" || e === "[object RegExp]" || e === "[object Module]" || n === void 0 || n === null || // This flag is meant to exclude singletons shared across editor instances. So when an error is thrown in one editor,
  // the other editors connected through the reference to the same singleton are not restarted. This is a temporary workaround
  // until a better solution is found.
  // More in https://github.com/ckeditor/ckeditor5/issues/12292.
  n._watchdogExcluded || // Skip native DOM objects, e.g. Window, nodes, events, etc.
  n instanceof EventTarget || n instanceof Event);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function kh(n, e, t = /* @__PURE__ */ new Set()) {
  if (n === e && p2(n))
    return !0;
  const i = tr(n, t), s = tr(e, t);
  for (const r of i)
    if (s.has(r))
      return !0;
  return !1;
}
function p2(n) {
  return typeof n == "object" && n !== null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ch extends yh {
  /**
   * @param Editor The editor class.
   * @param watchdogConfig The watchdog plugin configuration.
   */
  constructor(e, t = {}) {
    super(t), this._editor = null, this._throttledSave = Vn(this._save.bind(this), typeof t.saveInterval == "number" ? t.saveInterval : 5e3), e && (this._creator = (i, s) => e.create(i, s)), this._destructor = (i) => i.destroy();
  }
  /**
   * The current editor instance.
   */
  get editor() {
    return this._editor;
  }
  /**
   * @internal
   */
  get _item() {
    return this._editor;
  }
  /**
   * Sets the function that is responsible for the editor creation.
   * It expects a function that should return a promise.
   *
   * ```ts
   * watchdog.setCreator( ( element, config ) => ClassicEditor.create( element, config ) );
   * ```
   */
  setCreator(e) {
    this._creator = e;
  }
  /**
   * Sets the function that is responsible for the editor destruction.
   * Overrides the default destruction function, which destroys only the editor instance.
   * It expects a function that should return a promise or `undefined`.
   *
   * ```ts
   * watchdog.setDestructor( editor => {
   * 	// Do something before the editor is destroyed.
   *
   * 	return editor
   * 		.destroy()
   * 		.then( () => {
   * 			// Do something after the editor is destroyed.
   * 		} );
   * } );
   * ```
   */
  setDestructor(e) {
    this._destructor = e;
  }
  /**
   * Restarts the editor instance. This method is called whenever an editor error occurs. It fires the `restart` event and changes
   * the state to `initializing`.
   *
   * @fires restart
   */
  _restart() {
    return Promise.resolve().then(() => (this.state = "initializing", this._fire("stateChange"), this._destroy())).catch((e) => {
      console.error("An error happened during the editor destroying.", e);
    }).then(() => {
      if (typeof this._elementOrData == "string")
        return this.create(this._data, this._config, this._config.context);
      {
        const e = Object.assign({}, this._config, {
          initialData: this._data
        });
        return this.create(this._elementOrData, e, e.context);
      }
    }).then(() => {
      this._fire("restart");
    });
  }
  /**
   * Creates the editor instance and keeps it running, using the defined creator and destructor.
   *
   * @param elementOrData The editor source element or the editor data.
   * @param config The editor configuration.
   * @param context A context for the editor.
   */
  create(e = this._elementOrData, t = this._config, i) {
    return Promise.resolve().then(() => (super._startErrorHandling(), this._elementOrData = e, this._config = this._cloneEditorConfiguration(t) || {}, this._config.context = i, this._creator(e, this._config))).then((s) => {
      this._editor = s, s.model.document.on("change:data", this._throttledSave), this._lastDocumentVersion = s.model.document.version, this._data = this._getData(), this.state = "ready", this._fire("stateChange");
    });
  }
  /**
   * Destroys the watchdog and the current editor instance. It fires the callback
   * registered in {@link #setDestructor `setDestructor()`} and uses it to destroy the editor instance.
   * It also sets the state to `destroyed`.
   */
  destroy() {
    return Promise.resolve().then(() => (this.state = "destroyed", this._fire("stateChange"), super.destroy(), this._destroy()));
  }
  _destroy() {
    return Promise.resolve().then(() => {
      this._stopErrorHandling(), this._throttledSave.flush();
      const e = this._editor;
      return this._editor = null, e.model.document.off("change:data", this._throttledSave), this._destructor(e);
    });
  }
  /**
   * Saves the editor data, so it can be restored after the crash even if the data cannot be fetched at
   * the moment of the crash.
   */
  _save() {
    const e = this._editor.model.document.version;
    try {
      this._data = this._getData(), this._lastDocumentVersion = e;
    } catch (t) {
      console.error(t, "An error happened during restoring editor data. Editor will be restored from the previously saved data.");
    }
  }
  /**
   * @internal
   */
  _setExcludedProperties(e) {
    this._excludedProps = e;
  }
  /**
   * Returns the editor data.
   */
  _getData() {
    const e = {};
    for (const t of this._editor.model.document.getRootNames())
      e[t] = this._editor.data.get({ rootName: t });
    return e;
  }
  /**
   * Traverses the error context and the current editor to find out whether these structures are connected
   * to each other via properties.
   *
   * @internal
   */
  _isErrorComingFromThisItem(e) {
    return kh(this._editor, e.context, this._excludedProps);
  }
  /**
   * Clones the editor configuration.
   */
  _cloneEditorConfiguration(e) {
    return Tr(e, (t, i) => {
      if (di(t) || i === "context")
        return t;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Ti = Symbol("MainQueueId");
class w2 extends yh {
  /**
   * The context watchdog class constructor.
   *
   * ```ts
   * const watchdog = new ContextWatchdog( Context );
   *
   * await watchdog.create( contextConfiguration );
   *
   * await watchdog.add( item );
   * ```
   *
   * See the {@glink features/watchdog Watchdog feature guide} to learn more how to use this feature.
   *
   * @param Context The {@link module:core/context~Context} class.
   * @param watchdogConfig The watchdog configuration.
   */
  constructor(e, t = {}) {
    super(t), this._watchdogs = /* @__PURE__ */ new Map(), this._context = null, this._contextProps = /* @__PURE__ */ new Set(), this._actionQueues = new b2(), this._watchdogConfig = t, this._creator = (i) => e.create(i), this._destructor = (i) => i.destroy(), this._actionQueues.onEmpty(() => {
      this.state === "initializing" && (this.state = "ready", this._fire("stateChange"));
    });
  }
  /**
   * Sets the function that is responsible for the context creation.
   * It expects a function that should return a promise (or `undefined`).
   *
   * ```ts
   * watchdog.setCreator( config => Context.create( config ) );
   * ```
   */
  setCreator(e) {
    this._creator = e;
  }
  /**
   * Sets the function that is responsible for the context destruction.
   * Overrides the default destruction function, which destroys only the context instance.
   * It expects a function that should return a promise (or `undefined`).
   *
   * ```ts
   * watchdog.setDestructor( context => {
   * 	// Do something before the context is destroyed.
   *
   * 	return context
   * 		.destroy()
   * 		.then( () => {
   * 			// Do something after the context is destroyed.
   * 		} );
   * } );
   * ```
   */
  setDestructor(e) {
    this._destructor = e;
  }
  /**
   * The context instance. Keep in mind that this property might be changed when the context watchdog restarts,
   * so do not keep this instance internally. Always operate on the `ContextWatchdog#context` property.
   */
  get context() {
    return this._context;
  }
  /**
   * Initializes the context watchdog. Once it is created, the watchdog takes care about
   * recreating the context and the provided items, and starts the error handling mechanism.
   *
   * ```ts
   * await watchdog.create( {
   * 	plugins: []
   * } );
   * ```
   *
   * @param contextConfig The context configuration. See {@link module:core/context~Context}.
   */
  create(e = {}) {
    return this._actionQueues.enqueue(Ti, () => (this._contextConfig = e, this._create()));
  }
  /**
   * Returns an item instance with the given `itemId`.
   *
   * ```ts
   * const editor1 = watchdog.getItem( 'editor1' );
   * ```
   *
   * @param itemId The item ID.
   * @returns The item instance or `undefined` if an item with a given ID has not been found.
   */
  getItem(e) {
    return this._getWatchdog(e)._item;
  }
  /**
   * Gets the state of the given item. See {@link #state} for a list of available states.
   *
   * ```ts
   * const editor1State = watchdog.getItemState( 'editor1' );
   * ```
   *
   * @param itemId Item ID.
   * @returns The state of the item.
   */
  getItemState(e) {
    return this._getWatchdog(e).state;
  }
  /**
   * Adds items to the watchdog. Once created, instances of these items will be available using the {@link #getItem} method.
   *
   * Items can be passed together as an array of objects:
   *
   * ```ts
   * await watchdog.add( [ {
   * 	id: 'editor1',
   * 	type: 'editor',
   * 	sourceElementOrData: document.querySelector( '#editor' ),
   * 	config: {
   * 		plugins: [ Essentials, Paragraph, Bold, Italic ],
   * 		toolbar: [ 'bold', 'italic', 'alignment' ]
   * 	},
   * 	creator: ( element, config ) => ClassicEditor.create( element, config )
   * } ] );
   * ```
   *
   * Or one by one as objects:
   *
   * ```ts
   * await watchdog.add( {
   * 	id: 'editor1',
   * 	type: 'editor',
   * 	sourceElementOrData: document.querySelector( '#editor' ),
   * 	config: {
   * 		plugins: [ Essentials, Paragraph, Bold, Italic ],
   * 		toolbar: [ 'bold', 'italic', 'alignment' ]
   * 	},
   * 	creator: ( element, config ) => ClassicEditor.create( element, config )
   * ] );
   * ```
   *
   * Then an instance can be retrieved using the {@link #getItem} method:
   *
   * ```ts
   * const editor1 = watchdog.getItem( 'editor1' );
   * ```
   *
   * Note that this method can be called multiple times, but for performance reasons it is better
   * to pass all items together.
   *
   * @param itemConfigurationOrItemConfigurations An item configuration object or an array of item configurations.
   */
  add(e) {
    const t = ja(e);
    return Promise.all(t.map((i) => this._actionQueues.enqueue(i.id, () => {
      if (this.state === "destroyed")
        throw new Error("Cannot add items to destroyed watchdog.");
      if (!this._context)
        throw new Error("Context was not created yet. You should call the `ContextWatchdog#create()` method first.");
      let s;
      if (this._watchdogs.has(i.id))
        throw new Error(`Item with the given id is already added: '${i.id}'.`);
      if (i.type === "editor")
        return s = new Ch(null, this._watchdogConfig), s.setCreator(i.creator), s._setExcludedProperties(this._contextProps), i.destructor && s.setDestructor(i.destructor), this._watchdogs.set(i.id, s), s.on("error", (r, { error: o, causesRestart: a }) => {
          this._fire("itemError", { itemId: i.id, error: o }), a && this._actionQueues.enqueue(i.id, () => new Promise((l) => {
            const c = () => {
              s.off("restart", c), this._fire("itemRestart", { itemId: i.id }), l();
            };
            s.on("restart", c);
          }));
        }), s.create(i.sourceElementOrData, i.config, this._context);
      throw new Error(`Not supported item type: '${i.type}'.`);
    })));
  }
  /**
   * Removes and destroys item(s) with given ID(s).
   *
   * ```ts
   * await watchdog.remove( 'editor1' );
   * ```
   *
   * Or
   *
   * ```ts
   * await watchdog.remove( [ 'editor1', 'editor2' ] );
   * ```
   *
   * @param itemIdOrItemIds Item ID or an array of item IDs.
   */
  remove(e) {
    const t = ja(e);
    return Promise.all(t.map((i) => this._actionQueues.enqueue(i, () => {
      const s = this._getWatchdog(i);
      return this._watchdogs.delete(i), s.destroy();
    })));
  }
  /**
   * Destroys the context watchdog and all added items.
   * Once the context watchdog is destroyed, new items cannot be added.
   *
   * ```ts
   * await watchdog.destroy();
   * ```
   */
  destroy() {
    return this._actionQueues.enqueue(Ti, () => (this.state = "destroyed", this._fire("stateChange"), super.destroy(), this._destroy()));
  }
  /**
   * Restarts the context watchdog.
   */
  _restart() {
    return this._actionQueues.enqueue(Ti, () => (this.state = "initializing", this._fire("stateChange"), this._destroy().catch((e) => {
      console.error("An error happened during destroying the context or items.", e);
    }).then(() => this._create()).then(() => this._fire("restart"))));
  }
  /**
   * Initializes the context watchdog.
   */
  _create() {
    return Promise.resolve().then(() => (this._startErrorHandling(), this._creator(this._contextConfig))).then((e) => (this._context = e, this._contextProps = tr(this._context), Promise.all(Array.from(this._watchdogs.values()).map((t) => (t._setExcludedProperties(this._contextProps), t.create(void 0, void 0, this._context))))));
  }
  /**
   * Destroys the context instance and all added items.
   */
  _destroy() {
    return Promise.resolve().then(() => {
      this._stopErrorHandling();
      const e = this._context;
      return this._context = null, this._contextProps = /* @__PURE__ */ new Set(), Promise.all(Array.from(this._watchdogs.values()).map((t) => t.destroy())).then(() => this._destructor(e));
    });
  }
  /**
   * Returns the watchdog for a given item ID.
   *
   * @param itemId Item ID.
   */
  _getWatchdog(e) {
    const t = this._watchdogs.get(e);
    if (!t)
      throw new Error(`Item with the given id was not registered: ${e}.`);
    return t;
  }
  /**
   * Checks whether an error comes from the context instance and not from the item instances.
   *
   * @internal
   */
  _isErrorComingFromThisItem(e) {
    for (const t of this._watchdogs.values())
      if (t._isErrorComingFromThisItem(e))
        return !1;
    return kh(this._context, e.context);
  }
}
class b2 {
  constructor() {
    this._onEmptyCallbacks = [], this._queues = /* @__PURE__ */ new Map(), this._activeActions = 0;
  }
  /**
   * Used to register callbacks that will be run when the queue becomes empty.
   *
   * @param onEmptyCallback A callback that will be run whenever the queue becomes empty.
   */
  onEmpty(e) {
    this._onEmptyCallbacks.push(e);
  }
  /**
   * It adds asynchronous actions (functions) to the proper queue and runs them one by one.
   *
   * @param queueId The action queue ID.
   * @param action A function that should be enqueued.
   */
  enqueue(e, t) {
    const i = e === Ti;
    this._activeActions++, this._queues.get(e) || this._queues.set(e, Promise.resolve());
    const r = (i ? Promise.all(this._queues.values()) : Promise.all([this._queues.get(Ti), this._queues.get(e)])).then(t), o = r.catch(() => {
    });
    return this._queues.set(e, o), r.finally(() => {
      this._activeActions--, this._queues.get(e) === o && this._activeActions === 0 && this._onEmptyCallbacks.forEach((a) => a());
    });
  }
}
function ja(n) {
  return Array.isArray(n) ? n : [n];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Ur({ emitter: n, activator: e, callback: t, contextElements: i }) {
  n.listenTo(document, "mousedown", (s, r) => {
    if (!e())
      return;
    const o = typeof r.composedPath == "function" ? r.composedPath() : [], a = typeof i == "function" ? i() : i;
    for (const l of a)
      if (l.contains(r.target) || o.includes(l))
        return;
    t();
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function jr(n) {
  class e extends n {
    disableCssTransitions() {
      this._isCssTransitionsDisabled = !0;
    }
    enableCssTransitions() {
      this._isCssTransitionsDisabled = !1;
    }
    constructor(...i) {
      super(...i), this.set("_isCssTransitionsDisabled", !1), this.initializeCssTransitionDisablerMixin();
    }
    initializeCssTransitionDisablerMixin() {
      this.extendTemplate({
        attributes: {
          class: [
            this.bindTemplate.if("_isCssTransitionsDisabled", "ck-transitions-disabled")
          ]
        }
      });
    }
  }
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function qr({ view: n }) {
  n.listenTo(n.element, "submit", (e, t) => {
    t.preventDefault(), n.fire("submit");
  }, { useCapture: !0 });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function _2({ keystrokeHandler: n, focusTracker: e, gridItems: t, numberOfColumns: i, uiLanguageDirection: s }) {
  const r = typeof i == "number" ? () => i : i;
  n.set("arrowright", o((c, u) => s === "rtl" ? l(c, u.length) : a(c, u.length))), n.set("arrowleft", o((c, u) => s === "rtl" ? a(c, u.length) : l(c, u.length))), n.set("arrowup", o((c, u) => {
    let h = c - r();
    return h < 0 && (h = c + r() * Math.floor(u.length / r()), h > u.length - 1 && (h -= r())), h;
  })), n.set("arrowdown", o((c, u) => {
    let h = c + r();
    return h > u.length - 1 && (h = c % r()), h;
  }));
  function o(c) {
    return (u) => {
      const h = t.find((p) => p.element === e.focusedElement), f = t.getIndex(h), m = c(f, t);
      t.get(m).focus(), u.stopPropagation(), u.preventDefault();
    };
  }
  function a(c, u) {
    return c === u - 1 ? 0 : c + 1;
  }
  function l(c, u) {
    return c === 0 ? u - 1 : c - 1;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class nt extends He {
  /**
   * Creates a new instance of the {@link module:ui/viewcollection~ViewCollection}.
   *
   * @param initialItems The initial items of the collection.
   */
  constructor(e = []) {
    super(e, {
      // An #id Number attribute should be legal and not break the `ViewCollection` instance.
      // https://github.com/ckeditor/ckeditor5-ui/issues/93
      idProperty: "viewUid"
    }), this.on("add", (t, i, s) => {
      this._renderViewIntoCollectionParent(i, s);
    }), this.on("remove", (t, i) => {
      i.element && this._parentElement && i.element.remove();
    }), this._parentElement = null;
  }
  /**
   * Destroys the view collection along with child views.
   * See the view {@link module:ui/view~View#destroy} method.
   */
  destroy() {
    this.map((e) => e.destroy());
  }
  /**
   * Sets the parent HTML element of this collection. When parent is set, {@link #add adding} and
   * {@link #remove removing} views in the collection synchronizes their
   * {@link module:ui/view~View#element elements} in the parent element.
   *
   * @param element A new parent element.
   */
  setParent(e) {
    this._parentElement = e;
    for (const t of this)
      this._renderViewIntoCollectionParent(t);
  }
  /**
   * Delegates selected events coming from within views in the collection to any
   * {@link module:utils/emittermixin~Emitter}.
   *
   * For the following views and collection:
   *
   * ```ts
   * const viewA = new View();
   * const viewB = new View();
   * const viewC = new View();
   *
   * const views = parentView.createCollection();
   *
   * views.delegate( 'eventX' ).to( viewB );
   * views.delegate( 'eventX', 'eventY' ).to( viewC );
   *
   * views.add( viewA );
   * ```
   *
   * the `eventX` is delegated (fired by) `viewB` and `viewC` along with `customData`:
   *
   * ```ts
   * viewA.fire( 'eventX', customData );
   * ```
   *
   * and `eventY` is delegated (fired by) `viewC` along with `customData`:
   *
   * ```ts
   * viewA.fire( 'eventY', customData );
   * ```
   *
   * See {@link module:utils/emittermixin~Emitter#delegate}.
   *
   * @param events {@link module:ui/view~View} event names to be delegated to another
   * {@link module:utils/emittermixin~Emitter}.
   * @returns Object with `to` property, a function which accepts the destination
   * of {@link module:utils/emittermixin~Emitter#delegate delegated} events.
   */
  delegate(...e) {
    if (!e.length || !v2(e))
      throw new d("ui-viewcollection-delegate-wrong-events", this);
    return {
      to: (t) => {
        for (const i of this)
          for (const s of e)
            i.delegate(s).to(t);
        this.on("add", (i, s) => {
          for (const r of e)
            s.delegate(r).to(t);
        }), this.on("remove", (i, s) => {
          for (const r of e)
            s.stopDelegating(r, t);
        });
      }
    };
  }
  /**
   * This method {@link module:ui/view~View#render renders} a new view added to the collection.
   *
   * If the {@link #_parentElement parent element} of the collection is set, this method also adds
   * the view's {@link module:ui/view~View#element} as a child of the parent in DOM at a specified index.
   *
   * **Note**: If index is not specified, the view's element is pushed as the last child
   * of the parent element.
   *
   * @param view A new view added to the collection.
   * @param index An index the view holds in the collection. When not specified,
   * the view is added at the end.
   */
  _renderViewIntoCollectionParent(e, t) {
    e.isRendered || e.render(), e.element && this._parentElement && this._parentElement.insertBefore(e.element, this._parentElement.children[t]);
  }
  /**
   * Removes a child view from the collection. If the {@link #setParent parent element} of the
   * collection has been set, the {@link module:ui/view~View#element element} of the view is also removed
   * in DOM, reflecting the order of the collection.
   *
   * See the {@link #add} method.
   *
   * @param subject The view to remove, its id or index in the collection.
   * @returns The removed view.
   */
  remove(e) {
    return super.remove(e);
  }
}
function v2(n) {
  return n.every((e) => typeof e == "string");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class T extends it(z()) {
  /**
   * Creates an instance of the {@link module:ui/view~View} class.
   *
   * Also see {@link #render}.
   *
   * @param locale The localization services instance.
   */
  constructor(e) {
    super(), this.element = null, this.isRendered = !1, this.locale = e, this.t = e && e.t, this._viewCollections = new He(), this._unboundChildren = this.createCollection(), this._viewCollections.on("add", (t, i) => {
      i.locale = e, i.t = e && e.t;
    }), this.decorate("render");
  }
  /**
   * Shorthand for {@link module:ui/template~Template.bind}, a binding
   * {@link module:ui/template~BindChain interface} pre–configured for the view instance.
   *
   * It provides {@link module:ui/template~BindChain#to `to()`} and
   * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with
   * observable attributes and attach DOM listeners.
   *
   * ```ts
   * class SampleView extends View {
   * 	constructor( locale ) {
   * 		super( locale );
   *
   * 		const bind = this.bindTemplate;
   *
   * 		// These {@link module:utils/observablemixin~Observable observable} attributes will control
   * 		// the state of the view in DOM.
   * 		this.set( {
   * 			elementClass: 'foo',
   * 		 	isEnabled: true
   * 		 } );
   *
   * 		this.setTemplate( {
   * 			tag: 'p',
   *
   * 			attributes: {
   * 				// The class HTML attribute will follow elementClass
   * 				// and isEnabled view attributes.
   * 				class: [
   * 					bind.to( 'elementClass' )
   * 					bind.if( 'isEnabled', 'present-when-enabled' )
   * 				]
   * 			},
   *
   * 			on: {
   * 				// The view will fire the "clicked" event upon clicking <p> in DOM.
   * 				click: bind.to( 'clicked' )
   * 			}
   * 		} );
   * 	}
   * }
   * ```
   */
  get bindTemplate() {
    return this._bindTemplate ? this._bindTemplate : this._bindTemplate = Ce.bind(this, this);
  }
  /**
   * Creates a new collection of views, which can be used as
   * {@link module:ui/template~Template#children} of this view.
   *
   * ```ts
   * class SampleView extends View {
   * 	constructor( locale ) {
   * 		super( locale );
   *
   * 		const child = new ChildView( locale );
   * 		this.items = this.createCollection( [ child ] );
   *
   * 		this.setTemplate( {
   * 			tag: 'p',
   *
   * 			// `items` collection will render here.
   * 			children: this.items
   * 		} );
   * 	}
   * }
   *
   * const view = new SampleView( locale );
   * view.render();
   *
   * // It will append <p><child#element></p> to the <body>.
   * document.body.appendChild( view.element );
   * ```
   *
   * @param views Initial views of the collection.
   * @returns A new collection of view instances.
   */
  createCollection(e) {
    const t = new nt(e);
    return this._viewCollections.add(t), t;
  }
  /**
   * Registers a new child view under the view instance. Once registered, a child
   * view is managed by its parent, including {@link #render rendering}
   * and {@link #destroy destruction}.
   *
   * To revert this, use {@link #deregisterChild}.
   *
   * ```ts
   * class SampleView extends View {
   * 	constructor( locale ) {
   * 		super( locale );
   *
   * 		this.childA = new SomeChildView( locale );
   * 		this.childB = new SomeChildView( locale );
   *
   * 		this.setTemplate( { tag: 'p' } );
   *
   * 		// Register the children.
   * 		this.registerChild( [ this.childA, this.childB ] );
   * 	}
   *
   * 	render() {
   * 		super.render();
   *
   * 		this.element.appendChild( this.childA.element );
   * 		this.element.appendChild( this.childB.element );
   * 	}
   * }
   *
   * const view = new SampleView( locale );
   *
   * view.render();
   *
   * // Will append <p><childA#element><b></b><childB#element></p>.
   * document.body.appendChild( view.element );
   * ```
   *
   * **Note**: There's no need to add child views if they're already referenced in the
   * {@link #template}:
   *
   * ```ts
   * class SampleView extends View {
   * 	constructor( locale ) {
   * 		super( locale );
   *
   * 		this.childA = new SomeChildView( locale );
   * 		this.childB = new SomeChildView( locale );
   *
   * 		this.setTemplate( {
   * 			tag: 'p',
   *
   * 			// These children will be added automatically. There's no
   * 			// need to call {@link #registerChild} for any of them.
   * 			children: [ this.childA, this.childB ]
   * 		} );
   * 	}
   *
   * 	// ...
   * }
   * ```
   *
   * @param children Children views to be registered.
   */
  registerChild(e) {
    _e(e) || (e = [e]);
    for (const t of e)
      this._unboundChildren.add(t);
  }
  /**
   * The opposite of {@link #registerChild}. Removes a child view from this view instance.
   * Once removed, the child is no longer managed by its parent, e.g. it can safely
   * become a child of another parent view.
   *
   * @see #registerChild
   * @param children Child views to be removed.
   */
  deregisterChild(e) {
    _e(e) || (e = [e]);
    for (const t of e)
      this._unboundChildren.remove(t);
  }
  /**
   * Sets the {@link #template} of the view with with given definition.
   *
   * A shorthand for:
   *
   * ```ts
   * view.setTemplate( definition );
   * ```
   *
   * @param definition Definition of view's template.
   */
  setTemplate(e) {
    this.template = new Ce(e);
  }
  /**
   * {@link module:ui/template~Template.extend Extends} the {@link #template} of the view with
   * with given definition.
   *
   * A shorthand for:
   *
   * ```ts
   * Template.extend( view.template, definition );
   * ```
   *
   * **Note**: Is requires the {@link #template} to be already set. See {@link #setTemplate}.
   *
   * @param definition Definition which extends the {@link #template}.
   */
  extendTemplate(e) {
    Ce.extend(this.template, e);
  }
  /**
   * Recursively renders the view.
   *
   * Once the view is rendered:
   * * the {@link #element} becomes an HTML element out of {@link #template},
   * * the {@link #isRendered} flag is set `true`.
   *
   * **Note**: The children of the view:
   * * defined directly in the {@link #template}
   * * residing in collections created by the {@link #createCollection} method,
   * * and added by {@link #registerChild}
   * are also rendered in the process.
   *
   * In general, `render()` method is the right place to keep the code which refers to the
   * {@link #element} and should be executed at the very beginning of the view's life cycle.
   *
   * It is possible to {@link module:ui/template~Template.extend} the {@link #template} before
   * the view is rendered. To allow an early customization of the view (e.g. by its parent),
   * such references should be done in `render()`.
   *
   * ```ts
   * class SampleView extends View {
   * 	constructor() {
   * 		this.setTemplate( {
   * 			// ...
   * 		} );
   * 	},
   *
   * 	render() {
   * 		// View#element becomes available.
   * 		super.render();
   *
   * 		// The "scroll" listener depends on #element.
   * 		this.listenTo( window, 'scroll', () => {
   * 			// A reference to #element would render the #template and make it non-extendable.
   * 			if ( window.scrollY > 0 ) {
   * 				this.element.scrollLeft = 100;
   * 			} else {
   * 				this.element.scrollLeft = 0;
   * 			}
   * 		} );
   * 	}
   * }
   *
   * const view = new SampleView();
   *
   * // Let's customize the view before it gets rendered.
   * view.extendTemplate( {
   * 	attributes: {
   * 		class: [
   * 			'additional-class'
   * 		]
   * 	}
   * } );
   *
   * // Late rendering allows customization of the view.
   * view.render();
   * ```
   */
  render() {
    if (this.isRendered)
      throw new d("ui-view-render-already-rendered", this);
    this.template && (this.element = this.template.render(), this.registerChild(this.template.getViews())), this.isRendered = !0;
  }
  /**
   * Recursively destroys the view instance and child views added by {@link #registerChild} and
   * residing in collections created by the {@link #createCollection}.
   *
   * Destruction disables all event listeners:
   * * created on the view, e.g. `view.on( 'event', () => {} )`,
   * * defined in the {@link #template} for DOM events.
   */
  destroy() {
    this.stopListening(), this._viewCollections.map((e) => e.destroy()), this.template && this.template._revertData && this.template.revert(this.element);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const y2 = "http://www.w3.org/1999/xhtml";
class Ce extends N() {
  /**
   * Creates an instance of the {@link ~Template} class.
   *
   * @param def The definition of the template.
   */
  constructor(e) {
    super(), Object.assign(this, Ga(qa(e))), this._isRendered = !1, this._revertData = null;
  }
  /**
   * Renders a DOM Node (an HTML element or text) out of the template.
   *
   * ```ts
   * const domNode = new Template( { ... } ).render();
   * ```
   *
   * See: {@link #apply}.
   */
  render() {
    const e = this._renderNode({
      intoFragment: !0
    });
    return this._isRendered = !0, e;
  }
  /**
   * Applies the template to an existing DOM Node, either HTML element or text.
   *
   * **Note:** No new DOM nodes will be created. Applying extends:
   *
   * {@link module:ui/template~TemplateDefinition attributes},
   * {@link module:ui/template~TemplateDefinition event listeners}, and
   * `textContent` of {@link module:ui/template~TemplateDefinition children} only.
   *
   * **Note:** Existing `class` and `style` attributes are extended when a template
   * is applied to an HTML element, while other attributes and `textContent` are overridden.
   *
   * **Note:** The process of applying a template can be easily reverted using the
   * {@link module:ui/template~Template#revert} method.
   *
   * ```ts
   * const element = document.createElement( 'div' );
   * const observable = new Model( { divClass: 'my-div' } );
   * const emitter = Object.create( EmitterMixin );
   * const bind = Template.bind( observable, emitter );
   *
   * new Template( {
   * 	attributes: {
   * 		id: 'first-div',
   * 		class: bind.to( 'divClass' )
   * 	},
   * 	on: {
   * 		click: bind( 'elementClicked' ) // Will be fired by the observable.
   * 	},
   * 	children: [
   * 		'Div text.'
   * 	]
   * } ).apply( element );
   *
   * console.log( element.outerHTML ); // -> '<div id="first-div" class="my-div"></div>'
   * ```
   *
   * @see module:ui/template~Template#render
   * @see module:ui/template~Template#revert
   * @param node Root node for the template to apply.
   */
  apply(e) {
    return this._revertData = Za(), this._renderNode({
      node: e,
      intoFragment: !1,
      isApplying: !0,
      revertData: this._revertData
    }), e;
  }
  /**
   * Reverts a template {@link module:ui/template~Template#apply applied} to a DOM node.
   *
   * @param node The root node for the template to revert. In most of the cases, it is the
   * same node used by {@link module:ui/template~Template#apply}.
   */
  revert(e) {
    if (!this._revertData)
      throw new d("ui-template-revert-not-applied", [this, e]);
    this._revertTemplateFromNode(e, this._revertData);
  }
  /**
   * Returns an iterator which traverses the template in search of {@link module:ui/view~View}
   * instances and returns them one by one.
   *
   * ```ts
   * const viewFoo = new View();
   * const viewBar = new View();
   * const viewBaz = new View();
   * const template = new Template( {
   * 	tag: 'div',
   * 	children: [
   * 		viewFoo,
   * 		{
   * 			tag: 'div',
   * 			children: [
   * 				viewBar
   * 			]
   * 		},
   * 		viewBaz
   * 	]
   * } );
   *
   * // Logs: viewFoo, viewBar, viewBaz
   * for ( const view of template.getViews() ) {
   * 	console.log( view );
   * }
   * ```
   */
  *getViews() {
    function* e(t) {
      if (t.children)
        for (const i of t.children)
          yn(i) ? yield i : Gr(i) && (yield* e(i));
    }
    yield* e(this);
  }
  /**
   * An entry point to the interface which binds DOM nodes to
   * {@link module:utils/observablemixin~Observable observables}.
   * There are two types of bindings:
   *
   * * HTML element attributes or text `textContent` synchronized with attributes of an
   * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}
   * and {@link module:ui/template~BindChain#if}.
   *
   * ```ts
   * const bind = Template.bind( observable, emitter );
   *
   * new Template( {
   * 	attributes: {
   * 		// Binds the element "class" attribute to observable#classAttribute.
   * 		class: bind.to( 'classAttribute' )
   * 	}
   * } ).render();
   * ```
   *
   * * DOM events fired on HTML element propagated through
   * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}.
   *
   * ```ts
   * const bind = Template.bind( observable, emitter );
   *
   * new Template( {
   * 	on: {
   * 		// Will be fired by the observable.
   * 		click: bind( 'elementClicked' )
   * 	}
   * } ).render();
   * ```
   *
   * Also see {@link module:ui/view~View#bindTemplate}.
   *
   * @param observable An observable which provides boundable attributes.
   * @param emitter An emitter that listens to observable attribute
   * changes or DOM Events (depending on the kind of the binding). Usually, a {@link module:ui/view~View} instance.
   */
  static bind(e, t) {
    return {
      to(i, s) {
        return new k2({
          eventNameOrFunction: i,
          attribute: i,
          observable: e,
          emitter: t,
          callback: s
        });
      },
      if(i, s, r) {
        return new Eh({
          observable: e,
          emitter: t,
          attribute: i,
          valueIfTrue: s,
          callback: r
        });
      }
    };
  }
  /**
   * Extends an existing {@link module:ui/template~Template} instance with some additional content
   * from another {@link module:ui/template~TemplateDefinition}.
   *
   * ```ts
   * const bind = Template.bind( observable, emitter );
   *
   * const template = new Template( {
   * 	tag: 'p',
   * 	attributes: {
   * 		class: 'a',
   * 		data-x: bind.to( 'foo' )
   * 	},
   * 	children: [
   * 		{
   * 			tag: 'span',
   * 			attributes: {
   * 				class: 'b'
   * 			},
   * 			children: [
   * 				'Span'
   * 			]
   * 		}
   * 	]
   *  } );
   *
   * // Instance-level extension.
   * Template.extend( template, {
   * 	attributes: {
   * 		class: 'b',
   * 		data-x: bind.to( 'bar' )
   * 	},
   * 	children: [
   * 		{
   * 			attributes: {
   * 				class: 'c'
   * 			}
   * 		}
   * 	]
   * } );
   *
   * // Child extension.
   * Template.extend( template.children[ 0 ], {
   * 	attributes: {
   * 		class: 'd'
   * 	}
   * } );
   * ```
   *
   * the `outerHTML` of `template.render()` is:
   *
   * ```html
   * <p class="a b" data-x="{ observable.foo } { observable.bar }">
   * 	<span class="b c d">Span</span>
   * </p>
   * ```
   *
   * @param template An existing template instance to be extended.
   * @param def Additional definition to be applied to a template.
   */
  static extend(e, t) {
    if (e._isRendered)
      throw new d("template-extend-render", [this, e]);
    xh(e, Ga(qa(t)));
  }
  /**
   * Renders a DOM Node (either an HTML element or text) out of the template.
   *
   * @param data Rendering data.
   */
  _renderNode(e) {
    let t;
    if (e.node ? t = this.tag && this.text : t = this.tag ? this.text : !this.text, t)
      throw new d("ui-template-wrong-syntax", this);
    return this.text ? this._renderText(e) : this._renderElement(e);
  }
  /**
   * Renders an HTML element out of the template.
   *
   * @param data Rendering data.
   */
  _renderElement(e) {
    let t = e.node;
    return t || (t = e.node = document.createElementNS(this.ns || y2, this.tag)), this._renderAttributes(e), this._renderElementChildren(e), this._setUpListeners(e), t;
  }
  /**
   * Renders a text node out of {@link module:ui/template~Template#text}.
   *
   * @param data Rendering data.
   */
  _renderText(e) {
    let t = e.node;
    return t ? e.revertData.text = t.textContent : t = e.node = document.createTextNode(""), an(this.text) ? this._bindToObservable({
      schema: this.text,
      updater: E2(t),
      data: e
    }) : t.textContent = this.text.join(""), t;
  }
  /**
   * Renders HTML element attributes out of {@link module:ui/template~Template#attributes}.
   *
   * @param data Rendering data.
   */
  _renderAttributes(e) {
    if (!this.attributes)
      return;
    const t = e.node, i = e.revertData;
    for (const s in this.attributes) {
      const r = t.getAttribute(s), o = this.attributes[s];
      i && (i.attributes[s] = r);
      const a = Ja(o) ? o[0].ns : null;
      if (an(o)) {
        const l = Ja(o) ? o[0].value : o;
        i && Ya(s) && l.unshift(r), this._bindToObservable({
          schema: l,
          updater: A2(t, s, a),
          data: e
        });
      } else if (s == "style" && typeof o[0] != "string")
        this._renderStyleAttribute(o[0], e);
      else {
        i && r && Ya(s) && o.unshift(r);
        const l = o.map((c) => c && (c.value || c)).reduce((c, u) => c.concat(u), []).reduce(Ph, "");
        ri(l) || t.setAttributeNS(a, s, l);
      }
    }
  }
  /**
   * Renders the `style` attribute of an HTML element based on
   * {@link module:ui/template~Template#attributes}.
   *
   * A style attribute is an object with static values:
   *
   * ```ts
   * attributes: {
   * 	style: {
   * 		color: 'red'
   * 	}
   * }
   * ```
   *
   * or values bound to {@link module:ui/model~Model} properties:
   *
   * ```ts
   * attributes: {
   * 	style: {
   * 		color: bind.to( ... )
   * 	}
   * }
   * ```
   *
   * Note: The `style` attribute is rendered without setting the namespace. It does not seem to be
   * needed.
   *
   * @param styles Styles located in `attributes.style` of {@link module:ui/template~TemplateDefinition}.
   * @param data Rendering data.
   */
  _renderStyleAttribute(e, t) {
    const i = t.node;
    for (const s in e) {
      const r = e[s];
      an(r) ? this._bindToObservable({
        schema: [r],
        updater: T2(i, s),
        data: t
      }) : i.style[s] = r;
    }
  }
  /**
   * Recursively renders HTML element's children from {@link module:ui/template~Template#children}.
   *
   * @param data Rendering data.
   */
  _renderElementChildren(e) {
    const t = e.node, i = e.intoFragment ? document.createDocumentFragment() : t, s = e.isApplying;
    let r = 0;
    for (const o of this.children)
      if (Kr(o)) {
        if (!s) {
          o.setParent(t);
          for (const a of o)
            i.appendChild(a.element);
        }
      } else if (yn(o))
        s || (o.isRendered || o.render(), i.appendChild(o.element));
      else if (lt(o))
        i.appendChild(o);
      else if (s) {
        const a = e.revertData, l = Za();
        a.children.push(l), o._renderNode({
          intoFragment: !1,
          node: i.childNodes[r++],
          isApplying: !0,
          revertData: l
        });
      } else
        i.appendChild(o.render());
    e.intoFragment && t.appendChild(i);
  }
  /**
   * Activates `on` event listeners from the {@link module:ui/template~TemplateDefinition}
   * on an HTML element.
   *
   * @param data Rendering data.
   */
  _setUpListeners(e) {
    if (this.eventListeners)
      for (const t in this.eventListeners) {
        const i = this.eventListeners[t].map((s) => {
          const [r, o] = t.split("@");
          return s.activateDomEventListener(r, o, e);
        });
        e.revertData && e.revertData.bindings.push(i);
      }
  }
  /**
   * For a given {@link module:ui/template~TemplateValueSchema} containing {@link module:ui/template~TemplateBinding}
   * activates the binding and sets its initial value.
   *
   * Note: {@link module:ui/template~TemplateValueSchema} can be for HTML element attributes or
   * text node `textContent`.
   *
   * @param options Binding options.
   * @param options.updater A function which updates the DOM (like attribute or text).
   * @param options.data Rendering data.
   */
  _bindToObservable({ schema: e, updater: t, data: i }) {
    const s = i.revertData;
    Ah(e, t, i);
    const r = e.filter((o) => !ri(o)).filter((o) => o.observable).map((o) => o.activateAttributeListener(e, t, i));
    s && s.bindings.push(r);
  }
  /**
   * Reverts {@link module:ui/template~RenderData#revertData template data} from a node to
   * return it to the original state.
   *
   * @param node A node to be reverted.
   * @param revertData An object that stores information about what changes have been made by
   * {@link #apply} to the node. See {@link module:ui/template~RenderData#revertData} for more information.
   */
  _revertTemplateFromNode(e, t) {
    for (const s of t.bindings)
      for (const r of s)
        r();
    if (t.text) {
      e.textContent = t.text;
      return;
    }
    const i = e;
    for (const s in t.attributes) {
      const r = t.attributes[s];
      r === null ? i.removeAttribute(s) : i.setAttribute(s, r);
    }
    for (let s = 0; s < t.children.length; ++s)
      this._revertTemplateFromNode(i.childNodes[s], t.children[s]);
  }
}
class Hi {
  /**
   * Creates an instance of the {@link module:ui/template~TemplateBinding} class.
   *
   * @param def The definition of the binding.
   */
  constructor(e) {
    this.attribute = e.attribute, this.observable = e.observable, this.emitter = e.emitter, this.callback = e.callback;
  }
  /**
   * Returns the value of the binding. It is the value of the {@link module:ui/template~TemplateBinding#attribute} in
   * {@link module:ui/template~TemplateBinding#observable}. The value may be processed by the
   * {@link module:ui/template~TemplateBinding#callback}, if such has been passed to the binding.
   *
   * @param node A native DOM node, passed to the custom {@link module:ui/template~TemplateBinding#callback}.
   * @returns The value of {@link module:ui/template~TemplateBinding#attribute} in
   * {@link module:ui/template~TemplateBinding#observable}.
   */
  getValue(e) {
    const t = this.observable[this.attribute];
    return this.callback ? this.callback(t, e) : t;
  }
  /**
   * Activates the listener which waits for changes of the {@link module:ui/template~TemplateBinding#attribute} in
   * {@link module:ui/template~TemplateBinding#observable}, then updates the DOM with the aggregated
   * value of {@link module:ui/template~TemplateValueSchema}.
   *
   * @param schema A full schema to generate an attribute or text in the DOM.
   * @param updater A DOM updater function used to update the native DOM attribute or text.
   * @param data Rendering data.
   * @returns A function to sever the listener binding.
   */
  activateAttributeListener(e, t, i) {
    const s = () => Ah(e, t, i);
    return this.emitter.listenTo(this.observable, `change:${this.attribute}`, s), () => {
      this.emitter.stopListening(this.observable, `change:${this.attribute}`, s);
    };
  }
}
class k2 extends Hi {
  constructor(e) {
    super(e), this.eventNameOrFunction = e.eventNameOrFunction;
  }
  /**
   * Activates the listener for the native DOM event, which when fired, is propagated by
   * the {@link module:ui/template~TemplateBinding#emitter}.
   *
   * @param domEvtName The name of the native DOM event.
   * @param domSelector The selector in the DOM to filter delegated events.
   * @param data Rendering data.
   * @returns A function to sever the listener binding.
   */
  activateDomEventListener(e, t, i) {
    const s = (r, o) => {
      (!t || o.target.matches(t)) && (typeof this.eventNameOrFunction == "function" ? this.eventNameOrFunction(o) : this.observable.fire(this.eventNameOrFunction, o));
    };
    return this.emitter.listenTo(i.node, e, s), () => {
      this.emitter.stopListening(i.node, e, s);
    };
  }
}
class Eh extends Hi {
  constructor(e) {
    super(e), this.valueIfTrue = e.valueIfTrue;
  }
  /**
   * @inheritDoc
   */
  getValue(e) {
    const t = super.getValue(e);
    return ri(t) ? !1 : this.valueIfTrue || !0;
  }
}
function an(n) {
  return n ? (n.value && (n = n.value), Array.isArray(n) ? n.some(an) : n instanceof Hi) : !1;
}
function C2(n, e) {
  return n.map((t) => t instanceof Hi ? t.getValue(e) : t);
}
function Ah(n, e, { node: t }) {
  const i = C2(n, t);
  let s;
  n.length == 1 && n[0] instanceof Eh ? s = i[0] : s = i.reduce(Ph, ""), ri(s) ? e.remove() : e.set(s);
}
function E2(n) {
  return {
    set(e) {
      n.textContent = e;
    },
    remove() {
      n.textContent = "";
    }
  };
}
function A2(n, e, t) {
  return {
    set(i) {
      n.setAttributeNS(t, e, i);
    },
    remove() {
      n.removeAttributeNS(t, e);
    }
  };
}
function T2(n, e) {
  return {
    set(t) {
      n.style[e] = t;
    },
    remove() {
      n.style[e] = null;
    }
  };
}
function qa(n) {
  return Tr(n, (t) => {
    if (t && (t instanceof Hi || Gr(t) || yn(t) || Kr(t)))
      return t;
  });
}
function Ga(n) {
  if (typeof n == "string" ? n = S2(n) : n.text && I2(n), n.on && (n.eventListeners = x2(n.on), delete n.on), !n.text) {
    n.attributes && P2(n.attributes);
    const e = [];
    if (n.children)
      if (Kr(n.children))
        e.push(n.children);
      else
        for (const t of n.children)
          Gr(t) || yn(t) || lt(t) ? e.push(t) : e.push(new Ce(t));
    n.children = e;
  }
  return n;
}
function P2(n) {
  for (const e in n)
    n[e].value && (n[e].value = X(n[e].value)), Th(n, e);
}
function x2(n) {
  for (const e in n)
    Th(n, e);
  return n;
}
function S2(n) {
  return {
    text: [n]
  };
}
function I2(n) {
  n.text = X(n.text);
}
function Th(n, e) {
  n[e] = X(n[e]);
}
function Ph(n, e) {
  return ri(e) ? n : ri(n) ? e : `${n} ${e}`;
}
function Ka(n, e) {
  for (const t in e)
    n[t] ? n[t].push(...e[t]) : n[t] = e[t];
}
function xh(n, e) {
  if (e.attributes && (n.attributes || (n.attributes = {}), Ka(n.attributes, e.attributes)), e.eventListeners && (n.eventListeners || (n.eventListeners = {}), Ka(n.eventListeners, e.eventListeners)), e.text && n.text.push(...e.text), e.children && e.children.length) {
    if (n.children.length != e.children.length)
      throw new d("ui-template-extend-children-mismatch", n);
    let t = 0;
    for (const i of e.children)
      xh(n.children[t++], i);
  }
}
function ri(n) {
  return !n && n !== 0;
}
function yn(n) {
  return n instanceof T;
}
function Gr(n) {
  return n instanceof Ce;
}
function Kr(n) {
  return n instanceof nt;
}
function Ja(n) {
  return G(n[0]) && n[0].ns;
}
function Za() {
  return {
    children: [],
    bindings: [],
    attributes: {}
  };
}
function Ya(n) {
  return n == "class" || n == "style";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class R2 extends nt {
  /**
   * Creates a new instance of the {@link module:ui/editorui/bodycollection~BodyCollection}.
   *
   * @param locale The {@link module:core/editor/editor~Editor editor's locale} instance.
   * @param initialItems The initial items of the collection.
   */
  constructor(e, t = []) {
    super(t), this.locale = e;
  }
  /**
   * The element holding elements of the body region.
   */
  get bodyCollectionContainer() {
    return this._bodyCollectionContainer;
  }
  /**
   * Attaches the body collection to the DOM body element. You need to execute this method to render the content of
   * the body collection.
   */
  attachToDom() {
    this._bodyCollectionContainer = new Ce({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-reset_all",
          "ck-body",
          "ck-rounded-corners"
        ],
        dir: this.locale.uiLanguageDirection
      },
      children: this
    }).render();
    let e = document.querySelector(".ck-body-wrapper");
    e || (e = w_(document, "div", { class: "ck-body-wrapper" }), document.body.appendChild(e)), e.appendChild(this._bodyCollectionContainer);
  }
  /**
   * Detaches the collection from the DOM structure. Use this method when you do not need to use the body collection
   * anymore to clean-up the DOM structure.
   */
  detachFromDom() {
    super.destroy(), this._bodyCollectionContainer && this._bodyCollectionContainer.remove();
    const e = document.querySelector(".ck-body-wrapper");
    e && e.childElementCount == 0 && e.remove();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class mt extends T {
  /**
   * @inheritDoc
   */
  constructor() {
    super();
    const e = this.bindTemplate;
    this.set("content", ""), this.set("viewBox", "0 0 20 20"), this.set("fillColor", ""), this.set("isColorInherited", !0), this.setTemplate({
      tag: "svg",
      ns: "http://www.w3.org/2000/svg",
      attributes: {
        class: [
          "ck",
          "ck-icon",
          // Exclude icon internals from the CSS reset to allow rich (non-monochromatic) icons
          // (https://github.com/ckeditor/ckeditor5/issues/12599).
          "ck-reset_all-excluded",
          // The class to remove the dynamic color inheritance is toggleable
          // (https://github.com/ckeditor/ckeditor5/issues/12599).
          e.if("isColorInherited", "ck-icon_inherit-color")
        ],
        viewBox: e.to("viewBox")
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this._updateXMLContent(), this._colorFillPaths(), this.on("change:content", () => {
      this._updateXMLContent(), this._colorFillPaths();
    }), this.on("change:fillColor", () => {
      this._colorFillPaths();
    });
  }
  /**
   * Updates the {@link #element} with the value of {@link #content}.
   */
  _updateXMLContent() {
    if (this.content) {
      const t = new DOMParser().parseFromString(this.content.trim(), "image/svg+xml").querySelector("svg"), i = t.getAttribute("viewBox");
      i && (this.viewBox = i);
      for (const { name: s, value: r } of Array.from(t.attributes))
        mt.presentationalAttributeNames.includes(s) && this.element.setAttribute(s, r);
      for (; this.element.firstChild; )
        this.element.removeChild(this.element.firstChild);
      for (; t.childNodes.length > 0; )
        this.element.appendChild(t.childNodes[0]);
    }
  }
  /**
   * Fills all child `path.ck-icon__fill` with the `#fillColor`.
   */
  _colorFillPaths() {
    this.fillColor && this.element.querySelectorAll(".ck-icon__fill").forEach((e) => {
      e.style.fill = this.fillColor;
    });
  }
}
mt.presentationalAttributeNames = [
  "alignment-baseline",
  "baseline-shift",
  "clip-path",
  "clip-rule",
  "color",
  "color-interpolation",
  "color-interpolation-filters",
  "color-rendering",
  "cursor",
  "direction",
  "display",
  "dominant-baseline",
  "fill",
  "fill-opacity",
  "fill-rule",
  "filter",
  "flood-color",
  "flood-opacity",
  "font-family",
  "font-size",
  "font-size-adjust",
  "font-stretch",
  "font-style",
  "font-variant",
  "font-weight",
  "image-rendering",
  "letter-spacing",
  "lighting-color",
  "marker-end",
  "marker-mid",
  "marker-start",
  "mask",
  "opacity",
  "overflow",
  "paint-order",
  "pointer-events",
  "shape-rendering",
  "stop-color",
  "stop-opacity",
  "stroke",
  "stroke-dasharray",
  "stroke-dashoffset",
  "stroke-linecap",
  "stroke-linejoin",
  "stroke-miterlimit",
  "stroke-opacity",
  "stroke-width",
  "text-anchor",
  "text-decoration",
  "text-overflow",
  "text-rendering",
  "transform",
  "unicode-bidi",
  "vector-effect",
  "visibility",
  "white-space",
  "word-spacing",
  "writing-mode"
];
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class H extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._focusDelayed = null;
    const t = this.bindTemplate, i = Ye();
    this.set("ariaChecked", void 0), this.set("ariaLabel", void 0), this.set("ariaLabelledBy", `ck-editor__aria-label_${i}`), this.set("class", void 0), this.set("labelStyle", void 0), this.set("icon", void 0), this.set("isEnabled", !0), this.set("isOn", !1), this.set("isVisible", !0), this.set("isToggleable", !1), this.set("keystroke", void 0), this.set("label", void 0), this.set("role", void 0), this.set("tabindex", -1), this.set("tooltip", !1), this.set("tooltipPosition", "s"), this.set("type", "button"), this.set("withText", !1), this.set("withKeystroke", !1), this.children = this.createCollection(), this.labelView = this._createLabelView(), this.iconView = new mt(), this.iconView.extendTemplate({
      attributes: {
        class: "ck-button__icon"
      }
    }), this.keystrokeView = this._createKeystrokeView(), this.bind("_tooltipString").to(this, "tooltip", this, "label", this, "keystroke", this._getTooltipString.bind(this));
    const s = {
      tag: "button",
      attributes: {
        class: [
          "ck",
          "ck-button",
          t.to("class"),
          t.if("isEnabled", "ck-disabled", (r) => !r),
          t.if("isVisible", "ck-hidden", (r) => !r),
          t.to("isOn", (r) => r ? "ck-on" : "ck-off"),
          t.if("withText", "ck-button_with-text"),
          t.if("withKeystroke", "ck-button_with-keystroke")
        ],
        role: t.to("role"),
        type: t.to("type", (r) => r || "button"),
        tabindex: t.to("tabindex"),
        "aria-label": t.to("ariaLabel"),
        "aria-labelledby": t.to("ariaLabelledBy"),
        "aria-disabled": t.if("isEnabled", !0, (r) => !r),
        "aria-checked": t.to("isOn"),
        "aria-pressed": t.to("isOn", (r) => this.isToggleable ? String(!!r) : !1),
        "data-cke-tooltip-text": t.to("_tooltipString"),
        "data-cke-tooltip-position": t.to("tooltipPosition")
      },
      children: this.children,
      on: {
        click: t.to((r) => {
          this.isEnabled ? this.fire("execute") : r.preventDefault();
        })
      }
    };
    S.isSafari && (this._focusDelayed || (this._focusDelayed = Ws(() => this.focus(), 0)), s.on.mousedown = t.to(() => {
      this._focusDelayed();
    }), s.on.mouseup = t.to(() => {
      this._focusDelayed.cancel();
    })), this.setTemplate(s);
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.icon && (this.iconView.bind("content").to(this, "icon"), this.children.add(this.iconView)), this.children.add(this.labelView), this.withKeystroke && this.keystroke && this.children.add(this.keystrokeView);
  }
  /**
   * Focuses the {@link #element} of the button.
   */
  focus() {
    this.element.focus();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    this._focusDelayed && this._focusDelayed.cancel(), super.destroy();
  }
  /**
   * Creates a label view instance and binds it with button attributes.
   */
  _createLabelView() {
    const e = new T(), t = this.bindTemplate;
    return e.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-button__label"
        ],
        style: t.to("labelStyle"),
        id: this.ariaLabelledBy
      },
      children: [
        {
          text: t.to("label")
        }
      ]
    }), e;
  }
  /**
   * Creates a view that displays a keystroke next to a {@link #labelView label }
   * and binds it with button attributes.
   */
  _createKeystrokeView() {
    const e = new T();
    return e.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-button__keystroke"
        ]
      },
      children: [
        {
          text: this.bindTemplate.to("keystroke", (t) => oa(t))
        }
      ]
    }), e;
  }
  /**
   * Gets the text for the tooltip from the combination of
   * {@link #tooltip}, {@link #label} and {@link #keystroke} attributes.
   *
   * @see #tooltip
   * @see #_tooltipString
   * @param tooltip Button tooltip.
   * @param label Button label.
   * @param keystroke Button keystroke.
   */
  _getTooltipString(e, t, i) {
    return e ? typeof e == "string" ? e : (i && (i = oa(i)), e instanceof Function ? e(t, i) : `${t}${i ? ` (${i})` : ""}`) : "";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Jr extends H {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.isToggleable = !0, this.toggleSwitchView = this._createToggleView(), this.extendTemplate({
      attributes: {
        class: "ck-switchbutton"
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.children.add(this.toggleSwitchView);
  }
  /**
   * Creates a toggle child view.
   */
  _createToggleView() {
    const e = new T();
    return e.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-button__toggle"
        ]
      },
      children: [
        {
          tag: "span",
          attributes: {
            class: [
              "ck",
              "ck-button__toggle__inner"
            ]
          }
        }
      ]
    }), e;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function O2(n, e) {
  const t = n.t, i = {
    Black: t("Black"),
    "Dim grey": t("Dim grey"),
    Grey: t("Grey"),
    "Light grey": t("Light grey"),
    White: t("White"),
    Red: t("Red"),
    Orange: t("Orange"),
    Yellow: t("Yellow"),
    "Light green": t("Light green"),
    Green: t("Green"),
    Aquamarine: t("Aquamarine"),
    Turquoise: t("Turquoise"),
    "Light blue": t("Light blue"),
    Blue: t("Blue"),
    Purple: t("Purple")
  };
  return e.map((s) => {
    const r = i[s.label];
    return r && r != s.label && (s.label = r), s;
  });
}
function M2(n) {
  return n.map(V2).filter((e) => !!e);
}
function V2(n) {
  return typeof n == "string" ? {
    model: n,
    label: n,
    hasBorder: !1,
    view: {
      name: "span",
      styles: {
        color: n
      }
    }
  } : {
    model: n.color,
    label: n.label || n.color,
    hasBorder: n.hasBorder === void 0 ? !1 : n.hasBorder,
    view: {
      name: "span",
      styles: {
        color: `${n.color}`
      }
    }
  };
}
const D2 = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path class="ck-icon__fill" d="M16.935 5.328a2 2 0 0 1 0 2.829l-7.778 7.778a2 2 0 0 1-2.829 0L3.5 13.107a1.999 1.999 0 1 1 2.828-2.829l.707.707a1 1 0 0 0 1.414 0l5.658-5.657a2 2 0 0 1 2.828 0z"/><path d="M14.814 6.035 8.448 12.4a1 1 0 0 1-1.414 0l-1.413-1.415A1 1 0 1 0 4.207 12.4l2.829 2.829a1 1 0 0 0 1.414 0l7.778-7.778a1 1 0 1 0-1.414-1.415z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Sh extends H {
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.set("color", void 0), this.set("hasBorder", !1), this.icon = D2, this.extendTemplate({
      attributes: {
        style: {
          backgroundColor: t.to("color")
        },
        class: [
          "ck",
          "ck-color-grid__tile",
          t.if("hasBorder", "ck-color-table__color-tile_bordered")
        ]
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.iconView.fillColor = "hsl(0, 0%, 100%)";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Xa extends T {
  /**
   * Creates an instance of a color grid containing {@link module:ui/colorgrid/colortileview~ColorTileView tiles}.
   *
   * @fires execute
   * @param locale The localization services instance.
   * @param options Component configuration
   * @param options.colorDefinitions Array with definitions
   * required to create the {@link module:ui/colorgrid/colortileview~ColorTileView tiles}.
   * @param options.columns A number of columns to display the tiles.
   */
  constructor(e, t) {
    super(e);
    const i = t && t.colorDefinitions ? t.colorDefinitions : [];
    this.columns = t && t.columns ? t.columns : 5;
    const s = {
      gridTemplateColumns: `repeat( ${this.columns}, 1fr)`
    };
    this.set("selectedColor", void 0), this.items = this.createCollection(), this.focusTracker = new ye(), this.keystrokes = new Oe(), this.items.on("add", (r, o) => {
      o.isOn = o.color === this.selectedColor;
    }), i.forEach((r) => {
      const o = new Sh();
      o.set({
        color: r.color,
        label: r.label,
        tooltip: !0,
        hasBorder: r.options.hasBorder
      }), o.on("execute", () => {
        this.fire("execute", {
          value: r.color,
          hasBorder: r.options.hasBorder,
          label: r.label
        });
      }), this.items.add(o);
    }), this.setTemplate({
      tag: "div",
      children: this.items,
      attributes: {
        class: [
          "ck",
          "ck-color-grid"
        ],
        style: s
      }
    }), this.on("change:selectedColor", (r, o, a) => {
      for (const l of this.items)
        l.isOn = l.color === a;
    });
  }
  /**
   * Focuses the first focusable in {@link #items}.
   */
  focus() {
    this.items.length && this.items.first.focus();
  }
  /**
   * Focuses the last focusable in {@link #items}.
   */
  focusLast() {
    this.items.length && this.items.last.focus();
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render();
    for (const e of this.items)
      this.focusTracker.add(e.element);
    this.items.on("add", (e, t) => {
      this.focusTracker.add(t.element);
    }), this.items.on("remove", (e, t) => {
      this.focusTracker.remove(t.element);
    }), this.keystrokes.listenTo(this.element), _2({
      keystrokeHandler: this.keystrokes,
      focusTracker: this.focusTracker,
      gridItems: this.items,
      numberOfColumns: this.columns,
      uiLanguageDirection: this.locale && this.locale.uiLanguageDirection
    });
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
}
function Ih(n) {
  return n && n.__esModule && Object.prototype.hasOwnProperty.call(n, "default") ? n.default : n;
}
var Rh = {
  aliceblue: [240, 248, 255],
  antiquewhite: [250, 235, 215],
  aqua: [0, 255, 255],
  aquamarine: [127, 255, 212],
  azure: [240, 255, 255],
  beige: [245, 245, 220],
  bisque: [255, 228, 196],
  black: [0, 0, 0],
  blanchedalmond: [255, 235, 205],
  blue: [0, 0, 255],
  blueviolet: [138, 43, 226],
  brown: [165, 42, 42],
  burlywood: [222, 184, 135],
  cadetblue: [95, 158, 160],
  chartreuse: [127, 255, 0],
  chocolate: [210, 105, 30],
  coral: [255, 127, 80],
  cornflowerblue: [100, 149, 237],
  cornsilk: [255, 248, 220],
  crimson: [220, 20, 60],
  cyan: [0, 255, 255],
  darkblue: [0, 0, 139],
  darkcyan: [0, 139, 139],
  darkgoldenrod: [184, 134, 11],
  darkgray: [169, 169, 169],
  darkgreen: [0, 100, 0],
  darkgrey: [169, 169, 169],
  darkkhaki: [189, 183, 107],
  darkmagenta: [139, 0, 139],
  darkolivegreen: [85, 107, 47],
  darkorange: [255, 140, 0],
  darkorchid: [153, 50, 204],
  darkred: [139, 0, 0],
  darksalmon: [233, 150, 122],
  darkseagreen: [143, 188, 143],
  darkslateblue: [72, 61, 139],
  darkslategray: [47, 79, 79],
  darkslategrey: [47, 79, 79],
  darkturquoise: [0, 206, 209],
  darkviolet: [148, 0, 211],
  deeppink: [255, 20, 147],
  deepskyblue: [0, 191, 255],
  dimgray: [105, 105, 105],
  dimgrey: [105, 105, 105],
  dodgerblue: [30, 144, 255],
  firebrick: [178, 34, 34],
  floralwhite: [255, 250, 240],
  forestgreen: [34, 139, 34],
  fuchsia: [255, 0, 255],
  gainsboro: [220, 220, 220],
  ghostwhite: [248, 248, 255],
  gold: [255, 215, 0],
  goldenrod: [218, 165, 32],
  gray: [128, 128, 128],
  green: [0, 128, 0],
  greenyellow: [173, 255, 47],
  grey: [128, 128, 128],
  honeydew: [240, 255, 240],
  hotpink: [255, 105, 180],
  indianred: [205, 92, 92],
  indigo: [75, 0, 130],
  ivory: [255, 255, 240],
  khaki: [240, 230, 140],
  lavender: [230, 230, 250],
  lavenderblush: [255, 240, 245],
  lawngreen: [124, 252, 0],
  lemonchiffon: [255, 250, 205],
  lightblue: [173, 216, 230],
  lightcoral: [240, 128, 128],
  lightcyan: [224, 255, 255],
  lightgoldenrodyellow: [250, 250, 210],
  lightgray: [211, 211, 211],
  lightgreen: [144, 238, 144],
  lightgrey: [211, 211, 211],
  lightpink: [255, 182, 193],
  lightsalmon: [255, 160, 122],
  lightseagreen: [32, 178, 170],
  lightskyblue: [135, 206, 250],
  lightslategray: [119, 136, 153],
  lightslategrey: [119, 136, 153],
  lightsteelblue: [176, 196, 222],
  lightyellow: [255, 255, 224],
  lime: [0, 255, 0],
  limegreen: [50, 205, 50],
  linen: [250, 240, 230],
  magenta: [255, 0, 255],
  maroon: [128, 0, 0],
  mediumaquamarine: [102, 205, 170],
  mediumblue: [0, 0, 205],
  mediumorchid: [186, 85, 211],
  mediumpurple: [147, 112, 219],
  mediumseagreen: [60, 179, 113],
  mediumslateblue: [123, 104, 238],
  mediumspringgreen: [0, 250, 154],
  mediumturquoise: [72, 209, 204],
  mediumvioletred: [199, 21, 133],
  midnightblue: [25, 25, 112],
  mintcream: [245, 255, 250],
  mistyrose: [255, 228, 225],
  moccasin: [255, 228, 181],
  navajowhite: [255, 222, 173],
  navy: [0, 0, 128],
  oldlace: [253, 245, 230],
  olive: [128, 128, 0],
  olivedrab: [107, 142, 35],
  orange: [255, 165, 0],
  orangered: [255, 69, 0],
  orchid: [218, 112, 214],
  palegoldenrod: [238, 232, 170],
  palegreen: [152, 251, 152],
  paleturquoise: [175, 238, 238],
  palevioletred: [219, 112, 147],
  papayawhip: [255, 239, 213],
  peachpuff: [255, 218, 185],
  peru: [205, 133, 63],
  pink: [255, 192, 203],
  plum: [221, 160, 221],
  powderblue: [176, 224, 230],
  purple: [128, 0, 128],
  rebeccapurple: [102, 51, 153],
  red: [255, 0, 0],
  rosybrown: [188, 143, 143],
  royalblue: [65, 105, 225],
  saddlebrown: [139, 69, 19],
  salmon: [250, 128, 114],
  sandybrown: [244, 164, 96],
  seagreen: [46, 139, 87],
  seashell: [255, 245, 238],
  sienna: [160, 82, 45],
  silver: [192, 192, 192],
  skyblue: [135, 206, 235],
  slateblue: [106, 90, 205],
  slategray: [112, 128, 144],
  slategrey: [112, 128, 144],
  snow: [255, 250, 250],
  springgreen: [0, 255, 127],
  steelblue: [70, 130, 180],
  tan: [210, 180, 140],
  teal: [0, 128, 128],
  thistle: [216, 191, 216],
  tomato: [255, 99, 71],
  turquoise: [64, 224, 208],
  violet: [238, 130, 238],
  wheat: [245, 222, 179],
  white: [255, 255, 255],
  whitesmoke: [245, 245, 245],
  yellow: [255, 255, 0],
  yellowgreen: [154, 205, 50]
};
const Qa = /* @__PURE__ */ Ih(Rh);
var el = {
  red: 0,
  orange: 60,
  yellow: 120,
  green: 180,
  blue: 240,
  purple: 300
};
function tl(n) {
  var e, t = [], i = 1, s;
  if (typeof n == "string")
    if (Qa[n])
      t = Qa[n].slice(), s = "rgb";
    else if (n === "transparent")
      i = 0, s = "rgb", t = [0, 0, 0];
    else if (/^#[A-Fa-f0-9]+$/.test(n)) {
      var r = n.slice(1), o = r.length, a = o <= 4;
      i = 1, a ? (t = [
        parseInt(r[0] + r[0], 16),
        parseInt(r[1] + r[1], 16),
        parseInt(r[2] + r[2], 16)
      ], o === 4 && (i = parseInt(r[3] + r[3], 16) / 255)) : (t = [
        parseInt(r[0] + r[1], 16),
        parseInt(r[2] + r[3], 16),
        parseInt(r[4] + r[5], 16)
      ], o === 8 && (i = parseInt(r[6] + r[7], 16) / 255)), t[0] || (t[0] = 0), t[1] || (t[1] = 0), t[2] || (t[2] = 0), s = "rgb";
    } else if (e = /^((?:rgb|hs[lvb]|hwb|cmyk?|xy[zy]|gray|lab|lchu?v?|[ly]uv|lms)a?)\s*\(([^\)]*)\)/.exec(n)) {
      var l = e[1], c = l === "rgb", r = l.replace(/a$/, "");
      s = r;
      var o = r === "cmyk" ? 4 : r === "gray" ? 1 : 3;
      t = e[2].trim().split(/\s*[,\/]\s*|\s+/).map(function(f, m) {
        if (/%$/.test(f))
          return m === o ? parseFloat(f) / 100 : r === "rgb" ? parseFloat(f) * 255 / 100 : parseFloat(f);
        if (r[m] === "h") {
          if (/deg$/.test(f))
            return parseFloat(f);
          if (el[f] !== void 0)
            return el[f];
        }
        return parseFloat(f);
      }), l === r && t.push(1), i = c || t[o] === void 0 ? 1 : t[o], t = t.slice(0, o);
    } else
      n.length > 10 && /[0-9](?:\s|\/)/.test(n) && (t = n.match(/([0-9]+)/g).map(function(u) {
        return parseFloat(u);
      }), s = n.match(/([a-z])/ig).join("").toLowerCase());
  else
    isNaN(n) ? Array.isArray(n) || n.length ? (t = [n[0], n[1], n[2]], s = "rgb", i = n.length === 4 ? n[3] : 1) : n instanceof Object && (n.r != null || n.red != null || n.R != null ? (s = "rgb", t = [
      n.r || n.red || n.R || 0,
      n.g || n.green || n.G || 0,
      n.b || n.blue || n.B || 0
    ]) : (s = "hsl", t = [
      n.h || n.hue || n.H || 0,
      n.s || n.saturation || n.S || 0,
      n.l || n.lightness || n.L || n.b || n.brightness
    ]), i = n.a || n.alpha || n.opacity || 1, n.opacity != null && (i /= 100)) : (s = "rgb", t = [n >>> 16, (n & 65280) >>> 8, n & 255]);
  return {
    space: s,
    values: t,
    alpha: i
  };
}
const Fi = Rh, Oh = {};
for (const n of Object.keys(Fi))
  Oh[Fi[n]] = n;
const y = {
  rgb: { channels: 3, labels: "rgb" },
  hsl: { channels: 3, labels: "hsl" },
  hsv: { channels: 3, labels: "hsv" },
  hwb: { channels: 3, labels: "hwb" },
  cmyk: { channels: 4, labels: "cmyk" },
  xyz: { channels: 3, labels: "xyz" },
  lab: { channels: 3, labels: "lab" },
  lch: { channels: 3, labels: "lch" },
  hex: { channels: 1, labels: ["hex"] },
  keyword: { channels: 1, labels: ["keyword"] },
  ansi16: { channels: 1, labels: ["ansi16"] },
  ansi256: { channels: 1, labels: ["ansi256"] },
  hcg: { channels: 3, labels: ["h", "c", "g"] },
  apple: { channels: 3, labels: ["r16", "g16", "b16"] },
  gray: { channels: 1, labels: ["gray"] }
};
var Mh = y;
for (const n of Object.keys(y)) {
  if (!("channels" in y[n]))
    throw new Error("missing channels property: " + n);
  if (!("labels" in y[n]))
    throw new Error("missing channel labels property: " + n);
  if (y[n].labels.length !== y[n].channels)
    throw new Error("channel and label counts mismatch: " + n);
  const { channels: e, labels: t } = y[n];
  delete y[n].channels, delete y[n].labels, Object.defineProperty(y[n], "channels", { value: e }), Object.defineProperty(y[n], "labels", { value: t });
}
y.rgb.hsl = function(n) {
  const e = n[0] / 255, t = n[1] / 255, i = n[2] / 255, s = Math.min(e, t, i), r = Math.max(e, t, i), o = r - s;
  let a, l;
  r === s ? a = 0 : e === r ? a = (t - i) / o : t === r ? a = 2 + (i - e) / o : i === r && (a = 4 + (e - t) / o), a = Math.min(a * 60, 360), a < 0 && (a += 360);
  const c = (s + r) / 2;
  return r === s ? l = 0 : c <= 0.5 ? l = o / (r + s) : l = o / (2 - r - s), [a, l * 100, c * 100];
};
y.rgb.hsv = function(n) {
  let e, t, i, s, r;
  const o = n[0] / 255, a = n[1] / 255, l = n[2] / 255, c = Math.max(o, a, l), u = c - Math.min(o, a, l), h = function(f) {
    return (c - f) / 6 / u + 1 / 2;
  };
  return u === 0 ? (s = 0, r = 0) : (r = u / c, e = h(o), t = h(a), i = h(l), o === c ? s = i - t : a === c ? s = 1 / 3 + e - i : l === c && (s = 2 / 3 + t - e), s < 0 ? s += 1 : s > 1 && (s -= 1)), [
    s * 360,
    r * 100,
    c * 100
  ];
};
y.rgb.hwb = function(n) {
  const e = n[0], t = n[1];
  let i = n[2];
  const s = y.rgb.hsl(n)[0], r = 1 / 255 * Math.min(e, Math.min(t, i));
  return i = 1 - 1 / 255 * Math.max(e, Math.max(t, i)), [s, r * 100, i * 100];
};
y.rgb.cmyk = function(n) {
  const e = n[0] / 255, t = n[1] / 255, i = n[2] / 255, s = Math.min(1 - e, 1 - t, 1 - i), r = (1 - e - s) / (1 - s) || 0, o = (1 - t - s) / (1 - s) || 0, a = (1 - i - s) / (1 - s) || 0;
  return [r * 100, o * 100, a * 100, s * 100];
};
function B2(n, e) {
  return (n[0] - e[0]) ** 2 + (n[1] - e[1]) ** 2 + (n[2] - e[2]) ** 2;
}
y.rgb.keyword = function(n) {
  const e = Oh[n];
  if (e)
    return e;
  let t = 1 / 0, i;
  for (const s of Object.keys(Fi)) {
    const r = Fi[s], o = B2(n, r);
    o < t && (t = o, i = s);
  }
  return i;
};
y.keyword.rgb = function(n) {
  return Fi[n];
};
y.rgb.xyz = function(n) {
  let e = n[0] / 255, t = n[1] / 255, i = n[2] / 255;
  e = e > 0.04045 ? ((e + 0.055) / 1.055) ** 2.4 : e / 12.92, t = t > 0.04045 ? ((t + 0.055) / 1.055) ** 2.4 : t / 12.92, i = i > 0.04045 ? ((i + 0.055) / 1.055) ** 2.4 : i / 12.92;
  const s = e * 0.4124 + t * 0.3576 + i * 0.1805, r = e * 0.2126 + t * 0.7152 + i * 0.0722, o = e * 0.0193 + t * 0.1192 + i * 0.9505;
  return [s * 100, r * 100, o * 100];
};
y.rgb.lab = function(n) {
  const e = y.rgb.xyz(n);
  let t = e[0], i = e[1], s = e[2];
  t /= 95.047, i /= 100, s /= 108.883, t = t > 8856e-6 ? t ** (1 / 3) : 7.787 * t + 16 / 116, i = i > 8856e-6 ? i ** (1 / 3) : 7.787 * i + 16 / 116, s = s > 8856e-6 ? s ** (1 / 3) : 7.787 * s + 16 / 116;
  const r = 116 * i - 16, o = 500 * (t - i), a = 200 * (i - s);
  return [r, o, a];
};
y.hsl.rgb = function(n) {
  const e = n[0] / 360, t = n[1] / 100, i = n[2] / 100;
  let s, r, o;
  if (t === 0)
    return o = i * 255, [o, o, o];
  i < 0.5 ? s = i * (1 + t) : s = i + t - i * t;
  const a = 2 * i - s, l = [0, 0, 0];
  for (let c = 0; c < 3; c++)
    r = e + 1 / 3 * -(c - 1), r < 0 && r++, r > 1 && r--, 6 * r < 1 ? o = a + (s - a) * 6 * r : 2 * r < 1 ? o = s : 3 * r < 2 ? o = a + (s - a) * (2 / 3 - r) * 6 : o = a, l[c] = o * 255;
  return l;
};
y.hsl.hsv = function(n) {
  const e = n[0];
  let t = n[1] / 100, i = n[2] / 100, s = t;
  const r = Math.max(i, 0.01);
  i *= 2, t *= i <= 1 ? i : 2 - i, s *= r <= 1 ? r : 2 - r;
  const o = (i + t) / 2, a = i === 0 ? 2 * s / (r + s) : 2 * t / (i + t);
  return [e, a * 100, o * 100];
};
y.hsv.rgb = function(n) {
  const e = n[0] / 60, t = n[1] / 100;
  let i = n[2] / 100;
  const s = Math.floor(e) % 6, r = e - Math.floor(e), o = 255 * i * (1 - t), a = 255 * i * (1 - t * r), l = 255 * i * (1 - t * (1 - r));
  switch (i *= 255, s) {
    case 0:
      return [i, l, o];
    case 1:
      return [a, i, o];
    case 2:
      return [o, i, l];
    case 3:
      return [o, a, i];
    case 4:
      return [l, o, i];
    case 5:
      return [i, o, a];
  }
};
y.hsv.hsl = function(n) {
  const e = n[0], t = n[1] / 100, i = n[2] / 100, s = Math.max(i, 0.01);
  let r, o;
  o = (2 - t) * i;
  const a = (2 - t) * s;
  return r = t * s, r /= a <= 1 ? a : 2 - a, r = r || 0, o /= 2, [e, r * 100, o * 100];
};
y.hwb.rgb = function(n) {
  const e = n[0] / 360;
  let t = n[1] / 100, i = n[2] / 100;
  const s = t + i;
  let r;
  s > 1 && (t /= s, i /= s);
  const o = Math.floor(6 * e), a = 1 - i;
  r = 6 * e - o, o & 1 && (r = 1 - r);
  const l = t + r * (a - t);
  let c, u, h;
  switch (o) {
    default:
    case 6:
    case 0:
      c = a, u = l, h = t;
      break;
    case 1:
      c = l, u = a, h = t;
      break;
    case 2:
      c = t, u = a, h = l;
      break;
    case 3:
      c = t, u = l, h = a;
      break;
    case 4:
      c = l, u = t, h = a;
      break;
    case 5:
      c = a, u = t, h = l;
      break;
  }
  return [c * 255, u * 255, h * 255];
};
y.cmyk.rgb = function(n) {
  const e = n[0] / 100, t = n[1] / 100, i = n[2] / 100, s = n[3] / 100, r = 1 - Math.min(1, e * (1 - s) + s), o = 1 - Math.min(1, t * (1 - s) + s), a = 1 - Math.min(1, i * (1 - s) + s);
  return [r * 255, o * 255, a * 255];
};
y.xyz.rgb = function(n) {
  const e = n[0] / 100, t = n[1] / 100, i = n[2] / 100;
  let s, r, o;
  return s = e * 3.2406 + t * -1.5372 + i * -0.4986, r = e * -0.9689 + t * 1.8758 + i * 0.0415, o = e * 0.0557 + t * -0.204 + i * 1.057, s = s > 31308e-7 ? 1.055 * s ** (1 / 2.4) - 0.055 : s * 12.92, r = r > 31308e-7 ? 1.055 * r ** (1 / 2.4) - 0.055 : r * 12.92, o = o > 31308e-7 ? 1.055 * o ** (1 / 2.4) - 0.055 : o * 12.92, s = Math.min(Math.max(0, s), 1), r = Math.min(Math.max(0, r), 1), o = Math.min(Math.max(0, o), 1), [s * 255, r * 255, o * 255];
};
y.xyz.lab = function(n) {
  let e = n[0], t = n[1], i = n[2];
  e /= 95.047, t /= 100, i /= 108.883, e = e > 8856e-6 ? e ** (1 / 3) : 7.787 * e + 16 / 116, t = t > 8856e-6 ? t ** (1 / 3) : 7.787 * t + 16 / 116, i = i > 8856e-6 ? i ** (1 / 3) : 7.787 * i + 16 / 116;
  const s = 116 * t - 16, r = 500 * (e - t), o = 200 * (t - i);
  return [s, r, o];
};
y.lab.xyz = function(n) {
  const e = n[0], t = n[1], i = n[2];
  let s, r, o;
  r = (e + 16) / 116, s = t / 500 + r, o = r - i / 200;
  const a = r ** 3, l = s ** 3, c = o ** 3;
  return r = a > 8856e-6 ? a : (r - 16 / 116) / 7.787, s = l > 8856e-6 ? l : (s - 16 / 116) / 7.787, o = c > 8856e-6 ? c : (o - 16 / 116) / 7.787, s *= 95.047, r *= 100, o *= 108.883, [s, r, o];
};
y.lab.lch = function(n) {
  const e = n[0], t = n[1], i = n[2];
  let s;
  s = Math.atan2(i, t) * 360 / 2 / Math.PI, s < 0 && (s += 360);
  const o = Math.sqrt(t * t + i * i);
  return [e, o, s];
};
y.lch.lab = function(n) {
  const e = n[0], t = n[1], s = n[2] / 360 * 2 * Math.PI, r = t * Math.cos(s), o = t * Math.sin(s);
  return [e, r, o];
};
y.rgb.ansi16 = function(n, e = null) {
  const [t, i, s] = n;
  let r = e === null ? y.rgb.hsv(n)[2] : e;
  if (r = Math.round(r / 50), r === 0)
    return 30;
  let o = 30 + (Math.round(s / 255) << 2 | Math.round(i / 255) << 1 | Math.round(t / 255));
  return r === 2 && (o += 60), o;
};
y.hsv.ansi16 = function(n) {
  return y.rgb.ansi16(y.hsv.rgb(n), n[2]);
};
y.rgb.ansi256 = function(n) {
  const e = n[0], t = n[1], i = n[2];
  return e === t && t === i ? e < 8 ? 16 : e > 248 ? 231 : Math.round((e - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(e / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(i / 255 * 5);
};
y.ansi16.rgb = function(n) {
  let e = n % 10;
  if (e === 0 || e === 7)
    return n > 50 && (e += 3.5), e = e / 10.5 * 255, [e, e, e];
  const t = (~~(n > 50) + 1) * 0.5, i = (e & 1) * t * 255, s = (e >> 1 & 1) * t * 255, r = (e >> 2 & 1) * t * 255;
  return [i, s, r];
};
y.ansi256.rgb = function(n) {
  if (n >= 232) {
    const r = (n - 232) * 10 + 8;
    return [r, r, r];
  }
  n -= 16;
  let e;
  const t = Math.floor(n / 36) / 5 * 255, i = Math.floor((e = n % 36) / 6) / 5 * 255, s = e % 6 / 5 * 255;
  return [t, i, s];
};
y.rgb.hex = function(n) {
  const t = (((Math.round(n[0]) & 255) << 16) + ((Math.round(n[1]) & 255) << 8) + (Math.round(n[2]) & 255)).toString(16).toUpperCase();
  return "000000".substring(t.length) + t;
};
y.hex.rgb = function(n) {
  const e = n.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
  if (!e)
    return [0, 0, 0];
  let t = e[0];
  e[0].length === 3 && (t = t.split("").map((a) => a + a).join(""));
  const i = parseInt(t, 16), s = i >> 16 & 255, r = i >> 8 & 255, o = i & 255;
  return [s, r, o];
};
y.rgb.hcg = function(n) {
  const e = n[0] / 255, t = n[1] / 255, i = n[2] / 255, s = Math.max(Math.max(e, t), i), r = Math.min(Math.min(e, t), i), o = s - r;
  let a, l;
  return o < 1 ? a = r / (1 - o) : a = 0, o <= 0 ? l = 0 : s === e ? l = (t - i) / o % 6 : s === t ? l = 2 + (i - e) / o : l = 4 + (e - t) / o, l /= 6, l %= 1, [l * 360, o * 100, a * 100];
};
y.hsl.hcg = function(n) {
  const e = n[1] / 100, t = n[2] / 100, i = t < 0.5 ? 2 * e * t : 2 * e * (1 - t);
  let s = 0;
  return i < 1 && (s = (t - 0.5 * i) / (1 - i)), [n[0], i * 100, s * 100];
};
y.hsv.hcg = function(n) {
  const e = n[1] / 100, t = n[2] / 100, i = e * t;
  let s = 0;
  return i < 1 && (s = (t - i) / (1 - i)), [n[0], i * 100, s * 100];
};
y.hcg.rgb = function(n) {
  const e = n[0] / 360, t = n[1] / 100, i = n[2] / 100;
  if (t === 0)
    return [i * 255, i * 255, i * 255];
  const s = [0, 0, 0], r = e % 1 * 6, o = r % 1, a = 1 - o;
  let l = 0;
  switch (Math.floor(r)) {
    case 0:
      s[0] = 1, s[1] = o, s[2] = 0;
      break;
    case 1:
      s[0] = a, s[1] = 1, s[2] = 0;
      break;
    case 2:
      s[0] = 0, s[1] = 1, s[2] = o;
      break;
    case 3:
      s[0] = 0, s[1] = a, s[2] = 1;
      break;
    case 4:
      s[0] = o, s[1] = 0, s[2] = 1;
      break;
    default:
      s[0] = 1, s[1] = 0, s[2] = a;
  }
  return l = (1 - t) * i, [
    (t * s[0] + l) * 255,
    (t * s[1] + l) * 255,
    (t * s[2] + l) * 255
  ];
};
y.hcg.hsv = function(n) {
  const e = n[1] / 100, t = n[2] / 100, i = e + t * (1 - e);
  let s = 0;
  return i > 0 && (s = e / i), [n[0], s * 100, i * 100];
};
y.hcg.hsl = function(n) {
  const e = n[1] / 100, i = n[2] / 100 * (1 - e) + 0.5 * e;
  let s = 0;
  return i > 0 && i < 0.5 ? s = e / (2 * i) : i >= 0.5 && i < 1 && (s = e / (2 * (1 - i))), [n[0], s * 100, i * 100];
};
y.hcg.hwb = function(n) {
  const e = n[1] / 100, t = n[2] / 100, i = e + t * (1 - e);
  return [n[0], (i - e) * 100, (1 - i) * 100];
};
y.hwb.hcg = function(n) {
  const e = n[1] / 100, i = 1 - n[2] / 100, s = i - e;
  let r = 0;
  return s < 1 && (r = (i - s) / (1 - s)), [n[0], s * 100, r * 100];
};
y.apple.rgb = function(n) {
  return [n[0] / 65535 * 255, n[1] / 65535 * 255, n[2] / 65535 * 255];
};
y.rgb.apple = function(n) {
  return [n[0] / 255 * 65535, n[1] / 255 * 65535, n[2] / 255 * 65535];
};
y.gray.rgb = function(n) {
  return [n[0] / 100 * 255, n[0] / 100 * 255, n[0] / 100 * 255];
};
y.gray.hsl = function(n) {
  return [0, 0, n[0]];
};
y.gray.hsv = y.gray.hsl;
y.gray.hwb = function(n) {
  return [0, 100, n[0]];
};
y.gray.cmyk = function(n) {
  return [0, 0, 0, n[0]];
};
y.gray.lab = function(n) {
  return [n[0], 0, 0];
};
y.gray.hex = function(n) {
  const e = Math.round(n[0] / 100 * 255) & 255, i = ((e << 16) + (e << 8) + e).toString(16).toUpperCase();
  return "000000".substring(i.length) + i;
};
y.rgb.gray = function(n) {
  return [(n[0] + n[1] + n[2]) / 3 / 255 * 100];
};
const kn = Mh;
function F2() {
  const n = {}, e = Object.keys(kn);
  for (let t = e.length, i = 0; i < t; i++)
    n[e[i]] = {
      // http://jsperf.com/1-vs-infinity
      // micro-opt, but this is simple.
      distance: -1,
      parent: null
    };
  return n;
}
function N2(n) {
  const e = F2(), t = [n];
  for (e[n].distance = 0; t.length; ) {
    const i = t.pop(), s = Object.keys(kn[i]);
    for (let r = s.length, o = 0; o < r; o++) {
      const a = s[o], l = e[a];
      l.distance === -1 && (l.distance = e[i].distance + 1, l.parent = i, t.unshift(a));
    }
  }
  return e;
}
function L2(n, e) {
  return function(t) {
    return e(n(t));
  };
}
function $2(n, e) {
  const t = [e[n].parent, n];
  let i = kn[e[n].parent][n], s = e[n].parent;
  for (; e[s].parent; )
    t.unshift(e[s].parent), i = L2(kn[e[s].parent][s], i), s = e[s].parent;
  return i.conversion = t, i;
}
var z2 = function(n) {
  const e = N2(n), t = {}, i = Object.keys(e);
  for (let s = i.length, r = 0; r < s; r++) {
    const o = i[r];
    e[o].parent !== null && (t[o] = $2(o, e));
  }
  return t;
};
const ir = Mh, H2 = z2, Kt = {}, W2 = Object.keys(ir);
function U2(n) {
  const e = function(...t) {
    const i = t[0];
    return i == null ? i : (i.length > 1 && (t = i), n(t));
  };
  return "conversion" in n && (e.conversion = n.conversion), e;
}
function j2(n) {
  const e = function(...t) {
    const i = t[0];
    if (i == null)
      return i;
    i.length > 1 && (t = i);
    const s = n(t);
    if (typeof s == "object")
      for (let r = s.length, o = 0; o < r; o++)
        s[o] = Math.round(s[o]);
    return s;
  };
  return "conversion" in n && (e.conversion = n.conversion), e;
}
W2.forEach((n) => {
  Kt[n] = {}, Object.defineProperty(Kt[n], "channels", { value: ir[n].channels }), Object.defineProperty(Kt[n], "labels", { value: ir[n].labels });
  const e = H2(n);
  Object.keys(e).forEach((i) => {
    const s = e[i];
    Kt[n][i] = j2(s), Kt[n][i].raw = U2(s);
  });
});
var Vh = Kt;
const q2 = /* @__PURE__ */ Ih(Vh), Dh = /* @__PURE__ */ Bd({
  __proto__: null,
  default: q2
}, [Vh]);
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Bh(n, e) {
  if (!n)
    return "";
  const t = Fh(n);
  if (!t)
    return "";
  if (t.space === e)
    return n;
  if (!J2(t))
    return "";
  const s = Dh[t.space][e];
  if (!s)
    return "";
  const r = s(t.space === "hex" ? t.hexValue : t.values);
  return K2(r, e);
}
function G2(n) {
  if (!n)
    return "";
  const e = Fh(n);
  return e ? e.space === "hex" ? e.hexValue : Bh(n, "hex") : "#000";
}
function K2(n, e) {
  switch (e) {
    case "hex":
      return `#${n}`;
    case "rgb":
      return `rgb( ${n[0]}, ${n[1]}, ${n[2]} )`;
    case "hsl":
      return `hsl( ${n[0]}, ${n[1]}%, ${n[2]}% )`;
    case "hwb":
      return `hwb( ${n[0]}, ${n[1]}, ${n[2]} )`;
    case "lab":
      return `lab( ${n[0]}% ${n[1]} ${n[2]} )`;
    case "lch":
      return `lch( ${n[0]}% ${n[1]} ${n[2]} )`;
    default:
      return "";
  }
}
function Fh(n) {
  if (n.startsWith("#")) {
    const t = tl(n);
    return {
      space: "hex",
      values: t.values,
      hexValue: n,
      alpha: t.alpha
    };
  }
  const e = tl(n);
  return e.space ? e : null;
}
function J2(n) {
  return Object.keys(Dh).includes(n.space);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Nh extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.set("text", void 0), this.set("for", void 0), this.id = `ck-editor__label_${Ye()}`;
    const t = this.bindTemplate;
    this.setTemplate({
      tag: "label",
      attributes: {
        class: [
          "ck",
          "ck-label"
        ],
        id: this.id,
        for: t.to("for")
      },
      children: [
        {
          text: t.to("text")
        }
      ]
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $n extends T {
  /**
   * Creates an instance of the labeled field view class using a provided creator function
   * that provides the view to be labeled.
   *
   * @param locale The locale instance.
   * @param viewCreator A function that returns a {@link module:ui/view~View}
   * that will be labeled. The following arguments are passed to the creator function:
   *
   * * an instance of the `LabeledFieldView` to allow binding observable properties,
   * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM,
   * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM.
   */
  constructor(e, t) {
    super(e);
    const i = `ck-labeled-field-view-${Ye()}`, s = `ck-labeled-field-view-status-${Ye()}`;
    this.fieldView = t(this, i, s), this.set("label", void 0), this.set("isEnabled", !0), this.set("isEmpty", !0), this.set("isFocused", !1), this.set("errorText", null), this.set("infoText", null), this.set("class", void 0), this.set("placeholder", void 0), this.labelView = this._createLabelView(i), this.statusView = this._createStatusView(s), this.fieldWrapperChildren = this.createCollection([this.fieldView, this.labelView]), this.bind("_statusText").to(this, "errorText", this, "infoText", (o, a) => o || a);
    const r = this.bindTemplate;
    this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-labeled-field-view",
          r.to("class"),
          r.if("isEnabled", "ck-disabled", (o) => !o),
          r.if("isEmpty", "ck-labeled-field-view_empty"),
          r.if("isFocused", "ck-labeled-field-view_focused"),
          r.if("placeholder", "ck-labeled-field-view_placeholder"),
          r.if("errorText", "ck-error")
        ]
      },
      children: [
        {
          tag: "div",
          attributes: {
            class: [
              "ck",
              "ck-labeled-field-view__input-wrapper"
            ]
          },
          children: this.fieldWrapperChildren
        },
        this.statusView
      ]
    });
  }
  /**
   * Creates label view class instance and bind with view.
   *
   * @param id Unique id to set as labelView#for attribute.
   */
  _createLabelView(e) {
    const t = new Nh(this.locale);
    return t.for = e, t.bind("text").to(this, "label"), t;
  }
  /**
   * Creates the status view instance. It displays {@link #errorText} and {@link #infoText}
   * next to the {@link #fieldView}. See {@link #_statusText}.
   *
   * @param statusUid Unique id of the status, shared with the {@link #fieldView view's}
   * `aria-describedby` attribute.
   */
  _createStatusView(e) {
    const t = new T(this.locale), i = this.bindTemplate;
    return t.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-labeled-field-view__status",
          i.if("errorText", "ck-labeled-field-view__status_error"),
          i.if("_statusText", "ck-hidden", (s) => !s)
        ],
        id: e,
        role: i.if("errorText", "alert")
      },
      children: [
        {
          text: i.to("_statusText")
        }
      ]
    }), t;
  }
  /**
   * Focuses the {@link #fieldView}.
   */
  focus() {
    this.fieldView.focus();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Z2 extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.set("value", void 0), this.set("id", void 0), this.set("placeholder", void 0), this.set("isReadOnly", !1), this.set("hasError", !1), this.set("ariaDescribedById", void 0), this.focusTracker = new ye(), this.bind("isFocused").to(this.focusTracker), this.set("isEmpty", !0), this.set("inputMode", "text");
    const t = this.bindTemplate;
    this.setTemplate({
      tag: "input",
      attributes: {
        class: [
          "ck",
          "ck-input",
          t.if("isFocused", "ck-input_focused"),
          t.if("isEmpty", "ck-input-text_empty"),
          t.if("hasError", "ck-error")
        ],
        id: t.to("id"),
        placeholder: t.to("placeholder"),
        readonly: t.to("isReadOnly"),
        inputmode: t.to("inputMode"),
        "aria-invalid": t.if("hasError", !0),
        "aria-describedby": t.to("ariaDescribedById")
      },
      on: {
        input: t.to((...i) => {
          this.fire("input", ...i), this._updateIsEmpty();
        }),
        change: t.to(this._updateIsEmpty.bind(this))
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.focusTracker.add(this.element), this._setDomElementValue(this.value), this._updateIsEmpty(), this.on("change:value", (e, t, i) => {
      this._setDomElementValue(i), this._updateIsEmpty();
    });
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy();
  }
  /**
   * Moves the focus to the input and selects the value.
   */
  select() {
    this.element.select();
  }
  /**
   * Focuses the input.
   */
  focus() {
    this.element.focus();
  }
  /**
   * Updates the {@link #isEmpty} property value on demand.
   */
  _updateIsEmpty() {
    this.isEmpty = Y2(this.element);
  }
  /**
   * Sets the `value` property of the {@link #element DOM element} on demand.
   */
  _setDomElementValue(e) {
    this.element.value = !e && e !== 0 ? "" : e;
  }
}
function Y2(n) {
  return !n.value;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class X2 extends Z2 {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.extendTemplate({
      attributes: {
        type: "text",
        class: [
          "ck-input-text"
        ]
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Q2 extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.set("isVisible", !1), this.set("position", "se"), this.children = this.createCollection(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-reset",
          "ck-dropdown__panel",
          t.to("position", (i) => `ck-dropdown__panel_${i}`),
          t.if("isVisible", "ck-dropdown__panel-visible")
        ]
      },
      children: this.children,
      on: {
        // Drag and drop in the panel should not break the selection in the editor.
        // https://github.com/ckeditor/ckeditor5-ui/issues/228
        selectstart: t.to((i) => {
          i.target.tagName.toLocaleLowerCase() !== "input" && i.preventDefault();
        })
      }
    });
  }
  /**
   * Focuses the first view in the {@link #children} collection.
   *
   * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.
   */
  focus() {
    if (this.children.length) {
      const e = this.children.first;
      typeof e.focus == "function" ? e.focus() : q("ui-dropdown-panel-focus-child-missing-focus", { childView: this.children.first, dropdownPanel: this });
    }
  }
  /**
   * Focuses the view element or last item in view collection on opening dropdown's panel.
   *
   * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.
   */
  focusLast() {
    if (this.children.length) {
      const e = this.children.last;
      typeof e.focusLast == "function" ? e.focusLast() : e.focus();
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class oi extends T {
  /**
   * Creates an instance of the dropdown.
   *
   * Also see {@link #render}.
   *
   * @param locale The localization services instance.
   */
  constructor(e, t, i) {
    super(e);
    const s = this.bindTemplate;
    this.buttonView = t, this.panelView = i, this.set("isOpen", !1), this.set("isEnabled", !0), this.set("class", void 0), this.set("id", void 0), this.set("panelPosition", "auto"), this.keystrokes = new Oe(), this.focusTracker = new ye(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-dropdown",
          s.to("class"),
          s.if("isEnabled", "ck-disabled", (r) => !r)
        ],
        id: s.to("id"),
        "aria-describedby": s.to("ariaDescribedById")
      },
      children: [
        t,
        i
      ]
    }), t.extendTemplate({
      attributes: {
        class: [
          "ck-dropdown__button"
        ],
        "data-cke-tooltip-disabled": s.to("isOpen")
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.focusTracker.add(this.buttonView.element), this.focusTracker.add(this.panelView.element), this.listenTo(this.buttonView, "open", () => {
      this.isOpen = !this.isOpen;
    }), this.panelView.bind("isVisible").to(this, "isOpen"), this.on("change:isOpen", (t, i, s) => {
      s && (this.panelPosition === "auto" ? this.panelView.position = oi._getOptimalPosition({
        element: this.panelView.element,
        target: this.buttonView.element,
        fitInViewport: !0,
        positions: this._panelPositions
      }).name : this.panelView.position = this.panelPosition);
    }), this.keystrokes.listenTo(this.element);
    const e = (t, i) => {
      this.isOpen && (this.isOpen = !1, i());
    };
    this.keystrokes.set("arrowdown", (t, i) => {
      this.buttonView.isEnabled && !this.isOpen && (this.isOpen = !0, i());
    }), this.keystrokes.set("arrowright", (t, i) => {
      this.isOpen && i();
    }), this.keystrokes.set("arrowleft", e), this.keystrokes.set("esc", e);
  }
  /**
   * Focuses the {@link #buttonView}.
   */
  focus() {
    this.buttonView.focus();
  }
  /**
   * Returns {@link #panelView panel} positions to be used by the
   * {@link module:utils/dom/position~getOptimalPosition `getOptimalPosition()`}
   * utility considering the direction of the language the UI of the editor is displayed in.
   */
  get _panelPositions() {
    const { south: e, north: t, southEast: i, southWest: s, northEast: r, northWest: o, southMiddleEast: a, southMiddleWest: l, northMiddleEast: c, northMiddleWest: u } = oi.defaultPanelPositions;
    return this.locale.uiLanguageDirection !== "rtl" ? [
      i,
      s,
      a,
      l,
      e,
      r,
      o,
      c,
      u,
      t
    ] : [
      s,
      i,
      l,
      a,
      e,
      o,
      r,
      u,
      c,
      t
    ];
  }
}
oi.defaultPanelPositions = {
  south: (n, e) => ({
    top: n.bottom,
    left: n.left - (e.width - n.width) / 2,
    name: "s"
  }),
  southEast: (n) => ({
    top: n.bottom,
    left: n.left,
    name: "se"
  }),
  southWest: (n, e) => ({
    top: n.bottom,
    left: n.left - e.width + n.width,
    name: "sw"
  }),
  southMiddleEast: (n, e) => ({
    top: n.bottom,
    left: n.left - (e.width - n.width) / 4,
    name: "sme"
  }),
  southMiddleWest: (n, e) => ({
    top: n.bottom,
    left: n.left - (e.width - n.width) * 3 / 4,
    name: "smw"
  }),
  north: (n, e) => ({
    top: n.top - e.height,
    left: n.left - (e.width - n.width) / 2,
    name: "n"
  }),
  northEast: (n, e) => ({
    top: n.top - e.height,
    left: n.left,
    name: "ne"
  }),
  northWest: (n, e) => ({
    top: n.top - e.height,
    left: n.left - e.width + n.width,
    name: "nw"
  }),
  northMiddleEast: (n, e) => ({
    top: n.top - e.height,
    left: n.left - (e.width - n.width) / 4,
    name: "nme"
  }),
  northMiddleWest: (n, e) => ({
    top: n.top - e.height,
    left: n.left - (e.width - n.width) * 3 / 4,
    name: "nmw"
  })
};
oi._getOptimalPosition = vu;
const Lh = '<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"><path d="M.941 4.523a.75.75 0 1 1 1.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 1 1 1.06 1.06l-3.549 3.55a.75.75 0 0 1-1.168-.136L.941 4.523z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $h extends H {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.arrowView = this._createArrowView(), this.extendTemplate({
      attributes: {
        "aria-haspopup": !0,
        "aria-expanded": this.bindTemplate.to("isOn", (t) => String(t))
      }
    }), this.delegate("execute").to(this, "open");
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.children.add(this.arrowView);
  }
  /**
   * Creates a {@link module:ui/icon/iconview~IconView} instance as {@link #arrowView}.
   */
  _createArrowView() {
    const e = new mt();
    return e.content = Lh, e.extendTemplate({
      attributes: {
        class: "ck-dropdown__arrow"
      }
    }), e;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ft {
  /**
   * Creates an instance of the focus cycler utility.
   *
   * @param options Configuration options.
   */
  constructor(e) {
    if (this.focusables = e.focusables, this.focusTracker = e.focusTracker, this.keystrokeHandler = e.keystrokeHandler, this.actions = e.actions, e.actions && e.keystrokeHandler)
      for (const t in e.actions) {
        let i = e.actions[t];
        typeof i == "string" && (i = [i]);
        for (const s of i)
          e.keystrokeHandler.set(s, (r, o) => {
            this[t](), o();
          });
      }
  }
  /**
   * Returns the first focusable view in {@link #focusables}.
   * Returns `null` if there is none.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  get first() {
    return this.focusables.find(as) || null;
  }
  /**
   * Returns the last focusable view in {@link #focusables}.
   * Returns `null` if there is none.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  get last() {
    return this.focusables.filter(as).slice(-1)[0] || null;
  }
  /**
   * Returns the next focusable view in {@link #focusables} based on {@link #current}.
   * Returns `null` if there is none.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  get next() {
    return this._getFocusableItem(1);
  }
  /**
   * Returns the previous focusable view in {@link #focusables} based on {@link #current}.
   * Returns `null` if there is none.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  get previous() {
    return this._getFocusableItem(-1);
  }
  /**
   * An index of the view in the {@link #focusables} which is focused according
   * to {@link #focusTracker}. Returns `null` when there is no such view.
   */
  get current() {
    let e = null;
    return this.focusTracker.focusedElement === null ? null : (this.focusables.find((t, i) => {
      const s = t.element === this.focusTracker.focusedElement;
      return s && (e = i), s;
    }), e);
  }
  /**
   * Focuses the {@link #first} item in {@link #focusables}.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  focusFirst() {
    this._focus(this.first);
  }
  /**
   * Focuses the {@link #last} item in {@link #focusables}.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  focusLast() {
    this._focus(this.last);
  }
  /**
   * Focuses the {@link #next} item in {@link #focusables}.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  focusNext() {
    this._focus(this.next);
  }
  /**
   * Focuses the {@link #previous} item in {@link #focusables}.
   *
   * **Note**: Hidden views (e.g. with `display: none`) are ignored.
   */
  focusPrevious() {
    this._focus(this.previous);
  }
  /**
   * Focuses the given view if it exists.
   */
  _focus(e) {
    e && e.focus();
  }
  /**
   * Returns the next or previous focusable view in {@link #focusables} with respect
   * to {@link #current}.
   *
   * @param step Either `1` for checking forward from {@link #current} or `-1` for checking backwards.
   */
  _getFocusableItem(e) {
    const t = this.current, i = this.focusables.length;
    if (!i)
      return null;
    if (t === null)
      return this[e === 1 ? "first" : "last"];
    let s = (t + i + e) % i;
    do {
      const r = this.focusables.get(s);
      if (as(r))
        return r;
      s = (s + i + e) % i;
    } while (s !== t);
    return null;
  }
}
function as(n) {
  return !!(n.focus && St(n.element));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class zh extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-toolbar__separator"
        ]
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class eC extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-toolbar__line-break"
        ]
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function tC(n) {
  return n.bindTemplate.to((e) => {
    e.target === n.element && e.preventDefault();
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Hh(n) {
  return Array.isArray(n) ? {
    items: n,
    removeItems: []
  } : n ? Object.assign({
    items: [],
    removeItems: []
  }, n) : {
    items: [],
    removeItems: []
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const { threeVerticalDots: Wh } = D, iC = {
  alignLeft: D.alignLeft,
  bold: D.bold,
  importExport: D.importExport,
  paragraph: D.paragraph,
  plus: D.plus,
  text: D.text,
  threeVerticalDots: D.threeVerticalDots
};
class Zr extends T {
  /**
   * Creates an instance of the {@link module:ui/toolbar/toolbarview~ToolbarView} class.
   *
   * Also see {@link #render}.
   *
   * @param locale The localization services instance.
   * @param options Configuration options of the toolbar.
   */
  constructor(e, t) {
    super(e);
    const i = this.bindTemplate, s = this.t;
    this.options = t || {}, this.set("ariaLabel", s("Editor toolbar")), this.set("maxWidth", "auto"), this.items = this.createCollection(), this.focusTracker = new ye(), this.keystrokes = new Oe(), this.set("class", void 0), this.set("isCompact", !1), this.itemsView = new nC(e), this.children = this.createCollection(), this.children.add(this.itemsView), this.focusables = this.createCollection();
    const r = e.uiLanguageDirection === "rtl";
    this._focusCycler = new Ft({
      focusables: this.focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate toolbar items backwards using the arrow[left,up] keys.
        focusPrevious: [r ? "arrowright" : "arrowleft", "arrowup"],
        // Navigate toolbar items forwards using the arrow[right,down] keys.
        focusNext: [r ? "arrowleft" : "arrowright", "arrowdown"]
      }
    });
    const o = [
      "ck",
      "ck-toolbar",
      i.to("class"),
      i.if("isCompact", "ck-toolbar_compact")
    ];
    this.options.shouldGroupWhenFull && this.options.isFloating && o.push("ck-toolbar_floating"), this.setTemplate({
      tag: "div",
      attributes: {
        class: o,
        role: "toolbar",
        "aria-label": i.to("ariaLabel"),
        style: {
          maxWidth: i.to("maxWidth")
        },
        tabindex: -1
      },
      children: this.children,
      on: {
        // https://github.com/ckeditor/ckeditor5-ui/issues/206
        mousedown: tC(this)
      }
    }), this._behavior = this.options.shouldGroupWhenFull ? new rC(this) : new sC(this);
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.focusTracker.add(this.element);
    for (const e of this.items)
      this.focusTracker.add(e.element);
    this.items.on("add", (e, t) => {
      this.focusTracker.add(t.element);
    }), this.items.on("remove", (e, t) => {
      this.focusTracker.remove(t.element);
    }), this.keystrokes.listenTo(this.element), this._behavior.render(this);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    return this._behavior.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy(), super.destroy();
  }
  /**
   * Focuses the first focusable in {@link #focusables}.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * Focuses the last focusable in {@link #focusables}.
   */
  focusLast() {
    this._focusCycler.focusLast();
  }
  /**
   * A utility that expands the plain toolbar configuration into
   * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.
   *
   * @param itemsOrConfig The toolbar items or the entire toolbar configuration object.
   * @param factory A factory producing toolbar items.
   * @param removeItems An array of items names to be removed from the configuration. When present, applies
   * to this toolbar and all nested ones as well.
   */
  fillFromConfig(e, t, i) {
    this.items.addMany(this._buildItemsFromConfig(e, t, i));
  }
  /**
   * A utility that expands the plain toolbar configuration into a list of view items using a given component factory.
   *
   * @param itemsOrConfig The toolbar items or the entire toolbar configuration object.
   * @param factory A factory producing toolbar items.
   * @param removeItems An array of items names to be removed from the configuration. When present, applies
   * to this toolbar and all nested ones as well.
   */
  _buildItemsFromConfig(e, t, i) {
    const s = Hh(e), r = i || s.removeItems;
    return this._cleanItemsConfiguration(s.items, t, r).map((a) => G(a) ? this._createNestedToolbarDropdown(a, t, r) : a === "|" ? new zh() : a === "-" ? new eC() : t.create(a)).filter((a) => !!a);
  }
  /**
   * Cleans up the {@link module:ui/toolbar/toolbarview~ToolbarView#items} of the toolbar by removing unwanted items and
   * duplicated (obsolete) separators or line breaks.
   *
   * @param items The toolbar items configuration.
   * @param factory A factory producing toolbar items.
   * @param removeItems An array of items names to be removed from the configuration.
   * @returns Items after the clean-up.
   */
  _cleanItemsConfiguration(e, t, i) {
    const s = e.filter((r, o, a) => r === "|" ? !0 : i.indexOf(r) !== -1 ? !1 : r === "-" ? this.options.shouldGroupWhenFull ? (q("toolbarview-line-break-ignored-when-grouping-items", a), !1) : !0 : !G(r) && !t.has(r) ? (q("toolbarview-item-unavailable", { item: r }), !1) : !0);
    return this._cleanSeparatorsAndLineBreaks(s);
  }
  /**
   * Remove leading, trailing, and duplicated separators (`-` and `|`).
   *
   * @returns Toolbar items after the separator and line break clean-up.
   */
  _cleanSeparatorsAndLineBreaks(e) {
    const t = (o) => o !== "-" && o !== "|", i = e.length, s = e.findIndex(t);
    if (s === -1)
      return [];
    const r = i - e.slice().reverse().findIndex(t);
    return e.slice(s, r).filter((o, a, l) => t(o) ? !0 : !(a > 0 && l[a - 1] === o));
  }
  /**
   * Creates a user-defined dropdown containing a toolbar with items.
   *
   * @param definition A definition of the nested toolbar dropdown.
   * @param definition.label A label of the dropdown.
   * @param definition.icon An icon of the drop-down. One of 'bold', 'plus', 'text', 'importExport', 'alignLeft',
   * 'paragraph' or an SVG string. When `false` is passed, no icon will be used.
   * @param definition.withText When set `true`, the label of the dropdown will be visible. See
   * {@link module:ui/button/buttonview~ButtonView#withText} to learn more.
   * @param definition.tooltip A tooltip of the dropdown button. See
   * {@link module:ui/button/buttonview~ButtonView#tooltip} to learn more. Defaults to `true`.
   * @param componentFactory Component factory used to create items
   * of the nested toolbar.
   */
  _createNestedToolbarDropdown(e, t, i) {
    let { label: s, icon: r, items: o, tooltip: a = !0, withText: l = !1 } = e;
    if (o = this._cleanItemsConfiguration(o, t, i), !o.length)
      return null;
    const c = this.locale, u = gt(c);
    return s || q("toolbarview-nested-toolbar-dropdown-missing-label", e), u.class = "ck-toolbar__nested-toolbar-dropdown", u.buttonView.set({
      label: s,
      tooltip: a,
      withText: !!l
    }), r !== !1 ? u.buttonView.icon = iC[r] || r || Wh : u.buttonView.withText = !0, zn(u, () => u.toolbarView._buildItemsFromConfig(o, t, i)), u;
  }
}
class nC extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.children = this.createCollection(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-toolbar__items"
        ]
      },
      children: this.children
    });
  }
}
class sC {
  /**
   * Creates an instance of the {@link module:ui/toolbar/toolbarview~StaticLayout} toolbar
   * behavior.
   *
   * @param view An instance of the toolbar that this behavior is added to.
   */
  constructor(e) {
    const t = e.bindTemplate;
    e.set("isVertical", !1), e.itemsView.children.bindTo(e.items).using((i) => i), e.focusables.bindTo(e.items).using((i) => i), e.extendTemplate({
      attributes: {
        class: [
          // When vertical, the toolbar has an additional CSS class.
          t.if("isVertical", "ck-toolbar_vertical")
        ]
      }
    });
  }
  /**
   * @inheritDoc
   */
  render() {
  }
  /**
   * @inheritDoc
   */
  destroy() {
  }
}
class rC {
  /**
   * Creates an instance of the {@link module:ui/toolbar/toolbarview~DynamicGrouping} toolbar
   * behavior.
   *
   * @param view An instance of the toolbar that this behavior is added to.
   */
  constructor(e) {
    this.resizeObserver = null, this.cachedPadding = null, this.shouldUpdateGroupingOnNextResize = !1, this.view = e, this.viewChildren = e.children, this.viewFocusables = e.focusables, this.viewItemsView = e.itemsView, this.viewFocusTracker = e.focusTracker, this.viewLocale = e.locale, this.ungroupedItems = e.createCollection(), this.groupedItems = e.createCollection(), this.groupedItemsDropdown = this._createGroupedItemsDropdown(), e.itemsView.children.bindTo(this.ungroupedItems).using((t) => t), this.ungroupedItems.on("change", this._updateFocusCycleableItems.bind(this)), e.children.on("change", this._updateFocusCycleableItems.bind(this)), e.items.on("change", (t, i) => {
      const s = i.index, r = Array.from(i.added);
      for (const o of i.removed)
        s >= this.ungroupedItems.length ? this.groupedItems.remove(o) : this.ungroupedItems.remove(o);
      for (let o = s; o < s + r.length; o++) {
        const a = r[o - s];
        o > this.ungroupedItems.length ? this.groupedItems.add(a, o - this.ungroupedItems.length) : this.ungroupedItems.add(a, o);
      }
      this._updateGrouping();
    }), e.extendTemplate({
      attributes: {
        class: [
          // To group items dynamically, the toolbar needs a dedicated CSS class.
          "ck-toolbar_grouping"
        ]
      }
    });
  }
  /**
   * Enables dynamic items grouping based on the dimensions of the toolbar.
   *
   * @param view An instance of the toolbar that this behavior is added to.
   */
  render(e) {
    this.viewElement = e.element, this._enableGroupingOnResize(), this._enableGroupingOnMaxWidthChange(e);
  }
  /**
   * Cleans up the internals used by this behavior.
   */
  destroy() {
    this.groupedItemsDropdown.destroy(), this.resizeObserver.destroy();
  }
  /**
   * When called, it will check if any of the {@link #ungroupedItems} do not fit into a single row of the toolbar,
   * and it will move them to the {@link #groupedItems} when it happens.
   *
   * At the same time, it will also check if there is enough space in the toolbar for the first of the
   * {@link #groupedItems} to be returned back to {@link #ungroupedItems} and still fit into a single row
   * without the toolbar wrapping.
   */
  _updateGrouping() {
    if (!this.viewElement.ownerDocument.body.contains(this.viewElement))
      return;
    if (!St(this.viewElement)) {
      this.shouldUpdateGroupingOnNextResize = !0;
      return;
    }
    const e = this.groupedItems.length;
    let t;
    for (; this._areItemsOverflowing; )
      this._groupLastItem(), t = !0;
    if (!t && this.groupedItems.length) {
      for (; this.groupedItems.length && !this._areItemsOverflowing; )
        this._ungroupFirstItem();
      this._areItemsOverflowing && this._groupLastItem();
    }
    this.groupedItems.length !== e && this.view.fire("groupedItemsUpdate");
  }
  /**
   * Returns `true` when {@link module:ui/toolbar/toolbarview~ToolbarView#element} children visually overflow,
   * for instance if the toolbar is narrower than its members. Returns `false` otherwise.
   */
  get _areItemsOverflowing() {
    if (!this.ungroupedItems.length)
      return !1;
    const e = this.viewElement, t = this.viewLocale.uiLanguageDirection, i = new V(e.lastChild), s = new V(e);
    if (!this.cachedPadding) {
      const r = I.window.getComputedStyle(e), o = t === "ltr" ? "paddingRight" : "paddingLeft";
      this.cachedPadding = Number.parseInt(r[o]);
    }
    return t === "ltr" ? i.right > s.right - this.cachedPadding : i.left < s.left + this.cachedPadding;
  }
  /**
   * Enables the functionality that prevents {@link #ungroupedItems} from overflowing (wrapping to the next row)
   * upon resize when there is little space available. Instead, the toolbar items are moved to the
   * {@link #groupedItems} collection and displayed in a dropdown at the end of the row (which has its own nested toolbar).
   *
   * When called, the toolbar will automatically analyze the location of its {@link #ungroupedItems} and "group"
   * them in the dropdown if necessary. It will also observe the browser window for size changes in
   * the future and respond to them by grouping more items or reverting already grouped back, depending
   * on the visual space available.
   */
  _enableGroupingOnResize() {
    let e;
    this.resizeObserver = new $(this.viewElement, (t) => {
      (!e || e !== t.contentRect.width || this.shouldUpdateGroupingOnNextResize) && (this.shouldUpdateGroupingOnNextResize = !1, this._updateGrouping(), e = t.contentRect.width);
    }), this._updateGrouping();
  }
  /**
   * Enables the grouping functionality, just like {@link #_enableGroupingOnResize} but the difference is that
   * it listens to the changes of {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth} instead.
   */
  _enableGroupingOnMaxWidthChange(e) {
    e.on("change:maxWidth", () => {
      this._updateGrouping();
    });
  }
  /**
   * When called, it will remove the last item from {@link #ungroupedItems} and move it back
   * to the {@link #groupedItems} collection.
   *
   * The opposite of {@link #_ungroupFirstItem}.
   */
  _groupLastItem() {
    this.groupedItems.length || (this.viewChildren.add(new zh()), this.viewChildren.add(this.groupedItemsDropdown), this.viewFocusTracker.add(this.groupedItemsDropdown.element)), this.groupedItems.add(this.ungroupedItems.remove(this.ungroupedItems.last), 0);
  }
  /**
   * Moves the very first item belonging to {@link #groupedItems} back
   * to the {@link #ungroupedItems} collection.
   *
   * The opposite of {@link #_groupLastItem}.
   */
  _ungroupFirstItem() {
    this.ungroupedItems.add(this.groupedItems.remove(this.groupedItems.first)), this.groupedItems.length || (this.viewChildren.remove(this.groupedItemsDropdown), this.viewChildren.remove(this.viewChildren.last), this.viewFocusTracker.remove(this.groupedItemsDropdown.element));
  }
  /**
   * Creates the {@link #groupedItemsDropdown} that hosts the members of the {@link #groupedItems}
   * collection when there is not enough space in the toolbar to display all items in a single row.
   */
  _createGroupedItemsDropdown() {
    const e = this.viewLocale, t = e.t, i = gt(e);
    return i.class = "ck-toolbar__grouped-dropdown", i.panelPosition = e.uiLanguageDirection === "ltr" ? "sw" : "se", zn(i, this.groupedItems), i.buttonView.set({
      label: t("Show more items"),
      tooltip: !0,
      tooltipPosition: e.uiLanguageDirection === "rtl" ? "se" : "sw",
      icon: Wh
    }), i;
  }
  /**
   * Updates the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables focus–cycleable items}
   * collection so it represents the up–to–date state of the UI from the perspective of the user.
   *
   * For instance, the {@link #groupedItemsDropdown} can show up and hide but when it is visible,
   * it must be subject to focus cycling in the toolbar.
   *
   * See the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables collection} documentation
   * to learn more about the purpose of this method.
   */
  _updateFocusCycleableItems() {
    this.viewFocusables.clear(), this.ungroupedItems.map((e) => {
      this.viewFocusables.add(e);
    }), this.groupedItems.length && this.viewFocusables.add(this.groupedItemsDropdown);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class oC extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.items = this.createCollection(), this.focusTracker = new ye(), this.keystrokes = new Oe(), this._focusCycler = new Ft({
      focusables: this.items,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate list items backwards using the arrowup key.
        focusPrevious: "arrowup",
        // Navigate toolbar items forwards using the arrowdown key.
        focusNext: "arrowdown"
      }
    }), this.set("ariaLabel", void 0), this.set("role", void 0), this.setTemplate({
      tag: "ul",
      attributes: {
        class: [
          "ck",
          "ck-reset",
          "ck-list"
        ],
        role: t.to("role"),
        "aria-label": t.to("ariaLabel")
      },
      children: this.items
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render();
    for (const e of this.items)
      this.focusTracker.add(e.element);
    this.items.on("add", (e, t) => {
      this.focusTracker.add(t.element);
    }), this.items.on("remove", (e, t) => {
      this.focusTracker.remove(t.element);
    }), this.keystrokes.listenTo(this.element);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Focuses the first focusable in {@link #items}.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * Focuses the last focusable in {@link #items}.
   */
  focusLast() {
    this._focusCycler.focusLast();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Uh extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.set("isVisible", !0), this.children = this.createCollection(), this.setTemplate({
      tag: "li",
      attributes: {
        class: [
          "ck",
          "ck-list__item",
          t.if("isVisible", "ck-hidden", (i) => !i)
        ],
        role: "presentation"
      },
      children: this.children
    });
  }
  /**
   * Focuses the list item.
   */
  focus() {
    this.children.first.focus();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class aC extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.setTemplate({
      tag: "li",
      attributes: {
        class: [
          "ck",
          "ck-list__separator"
        ]
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class jh extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.set("class", void 0), this.set("labelStyle", void 0), this.set("icon", void 0), this.set("isEnabled", !0), this.set("isOn", !1), this.set("isToggleable", !1), this.set("isVisible", !0), this.set("keystroke", void 0), this.set("withKeystroke", !1), this.set("label", void 0), this.set("tabindex", -1), this.set("tooltip", !1), this.set("tooltipPosition", "s"), this.set("type", "button"), this.set("withText", !1), this.children = this.createCollection(), this.actionView = this._createActionView(), this.arrowView = this._createArrowView(), this.keystrokes = new Oe(), this.focusTracker = new ye(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-splitbutton",
          t.to("class"),
          t.if("isVisible", "ck-hidden", (i) => !i),
          this.arrowView.bindTemplate.if("isOn", "ck-splitbutton_open")
        ]
      },
      children: this.children
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.children.add(this.actionView), this.children.add(this.arrowView), this.focusTracker.add(this.actionView.element), this.focusTracker.add(this.arrowView.element), this.keystrokes.listenTo(this.element), this.keystrokes.set("arrowright", (e, t) => {
      this.focusTracker.focusedElement === this.actionView.element && (this.arrowView.focus(), t());
    }), this.keystrokes.set("arrowleft", (e, t) => {
      this.focusTracker.focusedElement === this.arrowView.element && (this.actionView.focus(), t());
    });
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Focuses the {@link module:ui/button/buttonview~ButtonView#element} of the action part of split button.
   */
  focus() {
    this.actionView.focus();
  }
  /**
   * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #actionView} and binds it with main split button
   * attributes.
   */
  _createActionView() {
    const e = new H();
    return e.bind("icon", "isEnabled", "isOn", "isToggleable", "keystroke", "label", "tabindex", "tooltip", "tooltipPosition", "type", "withText").to(this), e.extendTemplate({
      attributes: {
        class: "ck-splitbutton__action"
      }
    }), e.delegate("execute").to(this), e;
  }
  /**
   * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #arrowView} and binds it with main split button
   * attributes.
   */
  _createArrowView() {
    const e = new H(), t = e.bindTemplate;
    return e.icon = Lh, e.extendTemplate({
      attributes: {
        class: [
          "ck-splitbutton__arrow"
        ],
        "data-cke-tooltip-disabled": t.to("isOn"),
        "aria-haspopup": !0,
        "aria-expanded": t.to("isOn", (i) => String(i))
      }
    }), e.bind("isEnabled").to(this), e.bind("label").to(this), e.bind("tooltip").to(this), e.delegate("execute").to(this, "open"), e;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function gt(n, e = $h) {
  const t = new e(n), i = new Q2(n), s = new oi(n, t, i);
  return t.bind("isEnabled").to(s), t instanceof jh ? t.arrowView.bind("isOn").to(s, "isOpen") : t.bind("isOn").to(s, "isOpen"), lC(s), s;
}
function zn(n, e, t = {}) {
  n.extendTemplate({
    attributes: {
      class: ["ck-toolbar-dropdown"]
    }
  }), n.isOpen ? il(n, e, t) : n.once("change:isOpen", () => il(n, e, t), { priority: "highest" }), t.enableActiveItemFocusOnDropdownOpen && Yr(n, () => n.toolbarView.items.find((i) => i.isOn));
}
function il(n, e, t) {
  const i = n.locale, s = i.t, r = n.toolbarView = new Zr(i), o = typeof e == "function" ? e() : e;
  r.ariaLabel = t.ariaLabel || s("Dropdown toolbar"), t.maxWidth && (r.maxWidth = t.maxWidth), t.class && (r.class = t.class), t.isCompact && (r.isCompact = t.isCompact), t.isVertical && (r.isVertical = !0), o instanceof nt ? r.items.bindTo(o).using((a) => a) : r.items.addMany(o), n.panelView.children.add(r), r.items.delegate("execute").to(n);
}
function qh(n, e, t = {}) {
  n.isOpen ? nl(n, e, t) : n.once("change:isOpen", () => nl(n, e, t), { priority: "highest" }), Yr(n, () => n.listView.items.find((i) => i instanceof Uh ? i.children.first.isOn : !1));
}
function nl(n, e, t) {
  const i = n.locale, s = n.listView = new oC(i), r = typeof e == "function" ? e() : e;
  s.ariaLabel = t.ariaLabel, s.role = t.role, s.items.bindTo(r).using((o) => {
    if (o.type === "separator")
      return new aC(i);
    if (o.type === "button" || o.type === "switchbutton") {
      const a = new Uh(i);
      let l;
      return o.type === "button" ? l = new H(i) : l = new Jr(i), l.bind(...Object.keys(o.model)).to(o.model), l.delegate("execute").to(a), a.children.add(l), a;
    }
    return null;
  }), n.panelView.children.add(s), s.items.delegate("execute").to(n);
}
function Yr(n, e) {
  n.on("change:isOpen", () => {
    if (!n.isOpen)
      return;
    const t = e();
    t && (typeof t.focus == "function" ? t.focus() : q("ui-dropdown-focus-child-on-open-child-missing-focus", { view: t }));
  }, { priority: be.low - 10 });
}
function lC(n) {
  cC(n), uC(n), hC(n), dC(n), fC(n), mC(n);
}
function cC(n) {
  n.on("render", () => {
    Ur({
      emitter: n,
      activator: () => n.isOpen,
      callback: () => {
        n.isOpen = !1;
      },
      contextElements: [n.element]
    });
  });
}
function uC(n) {
  n.on("execute", (e) => {
    e.source instanceof Jr || (n.isOpen = !1);
  });
}
function hC(n) {
  n.focusTracker.on("change:isFocused", (e, t, i) => {
    n.isOpen && !i && (n.isOpen = !1);
  });
}
function dC(n) {
  n.keystrokes.set("arrowdown", (e, t) => {
    n.isOpen && (n.panelView.focus(), t());
  }), n.keystrokes.set("arrowup", (e, t) => {
    n.isOpen && (n.panelView.focusLast(), t());
  });
}
function fC(n) {
  n.on("change:isOpen", (e, t, i) => {
    if (i)
      return;
    const s = n.panelView.element;
    s && s.contains(I.document.activeElement) && n.buttonView.focus();
  });
}
function mC(n) {
  n.on("change:isOpen", (e, t, i) => {
    i && n.panelView.focus();
  }, { priority: "low" });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Hn(n, e, t) {
  const i = new X2(n.locale);
  return i.set({
    id: e,
    ariaDescribedById: t
  }), i.bind("isReadOnly").to(n, "isEnabled", (s) => !s), i.bind("hasError").to(n, "errorText", (s) => !!s), i.on("input", () => {
    n.errorText = null;
  }), n.bind("isEmpty", "isFocused", "placeholder").to(i), i;
}
const Ni = (n, e = 0, t = 1) => n > t ? t : n < e ? e : n, oe = (n, e = 0, t = Math.pow(10, e)) => Math.round(t * n) / t, gC = (n) => vC(nr(n)), nr = (n) => (n[0] === "#" && (n = n.substring(1)), n.length < 6 ? {
  r: parseInt(n[0] + n[0], 16),
  g: parseInt(n[1] + n[1], 16),
  b: parseInt(n[2] + n[2], 16),
  a: n.length === 4 ? oe(parseInt(n[3] + n[3], 16) / 255, 2) : 1
} : {
  r: parseInt(n.substring(0, 2), 16),
  g: parseInt(n.substring(2, 4), 16),
  b: parseInt(n.substring(4, 6), 16),
  a: n.length === 8 ? oe(parseInt(n.substring(6, 8), 16) / 255, 2) : 1
}), pC = (n) => _C(bC(n)), wC = ({ h: n, s: e, v: t, a: i }) => {
  const s = (200 - e) * t / 100;
  return {
    h: oe(n),
    s: oe(s > 0 && s < 200 ? e * t / 100 / (s <= 100 ? s : 200 - s) * 100 : 0),
    l: oe(s / 2),
    a: oe(i, 2)
  };
}, sr = (n) => {
  const { h: e, s: t, l: i } = wC(n);
  return `hsl(${e}, ${t}%, ${i}%)`;
}, bC = ({ h: n, s: e, v: t, a: i }) => {
  n = n / 360 * 6, e = e / 100, t = t / 100;
  const s = Math.floor(n), r = t * (1 - e), o = t * (1 - (n - s) * e), a = t * (1 - (1 - n + s) * e), l = s % 6;
  return {
    r: oe([t, o, r, r, a, t][l] * 255),
    g: oe([a, t, t, o, r, r][l] * 255),
    b: oe([r, r, a, t, t, o][l] * 255),
    a: oe(i, 2)
  };
}, Xi = (n) => {
  const e = n.toString(16);
  return e.length < 2 ? "0" + e : e;
}, _C = ({ r: n, g: e, b: t, a: i }) => {
  const s = i < 1 ? Xi(oe(i * 255)) : "";
  return "#" + Xi(n) + Xi(e) + Xi(t) + s;
}, vC = ({ r: n, g: e, b: t, a: i }) => {
  const s = Math.max(n, e, t), r = s - Math.min(n, e, t), o = r ? s === n ? (e - t) / r : s === e ? 2 + (t - n) / r : 4 + (n - e) / r : 0;
  return {
    h: oe(60 * (o < 0 ? o + 6 : o)),
    s: oe(s ? r / s * 100 : 0),
    v: oe(s / 255 * 100),
    a: i
  };
}, Gh = (n, e) => {
  if (n === e)
    return !0;
  for (const t in n)
    if (n[t] !== e[t])
      return !1;
  return !0;
}, yC = (n, e) => n.toLowerCase() === e.toLowerCase() ? !0 : Gh(nr(n), nr(e)), sl = {}, Kh = (n) => {
  let e = sl[n];
  return e || (e = document.createElement("template"), e.innerHTML = n, sl[n] = e), e;
}, Xr = (n, e, t) => {
  n.dispatchEvent(new CustomEvent(e, {
    bubbles: !0,
    detail: t
  }));
};
let Qt = !1;
const rr = (n) => "touches" in n, kC = (n) => Qt && !rr(n) ? !1 : (Qt || (Qt = rr(n)), !0), rl = (n, e) => {
  const t = rr(e) ? e.touches[0] : e, i = n.el.getBoundingClientRect();
  Xr(n.el, "move", n.getMove({
    x: Ni((t.pageX - (i.left + window.pageXOffset)) / i.width),
    y: Ni((t.pageY - (i.top + window.pageYOffset)) / i.height)
  }));
}, CC = (n, e) => {
  const t = e.keyCode;
  t > 40 || n.xy && t < 37 || t < 33 || (e.preventDefault(), Xr(n.el, "move", n.getMove({
    x: t === 39 ? 0.01 : t === 37 ? -0.01 : t === 34 ? 0.05 : t === 33 ? -0.05 : t === 35 ? 1 : t === 36 ? -1 : 0,
    y: t === 40 ? 0.01 : t === 38 ? -0.01 : 0
  }, !0)));
};
class Jh {
  constructor(e, t, i, s) {
    const r = Kh(`<div role="slider" tabindex="0" part="${t}" ${i}><div part="${t}-pointer"></div></div>`);
    e.appendChild(r.content.cloneNode(!0));
    const o = e.querySelector(`[part=${t}]`);
    o.addEventListener("mousedown", this), o.addEventListener("touchstart", this), o.addEventListener("keydown", this), this.el = o, this.xy = s, this.nodes = [o.firstChild, o];
  }
  set dragging(e) {
    const t = e ? document.addEventListener : document.removeEventListener;
    t(Qt ? "touchmove" : "mousemove", this), t(Qt ? "touchend" : "mouseup", this);
  }
  handleEvent(e) {
    switch (e.type) {
      case "mousedown":
      case "touchstart":
        if (e.preventDefault(), !kC(e) || !Qt && e.button != 0)
          return;
        this.el.focus(), rl(this, e), this.dragging = !0;
        break;
      case "mousemove":
      case "touchmove":
        e.preventDefault(), rl(this, e);
        break;
      case "mouseup":
      case "touchend":
        this.dragging = !1;
        break;
      case "keydown":
        CC(this, e);
        break;
    }
  }
  style(e) {
    e.forEach((t, i) => {
      for (const s in t)
        this.nodes[i].style.setProperty(s, t[s]);
    });
  }
}
class EC extends Jh {
  constructor(e) {
    super(e, "hue", 'aria-label="Hue" aria-valuemin="0" aria-valuemax="360"', !1);
  }
  update({ h: e }) {
    this.h = e, this.style([
      {
        left: `${e / 360 * 100}%`,
        color: sr({ h: e, s: 100, v: 100, a: 1 })
      }
    ]), this.el.setAttribute("aria-valuenow", `${oe(e)}`);
  }
  getMove(e, t) {
    return { h: t ? Ni(this.h + e.x * 360, 0, 360) : 360 * e.x };
  }
}
class AC extends Jh {
  constructor(e) {
    super(e, "saturation", 'aria-label="Color"', !0);
  }
  update(e) {
    this.hsva = e, this.style([
      {
        top: `${100 - e.v}%`,
        left: `${e.s}%`,
        color: sr(e)
      },
      {
        "background-color": sr({ h: e.h, s: 100, v: 100, a: 1 })
      }
    ]), this.el.setAttribute("aria-valuetext", `Saturation ${oe(e.s)}%, Brightness ${oe(e.v)}%`);
  }
  getMove(e, t) {
    return {
      s: t ? Ni(this.hsva.s + e.x * 100, 0, 100) : e.x * 100,
      v: t ? Ni(this.hsva.v - e.y * 100, 0, 100) : Math.round(100 - e.y * 100)
    };
  }
}
const TC = ':host{display:flex;flex-direction:column;position:relative;width:200px;height:200px;user-select:none;-webkit-user-select:none;cursor:default}:host([hidden]){display:none!important}[role=slider]{position:relative;touch-action:none;user-select:none;-webkit-user-select:none;outline:0}[role=slider]:last-child{border-radius:0 0 8px 8px}[part$=pointer]{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;display:flex;place-content:center center;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}[part$=pointer]::after{content:"";width:100%;height:100%;border-radius:inherit;background-color:currentColor}[role=slider]:focus [part$=pointer]{transform:translate(-50%,-50%) scale(1.1)}', PC = "[part=hue]{flex:0 0 24px;background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}[part=hue-pointer]{top:50%;z-index:2}", xC = "[part=saturation]{flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,rgba(255,255,255,0));box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}[part=saturation-pointer]{z-index:3}", Qi = Symbol("same"), ls = Symbol("color"), ol = Symbol("hsva"), cs = Symbol("update"), al = Symbol("parts"), ll = Symbol("css"), cl = Symbol("sliders");
class SC extends HTMLElement {
  static get observedAttributes() {
    return ["color"];
  }
  get [ll]() {
    return [TC, PC, xC];
  }
  get [cl]() {
    return [AC, EC];
  }
  get color() {
    return this[ls];
  }
  set color(e) {
    if (!this[Qi](e)) {
      const t = this.colorModel.toHsva(e);
      this[cs](t), this[ls] = e;
    }
  }
  constructor() {
    super();
    const e = Kh(`<style>${this[ll].join("")}</style>`), t = this.attachShadow({ mode: "open" });
    t.appendChild(e.content.cloneNode(!0)), t.addEventListener("move", this), this[al] = this[cl].map((i) => new i(t));
  }
  connectedCallback() {
    if (this.hasOwnProperty("color")) {
      const e = this.color;
      delete this.color, this.color = e;
    } else
      this.color || (this.color = this.colorModel.defaultColor);
  }
  attributeChangedCallback(e, t, i) {
    const s = this.colorModel.fromAttr(i);
    this[Qi](s) || (this.color = s);
  }
  handleEvent(e) {
    const t = this[ol], i = { ...t, ...e.detail };
    this[cs](i);
    let s;
    !Gh(i, t) && !this[Qi](s = this.colorModel.fromHsva(i)) && (this[ls] = s, Xr(this, "color-changed", { value: s }));
  }
  [Qi](e) {
    return this.color && this.colorModel.equal(e, this.color);
  }
  [cs](e) {
    this[ol] = e, this[al].forEach((t) => t.update(e));
  }
}
const IC = {
  defaultColor: "#000",
  toHsva: gC,
  fromHsva: ({ h: n, s: e, v: t }) => pC({ h: n, s: e, v: t, a: 1 }),
  equal: yC,
  fromAttr: (n) => n
};
class RC extends SC {
  get colorModel() {
    return IC;
  }
}
class OC extends RC {
}
customElements.define("hex-color-picker", OC);
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const MC = 150;
class VC extends T {
  /**
   * Creates a view of color picker.
   *
   * @param locale
   * @param config
   */
  constructor(e, t) {
    super(e), this.set("color", ""), this.set("_hexColor", ""), this._format = t.format || "hsl", this.hexInputRow = this._createInputRow();
    const i = this.createCollection();
    i.add(this.hexInputRow), this.setTemplate({
      tag: "div",
      attributes: {
        class: ["ck", "ck-color-picker"],
        tabindex: -1
      },
      children: i
    }), this._debounceColorPickerEvent = ti((s) => {
      this.set("color", s);
    }, MC, {
      leading: !0
    }), this.on("set:color", (s, r, o) => {
      s.return = Bh(o, this._format);
    }), this.on("change:color", () => {
      this._hexColor = us(this.color);
    }), this.on("change:_hexColor", () => {
      document.activeElement !== this.picker && this.picker.setAttribute("color", this._hexColor), us(this.color) != us(this._hexColor) && (this.color = this._hexColor);
    });
  }
  /**
   * Renders color picker in the view.
   */
  render() {
    if (super.render(), this.picker = I.document.createElement("hex-color-picker"), this.picker.setAttribute("class", "hex-color-picker"), this.picker.setAttribute("tabindex", "-1"), this._createSlidersView(), this.element) {
      this.element.insertBefore(this.picker, this.hexInputRow.element);
      const e = document.createElement("style");
      e.textContent = '[role="slider"]:focus [part$="pointer"] {border: 1px solid #fff;outline: 1px solid var(--ck-color-focus-border);box-shadow: 0 0 0 2px #fff;}', this.picker.shadowRoot.appendChild(e);
    }
    this.picker.addEventListener("color-changed", (e) => {
      const i = e.detail.value;
      this._debounceColorPickerEvent(i);
    });
  }
  /**
   * Focuses the first pointer in color picker.
   *
   */
  focus() {
    /* istanbul ignore next -- @preserve */
    (S.isGecko || S.isiOS || S.isSafari) && this.hexInputRow.children.get(1).focus(), this.slidersView.first.focus();
  }
  /**
   * Creates collection of sliders in color picker.
   *
   * @private
   */
  _createSlidersView() {
    const i = [...this.picker.shadowRoot.children].filter((s) => s.getAttribute("role") === "slider").map((s) => new DC(s));
    this.slidersView = this.createCollection(), i.forEach((s) => {
      this.slidersView.add(s);
    });
  }
  /**
   * Creates input row for defining custom colors in color picker.
   *
   * @private
   */
  _createInputRow() {
    const e = new BC(), t = this._createColorInput();
    return new FC(this.locale, [e, t]);
  }
  /**
   * Creates the input where user can type or paste the color in hex format.
   *
   * @private
   */
  _createColorInput() {
    const e = new $n(this.locale, Hn), { t } = this.locale;
    return e.set({
      label: t("HEX"),
      class: "color-picker-hex-input"
    }), e.fieldView.bind("value").to(this, "_hexColor", (i) => e.isFocused ? e.fieldView.value : i.startsWith("#") ? i.substring(1) : i), e.fieldView.on("input", () => {
      const i = e.fieldView.element.value;
      if (i) {
        const s = i.trim(), r = s.startsWith("#") ? s.substring(1) : s;
        [3, 4, 6, 8].includes(r.length) && /(([0-9a-fA-F]{2}){3,4}|([0-9a-fA-F]){3,4})/.test(r) && this._debounceColorPickerEvent("#" + r);
      }
    }), e;
  }
}
function us(n) {
  let e = G2(n);
  return e || (e = "#000"), e.length === 4 && (e = "#" + [e[1], e[1], e[2], e[2], e[3], e[3]].join("")), e.toLowerCase();
}
class DC extends T {
  /**
   * @param element HTML elemnt of slider in color picker.
   */
  constructor(e) {
    super(), this.element = e;
  }
  /**
   * Focuses element.
   */
  focus() {
    this.element.focus();
  }
}
class BC extends T {
  constructor(e) {
    super(e), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-color-picker__hash-view"
        ]
      },
      children: "#"
    });
  }
}
class FC extends T {
  /**
   * Creates an instance of the form row class.
   *
   * @param locale The locale instance.
   */
  constructor(e, t) {
    super(e), this.children = this.createCollection(t), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-color-picker__row"
        ]
      },
      children: this.children
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class NC {
  /**
   * Creates an instance of the factory.
   *
   * @param editor The editor instance.
   */
  constructor(e) {
    this._components = /* @__PURE__ */ new Map(), this.editor = e;
  }
  /**
   * Returns an iterator of registered component names. Names are returned in lower case.
   */
  *names() {
    for (const e of this._components.values())
      yield e.originalName;
  }
  /**
   * Registers a component factory function that will be used by the
   * {@link #create create} method and called with the
   * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,
   * allowing localization of the {@link module:ui/view~View view}.
   *
   * @param name The name of the component.
   * @param callback The callback that returns the component.
   */
  add(e, t) {
    this._components.set(hs(e), { callback: t, originalName: e });
  }
  /**
   * Creates an instance of a component registered in the factory under a specific name.
   *
   * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to
   * the previously {@link #add added} factory function, allowing localization of the
   * {@link module:ui/view~View view}.
   *
   * @param name The name of the component.
   * @returns The instantiated component view.
   */
  create(e) {
    if (!this.has(e))
      throw new d("componentfactory-item-missing", this, { name: e });
    return this._components.get(hs(e)).callback(this.editor.locale);
  }
  /**
   * Checks if a component of a given name is registered in the factory.
   *
   * @param name The name of the component.
   */
  has(e) {
    return this._components.has(hs(e));
  }
}
function hs(n) {
  return String(n).toLowerCase();
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const ul = Sr("px"), hl = I.document.body;
class ae extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.bindTemplate;
    this.set("top", 0), this.set("left", 0), this.set("position", "arrow_nw"), this.set("isVisible", !1), this.set("withArrow", !0), this.set("class", void 0), this._pinWhenIsVisibleCallback = null, this.content = this.createCollection(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-balloon-panel",
          t.to("position", (i) => `ck-balloon-panel_${i}`),
          t.if("isVisible", "ck-balloon-panel_visible"),
          t.if("withArrow", "ck-balloon-panel_with-arrow"),
          t.to("class")
        ],
        style: {
          top: t.to("top", ul),
          left: t.to("left", ul)
        }
      },
      children: this.content
    });
  }
  /**
   * Shows the panel.
   *
   * See {@link #isVisible}.
   */
  show() {
    this.isVisible = !0;
  }
  /**
   * Hides the panel.
   *
   * See {@link #isVisible}.
   */
  hide() {
    this.isVisible = !1;
  }
  /**
   * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a
   * smart positioning heuristics that chooses from available positions to make sure the panel
   * is visible to the user i.e. within the limits of the viewport.
   *
   * This method accepts configuration {@link module:utils/dom/position~Options options}
   * to set the `target`, optional `limiter` and `positions` the balloon should choose from.
   *
   * ```ts
   * const panel = new BalloonPanelView( locale );
   * const positions = BalloonPanelView.defaultPositions;
   *
   * panel.render();
   *
   * // Attach the panel to an element with the "target" id DOM.
   * panel.attachTo( {
   * 	target: document.querySelector( '#target' ),
   * 	positions: [
   * 		positions.northArrowSouth,
   * 		positions.southArrowNorth
   * 	]
   * } );
   * ```
   *
   * **Note**: Attaching the panel will also automatically {@link #show} it.
   *
   * **Note**: An attached panel will not follow its target when the window is scrolled or resized.
   * See the {@link #pin} method for a more permanent positioning strategy.
   *
   * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.
   * Default `positions` array is {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
   */
  attachTo(e) {
    this.show();
    const t = ae.defaultPositions, i = Object.assign({}, {
      element: this.element,
      positions: [
        t.southArrowNorth,
        t.southArrowNorthMiddleWest,
        t.southArrowNorthMiddleEast,
        t.southArrowNorthWest,
        t.southArrowNorthEast,
        t.northArrowSouth,
        t.northArrowSouthMiddleWest,
        t.northArrowSouthMiddleEast,
        t.northArrowSouthWest,
        t.northArrowSouthEast,
        t.viewportStickyNorth
      ],
      limiter: hl,
      fitInViewport: !0
    }, e), s = ae._getOptimalPosition(i), r = parseInt(s.left), o = parseInt(s.top), a = s.name, l = s.config || {}, { withArrow: c = !0 } = l;
    this.top = o, this.left = r, this.position = a, this.withArrow = c;
  }
  /**
   * Works the same way as the {@link #attachTo} method except that the position of the panel is
   * continuously updated when:
   *
   * * any ancestor of the {@link module:utils/dom/position~Options#target}
   * or {@link module:utils/dom/position~Options#limiter} is scrolled,
   * * the browser window gets resized or scrolled.
   *
   * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}
   * and is immune to the changing environment.
   *
   * ```ts
   * const panel = new BalloonPanelView( locale );
   * const positions = BalloonPanelView.defaultPositions;
   *
   * panel.render();
   *
   * // Pin the panel to an element with the "target" id DOM.
   * panel.pin( {
   * 	target: document.querySelector( '#target' ),
   * 	positions: [
   * 		positions.northArrowSouth,
   * 		positions.southArrowNorth
   * 	]
   * } );
   * ```
   *
   * To leave the pinned state, use the {@link #unpin} method.
   *
   * **Note**: Pinning the panel will also automatically {@link #show} it.
   *
   * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.
   * Default `positions` array is {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
   */
  pin(e) {
    this.unpin(), this._pinWhenIsVisibleCallback = () => {
      this.isVisible ? this._startPinning(e) : this._stopPinning();
    }, this._startPinning(e), this.listenTo(this, "change:isVisible", this._pinWhenIsVisibleCallback);
  }
  /**
   * Stops pinning the panel, as set up by {@link #pin}.
   */
  unpin() {
    this._pinWhenIsVisibleCallback && (this._stopPinning(), this.stopListening(this, "change:isVisible", this._pinWhenIsVisibleCallback), this._pinWhenIsVisibleCallback = null, this.hide());
  }
  /**
   * Starts managing the pinned state of the panel. See {@link #pin}.
   *
   * @param options Positioning options compatible with {@link module:utils/dom/position~getOptimalPosition}.
   */
  _startPinning(e) {
    this.attachTo(e);
    const t = or(e.target), i = e.limiter ? or(e.limiter) : hl;
    this.listenTo(I.document, "scroll", (s, r) => {
      const o = r.target, a = t && o.contains(t), l = i && o.contains(i);
      (a || l || !t || !i) && this.attachTo(e);
    }, { useCapture: !0 }), this.listenTo(I.window, "resize", () => {
      this.attachTo(e);
    });
  }
  /**
   * Stops managing the pinned state of the panel. See {@link #pin}.
   */
  _stopPinning() {
    this.stopListening(I.document, "scroll"), this.stopListening(I.window, "resize");
  }
}
ae.arrowSideOffset = 25;
ae.arrowHeightOffset = 10;
ae.stickyVerticalOffset = 20;
ae._getOptimalPosition = vu;
ae.defaultPositions = Zh();
function or(n) {
  return di(n) ? n : Bn(n) ? n.commonAncestorContainer : typeof n == "function" ? or(n()) : null;
}
function Zh(n = {}) {
  const { sideOffset: e = ae.arrowSideOffset, heightOffset: t = ae.arrowHeightOffset, stickyVerticalOffset: i = ae.stickyVerticalOffset, config: s } = n;
  return {
    // ------- North west
    northWestArrowSouthWest: (a, l) => ({
      top: r(a, l),
      left: a.left - e,
      name: "arrow_sw",
      ...s && { config: s }
    }),
    northWestArrowSouthMiddleWest: (a, l) => ({
      top: r(a, l),
      left: a.left - l.width * 0.25 - e,
      name: "arrow_smw",
      ...s && { config: s }
    }),
    northWestArrowSouth: (a, l) => ({
      top: r(a, l),
      left: a.left - l.width / 2,
      name: "arrow_s",
      ...s && { config: s }
    }),
    northWestArrowSouthMiddleEast: (a, l) => ({
      top: r(a, l),
      left: a.left - l.width * 0.75 + e,
      name: "arrow_sme",
      ...s && { config: s }
    }),
    northWestArrowSouthEast: (a, l) => ({
      top: r(a, l),
      left: a.left - l.width + e,
      name: "arrow_se",
      ...s && { config: s }
    }),
    // ------- North
    northArrowSouthWest: (a, l) => ({
      top: r(a, l),
      left: a.left + a.width / 2 - e,
      name: "arrow_sw",
      ...s && { config: s }
    }),
    northArrowSouthMiddleWest: (a, l) => ({
      top: r(a, l),
      left: a.left + a.width / 2 - l.width * 0.25 - e,
      name: "arrow_smw",
      ...s && { config: s }
    }),
    northArrowSouth: (a, l) => ({
      top: r(a, l),
      left: a.left + a.width / 2 - l.width / 2,
      name: "arrow_s",
      ...s && { config: s }
    }),
    northArrowSouthMiddleEast: (a, l) => ({
      top: r(a, l),
      left: a.left + a.width / 2 - l.width * 0.75 + e,
      name: "arrow_sme",
      ...s && { config: s }
    }),
    northArrowSouthEast: (a, l) => ({
      top: r(a, l),
      left: a.left + a.width / 2 - l.width + e,
      name: "arrow_se",
      ...s && { config: s }
    }),
    // ------- North east
    northEastArrowSouthWest: (a, l) => ({
      top: r(a, l),
      left: a.right - e,
      name: "arrow_sw",
      ...s && { config: s }
    }),
    northEastArrowSouthMiddleWest: (a, l) => ({
      top: r(a, l),
      left: a.right - l.width * 0.25 - e,
      name: "arrow_smw",
      ...s && { config: s }
    }),
    northEastArrowSouth: (a, l) => ({
      top: r(a, l),
      left: a.right - l.width / 2,
      name: "arrow_s",
      ...s && { config: s }
    }),
    northEastArrowSouthMiddleEast: (a, l) => ({
      top: r(a, l),
      left: a.right - l.width * 0.75 + e,
      name: "arrow_sme",
      ...s && { config: s }
    }),
    northEastArrowSouthEast: (a, l) => ({
      top: r(a, l),
      left: a.right - l.width + e,
      name: "arrow_se",
      ...s && { config: s }
    }),
    // ------- South west
    southWestArrowNorthWest: (a) => ({
      top: o(a),
      left: a.left - e,
      name: "arrow_nw",
      ...s && { config: s }
    }),
    southWestArrowNorthMiddleWest: (a, l) => ({
      top: o(a),
      left: a.left - l.width * 0.25 - e,
      name: "arrow_nmw",
      ...s && { config: s }
    }),
    southWestArrowNorth: (a, l) => ({
      top: o(a),
      left: a.left - l.width / 2,
      name: "arrow_n",
      ...s && { config: s }
    }),
    southWestArrowNorthMiddleEast: (a, l) => ({
      top: o(a),
      left: a.left - l.width * 0.75 + e,
      name: "arrow_nme",
      ...s && { config: s }
    }),
    southWestArrowNorthEast: (a, l) => ({
      top: o(a),
      left: a.left - l.width + e,
      name: "arrow_ne",
      ...s && { config: s }
    }),
    // ------- South
    southArrowNorthWest: (a) => ({
      top: o(a),
      left: a.left + a.width / 2 - e,
      name: "arrow_nw",
      ...s && { config: s }
    }),
    southArrowNorthMiddleWest: (a, l) => ({
      top: o(a),
      left: a.left + a.width / 2 - l.width * 0.25 - e,
      name: "arrow_nmw",
      ...s && { config: s }
    }),
    southArrowNorth: (a, l) => ({
      top: o(a),
      left: a.left + a.width / 2 - l.width / 2,
      name: "arrow_n",
      ...s && { config: s }
    }),
    southArrowNorthMiddleEast: (a, l) => ({
      top: o(a),
      left: a.left + a.width / 2 - l.width * 0.75 + e,
      name: "arrow_nme",
      ...s && { config: s }
    }),
    southArrowNorthEast: (a, l) => ({
      top: o(a),
      left: a.left + a.width / 2 - l.width + e,
      name: "arrow_ne",
      ...s && { config: s }
    }),
    // ------- South east
    southEastArrowNorthWest: (a) => ({
      top: o(a),
      left: a.right - e,
      name: "arrow_nw",
      ...s && { config: s }
    }),
    southEastArrowNorthMiddleWest: (a, l) => ({
      top: o(a),
      left: a.right - l.width * 0.25 - e,
      name: "arrow_nmw",
      ...s && { config: s }
    }),
    southEastArrowNorth: (a, l) => ({
      top: o(a),
      left: a.right - l.width / 2,
      name: "arrow_n",
      ...s && { config: s }
    }),
    southEastArrowNorthMiddleEast: (a, l) => ({
      top: o(a),
      left: a.right - l.width * 0.75 + e,
      name: "arrow_nme",
      ...s && { config: s }
    }),
    southEastArrowNorthEast: (a, l) => ({
      top: o(a),
      left: a.right - l.width + e,
      name: "arrow_ne",
      ...s && { config: s }
    }),
    // ------- West
    westArrowEast: (a, l) => ({
      top: a.top + a.height / 2 - l.height / 2,
      left: a.left - l.width - t,
      name: "arrow_e",
      ...s && { config: s }
    }),
    // ------- East
    eastArrowWest: (a, l) => ({
      top: a.top + a.height / 2 - l.height / 2,
      left: a.right + t,
      name: "arrow_w",
      ...s && { config: s }
    }),
    // ------- Sticky
    viewportStickyNorth: (a, l, c) => a.getIntersection(c) ? {
      top: c.top + i,
      left: a.left + a.width / 2 - l.width / 2,
      name: "arrowless",
      config: {
        withArrow: !1,
        ...s
      }
    } : null
  };
  function r(a, l) {
    return a.top - l.height - t;
  }
  function o(a) {
    return a.bottom + t;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const dl = "ck-tooltip";
class ne extends it() {
  /**
   * Creates an instance of the tooltip manager.
   */
  constructor(e) {
    if (super(), this._currentElementWithTooltip = null, this._currentTooltipPosition = null, this._resizeObserver = null, ne._editors.add(e), ne._instance)
      return ne._instance;
    ne._instance = this, this.tooltipTextView = new T(e.locale), this.tooltipTextView.set("text", ""), this.tooltipTextView.setTemplate({
      tag: "span",
      attributes: {
        class: [
          "ck",
          "ck-tooltip__text"
        ]
      },
      children: [
        {
          text: this.tooltipTextView.bindTemplate.to("text")
        }
      ]
    }), this.balloonPanelView = new ae(e.locale), this.balloonPanelView.class = dl, this.balloonPanelView.content.add(this.tooltipTextView), this._pinTooltipDebounced = ti(this._pinTooltip, 600), this.listenTo(I.document, "mouseenter", this._onEnterOrFocus.bind(this), { useCapture: !0 }), this.listenTo(I.document, "mouseleave", this._onLeaveOrBlur.bind(this), { useCapture: !0 }), this.listenTo(I.document, "focus", this._onEnterOrFocus.bind(this), { useCapture: !0 }), this.listenTo(I.document, "blur", this._onLeaveOrBlur.bind(this), { useCapture: !0 }), this.listenTo(I.document, "scroll", this._onScroll.bind(this), { useCapture: !0 }), this._watchdogExcluded = !0;
  }
  /**
   * Destroys the tooltip manager.
   *
   * **Note**: The manager singleton cannot be destroyed until all editors that use it are destroyed.
   *
   * @param editor The editor the manager was created for.
   */
  destroy(e) {
    const t = e.ui.view && e.ui.view.body;
    ne._editors.delete(e), this.stopListening(e.ui), t && t.has(this.balloonPanelView) && t.remove(this.balloonPanelView), ne._editors.size || (this._unpinTooltip(), this.balloonPanelView.destroy(), this.stopListening(), ne._instance = null);
  }
  /**
   * Returns {@link #balloonPanelView} {@link module:utils/dom/position~PositioningFunction positioning functions} for a given position
   * name.
   *
   * @param position Name of the position (`s`, `se`, `sw`, `n`, `e`, or `w`).
   * @returns Positioning functions to be used by the {@link #balloonPanelView}.
   */
  static getPositioningFunctions(e) {
    const t = ne.defaultBalloonPositions;
    return {
      // South is most popular. We can use positioning heuristics to avoid clipping by the viewport with the sane fallback.
      s: [
        t.southArrowNorth,
        t.southArrowNorthEast,
        t.southArrowNorthWest
      ],
      n: [t.northArrowSouth],
      e: [t.eastArrowWest],
      w: [t.westArrowEast],
      sw: [t.southArrowNorthEast],
      se: [t.southArrowNorthWest]
    }[e];
  }
  /**
   * Handles displaying tooltips on `mouseenter` and `focus` in DOM.
   *
   * @param evt An object containing information about the fired event.
   * @param domEvent The DOM event.
   */
  _onEnterOrFocus(e, { target: t }) {
    const i = ds(t);
    i && i !== this._currentElementWithTooltip && (this._unpinTooltip(), this._pinTooltipDebounced(i, LC(i)));
  }
  /**
   * Handles hiding tooltips on `mouseleave` and `blur` in DOM.
   *
   * @param evt An object containing information about the fired event.
   * @param domEvent The DOM event.
   */
  _onLeaveOrBlur(e, { target: t, relatedTarget: i }) {
    if (e.name === "mouseleave") {
      if (!di(t) || this._currentElementWithTooltip && t !== this._currentElementWithTooltip)
        return;
      const s = ds(t), r = ds(i);
      s && s !== r && this._unpinTooltip();
    } else {
      if (this._currentElementWithTooltip && t !== this._currentElementWithTooltip)
        return;
      this._unpinTooltip();
    }
  }
  /**
   * Handles hiding tooltips on `scroll` in DOM.
   *
   * @param evt An object containing information about the fired event.
   * @param domEvent The DOM event.
   */
  _onScroll(e, { target: t }) {
    this._currentElementWithTooltip && (t.contains(this.balloonPanelView.element) && t.contains(this._currentElementWithTooltip) || this._unpinTooltip());
  }
  /**
   * Pins the tooltip to a specific DOM element.
   *
   * @param options.text Text of the tooltip to display.
   * @param options.position The position of the tooltip.
   * @param options.cssClass Additional CSS class of the balloon with the tooltip.
   */
  _pinTooltip(e, { text: t, position: i, cssClass: s }) {
    const r = Te(ne._editors.values()).ui.view.body;
    r.has(this.balloonPanelView) || r.add(this.balloonPanelView), this.tooltipTextView.text = t, this.balloonPanelView.pin({
      target: e,
      positions: ne.getPositioningFunctions(i)
    }), this._resizeObserver = new $(e, () => {
      St(e) || this._unpinTooltip();
    }), this.balloonPanelView.class = [dl, s].filter((o) => o).join(" ");
    for (const o of ne._editors)
      this.listenTo(o.ui, "update", this._updateTooltipPosition.bind(this), { priority: "low" });
    this._currentElementWithTooltip = e, this._currentTooltipPosition = i;
  }
  /**
   * Unpins the tooltip and cancels all queued pinning.
   */
  _unpinTooltip() {
    this._pinTooltipDebounced.cancel(), this.balloonPanelView.unpin();
    for (const e of ne._editors)
      this.stopListening(e.ui, "update");
    this._currentElementWithTooltip = null, this._currentTooltipPosition = null, this._resizeObserver && this._resizeObserver.destroy();
  }
  /**
   * Updates the position of the tooltip so it stays in sync with the element it is pinned to.
   *
   * Hides the tooltip when the element is no longer visible in DOM.
   */
  _updateTooltipPosition() {
    if (!St(this._currentElementWithTooltip)) {
      this._unpinTooltip();
      return;
    }
    this.balloonPanelView.pin({
      target: this._currentElementWithTooltip,
      positions: ne.getPositioningFunctions(this._currentTooltipPosition)
    });
  }
}
ne.defaultBalloonPositions = Zh({
  heightOffset: 5,
  sideOffset: 13
});
ne._editors = /* @__PURE__ */ new Set();
ne._instance = null;
function ds(n) {
  return di(n) ? n.closest("[data-cke-tooltip-text]:not([data-cke-tooltip-disabled])") : null;
}
function LC(n) {
  return {
    text: n.dataset.ckeTooltipText,
    position: n.dataset.ckeTooltipPosition || "s",
    cssClass: n.dataset.ckeTooltipClass || ""
  };
}
const $C = `<svg xmlns="http://www.w3.org/2000/svg" width="53" height="10" viewBox="0 0 53 10"><path fill="#1C2331" d="M31.724 1.492a15.139 15.139 0 0 0 .045 1.16 2.434 2.434 0 0 0-.687-.34 3.68 3.68 0 0 0-1.103-.166 2.332 2.332 0 0 0-1.14.255 1.549 1.549 0 0 0-.686.87c-.15.41-.225.98-.225 1.712 0 .939.148 1.659.444 2.161.297.503.792.754 1.487.754.452.015.9-.094 1.294-.316.296-.174.557-.4.771-.669l.14.852h1.282V.007h-1.623v1.485ZM31 6.496a1.77 1.77 0 0 1-.494.061.964.964 0 0 1-.521-.127.758.758 0 0 1-.296-.466 3.984 3.984 0 0 1-.093-.992 4.208 4.208 0 0 1 .098-1.052.753.753 0 0 1 .307-.477 1.08 1.08 0 0 1 .55-.122c.233-.004.466.026.69.089l.483.144v2.553c-.11.076-.213.143-.307.2a1.73 1.73 0 0 1-.417.189ZM35.68 0l-.702.004c-.322.002-.482.168-.48.497l.004.581c.002.33.164.493.486.49l.702-.004c.322-.002.481-.167.48-.496L36.165.49c-.002-.33-.164-.493-.486-.491ZM36.145 2.313l-1.612.01.034 5.482 1.613-.01-.035-5.482ZM39.623.79 37.989.8 38 2.306l-.946.056.006 1.009.949-.006.024 2.983c.003.476.143.844.419 1.106.275.26.658.39 1.148.387.132 0 .293-.01.483-.03.19-.02.38-.046.57-.08.163-.028.324-.068.482-.119l-.183-1.095-.702.004a.664.664 0 0 1-.456-.123.553.553 0 0 1-.14-.422l-.016-2.621 1.513-.01-.006-1.064-1.514.01-.01-1.503ZM46.226 2.388c-.41-.184-.956-.274-1.636-.27-.673.004-1.215.101-1.627.29-.402.179-.72.505-.888.91-.18.419-.268.979-.264 1.68.004.688.1 1.24.285 1.655.172.404.495.724.9.894.414.18.957.268 1.63.264.68-.004 1.224-.099 1.632-.284.4-.176.714-.501.878-.905.176-.418.263-.971.258-1.658-.004-.702-.097-1.261-.28-1.677a1.696 1.696 0 0 0-.888-.9Zm-.613 3.607a.77.77 0 0 1-.337.501 1.649 1.649 0 0 1-1.317.009.776.776 0 0 1-.343-.497 4.066 4.066 0 0 1-.105-1.02 4.136 4.136 0 0 1 .092-1.03.786.786 0 0 1 .337-.507 1.59 1.59 0 0 1 1.316-.008.79.79 0 0 1 .344.502c.078.337.113.683.105 1.03.012.343-.019.685-.092 1.02ZM52.114 2.07a2.67 2.67 0 0 0-1.128.278c-.39.191-.752.437-1.072.73l-.157-.846-1.273.008.036 5.572 1.623-.01-.024-3.78c.35-.124.646-.22.887-.286.26-.075.53-.114.8-.118l.45-.003.144-1.546-.286.001ZM22.083 7.426l-1.576-2.532a2.137 2.137 0 0 0-.172-.253 1.95 1.95 0 0 0-.304-.29.138.138 0 0 1 .042-.04 1.7 1.7 0 0 0 .328-.374l1.75-2.71c.01-.015.025-.028.024-.048-.01-.01-.021-.007-.031-.007L20.49 1.17a.078.078 0 0 0-.075.045l-.868 1.384c-.23.366-.46.732-.688 1.099a.108.108 0 0 1-.112.06c-.098-.005-.196-.001-.294-.002-.018 0-.038.006-.055-.007.002-.02.002-.039.005-.058a4.6 4.6 0 0 0 .046-.701V1.203c0-.02-.009-.032-.03-.03h-.033L16.93 1.17c-.084 0-.073-.01-.073.076v6.491c-.001.018.006.028.025.027h1.494c.083 0 .072.007.072-.071v-2.19c0-.055-.003-.11-.004-.166a3.366 3.366 0 0 0-.05-.417h.06c.104 0 .209.002.313-.002a.082.082 0 0 1 .084.05c.535.913 1.07 1.824 1.607 2.736a.104.104 0 0 0 .103.062c.554-.003 1.107-.002 1.66-.002l.069-.003-.019-.032-.188-.304ZM27.112 6.555c-.005-.08-.004-.08-.082-.08h-2.414c-.053 0-.106-.003-.159-.011a.279.279 0 0 1-.246-.209.558.558 0 0 1-.022-.15c0-.382 0-.762-.002-1.143 0-.032.007-.049.042-.044h2.504c.029.003.037-.012.034-.038V3.814c0-.089.013-.078-.076-.078h-2.44c-.07 0-.062.003-.062-.06v-.837c0-.047.004-.093.013-.14a.283.283 0 0 1 .241-.246.717.717 0 0 1 .146-.011h2.484c.024.002.035-.009.036-.033l.003-.038.03-.496c.01-.183.024-.365.034-.548.005-.085.003-.087-.082-.094-.218-.018-.437-.038-.655-.05a17.845 17.845 0 0 0-.657-.026 72.994 72.994 0 0 0-1.756-.016 1.7 1.7 0 0 0-.471.064 1.286 1.286 0 0 0-.817.655c-.099.196-.149.413-.145.633v3.875c0 .072.003.144.011.216a1.27 1.27 0 0 0 .711 1.029c.228.113.48.167.734.158.757-.005 1.515.002 2.272-.042.274-.016.548-.034.82-.053.03-.002.043-.008.04-.041-.008-.104-.012-.208-.019-.312a69.964 69.964 0 0 1-.05-.768ZM16.14 7.415l-.127-1.075c-.004-.03-.014-.04-.044-.037a13.125 13.125 0 0 1-.998.073c-.336.01-.672.02-1.008.016-.116-.001-.233-.014-.347-.039a.746.746 0 0 1-.45-.262c-.075-.1-.132-.211-.167-.33a3.324 3.324 0 0 1-.126-.773 9.113 9.113 0 0 1-.015-.749c0-.285.022-.57.065-.852.023-.158.066-.312.127-.46a.728.728 0 0 1 .518-.443 1.64 1.64 0 0 1 .397-.048c.628-.001 1.255.003 1.882.05.022.001.033-.006.036-.026l.003-.031.06-.55c.019-.177.036-.355.057-.532.004-.034-.005-.046-.04-.056a5.595 5.595 0 0 0-1.213-.21 10.783 10.783 0 0 0-.708-.02c-.24-.003-.48.01-.719.041a3.477 3.477 0 0 0-.625.14 1.912 1.912 0 0 0-.807.497c-.185.2-.33.433-.424.688a4.311 4.311 0 0 0-.24 1.096c-.031.286-.045.572-.042.86-.006.43.024.86.091 1.286.04.25.104.497.193.734.098.279.26.53.473.734.214.205.473.358.756.446.344.11.702.17 1.063.177a8.505 8.505 0 0 0 1.578-.083 6.11 6.11 0 0 0 .766-.18c.03-.008.047-.023.037-.057a.157.157 0 0 1-.003-.025Z"/><path fill="#AFE229" d="M6.016 6.69a1.592 1.592 0 0 0-.614.21c-.23.132-.422.32-.56.546-.044.072-.287.539-.287.539l-.836 1.528.009.006c.038.025.08.046.123.063.127.046.26.07.395.073.505.023 1.011-.007 1.517-.003.29.009.58.002.869-.022a.886.886 0 0 0 .395-.116.962.962 0 0 0 .312-.286c.056-.083.114-.163.164-.249.24-.408.48-.816.718-1.226.075-.128.148-.257.222-.386l.112-.192a1.07 1.07 0 0 0 .153-.518l-1.304.023s-1.258-.005-1.388.01Z"/><path fill="#771BFF" d="m2.848 9.044.76-1.39.184-.352c-.124-.067-.245-.14-.367-.21-.346-.204-.706-.384-1.045-.6a.984.984 0 0 1-.244-.207c-.108-.134-.136-.294-.144-.46-.021-.409-.002-.818-.009-1.227-.003-.195 0-.39.003-.585.004-.322.153-.553.427-.713l.833-.488c.22-.13.44-.257.662-.385.05-.029.105-.052.158-.077.272-.128.519-.047.76.085l.044.028c.123.06.242.125.358.196.318.178.635.357.952.537.095.056.187.117.275.184.194.144.254.35.266.578.016.284.007.569.006.853-.001.28.004.558 0 .838.592-.003 1.259 0 1.259 0l.723-.013c-.003-.292-.007-.584-.007-.876 0-.524.015-1.048-.016-1.571-.024-.42-.135-.8-.492-1.067a5.02 5.02 0 0 0-.506-.339A400.52 400.52 0 0 0 5.94.787C5.722.664 5.513.524 5.282.423 5.255.406 5.228.388 5.2.373 4.758.126 4.305-.026 3.807.21c-.097.046-.197.087-.29.14A699.896 699.896 0 0 0 .783 1.948c-.501.294-.773.717-.778 1.31-.004.36-.009.718-.001 1.077.016.754-.017 1.508.024 2.261.016.304.07.6.269.848.127.15.279.28.448.382.622.4 1.283.734 1.92 1.11l.183.109Z"/></svg>
`;
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const zC = 53, HC = 10, WC = 50, UC = 350, jC = "Powered by", en = {
  top: -99999,
  left: -99999,
  name: "invalid",
  config: {
    withArrow: !1
  }
};
class qC extends it() {
  /**
   * Creates a "powered by" helper for a given editor. The feature is initialized on Editor#ready
   * event.
   *
   * @param editor
   */
  constructor(e) {
    super(), this.editor = e, this._balloonView = null, this._lastFocusedEditableElement = null, this._showBalloonThrottled = Vn(this._showBalloon.bind(this), 50, { leading: !0 }), e.on("ready", this._handleEditorReady.bind(this));
  }
  /**
   * Destroys the "powered by" helper along with its view.
   */
  destroy() {
    const e = this._balloonView;
    e && (e.unpin(), this._balloonView = null), this._showBalloonThrottled.cancel(), this.stopListening();
  }
  /**
   * Enables "powered by" label once the editor (ui) is ready.
   */
  _handleEditorReady() {
    const e = this.editor, t = !!e.config.get("ui.poweredBy.forceVisible");
    /* istanbul ignore next -- @preserve */
    !t && J_(e.config.get("licenseKey")) === "VALID" || e.ui.view && (e.ui.focusTracker.on("change:isFocused", (i, s, r) => {
      this._updateLastFocusedEditableElement(), r ? this._showBalloon() : this._hideBalloon();
    }), e.ui.focusTracker.on("change:focusedElement", (i, s, r) => {
      this._updateLastFocusedEditableElement(), r && this._showBalloon();
    }), e.ui.on("update", () => {
      this._showBalloonThrottled();
    }));
  }
  /**
   * Creates an instance of the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon panel}
   * with the "powered by" view inside ready for positioning.
   */
  _createBalloonView() {
    const e = this.editor, t = this._balloonView = new ae(), i = Xh(e), s = new GC(e.locale, i.label);
    t.content.add(s), t.set({
      class: "ck-powered-by-balloon"
    }), e.ui.view.body.add(t), e.ui.focusTracker.add(t.element), this._balloonView = t;
  }
  /**
   * Attempts to display the balloon with the "powered by" view.
   */
  _showBalloon() {
    if (!this._lastFocusedEditableElement)
      return;
    const e = KC(this.editor, this._lastFocusedEditableElement);
    e && (this._balloonView || this._createBalloonView(), this._balloonView.pin(e));
  }
  /**
   * Hides the "powered by" balloon if already visible.
   */
  _hideBalloon() {
    this._balloonView && this._balloonView.unpin();
  }
  /**
   * Updates the {@link #_lastFocusedEditableElement} based on the state of the global focus tracker.
   */
  _updateLastFocusedEditableElement() {
    const e = this.editor, t = e.ui.focusTracker.isFocused, i = e.ui.focusTracker.focusedElement;
    if (!t || !i) {
      this._lastFocusedEditableElement = null;
      return;
    }
    const s = Array.from(e.ui.getEditableElementsNames()).map((r) => e.ui.getEditableElement(r));
    s.includes(i) ? this._lastFocusedEditableElement = i : this._lastFocusedEditableElement = s[0];
  }
}
class GC extends T {
  /**
   * Created an instance of the "powered by" view.
   *
   * @param locale The localization services instance.
   * @param label The label text.
   */
  constructor(e, t) {
    super(e);
    const i = new mt(), s = this.bindTemplate;
    i.set({
      content: $C,
      isColorInherited: !1
    }), i.extendTemplate({
      attributes: {
        style: {
          width: zC + "px",
          height: HC + "px"
        }
      }
    }), this.setTemplate({
      tag: "div",
      attributes: {
        class: ["ck", "ck-powered-by"],
        "aria-hidden": !0
      },
      children: [
        {
          tag: "a",
          attributes: {
            href: "https://ckeditor.com/?utm_source=ckeditor&utm_medium=referral&utm_campaign=701Dn000000hVgmIAE_powered_by_ckeditor_logo",
            target: "_blank",
            tabindex: "-1"
          },
          children: [
            ...t ? [
              {
                tag: "span",
                attributes: {
                  class: ["ck", "ck-powered-by__label"]
                },
                children: [t]
              }
            ] : [],
            i
          ],
          on: {
            dragstart: s.to((r) => r.preventDefault())
          }
        }
      ]
    });
  }
}
function KC(n, e) {
  const t = Xh(n), i = t.side === "right" ? JC(e, t) : ZC(e, t);
  return {
    target: e,
    positions: [i]
  };
}
function JC(n, e) {
  return Yh(n, e, (t, i) => t.left + t.width - i.width - e.horizontalOffset);
}
function ZC(n, e) {
  return Yh(n, e, (t) => t.left + e.horizontalOffset);
}
function Yh(n, e, t) {
  return (i, s) => {
    const r = i.getVisible();
    if (!r || i.width < UC || i.height < WC)
      return en;
    let o;
    e.position === "inside" ? o = i.bottom - s.height : o = i.bottom - s.height / 2, o -= e.verticalOffset;
    const a = t(i, s);
    if (e.position === "inside") {
      const l = s.clone().moveTo(a, o);
      if (l.getIntersectionArea(r) < l.getArea())
        return en;
    } else {
      const l = y_(n);
      if (l) {
        const c = new V(l);
        if (r.bottom + s.height / 2 > c.bottom)
          return en;
      }
    }
    return {
      top: o,
      left: a,
      name: `position_${e.position}-side_${e.side}`,
      config: {
        withArrow: !1
      }
    };
  };
}
function Xh(n) {
  const e = n.config.get("ui.poweredBy"), t = e && e.position || "border";
  return {
    position: t,
    label: jC,
    verticalOffset: t === "inside" ? 5 : 0,
    horizontalOffset: 5,
    side: n.locale.contentLanguageDirection === "ltr" ? "right" : "left",
    ...e
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class YC extends z() {
  /**
   * Creates an instance of the editor UI class.
   *
   * @param editor The editor instance.
   */
  constructor(e) {
    super(), this.isReady = !1, this._editableElementsMap = /* @__PURE__ */ new Map(), this._focusableToolbarDefinitions = [];
    const t = e.editing.view;
    this.editor = e, this.componentFactory = new NC(e), this.focusTracker = new ye(), this.tooltipManager = new ne(e), this.poweredBy = new qC(e), this.set("viewportOffset", this._readViewportOffsetFromConfig()), this.once("ready", () => {
      this.isReady = !0;
    }), this.listenTo(t.document, "layoutChanged", this.update.bind(this)), this.listenTo(t, "scrollToTheSelection", this._handleScrollToTheSelection.bind(this)), this._initFocusTracking();
  }
  /**
   * The main (outermost) DOM element of the editor UI.
   *
   * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `<div>` which
   * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}
   * it is the editable element itself (as there is no other wrapper). However, in
   * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not
   * come with a single "main" HTML element (its editable element and toolbar are separate).
   *
   * This property can be understood as a shorthand for retrieving the element that a specific editor integration
   * considers to be its main DOM element.
   */
  get element() {
    return null;
  }
  /**
   * Fires the {@link module:ui/editorui/editorui~EditorUI#event:update `update`} event.
   *
   * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to
   * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).
   */
  update() {
    this.fire("update");
  }
  /**
   * Destroys the UI.
   */
  destroy() {
    this.stopListening(), this.focusTracker.destroy(), this.tooltipManager.destroy(this.editor), this.poweredBy.destroy();
    for (const e of this._editableElementsMap.values())
      e.ckeditorInstance = null, this.editor.keystrokes.stopListening(e);
    this._editableElementsMap = /* @__PURE__ */ new Map(), this._focusableToolbarDefinitions = [];
  }
  /**
   * Stores the native DOM editable element used by the editor under a unique name.
   *
   * Also, registers the element in the editor to maintain the accessibility of the UI. When the user is editing text in a focusable
   * editable area, they can use the <kbd>Alt</kbd> + <kbd>F10</kbd> keystroke to navigate over editor toolbars. See {@link #addToolbar}.
   *
   * @param rootName The unique name of the editable element.
   * @param domElement The native DOM editable element.
   */
  setEditableElement(e, t) {
    this._editableElementsMap.set(e, t), t.ckeditorInstance || (t.ckeditorInstance = this.editor), this.focusTracker.add(t);
    const i = () => {
      this.editor.editing.view.getDomRoot(e) || this.editor.keystrokes.listenTo(t);
    };
    this.isReady ? i() : this.once("ready", i);
  }
  /**
   * Removes the editable from the editor UI. Removes all handlers added by {@link #setEditableElement}.
   *
   * @param rootName The name of the editable element to remove.
   */
  removeEditableElement(e) {
    const t = this._editableElementsMap.get(e);
    t && (this._editableElementsMap.delete(e), this.editor.keystrokes.stopListening(t), this.focusTracker.remove(t), t.ckeditorInstance = null);
  }
  /**
   * Returns the editable editor element with the given name or null if editable does not exist.
   *
   * @param rootName The editable name.
   */
  getEditableElement(e = "main") {
    return this._editableElementsMap.get(e);
  }
  /**
   * Returns array of names of all editor editable elements.
   */
  getEditableElementsNames() {
    return this._editableElementsMap.keys();
  }
  /**
   * Adds a toolbar to the editor UI. Used primarily to maintain the accessibility of the UI.
   *
   * Focusable toolbars can be accessed (focused) by users by pressing the <kbd>Alt</kbd> + <kbd>F10</kbd> keystroke.
   * Successive keystroke presses navigate over available toolbars.
   *
   * @param toolbarView A instance of the toolbar to be registered.
   */
  addToolbar(e, t = {}) {
    e.isRendered ? (this.focusTracker.add(e.element), this.editor.keystrokes.listenTo(e.element)) : e.once("render", () => {
      this.focusTracker.add(e.element), this.editor.keystrokes.listenTo(e.element);
    }), this._focusableToolbarDefinitions.push({ toolbarView: e, options: t });
  }
  /**
   * Stores all editable elements used by the editor instance.
   *
   * @deprecated
   */
  get _editableElements() {
    return console.warn("editor-ui-deprecated-editable-elements: The EditorUI#_editableElements property has been deprecated and will be removed in the near future.", { editorUI: this }), this._editableElementsMap;
  }
  /**
   * Returns viewport offsets object:
   *
   * ```js
   * {
   * 	top: Number,
   * 	right: Number,
   * 	bottom: Number,
   * 	left: Number
   * }
   * ```
   *
   * Only top property is currently supported.
   */
  _readViewportOffsetFromConfig() {
    const e = this.editor, t = e.config.get("ui.viewportOffset");
    if (t)
      return t;
    const i = e.config.get("toolbar.viewportTopOffset");
    return i ? (console.warn("editor-ui-deprecated-viewport-offset-config: The `toolbar.vieportTopOffset` configuration option is deprecated. It will be removed from future CKEditor versions. Use `ui.viewportOffset.top` instead."), { top: i }) : { top: 0 };
  }
  /**
   * Starts listening for <kbd>Alt</kbd> + <kbd>F10</kbd> and <kbd>Esc</kbd> keystrokes in the context of focusable
   * {@link #setEditableElement editable elements} and {@link #addToolbar toolbars}
   * to allow users navigate across the UI.
   */
  _initFocusTracking() {
    const e = this.editor, t = e.editing.view;
    let i, s;
    e.keystrokes.set("Alt+F10", (r, o) => {
      const a = this.focusTracker.focusedElement;
      Array.from(this._editableElementsMap.values()).includes(a) && !Array.from(t.domRoots.values()).includes(a) && (i = a);
      const l = this._getCurrentFocusedToolbarDefinition();
      (!l || !s) && (s = this._getFocusableCandidateToolbarDefinitions());
      for (let c = 0; c < s.length; c++) {
        const u = s.shift();
        if (s.push(u), u !== l && this._focusFocusableCandidateToolbar(u)) {
          l && l.options.afterBlur && l.options.afterBlur();
          break;
        }
      }
      o();
    }), e.keystrokes.set("Esc", (r, o) => {
      const a = this._getCurrentFocusedToolbarDefinition();
      a && (i ? (i.focus(), i = null) : e.editing.view.focus(), a.options.afterBlur && a.options.afterBlur(), o());
    });
  }
  /**
   * Returns definitions of toolbars that could potentially be focused, sorted by their importance for the user.
   *
   * Focusable toolbars candidates are either:
   * * already visible,
   * * have `beforeFocus()` set in their {@link module:ui/editorui/editorui~FocusableToolbarDefinition definition} that suggests that
   * they might show up when called. Keep in mind that determining whether a toolbar will show up (and become focusable) is impossible
   * at this stage because it depends on its implementation, that in turn depends on the editing context (selection).
   *
   * **Note**: Contextual toolbars take precedence over regular toolbars.
   */
  _getFocusableCandidateToolbarDefinitions() {
    const e = [];
    for (const t of this._focusableToolbarDefinitions) {
      const { toolbarView: i, options: s } = t;
      (St(i.element) || s.beforeFocus) && e.push(t);
    }
    return e.sort((t, i) => fl(t) - fl(i)), e;
  }
  /**
   * Returns a definition of the toolbar that is currently visible and focused (one of its children has focus).
   *
   * `null` is returned when no toolbar is currently focused.
   */
  _getCurrentFocusedToolbarDefinition() {
    for (const e of this._focusableToolbarDefinitions)
      if (e.toolbarView.element && e.toolbarView.element.contains(this.focusTracker.focusedElement))
        return e;
    return null;
  }
  /**
   * Focuses a focusable toolbar candidate using its definition.
   *
   * @param candidateToolbarDefinition A definition of the toolbar to focus.
   * @returns `true` when the toolbar candidate was focused. `false` otherwise.
   */
  _focusFocusableCandidateToolbar(e) {
    const { toolbarView: t, options: { beforeFocus: i } } = e;
    return i && i(), St(t.element) ? (t.focus(), !0) : !1;
  }
  /**
   * Provides an integration between {@link #viewportOffset} and {@link module:utils/dom/scroll~scrollViewportToShowTarget}.
   * It allows the UI-agnostic engine method to consider user-configured viewport offsets specific for the integration.
   *
   * @param evt The `scrollToTheSelection` event info.
   * @param data The payload carried by the `scrollToTheSelection` event.
   */
  _handleScrollToTheSelection(e, t) {
    const i = {
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      ...this.viewportOffset
    };
    t.viewportOffset.top += i.top, t.viewportOffset.bottom += i.bottom, t.viewportOffset.left += i.left, t.viewportOffset.right += i.right;
  }
}
function fl(n) {
  const { toolbarView: e, options: t } = n;
  let i = 10;
  return St(e.element) && i--, t.isContextual && i--, i;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class XC extends T {
  /**
   * Creates an instance of the editor UI view class.
   *
   * @param locale The locale instance.
   */
  constructor(e) {
    super(e), this.body = new R2(e);
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.body.attachToDom();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    return this.body.detachFromDom(), super.destroy();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class QC extends T {
  /**
   * Creates an instance of EditableUIView class.
   *
   * @param locale The locale instance.
   * @param editingView The editing view instance the editable is related to.
   * @param editableElement The editable element. If not specified, this view
   * should create it. Otherwise, the existing element should be used.
   */
  constructor(e, t, i) {
    super(e), this.name = null, this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-content",
          "ck-editor__editable",
          "ck-rounded-corners"
        ],
        lang: e.contentLanguage,
        dir: e.contentLanguageDirection
      }
    }), this.set("isFocused", !1), this._editableElement = i, this._hasExternalElement = !!this._editableElement, this._editingView = t;
  }
  /**
   * Renders the view by either applying the {@link #template} to the existing
   * {@link module:ui/editableui/editableuiview~EditableUIView#_editableElement} or assigning {@link #element}
   * as {@link module:ui/editableui/editableuiview~EditableUIView#_editableElement}.
   */
  render() {
    super.render(), this._hasExternalElement ? this.template.apply(this.element = this._editableElement) : this._editableElement = this.element, this.on("change:isFocused", () => this._updateIsFocusedClasses()), this._updateIsFocusedClasses();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    this._hasExternalElement && this.template.revert(this._editableElement), super.destroy();
  }
  /**
   * Whether an external {@link #_editableElement} was passed into the constructor, which also means
   * the view will not render its {@link #template}.
   */
  get hasExternalElement() {
    return this._hasExternalElement;
  }
  /**
   * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to
   * the {@link #isFocused} property value using the {@link #_editingView editing view} API.
   */
  _updateIsFocusedClasses() {
    const e = this._editingView;
    e.isRenderingInProgress ? i(this) : t(this);
    function t(s) {
      e.change((r) => {
        const o = e.document.getRoot(s.name);
        r.addClass(s.isFocused ? "ck-focused" : "ck-blurred", o), r.removeClass(s.isFocused ? "ck-blurred" : "ck-focused", o);
      });
    }
    function i(s) {
      e.once("change:isRenderingInProgress", (r, o, a) => {
        a ? i(s) : t(s);
      });
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class eE extends QC {
  /**
   * Creates an instance of the InlineEditableUIView class.
   *
   * @param locale The locale instance.
   * @param editingView The editing view instance the editable is related to.
   * @param editableElement The editable element. If not specified, the
   * {@link module:ui/editableui/editableuiview~EditableUIView}
   * will create it. Otherwise, the existing element will be used.
   * @param options Additional configuration of the view.
   * @param options.label A function that gets called with the instance of this view as an argument
   * and should return a string that represents the label of the editable for assistive technologies. If not provided,
   * a default label generator is used.
   */
  constructor(e, t, i, s = {}) {
    super(e, t, i);
    const r = e.t;
    this.extendTemplate({
      attributes: {
        role: "textbox",
        class: "ck-editor__editable_inline"
      }
    }), this._generateLabel = s.label || (() => r("Editor editing area: %0", this.name));
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render();
    const e = this._editingView;
    e.change((t) => {
      const i = e.document.getRoot(this.name);
      t.setAttribute("aria-label", this._generateLabel(this), i);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Qh extends z() {
  /**
   * Creates a new Model instance.
   *
   * @param attributes The model state attributes to be defined during the instance creation.
   * @param properties The (out of state) properties to be appended to the instance during creation.
   */
  constructor(e, t) {
    super(), t && Ec(this, t), e && this.set(e);
  }
}
const tE = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.463 5.187a.888.888 0 1 1 1.254 1.255L9.16 10l3.557 3.557a.888.888 0 1 1-1.254 1.255L7.26 10.61a.888.888 0 0 1 .16-1.382l4.043-4.042z"/></svg>', iE = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M8.537 14.813a.888.888 0 1 1-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 1 1 1.254-1.255L12.74 9.39a.888.888 0 0 1-.16 1.382l-4.043 4.042z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const tn = Sr("px");
class Cn extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ContextualBalloon";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._viewToStack = /* @__PURE__ */ new Map(), this._idToStack = /* @__PURE__ */ new Map(), this._view = null, this._rotatorView = null, this._fakePanelsView = null, this.positionLimiter = () => {
      const t = this.editor.editing.view, s = t.document.selection.editableElement;
      return s ? t.domConverter.mapViewToDom(s.root) : null;
    }, this.set("visibleView", null), this.set("_numberOfStacks", 0), this.set("_singleViewMode", !1);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._view && this._view.destroy(), this._rotatorView && this._rotatorView.destroy(), this._fakePanelsView && this._fakePanelsView.destroy();
  }
  /**
   * The common balloon panel view.
   */
  get view() {
    return this._view || this._createPanelView(), this._view;
  }
  /**
   * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.
   */
  hasView(e) {
    return Array.from(this._viewToStack.keys()).includes(e);
  }
  /**
   * Adds a new view to the stack and makes it visible if the current stack is visible
   * or it is the first view in the balloon.
   *
   * @param data The configuration of the view.
   * @param data.stackId The ID of the stack that the view is added to. Defaults to `'main'`.
   * @param data.view The content of the balloon.
   * @param data.position Positioning options.
   * @param data.balloonClassName An additional CSS class added to the {@link #view balloon} when visible.
   * @param data.withArrow Whether the {@link #view balloon} should be rendered with an arrow. Defaults to `true`.
   * @param data.singleViewMode Whether the view should be the only visible view even if other stacks were added. Defaults to `false`.
   */
  add(e) {
    if (this._view || this._createPanelView(), this.hasView(e.view))
      throw new d("contextualballoon-add-view-exist", [this, e]);
    const t = e.stackId || "main";
    if (!this._idToStack.has(t)) {
      this._idToStack.set(t, /* @__PURE__ */ new Map([[e.view, e]])), this._viewToStack.set(e.view, this._idToStack.get(t)), this._numberOfStacks = this._idToStack.size, (!this._visibleStack || e.singleViewMode) && this.showStack(t);
      return;
    }
    const i = this._idToStack.get(t);
    e.singleViewMode && this.showStack(t), i.set(e.view, e), this._viewToStack.set(e.view, i), i === this._visibleStack && this._showView(e);
  }
  /**
   * Removes the given view from the stack. If the removed view was visible,
   * the view preceding it in the stack will become visible instead.
   * When there is no view in the stack, the next stack will be displayed.
   * When there are no more stacks, the balloon will hide.
   *
   * @param view A view to be removed from the balloon.
   */
  remove(e) {
    if (!this.hasView(e))
      throw new d("contextualballoon-remove-view-not-exist", [this, e]);
    const t = this._viewToStack.get(e);
    this._singleViewMode && this.visibleView === e && (this._singleViewMode = !1), this.visibleView === e && (t.size === 1 ? this._idToStack.size > 1 ? this._showNextStack() : (this.view.hide(), this.visibleView = null, this._rotatorView.hideView()) : this._showView(Array.from(t.values())[t.size - 2])), t.size === 1 ? (this._idToStack.delete(this._getStackId(t)), this._numberOfStacks = this._idToStack.size) : t.delete(e), this._viewToStack.delete(e);
  }
  /**
   * Updates the position of the balloon using the position data of the first visible view in the stack.
   * When new position data is given, the position data of the currently visible view will be updated.
   *
   * @param position Position options.
   */
  updatePosition(e) {
    e && (this._visibleStack.get(this.visibleView).position = e), this.view.pin(this._getBalloonPosition()), this._fakePanelsView.updatePosition();
  }
  /**
   * Shows the last view from the stack of a given ID.
   */
  showStack(e) {
    this.visibleStack = e;
    const t = this._idToStack.get(e);
    if (!t)
      throw new d("contextualballoon-showstack-stack-not-exist", this);
    this._visibleStack !== t && this._showView(Array.from(t.values()).pop());
  }
  /**
   * Initializes view instances.
   */
  _createPanelView() {
    this._view = new ae(this.editor.locale), this.editor.ui.view.body.add(this._view), this.editor.ui.focusTracker.add(this._view.element), this._rotatorView = this._createRotatorView(), this._fakePanelsView = this._createFakePanelsView();
  }
  /**
   * Returns the stack of the currently visible view.
   */
  get _visibleStack() {
    return this._viewToStack.get(this.visibleView);
  }
  /**
   * Returns the ID of the given stack.
   */
  _getStackId(e) {
    return Array.from(this._idToStack.entries()).find((i) => i[1] === e)[0];
  }
  /**
   * Shows the last view from the next stack.
   */
  _showNextStack() {
    const e = Array.from(this._idToStack.values());
    let t = e.indexOf(this._visibleStack) + 1;
    e[t] || (t = 0), this.showStack(this._getStackId(e[t]));
  }
  /**
   * Shows the last view from the previous stack.
   */
  _showPrevStack() {
    const e = Array.from(this._idToStack.values());
    let t = e.indexOf(this._visibleStack) - 1;
    e[t] || (t = e.length - 1), this.showStack(this._getStackId(e[t]));
  }
  /**
   * Creates a rotator view.
   */
  _createRotatorView() {
    const e = new nE(this.editor.locale), t = this.editor.locale.t;
    return this.view.content.add(e), e.bind("isNavigationVisible").to(this, "_numberOfStacks", this, "_singleViewMode", (i, s) => !s && i > 1), e.on("change:isNavigationVisible", () => this.updatePosition(), { priority: "low" }), e.bind("counter").to(this, "visibleView", this, "_numberOfStacks", (i, s) => {
      if (s < 2)
        return "";
      const r = Array.from(this._idToStack.values()).indexOf(this._visibleStack) + 1;
      return t("%0 of %1", [r, s]);
    }), e.buttonNextView.on("execute", () => {
      e.focusTracker.isFocused && this.editor.editing.view.focus(), this._showNextStack();
    }), e.buttonPrevView.on("execute", () => {
      e.focusTracker.isFocused && this.editor.editing.view.focus(), this._showPrevStack();
    }), e;
  }
  /**
   * Creates a fake panels view.
   */
  _createFakePanelsView() {
    const e = new sE(this.editor.locale, this.view);
    return e.bind("numberOfPanels").to(this, "_numberOfStacks", this, "_singleViewMode", (t, i) => !i && t >= 2 ? Math.min(t - 1, 2) : 0), e.listenTo(this.view, "change:top", () => e.updatePosition()), e.listenTo(this.view, "change:left", () => e.updatePosition()), this.editor.ui.view.body.add(e), e;
  }
  /**
   * Sets the view as the content of the balloon and attaches the balloon using position
   * options of the first view.
   *
   * @param data Configuration.
   * @param data.view The view to show in the balloon.
   * @param data.balloonClassName Additional class name which will be added to the {@link #view balloon}.
   * @param data.withArrow Whether the {@link #view balloon} should be rendered with an arrow.
   */
  _showView({ view: e, balloonClassName: t = "", withArrow: i = !0, singleViewMode: s = !1 }) {
    this.view.class = t, this.view.withArrow = i, this._rotatorView.showView(e), this.visibleView = e, this.view.pin(this._getBalloonPosition()), this._fakePanelsView.updatePosition(), s && (this._singleViewMode = !0);
  }
  /**
   * Returns position options of the last view in the stack.
   * This keeps the balloon in the same position when the view is changed.
   */
  _getBalloonPosition() {
    let e = Array.from(this._visibleStack.values()).pop().position;
    return e && (e.limiter || (e = Object.assign({}, e, {
      limiter: this.positionLimiter
    })), e = Object.assign({}, e, {
      viewportOffsetConfig: this.editor.ui.viewportOffset
    })), e;
  }
}
class nE extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = e.t, i = this.bindTemplate;
    this.set("isNavigationVisible", !0), this.focusTracker = new ye(), this.buttonPrevView = this._createButtonView(t("Previous"), tE), this.buttonNextView = this._createButtonView(t("Next"), iE), this.content = this.createCollection(), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-balloon-rotator"
        ],
        "z-index": "-1"
      },
      children: [
        {
          tag: "div",
          attributes: {
            class: [
              "ck-balloon-rotator__navigation",
              i.to("isNavigationVisible", (s) => s ? "" : "ck-hidden")
            ]
          },
          children: [
            this.buttonPrevView,
            {
              tag: "span",
              attributes: {
                class: [
                  "ck-balloon-rotator__counter"
                ]
              },
              children: [
                {
                  text: i.to("counter")
                }
              ]
            },
            this.buttonNextView
          ]
        },
        {
          tag: "div",
          attributes: {
            class: "ck-balloon-rotator__content"
          },
          children: this.content
        }
      ]
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.focusTracker.add(this.element);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy();
  }
  /**
   * Shows a given view.
   *
   * @param view The view to show.
   */
  showView(e) {
    this.hideView(), this.content.add(e);
  }
  /**
   * Hides the currently displayed view.
   */
  hideView() {
    this.content.clear();
  }
  /**
   * Creates a navigation button view.
   *
   * @param label The button label.
   * @param icon The button icon.
   */
  _createButtonView(e, t) {
    const i = new H(this.locale);
    return i.set({
      label: e,
      icon: t,
      tooltip: !0
    }), i;
  }
}
class sE extends T {
  /**
   * @inheritDoc
   */
  constructor(e, t) {
    super(e);
    const i = this.bindTemplate;
    this.set("top", 0), this.set("left", 0), this.set("height", 0), this.set("width", 0), this.set("numberOfPanels", 0), this.content = this.createCollection(), this._balloonPanelView = t, this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck-fake-panel",
          i.to("numberOfPanels", (s) => s ? "" : "ck-hidden")
        ],
        style: {
          top: i.to("top", tn),
          left: i.to("left", tn),
          width: i.to("width", tn),
          height: i.to("height", tn)
        }
      },
      children: this.content
    }), this.on("change:numberOfPanels", (s, r, o, a) => {
      o > a ? this._addPanels(o - a) : this._removePanels(a - o), this.updatePosition();
    });
  }
  _addPanels(e) {
    for (; e--; ) {
      const t = new T();
      t.setTemplate({ tag: "div" }), this.content.add(t), this.registerChild(t);
    }
  }
  _removePanels(e) {
    for (; e--; ) {
      const t = this.content.last;
      this.content.remove(t), this.deregisterChild(t), t.destroy();
    }
  }
  /**
   * Updates coordinates of fake panels.
   */
  updatePosition() {
    if (this.numberOfPanels) {
      const { top: e, left: t } = this._balloonPanelView, { width: i, height: s } = new V(this._balloonPanelView.element);
      Object.assign(this, { top: e, left: t, width: i, height: s });
    }
  }
}
const rE = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M10.209 18.717A8.5 8.5 0 1 1 18.686 9.6h-.008l.002.12a3 3 0 0 1-2.866 2.997h-.268l-.046-.002v.002h-4.791a2 2 0 1 0 0 4 1 1 0 1 1-.128 1.992 8.665 8.665 0 0 1-.372.008Zm-3.918-7.01a1.25 1.25 0 1 0-2.415-.648 1.25 1.25 0 0 0 2.415.647ZM5.723 8.18a1.25 1.25 0 1 0 .647-2.414 1.25 1.25 0 0 0-.647 2.414ZM9.76 6.155a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Zm4.028 1.759a1.25 1.25 0 1 0 .647-2.415 1.25 1.25 0 0 0-.647 2.415Z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const oE = {
  colorPaletteIcon: rE
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class aE extends YC {
  /**
   * Creates an instance of the inline editor UI class.
   *
   * @param editor The editor instance.
   * @param view The view of the UI.
   */
  constructor(e, t) {
    super(e), this.view = t, this._toolbarConfig = Hh(e.config.get("toolbar"));
  }
  /**
   * @inheritDoc
   */
  get element() {
    return this.view.editable.element;
  }
  /**
   * Initializes the UI.
   */
  init() {
    const e = this.editor, t = this.view, i = e.editing.view, s = t.editable, r = i.document.getRoot();
    s.name = r.rootName, t.render();
    const o = s.element;
    this.setEditableElement(s.name, o), s.bind("isFocused").to(this.focusTracker), i.attachDomRoot(o), this._initPlaceholder(), this._initToolbar(), this.fire("ready");
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy();
    const e = this.view;
    this.editor.editing.view.detachDomRoot(e.editable.name), e.destroy();
  }
  /**
   * Initializes the inline editor toolbar and its panel.
   */
  _initToolbar() {
    const e = this.editor, t = this.view, i = t.editable.element, s = t.toolbar;
    t.panel.bind("isVisible").to(this.focusTracker, "isFocused"), t.bind("viewportTopOffset").to(this, "viewportOffset", ({ top: r }) => r || 0), t.listenTo(e.ui, "update", () => {
      t.panel.isVisible && t.panel.pin({
        target: i,
        positions: t.panelPositions
      });
    }), s.fillFromConfig(this._toolbarConfig, this.componentFactory), this.addToolbar(s);
  }
  /**
   * Enable the placeholder text on the editing root, if any was configured.
   */
  _initPlaceholder() {
    const e = this.editor, t = e.editing.view, i = t.document.getRoot();
    e.sourceElement;
    const s = e.config.get("placeholder");
    if (s) {
      const r = typeof s == "string" ? s : s[i.rootName];
      r && t1({
        view: t,
        element: i,
        text: r,
        isDirectHost: !1,
        keepOnFocus: !0
      });
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const lE = Sr("px");
class cE extends XC {
  /**
   * Creates an instance of the inline editor UI view.
   *
   * @param locale The {@link module:core/editor/editor~Editor#locale} instance.
   * @param editingView The editing view instance this view is related to.
   * @param editableElement The editable element. If not specified, it will be automatically created by
   * {@link module:ui/editableui/editableuiview~EditableUIView}. Otherwise, the given element will be used.
   * @param options Configuration options for the view instance.
   * @param options.shouldToolbarGroupWhenFull When set `true` enables automatic items grouping
   * in the main {@link module:editor-inline/inlineeditoruiview~InlineEditorUIView#toolbar toolbar}.
   * See {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull} to learn more.
   */
  constructor(e, t, i, s = {}) {
    super(e);
    const r = e.t;
    this.toolbar = new Zr(e, {
      shouldGroupWhenFull: s.shouldToolbarGroupWhenFull,
      isFloating: !0
    }), this.set("viewportTopOffset", 0), this.panel = new ae(e), this.panelPositions = this._getPanelPositions(), this.panel.extendTemplate({
      attributes: {
        class: "ck-toolbar-container"
      }
    }), this.editable = new eE(e, t, i, {
      label: (o) => r("Rich Text Editor. Editing area: %0", o.name)
    }), this._resizeObserver = null;
  }
  /**
   * @inheritDoc
   */
  render() {
    if (super.render(), this.body.add(this.panel), this.registerChild(this.editable), this.panel.content.add(this.toolbar), this.toolbar.options.shouldGroupWhenFull) {
      const t = this.editable.element;
      this._resizeObserver = new $(t, () => {
        this.toolbar.maxWidth = lE(new V(t).width);
      });
    }
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._resizeObserver && this._resizeObserver.destroy();
  }
  /**
   * Determines the panel top position of the {@link #panel} in {@link #panelPositions}.
   *
   * @param editableRect Rect of the {@link #element}.
   * @param panelRect Rect of the {@link #panel}.
   */
  _getPanelPositionTop(e, t) {
    let i;
    return e.top > t.height + this.viewportTopOffset ? i = e.top - t.height : e.bottom > t.height + this.viewportTopOffset + 50 ? i = this.viewportTopOffset : i = e.bottom, i;
  }
  /**
   * Returns the positions for {@link #panelPositions}.
   *
   * See: {@link module:utils/dom/position~Options#positions}.
   */
  _getPanelPositions() {
    const e = [
      (t, i) => ({
        top: this._getPanelPositionTop(t, i),
        left: t.left,
        name: "toolbar_west",
        config: {
          withArrow: !1
        }
      }),
      (t, i) => ({
        top: this._getPanelPositionTop(t, i),
        left: t.left + t.width - i.width,
        name: "toolbar_east",
        config: {
          withArrow: !1
        }
      })
    ];
    return this.locale.uiLanguageDirection === "ltr" ? e : e.reverse();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Qr extends on(er(Rk)) {
  /**
   * Creates an instance of the inline editor.
   *
   * **Note:** Do not use the constructor to create editor instances. Use the static
   * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`} method instead.
   *
   * @param sourceElementOrData The DOM element that will be the source for the created editor
   * (on which the editor will be initialized) or initial data for the editor. For more information see
   * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}.
   * @param config The editor configuration.
   */
  constructor(e, t = {}) {
    if (!ln(e) && t.initialData !== void 0)
      throw new d("editor-create-initial-data", null);
    super(t), this.config.get("initialData") === void 0 && this.config.set("initialData", uE(e)), this.model.document.createRoot(), ln(e) && (this.sourceElement = e, Vk(this, e));
    const i = !this.config.get("toolbar.shouldNotGroupWhenFull"), s = new cE(this.locale, this.editing.view, this.sourceElement, {
      shouldToolbarGroupWhenFull: i
    });
    this.ui = new aE(this, s), Ok(this);
  }
  /**
   * Destroys the editor instance, releasing all resources used by it.
   *
   * Updates the original editor element with the data if the
   * {@link module:core/editor/editorconfig~EditorConfig#updateSourceElementOnDestroy `updateSourceElementOnDestroy`}
   * configuration option is set to `true`.
   */
  destroy() {
    const e = this.getData();
    return this.ui.destroy(), super.destroy().then(() => {
      this.sourceElement && this.updateSourceElement(e);
    });
  }
  /**
   * Creates a new inline editor instance.
   *
   * There are three general ways how the editor can be initialized.
   *
   * # Using an existing DOM element (and loading data from it)
   *
   * You can initialize the editor using an existing DOM element:
   *
   * ```ts
   * InlineEditor
   * 	.create( document.querySelector( '#editor' ) )
   * 	.then( editor => {
   * 		console.log( 'Editor was initialized', editor );
   * 	} )
   * 	.catch( err => {
   * 		console.error( err.stack );
   * 	} );
   * ```
   *
   * The element's content will be used as the editor data and the element will become the editable element.
   *
   * # Creating a detached editor
   *
   * Alternatively, you can initialize the editor by passing the initial data directly as a `String`.
   * In this case, the editor will render an element that must be inserted into the DOM for the editor to work properly:
   *
   * ```ts
   * InlineEditor
   * 	.create( '<p>Hello world!</p>' )
   * 	.then( editor => {
   * 		console.log( 'Editor was initialized', editor );
   *
   * 		// Initial data was provided so the editor UI element needs to be added manually to the DOM.
   * 		document.body.appendChild( editor.ui.element );
   * 	} )
   * 	.catch( err => {
   * 		console.error( err.stack );
   * 	} );
   * ```
   *
   * This lets you dynamically append the editor to your web page whenever it is convenient for you. You may use this method if your
   * web page content is generated on the client side and the DOM structure is not ready at the moment when you initialize the editor.
   *
   * # Using an existing DOM element (and data provided in `config.initialData`)
   *
   * You can also mix these two ways by providing a DOM element to be used and passing the initial data through the configuration:
   *
   * ```ts
   * InlineEditor
   * 	.create( document.querySelector( '#editor' ), {
   * 		initialData: '<h2>Initial data</h2><p>Foo bar.</p>'
   * 	} )
   * 	.then( editor => {
   * 		console.log( 'Editor was initialized', editor );
   * 	} )
   * 	.catch( err => {
   * 		console.error( err.stack );
   * 	} );
   * ```
   *
   * This method can be used to initialize the editor on an existing element with the specified content in case if your integration
   * makes it difficult to set the content of the source element.
   *
   * Note that an error will be thrown if you pass the initial data both as the first parameter and also in the configuration.
   *
   * # Configuring the editor
   *
   * See the {@link module:core/editor/editorconfig~EditorConfig editor configuration documentation} to learn more about
   * customizing plugins, toolbar and more.
   *
   * # Using the editor from source
   *
   * The code samples listed in the previous sections of this documentation assume that you are using an
   * {@glink installation/getting-started/predefined-builds editor build} (for example – `@ckeditor/ckeditor5-build-inline`).
   *
   * If you want to use the inline editor from source (`@ckeditor/ckeditor5-editor-inline/src/inlineeditor`),
   * you need to define the list of
   * {@link module:core/editor/editorconfig~EditorConfig#plugins plugins to be initialized} and
   * {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar items}. Read more about using the editor from
   * source in the {@glink installation/advanced/alternative-setups/integrating-from-source-webpack dedicated guide}.
   *
   * @param sourceElementOrData The DOM element that will be the source for the created editor
   * or the editor's initial data.
   *
   * If a DOM element is passed, its content will be automatically loaded to the editor upon initialization.
   * The editor data will be set back to the original element once the editor is destroyed only if the
   * {@link module:core/editor/editorconfig~EditorConfig#updateSourceElementOnDestroy updateSourceElementOnDestroy}
   * option is set to `true`.
   *
   * If the initial data is passed, a detached editor will be created. In this case you need to insert it into the DOM manually.
   * It is available under the {@link module:editor-inline/inlineeditorui~InlineEditorUI#element `editor.ui.element`} property.
   *
   * @param config The editor configuration.
   * @returns A promise resolved once the editor is ready. The promise resolves with the created editor instance.
   */
  static create(e, t = {}) {
    return new Promise((i) => {
      if (ln(e) && e.tagName === "TEXTAREA")
        throw new d("editor-wrong-element", null);
      const s = new this(e, t);
      i(s.initPlugins().then(() => s.ui.init()).then(() => s.data.init(s.config.get("initialData"))).then(() => s.fire("ready")).then(() => s));
    });
  }
}
Qr.Context = Su;
Qr.EditorWatchdog = Ch;
Qr.ContextWatchdog = w2;
function uE(n) {
  return ln(n) ? k_(n) : n;
}
function ln(n) {
  return di(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class eo extends Dt {
  constructor(e) {
    super(e), this.domEventType = [
      "paste",
      "copy",
      "cut",
      "drop",
      "dragover",
      "dragstart",
      "dragend",
      "dragenter",
      "dragleave"
    ];
    const t = this.document;
    this.listenTo(t, "paste", i("clipboardInput"), { priority: "low" }), this.listenTo(t, "drop", i("clipboardInput"), { priority: "low" }), this.listenTo(t, "dragover", i("dragging"), { priority: "low" });
    function i(s) {
      return (r, o) => {
        o.preventDefault();
        const a = o.dropRange ? [o.dropRange] : null, l = new Ze(t, s);
        t.fire(l, {
          dataTransfer: o.dataTransfer,
          method: r.name,
          targetRanges: a,
          target: o.target,
          domEvent: o.domEvent
        }), l.stop.called && o.stopPropagation();
      };
    }
  }
  onDomEvent(e) {
    const t = "clipboardData" in e ? e.clipboardData : e.dataTransfer, i = e.type == "drop" || e.type == "paste", s = {
      dataTransfer: new Uu(t, { cacheFiles: i })
    };
    (e.type == "drop" || e.type == "dragover") && (s.dropRange = hE(this.view, e)), this.fire(e.type, e, s);
  }
}
function hE(n, e) {
  const t = e.target.ownerDocument, i = e.clientX, s = e.clientY;
  let r;
  return t.caretRangeFromPoint && t.caretRangeFromPoint(i, s) ? r = t.caretRangeFromPoint(i, s) : e.rangeParent && (r = t.createRange(), r.setStart(e.rangeParent, e.rangeOffset), r.collapse(!0)), r ? n.domConverter.domRangeToView(r) : null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function dE(n) {
  return n = n.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\r?\n\r?\n/g, "</p><p>").replace(/\r?\n/g, "<br>").replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;").replace(/^\s/, "&nbsp;").replace(/\s$/, "&nbsp;").replace(/\s\s/g, " &nbsp;"), (n.includes("</p><p>") || n.includes("<br>")) && (n = `<p>${n}</p>`), n;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function fE(n) {
  return n.replace(/<span(?: class="Apple-converted-space"|)>(\s+)<\/span>/g, (e, t) => t.length == 1 ? " " : t).replace(/<!--[\s\S]*?-->/g, "");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const ml = ["figcaption", "li"];
function ed(n) {
  let e = "";
  if (n.is("$text") || n.is("$textProxy"))
    e = n.data;
  else if (n.is("element", "img") && n.hasAttribute("alt"))
    e = n.getAttribute("alt");
  else if (n.is("element", "br"))
    e = `
`;
  else {
    let t = null;
    for (const i of n.getChildren()) {
      const s = ed(i);
      t && (t.is("containerElement") || i.is("containerElement")) && (ml.includes(t.name) || ml.includes(i.name) ? e += `
` : e += `

`), e += s, t = i;
    }
  }
  return e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ut extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ClipboardPipeline";
  }
  /**
   * @inheritDoc
   */
  init() {
    this.editor.editing.view.addObserver(eo), this._setupPasteDrop(), this._setupCopyCut();
  }
  /**
   * The clipboard paste pipeline.
   */
  _setupPasteDrop() {
    const e = this.editor, t = e.model, i = e.editing.view, s = i.document;
    this.listenTo(s, "clipboardInput", (r, o) => {
      o.method == "paste" && !e.model.canEditAt(e.model.document.selection) && r.stop();
    }, { priority: "highest" }), this.listenTo(s, "clipboardInput", (r, o) => {
      const a = o.dataTransfer;
      let l;
      if (o.content)
        l = o.content;
      else {
        let u = "";
        a.getData("text/html") ? u = fE(a.getData("text/html")) : a.getData("text/plain") && (u = dE(a.getData("text/plain"))), l = this.editor.data.htmlProcessor.toView(u);
      }
      const c = new Ze(this, "inputTransformation");
      this.fire(c, {
        content: l,
        dataTransfer: a,
        targetRanges: o.targetRanges,
        method: o.method
      }), c.stop.called && r.stop(), i.scrollToTheSelection();
    }, { priority: "low" }), this.listenTo(this, "inputTransformation", (r, o) => {
      if (o.content.isEmpty)
        return;
      const l = this.editor.data.toModel(o.content, "$clipboardHolder");
      l.childCount != 0 && (r.stop(), t.change(() => {
        this.fire("contentInsertion", {
          content: l,
          method: o.method,
          dataTransfer: o.dataTransfer,
          targetRanges: o.targetRanges
        });
      }));
    }, { priority: "low" }), this.listenTo(this, "contentInsertion", (r, o) => {
      o.resultRange = t.insertContent(o.content);
    }, { priority: "low" });
  }
  /**
   * The clipboard copy/cut pipeline.
   */
  _setupCopyCut() {
    const e = this.editor, t = e.model.document, s = e.editing.view.document, r = (o, a) => {
      const l = a.dataTransfer;
      a.preventDefault();
      const c = e.data.toView(e.model.getSelectedContent(t.selection));
      s.fire("clipboardOutput", {
        dataTransfer: l,
        content: c,
        method: o.name
      });
    };
    this.listenTo(s, "copy", r, { priority: "low" }), this.listenTo(s, "cut", (o, a) => {
      e.model.canEditAt(e.model.document.selection) ? r(o, a) : a.preventDefault();
    }, { priority: "low" }), this.listenTo(s, "clipboardOutput", (o, a) => {
      a.content.isEmpty || (a.dataTransfer.setData("text/html", this.editor.data.htmlProcessor.toData(a.content)), a.dataTransfer.setData("text/plain", ed(a.content))), a.method == "cut" && e.model.deleteContent(t.selection);
    }, { priority: "low" });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class td {
  /**
   * Creates a new instance of the change buffer.
   *
   * @param limit The maximum number of atomic changes which can be contained in one batch.
   */
  constructor(e, t = 20) {
    this._batch = null, this.model = e, this._size = 0, this.limit = t, this._isLocked = !1, this._changeCallback = (i, s) => {
      s.isLocal && s.isUndoable && s !== this._batch && this._reset(!0);
    }, this._selectionChangeCallback = () => {
      this._reset();
    }, this.model.document.on("change", this._changeCallback), this.model.document.selection.on("change:range", this._selectionChangeCallback), this.model.document.selection.on("change:attribute", this._selectionChangeCallback);
  }
  /**
   * The current batch to which a feature should add its operations. Once the {@link #size}
   * is reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.
   */
  get batch() {
    return this._batch || (this._batch = this.model.createBatch({ isTyping: !0 })), this._batch;
  }
  /**
   * The number of atomic changes in the buffer. Once it exceeds the {@link #limit},
   * the {@link #batch batch} is set to a new one.
   */
  get size() {
    return this._size;
  }
  /**
   * The input number of changes into the buffer. Once the {@link #size} is
   * reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.
   *
   * @param changeCount The number of atomic changes to input.
   */
  input(e) {
    this._size += e, this._size >= this.limit && this._reset(!0);
  }
  /**
   * Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.
   */
  get isLocked() {
    return this._isLocked;
  }
  /**
   * Locks the buffer.
   */
  lock() {
    this._isLocked = !0;
  }
  /**
   * Unlocks the buffer.
   */
  unlock() {
    this._isLocked = !1;
  }
  /**
   * Destroys the buffer.
   */
  destroy() {
    this.model.document.off("change", this._changeCallback), this.model.document.selection.off("change:range", this._selectionChangeCallback), this.model.document.selection.off("change:attribute", this._selectionChangeCallback);
  }
  /**
   * Resets the change buffer.
   *
   * @param ignoreLock Whether internal lock {@link #isLocked} should be ignored.
   */
  _reset(e = !1) {
    (!this.isLocked || e) && (this._batch = null, this._size = 0);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class mE extends te {
  /**
   * Creates an instance of the command.
   *
   * @param undoStepSize The maximum number of atomic changes
   * which can be contained in one batch in the command buffer.
   */
  constructor(e, t) {
    super(e), this._buffer = new td(e.model, t), this._isEnabledBasedOnSelection = !1;
  }
  /**
   * The current change buffer.
   */
  get buffer() {
    return this._buffer;
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._buffer.destroy();
  }
  /**
   * Executes the input command. It replaces the content within the given range with the given text.
   * Replacing is a two step process, first the content within the range is removed and then the new text is inserted
   * at the beginning of the range (which after the removal is a collapsed range).
   *
   * @fires execute
   * @param options The command options.
   */
  execute(e = {}) {
    const t = this.editor.model, i = t.document, s = e.text || "", r = s.length;
    let o = i.selection;
    if (e.selection ? o = e.selection : e.range && (o = t.createSelection(e.range)), !t.canEditAt(o))
      return;
    const a = e.resultRange;
    t.enqueueChange(this._buffer.batch, (l) => {
      this._buffer.lock(), t.deleteContent(o), s && t.insertContent(l.createText(s, i.selection.getAttributes()), o), a ? l.setSelection(a) : o.is("documentSelection") || l.setSelection(o), this._buffer.unlock(), this._buffer.input(r);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const gl = [
  // For collapsed range:
  //	- This one is a regular typing (all browsers, all systems).
  //	- This one is used by Chrome when typing accented letter – 2nd step when the user selects the accent (Mac).
  // For non-collapsed range:
  //	- This one is used by Chrome when typing accented letter – when the selection box first appears (Mac).
  //	- This one is used by Safari when accepting spell check suggestions from the context menu (Mac).
  "insertText",
  // This one is used by Safari when typing accented letter (Mac).
  // This one is used by Safari when accepting spell check suggestions from the autocorrection pop-up (Mac).
  "insertReplacementText"
];
class gE extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), S.isAndroid && gl.push("insertCompositionText");
    const t = e.document;
    t.on("beforeinput", (i, s) => {
      if (!this.isEnabled)
        return;
      const { data: r, targetRanges: o, inputType: a, domEvent: l } = s;
      if (!gl.includes(a))
        return;
      const c = new Ze(t, "insertText");
      t.fire(c, new si(e, l, {
        text: r,
        selection: e.createSelection(o)
      })), c.stop.called && i.stop();
    }), t.on("compositionend", (i, { data: s, domEvent: r }) => {
      !this.isEnabled || S.isAndroid || s && t.fire("insertText", new si(e, r, {
        text: s,
        selection: t.selection
      }));
    }, { priority: "lowest" });
  }
  /**
   * @inheritDoc
   */
  observe() {
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class id extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Input";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model, i = e.editing.view, s = t.document.selection;
    i.addObserver(gE);
    const r = new mE(e, e.config.get("typing.undoStep") || 20);
    e.commands.add("insertText", r), e.commands.add("input", r), this.listenTo(i.document, "insertText", (o, a) => {
      i.document.isComposing || a.preventDefault();
      const { text: l, selection: c, resultRange: u } = a, h = Array.from(c.getRanges()).map((p) => e.editing.mapper.toModelRange(p));
      let f = l;
      if (S.isAndroid) {
        const p = Array.from(h[0].getItems()).reduce((b, E) => b + (E.is("$textProxy") ? E.data : ""), "");
        p && (p.length <= f.length ? f.startsWith(p) && (f = f.substring(p.length), h[0].start = h[0].start.getShiftedBy(p.length)) : p.startsWith(f) && (h[0].start = h[0].start.getShiftedBy(f.length), f = ""));
      }
      const m = {
        text: f,
        selection: t.createSelection(h)
      };
      u && (m.resultRange = e.editing.mapper.toModelRange(u)), e.execute("insertText", m);
    }), S.isAndroid ? this.listenTo(i.document, "keydown", (o, a) => {
      s.isCollapsed || a.keyCode != 229 || !i.document.isComposing || pl(t, r);
    }) : this.listenTo(i.document, "compositionstart", () => {
      s.isCollapsed || pl(t, r);
    });
  }
}
function pl(n, e) {
  if (!e.isEnabled)
    return;
  const t = e.buffer;
  t.lock(), n.enqueueChange(t.batch, () => {
    n.deleteContent(n.document.selection);
  }), t.unlock();
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class wl extends te {
  /**
   * Creates an instance of the command.
   *
   * @param direction The directionality of the delete describing in what direction it
   * should consume the content when the selection is collapsed.
   */
  constructor(e, t) {
    super(e), this.direction = t, this._buffer = new td(e.model, e.config.get("typing.undoStep")), this._isEnabledBasedOnSelection = !1;
  }
  /**
   * The current change buffer.
   */
  get buffer() {
    return this._buffer;
  }
  /**
   * Executes the delete command. Depending on whether the selection is collapsed or not, deletes its content
   * or a piece of content in the {@link #direction defined direction}.
   *
   * @fires execute
   * @param options The command options.
   * @param options.unit See {@link module:engine/model/utils/modifyselection~modifySelection}'s options.
   * @param options.sequence A number describing which subsequent delete event it is without the key being released.
   * See the {@link module:engine/view/document~Document#event:delete} event data.
   * @param options.selection Selection to remove. If not set, current model selection will be used.
   */
  execute(e = {}) {
    const t = this.editor.model, i = t.document;
    t.enqueueChange(this._buffer.batch, (s) => {
      this._buffer.lock();
      const r = s.createSelection(e.selection || i.selection);
      if (!t.canEditAt(r))
        return;
      const o = e.sequence || 1, a = r.isCollapsed;
      if (r.isCollapsed && t.modifySelection(r, {
        direction: this.direction,
        unit: e.unit,
        treatEmojiAsSingleUnit: !0
      }), this._shouldEntireContentBeReplacedWithParagraph(o)) {
        this._replaceEntireContentWithParagraph(s);
        return;
      }
      if (this._shouldReplaceFirstBlockWithParagraph(r, o)) {
        this.editor.execute("paragraph", { selection: r });
        return;
      }
      if (r.isCollapsed)
        return;
      let l = 0;
      r.getFirstRange().getMinimalFlatRanges().forEach((c) => {
        l += $s(c.getWalker({ singleCharacters: !0, ignoreElementEnd: !0, shallow: !0 }));
      }), t.deleteContent(r, {
        doNotResetEntireContent: a,
        direction: this.direction
      }), this._buffer.input(l), s.setSelection(r), this._buffer.unlock();
    });
  }
  /**
   * If the user keeps <kbd>Backspace</kbd> or <kbd>Delete</kbd> key pressed, the content of the current
   * editable will be cleared. However, this will not yet lead to resetting the remaining block to a paragraph
   * (which happens e.g. when the user does <kbd>Ctrl</kbd> + <kbd>A</kbd>, <kbd>Backspace</kbd>).
   *
   * But, if the user pressed the key in an empty editable for the first time,
   * we want to replace the entire content with a paragraph if:
   *
   * * the current limit element is empty,
   * * the paragraph is allowed in the limit element,
   * * the limit doesn't already have a paragraph inside.
   *
   * See https://github.com/ckeditor/ckeditor5-typing/issues/61.
   *
   * @param sequence A number describing which subsequent delete event it is without the key being released.
   */
  _shouldEntireContentBeReplacedWithParagraph(e) {
    if (e > 1)
      return !1;
    const t = this.editor.model, s = t.document.selection, r = t.schema.getLimitElement(s);
    if (!(s.isCollapsed && s.containsEntireContent(r)) || !t.schema.checkChild(r, "paragraph"))
      return !1;
    const a = r.getChild(0);
    return !(a && a.is("element", "paragraph"));
  }
  /**
   * The entire content is replaced with the paragraph. Selection is moved inside the paragraph.
   *
   * @param writer The model writer.
   */
  _replaceEntireContentWithParagraph(e) {
    const t = this.editor.model, s = t.document.selection, r = t.schema.getLimitElement(s), o = e.createElement("paragraph");
    e.remove(e.createRangeIn(r)), e.insert(o, r), e.setSelection(o, 0);
  }
  /**
   * Checks if the selection is inside an empty element that is the first child of the limit element
   * and should be replaced with a paragraph.
   *
   * @param selection The selection.
   * @param sequence A number describing which subsequent delete event it is without the key being released.
   */
  _shouldReplaceFirstBlockWithParagraph(e, t) {
    const i = this.editor.model;
    if (t > 1 || this.direction != "backward" || !e.isCollapsed)
      return !1;
    const s = e.getFirstPosition(), r = i.schema.getLimitElement(s), o = r.getChild(0);
    return !(s.parent != o || !e.containsEntireContent(o) || !i.schema.checkChild(r, "paragraph") || o.name == "paragraph");
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const pE = "character", bl = "word", wE = "codePoint", ot = "selection", Jt = "backward", vi = "forward", nd = {
  // --------------------------------------- Backward delete types -----------------------------------------------------
  // This happens in Safari on Mac when some content is selected and Ctrl + K is pressed.
  deleteContent: {
    unit: ot,
    // According to the Input Events Level 2 spec, this delete type has no direction
    // but to keep things simple, let's default to backward.
    direction: Jt
  },
  // Chrome and Safari on Mac: Backspace or Ctrl + H
  deleteContentBackward: {
    // This kind of deletions must be done on the code point-level instead of target range provided by the DOM beforeinput event.
    // Take for instance "👨‍👩‍👧‍👧", it equals:
    //
    //	* [ "👨", "ZERO WIDTH JOINER", "👩", "ZERO WIDTH JOINER", "👧", "ZERO WIDTH JOINER", "👧" ]
    //	* or simply "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F467}"
    //
    // The range provided by the browser would cause the entire multi-byte grapheme to disappear while the user
    // intention when deleting backwards ("👨‍👩‍👧‍👧[]", then backspace) is gradual "decomposition" (first to "👨‍👩‍👧‍[]",
    // then to "👨‍👩‍[]", etc.).
    //
    //	* "👨‍👩‍👧‍👧[]" + backward delete (by code point)  -> results in "👨‍👩‍👧[]", removed the last "👧" 👍
    //	* "👨‍👩‍👧‍👧[]" + backward delete (by character)  -> results in "[]", removed the whole grapheme 👎
    //
    // Deleting by code-point is simply a better UX. See "deleteContentForward" to learn more.
    unit: wE,
    direction: Jt
  },
  // On Mac: Option + Backspace.
  // On iOS: Hold the backspace for a while and the whole words will start to disappear.
  deleteWordBackward: {
    unit: bl,
    direction: Jt
  },
  // Safari on Mac: Cmd + Backspace
  deleteHardLineBackward: {
    unit: ot,
    direction: Jt
  },
  // Chrome on Mac: Cmd + Backspace.
  deleteSoftLineBackward: {
    unit: ot,
    direction: Jt
  },
  // --------------------------------------- Forward delete types -----------------------------------------------------
  // Chrome on Mac: Fn + Backspace or Ctrl + D
  // Safari on Mac: Ctrl + K or Ctrl + D
  deleteContentForward: {
    // Unlike backward delete, this delete must be performed by character instead of by code point, which
    // provides the best UX for working with accented letters.
    // Take, for example "b̂" ("\u0062\u0302", or [ "LATIN SMALL LETTER B", "COMBINING CIRCUMFLEX ACCENT" ]):
    //
    //	* "b̂[]" + backward delete (by code point)  -> results in "b[]", removed the combining mark 👍
    //	* "[]b̂" + forward delete (by code point)   -> results in "[]^", a bare combining mark does that not make sense when alone 👎
    //	* "[]b̂" + forward delete (by character)    -> results in "[]", removed both "b" and the combining mark 👍
    //
    // See: "deleteContentBackward" to learn more.
    unit: pE,
    direction: vi
  },
  // On Mac: Fn + Option + Backspace.
  deleteWordForward: {
    unit: bl,
    direction: vi
  },
  // Chrome on Mac: Ctrl + K (you have to disable the Link plugin first, though, because it uses the same keystroke)
  // This is weird that it does not work in Safari on Mac despite being listed in the official shortcuts listing
  // on Apple's webpage.
  deleteHardLineForward: {
    unit: ot,
    direction: vi
  },
  // At this moment there is no known way to trigger this event type but let's keep it for the symmetry with
  // deleteSoftLineBackward.
  deleteSoftLineForward: {
    unit: ot,
    direction: vi
  }
};
class bE extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = e.document;
    let i = 0;
    t.on("keydown", () => {
      i++;
    }), t.on("keyup", () => {
      i = 0;
    }), t.on("beforeinput", (s, r) => {
      if (!this.isEnabled)
        return;
      const { targetRanges: o, domEvent: a, inputType: l } = r, c = nd[l];
      if (!c)
        return;
      const u = {
        direction: c.direction,
        unit: c.unit,
        sequence: i
      };
      u.unit == ot && (u.selectionToRemove = e.createSelection(o[0])), l === "deleteContentBackward" && (S.isAndroid && (u.sequence = 1), vE(o) && (u.unit = ot, u.selectionToRemove = e.createSelection(o)));
      const h = new fi(t, "delete", o[0]);
      t.fire(h, new si(e, a, u)), h.stop.called && s.stop();
    }), S.isBlink && _E(this);
  }
  /**
   * @inheritDoc
   */
  observe() {
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
}
function _E(n) {
  const e = n.view, t = e.document;
  let i = null, s = !1;
  t.on("keydown", (a, { keyCode: l }) => {
    i = l, s = !1;
  }), t.on("keyup", (a, { keyCode: l, domEvent: c }) => {
    const u = t.selection, h = n.isEnabled && l == i && r(l) && !u.isCollapsed && !s;
    if (i = null, h) {
      const f = u.getFirstRange(), m = new fi(t, "delete", f), p = {
        unit: ot,
        direction: o(l),
        selectionToRemove: u
      };
      t.fire(m, new si(e, c, p));
    }
  }), t.on("beforeinput", (a, { inputType: l }) => {
    const c = nd[l];
    r(i) && c && c.direction == o(i) && (s = !0);
  }, { priority: "high" }), t.on("beforeinput", (a, { inputType: l, data: c }) => {
    i == R.delete && l == "insertText" && c == "" && a.stop();
  }, { priority: "high" });
  function r(a) {
    return a == R.backspace || a == R.delete;
  }
  function o(a) {
    return a == R.backspace ? Jt : vi;
  }
}
function vE(n) {
  if (n.length != 1 || n[0].isCollapsed)
    return !1;
  const e = n[0].getWalker({
    direction: "backward",
    singleCharacters: !0,
    ignoreElementEnd: !0
  });
  let t = 0;
  for (const { nextPosition: i } of e) {
    if (!i.parent.is("$text"))
      t++;
    else {
      const s = i.parent.data, r = i.offset;
      if (Or(s, r) || Mr(s, r) || Pu(s, r))
        continue;
      t++;
    }
    if (t > 1)
      return !0;
  }
  return !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ai extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Delete";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.editing.view, i = t.document, s = e.model.document;
    t.addObserver(bE), this._undoOnBackspace = !1;
    const r = new wl(e, "forward");
    e.commands.add("deleteForward", r), e.commands.add("forwardDelete", r), e.commands.add("delete", new wl(e, "backward")), this.listenTo(i, "delete", (o, a) => {
      i.isComposing || a.preventDefault();
      const { direction: l, sequence: c, selectionToRemove: u, unit: h } = a, f = l === "forward" ? "deleteForward" : "delete", m = { sequence: c };
      if (h == "selection") {
        const p = Array.from(u.getRanges()).map((b) => e.editing.mapper.toModelRange(b));
        m.selection = e.model.createSelection(p);
      } else
        m.unit = h;
      e.execute(f, m), t.scrollToTheSelection();
    }, { priority: "low" }), this.editor.plugins.has("UndoEditing") && (this.listenTo(i, "delete", (o, a) => {
      this._undoOnBackspace && a.direction == "backward" && a.sequence == 1 && a.unit == "codePoint" && (this._undoOnBackspace = !1, e.execute("undo"), a.preventDefault(), o.stop());
    }, { context: "$capture" }), this.listenTo(s, "change", () => {
      this._undoOnBackspace = !1;
    }));
  }
  /**
   * If the next user action after calling this method is pressing backspace, it would undo the last change.
   *
   * Requires {@link module:undo/undoediting~UndoEditing} plugin. If not loaded, does nothing.
   */
  requestUndoOnBackspace() {
    this.editor.plugins.has("UndoEditing") && (this._undoOnBackspace = !0);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class yE extends _ {
  static get requires() {
    return [id, ai];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Typing";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function sd(n, e) {
  let t = n.start;
  return { text: Array.from(n.getWalker({ ignoreElementEnd: !1 })).reduce((s, { item: r }) => r.is("$text") || r.is("$textProxy") ? s + r.data : (t = e.createPositionAfter(r), ""), ""), range: e.createRange(t, n.end) };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class kE extends z() {
  /**
   * Creates a text watcher instance.
   *
   * @param testCallback See {@link module:typing/textwatcher~TextWatcher#testCallback}.
   */
  constructor(e, t) {
    super(), this.model = e, this.testCallback = t, this._hasMatch = !1, this.set("isEnabled", !0), this.on("change:isEnabled", () => {
      this.isEnabled ? this._startListening() : (this.stopListening(e.document.selection), this.stopListening(e.document));
    }), this._startListening();
  }
  /**
   * Flag indicating whether there is a match currently.
   */
  get hasMatch() {
    return this._hasMatch;
  }
  /**
   * Starts listening to the editor for typing and selection events.
   */
  _startListening() {
    const t = this.model.document;
    this.listenTo(t.selection, "change:range", (i, { directChange: s }) => {
      if (s) {
        if (!t.selection.isCollapsed) {
          this.hasMatch && (this.fire("unmatched"), this._hasMatch = !1);
          return;
        }
        this._evaluateTextBeforeSelection("selection");
      }
    }), this.listenTo(t, "change:data", (i, s) => {
      s.isUndo || !s.isLocal || this._evaluateTextBeforeSelection("data", { batch: s });
    });
  }
  /**
   * Checks the editor content for matched text.
   *
   * @fires matched:data
   * @fires matched:selection
   * @fires unmatched
   *
   * @param suffix A suffix used for generating the event name.
   * @param data Data object for event.
   */
  _evaluateTextBeforeSelection(e, t = {}) {
    const i = this.model, r = i.document.selection, o = i.createRange(i.createPositionAt(r.focus.parent, 0), r.focus), { text: a, range: l } = sd(o, i), c = this.testCallback(a);
    if (!c && this.hasMatch && this.fire("unmatched"), this._hasMatch = !!c, c) {
      const u = Object.assign(t, { text: a, range: l });
      typeof c == "object" && Object.assign(u, c), this.fire(`matched:${e}`, u);
    }
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class _l extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "TwoStepCaretMovement";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.attributes = /* @__PURE__ */ new Set(), this._overrideUid = null;
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model, i = e.editing.view, s = e.locale, r = t.document.selection;
    this.listenTo(i.document, "arrowKey", (o, a) => {
      if (!r.isCollapsed || a.shiftKey || a.altKey || a.ctrlKey)
        return;
      const l = a.keyCode == R.arrowright, c = a.keyCode == R.arrowleft;
      if (!l && !c)
        return;
      const u = s.contentLanguageDirection;
      let h = !1;
      u === "ltr" && l || u === "rtl" && c ? h = this._handleForwardMovement(a) : h = this._handleBackwardMovement(a), h === !0 && o.stop();
    }, { context: "$text", priority: "highest" }), this._isNextGravityRestorationSkipped = !1, this.listenTo(r, "change:range", (o, a) => {
      if (this._isNextGravityRestorationSkipped) {
        this._isNextGravityRestorationSkipped = !1;
        return;
      }
      this._isGravityOverridden && (!a.directChange && cn(r.getFirstPosition(), this.attributes) || this._restoreGravity());
    });
  }
  /**
   * Registers a given attribute for the two-step caret movement.
   *
   * @param attribute Name of the attribute to handle.
   */
  registerAttribute(e) {
    this.attributes.add(e);
  }
  /**
   * Updates the document selection and the view according to the two–step caret movement state
   * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
   *
   * @param data Data of the key press.
   * @returns `true` when the handler prevented caret movement.
   */
  _handleForwardMovement(e) {
    const t = this.attributes, s = this.editor.model.document.selection, r = s.getFirstPosition();
    return this._isGravityOverridden || r.isAtStart && fs(s, t) ? !1 : cn(r, t) ? (nn(e), this._overrideGravity(), !0) : !1;
  }
  /**
   * Updates the document selection and the view according to the two–step caret movement state
   * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.
   *
   * @param data Data of the key press.
   * @returns `true` when the handler prevented caret movement
   */
  _handleBackwardMovement(e) {
    const t = this.attributes, i = this.editor.model, s = i.document.selection, r = s.getFirstPosition();
    return this._isGravityOverridden ? (nn(e), this._restoreGravity(), ms(i, t, r), !0) : r.isAtStart ? fs(s, t) ? (nn(e), ms(i, t, r), !0) : !1 : CE(r, t) ? r.isAtEnd && !fs(s, t) && cn(r, t) ? (nn(e), ms(i, t, r), !0) : (this._isNextGravityRestorationSkipped = !0, this._overrideGravity(), !1) : !1;
  }
  /**
   * `true` when the gravity is overridden for the plugin.
   */
  get _isGravityOverridden() {
    return !!this._overrideUid;
  }
  /**
   * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}
   * and stores the information about this fact in the {@link #_overrideUid}.
   *
   * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.
   */
  _overrideGravity() {
    this._overrideUid = this.editor.model.change((e) => e.overrideSelectionGravity());
  }
  /**
   * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.
   *
   * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.
   */
  _restoreGravity() {
    this.editor.model.change((e) => {
      e.restoreSelectionGravity(this._overrideUid), this._overrideUid = null;
    });
  }
}
function fs(n, e) {
  for (const t of e)
    if (n.hasAttribute(t))
      return !0;
  return !1;
}
function ms(n, e, t) {
  const i = t.nodeBefore;
  n.change((s) => {
    i ? s.setSelectionAttribute(i.getAttributes()) : s.removeSelectionAttribute(e);
  });
}
function nn(n) {
  n.preventDefault();
}
function CE(n, e) {
  const t = n.getShiftedBy(-1);
  return cn(t, e);
}
function cn(n, e) {
  const { nodeBefore: t, nodeAfter: i } = n;
  for (const s of e) {
    const r = t ? t.getAttribute(s) : void 0;
    if ((i ? i.getAttribute(s) : void 0) !== r)
      return !0;
  }
  return !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function li(n, e, t, i) {
  return i.createRange(vl(n, e, t, !0, i), vl(n, e, t, !1, i));
}
function vl(n, e, t, i, s) {
  let r = n.textNode || (i ? n.nodeBefore : n.nodeAfter), o = null;
  for (; r && r.getAttribute(e) == t; )
    o = r, r = i ? r.previousSibling : r.nextSibling;
  return o ? s.createPositionAt(o, i ? "before" : "after") : n;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function EE(n, e, t, i) {
  const s = n.editing.view, r = /* @__PURE__ */ new Set();
  s.document.registerPostFixer((o) => {
    const a = n.model.document.selection;
    let l = !1;
    if (a.hasAttribute(e)) {
      const c = li(a.getFirstPosition(), e, a.getAttribute(e), n.model), u = n.editing.mapper.toViewRange(c);
      for (const h of u.getItems())
        h.is("element", t) && !h.hasClass(i) && (o.addClass(i, h), r.add(h), l = !0);
    }
    return l;
  }), n.conversion.for("editingDowncast").add((o) => {
    o.on("insert", a, { priority: "highest" }), o.on("remove", a, { priority: "highest" }), o.on("attribute", a, { priority: "highest" }), o.on("selection", a, { priority: "highest" });
    function a() {
      s.change((l) => {
        for (const c of r.values())
          l.removeClass(i, c), r.delete(c);
      });
    }
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function* rd(n, e) {
  for (const t of e)
    t && n.getAttributeProperties(t[0]).copyOnEnter && (yield t);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class AE extends te {
  /**
   * @inheritDoc
   */
  execute() {
    this.editor.model.change((e) => {
      this.enterBlock(e), this.fire("afterExecute", { writer: e });
    });
  }
  /**
   * Splits a block where the document selection is placed, in the way how the <kbd>Enter</kbd> key is expected to work:
   *
   * ```
   * <p>Foo[]bar</p>   ->   <p>Foo</p><p>[]bar</p>
   * <p>Foobar[]</p>   ->   <p>Foobar</p><p>[]</p>
   * <p>Fo[ob]ar</p>   ->   <p>Fo</p><p>[]ar</p>
   * ```
   *
   * In some cases, the split will not happen:
   *
   * ```
   * // The selection parent is a limit element:
   * <figcaption>A[bc]d</figcaption>   ->   <figcaption>A[]d</figcaption>
   *
   * // The selection spans over multiple elements:
   * <h>x[x</h><p>y]y<p>   ->   <h>x</h><p>[]y</p>
   * ```
   *
   * @param writer Writer to use when performing the enter action.
   * @returns Boolean indicating if the block was split.
   */
  enterBlock(e) {
    const t = this.editor.model, i = t.document.selection, s = t.schema, r = i.isCollapsed, o = i.getFirstRange(), a = o.start.parent, l = o.end.parent;
    if (s.isLimit(a) || s.isLimit(l))
      return !r && a == l && t.deleteContent(i), !1;
    if (r) {
      const c = rd(e.model.schema, i.getAttributes());
      return yl(e, o.start), e.setSelectionAttribute(c), !0;
    } else {
      const c = !(o.start.isAtStart && o.end.isAtEnd), u = a == l;
      if (t.deleteContent(i, { leaveUnmerged: c }), c) {
        if (u)
          return yl(e, i.focus), !0;
        e.setSelection(l, 0);
      }
    }
    return !1;
  }
}
function yl(n, e) {
  n.split(e), n.setSelection(e.parent.nextSibling, 0);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const TE = {
  insertParagraph: { isSoft: !1 },
  insertLineBreak: { isSoft: !0 }
};
class od extends We {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.document;
    let i = !1;
    t.on("keydown", (s, r) => {
      i = r.shiftKey;
    }), t.on("beforeinput", (s, r) => {
      if (!this.isEnabled)
        return;
      let o = r.inputType;
      S.isSafari && i && o == "insertParagraph" && (o = "insertLineBreak");
      const a = r.domEvent, l = TE[o];
      if (!l)
        return;
      const c = new fi(t, "enter", r.targetRanges[0]);
      t.fire(c, new si(e, a, {
        isSoft: l.isSoft
      })), c.stop.called && s.stop();
    });
  }
  /**
   * @inheritDoc
   */
  observe() {
  }
  /**
   * @inheritDoc
   */
  stopObserving() {
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class to extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Enter";
  }
  init() {
    const e = this.editor, t = e.editing.view, i = t.document;
    t.addObserver(od), e.commands.add("enter", new AE(e)), this.listenTo(i, "enter", (s, r) => {
      i.isComposing || r.preventDefault(), !r.isSoft && (e.execute("enter"), t.scrollToTheSelection());
    }, { priority: "low" });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class PE extends te {
  /**
   * @inheritDoc
   */
  execute() {
    const e = this.editor.model, t = e.document;
    e.change((i) => {
      SE(e, i, t.selection), this.fire("afterExecute", { writer: i });
    });
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document;
    this.isEnabled = xE(e.schema, t.selection);
  }
}
function xE(n, e) {
  if (e.rangeCount > 1)
    return !1;
  const t = e.anchor;
  if (!t || !n.checkChild(t, "softBreak"))
    return !1;
  const i = e.getFirstRange(), s = i.start.parent, r = i.end.parent;
  return !((ar(s, n) || ar(r, n)) && s !== r);
}
function SE(n, e, t) {
  const i = t.isCollapsed, s = t.getFirstRange(), r = s.start.parent, o = s.end.parent, a = r == o;
  if (i) {
    const l = rd(n.schema, t.getAttributes());
    kl(n, e, s.end), e.removeSelectionAttribute(t.getAttributeKeys()), e.setSelectionAttribute(l);
  } else {
    const l = !(s.start.isAtStart && s.end.isAtEnd);
    n.deleteContent(t, { leaveUnmerged: l }), a ? kl(n, e, t.focus) : l && e.setSelection(o, 0);
  }
}
function kl(n, e, t) {
  const i = e.createElement("softBreak");
  n.insertContent(i, t), e.setSelection(i, "after");
}
function ar(n, e) {
  return n.is("rootElement") ? !1 : e.isLimit(n) || ar(n.parent, e);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class IE extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ShiftEnter";
  }
  init() {
    const e = this.editor, t = e.model.schema, i = e.conversion, s = e.editing.view, r = s.document;
    t.register("softBreak", {
      allowWhere: "$text",
      isInline: !0
    }), i.for("upcast").elementToElement({
      model: "softBreak",
      view: "br"
    }), i.for("downcast").elementToElement({
      model: "softBreak",
      view: (o, { writer: a }) => a.createEmptyElement("br")
    }), s.addObserver(od), e.commands.add("shiftEnter", new PE(e)), this.listenTo(r, "enter", (o, a) => {
      r.isComposing || a.preventDefault(), a.isSoft && (e.execute("shiftEnter"), s.scrollToTheSelection());
    }, { priority: "low" });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class RE extends N() {
  constructor() {
    super(...arguments), this._stack = [];
  }
  /**
   * Adds highlight descriptor to the stack.
   *
   * @fires change:top
   */
  add(e, t) {
    const i = this._stack, s = i[0];
    this._insertDescriptor(e);
    const r = i[0];
    s !== r && !gs(s, r) && this.fire("change:top", {
      oldDescriptor: s,
      newDescriptor: r,
      writer: t
    });
  }
  /**
   * Removes highlight descriptor from the stack.
   *
   * @fires change:top
   * @param id Id of the descriptor to remove.
   */
  remove(e, t) {
    const i = this._stack, s = i[0];
    this._removeDescriptor(e);
    const r = i[0];
    s !== r && !gs(s, r) && this.fire("change:top", {
      oldDescriptor: s,
      newDescriptor: r,
      writer: t
    });
  }
  /**
   * Inserts a given descriptor in correct place in the stack. It also takes care about updating information
   * when descriptor with same id is already present.
   */
  _insertDescriptor(e) {
    const t = this._stack, i = t.findIndex((r) => r.id === e.id);
    if (gs(e, t[i]))
      return;
    i > -1 && t.splice(i, 1);
    let s = 0;
    for (; t[s] && OE(t[s], e); )
      s++;
    t.splice(s, 0, e);
  }
  /**
   * Removes descriptor with given id from the stack.
   *
   * @param id Descriptor's id.
   */
  _removeDescriptor(e) {
    const t = this._stack, i = t.findIndex((s) => s.id === e);
    i > -1 && t.splice(i, 1);
  }
}
function gs(n, e) {
  return n && e && n.priority == e.priority && En(n.classes) == En(e.classes);
}
function OE(n, e) {
  return n.priority > e.priority ? !0 : n.priority < e.priority ? !1 : En(n.classes) > En(e.classes);
}
function En(n) {
  return Array.isArray(n) ? n.sort().join(",") : n;
}
const ME = '<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M4 0v1H1v3H0V.5A.5.5 0 0 1 .5 0H4zm8 0h3.5a.5.5 0 0 1 .5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 0 1-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 0 1-.5.5H12z"/><path fill-opacity=".256" d="M1 1h14v14H1z"/><g class="ck-icon__selected-indicator"><path d="M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z"/><path fill-opacity=".254" d="M1 1h14v14H1z"/></g></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const VE = "ck-widget", Cl = "ck-widget_selected";
function Y(n) {
  return n.is("element") ? !!n.getCustomProperty("widget") : !1;
}
function io(n, e, t = {}) {
  if (!n.is("containerElement"))
    throw new d("widget-to-widget-wrong-element-type", null, { element: n });
  return e.setAttribute("contenteditable", "false", n), e.addClass(VE, n), e.setCustomProperty("widget", !0, n), n.getFillerOffset = $E, e.setCustomProperty("widgetLabel", [], n), t.label && NE(n, t.label), t.hasSelectionHandle && zE(n, e), FE(n, e), n;
}
function DE(n, e, t) {
  if (e.classes && t.addClass(X(e.classes), n), e.attributes)
    for (const i in e.attributes)
      t.setAttribute(i, e.attributes[i], n);
}
function BE(n, e, t) {
  if (e.classes && t.removeClass(X(e.classes), n), e.attributes)
    for (const i in e.attributes)
      t.removeAttribute(i, n);
}
function FE(n, e, t = DE, i = BE) {
  const s = new RE();
  s.on("change:top", (a, l) => {
    l.oldDescriptor && i(n, l.oldDescriptor, l.writer), l.newDescriptor && t(n, l.newDescriptor, l.writer);
  });
  const r = (a, l, c) => s.add(l, c), o = (a, l, c) => s.remove(l, c);
  e.setCustomProperty("addHighlight", r, n), e.setCustomProperty("removeHighlight", o, n);
}
function NE(n, e) {
  n.getCustomProperty("widgetLabel").push(e);
}
function LE(n) {
  return n.getCustomProperty("widgetLabel").reduce((t, i) => typeof i == "function" ? t ? t + ". " + i() : i() : t ? t + ". " + i : i, "");
}
function ad(n, e) {
  const t = n.getSelectedElement();
  if (t) {
    const i = rt(n);
    if (i)
      return e.createRange(e.createPositionAt(t, i));
  }
  return vh(n, e);
}
function I5(n, e) {
  return (t, i) => {
    const { mapper: s, viewPosition: r } = i, o = s.findMappedViewAncestor(r);
    if (!e(o))
      return;
    const a = s.toModelElement(o);
    i.modelPosition = n.createPositionAt(a, r.isAtStart ? "before" : "after");
  };
}
function $E() {
  return null;
}
function zE(n, e) {
  const t = e.createUIElement("div", { class: "ck ck-widget__selection-handle" }, function(i) {
    const s = this.toDomElement(i), r = new mt();
    return r.set("content", ME), r.render(), s.appendChild(r.element), s;
  });
  e.insert(e.createPositionAt(n, 0), t), e.addClass(["ck-widget_with-selection-handle"], n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const qe = "widget-type-around";
function vt(n, e, t) {
  return !!n && Y(n) && !t.isInline(e);
}
function HE(n) {
  return n.closest(".ck-widget__type-around__button");
}
function WE(n) {
  return n.classList.contains("ck-widget__type-around__button_before") ? "before" : "after";
}
function UE(n, e) {
  const t = n.closest(".ck-widget");
  return e.mapDomToView(t);
}
function rt(n) {
  return n.getAttribute(qe);
}
const jE = '<svg viewBox="0 0 10 8" xmlns="http://www.w3.org/2000/svg"><path d="M9.055.263v3.972h-6.77M1 4.216l2-2.038m-2 2 2 2.038"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const ld = ["before", "after"], qE = new DOMParser().parseFromString(jE, "image/svg+xml").firstChild, El = "ck-widget__type-around_disabled";
class GE extends _ {
  constructor() {
    super(...arguments), this._currentFakeCaretModelElement = null;
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "WidgetTypeAround";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [to, ai];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.editing.view;
    this.on("change:isEnabled", (i, s, r) => {
      t.change((o) => {
        for (const a of t.document.roots)
          r ? o.removeClass(El, a) : o.addClass(El, a);
      }), r || e.model.change((o) => {
        o.removeSelectionAttribute(qe);
      });
    }), this._enableTypeAroundUIInjection(), this._enableInsertingParagraphsOnButtonClick(), this._enableInsertingParagraphsOnEnterKeypress(), this._enableInsertingParagraphsOnTypingKeystroke(), this._enableTypeAroundFakeCaretActivationUsingKeyboardArrows(), this._enableDeleteIntegration(), this._enableInsertContentIntegration(), this._enableInsertObjectIntegration(), this._enableDeleteContentIntegration();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._currentFakeCaretModelElement = null;
  }
  /**
   * Inserts a new paragraph next to a widget element with the selection anchored in it.
   *
   * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll
   * the viewport to the selection in the inserted paragraph.
   *
   * @param widgetModelElement The model widget element next to which a paragraph is inserted.
   * @param position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.
   */
  _insertParagraph(e, t) {
    const i = this.editor, s = i.editing.view, r = i.model.schema.getAttributesWithProperty(e, "copyOnReplace", !0);
    i.execute("insertParagraph", {
      position: i.model.createPositionAt(e, t),
      attributes: r
    }), s.focus(), s.scrollToTheSelection();
  }
  /**
   * A wrapper for the {@link module:utils/emittermixin~Emitter#listenTo} method that executes the callbacks only
   * when the plugin {@link #isEnabled is enabled}.
   *
   * @param emitter The object that fires the event.
   * @param event The name of the event.
   * @param callback The function to be called on event.
   * @param options Additional options.
   * @param options.priority The priority of this event callback. The higher the priority value the sooner
   * the callback will be fired. Events having the same priority are called in the order they were added.
   */
  _listenToIfEnabled(e, t, i, s) {
    this.listenTo(e, t, (...r) => {
      this.isEnabled && i(...r);
    }, s);
  }
  /**
   * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it
   * does not expect a position. Instead, it performs the insertion next to a selected widget
   * according to the `widget-type-around` model selection attribute value (fake caret position).
   *
   * Because this method requires the `widget-type-around` attribute to be set,
   * the insertion can only happen when the widget's fake caret is active (e.g. activated
   * using the keyboard).
   *
   * @returns Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.
   */
  _insertParagraphAccordingToFakeCaretPosition() {
    const i = this.editor.model.document.selection, s = rt(i);
    if (!s)
      return !1;
    const r = i.getSelectedElement();
    return this._insertParagraph(r, s), !0;
  }
  /**
   * Creates a listener in the editing conversion pipeline that injects the widget type around
   * UI into every single widget instance created in the editor.
   *
   * The UI is delivered as a {@link module:engine/view/uielement~UIElement}
   * wrapper which renders DOM buttons that users can use to insert paragraphs.
   */
  _enableTypeAroundUIInjection() {
    const e = this.editor, t = e.model.schema, i = e.locale.t, s = {
      before: i("Insert paragraph before block"),
      after: i("Insert paragraph after block")
    };
    e.editing.downcastDispatcher.on("insert", (r, o, a) => {
      const l = a.mapper.toViewElement(o.item);
      l && vt(l, o.item, t) && (KE(a.writer, s, l), l.getCustomProperty("widgetLabel").push(() => this.isEnabled ? i("Press Enter to type after or press Shift + Enter to type before the widget") : ""));
    }, { priority: "low" });
  }
  /**
   * Brings support for the fake caret that appears when either:
   *
   * * the selection moves to a widget from a position next to it using arrow keys,
   * * the arrow key is pressed when the widget is already selected.
   *
   * The fake caret lets the user know that they can start typing or just press
   * <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.
   *
   * The fake caret disappears when the user changes the selection or the editor
   * gets blurred.
   *
   * The whole idea is as follows:
   *
   * 1. A user does one of the 2 scenarios described at the beginning.
   * 2. The "keydown" listener is executed and the decision is made whether to show or hide the fake caret.
   * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating
   *    on which side of the widget it should appear.
   * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the
   *    fake caret on the view widget.
   * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher
   *    does the CSS class clean-up in the view.
   * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection
   *    attribute (the former also removes widget CSS classes).
   */
  _enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {
    const e = this.editor, t = e.model, i = t.document.selection, s = t.schema, r = e.editing.view;
    this._listenToIfEnabled(r.document, "arrowKey", (a, l) => {
      this._handleArrowKeyPress(a, l);
    }, { context: [Y, "$text"], priority: "high" }), this._listenToIfEnabled(i, "change:range", (a, l) => {
      l.directChange && e.model.change((c) => {
        c.removeSelectionAttribute(qe);
      });
    }), this._listenToIfEnabled(t.document, "change:data", () => {
      const a = i.getSelectedElement();
      if (a) {
        const l = e.editing.mapper.toViewElement(a);
        if (vt(l, a, s))
          return;
      }
      e.model.change((l) => {
        l.removeSelectionAttribute(qe);
      });
    }), this._listenToIfEnabled(e.editing.downcastDispatcher, "selection", (a, l, c) => {
      const u = c.writer;
      if (this._currentFakeCaretModelElement) {
        const p = c.mapper.toViewElement(this._currentFakeCaretModelElement);
        p && (u.removeClass(ld.map(o), p), this._currentFakeCaretModelElement = null);
      }
      const h = l.selection.getSelectedElement();
      if (!h)
        return;
      const f = c.mapper.toViewElement(h);
      if (!vt(f, h, s))
        return;
      const m = rt(l.selection);
      m && (u.addClass(o(m), f), this._currentFakeCaretModelElement = h);
    }), this._listenToIfEnabled(e.ui.focusTracker, "change:isFocused", (a, l, c) => {
      c || e.model.change((u) => {
        u.removeSelectionAttribute(qe);
      });
    });
    function o(a) {
      return `ck-widget_type-around_show-fake-caret_${a}`;
    }
  }
  /**
   * A listener executed on each "keydown" in the view document, a part of
   * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.
   *
   * It decides whether the arrow keypress should activate the fake caret or not (also whether it should
   * be deactivated).
   *
   * The fake caret activation is done by setting the `widget-type-around` model selection attribute
   * in this listener, and stopping and preventing the event that would normally be handled by the widget
   * plugin that is responsible for the regular keyboard navigation near/across all widgets (that
   * includes inline widgets, which are ignored by the widget type around plugin).
   */
  _handleArrowKeyPress(e, t) {
    const i = this.editor, s = i.model, r = s.document.selection, o = s.schema, a = i.editing.view, l = t.keyCode, c = F_(l, i.locale.contentLanguageDirection), u = a.document.selection.getSelectedElement(), h = i.editing.mapper.toModelElement(u);
    let f;
    vt(u, h, o) ? f = this._handleArrowKeyPressOnSelectedWidget(c) : r.isCollapsed ? f = this._handleArrowKeyPressWhenSelectionNextToAWidget(c) : t.shiftKey || (f = this._handleArrowKeyPressWhenNonCollapsedSelection(c)), f && (t.preventDefault(), e.stop());
  }
  /**
   * Handles the keyboard navigation on "keydown" when a widget is currently selected and activates or deactivates
   * the fake caret for that widget, depending on the current value of the `widget-type-around` model
   * selection attribute and the direction of the pressed arrow key.
   *
   * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
   * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
   * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
   * process the event any further. Returns `false` otherwise.
   */
  _handleArrowKeyPressOnSelectedWidget(e) {
    const i = this.editor.model, s = i.document.selection, r = rt(s);
    return i.change((o) => {
      if (r) {
        if (!(r === (e ? "after" : "before")))
          return o.removeSelectionAttribute(qe), !0;
      } else
        return o.setSelectionAttribute(qe, e ? "after" : "before"), !0;
      return !1;
    });
  }
  /**
   * Handles the keyboard navigation on "keydown" when **no** widget is selected but the selection is **directly** next
   * to one and upon the fake caret should become active for this widget upon arrow keypress
   * (AKA entering/selecting the widget).
   *
   * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.
   * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the
   * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.
   *
   * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
   * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
   * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
   * process the event any further. Returns `false` otherwise.
   */
  _handleArrowKeyPressWhenSelectionNextToAWidget(e) {
    const t = this.editor, i = t.model, s = i.schema, r = t.plugins.get("Widget"), o = r._getObjectElementNextToSelection(e), a = t.editing.mapper.toViewElement(o);
    return vt(a, o, s) ? (i.change((l) => {
      r._setSelectionOverElement(o), l.setSelectionAttribute(qe, e ? "before" : "after");
    }), !0) : !1;
  }
  /**
   * Handles the keyboard navigation on "keydown" when a widget is currently selected (together with some other content)
   * and the widget is the first or last element in the selection. It activates or deactivates the fake caret for that widget.
   *
   * @param isForward `true` when the pressed arrow key was responsible for the forward model selection movement
   * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.
   * @returns Returns `true` when the keypress was handled and no other keydown listener of the editor should
   * process the event any further. Returns `false` otherwise.
   */
  _handleArrowKeyPressWhenNonCollapsedSelection(e) {
    const t = this.editor, i = t.model, s = i.schema, r = t.editing.mapper, o = i.document.selection, a = e ? o.getLastPosition().nodeBefore : o.getFirstPosition().nodeAfter, l = r.toViewElement(a);
    return vt(l, a, s) ? (i.change((c) => {
      c.setSelection(a, "on"), c.setSelectionAttribute(qe, e ? "after" : "before");
    }), !0) : !1;
  }
  /**
   * Registers a `mousedown` listener for the view document which intercepts events
   * coming from the widget type around UI, which happens when a user clicks one of the buttons
   * that insert a paragraph next to a widget.
   */
  _enableInsertingParagraphsOnButtonClick() {
    const e = this.editor, t = e.editing.view;
    this._listenToIfEnabled(t.document, "mousedown", (i, s) => {
      const r = HE(s.domTarget);
      if (!r)
        return;
      const o = WE(r), a = UE(r, t.domConverter), l = e.editing.mapper.toModelElement(a);
      this._insertParagraph(l, o), s.preventDefault(), i.stop();
    });
  }
  /**
   * Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph
   * near the widget when either:
   *
   * * The fake caret was first activated using the arrow keys,
   * * The entire widget is selected in the model.
   *
   * In the first case, the new paragraph is inserted according to the `widget-type-around` selection
   * attribute (see {@link #_handleArrowKeyPress}).
   *
   * In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke
   * was pressed or not.
   */
  _enableInsertingParagraphsOnEnterKeypress() {
    const e = this.editor, t = e.model.document.selection, i = e.editing.view;
    this._listenToIfEnabled(i.document, "enter", (s, r) => {
      if (s.eventPhase != "atTarget")
        return;
      const o = t.getSelectedElement(), a = e.editing.mapper.toViewElement(o), l = e.model.schema;
      let c;
      this._insertParagraphAccordingToFakeCaretPosition() ? c = !0 : vt(a, o, l) && (this._insertParagraph(o, r.isSoft ? "before" : "after"), c = !0), c && (r.preventDefault(), s.stop());
    }, { context: Y });
  }
  /**
   * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user
   * to insert a paragraph next to a widget when the fake caret was activated using arrow
   * keys but it responds to typing instead of <kbd>Enter</kbd>.
   *
   * Listener enabled by this method will insert a new paragraph according to the `widget-type-around`
   * model selection attribute as the user simply starts typing, which creates the impression that the fake caret
   * behaves like a real one rendered by the browser (AKA your text appears where the caret was).
   *
   * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command
   * and another one for actual typing. It is not a disaster but this may need to be fixed
   * sooner or later.
   */
  _enableInsertingParagraphsOnTypingKeystroke() {
    const t = this.editor.editing.view.document;
    this._listenToIfEnabled(t, "insertText", (i, s) => {
      this._insertParagraphAccordingToFakeCaretPosition() && (s.selection = t.selection);
    }, { priority: "high" }), S.isAndroid ? this._listenToIfEnabled(t, "keydown", (i, s) => {
      s.keyCode == 229 && this._insertParagraphAccordingToFakeCaretPosition();
    }) : this._listenToIfEnabled(t, "compositionstart", () => {
      this._insertParagraphAccordingToFakeCaretPosition();
    }, { priority: "high" });
  }
  /**
   * It creates a "delete" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>
   * is pressed and the fake caret is currently active.
   *
   * The fake caret should create an illusion of a real browser caret so that when it appears before or after
   * a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content
   * before or after a widget (depending on the content surrounding the widget).
   */
  _enableDeleteIntegration() {
    const e = this.editor, t = e.editing.view, i = e.model, s = i.schema;
    this._listenToIfEnabled(t.document, "delete", (r, o) => {
      if (r.eventPhase != "atTarget")
        return;
      const a = rt(i.document.selection);
      if (!a)
        return;
      const l = o.direction, c = i.document.selection.getSelectedElement(), u = a === "before", h = l == "forward";
      if (u === h)
        e.execute("delete", {
          selection: i.createSelection(c, "on")
        });
      else {
        const m = s.getNearestSelectionRange(i.createPositionAt(c, a), l);
        if (m)
          if (!m.isCollapsed)
            i.change((p) => {
              p.setSelection(m), e.execute(h ? "deleteForward" : "delete");
            });
          else {
            const p = i.createSelection(m.start);
            if (i.modifySelection(p, { direction: l }), !p.focus.isEqual(m.start))
              i.change((b) => {
                b.setSelection(m), e.execute(h ? "deleteForward" : "delete");
              });
            else {
              const b = YE(s, m.start.parent);
              i.deleteContent(i.createSelection(b, "on"), {
                doNotAutoparagraph: !0
              });
            }
          }
      }
      o.preventDefault(), r.stop();
    }, { context: Y });
  }
  /**
   * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste
   * content near a widget when the fake caret is first activated using the arrow keys.
   *
   * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
   */
  _enableInsertContentIntegration() {
    const e = this.editor, t = this.editor.model, i = t.document.selection;
    this._listenToIfEnabled(e.model, "insertContent", (s, [r, o]) => {
      if (o && !o.is("documentSelection"))
        return;
      const a = rt(i);
      if (a)
        return s.stop(), t.change((l) => {
          const c = i.getSelectedElement(), u = t.createPositionAt(c, a), h = l.createSelection(u), f = t.insertContent(r, h);
          return l.setSelection(h), f;
        });
    }, { priority: "high" });
  }
  /**
   * Attaches the {@link module:engine/model/model~Model#event:insertObject} event listener that modifies the
   * `options.findOptimalPosition`parameter to position of fake caret in relation to selected element
   * to reflect user's intent of desired insertion position.
   *
   * The object is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).
   */
  _enableInsertObjectIntegration() {
    const e = this.editor, i = this.editor.model.document.selection;
    this._listenToIfEnabled(e.model, "insertObject", (s, r) => {
      const [, o, a = {}] = r;
      if (o && !o.is("documentSelection"))
        return;
      const l = rt(i);
      l && (a.findOptimalPosition = l, r[3] = a);
    }, { priority: "high" });
  }
  /**
   * Attaches the {@link module:engine/model/model~Model#event:deleteContent} event listener to block the event when the fake
   * caret is active.
   *
   * This is required for cases that trigger {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}
   * before calling {@link module:engine/model/model~Model#insertContent `model.insertContent()`} like, for instance,
   * plain text pasting.
   */
  _enableDeleteContentIntegration() {
    const e = this.editor, i = this.editor.model.document.selection;
    this._listenToIfEnabled(e.model, "deleteContent", (s, [r]) => {
      if (r && !r.is("documentSelection"))
        return;
      rt(i) && s.stop();
    }, { priority: "high" });
  }
}
function KE(n, e, t) {
  const i = n.createUIElement("div", {
    class: "ck ck-reset_all ck-widget__type-around"
  }, function(s) {
    const r = this.toDomElement(s);
    return JE(r, e), ZE(r), r;
  });
  n.insert(n.createPositionAt(t, "end"), i);
}
function JE(n, e) {
  for (const t of ld) {
    const i = new Ce({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-widget__type-around__button",
          `ck-widget__type-around__button_${t}`
        ],
        title: e[t],
        "aria-hidden": "true"
      },
      children: [
        n.ownerDocument.importNode(qE, !0)
      ]
    });
    n.appendChild(i.render());
  }
}
function ZE(n) {
  const e = new Ce({
    tag: "div",
    attributes: {
      class: [
        "ck",
        "ck-widget__type-around__fake-caret"
      ]
    }
  });
  n.appendChild(e.render());
}
function YE(n, e) {
  let t = e;
  for (const i of e.getAncestors({ parentFirst: !0 })) {
    if (i.childCount > 1 || n.isLimit(i))
      break;
    t = i;
  }
  return t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function XE(n) {
  const e = n.model;
  return (t, i) => {
    const s = i.keyCode == R.arrowup, r = i.keyCode == R.arrowdown, o = i.shiftKey, a = e.document.selection;
    if (!s && !r)
      return;
    const l = r;
    if (o && tA(a, l))
      return;
    const c = QE(n, a, l);
    if (c) {
      if (c.isCollapsed) {
        if (a.isCollapsed)
          return;
        if (o)
          return;
      }
      (c.isCollapsed || eA(n, c, l)) && (e.change((u) => {
        const h = l ? c.end : c.start;
        if (o) {
          const f = e.createSelection(a.anchor);
          f.setFocus(h), u.setSelection(f);
        } else
          u.setSelection(h);
      }), t.stop(), i.preventDefault(), i.stopPropagation());
    }
  };
}
function QE(n, e, t) {
  const i = n.model;
  if (t) {
    const s = e.isCollapsed ? e.focus : e.getLastPosition(), r = Al(i, s, "forward");
    if (!r)
      return null;
    const o = i.createRange(s, r), a = Tl(i.schema, o, "backward");
    return a ? i.createRange(s, a) : null;
  } else {
    const s = e.isCollapsed ? e.focus : e.getFirstPosition(), r = Al(i, s, "backward");
    if (!r)
      return null;
    const o = i.createRange(r, s), a = Tl(i.schema, o, "forward");
    return a ? i.createRange(a, s) : null;
  }
}
function Al(n, e, t) {
  const i = n.schema, s = n.createRangeIn(e.root), r = t == "forward" ? "elementStart" : "elementEnd";
  for (const { previousPosition: o, item: a, type: l } of s.getWalker({ startPosition: e, direction: t })) {
    if (i.isLimit(a) && !i.isInline(a))
      return o;
    if (l == r && i.isBlock(a))
      return null;
  }
  return null;
}
function Tl(n, e, t) {
  const i = t == "backward" ? e.end : e.start;
  if (n.checkChild(i, "$text"))
    return i;
  for (const { nextPosition: s } of e.getWalker({ direction: t }))
    if (n.checkChild(s, "$text"))
      return s;
  return null;
}
function eA(n, e, t) {
  const i = n.model, s = n.view.domConverter;
  if (t) {
    const c = i.createSelection(e.start);
    i.modifySelection(c), !c.focus.isAtEnd && !e.start.isEqual(c.focus) && (e = i.createRange(c.focus, e.end));
  }
  const r = n.mapper.toViewRange(e), o = s.viewRangeToDom(r), a = V.getDomRangeRects(o);
  let l;
  for (const c of a) {
    if (l === void 0) {
      l = Math.round(c.bottom);
      continue;
    }
    if (Math.round(c.top) >= l)
      return !1;
    l = Math.max(l, Math.round(c.bottom));
  }
  return !0;
}
function tA(n, e) {
  return !n.isCollapsed && n.isBackward == e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Wi extends _ {
  constructor() {
    super(...arguments), this._previouslySelected = /* @__PURE__ */ new Set();
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Widget";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [GE, ai];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.editing.view, i = t.document;
    this.editor.editing.downcastDispatcher.on("selection", (s, r, o) => {
      const a = o.writer, l = r.selection;
      if (l.isCollapsed)
        return;
      const c = l.getSelectedElement();
      if (!c)
        return;
      const u = e.editing.mapper.toViewElement(c);
      Y(u) && o.consumable.consume(l, "selection") && a.setSelection(a.createRangeOn(u), {
        fake: !0,
        label: LE(u)
      });
    }), this.editor.editing.downcastDispatcher.on("selection", (s, r, o) => {
      this._clearPreviouslySelectedWidgets(o.writer);
      const a = o.writer, l = a.document.selection;
      let c = null;
      for (const u of l.getRanges())
        for (const h of u) {
          const f = h.item;
          Y(f) && !nA(f, c) && (a.addClass(Cl, f), this._previouslySelected.add(f), c = f);
        }
    }, { priority: "low" }), t.addObserver(Ln), this.listenTo(i, "mousedown", (...s) => this._onMousedown(...s)), this.listenTo(i, "arrowKey", (...s) => {
      this._handleSelectionChangeOnArrowKeyPress(...s);
    }, { context: [Y, "$text"] }), this.listenTo(i, "arrowKey", (...s) => {
      this._preventDefaultOnArrowKeyPress(...s);
    }, { context: "$root" }), this.listenTo(i, "arrowKey", XE(this.editor.editing), { context: "$text" }), this.listenTo(i, "delete", (s, r) => {
      this._handleDelete(r.direction == "forward") && (r.preventDefault(), s.stop());
    }, { context: "$root" });
  }
  /**
   * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.
   */
  _onMousedown(e, t) {
    const i = this.editor, s = i.editing.view, r = s.document;
    let o = t.target;
    if (iA(o)) {
      if ((S.isSafari || S.isGecko) && t.domEvent.detail >= 3) {
        const l = i.editing.mapper, c = o.is("attributeElement") ? o.findAncestor((h) => !h.is("attributeElement")) : o, u = l.toModelElement(c);
        t.preventDefault(), this.editor.model.change((h) => {
          h.setSelection(u, "in");
        });
      }
      return;
    }
    if (!Y(o) && (o = o.findAncestor(Y), !o))
      return;
    S.isAndroid && t.preventDefault(), r.isFocused || s.focus();
    const a = i.editing.mapper.toModelElement(o);
    this._setSelectionOverElement(a);
  }
  /**
   * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes
   * the model selection when:
   *
   * * arrow key is pressed when the widget is selected,
   * * the selection is next to a widget and the widget should become selected upon the arrow key press.
   *
   * See {@link #_preventDefaultOnArrowKeyPress}.
   */
  _handleSelectionChangeOnArrowKeyPress(e, t) {
    const i = t.keyCode, s = this.editor.model, r = s.schema, o = s.document.selection, a = o.getSelectedElement(), l = Tu(i, this.editor.locale.contentLanguageDirection), c = l == "down" || l == "right", u = l == "up" || l == "down";
    if (a && r.isObject(a)) {
      const f = c ? o.getLastPosition() : o.getFirstPosition(), m = r.getNearestSelectionRange(f, c ? "forward" : "backward");
      m && (s.change((p) => {
        p.setSelection(m);
      }), t.preventDefault(), e.stop());
      return;
    }
    if (!o.isCollapsed && !t.shiftKey) {
      const f = o.getFirstPosition(), m = o.getLastPosition(), p = f.nodeAfter, b = m.nodeBefore;
      (p && r.isObject(p) || b && r.isObject(b)) && (s.change((E) => {
        E.setSelection(c ? m : f);
      }), t.preventDefault(), e.stop());
      return;
    }
    if (!o.isCollapsed)
      return;
    const h = this._getObjectElementNextToSelection(c);
    if (h && r.isObject(h)) {
      if (r.isInline(h) && u)
        return;
      this._setSelectionOverElement(h), t.preventDefault(), e.stop();
    }
  }
  /**
   * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents
   * the default browser behavior to make sure the fake selection is not being moved from a fake selection
   * container.
   *
   * See {@link #_handleSelectionChangeOnArrowKeyPress}.
   */
  _preventDefaultOnArrowKeyPress(e, t) {
    const i = this.editor.model, s = i.schema, r = i.document.selection.getSelectedElement();
    r && s.isObject(r) && (t.preventDefault(), e.stop());
  }
  /**
   * Handles delete keys: backspace and delete.
   *
   * @param isForward Set to true if delete was performed in forward direction.
   * @returns Returns `true` if keys were handled correctly.
   */
  _handleDelete(e) {
    const i = this.editor.model.document.selection;
    if (!this.editor.model.canEditAt(i) || !i.isCollapsed)
      return;
    const s = this._getObjectElementNextToSelection(e);
    if (s)
      return this.editor.model.change((r) => {
        let o = i.anchor.parent;
        for (; o.isEmpty; ) {
          const a = o;
          o = a.parent, r.remove(a);
        }
        this._setSelectionOverElement(s);
      }), !0;
  }
  /**
   * Sets {@link module:engine/model/selection~Selection document's selection} over given element.
   *
   * @internal
   */
  _setSelectionOverElement(e) {
    this.editor.model.change((t) => {
      t.setSelection(t.createRangeOn(e));
    });
  }
  /**
   * Checks if {@link module:engine/model/element~Element element} placed next to the current
   * {@link module:engine/model/selection~Selection model selection} exists and is marked in
   * {@link module:engine/model/schema~Schema schema} as `object`.
   *
   * @internal
   * @param forward Direction of checking.
   */
  _getObjectElementNextToSelection(e) {
    const t = this.editor.model, i = t.schema, s = t.document.selection, r = t.createSelection(s);
    if (t.modifySelection(r, { direction: e ? "forward" : "backward" }), r.isEqual(s))
      return null;
    const o = e ? r.focus.nodeBefore : r.focus.nodeAfter;
    return o && i.isObject(o) ? o : null;
  }
  /**
   * Removes CSS class from previously selected widgets.
   */
  _clearPreviouslySelectedWidgets(e) {
    for (const t of this._previouslySelected)
      e.removeClass(Cl, t);
    this._previouslySelected.clear();
  }
}
function iA(n) {
  let e = n;
  for (; e; ) {
    if (e.is("editableElement") && !e.is("rootElement"))
      return !0;
    if (Y(e))
      return !1;
    e = e.parent;
  }
  return !1;
}
function nA(n, e) {
  return e ? Array.from(n.getAncestors()).includes(e) : !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Pl extends _ {
  constructor() {
    super(...arguments), this._toolbarDefinitions = /* @__PURE__ */ new Map();
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Cn];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "WidgetToolbarRepository";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (e.plugins.has("BalloonToolbar")) {
      const t = e.plugins.get("BalloonToolbar");
      this.listenTo(t, "show", (i) => {
        sA(e.editing.view.document.selection) && i.stop();
      }, { priority: "high" });
    }
    this._balloon = this.editor.plugins.get("ContextualBalloon"), this.on("change:isEnabled", () => {
      this._updateToolbarsVisibility();
    }), this.listenTo(e.ui, "update", () => {
      this._updateToolbarsVisibility();
    }), this.listenTo(e.ui.focusTracker, "change:isFocused", () => {
      this._updateToolbarsVisibility();
    }, { priority: "low" });
  }
  destroy() {
    super.destroy();
    for (const e of this._toolbarDefinitions.values())
      e.view.destroy();
  }
  /**
   * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked
   * `getRelatedElement` function. Toolbar items are gathered from `items` array.
   * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.
   *
   * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}
   * callback (or later) to make sure that the given toolbar items were already registered by other plugins.
   *
   * @param toolbarId An id for the toolbar. Used to
   * @param options.ariaLabel Label used by assistive technologies to describe this toolbar element.
   * @param options.items Array of toolbar items.
   * @param options.getRelatedElement Callback which returns an element the toolbar should be attached to.
   * @param options.balloonClassName CSS class for the widget balloon.
   */
  register(e, { ariaLabel: t, items: i, getRelatedElement: s, balloonClassName: r = "ck-toolbar-container" }) {
    if (!i.length) {
      q("widget-toolbar-no-items", { toolbarId: e });
      return;
    }
    const o = this.editor, a = o.t, l = new Zr(o.locale);
    if (l.ariaLabel = t || a("Widget toolbar"), this._toolbarDefinitions.has(e))
      throw new d("widget-toolbar-duplicated", this, { toolbarId: e });
    const c = {
      view: l,
      getRelatedElement: s,
      balloonClassName: r,
      itemsConfig: i,
      initialized: !1
    };
    o.ui.addToolbar(l, {
      isContextual: !0,
      beforeFocus: () => {
        const u = s(o.editing.view.document.selection);
        u && this._showToolbar(c, u);
      },
      afterBlur: () => {
        this._hideToolbar(c);
      }
    }), this._toolbarDefinitions.set(e, c);
  }
  /**
   * Iterates over stored toolbars and makes them visible or hidden.
   */
  _updateToolbarsVisibility() {
    let e = 0, t = null, i = null;
    for (const s of this._toolbarDefinitions.values()) {
      const r = s.getRelatedElement(this.editor.editing.view.document.selection);
      if (!this.isEnabled || !r)
        this._isToolbarInBalloon(s) && this._hideToolbar(s);
      else if (!this.editor.ui.focusTracker.isFocused)
        this._isToolbarVisible(s) && this._hideToolbar(s);
      else {
        const o = r.getAncestors().length;
        o > e && (e = o, t = r, i = s);
      }
    }
    i && this._showToolbar(i, t);
  }
  /**
   * Hides the given toolbar.
   */
  _hideToolbar(e) {
    this._balloon.remove(e.view), this.stopListening(this._balloon, "change:visibleView");
  }
  /**
   * Shows up the toolbar if the toolbar is not visible.
   * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.
   *
   * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view
   * should be still visible after the {@link module:ui/editorui/editorui~EditorUI#event:update}.
   */
  _showToolbar(e, t) {
    this._isToolbarVisible(e) ? xl(this.editor, t) : this._isToolbarInBalloon(e) || (e.initialized || (e.initialized = !0, e.view.fillFromConfig(e.itemsConfig, this.editor.ui.componentFactory)), this._balloon.add({
      view: e.view,
      position: cd(this.editor, t),
      balloonClassName: e.balloonClassName
    }), this.listenTo(this._balloon, "change:visibleView", () => {
      for (const i of this._toolbarDefinitions.values())
        if (this._isToolbarVisible(i)) {
          const s = i.getRelatedElement(this.editor.editing.view.document.selection);
          xl(this.editor, s);
        }
    }));
  }
  _isToolbarVisible(e) {
    return this._balloon.visibleView === e.view;
  }
  _isToolbarInBalloon(e) {
    return this._balloon.hasView(e.view);
  }
}
function xl(n, e) {
  const t = n.plugins.get("ContextualBalloon"), i = cd(n, e);
  t.updatePosition(i);
}
function cd(n, e) {
  const t = n.editing.view, i = ae.defaultPositions;
  return {
    target: t.domConverter.mapViewToDom(e),
    positions: [
      i.northArrowSouth,
      i.northArrowSouthWest,
      i.northArrowSouthEast,
      i.southArrowNorth,
      i.southArrowNorthWest,
      i.southArrowNorthEast,
      i.viewportStickyNorth
    ]
  };
}
function sA(n) {
  const e = n.getSelectedElement();
  return !!(e && Y(e));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class rA extends z() {
  /**
   * @param options Resizer options.
   */
  constructor(e) {
    super(), this.set("activeHandlePosition", null), this.set("proposedWidthPercents", null), this.set("proposedWidth", null), this.set("proposedHeight", null), this.set("proposedHandleHostWidth", null), this.set("proposedHandleHostHeight", null), this._options = e, this._referenceCoordinates = null;
  }
  /**
   * The original width (pixels) of the resized object when the resize process was started.
   */
  get originalWidth() {
    return this._originalWidth;
  }
  /**
   * The original height (pixels) of the resized object when the resize process was started.
   */
  get originalHeight() {
    return this._originalHeight;
  }
  /**
   * The original width (percents) of the resized object when the resize process was started.
   */
  get originalWidthPercents() {
    return this._originalWidthPercents;
  }
  /**
   * A width to height ratio of the resized image.
   */
  get aspectRatio() {
    return this._aspectRatio;
  }
  /**
   *
   * @param domResizeHandle The handle used to calculate the reference point.
   */
  begin(e, t, i) {
    const s = new V(t);
    this.activeHandlePosition = cA(e), this._referenceCoordinates = aA(t, uA(this.activeHandlePosition)), this._originalWidth = s.width, this._originalHeight = s.height, this._aspectRatio = s.width / s.height;
    const r = i.style.width;
    r && r.match(/^\d+(\.\d*)?%$/) ? this._originalWidthPercents = parseFloat(r) : this._originalWidthPercents = oA(i, s);
  }
  update(e) {
    this.proposedWidth = e.width, this.proposedHeight = e.height, this.proposedWidthPercents = e.widthPercents, this.proposedHandleHostWidth = e.handleHostWidth, this.proposedHandleHostHeight = e.handleHostHeight;
  }
}
function oA(n, e) {
  const t = n.parentElement;
  let i = parseFloat(t.ownerDocument.defaultView.getComputedStyle(t).width);
  const s = 5;
  let r = 0, o = t;
  for (; isNaN(i); ) {
    if (o = o.parentElement, ++r > s)
      return 0;
    i = parseFloat(t.ownerDocument.defaultView.getComputedStyle(o).width);
  }
  return e.width / i * 100;
}
function aA(n, e) {
  const t = new V(n), i = e.split("-"), s = {
    x: i[1] == "right" ? t.right : t.left,
    y: i[0] == "bottom" ? t.bottom : t.top
  };
  return s.x += n.ownerDocument.defaultView.scrollX, s.y += n.ownerDocument.defaultView.scrollY, s;
}
function lA(n) {
  return `ck-widget__resizer__handle-${n}`;
}
function cA(n) {
  const e = ["top-left", "top-right", "bottom-right", "bottom-left"];
  for (const t of e)
    if (n.classList.contains(lA(t)))
      return t;
}
function uA(n) {
  const e = n.split("-"), t = {
    top: "bottom",
    bottom: "top",
    left: "right",
    right: "left"
  };
  return `${t[e[0]]}-${t[e[1]]}`;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class hA extends T {
  constructor() {
    super();
    const e = this.bindTemplate;
    this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-size-view",
          e.to("_viewPosition", (t) => t ? `ck-orientation-${t}` : "")
        ],
        style: {
          display: e.if("_isVisible", "none", (t) => !t)
        }
      },
      children: [{
        text: e.to("_label")
      }]
    });
  }
  /**
   * A method used for binding the `SizeView` instance properties to the `ResizeState` instance observable properties.
   *
   * @internal
   * @param options An object defining the resizer options, used for setting the proper size label.
   * @param resizeState The `ResizeState` class instance, used for keeping the `SizeView` state up to date.
   */
  _bindToState(e, t) {
    this.bind("_isVisible").to(t, "proposedWidth", t, "proposedHeight", (i, s) => i !== null && s !== null), this.bind("_label").to(t, "proposedHandleHostWidth", t, "proposedHandleHostHeight", t, "proposedWidthPercents", (i, s, r) => e.unit === "px" ? `${i}×${s}` : `${r}%`), this.bind("_viewPosition").to(
      t,
      "activeHandlePosition",
      t,
      "proposedHandleHostWidth",
      t,
      "proposedHandleHostHeight",
      // If the widget is too small to contain the size label, display the label above.
      (i, s, r) => s < 50 || r < 50 ? "above-center" : i
    );
  }
  /**
   * A method used for cleaning up. It removes the bindings and hides the view.
   *
   * @internal
   */
  _dismiss() {
    this.unbind(), this._isVisible = !1;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Sl extends z() {
  /**
   * @param options Resizer options.
   */
  constructor(e) {
    super(), this._viewResizerWrapper = null, this._options = e, this.set("isEnabled", !0), this.set("isSelected", !1), this.bind("isVisible").to(this, "isEnabled", this, "isSelected", (t, i) => t && i), this.decorate("begin"), this.decorate("cancel"), this.decorate("commit"), this.decorate("updateSize"), this.on("commit", (t) => {
      !this.state.proposedWidth && !this.state.proposedWidthPercents && (this._cleanup(), t.stop());
    }, { priority: "high" });
  }
  /**
   * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.
   *
   * Note that a new state is created for each resize transaction.
   */
  get state() {
    return this._state;
  }
  /**
   * Makes resizer visible in the UI.
   */
  show() {
    this._options.editor.editing.view.change((t) => {
      t.removeClass("ck-hidden", this._viewResizerWrapper);
    });
  }
  /**
   * Hides resizer in the UI.
   */
  hide() {
    this._options.editor.editing.view.change((t) => {
      t.addClass("ck-hidden", this._viewResizerWrapper);
    });
  }
  /**
   * Attaches the resizer to the DOM.
   */
  attach() {
    const e = this, t = this._options.viewElement;
    this._options.editor.editing.view.change((s) => {
      const r = s.createUIElement("div", {
        class: "ck ck-reset_all ck-widget__resizer"
      }, function(o) {
        const a = this.toDomElement(o);
        return e._appendHandles(a), e._appendSizeUI(a), a;
      });
      s.insert(s.createPositionAt(t, "end"), r), s.addClass("ck-widget_with-resizer", t), this._viewResizerWrapper = r, this.isVisible || this.hide();
    }), this.on("change:isVisible", () => {
      this.isVisible ? (this.show(), this.redraw()) : this.hide();
    });
  }
  /**
   * Starts the resizing process.
   *
   * Creates a new {@link #state} for the current process.
   *
   * @fires begin
   * @param domResizeHandle Clicked handle.
   */
  begin(e) {
    this._state = new rA(this._options), this._sizeView._bindToState(this._options, this.state), this._initialViewWidth = this._options.viewElement.getStyle("width"), this.state.begin(e, this._getHandleHost(), this._getResizeHost());
  }
  /**
   * Updates the proposed size based on `domEventData`.
   *
   * @fires updateSize
   */
  updateSize(e) {
    const t = this._proposeNewSize(e);
    this._options.editor.editing.view.change((c) => {
      const u = this._options.unit || "%", h = (u === "%" ? t.widthPercents : t.width) + u;
      c.setStyle("width", h, this._options.viewElement);
    });
    const s = this._getHandleHost(), r = new V(s), o = Math.round(r.width), a = Math.round(r.height), l = new V(s);
    t.width = Math.round(l.width), t.height = Math.round(l.height), this.redraw(r), this.state.update({
      ...t,
      handleHostWidth: o,
      handleHostHeight: a
    });
  }
  /**
   * Applies the geometry proposed with the resizer.
   *
   * @fires commit
   */
  commit() {
    const e = this._options.unit || "%", t = (e === "%" ? this.state.proposedWidthPercents : this.state.proposedWidth) + e;
    this._options.editor.editing.view.change(() => {
      this._cleanup(), this._options.onCommit(t);
    });
  }
  /**
   * Cancels and rejects the proposed resize dimensions, hiding the UI.
   *
   * @fires cancel
   */
  cancel() {
    this._cleanup();
  }
  /**
   * Destroys the resizer.
   */
  destroy() {
    this.cancel();
  }
  /**
   * Redraws the resizer.
   *
   * @param handleHostRect Handle host rectangle might be given to improve performance.
   */
  redraw(e) {
    const t = this._domResizerWrapper;
    if (!mA(t))
      return;
    const i = t.parentElement, s = this._getHandleHost(), r = this._viewResizerWrapper, o = [
      r.getStyle("width"),
      r.getStyle("height"),
      r.getStyle("left"),
      r.getStyle("top")
    ];
    let a;
    if (i.isSameNode(s)) {
      const l = e || new V(s);
      a = [
        l.width + "px",
        l.height + "px",
        void 0,
        void 0
      ];
    } else
      a = [
        s.offsetWidth + "px",
        s.offsetHeight + "px",
        s.offsetLeft + "px",
        s.offsetTop + "px"
      ];
    ce(o, a) !== "same" && this._options.editor.editing.view.change((l) => {
      l.setStyle({
        width: a[0],
        height: a[1],
        left: a[2],
        top: a[3]
      }, r);
    });
  }
  containsHandle(e) {
    return this._domResizerWrapper.contains(e);
  }
  static isResizeHandle(e) {
    return e.classList.contains("ck-widget__resizer__handle");
  }
  /**
   * Cleans up the context state.
   */
  _cleanup() {
    this._sizeView._dismiss(), this._options.editor.editing.view.change((t) => {
      t.setStyle("width", this._initialViewWidth, this._options.viewElement);
    });
  }
  /**
   * Calculates the proposed size as the resize handles are dragged.
   *
   * @param domEventData Event data that caused the size update request. It should be used to calculate the proposed size.
   */
  _proposeNewSize(e) {
    const t = this.state, i = fA(e), s = this._options.isCentered ? this._options.isCentered(this) : !0, r = {
      x: t._referenceCoordinates.x - (i.x + t.originalWidth),
      y: i.y - t.originalHeight - t._referenceCoordinates.y
    };
    s && t.activeHandlePosition.endsWith("-right") && (r.x = i.x - (t._referenceCoordinates.x + t.originalWidth)), s && (r.x *= 2);
    let o = Math.abs(t.originalWidth + r.x), a = Math.abs(t.originalHeight + r.y);
    return (o / t.aspectRatio > a ? "width" : "height") == "width" ? a = o / t.aspectRatio : o = a * t.aspectRatio, {
      width: Math.round(o),
      height: Math.round(a),
      widthPercents: Math.min(Math.round(t.originalWidthPercents / t.originalWidth * o * 100) / 100, 100)
    };
  }
  /**
   * Obtains the resize host.
   *
   * Resize host is an object that receives dimensions which are the result of resizing.
   */
  _getResizeHost() {
    const e = this._domResizerWrapper.parentElement;
    return this._options.getResizeHost(e);
  }
  /**
   * Obtains the handle host.
   *
   * Handle host is an object that the handles are aligned to.
   *
   * Handle host will not always be an entire widget itself. Take an image as an example. The image widget
   * contains an image and a caption. Only the image should be surrounded with handles.
   */
  _getHandleHost() {
    const e = this._domResizerWrapper.parentElement;
    return this._options.getHandleHost(e);
  }
  /**
   * DOM container of the entire resize UI.
   *
   * Note that this property will have a value only after the element bound with the resizer is rendered
   * (otherwise `null`).
   */
  get _domResizerWrapper() {
    return this._options.editor.editing.view.domConverter.mapViewToDom(this._viewResizerWrapper);
  }
  /**
   * Renders the resize handles in the DOM.
   *
   * @param domElement The resizer wrapper.
   */
  _appendHandles(e) {
    const t = ["top-left", "top-right", "bottom-right", "bottom-left"];
    for (const i of t)
      e.appendChild(new Ce({
        tag: "div",
        attributes: {
          class: `ck-widget__resizer__handle ${dA(i)}`
        }
      }).render());
  }
  /**
   * Sets up the {@link #_sizeView} property and adds it to the passed `domElement`.
   */
  _appendSizeUI(e) {
    this._sizeView = new hA(), this._sizeView.render(), e.appendChild(this._sizeView.element);
  }
}
function dA(n) {
  return `ck-widget__resizer__handle-${n}`;
}
function fA(n) {
  return {
    x: n.pageX,
    y: n.pageY
  };
}
function mA(n) {
  return n && n.ownerDocument && n.ownerDocument.contains(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ps extends _ {
  constructor() {
    super(...arguments), this._resizers = /* @__PURE__ */ new Map();
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "WidgetResize";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.editing, t = I.window.document;
    this.set("selectedResizer", null), this.set("_activeResizer", null), e.view.addObserver(Ln), this._observer = new (it())(), this.listenTo(e.view.document, "mousedown", this._mouseDownListener.bind(this), { priority: "high" }), this._observer.listenTo(t, "mousemove", this._mouseMoveListener.bind(this)), this._observer.listenTo(t, "mouseup", this._mouseUpListener.bind(this)), this._redrawSelectedResizerThrottled = Vn(() => this.redrawSelectedResizer(), 200), this.editor.ui.on("update", this._redrawSelectedResizerThrottled), this.editor.model.document.on("change", () => {
      for (const [s, r] of this._resizers)
        s.isAttached() || (this._resizers.delete(s), r.destroy());
    }, { priority: "lowest" }), this._observer.listenTo(I.window, "resize", this._redrawSelectedResizerThrottled);
    const i = this.editor.editing.view.document.selection;
    i.on("change", () => {
      const s = i.getSelectedElement(), r = this.getResizerByViewElement(s) || null;
      r ? this.select(r) : this.deselect();
    });
  }
  /**
   * Redraws the selected resizer if there is any selected resizer and if it is visible.
   */
  redrawSelectedResizer() {
    this.selectedResizer && this.selectedResizer.isVisible && this.selectedResizer.redraw();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._observer.stopListening();
    for (const e of this._resizers.values())
      e.destroy();
    this._redrawSelectedResizerThrottled.cancel();
  }
  /**
   * Marks resizer as selected.
   */
  select(e) {
    this.deselect(), this.selectedResizer = e, this.selectedResizer.isSelected = !0;
  }
  /**
   * Deselects currently set resizer.
   */
  deselect() {
    this.selectedResizer && (this.selectedResizer.isSelected = !1), this.selectedResizer = null;
  }
  /**
   * @param options Resizer options.
   */
  attachTo(e) {
    const t = new Sl(e), i = this.editor.plugins;
    if (t.attach(), i.has("WidgetToolbarRepository")) {
      const o = i.get("WidgetToolbarRepository");
      t.on("begin", () => {
        o.forceDisabled("resize");
      }, { priority: "lowest" }), t.on("cancel", () => {
        o.clearForceDisabled("resize");
      }, { priority: "highest" }), t.on("commit", () => {
        o.clearForceDisabled("resize");
      }, { priority: "highest" });
    }
    this._resizers.set(e.viewElement, t);
    const r = this.editor.editing.view.document.selection.getSelectedElement();
    return this.getResizerByViewElement(r) == t && this.select(t), t;
  }
  /**
   * Returns a resizer created for a given view element (widget element).
   *
   * @param viewElement View element associated with the resizer.
   */
  getResizerByViewElement(e) {
    return this._resizers.get(e);
  }
  /**
   * Returns a resizer that contains a given resize handle.
   */
  _getResizerByHandle(e) {
    for (const t of this._resizers.values())
      if (t.containsHandle(e))
        return t;
  }
  /**
   * @param domEventData Native DOM event.
   */
  _mouseDownListener(e, t) {
    const i = t.domTarget;
    Sl.isResizeHandle(i) && (this._activeResizer = this._getResizerByHandle(i) || null, this._activeResizer && (this._activeResizer.begin(i), e.stop(), t.preventDefault()));
  }
  /**
   * @param domEventData Native DOM event.
   */
  _mouseMoveListener(e, t) {
    this._activeResizer && this._activeResizer.updateSize(t);
  }
  _mouseUpListener() {
    this._activeResizer && (this._activeResizer.commit(), this._activeResizer = null);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class gA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "DragDrop";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ut, Wi];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.editing.view;
    if (this._draggedRange = null, this._draggingUid = "", this._draggableElement = null, this._updateDropMarkerThrottled = Vn((i) => this._updateDropMarker(i), 40), this._removeDropMarkerDelayed = Ws(() => this._removeDropMarker(), 40), this._clearDraggableAttributesDelayed = Ws(() => this._clearDraggableAttributes(), 40), e.plugins.has("DragDropExperimental")) {
      this.forceDisabled("DragDropExperimental");
      return;
    }
    t.addObserver(eo), t.addObserver(Ln), this._setupDragging(), this._setupContentInsertionIntegration(), this._setupClipboardInputIntegration(), this._setupDropMarker(), this._setupDraggableAttributeHandling(), this.listenTo(e, "change:isReadOnly", (i, s, r) => {
      r ? this.forceDisabled("readOnlyMode") : this.clearForceDisabled("readOnlyMode");
    }), this.on("change:isEnabled", (i, s, r) => {
      r || this._finalizeDragging(!1);
    }), S.isAndroid && this.forceDisabled("noAndroidSupport");
  }
  /**
   * @inheritDoc
   */
  destroy() {
    return this._draggedRange && (this._draggedRange.detach(), this._draggedRange = null), this._updateDropMarkerThrottled.cancel(), this._removeDropMarkerDelayed.cancel(), this._clearDraggableAttributesDelayed.cancel(), super.destroy();
  }
  /**
   * Drag and drop events handling.
   */
  _setupDragging() {
    const e = this.editor, t = e.model, i = t.document, s = e.editing.view, r = s.document;
    this.listenTo(r, "dragstart", (o, a) => {
      const l = i.selection;
      if (a.target && a.target.is("editableElement")) {
        a.preventDefault();
        return;
      }
      const c = a.target ? Ol(a.target) : null;
      if (c) {
        const m = e.editing.mapper.toModelElement(c);
        this._draggedRange = ze.fromRange(t.createRangeOn(m)), e.plugins.has("WidgetToolbarRepository") && e.plugins.get("WidgetToolbarRepository").forceDisabled("dragDrop");
      } else if (!r.selection.isCollapsed) {
        const m = r.selection.getSelectedElement();
        (!m || !Y(m)) && (this._draggedRange = ze.fromRange(l.getFirstRange()));
      }
      if (!this._draggedRange) {
        a.preventDefault();
        return;
      }
      this._draggingUid = Ye();
      const u = this.isEnabled && e.model.canEditAt(this._draggedRange);
      a.dataTransfer.effectAllowed = u ? "copyMove" : "copy", a.dataTransfer.setData("application/ckeditor5-dragging-uid", this._draggingUid);
      const h = t.createSelection(this._draggedRange.toRange()), f = e.data.toView(t.getSelectedContent(h));
      r.fire("clipboardOutput", {
        dataTransfer: a.dataTransfer,
        content: f,
        method: "dragstart"
      }), u || (this._draggedRange.detach(), this._draggedRange = null, this._draggingUid = "");
    }, { priority: "low" }), this.listenTo(r, "dragend", (o, a) => {
      this._finalizeDragging(!a.dataTransfer.isCanceled && a.dataTransfer.dropEffect == "move");
    }, { priority: "low" }), this.listenTo(r, "dragenter", () => {
      this.isEnabled && s.focus();
    }), this.listenTo(r, "dragleave", () => {
      this._removeDropMarkerDelayed();
    }), this.listenTo(r, "dragging", (o, a) => {
      if (!this.isEnabled) {
        a.dataTransfer.dropEffect = "none";
        return;
      }
      this._removeDropMarkerDelayed.cancel();
      const l = Il(e, a.targetRanges, a.target);
      if (!e.model.canEditAt(l)) {
        a.dataTransfer.dropEffect = "none";
        return;
      }
      this._draggedRange || (a.dataTransfer.dropEffect = "copy"), S.isGecko || (a.dataTransfer.effectAllowed == "copy" ? a.dataTransfer.dropEffect = "copy" : ["all", "copyMove"].includes(a.dataTransfer.effectAllowed) && (a.dataTransfer.dropEffect = "move"));
      /* istanbul ignore else -- @preserve */
      l && this._updateDropMarkerThrottled(l);
    }, { priority: "low" });
  }
  /**
   * Integration with the `clipboardInput` event.
   */
  _setupClipboardInputIntegration() {
    const e = this.editor, i = e.editing.view.document;
    this.listenTo(i, "clipboardInput", (s, r) => {
      if (r.method != "drop")
        return;
      const o = Il(e, r.targetRanges, r.target);
      this._removeDropMarker();
      /* istanbul ignore if -- @preserve */
      if (!o || !e.model.canEditAt(o)) {
        this._finalizeDragging(!1), s.stop();
        return;
      }
      if (this._draggedRange && this._draggingUid != r.dataTransfer.getData("application/ckeditor5-dragging-uid") && (this._draggedRange.detach(), this._draggedRange = null, this._draggingUid = ""), Rl(r.dataTransfer) == "move" && this._draggedRange && this._draggedRange.containsRange(o, !0)) {
        this._finalizeDragging(!1), s.stop();
        return;
      }
      r.targetRanges = [e.editing.mapper.toViewRange(o)];
    }, { priority: "high" });
  }
  /**
   * Integration with the `contentInsertion` event of the clipboard pipeline.
   */
  _setupContentInsertionIntegration() {
    const e = this.editor.plugins.get(ut);
    e.on("contentInsertion", (t, i) => {
      if (!this.isEnabled || i.method !== "drop")
        return;
      const s = i.targetRanges.map((r) => this.editor.editing.mapper.toModelRange(r));
      this.editor.model.change((r) => r.setSelection(s));
    }, { priority: "high" }), e.on("contentInsertion", (t, i) => {
      if (!this.isEnabled || i.method !== "drop")
        return;
      const s = Rl(i.dataTransfer) == "move", r = !i.resultRange || !i.resultRange.isCollapsed;
      this._finalizeDragging(r && s);
    }, { priority: "lowest" });
  }
  /**
   * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start.
   */
  _setupDraggableAttributeHandling() {
    const e = this.editor, t = e.editing.view, i = t.document;
    this.listenTo(i, "mousedown", (s, r) => {
      if (S.isAndroid || !r)
        return;
      this._clearDraggableAttributesDelayed.cancel();
      let o = Ol(r.target);
      if (S.isBlink && !o && !i.selection.isCollapsed) {
        const a = i.selection.getSelectedElement();
        if (!a || !Y(a)) {
          const l = i.selection.editableElement;
          l && !l.isReadOnly && (o = l);
        }
      }
      o && (t.change((a) => {
        a.setAttribute("draggable", "true", o);
      }), this._draggableElement = e.editing.mapper.toModelElement(o));
    }), this.listenTo(i, "mouseup", () => {
      S.isAndroid || this._clearDraggableAttributesDelayed();
    });
  }
  /**
   * Removes the `draggable` attribute from the element that was used for dragging.
   */
  _clearDraggableAttributes() {
    const e = this.editor.editing;
    e.view.change((t) => {
      this._draggableElement && this._draggableElement.root.rootName != "$graveyard" && t.removeAttribute("draggable", e.mapper.toViewElement(this._draggableElement)), this._draggableElement = null;
    });
  }
  /**
   * Creates downcast conversion for the drop target marker.
   */
  _setupDropMarker() {
    const e = this.editor;
    e.conversion.for("editingDowncast").markerToHighlight({
      model: "drop-target",
      view: {
        classes: ["ck-clipboard-drop-target-range"]
      }
    }), e.conversion.for("editingDowncast").markerToElement({
      model: "drop-target",
      view: (t, { writer: i }) => {
        if (e.model.schema.checkChild(t.markerRange.start, "$text"))
          return i.createUIElement("span", { class: "ck ck-clipboard-drop-target-position" }, function(r) {
            const o = this.toDomElement(r);
            return o.append("⁠", r.createElement("span"), "⁠"), o;
          });
      }
    });
  }
  /**
   * Updates the drop target marker to the provided range.
   *
   * @param targetRange The range to set the marker to.
   */
  _updateDropMarker(e) {
    const t = this.editor, i = t.model.markers;
    t.model.change((s) => {
      i.has("drop-target") ? i.get("drop-target").getRange().isEqual(e) || s.updateMarker("drop-target", { range: e }) : s.addMarker("drop-target", {
        range: e,
        usingOperation: !1,
        affectsData: !1
      });
    });
  }
  /**
   * Removes the drop target marker.
   */
  _removeDropMarker() {
    const e = this.editor.model;
    this._removeDropMarkerDelayed.cancel(), this._updateDropMarkerThrottled.cancel(), e.markers.has("drop-target") && e.change((t) => {
      t.removeMarker("drop-target");
    });
  }
  /**
   * Deletes the dragged content from its original range and clears the dragging state.
   *
   * @param moved Whether the move succeeded.
   */
  _finalizeDragging(e) {
    const t = this.editor, i = t.model;
    this._removeDropMarker(), this._clearDraggableAttributes(), t.plugins.has("WidgetToolbarRepository") && t.plugins.get("WidgetToolbarRepository").clearForceDisabled("dragDrop"), this._draggingUid = "", this._draggedRange && (e && this.isEnabled && i.deleteContent(i.createSelection(this._draggedRange), { doNotAutoparagraph: !0 }), this._draggedRange.detach(), this._draggedRange = null);
  }
}
function Il(n, e, t) {
  const i = n.model, s = n.editing.mapper;
  let r = null;
  const o = e ? e[0].start : null;
  if (t.is("uiElement") && (t = t.parent), r = pA(n, t), r)
    return r;
  const a = vA(n, t), l = o ? s.toModelPosition(o) : null;
  return l ? (r = bA(n, l, a), r || (r = i.schema.getNearestSelectionRange(l, S.isGecko ? "forward" : "backward"), r) ? r : _A(n, l.parent)) : wA(n, a);
}
function pA(n, e) {
  const t = n.model, i = n.editing.mapper;
  if (Y(e))
    return t.createRangeOn(i.toModelElement(e));
  if (!e.is("editableElement")) {
    const s = e.findAncestor((r) => Y(r) || r.is("editableElement"));
    if (Y(s))
      return t.createRangeOn(i.toModelElement(s));
  }
  return null;
}
function wA(n, e) {
  const t = n.model, i = t.schema, s = t.createPositionAt(e, 0);
  return i.getNearestSelectionRange(s, "forward");
}
function bA(n, e, t) {
  const i = n.model;
  if (!i.schema.checkChild(t, "$block"))
    return null;
  const s = i.createPositionAt(t, 0), r = e.path.slice(0, s.path.length), a = i.createPositionFromPath(e.root, r).nodeAfter;
  return a && i.schema.isObject(a) ? i.createRangeOn(a) : null;
}
function _A(n, e) {
  const t = n.model;
  let i = e;
  for (; i; ) {
    if (t.schema.isObject(i))
      return t.createRangeOn(i);
    i = i.parent;
  }
  /* istanbul ignore next -- @preserve */
  return null;
}
function vA(n, e) {
  const t = n.editing.mapper, i = n.editing.view, s = t.toModelElement(e);
  if (s)
    return s;
  const r = i.createPositionBefore(e), o = t.findMappedViewAncestor(r);
  return t.toModelElement(o);
}
function Rl(n) {
  return S.isGecko ? n.dropEffect : ["all", "copyMove"].includes(n.effectAllowed) ? "move" : "copy";
}
function Ol(n) {
  if (n.is("editableElement"))
    return null;
  if (n.hasClass("ck-widget__selection-handle"))
    return n.findAncestor(Y);
  if (Y(n))
    return n;
  const e = n.findAncestor((t) => Y(t) || t.is("editableElement"));
  return Y(e) ? e : null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class yA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "PastePlainText";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ut];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model, i = e.editing.view, s = i.document, r = t.document.selection;
    let o = !1;
    i.addObserver(eo), this.listenTo(s, "keydown", (a, l) => {
      o = l.shiftKey;
    }), e.plugins.get(ut).on("contentInsertion", (a, l) => {
      !o && !kA(l.content, t.schema) || t.change((c) => {
        const u = Array.from(r.getAttributes()).filter(([f]) => t.schema.getAttributeProperties(f).isFormatting);
        r.isCollapsed || t.deleteContent(r, { doNotAutoparagraph: !0 }), u.push(...r.getAttributes());
        const h = c.createRangeIn(l.content);
        for (const f of h.getItems())
          f.is("$textProxy") && c.setAttributes(u, f);
      });
    });
  }
}
function kA(n, e) {
  if (n.childCount > 1)
    return !1;
  const t = n.getChild(0);
  return e.isObject(t) ? !1 : Array.from(t.getAttributeKeys()).length == 0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ud extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Clipboard";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ut, gA, yA];
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class CA extends te {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.affectsData = !1;
  }
  /**
   * @inheritDoc
   */
  execute() {
    const e = this.editor.model, t = e.document.selection;
    let i = e.schema.getLimitElement(t);
    if (t.containsEntireContent(i) || !Ml(e.schema, i))
      do
        if (i = i.parent, !i)
          return;
      while (!Ml(e.schema, i));
    e.change((s) => {
      s.setSelection(i, "in");
    });
  }
}
function Ml(n, e) {
  return n.isLimit(e) && (n.checkChild(e, "$text") || n.checkChild(e, "paragraph"));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const EA = Rr("Ctrl+A");
class AA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "SelectAllEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, i = e.editing.view.document;
    e.commands.add("selectAll", new CA(e)), this.listenTo(i, "keydown", (s, r) => {
      ii(r) === EA && (e.execute("selectAll"), r.preventDefault());
    });
  }
}
const TA = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M.75 15.5a.75.75 0 0 1 .75.75V18l.008.09A.5.5 0 0 0 2 18.5h1.75a.75.75 0 1 1 0 1.5H1.5l-.144-.007a1.5 1.5 0 0 1-1.35-1.349L0 18.5v-2.25a.75.75 0 0 1 .75-.75zm18.5 0a.75.75 0 0 1 .75.75v2.25l-.007.144a1.5 1.5 0 0 1-1.349 1.35L18.5 20h-2.25a.75.75 0 1 1 0-1.5H18a.5.5 0 0 0 .492-.41L18.5 18v-1.75a.75.75 0 0 1 .75-.75zm-10.45 3c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm.45-5.5a.75.75 0 1 1 0 1.5h-8.5a.75.75 0 1 1 0-1.5h8.5zM1.3 11c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM1.3 7c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5h-2.5a.75.75 0 1 1 0-1.5h2.5zm-5 0a.75.75 0 1 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5h5.5zm-6.5-5a.75.75 0 0 1 0 1.5H2a.5.5 0 0 0-.492.41L1.5 2v1.75a.75.75 0 0 1-1.5 0V1.5l.007-.144A1.5 1.5 0 0 1 1.356.006L1.5 0h2.25zM18.5 0l.144.007a1.5 1.5 0 0 1 1.35 1.349L20 1.5v2.25a.75.75 0 1 1-1.5 0V2l-.008-.09A.5.5 0 0 0 18 1.5h-1.75a.75.75 0 1 1 0-1.5h2.25zM8.8 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class PA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "SelectAllUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.ui.componentFactory.add("selectAll", (t) => {
      const i = e.commands.get("selectAll"), s = new H(t), r = t.t;
      return s.set({
        label: r("Select all"),
        icon: TA,
        keystroke: "Ctrl+A",
        tooltip: !0
      }), s.bind("isEnabled").to(i, "isEnabled"), this.listenTo(s, "execute", () => {
        e.execute("selectAll"), e.editing.view.focus();
      }), s;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class xA extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [AA, PA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "SelectAll";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class hd extends te {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._stack = [], this._createdBatches = /* @__PURE__ */ new WeakSet(), this.refresh(), this._isEnabledBasedOnSelection = !1, this.listenTo(e.data, "set", (t, i) => {
      i[1] = { ...i[1] };
      const s = i[1];
      s.batchType || (s.batchType = { isUndoable: !1 });
    }, { priority: "high" }), this.listenTo(e.data, "set", (t, i) => {
      i[1].batchType.isUndoable || this.clearStack();
    });
  }
  /**
   * @inheritDoc
   */
  refresh() {
    this.isEnabled = this._stack.length > 0;
  }
  /**
   * Returns all batches created by this command.
   */
  get createdBatches() {
    return this._createdBatches;
  }
  /**
   * Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}
   * created by the editor which this command is registered to.
   *
   * @param batch The batch to add.
   */
  addBatch(e) {
    const t = this.editor.model.document.selection, i = {
      ranges: t.hasOwnRange ? Array.from(t.getRanges()) : [],
      isBackward: t.isBackward
    };
    this._stack.push({ batch: e, selection: i }), this.refresh();
  }
  /**
   * Removes all items from the stack.
   */
  clearStack() {
    this._stack = [], this.refresh();
  }
  /**
   * Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.
   *
   * @param ranges Ranges to be restored.
   * @param isBackward A flag describing whether the restored range was selected forward or backward.
   * @param operations Operations which has been applied since selection has been stored.
   */
  _restoreSelection(e, t, i) {
    const s = this.editor.model, r = s.document, o = [], a = e.map((c) => c.getTransformedByOperations(i)), l = a.flat();
    for (const c of a) {
      const u = c.filter((h) => h.root != r.graveyard).filter((h) => !IA(h, l));
      u.length && (SA(u), o.push(u[0]));
    }
    o.length && s.change((c) => {
      c.setSelection(o, { backward: t });
    });
  }
  /**
   * Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.
   * This is a helper method for {@link #execute}.
   *
   * @param batchToUndo The batch to be undone.
   * @param undoingBatch The batch that will contain undoing changes.
   */
  _undo(e, t) {
    const i = this.editor.model, s = i.document;
    this._createdBatches.add(t);
    const r = e.operations.slice().filter((o) => o.isDocumentOperation);
    r.reverse();
    for (const o of r) {
      const a = o.baseVersion + 1, l = Array.from(s.history.getOperations(a)), u = Wy([o.getReversed()], l, {
        useRelations: !0,
        document: this.editor.model.document,
        padWithNoOps: !1,
        forceWeakRemove: !0
      }).operationsA;
      for (let h of u) {
        const f = h.affectedSelectable;
        f && !i.canEditAt(f) && (h = new ie(h.baseVersion)), t.addOperation(h), i.applyOperation(h), s.history.setOperationAsUndone(o, h);
      }
    }
  }
}
function SA(n) {
  n.sort((e, t) => e.start.isBefore(t.start) ? -1 : 1);
  for (let e = 1; e < n.length; e++) {
    const i = n[e - 1].getJoined(n[e], !0);
    i && (e--, n.splice(e, 2, i));
  }
}
function IA(n, e) {
  return e.some((t) => t !== n && t.containsRange(n, !0));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class RA extends hd {
  /**
   * Executes the command. This method reverts a {@link module:engine/model/batch~Batch batch} added to the command's stack, transforms
   * and applies the reverted version on the {@link module:engine/model/document~Document document} and removes the batch from the stack.
   * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.
   *
   * @fires execute
   * @fires revert
   * @param batch A batch that should be undone. If not set, the last added batch will be undone.
   */
  execute(e = null) {
    const t = e ? this._stack.findIndex((r) => r.batch == e) : this._stack.length - 1, i = this._stack.splice(t, 1)[0], s = this.editor.model.createBatch({ isUndo: !0 });
    this.editor.model.enqueueChange(s, () => {
      this._undo(i.batch, s);
      const r = this.editor.model.document.history.getOperations(i.batch.baseVersion);
      this._restoreSelection(i.selection.ranges, i.selection.isBackward, r), this.fire("revert", i.batch, s);
    }), this.refresh();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class OA extends hd {
  /**
   * Executes the command. This method reverts the last {@link module:engine/model/batch~Batch batch} added to
   * the command's stack, applies the reverted and transformed version on the
   * {@link module:engine/model/document~Document document} and removes the batch from the stack.
   * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.
   *
   * @fires execute
   */
  execute() {
    const e = this._stack.pop(), t = this.editor.model.createBatch({ isUndo: !0 });
    this.editor.model.enqueueChange(t, () => {
      const s = e.batch.operations[e.batch.operations.length - 1].baseVersion + 1, r = this.editor.model.document.history.getOperations(s);
      this._restoreSelection(e.selection.ranges, e.selection.isBackward, r), this._undo(e.batch, t);
    }), this.refresh();
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class MA extends _ {
  constructor() {
    super(...arguments), this._batchRegistry = /* @__PURE__ */ new WeakSet();
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "UndoEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    this._undoCommand = new RA(e), this._redoCommand = new OA(e), e.commands.add("undo", this._undoCommand), e.commands.add("redo", this._redoCommand), this.listenTo(e.model, "applyOperation", (t, i) => {
      const s = i[0];
      if (!s.isDocumentOperation)
        return;
      const r = s.batch, o = this._redoCommand.createdBatches.has(r), a = this._undoCommand.createdBatches.has(r);
      this._batchRegistry.has(r) || (this._batchRegistry.add(r), r.isUndoable && (o ? this._undoCommand.addBatch(r) : a || (this._undoCommand.addBatch(r), this._redoCommand.clearStack())));
    }, { priority: "highest" }), this.listenTo(this._undoCommand, "revert", (t, i, s) => {
      this._redoCommand.addBatch(s);
    }), e.keystrokes.set("CTRL+Z", "undo"), e.keystrokes.set("CTRL+Y", "redo"), e.keystrokes.set("CTRL+SHIFT+Z", "redo");
  }
}
const Vl = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m5.042 9.367 2.189 1.837a.75.75 0 0 1-.965 1.149l-3.788-3.18a.747.747 0 0 1-.21-.284.75.75 0 0 1 .17-.945L6.23 4.762a.75.75 0 1 1 .964 1.15L4.863 7.866h8.917A.75.75 0 0 1 14 7.9a4 4 0 1 1-1.477 7.718l.344-1.489a2.5 2.5 0 1 0 1.094-4.73l.008-.032H5.042z"/></svg>', Dl = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m14.958 9.367-2.189 1.837a.75.75 0 0 0 .965 1.149l3.788-3.18a.747.747 0 0 0 .21-.284.75.75 0 0 0-.17-.945L13.77 4.762a.75.75 0 1 0-.964 1.15l2.331 1.955H6.22A.75.75 0 0 0 6 7.9a4 4 0 1 0 1.477 7.718l-.344-1.489A2.5 2.5 0 1 1 6.039 9.4l-.008-.032h8.927z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class VA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "UndoUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.locale, i = e.t, s = t.uiLanguageDirection == "ltr" ? Vl : Dl, r = t.uiLanguageDirection == "ltr" ? Dl : Vl;
    this._addButton("undo", i("Undo"), "CTRL+Z", s), this._addButton("redo", i("Redo"), "CTRL+Y", r);
  }
  /**
   * Creates a button for the specified command.
   *
   * @param name Command name.
   * @param label Button label.
   * @param keystroke Command keystroke.
   * @param Icon Source of the icon.
   */
  _addButton(e, t, i, s) {
    const r = this.editor;
    r.ui.componentFactory.add(e, (o) => {
      const a = r.commands.get(e), l = new H(o);
      return l.set({
        label: t,
        icon: s,
        keystroke: i,
        tooltip: !0
      }), l.bind("isEnabled").to(a, "isEnabled"), this.listenTo(l, "execute", () => {
        r.execute(e), r.editing.view.focus();
      }), l;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class dd extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [MA, VA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Undo";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class R5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ud, to, xA, IE, yE, dd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Essentials";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class DA extends te {
  constructor(e) {
    super(e), this._isEnabledBasedOnSelection = !1;
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document, i = Te(t.selection.getSelectedBlocks());
    this.value = !!i && i.is("element", "paragraph"), this.isEnabled = !!i && Bl(i, e.schema);
  }
  /**
   * Executes the command. All the blocks (see {@link module:engine/model/schema~Schema}) in the selection
   * will be turned to paragraphs.
   *
   * @fires execute
   * @param options Options for the executed command.
   * @param options.selection The selection that the command should be applied to. By default,
   * if not provided, the command is applied to the {@link module:engine/model/document~Document#selection}.
   */
  execute(e = {}) {
    const t = this.editor.model, i = t.document, s = e.selection || i.selection;
    t.canEditAt(s) && t.change((r) => {
      const o = s.getSelectedBlocks();
      for (const a of o)
        !a.is("element", "paragraph") && Bl(a, t.schema) && r.rename(a, "paragraph");
    });
  }
}
function Bl(n, e) {
  return e.checkChild(n.parent, "paragraph") && !e.isObject(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class BA extends te {
  constructor(e) {
    super(e), this._isEnabledBasedOnSelection = !1;
  }
  /**
   * Executes the command.
   *
   * @param options Options for the executed command.
   * @param options.position The model position at which the new paragraph will be inserted.
   * @param options.attributes Attributes keys and values to set on a inserted paragraph.
   * @fires execute
   */
  execute(e) {
    const t = this.editor.model, i = e.attributes;
    let s = e.position;
    t.canEditAt(s) && t.change((r) => {
      const o = r.createElement("paragraph");
      if (i && t.schema.setAllowedAttributes(o, i, r), !t.schema.checkChild(s.parent, o)) {
        const a = t.schema.findAllowedParent(s, o);
        if (!a)
          return;
        s = r.split(s, a).position;
      }
      t.insertContent(o, s), r.setSelection(o, "in");
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Wn extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Paragraph";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model;
    e.commands.add("paragraph", new DA(e)), e.commands.add("insertParagraph", new BA(e)), t.schema.register("paragraph", { inheritAllFrom: "$block" }), e.conversion.elementToElement({ model: "paragraph", view: "p" }), e.conversion.for("upcast").elementToElement({
      model: (i, { writer: s }) => !Wn.paragraphLikeElements.has(i.name) || i.isEmpty ? null : s.createElement("paragraph"),
      view: /.+/,
      converterPriority: "low"
    });
  }
}
Wn.paragraphLikeElements = /* @__PURE__ */ new Set([
  "blockquote",
  "dd",
  "div",
  "dt",
  "h1",
  "h2",
  "h3",
  "h4",
  "h5",
  "h6",
  "li",
  "p",
  "td",
  "th"
]);
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const no = ["left", "right", "center", "justify"];
function fd(n) {
  return no.includes(n);
}
function md(n, e) {
  return e.contentLanguageDirection == "rtl" ? n === "right" : n === "left";
}
function gd(n) {
  const e = n.map((i) => {
    let s;
    return typeof i == "string" ? s = { name: i } : s = i, s;
  }).filter((i) => {
    const s = no.includes(i.name);
    return s || q("alignment-config-name-not-recognized", { option: i }), s;
  }), t = e.filter((i) => !!i.className).length;
  if (t && t < e.length)
    throw new d("alignment-config-classnames-are-missing", { configuredOptions: n });
  return e.forEach((i, s, r) => {
    const o = r.slice(s + 1);
    if (o.some((l) => l.name == i.name))
      throw new d("alignment-config-name-already-defined", { option: i, configuredOptions: n });
    if (i.className && o.some((c) => c.className == i.className))
      throw new d("alignment-config-classname-already-defined", { option: i, configuredOptions: n });
  }), e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const so = "alignment";
class FA extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const t = this.editor.locale, i = Te(this.editor.model.document.selection.getSelectedBlocks());
    this.isEnabled = !!i && this._canBeAligned(i), this.isEnabled && i.hasAttribute("alignment") ? this.value = i.getAttribute("alignment") : this.value = t.contentLanguageDirection === "rtl" ? "right" : "left";
  }
  /**
   * Executes the command. Applies the alignment `value` to the selected blocks.
   * If no `value` is passed, the `value` is the default one or it is equal to the currently selected block's alignment attribute,
   * the command will remove the attribute from the selected blocks.
   *
   * @param options Options for the executed command.
   * @param options.value The value to apply.
   * @fires execute
   */
  execute(e = {}) {
    const t = this.editor, i = t.locale, s = t.model, r = s.document, o = e.value;
    s.change((a) => {
      const l = Array.from(r.selection.getSelectedBlocks()).filter((h) => this._canBeAligned(h)), c = l[0].getAttribute("alignment");
      md(o, i) || c === o || !o ? NA(l, a) : LA(l, a, o);
    });
  }
  /**
   * Checks whether a block can have alignment set.
   *
   * @param block The block to be checked.
   */
  _canBeAligned(e) {
    return this.editor.model.schema.checkAttribute(e, so);
  }
}
function NA(n, e) {
  for (const t of n)
    e.removeAttribute(so, t);
}
function LA(n, e, t) {
  for (const i of n)
    e.setAttribute(so, t, i);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $A extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "AlignmentEditing";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define("alignment", {
      options: no.map((t) => ({ name: t }))
    });
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.locale, i = e.model.schema, r = gd(e.config.get("alignment.options")).filter((c) => fd(c.name) && !md(c.name, t)), o = r.some((c) => !!c.className);
    i.extend("$block", { allowAttributes: "alignment" }), e.model.schema.setAttributeProperties("alignment", { isFormatting: !0 }), o ? e.conversion.attributeToAttribute(UA(r)) : e.conversion.for("downcast").attributeToAttribute(zA(r));
    const a = HA(r);
    for (const c of a)
      e.conversion.for("upcast").attributeToAttribute(c);
    const l = WA(r);
    for (const c of l)
      e.conversion.for("upcast").attributeToAttribute(c);
    e.commands.add("alignment", new FA(e));
  }
}
function zA(n) {
  const e = {};
  for (const { name: i } of n)
    e[i] = {
      key: "style",
      value: {
        "text-align": i
      }
    };
  return {
    model: {
      key: "alignment",
      values: n.map((i) => i.name)
    },
    view: e
  };
}
function HA(n) {
  const e = [];
  for (const { name: t } of n)
    e.push({
      view: {
        key: "style",
        value: {
          "text-align": t
        }
      },
      model: {
        key: "alignment",
        value: t
      }
    });
  return e;
}
function WA(n) {
  const e = [];
  for (const { name: t } of n)
    e.push({
      view: {
        key: "align",
        value: t
      },
      model: {
        key: "alignment",
        value: t
      }
    });
  return e;
}
function UA(n) {
  const e = {};
  for (const i of n)
    e[i.name] = {
      key: "class",
      value: i.className
    };
  return {
    model: {
      key: "alignment",
      values: n.map((i) => i.name)
    },
    view: e
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const sn = /* @__PURE__ */ new Map([
  ["left", D.alignLeft],
  ["right", D.alignRight],
  ["center", D.alignCenter],
  ["justify", D.alignJustify]
]);
class jA extends _ {
  /**
   * Returns the localized option titles provided by the plugin.
   *
   * The following localized titles corresponding with
   * {@link module:alignment/alignmentconfig~AlignmentConfig#options} are available:
   *
   * * `'left'`,
   * * `'right'`,
   * * `'center'`,
   * * `'justify'`.
   *
   * @readonly
   */
  get localizedOptionTitles() {
    const e = this.editor.t;
    return {
      left: e("Align left"),
      right: e("Align right"),
      center: e("Align center"),
      justify: e("Justify")
    };
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "AlignmentUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.ui.componentFactory, i = e.t, s = gd(e.config.get("alignment.options"));
    s.map((r) => r.name).filter(fd).forEach((r) => this._addButton(r)), t.add("alignment", (r) => {
      const o = gt(r);
      zn(o, () => s.map((c) => t.create(`alignment:${c.name}`)), {
        enableActiveItemFocusOnDropdownOpen: !0,
        isVertical: !0,
        ariaLabel: i("Text alignment toolbar")
      }), o.buttonView.set({
        label: i("Text alignment"),
        tooltip: !0
      }), o.extendTemplate({
        attributes: {
          class: "ck-alignment-dropdown"
        }
      });
      const a = r.contentLanguageDirection === "rtl" ? sn.get("right") : sn.get("left"), l = e.commands.get("alignment");
      return o.buttonView.bind("icon").to(l, "value", (c) => sn.get(c) || a), o.bind("isEnabled").to(l, "isEnabled"), this.listenTo(o, "execute", () => {
        e.editing.view.focus();
      }), o;
    });
  }
  /**
   * Helper method for initializing the button and linking it with an appropriate command.
   *
   * @param option The name of the alignment option for which the button is added.
   */
  _addButton(e) {
    const t = this.editor;
    t.ui.componentFactory.add(`alignment:${e}`, (i) => {
      const s = t.commands.get("alignment"), r = new H(i);
      return r.set({
        label: this.localizedOptionTitles[e],
        icon: sn.get(e),
        tooltip: !0,
        isToggleable: !0
      }), r.bind("isEnabled").to(s), r.bind("isOn").to(s, "value", (o) => o === e), this.listenTo(r, "execute", () => {
        t.execute("alignment", { value: e }), t.editing.view.focus();
      }), r;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class O5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [$A, jA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Alignment";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ro extends te {
  /**
   * @param attributeKey Attribute that will be set by the command.
   */
  constructor(e, t) {
    super(e), this.attributeKey = t;
  }
  /**
   * Updates the command's {@link #value} and {@link #isEnabled} based on the current selection.
   */
  refresh() {
    const e = this.editor.model, t = e.document;
    this.value = this._getValueFromFirstAllowedNode(), this.isEnabled = e.schema.checkAttributeInSelection(t.selection, this.attributeKey);
  }
  /**
   * Executes the command &mdash; applies the attribute to the selection or removes it from the selection.
   *
   * If the command is active (`value == true`), it will remove attributes. Otherwise, it will set attributes.
   *
   * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}:
   *
   * * If the selection is on a range, the command applies the attribute to all nodes in that range
   * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}).
   * * If the selection is collapsed in a non-empty node, the command applies the attribute to the
   * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection).
   * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note
   * that the selection inherits all attributes from a node if it is in an empty node).
   *
   * @fires execute
   * @param options Command options.
   * @param options.forceValue If set, it will force the command behavior. If `true`,
   * the command will apply the attribute, otherwise the command will remove the attribute.
   * If not set, the command will look for its current value to decide what it should do.
   */
  execute(e = {}) {
    const t = this.editor.model, s = t.document.selection, r = e.forceValue === void 0 ? !this.value : e.forceValue;
    t.change((o) => {
      if (s.isCollapsed)
        r ? o.setSelectionAttribute(this.attributeKey, !0) : o.removeSelectionAttribute(this.attributeKey);
      else {
        const a = t.schema.getValidRanges(s.getRanges(), this.attributeKey);
        for (const l of a)
          r ? o.setAttribute(this.attributeKey, r, l) : o.removeAttribute(this.attributeKey, l);
      }
    });
  }
  /**
   * Checks the attribute value of the first node in the selection that allows the attribute.
   * For the collapsed selection returns the selection attribute.
   *
   * @returns The attribute value.
   */
  _getValueFromFirstAllowedNode() {
    const e = this.editor.model, t = e.schema, i = e.document.selection;
    if (i.isCollapsed)
      return i.hasAttribute(this.attributeKey);
    for (const s of i.getRanges())
      for (const r of s.getItems())
        if (t.checkAttribute(r, this.attributeKey))
          return r.hasAttribute(this.attributeKey);
    return !1;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const zt = "bold";
class qA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "BoldEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.model.schema.extend("$text", { allowAttributes: zt }), e.model.schema.setAttributeProperties(zt, {
      isFormatting: !0,
      copyOnEnter: !0
    }), e.conversion.attributeToElement({
      model: zt,
      view: "strong",
      upcastAlso: [
        "b",
        (t) => {
          const i = t.getStyle("font-weight");
          return i && (i == "bold" || Number(i) >= 600) ? {
            name: !0,
            styles: ["font-weight"]
          } : null;
        }
      ]
    }), e.commands.add(zt, new ro(e, zt)), e.keystrokes.set("CTRL+B", zt);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const ws = "bold";
class GA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "BoldUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.t;
    e.ui.componentFactory.add(ws, (i) => {
      const s = e.commands.get(ws), r = new H(i);
      return r.set({
        label: t("Bold"),
        icon: D.bold,
        keystroke: "CTRL+B",
        tooltip: !0,
        isToggleable: !0
      }), r.bind("isOn", "isEnabled").to(s, "value", "isEnabled"), this.listenTo(r, "execute", () => {
        e.execute(ws), e.editing.view.focus();
      }), r;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class M5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [qA, GA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Bold";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Ht = "italic";
class KA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ItalicEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.model.schema.extend("$text", { allowAttributes: Ht }), e.model.schema.setAttributeProperties(Ht, {
      isFormatting: !0,
      copyOnEnter: !0
    }), e.conversion.attributeToElement({
      model: Ht,
      view: "i",
      upcastAlso: [
        "em",
        {
          styles: {
            "font-style": "italic"
          }
        }
      ]
    }), e.commands.add(Ht, new ro(e, Ht)), e.keystrokes.set("CTRL+I", Ht);
  }
}
const JA = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m9.586 14.633.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 1 1 0 1.2H5.304a.6.6 0 0 1 0-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 0 0-.281-.823 1.12 1.12 0 0 0-.442-.296H8.15a.6.6 0 0 1 0-1.2h6.443a.6.6 0 1 1 0 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const bs = "italic";
class ZA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ItalicUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.t;
    e.ui.componentFactory.add(bs, (i) => {
      const s = e.commands.get(bs), r = new H(i);
      return r.set({
        label: t("Italic"),
        icon: JA,
        keystroke: "CTRL+I",
        tooltip: !0,
        isToggleable: !0
      }), r.bind("isOn", "isEnabled").to(s, "value", "isEnabled"), this.listenTo(r, "execute", () => {
        e.execute(bs), e.editing.view.focus();
      }), r;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class V5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [KA, ZA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Italic";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const bi = "underline";
class YA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "UnderlineEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.model.schema.extend("$text", { allowAttributes: bi }), e.model.schema.setAttributeProperties(bi, {
      isFormatting: !0,
      copyOnEnter: !0
    }), e.conversion.attributeToElement({
      model: bi,
      view: "u",
      upcastAlso: {
        styles: {
          "text-decoration": "underline"
        }
      }
    }), e.commands.add(bi, new ro(e, bi)), e.keystrokes.set("CTRL+U", "underline");
  }
}
const XA = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M3 18v-1.5h14V18zm2.2-8V3.6c0-.4.4-.6.8-.6.3 0 .7.2.7.6v6.2c0 2 1.3 2.8 3.2 2.8 1.9 0 3.4-.9 3.4-2.9V3.6c0-.3.4-.5.8-.5.3 0 .7.2.7.5V10c0 2.7-2.2 4-4.9 4-2.6 0-4.7-1.2-4.7-4z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const _s = "underline";
class QA extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "UnderlineUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.t;
    e.ui.componentFactory.add(_s, (i) => {
      const s = e.commands.get(_s), r = new H(i);
      return r.set({
        label: t("Underline"),
        icon: XA,
        keystroke: "CTRL+U",
        tooltip: !0,
        isToggleable: !0
      }), r.bind("isOn", "isEnabled").to(s, "value", "isEnabled"), this.listenTo(r, "execute", () => {
        e.execute(_s), e.editing.view.focus();
      }), r;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class D5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [YA, QA];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Underline";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class eT extends te {
  /**
   * Creates an instance of the command.
   *
   * @param editor Editor instance.
   * @param modelElements Names of the element which this command can apply in the model.
   */
  constructor(e, t) {
    super(e), this.modelElements = t;
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = Te(this.editor.model.document.selection.getSelectedBlocks());
    this.value = !!e && this.modelElements.includes(e.name) && e.name, this.isEnabled = !!e && this.modelElements.some((t) => Fl(e, t, this.editor.model.schema));
  }
  /**
   * Executes the command. Applies the heading to the selected blocks or, if the first selected
   * block is a heading already, turns selected headings (of this level only) to paragraphs.
   *
   * @param options.value Name of the element which this command will apply in the model.
   * @fires execute
   */
  execute(e) {
    const t = this.editor.model, i = t.document, s = e.value;
    t.change((r) => {
      const o = Array.from(i.selection.getSelectedBlocks()).filter((a) => Fl(a, s, t.schema));
      for (const a of o)
        a.is("element", s) || r.rename(a, s);
    });
  }
}
function Fl(n, e, t) {
  return t.checkChild(n.parent, e) && !t.isObject(n);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Nl = "paragraph";
class tT extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "HeadingEditing";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define("heading", {
      options: [
        { model: "paragraph", title: "Paragraph", class: "ck-heading_paragraph" },
        { model: "heading1", view: "h2", title: "Heading 1", class: "ck-heading_heading1" },
        { model: "heading2", view: "h3", title: "Heading 2", class: "ck-heading_heading2" },
        { model: "heading3", view: "h4", title: "Heading 3", class: "ck-heading_heading3" }
      ]
    });
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Wn];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.config.get("heading.options"), i = [];
    for (const s of t)
      s.model !== "paragraph" && (e.model.schema.register(s.model, {
        inheritAllFrom: "$block"
      }), e.conversion.elementToElement(s), i.push(s.model));
    this._addDefaultH1Conversion(e), e.commands.add("heading", new eT(e, i));
  }
  /**
   * @inheritDoc
   */
  afterInit() {
    const e = this.editor, t = e.commands.get("enter"), i = e.config.get("heading.options");
    t && this.listenTo(t, "afterExecute", (s, r) => {
      const o = e.model.document.selection.getFirstPosition().parent;
      i.some((l) => o.is("element", l.model)) && !o.is("element", Nl) && o.childCount === 0 && r.writer.rename(o, Nl);
    });
  }
  /**
   * Adds default conversion for `h1` -> `heading1` with a low priority.
   *
   * @param editor Editor instance on which to add the `h1` conversion.
   */
  _addDefaultH1Conversion(e) {
    e.conversion.for("upcast").elementToElement({
      model: "heading1",
      view: "h1",
      // With a `low` priority, `paragraph` plugin autoparagraphing mechanism is executed. Make sure
      // this listener is called before it. If not, `h1` will be transformed into a paragraph.
      converterPriority: be.low + 1
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function iT(n) {
  const e = n.t, t = {
    Paragraph: e("Paragraph"),
    "Heading 1": e("Heading 1"),
    "Heading 2": e("Heading 2"),
    "Heading 3": e("Heading 3"),
    "Heading 4": e("Heading 4"),
    "Heading 5": e("Heading 5"),
    "Heading 6": e("Heading 6")
  };
  return n.config.get("heading.options").map((i) => {
    const s = t[i.title];
    return s && s != i.title && (i.title = s), i;
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class nT extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "HeadingUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.t, i = iT(e), s = t("Choose heading"), r = t("Heading");
    e.ui.componentFactory.add("heading", (o) => {
      const a = {}, l = new He(), c = e.commands.get("heading"), u = e.commands.get("paragraph"), h = [c];
      for (const m of i) {
        const p = {
          type: "button",
          model: new Qh({
            label: m.title,
            class: m.class,
            role: "menuitemradio",
            withText: !0
          })
        };
        m.model === "paragraph" ? (p.model.bind("isOn").to(u, "value"), p.model.set("commandName", "paragraph"), h.push(u)) : (p.model.bind("isOn").to(c, "value", (b) => b === m.model), p.model.set({
          commandName: "heading",
          commandValue: m.model
        })), l.add(p), a[m.model] = m.title;
      }
      const f = gt(o);
      return qh(f, l, {
        ariaLabel: r,
        role: "menu"
      }), f.buttonView.set({
        ariaLabel: r,
        ariaLabelledBy: void 0,
        isOn: !1,
        withText: !0,
        tooltip: r
      }), f.extendTemplate({
        attributes: {
          class: [
            "ck-heading-dropdown"
          ]
        }
      }), f.bind("isEnabled").toMany(h, "isEnabled", (...m) => m.some((p) => p)), f.buttonView.bind("label").to(c, "value", u, "value", (m, p) => {
        const b = m || p && "paragraph";
        return typeof b == "boolean" || !a[b] ? s : a[b];
      }), this.listenTo(f, "execute", (m) => {
        const { commandName: p, commandValue: b } = m.source;
        e.execute(p, b ? { value: b } : void 0), e.editing.view.focus();
      }), f;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class B5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [tT, nT];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Heading";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class sT extends te {
  /**
   * Creates an instance of the command.
   *
   * @param editor Editor instance.
   * @param attributeKey The name of a model attribute on which this command operates.
   */
  constructor(e, t) {
    super(e), this.attributeKey = t;
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document;
    this.value = t.selection.getAttribute(this.attributeKey), this.isEnabled = e.schema.checkAttributeInSelection(t.selection, this.attributeKey);
  }
  /**
   * Executes the command. Applies the `value` of the {@link #attributeKey} to the selection.
   * If no `value` is passed, it removes the attribute from the selection.
   *
   * @param options Options for the executed command.
   * @param options.value The value to apply.
   * @fires execute
   */
  execute(e = {}) {
    const t = this.editor.model, s = t.document.selection, r = e.value, o = e.batch, a = (l) => {
      if (s.isCollapsed)
        r ? l.setSelectionAttribute(this.attributeKey, r) : l.removeSelectionAttribute(this.attributeKey);
      else {
        const c = t.schema.getValidRanges(s.getRanges(), this.attributeKey);
        for (const u of c)
          r ? l.setAttribute(this.attributeKey, r, u) : l.removeAttribute(this.attributeKey, u);
      }
    };
    o ? t.enqueueChange(o, (l) => {
      a(l);
    }) : t.change((l) => {
      a(l);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class rT extends z(He) {
  constructor(e) {
    super(e), this.set("isEmpty", !0), this.on("change", () => {
      this.set("isEmpty", this.length === 0);
    });
  }
  /**
   * Adds a color to the document color collection.
   *
   * This method ensures that no color duplicates are inserted (compared using
   * the color value of the {@link module:ui/colorgrid/colorgridview~ColorDefinition}).
   *
   * If the item does not have an ID, it will be automatically generated and set on the item.
   *
   * @param index The position of the item in the collection. The item is pushed to the collection when `index` is not specified.
   * @fires add
   * @fires change
   */
  add(e, t) {
    return this.find((i) => i.color === e.color) ? this : super.add(e, t);
  }
  /**
   * Checks if an object with given colors is present in the document color collection.
   */
  hasColor(e) {
    return !!this.find((t) => t.color === e);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class oT extends T {
  /**
   * Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.
   *
   * @param locale The localization services instance.
   * @param colors An array with definitions of colors to be displayed in the table.
   * @param columns The number of columns in the color grid.
   * @param removeButtonLabel The label of the button responsible for removing the color.
   * @param colorPickerLabel The label of the button responsible for color picker appearing.
   * @param documentColorsLabel The label for the section with the document colors.
   * @param documentColorsCount The number of colors in the document colors section inside the color dropdown.
   * @param colorPickerConfig The configuration of color picker feature.
   */
  constructor(e, { colors: t, columns: i, removeButtonLabel: s, documentColorsLabel: r, documentColorsCount: o, colorPickerLabel: a, colorPickerConfig: l }) {
    super(e), this.items = this.createCollection(), this.focusTracker = new ye(), this.keystrokes = new Oe(), this._focusables = new nt(), this._colorPickerConfig = l, this._focusCycler = new Ft({
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate list items backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke.
        focusPrevious: "shift + tab",
        // Navigate list items forwards using the <kbd>Tab</kbd> key.
        focusNext: "tab"
      }
    }), this.colorGridsPageView = new aT(e, {
      colors: t,
      columns: i,
      removeButtonLabel: s,
      documentColorsLabel: r,
      documentColorsCount: o,
      colorPickerLabel: a,
      focusTracker: this.focusTracker,
      focusables: this._focusables
    }), this.colorPickerPageView = new lT(e, {
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokes: this.keystrokes,
      colorPickerConfig: l
    }), this.set("_isColorGridsPageVisible", !0), this.set("_isColorPickerPageVisible", !1), this.set("selectedColor", void 0), this.colorGridsPageView.bind("isVisible").to(this, "_isColorGridsPageVisible"), this.colorPickerPageView.bind("isVisible").to(this, "_isColorPickerPageVisible"), this.on("change:selectedColor", (c, u, h) => {
      this.colorGridsPageView.set("selectedColor", h), this.colorPickerPageView.set("selectedColor", h);
    }), this.colorGridsPageView.on("change:selectedColor", (c, u, h) => {
      this.set("selectedColor", h);
    }), this.colorPickerPageView.on("change:selectedColor", (c, u, h) => {
      this.set("selectedColor", h);
    }), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-color-table"
        ]
      },
      children: this.items
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.keystrokes.listenTo(this.element);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Appends static and document color grid views.
   */
  appendGrids() {
    this.items.length || (this.items.add(this.colorGridsPageView), this.colorGridsPageView.delegate("execute").to(this), this.colorGridsPageView.delegate("showColorPicker").to(this));
  }
  /**
   * Renders UI in dropdown. Which sub-components are rendered
   * depends on the component configuration.
   */
  appendUI() {
    this.appendGrids(), this._colorPickerConfig && this._appendColorPicker();
  }
  /**
   * Show "Color picker" and hide "Color grids".
   */
  showColorPicker() {
    this.colorPickerPageView.colorPickerView && (this.set("_isColorPickerPageVisible", !0), this.colorPickerPageView.focus(), this.set("_isColorGridsPageVisible", !1));
  }
  /**
   * Show "Color grids" and hide "Color picker".
   */
  showColorGrids() {
    this.set("_isColorGridsPageVisible", !0), this.set("_isColorPickerPageVisible", !1);
  }
  /**
   * Focuses the first focusable element in {@link #items}.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * Focuses the last focusable element in {@link #items}.
   */
  focusLast() {
    this._focusCycler.focusLast();
  }
  /**
   * Scans through the editor model and searches for text node attributes with the given attribute name.
   * Found entries are set as document colors.
   *
   * All the previously stored document colors will be lost in the process.
   *
   * @param model The model used as a source to obtain the document colors.
   * @param attributeName Determines the name of the related model's attribute for a given dropdown.
   */
  updateDocumentColors(e, t) {
    this.colorGridsPageView.updateDocumentColors(e, t);
  }
  /**
   * Refreshes the state of the selected color in one or both {@link module:ui/colorgrid/colorgridview~ColorGridView}s
   * available in the {@link module:font/ui/colortableview~ColorTableView}. It guarantees that the selection will occur only in one
   * of them.
   */
  updateSelectedColors() {
    this.colorGridsPageView.updateSelectedColors();
  }
  /**
   * Appends the color picker view.
   */
  _appendColorPicker() {
    this.items.length !== 2 && (this.items.add(this.colorPickerPageView), this.colorGridsPageView.colorPickerButtonView && this.colorGridsPageView.colorPickerButtonView.on("execute", () => {
      this.showColorPicker();
    }), this.colorGridsPageView.addColorPickerButton(), this.colorPickerPageView.delegate("execute").to(this), this.colorPickerPageView.delegate("cancel").to(this));
  }
}
class aT extends T {
  /**
   * Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.
   *
   * @param locale The localization services instance.
   * @param colors An array with definitions of colors to be displayed in the table.
   * @param columns The number of columns in the color grid.
   * @param removeButtonLabel The label of the button responsible for removing the color.
   * @param colorPickerLabel The label of the button responsible for color picker appearing.
   * @param documentColorsLabel The label for the section with the document colors.
   * @param documentColorsCount The number of colors in the document colors section inside the color dropdown.
   * @param focusTracker Tracks information about the DOM focus in the list.
   * @param focusables A collection of views that can be focused in the view.
   */
  constructor(e, { colors: t, columns: i, removeButtonLabel: s, documentColorsLabel: r, documentColorsCount: o, colorPickerLabel: a, focusTracker: l, focusables: c }) {
    super(e);
    const u = this.bindTemplate;
    this.set("isVisible", !0), this.focusTracker = l, this.items = this.createCollection(), this.colorDefinitions = t, this.columns = i, this.documentColors = new rT(), this.documentColorsCount = o, this._focusables = c, this._removeButtonLabel = s, this._colorPickerLabel = a, this._documentColorsLabel = r, this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck-color-grids-page-view",
          u.if("isVisible", "ck-hidden", (h) => !h)
        ]
      },
      children: this.items
    }), this.removeColorButtonView = this._createRemoveColorButton(), this.items.add(this.removeColorButtonView);
  }
  /**
   * Scans through the editor model and searches for text node attributes with the given attribute name.
   * Found entries are set as document colors.
   *
   * All the previously stored document colors will be lost in the process.
   *
   * @param model The model used as a source to obtain the document colors.
   * @param attributeName Determines the name of the related model's attribute for a given dropdown.
   */
  updateDocumentColors(e, t) {
    const i = e.document, s = this.documentColorsCount;
    this.documentColors.clear();
    for (const r of i.getRootNames()) {
      const o = i.getRoot(r), a = e.createRangeIn(o);
      for (const l of a.getItems())
        if (l.is("$textProxy") && l.hasAttribute(t) && (this._addColorToDocumentColors(l.getAttribute(t)), this.documentColors.length >= s))
          return;
    }
  }
  /**
   * Refreshes the state of the selected color in one or both {@link module:ui/colorgrid/colorgridview~ColorGridView}s
   * available in the {@link module:font/ui/colortableview~ColorTableView}. It guarantees that the selection will occur only in one
   * of them.
   */
  updateSelectedColors() {
    const e = this.documentColorsGrid, t = this.staticColorsGrid, i = this.selectedColor;
    t.selectedColor = i, e && (e.selectedColor = i);
  }
  /**
   * @inheritDoc
   */
  render() {
    if (super.render(), this.staticColorsGrid = this._createStaticColorsGrid(), this.items.add(this.staticColorsGrid), this.documentColorsCount) {
      const e = Ce.bind(this.documentColors, this.documentColors), t = new Nh(this.locale);
      t.text = this._documentColorsLabel, t.extendTemplate({
        attributes: {
          class: [
            "ck",
            "ck-color-grid__label",
            e.if("isEmpty", "ck-hidden")
          ]
        }
      }), this.items.add(t), this.documentColorsGrid = this._createDocumentColorsGrid(), this.items.add(this.documentColorsGrid);
    }
    this._createColorPickerButton(), this._addColorTablesElementsToFocusTracker(), this.focus();
  }
  /**
   * Focuses the component.
   */
  focus() {
    this.removeColorButtonView.focus();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy();
  }
  /**
   * Handles displaying the color picker button (if it was previously created) and making it focusable.
   */
  addColorPickerButton() {
    this.colorPickerButtonView && (this.items.add(this.colorPickerButtonView), this.focusTracker.add(this.colorPickerButtonView.element), this._focusables.add(this.colorPickerButtonView));
  }
  /**
   * Adds color table elements to focus tracker.
   */
  _addColorTablesElementsToFocusTracker() {
    this.focusTracker.add(this.removeColorButtonView.element), this._focusables.add(this.removeColorButtonView), this.staticColorsGrid && (this.focusTracker.add(this.staticColorsGrid.element), this._focusables.add(this.staticColorsGrid)), this.documentColorsGrid && (this.focusTracker.add(this.documentColorsGrid.element), this._focusables.add(this.documentColorsGrid));
  }
  /**
   * Creates the button responsible for displaying the color picker component.
   */
  _createColorPickerButton() {
    this.colorPickerButtonView = new H(), this.colorPickerButtonView.set({
      label: this._colorPickerLabel,
      withText: !0,
      icon: oE.colorPaletteIcon,
      class: "ck-color-table__color-picker"
    }), this.colorPickerButtonView.on("execute", () => {
      this.fire("showColorPicker");
    });
  }
  /**
   * Adds the remove color button as a child of the current view.
   */
  _createRemoveColorButton() {
    const e = new H();
    return e.set({
      withText: !0,
      icon: D.eraser,
      label: this._removeButtonLabel
    }), e.class = "ck-color-table__remove-color", e.on("execute", () => {
      this.fire("execute", {
        value: null,
        source: "removeColorButton"
      });
    }), e.render(), e;
  }
  /**
   * Creates a static color table grid based on the editor configuration.
   */
  _createStaticColorsGrid() {
    const e = new Xa(this.locale, {
      colorDefinitions: this.colorDefinitions,
      columns: this.columns
    });
    return e.on("execute", (t, i) => {
      this.fire("execute", {
        value: i.value,
        source: "staticColorsGrid"
      });
    }), e;
  }
  /**
   * Creates the document colors section view and binds it to {@link #documentColors}.
   */
  _createDocumentColorsGrid() {
    const e = Ce.bind(this.documentColors, this.documentColors), t = new Xa(this.locale, {
      columns: this.columns
    });
    return t.extendTemplate({
      attributes: {
        class: e.if("isEmpty", "ck-hidden")
      }
    }), t.items.bindTo(this.documentColors).using((i) => {
      const s = new Sh();
      return s.set({
        color: i.color,
        hasBorder: i.options && i.options.hasBorder
      }), i.label && s.set({
        label: i.label,
        tooltip: !0
      }), s.on("execute", () => {
        this.fire("execute", {
          value: i.color,
          source: "documentColorsGrid"
        });
      }), s;
    }), this.documentColors.on("change:isEmpty", (i, s, r) => {
      r && (t.selectedColor = null);
    }), t;
  }
  /**
   * Adds a given color to the document colors list. If possible, the method will attempt to use
   * data from the {@link #colorDefinitions} (label, color options).
   *
   * @param color A string that stores the value of the recently applied color.
   */
  _addColorToDocumentColors(e) {
    const t = this.colorDefinitions.find((i) => i.color === e);
    t ? this.documentColors.add(Object.assign({}, t)) : this.documentColors.add({
      color: e,
      label: e,
      options: {
        hasBorder: !1
      }
    });
  }
}
class lT extends T {
  /**
   * @param locale The localization services instance.
   * @param focusTracker Tracks information about the DOM focus in the list.
   * @param focusables A collection of views that can be focused in the view..
   * @param keystrokes An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.
   * @param colorPickerConfig The configuration of color picker feature.
   */
  constructor(e, { focusTracker: t, focusables: i, keystrokes: s, colorPickerConfig: r }) {
    super(e), this.items = this.createCollection(), this.focusTracker = t, this.keystrokes = s, this.set("isVisible", !1), this.set("selectedColor", void 0), this._focusables = i, this._pickerConfig = r;
    const o = this.bindTemplate, { saveButtonView: a, cancelButtonView: l } = this._createActionButtons();
    this.saveButtonView = a, this.cancelButtonView = l, this.actionBarView = this._createActionBarView({ saveButtonView: a, cancelButtonView: l }), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck-color-picker-page-view",
          o.if("isVisible", "ck-hidden", (c) => !c)
        ]
      },
      children: this.items
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render();
    const e = new VC(this.locale, this._pickerConfig);
    this.colorPickerView = e, this.colorPickerView.render(), this.selectedColor && (e.color = this.selectedColor), this.listenTo(this, "change:selectedColor", (t, i, s) => {
      e.color = s;
    }), this.items.add(this.colorPickerView), this.items.add(this.actionBarView), this._addColorPickersElementsToFocusTracker(), this._stopPropagationOnArrowsKeys(), this._executeOnEnterPress(), this._executeUponColorChange();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy();
  }
  /**
   * Focuses the color picker.
   */
  focus() {
    this.colorPickerView.focus();
  }
  /**
   * When color picker is focused and "enter" is pressed it executes command.
   */
  _executeOnEnterPress() {
    this.keystrokes.set("enter", (e) => {
      this.isVisible && this.focusTracker.focusedElement !== this.cancelButtonView.element && (this.fire("execute", {
        value: this.selectedColor
      }), e.stopPropagation(), e.preventDefault());
    });
  }
  /**
   * Removes default behavior of arrow keys in dropdown.
   */
  _stopPropagationOnArrowsKeys() {
    const e = (t) => t.stopPropagation();
    this.keystrokes.set("arrowright", e), this.keystrokes.set("arrowleft", e), this.keystrokes.set("arrowup", e), this.keystrokes.set("arrowdown", e);
  }
  /**
   * Adds color picker elements to focus tracker.
   */
  _addColorPickersElementsToFocusTracker() {
    for (const e of this.colorPickerView.slidersView)
      this.focusTracker.add(e.element), this._focusables.add(e);
    this.focusTracker.add(this.colorPickerView.hexInputRow.children.get(1).element), this._focusables.add(this.colorPickerView.hexInputRow.children.get(1)), this.focusTracker.add(this.saveButtonView.element), this._focusables.add(this.saveButtonView), this.focusTracker.add(this.cancelButtonView.element), this._focusables.add(this.cancelButtonView);
  }
  /**
   * Creates bar containing "Save" and "Cancel" buttons.
   */
  _createActionBarView({ saveButtonView: e, cancelButtonView: t }) {
    const i = new T(), s = this.createCollection();
    return s.add(e), s.add(t), i.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-color-table_action-bar"
        ]
      },
      children: s
    }), i;
  }
  /**
   * Creates "Save" and "Cancel" buttons.
   */
  _createActionButtons() {
    const e = this.locale, t = e.t, i = new H(e), s = new H(e);
    return i.set({
      icon: D.check,
      class: "ck-button-save",
      withText: !1,
      label: t("Accept"),
      type: "button"
    }), s.set({
      icon: D.cancel,
      class: "ck-button-cancel",
      withText: !1,
      label: t("Cancel")
    }), i.on("execute", () => {
      this.fire("execute", {
        source: "saveButton",
        value: this.selectedColor
      });
    }), s.on("execute", () => {
      this.fire("cancel");
    }), {
      saveButtonView: i,
      cancelButtonView: s
    };
  }
  /**
   * Fires the `execute` event if color in color picker changed.
   *
   * @fires execute
   */
  _executeUponColorChange() {
    this.colorPickerView.on("change:color", (e, t, i) => {
      this.fire("execute", {
        value: i,
        source: "colorPicker"
      });
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Be = "fontColor";
function cT(n) {
  return (e) => dT(e.getStyle(n));
}
function uT(n) {
  return (e, { writer: t }) => t.createAttributeElement("span", {
    style: `${n}:${e}`
  }, { priority: 7 });
}
function hT({ dropdownView: n, colors: e, columns: t, removeButtonLabel: i, colorPickerLabel: s, documentColorsLabel: r, documentColorsCount: o, colorPickerConfig: a }) {
  const l = n.locale, c = new oT(l, {
    colors: e,
    columns: t,
    removeButtonLabel: i,
    colorPickerLabel: s,
    documentColorsLabel: r,
    documentColorsCount: o,
    colorPickerConfig: a
  });
  return n.colorTableView = c, n.panelView.children.add(c), c;
}
function dT(n) {
  return n.replace(/\s/g, "");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class fT extends sT {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e, Be);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class mT extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "FontColorEditing";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define(Be, {
      colors: [
        {
          color: "hsl(0, 0%, 0%)",
          label: "Black"
        },
        {
          color: "hsl(0, 0%, 30%)",
          label: "Dim grey"
        },
        {
          color: "hsl(0, 0%, 60%)",
          label: "Grey"
        },
        {
          color: "hsl(0, 0%, 90%)",
          label: "Light grey"
        },
        {
          color: "hsl(0, 0%, 100%)",
          label: "White",
          hasBorder: !0
        },
        {
          color: "hsl(0, 75%, 60%)",
          label: "Red"
        },
        {
          color: "hsl(30, 75%, 60%)",
          label: "Orange"
        },
        {
          color: "hsl(60, 75%, 60%)",
          label: "Yellow"
        },
        {
          color: "hsl(90, 75%, 60%)",
          label: "Light green"
        },
        {
          color: "hsl(120, 75%, 60%)",
          label: "Green"
        },
        {
          color: "hsl(150, 75%, 60%)",
          label: "Aquamarine"
        },
        {
          color: "hsl(180, 75%, 60%)",
          label: "Turquoise"
        },
        {
          color: "hsl(210, 75%, 60%)",
          label: "Light blue"
        },
        {
          color: "hsl(240, 75%, 60%)",
          label: "Blue"
        },
        {
          color: "hsl(270, 75%, 60%)",
          label: "Purple"
        }
      ],
      columns: 5
    }), e.conversion.for("upcast").elementToAttribute({
      view: {
        name: "span",
        styles: {
          color: /[\s\S]+/
        }
      },
      model: {
        key: Be,
        value: cT("color")
      }
    }), e.conversion.for("upcast").elementToAttribute({
      view: {
        name: "font",
        attributes: {
          color: /^#?\w+$/
        }
      },
      model: {
        key: Be,
        value: (t) => t.getAttribute("color")
      }
    }), e.conversion.for("downcast").attributeToElement({
      model: Be,
      view: uT("color")
    }), e.commands.add(Be, new fT(e)), e.model.schema.extend("$text", { allowAttributes: Be }), e.model.schema.setAttributeProperties(Be, {
      isFormatting: !0,
      copyOnEnter: !0
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class gT extends _ {
  /**
   * Creates a plugin which introduces a dropdown with a pre–configured {@link module:font/ui/colortableview~ColorTableView}.
   *
   * @param config The configuration object.
   * @param config.commandName The name of the command which will be executed when a color tile is clicked.
   * @param config.componentName The name of the dropdown in the {@link module:ui/componentfactory~ComponentFactory}
   * and the configuration scope name in `editor.config`.
   * @param config.icon The SVG icon used by the dropdown.
   * @param config.dropdownLabel The label used by the dropdown.
   */
  constructor(e, { commandName: t, componentName: i, icon: s, dropdownLabel: r }) {
    super(e), this.commandName = t, this.componentName = i, this.icon = s, this.dropdownLabel = r, this.columns = e.config.get(`${this.componentName}.columns`), this.colorTableView = void 0;
  }
  /**
  * @inheritDoc
  */
  init() {
    const e = this.editor, t = e.locale, i = t.t, s = e.commands.get(this.commandName), r = e.config.get(this.componentName), o = M2(r.colors), a = O2(t, o), l = r.documentColors, c = r.colorPicker !== !1;
    e.ui.componentFactory.add(this.componentName, (u) => {
      const h = gt(u);
      let f = !1;
      return this.colorTableView = hT({
        dropdownView: h,
        colors: a.map((m) => ({
          label: m.label,
          color: m.model,
          options: {
            hasBorder: m.hasBorder
          }
        })),
        columns: this.columns,
        removeButtonLabel: i("Remove color"),
        colorPickerLabel: i("Color picker"),
        documentColorsLabel: l !== 0 ? i("Document colors") : "",
        documentColorsCount: l === void 0 ? this.columns : l,
        colorPickerConfig: c ? r.colorPicker || {} : !1
      }), this.colorTableView.bind("selectedColor").to(s, "value"), h.buttonView.set({
        label: this.dropdownLabel,
        icon: this.icon,
        tooltip: !0
      }), h.extendTemplate({
        attributes: {
          class: "ck-color-ui-dropdown"
        }
      }), h.bind("isEnabled").to(s), this.colorTableView.on("execute", (m, p) => {
        h.isOpen && e.execute(this.commandName, {
          value: p.value,
          batch: this._undoStepBatch
        }), p.source !== "colorPicker" && e.editing.view.focus();
      }), this.colorTableView.on("showColorPicker", () => {
        this._undoStepBatch = e.model.createBatch();
      }), this.colorTableView.on("cancel", () => {
        this._undoStepBatch.operations.length && (h.isOpen = !1, e.execute("undo", this._undoStepBatch)), e.editing.view.focus();
      }), h.on("change:isOpen", (m, p, b) => {
        f || (f = !0, h.colorTableView.appendUI()), b ? (l !== 0 && this.colorTableView.updateDocumentColors(e.model, this.componentName), this.colorTableView.updateSelectedColors()) : this.colorTableView.showColorGrids();
      }), Yr(h, () => h.colorTableView.colorGridsPageView.staticColorsGrid.items.find((m) => m.isOn)), h;
    });
  }
}
const pT = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.4 10.3 10 4.5l-2.4 5.8h4.8zm.5 1.2H7.1L5.7 15H4.2l5-12h1.6l5 12h-1.5L13 11.5zm3.1 7H4a1 1 0 0 1 0-2h12a1 1 0 0 1 0 2z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class wT extends gT {
  /**
   * @inheritDoc
   */
  constructor(e) {
    const t = e.locale.t;
    super(e, {
      commandName: Be,
      componentName: Be,
      icon: pT,
      dropdownLabel: t("Font Color")
    });
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "FontColorUI";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class F5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [mT, wT];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "FontColor";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Ll(n, e) {
  const t = (i, s, r) => {
    if (!r.consumable.consume(s.item, i.name))
      return;
    const o = s.attributeNewValue, a = r.writer, l = r.mapper.toViewElement(s.item), c = [...l.getChildren()].find((h) => h.getCustomProperty("media-content"));
    a.remove(c);
    const u = n.getMediaViewElement(a, o, e);
    a.insert(a.createPositionAt(l, 0), u);
  };
  return (i) => {
    i.on("attribute:url:media", t);
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function bT(n, e, t) {
  return e.setCustomProperty("media", !0, n), io(n, e, { label: t });
}
function $l(n, e, t, i) {
  return n.createContainerElement("figure", { class: "media" }, [
    e.getMediaViewElement(n, t, i),
    n.createSlot()
  ]);
}
function zl(n) {
  const e = n.getSelectedElement();
  return e && e.is("element", "media") ? e : null;
}
function pd(n, e, t, i) {
  n.change((s) => {
    const r = s.createElement("media", { url: e });
    n.insertObject(r, t, null, {
      setSelection: "on",
      findOptimalPosition: i ? "auto" : void 0
    });
  });
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class _T extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document.selection, i = zl(t);
    this.value = i ? i.getAttribute("url") : void 0, this.isEnabled = yT(t) || vT(t, e);
  }
  /**
   * Executes the command, which either:
   *
   * * updates the URL of the selected media,
   * * inserts the new media into the editor and puts the selection around it.
   *
   * @fires execute
   * @param url The URL of the media.
   */
  execute(e) {
    const t = this.editor.model, i = t.document.selection, s = zl(i);
    s ? t.change((r) => {
      r.setAttribute("url", e, s);
    }) : pd(t, e, i, !0);
  }
}
function vT(n, e) {
  let i = ad(n, e).start.parent;
  return i.isEmpty && !e.schema.isLimit(i) && (i = i.parent), e.schema.checkChild(i, "media");
}
function yT(n) {
  const e = n.getSelectedElement();
  return !!e && e.name === "media";
}
const kT = '<svg viewBox="0 0 64 42" xmlns="http://www.w3.org/2000/svg"><path d="M47.426 17V3.713L63.102 0v19.389h-.001l.001.272c0 1.595-2.032 3.43-4.538 4.098-2.506.668-4.538-.083-4.538-1.678 0-1.594 2.032-3.43 4.538-4.098.914-.244 2.032-.565 2.888-.603V4.516L49.076 7.447v9.556A1.014 1.014 0 0 0 49 17h-1.574zM29.5 17h-8.343a7.073 7.073 0 1 0-4.657 4.06v3.781H3.3a2.803 2.803 0 0 1-2.8-2.804V8.63a2.803 2.803 0 0 1 2.8-2.805h4.082L8.58 2.768A1.994 1.994 0 0 1 10.435 1.5h8.985c.773 0 1.477.448 1.805 1.149l1.488 3.177H26.7c1.546 0 2.8 1.256 2.8 2.805V17zm-11.637 0H17.5a1 1 0 0 0-1 1v.05A4.244 4.244 0 1 1 17.863 17zm29.684 2c.97 0 .953-.048.953.889v20.743c0 .953.016.905-.953.905H19.453c-.97 0-.953.048-.953-.905V19.89c0-.937-.016-.889.97-.889h28.077zm-4.701 19.338V22.183H24.154v16.155h18.692zM20.6 21.375v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616v-1.616H20.6zm0 3.231v1.616h1.616V37.53H20.6zm24.233-16.155v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615v-1.616h-1.615zm0 3.231v1.616h1.615V37.53h-1.615zM29.485 25.283a.4.4 0 0 1 .593-.35l9.05 4.977a.4.4 0 0 1 0 .701l-9.05 4.978a.4.4 0 0 1-.593-.35v-9.956z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const CT = "0 0 64 42";
class ET {
  /**
   * Creates an instance of the {@link module:media-embed/mediaregistry~MediaRegistry} class.
   *
   * @param locale The localization services instance.
   * @param config The configuration of the media embed feature.
   */
  constructor(e, t) {
    const i = t.providers, s = t.extraProviders || [], r = new Set(t.removeProviders), o = i.concat(s).filter((a) => {
      const l = a.name;
      return l ? !r.has(l) : (q("media-embed-no-provider-name", { provider: a }), !1);
    });
    this.locale = e, this.providerDefinitions = o;
  }
  /**
   * Checks whether the passed URL is representing a certain media type allowed in the editor.
   *
   * @param url The URL to be checked
   */
  hasMedia(e) {
    return !!this._getMedia(e);
  }
  /**
   * For the given media URL string and options, it returns the {@link module:engine/view/element~Element view element}
   * representing that media.
   *
   * **Note:** If no URL is specified, an empty view element is returned.
   *
   * @param writer The view writer used to produce a view element.
   * @param url The URL to be translated into a view element.
   */
  getMediaViewElement(e, t, i) {
    return this._getMedia(t).getViewElement(e, i);
  }
  /**
   * Returns a `Media` instance for the given URL.
   *
   * @param url The URL of the media.
   * @returns The `Media` instance or `null` when there is none.
   */
  _getMedia(e) {
    if (!e)
      return new Hl(this.locale);
    e = e.trim();
    for (const t of this.providerDefinitions) {
      const i = t.html, s = X(t.url);
      for (const r of s) {
        const o = this._getUrlMatches(e, r);
        if (o)
          return new Hl(this.locale, e, o, i);
      }
    }
    return null;
  }
  /**
   * Tries to match `url` to `pattern`.
   *
   * @param url The URL of the media.
   * @param pattern The pattern that should accept the media URL.
   */
  _getUrlMatches(e, t) {
    let i = e.match(t);
    if (i)
      return i;
    let s = e.replace(/^https?:\/\//, "");
    return i = s.match(t), i || (s = s.replace(/^www\./, ""), i = s.match(t), i) ? i : null;
  }
}
class Hl {
  constructor(e, t, i, s) {
    this.url = this._getValidUrl(t), this._locale = e, this._match = i, this._previewRenderer = s;
  }
  /**
   * Returns the view element representation of the media.
   *
   * @param writer The view writer used to produce a view element.
   */
  getViewElement(e, t) {
    const i = {};
    let s;
    if (t.renderForEditingView || t.renderMediaPreview && this.url && this._previewRenderer) {
      this.url && (i["data-oembed-url"] = this.url), t.renderForEditingView && (i.class = "ck-media__wrapper");
      const r = this._getPreviewHtml(t);
      s = e.createRawElement("div", i, (o, a) => {
        a.setContentOf(o, r);
      });
    } else
      this.url && (i.url = this.url), s = e.createEmptyElement(t.elementName, i);
    return e.setCustomProperty("media-content", !0, s), s;
  }
  /**
   * Returns the HTML string of the media content preview.
   */
  _getPreviewHtml(e) {
    return this._previewRenderer ? this._previewRenderer(this._match) : this.url && e.renderForEditingView ? this._getPlaceholderHtml() : "";
  }
  /**
   * Returns the placeholder HTML when the media has no content preview.
   */
  _getPlaceholderHtml() {
    const e = new mt(), t = this._locale.t;
    return e.content = kT, e.viewBox = CT, new Ce({
      tag: "div",
      attributes: {
        class: "ck ck-reset_all ck-media__placeholder"
      },
      children: [
        {
          tag: "div",
          attributes: {
            class: "ck-media__placeholder__icon"
          },
          children: [e]
        },
        {
          tag: "a",
          attributes: {
            class: "ck-media__placeholder__url",
            target: "_blank",
            rel: "noopener noreferrer",
            href: this.url,
            "data-cke-tooltip-text": t("Open media in new tab")
          },
          children: [
            {
              tag: "span",
              attributes: {
                class: "ck-media__placeholder__url__text"
              },
              children: [this.url]
            }
          ]
        }
      ]
    }).render().outerHTML;
  }
  /**
   * Returns the full URL to the specified media.
   *
   * @param url The URL of the media.
   */
  _getValidUrl(e) {
    return e ? e.match(/^https?/) ? e : "https://" + e : null;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class An extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "MediaEmbedEditing";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define("mediaEmbed", {
      elementName: "oembed",
      providers: [
        {
          name: "dailymotion",
          url: /^dailymotion\.com\/video\/(\w+)/,
          html: (t) => `<div style="position: relative; padding-bottom: 100%; height: 0; "><iframe src="https://www.dailymotion.com/embed/video/${t[1]}" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" width="480" height="270" allowfullscreen allow="autoplay"></iframe></div>`
        },
        {
          name: "spotify",
          url: [
            /^open\.spotify\.com\/(artist\/\w+)/,
            /^open\.spotify\.com\/(album\/\w+)/,
            /^open\.spotify\.com\/(track\/\w+)/
          ],
          html: (t) => `<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 126%;"><iframe src="https://open.spotify.com/embed/${t[1]}" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" allowtransparency="true" allow="encrypted-media"></iframe></div>`
        },
        {
          name: "youtube",
          url: [
            /^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)(?:&t=(\d+))?/,
            /^(?:m\.)?youtube\.com\/v\/([\w-]+)(?:\?t=(\d+))?/,
            /^youtube\.com\/embed\/([\w-]+)(?:\?start=(\d+))?/,
            /^youtu\.be\/([\w-]+)(?:\?t=(\d+))?/
          ],
          html: (t) => {
            const i = t[1], s = t[2];
            return `<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;"><iframe src="https://www.youtube.com/embed/${i}${s ? `?start=${s}` : ""}" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe></div>`;
          }
        },
        {
          name: "vimeo",
          url: [
            /^vimeo\.com\/(\d+)/,
            /^vimeo\.com\/[^/]+\/[^/]+\/video\/(\d+)/,
            /^vimeo\.com\/album\/[^/]+\/video\/(\d+)/,
            /^vimeo\.com\/channels\/[^/]+\/(\d+)/,
            /^vimeo\.com\/groups\/[^/]+\/videos\/(\d+)/,
            /^vimeo\.com\/ondemand\/[^/]+\/(\d+)/,
            /^player\.vimeo\.com\/video\/(\d+)/
          ],
          html: (t) => `<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;"><iframe src="https://player.vimeo.com/video/${t[1]}" style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>`
        },
        {
          name: "instagram",
          url: /^instagram\.com\/p\/(\w+)/
        },
        {
          name: "twitter",
          url: /^twitter\.com/
        },
        {
          name: "googleMaps",
          url: [
            /^google\.com\/maps/,
            /^goo\.gl\/maps/,
            /^maps\.google\.com/,
            /^maps\.app\.goo\.gl/
          ]
        },
        {
          name: "flickr",
          url: /^flickr\.com/
        },
        {
          name: "facebook",
          url: /^facebook\.com/
        }
      ]
    }), this.registry = new ET(e.locale, e.config.get("mediaEmbed"));
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model.schema, i = e.t, s = e.conversion, r = e.config.get("mediaEmbed.previewsInData"), o = e.config.get("mediaEmbed.elementName"), a = this.registry;
    e.commands.add("mediaEmbed", new _T(e)), t.register("media", {
      inheritAllFrom: "$blockObject",
      allowAttributes: ["url"]
    }), s.for("dataDowncast").elementToStructure({
      model: "media",
      view: (l, { writer: c }) => {
        const u = l.getAttribute("url");
        return $l(c, a, u, {
          elementName: o,
          renderMediaPreview: !!u && r
        });
      }
    }), s.for("dataDowncast").add(Ll(a, {
      elementName: o,
      renderMediaPreview: r
    })), s.for("editingDowncast").elementToStructure({
      model: "media",
      view: (l, { writer: c }) => {
        const u = l.getAttribute("url"), h = $l(c, a, u, {
          elementName: o,
          renderForEditingView: !0
        });
        return bT(h, c, i("media widget"));
      }
    }), s.for("editingDowncast").add(Ll(a, {
      elementName: o,
      renderForEditingView: !0
    })), s.for("upcast").elementToElement({
      view: (l) => ["oembed", o].includes(l.name) && l.getAttribute("url") ? { name: !0 } : null,
      model: (l, { writer: c }) => {
        const u = l.getAttribute("url");
        return a.hasMedia(u) ? c.createElement("media", { url: u }) : null;
      }
    }).elementToElement({
      view: {
        name: "div",
        attributes: {
          "data-oembed-url": !0
        }
      },
      model: (l, { writer: c }) => {
        const u = l.getAttribute("data-oembed-url");
        return a.hasMedia(u) ? c.createElement("media", { url: u }) : null;
      }
    }).add((l) => {
      const c = (u, h, f) => {
        if (!f.consumable.consume(h.viewItem, { name: !0, classes: "media" }))
          return;
        const { modelRange: m, modelCursor: p } = f.convertChildren(h.viewItem, h.modelCursor);
        h.modelRange = m, h.modelCursor = p, Te(m.getItems()) || f.consumable.revert(h.viewItem, { name: !0, classes: "media" });
      };
      l.on("element:figure", c);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const AT = /^(?:http(s)?:\/\/)?[\w-]+\.[\w-.~:/?#[\]@!$&'()*+,;=%]+$/;
class TT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ud, ai, dd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "AutoMediaEmbed";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._timeoutId = null, this._positionToInsert = null;
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model.document, i = e.plugins.get("ClipboardPipeline");
    this.listenTo(i, "inputTransformation", () => {
      const r = t.selection.getFirstRange(), o = re.fromPosition(r.start);
      o.stickiness = "toPrevious";
      const a = re.fromPosition(r.end);
      a.stickiness = "toNext", t.once("change:data", () => {
        this._embedMediaBetweenPositions(o, a), o.detach(), a.detach();
      }, { priority: "high" });
    }), e.commands.get("undo").on("execute", () => {
      this._timeoutId && (I.window.clearTimeout(this._timeoutId), this._positionToInsert.detach(), this._timeoutId = null, this._positionToInsert = null);
    }, { priority: "high" });
  }
  /**
   * Analyzes the part of the document between provided positions in search for a URL representing media.
   * When the URL is found, it is automatically converted into media.
   *
   * @param leftPosition Left position of the selection.
   * @param rightPosition Right position of the selection.
   */
  _embedMediaBetweenPositions(e, t) {
    const i = this.editor, s = i.plugins.get(An).registry, r = new ze(e, t), o = r.getWalker({ ignoreElementEnd: !0 });
    let a = "";
    for (const c of o)
      c.item.is("$textProxy") && (a += c.item.data);
    if (a = a.trim(), !a.match(AT)) {
      r.detach();
      return;
    }
    if (!s.hasMedia(a)) {
      r.detach();
      return;
    }
    if (!i.commands.get("mediaEmbed").isEnabled) {
      r.detach();
      return;
    }
    this._positionToInsert = re.fromPosition(e), this._timeoutId = I.window.setTimeout(() => {
      i.model.change((c) => {
        this._timeoutId = null, c.remove(r), r.detach();
        let u = null;
        this._positionToInsert.root.rootName !== "$graveyard" && (u = this._positionToInsert), pd(i.model, a, u, !1), this._positionToInsert.detach(), this._positionToInsert = null;
      }), i.plugins.get(ai).requestUndoOnBackspace();
    }, 100);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class PT extends T {
  /**
   * @param validators Form validators used by {@link #isValid}.
   * @param locale The localization services instance.
   */
  constructor(e, t) {
    super(t);
    const i = t.t;
    this.focusTracker = new ye(), this.keystrokes = new Oe(), this.set("mediaURLInputValue", ""), this.urlInputView = this._createUrlInput(), this.saveButtonView = this._createButton(i("Save"), D.check, "ck-button-save"), this.saveButtonView.type = "submit", this.saveButtonView.bind("isEnabled").to(this, "mediaURLInputValue", (s) => !!s), this.cancelButtonView = this._createButton(i("Cancel"), D.cancel, "ck-button-cancel", "cancel"), this._focusables = new nt(), this._focusCycler = new Ft({
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate form fields backwards using the <kbd>Shift</kbd> + <kbd>Tab</kbd> keystroke.
        focusPrevious: "shift + tab",
        // Navigate form fields forwards using the <kbd>Tab</kbd> key.
        focusNext: "tab"
      }
    }), this._validators = e, this.setTemplate({
      tag: "form",
      attributes: {
        class: [
          "ck",
          "ck-media-form",
          "ck-responsive-form"
        ],
        tabindex: "-1"
      },
      children: [
        this.urlInputView,
        this.saveButtonView,
        this.cancelButtonView
      ]
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), qr({
      view: this
    }), [
      this.urlInputView,
      this.saveButtonView,
      this.cancelButtonView
    ].forEach((i) => {
      this._focusables.add(i), this.focusTracker.add(i.element);
    }), this.keystrokes.listenTo(this.element);
    const t = (i) => i.stopPropagation();
    this.keystrokes.set("arrowright", t), this.keystrokes.set("arrowleft", t), this.keystrokes.set("arrowup", t), this.keystrokes.set("arrowdown", t);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Focuses the fist {@link #_focusables} in the form.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * The native DOM `value` of the {@link #urlInputView} element.
   *
   * **Note**: Do not confuse it with the {@link module:ui/inputtext/inputtextview~InputTextView#value}
   * which works one way only and may not represent the actual state of the component in the DOM.
   */
  get url() {
    return this.urlInputView.fieldView.element.value.trim();
  }
  set url(e) {
    this.urlInputView.fieldView.element.value = e.trim();
  }
  /**
   * Validates the form and returns `false` when some fields are invalid.
   */
  isValid() {
    this.resetFormStatus();
    for (const e of this._validators) {
      const t = e(this);
      if (t)
        return this.urlInputView.errorText = t, !1;
    }
    return !0;
  }
  /**
   * Cleans up the supplementary error and information text of the {@link #urlInputView}
   * bringing them back to the state when the form has been displayed for the first time.
   *
   * See {@link #isValid}.
   */
  resetFormStatus() {
    this.urlInputView.errorText = null, this.urlInputView.infoText = this._urlInputViewInfoDefault;
  }
  /**
   * Creates a labeled input view.
   *
   * @returns Labeled input view instance.
   */
  _createUrlInput() {
    const e = this.locale.t, t = new $n(this.locale, Hn), i = t.fieldView;
    return this._urlInputViewInfoDefault = e("Paste the media URL in the input."), this._urlInputViewInfoTip = e("Tip: Paste the URL into the content to embed faster."), t.label = e("Media URL"), t.infoText = this._urlInputViewInfoDefault, i.on("input", () => {
      t.infoText = i.element.value ? this._urlInputViewInfoTip : this._urlInputViewInfoDefault, this.mediaURLInputValue = i.element.value.trim();
    }), t;
  }
  /**
   * Creates a button view.
   *
   * @param label The button label.
   * @param icon The button icon.
   * @param className The additional button CSS class name.
   * @param eventName An event name that the `ButtonView#execute` event will be delegated to.
   * @returns The button view instance.
   */
  _createButton(e, t, i, s) {
    const r = new H(this.locale);
    return r.set({
      label: e,
      icon: t,
      tooltip: !0
    }), r.extendTemplate({
      attributes: {
        class: i
      }
    }), s && r.delegate("execute").to(this, s), r;
  }
}
const xT = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M18.68 3.03c.6 0 .59-.03.59.55v12.84c0 .59.01.56-.59.56H1.29c-.6 0-.59.03-.59-.56V3.58c0-.58-.01-.55.6-.55h17.38zM15.77 15V5H4.2v10h11.57zM2 4v1h1V4H2zm0 2v1h1V6H2zm0 2v1h1V8H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zm0 2v1h1v-1H2zM17 4v1h1V4h-1zm0 2v1h1V6h-1zm0 2v1h1V8h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zm0 2v1h1v-1h-1zM7.5 7.177a.4.4 0 0 1 .593-.351l5.133 2.824a.4.4 0 0 1 0 .7l-5.133 2.824a.4.4 0 0 1-.593-.35V7.176v.001z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ST extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [An];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "MediaEmbedUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.commands.get("mediaEmbed");
    e.ui.componentFactory.add("mediaEmbed", (i) => {
      const s = gt(i);
      return this._setUpDropdown(s, t), s;
    });
  }
  _setUpDropdown(e, t) {
    const i = this.editor, s = i.t, r = e.buttonView, o = i.plugins.get(An).registry;
    e.once("change:isOpen", () => {
      const a = new (jr(PT))(IT(i.t, o), i.locale);
      e.panelView.children.add(a), r.on("open", () => {
        a.disableCssTransitions(), a.url = t.value || "", a.urlInputView.fieldView.select(), a.enableCssTransitions();
      }, { priority: "low" }), e.on("submit", () => {
        a.isValid() && (i.execute("mediaEmbed", a.url), i.editing.view.focus());
      }), e.on("change:isOpen", () => a.resetFormStatus()), e.on("cancel", () => {
        i.editing.view.focus();
      }), a.delegate("submit", "cancel").to(e), a.urlInputView.fieldView.bind("value").to(t, "value"), a.urlInputView.bind("isEnabled").to(t, "isEnabled");
    }), e.bind("isEnabled").to(t), r.set({
      label: s("Insert media"),
      icon: xT,
      tooltip: !0
    });
  }
}
function IT(n, e) {
  return [
    (t) => {
      if (!t.url.length)
        return n("The URL must not be empty.");
    },
    (t) => {
      if (!e.hasMedia(t.url))
        return n("This media URL is not supported.");
    }
  ];
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class N5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [An, ST, TT, Wi];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "MediaEmbed";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function It(n, e, t, i) {
  e && RT(n, e, i), t && Je(n, t, i);
}
function Je(n, e, t) {
  if (e.attributes)
    for (const [i, s] of Object.entries(e.attributes))
      n.setAttribute(i, s, t);
  e.styles && n.setStyle(e.styles, t), e.classes && n.addClass(e.classes, t);
}
function RT(n, e, t) {
  if (e.attributes)
    for (const [i] of Object.entries(e.attributes))
      n.removeAttribute(i, t);
  if (e.styles)
    for (const i of Object.keys(e.styles))
      n.removeStyle(i, t);
  e.classes && n.removeClass(e.classes, t);
}
function OT(n, e) {
  const t = tt(n);
  let i = "attributes";
  for (i in e)
    i == "classes" ? t[i] = Array.from(/* @__PURE__ */ new Set([...n[i] || [], ...e[i]])) : t[i] = { ...n[i], ...e[i] };
  return t;
}
function Wt(n, e, t, i, s) {
  const r = e.getAttribute(t), o = {};
  for (const a of ["attributes", "styles", "classes"]) {
    if (a != i) {
      r && r[a] && (o[a] = r[a]);
      continue;
    }
    if (i == "classes") {
      const c = new Set(r && r.classes || []);
      s(c), c.size && (o[a] = Array.from(c));
      continue;
    }
    const l = new Map(Object.entries(r && r[a] || {}));
    s(l), l.size && (o[a] = Object.fromEntries(l));
  }
  Object.keys(o).length ? e.is("documentSelection") ? n.setSelectionAttribute(t, o) : n.setAttribute(t, o, e) : r && (e.is("documentSelection") ? n.removeSelectionAttribute(t) : n.removeAttribute(t, e));
}
function MT(n) {
  return a_(n).replace(/ /g, "");
}
function Ee(n) {
  return `html${MT(n)}Attributes`;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function oo({ model: n }) {
  return (e, t) => t.writer.createElement(n, {
    htmlContent: e.getCustomProperty("$rawContent")
  });
}
function VT(n, { view: e, isInline: t }) {
  const i = n.t;
  return (s, { writer: r }) => {
    const o = i("HTML object"), a = Un(e, s, r), l = s.getAttribute(Ee(e));
    r.addClass("html-object-embed__content", a), l && Je(r, l, a);
    const c = r.createContainerElement(t ? "span" : "div", {
      class: "html-object-embed",
      "data-html-object-embed-label": o
    }, a);
    return io(c, r, { label: o });
  };
}
function Un(n, e, t) {
  return t.createRawElement(n, null, (i, s) => {
    s.setContentOf(i, e.getAttribute("htmlContent"));
  });
}
function DT({ view: n, model: e }, t) {
  return (i) => {
    i.on(`element:${n}`, (s, r, o) => {
      let a = t.processViewAttributes(r.viewItem, o);
      if (!(!a && !o.consumable.test(r.viewItem, { name: !0 }))) {
        a = a || {}, o.consumable.consume(r.viewItem, { name: !0 }), r.modelRange || (r = Object.assign(r, o.convertChildren(r.viewItem, r.modelCursor)));
        for (const l of r.modelRange.getItems())
          if (o.schema.checkAttribute(l, e)) {
            const c = l.getAttribute(e), u = OT(a, c || {});
            o.writer.setAttribute(e, u, l);
          }
      }
    }, { priority: "low" });
  };
}
function BT({ priority: n, view: e }) {
  return (t, i) => {
    if (!t)
      return;
    const { writer: s } = i, r = s.createAttributeElement(e, null, { priority: n });
    return Je(s, t, r), r;
  };
}
function Li({ view: n }, e) {
  return (t) => {
    t.on(`element:${n}`, (i, s, r) => {
      if (!s.modelRange || s.modelRange.isCollapsed)
        return;
      const o = e.processViewAttributes(s.viewItem, r);
      o && r.writer.setAttribute(Ee(s.viewItem.name), o, s.modelRange);
    }, { priority: "low" });
  };
}
function $i({ view: n, model: e }) {
  return (t) => {
    t.on(`attribute:${Ee(n)}:${e}`, (i, s, r) => {
      if (!r.consumable.consume(s.item, i.name))
        return;
      const { attributeOldValue: o, attributeNewValue: a } = s, l = r.writer, c = r.mapper.toViewElement(s.item);
      It(l, o, a, c);
    });
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Wl = {
  block: [
    // Existing features.
    {
      model: "codeBlock",
      view: "pre"
    },
    {
      model: "paragraph",
      view: "p"
    },
    {
      model: "blockQuote",
      view: "blockquote"
    },
    {
      model: "listItem",
      view: "li"
    },
    {
      model: "pageBreak",
      view: "div"
    },
    {
      model: "rawHtml",
      view: "div"
    },
    {
      model: "table",
      view: "table"
    },
    {
      model: "tableRow",
      view: "tr"
    },
    {
      model: "tableCell",
      view: "td"
    },
    {
      model: "tableCell",
      view: "th"
    },
    {
      model: "tableColumnGroup",
      view: "colgroup"
    },
    {
      model: "tableColumn",
      view: "col"
    },
    {
      model: "caption",
      view: "caption"
    },
    {
      model: "caption",
      view: "figcaption"
    },
    {
      model: "imageBlock",
      view: "img"
    },
    {
      model: "imageInline",
      view: "img"
    },
    // Compatibility features.
    {
      model: "htmlP",
      view: "p",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlBlockquote",
      view: "blockquote",
      modelSchema: {
        inheritAllFrom: "$container"
      }
    },
    {
      model: "htmlTable",
      view: "table",
      modelSchema: {
        allowWhere: "$block",
        isBlock: !0
      }
    },
    {
      model: "htmlTbody",
      view: "tbody",
      modelSchema: {
        allowIn: "htmlTable",
        isBlock: !1
      }
    },
    {
      model: "htmlThead",
      view: "thead",
      modelSchema: {
        allowIn: "htmlTable",
        isBlock: !1
      }
    },
    {
      model: "htmlTfoot",
      view: "tfoot",
      modelSchema: {
        allowIn: "htmlTable",
        isBlock: !1
      }
    },
    {
      model: "htmlCaption",
      view: "caption",
      modelSchema: {
        allowIn: "htmlTable",
        allowChildren: "$text",
        isBlock: !1
      }
    },
    {
      model: "htmlColgroup",
      view: "colgroup",
      modelSchema: {
        allowIn: "htmlTable",
        allowChildren: "col",
        isBlock: !1
      }
    },
    {
      model: "htmlCol",
      view: "col",
      modelSchema: {
        allowIn: "htmlColgroup",
        isBlock: !1
      }
    },
    {
      model: "htmlTr",
      view: "tr",
      modelSchema: {
        allowIn: ["htmlTable", "htmlThead", "htmlTbody"],
        isLimit: !0
      }
    },
    // TODO can also include text.
    {
      model: "htmlTd",
      view: "td",
      modelSchema: {
        allowIn: "htmlTr",
        allowContentOf: "$container",
        isLimit: !0,
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlTh",
      view: "th",
      modelSchema: {
        allowIn: "htmlTr",
        allowContentOf: "$container",
        isLimit: !0,
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlFigure",
      view: "figure",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include other block elements.
    {
      model: "htmlFigcaption",
      view: "figcaption",
      modelSchema: {
        allowIn: "htmlFigure",
        allowChildren: "$text",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlAddress",
      view: "address",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlAside",
      view: "aside",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlMain",
      view: "main",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlDetails",
      view: "details",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    {
      model: "htmlSummary",
      view: "summary",
      modelSchema: {
        allowChildren: "$text",
        allowIn: "htmlDetails",
        isBlock: !1
      }
    },
    {
      model: "htmlDiv",
      view: "div",
      paragraphLikeModel: "htmlDivParagraph",
      modelSchema: {
        inheritAllFrom: "$container"
      }
    },
    // TODO can also include text.
    {
      model: "htmlFieldset",
      view: "fieldset",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include h1-h6.
    {
      model: "htmlLegend",
      view: "legend",
      modelSchema: {
        allowIn: "htmlFieldset",
        allowChildren: "$text"
      }
    },
    // TODO can also include text.
    {
      model: "htmlHeader",
      view: "header",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlFooter",
      view: "footer",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlForm",
      view: "form",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !0
      }
    },
    {
      model: "htmlHgroup",
      view: "hgroup",
      modelSchema: {
        allowChildren: [
          "htmlH1",
          "htmlH2",
          "htmlH3",
          "htmlH4",
          "htmlH5",
          "htmlH6"
        ],
        isBlock: !1
      }
    },
    {
      model: "htmlH1",
      view: "h1",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlH2",
      view: "h2",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlH3",
      view: "h3",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlH4",
      view: "h4",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlH5",
      view: "h5",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlH6",
      view: "h6",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "$htmlList",
      modelSchema: {
        allowWhere: "$container",
        allowChildren: ["$htmlList", "htmlLi"],
        isBlock: !1
      }
    },
    {
      model: "htmlDir",
      view: "dir",
      modelSchema: {
        inheritAllFrom: "$htmlList"
      }
    },
    {
      model: "htmlMenu",
      view: "menu",
      modelSchema: {
        inheritAllFrom: "$htmlList"
      }
    },
    {
      model: "htmlUl",
      view: "ul",
      modelSchema: {
        inheritAllFrom: "$htmlList"
      }
    },
    {
      model: "htmlOl",
      view: "ol",
      modelSchema: {
        inheritAllFrom: "$htmlList"
      }
    },
    // TODO can also include other block elements.
    {
      model: "htmlLi",
      view: "li",
      modelSchema: {
        allowIn: "$htmlList",
        allowChildren: "$text",
        isBlock: !1
      }
    },
    {
      model: "htmlPre",
      view: "pre",
      modelSchema: {
        inheritAllFrom: "$block"
      }
    },
    {
      model: "htmlArticle",
      view: "article",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    {
      model: "htmlSection",
      view: "section",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    // TODO can also include text.
    {
      model: "htmlNav",
      view: "nav",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    },
    {
      model: "htmlDivDl",
      view: "div",
      modelSchema: {
        allowChildren: ["htmlDt", "htmlDd"],
        allowIn: "htmlDl"
      }
    },
    {
      model: "htmlDl",
      view: "dl",
      modelSchema: {
        allowWhere: "$container",
        allowChildren: ["htmlDt", "htmlDd", "htmlDivDl"],
        isBlock: !1
      }
    },
    {
      model: "htmlDt",
      view: "dt",
      modelSchema: {
        allowChildren: "$block",
        isBlock: !1
      }
    },
    {
      model: "htmlDd",
      view: "dd",
      modelSchema: {
        allowChildren: "$block",
        isBlock: !1
      }
    },
    {
      model: "htmlCenter",
      view: "center",
      modelSchema: {
        inheritAllFrom: "$container",
        isBlock: !1
      }
    }
  ],
  inline: [
    // Existing features (attribute set on an existing model element).
    {
      model: "htmlLiAttributes",
      view: "li",
      appliesToBlock: !0,
      coupledAttribute: "listItemId"
    },
    {
      model: "htmlOlAttributes",
      view: "ol",
      appliesToBlock: !0,
      coupledAttribute: "listItemId"
    },
    {
      model: "htmlUlAttributes",
      view: "ul",
      appliesToBlock: !0,
      coupledAttribute: "listItemId"
    },
    {
      model: "htmlFigureAttributes",
      view: "figure",
      appliesToBlock: "table"
    },
    {
      model: "htmlTheadAttributes",
      view: "thead",
      appliesToBlock: "table"
    },
    {
      model: "htmlTbodyAttributes",
      view: "tbody",
      appliesToBlock: "table"
    },
    {
      model: "htmlFigureAttributes",
      view: "figure",
      appliesToBlock: "imageBlock"
    },
    // Compatibility features.
    {
      model: "htmlAcronym",
      view: "acronym",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlTt",
      view: "tt",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlFont",
      view: "font",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlTime",
      view: "time",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlVar",
      view: "var",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlBig",
      view: "big",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlSmall",
      view: "small",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlSamp",
      view: "samp",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlQ",
      view: "q",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlOutput",
      view: "output",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlKbd",
      view: "kbd",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlBdi",
      view: "bdi",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlBdo",
      view: "bdo",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlAbbr",
      view: "abbr",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlA",
      view: "a",
      priority: 5,
      coupledAttribute: "linkHref",
      attributeProperties: {
        copyOnEnter: !0
      }
    },
    {
      model: "htmlStrong",
      view: "strong",
      coupledAttribute: "bold",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlB",
      view: "b",
      coupledAttribute: "bold",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlI",
      view: "i",
      coupledAttribute: "italic",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlEm",
      view: "em",
      coupledAttribute: "italic",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlS",
      view: "s",
      coupledAttribute: "strikethrough",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    // TODO According to HTML-spec can behave as div-like element, although CKE4 only handles it as an inline element.
    {
      model: "htmlDel",
      view: "del",
      coupledAttribute: "strikethrough",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    // TODO According to HTML-spec can behave as div-like element, although CKE4 only handles it as an inline element.
    {
      model: "htmlIns",
      view: "ins",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlU",
      view: "u",
      coupledAttribute: "underline",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlSub",
      view: "sub",
      coupledAttribute: "subscript",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlSup",
      view: "sup",
      coupledAttribute: "superscript",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlCode",
      view: "code",
      coupledAttribute: "code",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlMark",
      view: "mark",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlSpan",
      view: "span",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlCite",
      view: "cite",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlLabel",
      view: "label",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    {
      model: "htmlDfn",
      view: "dfn",
      attributeProperties: {
        copyOnEnter: !0,
        isFormatting: !0
      }
    },
    // Objects.
    {
      model: "htmlObject",
      view: "object",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlIframe",
      view: "iframe",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlInput",
      view: "input",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlButton",
      view: "button",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlTextarea",
      view: "textarea",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlSelect",
      view: "select",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlVideo",
      view: "video",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlEmbed",
      view: "embed",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlOembed",
      view: "oembed",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlAudio",
      view: "audio",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlImg",
      view: "img",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlCanvas",
      view: "canvas",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    // TODO it could be probably represented as non-object element, although it has graphical representation,
    // so probably makes more sense to keep it as an object.
    {
      model: "htmlMeter",
      view: "meter",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    // TODO it could be probably represented as non-object element, although it has graphical representation,
    // so probably makes more sense to keep it as an object.
    {
      model: "htmlProgress",
      view: "progress",
      isObject: !0,
      modelSchema: {
        inheritAllFrom: "$inlineObject"
      }
    },
    {
      model: "htmlScript",
      view: "script",
      modelSchema: {
        allowWhere: ["$text", "$block"],
        isInline: !0
      }
    },
    {
      model: "htmlStyle",
      view: "style",
      modelSchema: {
        allowWhere: ["$text", "$block"],
        isInline: !0
      }
    },
    {
      model: "htmlCustomElement",
      view: "$customElement",
      modelSchema: {
        allowWhere: ["$text", "$block"],
        allowAttributesOf: "$inlineObject",
        isInline: !0
      }
    }
  ]
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ci extends _ {
  constructor() {
    super(...arguments), this._definitions = [];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "DataSchema";
  }
  /**
   * @inheritDoc
   */
  init() {
    for (const e of Wl.block)
      this.registerBlockElement(e);
    for (const e of Wl.inline)
      this.registerInlineElement(e);
  }
  /**
   * Add new data schema definition describing block element.
   */
  registerBlockElement(e) {
    this._definitions.push({ ...e, isBlock: !0 });
  }
  /**
   * Add new data schema definition describing inline element.
   */
  registerInlineElement(e) {
    this._definitions.push({ ...e, isInline: !0 });
  }
  /**
   * Updates schema definition describing block element with new properties.
   *
   * Creates new scheme if it doesn't exist.
   * Array properties are concatenated with original values.
   *
   * @param definition Definition update.
   */
  extendBlockElement(e) {
    this._extendDefinition({ ...e, isBlock: !0 });
  }
  /**
   * Updates schema definition describing inline element with new properties.
   *
   * Creates new scheme if it doesn't exist.
   * Array properties are concatenated with original values.
   *
   * @param definition Definition update.
   */
  extendInlineElement(e) {
    this._extendDefinition({ ...e, isInline: !0 });
  }
  /**
   * Returns all definitions matching the given view name.
   *
   * @param includeReferences Indicates if this method should also include definitions of referenced models.
   */
  getDefinitionsForView(e, t = !1) {
    const i = /* @__PURE__ */ new Set();
    for (const s of this._getMatchingViewDefinitions(e)) {
      if (t)
        for (const r of this._getReferences(s.model))
          i.add(r);
      i.add(s);
    }
    return i;
  }
  /**
   * Returns definitions matching the given model name.
   */
  getDefinitionsForModel(e) {
    return this._definitions.filter((t) => t.model == e);
  }
  /**
   * Returns definitions matching the given view name.
   */
  _getMatchingViewDefinitions(e) {
    return this._definitions.filter((t) => t.view && FT(e, t.view));
  }
  /**
   * Resolves all definition references registered for the given data schema definition.
   *
   * @param modelName Data schema model name.
   */
  *_getReferences(e) {
    const t = [
      "inheritAllFrom",
      "inheritTypesFrom",
      "allowWhere",
      "allowContentOf",
      "allowAttributesOf"
    ], i = this._definitions.filter((s) => s.model == e);
    for (const { modelSchema: s } of i)
      if (s)
        for (const r of t)
          for (const o of X(s[r] || [])) {
            const a = this._definitions.filter((l) => l.model == o);
            for (const l of a)
              o !== e && (yield* this._getReferences(l.model), yield l);
          }
  }
  /**
   * Updates schema definition with new properties.
   *
   * Creates new scheme if it doesn't exist.
   * Array properties are concatenated with original values.
   *
   * @param definition Definition update.
   */
  _extendDefinition(e) {
    const t = Array.from(this._definitions.entries()).filter(([, i]) => i.model == e.model);
    if (t.length == 0) {
      this._definitions.push(e);
      return;
    }
    for (const [i, s] of t)
      this._definitions[i] = j0({}, s, e, (r, o) => Array.isArray(r) ? r.concat(o) : void 0);
  }
}
function FT(n, e) {
  return typeof n == "string" ? n === e : n instanceof RegExp ? n.test(e) : !1;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ee extends _ {
  constructor(e) {
    super(e), this._dataSchema = e.plugins.get("DataSchema"), this._allowedAttributes = new ni(), this._disallowedAttributes = new ni(), this._allowedElements = /* @__PURE__ */ new Set(), this._disallowedElements = /* @__PURE__ */ new Set(), this._dataInitialized = !1, this._coupledAttributes = null, this._registerElementsAfterInit(), this._registerElementHandlers(), this._registerCoupledAttributesPostFixer(), this._registerAssociatedHtmlAttributesPostFixer();
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "DataFilter";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ci, Wi];
  }
  /**
   * Load a configuration of one or many elements, where their attributes should be allowed.
   *
   * **Note**: Rules will be applied just before next data pipeline data init or set.
   *
   * @param config Configuration of elements that should have their attributes accepted in the editor.
   */
  loadAllowedConfig(e) {
    for (const t of e) {
      const i = t.name || /[\s\S]+/, s = ql(t);
      this.allowElement(i), s.forEach((r) => this.allowAttributes(r));
    }
  }
  /**
   * Load a configuration of one or many elements, where their attributes should be disallowed.
   *
   * **Note**: Rules will be applied just before next data pipeline data init or set.
   *
   * @param config Configuration of elements that should have their attributes rejected from the editor.
   */
  loadDisallowedConfig(e) {
    for (const t of e) {
      const i = t.name || /[\s\S]+/, s = ql(t);
      s.length == 0 ? this.disallowElement(i) : s.forEach((r) => this.disallowAttributes(r));
    }
  }
  /**
   * Allow the given element in the editor context.
   *
   * This method will only allow elements described by the {@link module:html-support/dataschema~DataSchema} used
   * to create data filter.
   *
   * **Note**: Rules will be applied just before next data pipeline data init or set.
   *
   * @param viewName String or regular expression matching view name.
   */
  allowElement(e) {
    for (const t of this._dataSchema.getDefinitionsForView(e, !0))
      this._addAllowedElement(t), this._coupledAttributes = null;
  }
  /**
   * Disallow the given element in the editor context.
   *
   * This method will only disallow elements described by the {@link module:html-support/dataschema~DataSchema} used
   * to create data filter.
   *
   * @param viewName String or regular expression matching view name.
   */
  disallowElement(e) {
    for (const t of this._dataSchema.getDefinitionsForView(e, !1))
      this._disallowedElements.add(t.view);
  }
  /**
   * Allow the given attributes for view element allowed by {@link #allowElement} method.
   *
   * @param config Pattern matching all attributes which should be allowed.
   */
  allowAttributes(e) {
    this._allowedAttributes.add(e);
  }
  /**
   * Disallow the given attributes for view element allowed by {@link #allowElement} method.
   *
   * @param config Pattern matching all attributes which should be disallowed.
   */
  disallowAttributes(e) {
    this._disallowedAttributes.add(e);
  }
  /**
   * Processes all allowed and disallowed attributes on the view element by consuming them and returning the allowed ones.
   *
   * This method applies the configuration set up by {@link #allowAttributes `allowAttributes()`}
   * and {@link #disallowAttributes `disallowAttributes()`} over the given view element by consuming relevant attributes.
   * It returns the allowed attributes that were found on the given view element for further processing by integration code.
   *
   * ```ts
   * dispatcher.on( 'element:myElement', ( evt, data, conversionApi ) => {
   * 	// Get rid of disallowed and extract all allowed attributes from a viewElement.
   * 	const viewAttributes = dataFilter.processViewAttributes( data.viewItem, conversionApi );
   * 	// Do something with them, i.e. store inside a model as a dictionary.
   * 	if ( viewAttributes ) {
   * 		conversionApi.writer.setAttribute( 'htmlAttributesOfMyElement', viewAttributes, data.modelRange );
   * 	}
   * } );
   * ```
   *
   * @see module:engine/conversion/viewconsumable~ViewConsumable#consume
   *
   * @returns Object with following properties:
   * - attributes Set with matched attribute names.
   * - styles Set with matched style names.
   * - classes Set with matched class names.
   */
  processViewAttributes(e, t) {
    return Ul(e, t, this._disallowedAttributes), Ul(e, t, this._allowedAttributes);
  }
  /**
   * Adds allowed element definition and fires registration event.
   */
  _addAllowedElement(e) {
    if (!this._allowedElements.has(e)) {
      if (this._allowedElements.add(e), "appliesToBlock" in e && typeof e.appliesToBlock == "string")
        for (const t of this._dataSchema.getDefinitionsForModel(e.appliesToBlock))
          t.isBlock && this._addAllowedElement(t);
      this._dataInitialized && this.editor.data.once("set", () => {
        this._fireRegisterEvent(e);
      }, {
        // With the highest priority listener we are able to register elements right before
        // running data conversion.
        priority: be.highest + 1
      });
    }
  }
  /**
   * Registers elements allowed by {@link module:html-support/datafilter~DataFilter#allowElement} method
   * once {@link module:engine/controller/datacontroller~DataController editor's data controller} is initialized.
  */
  _registerElementsAfterInit() {
    this.editor.data.on("init", () => {
      this._dataInitialized = !0;
      for (const e of this._allowedElements)
        this._fireRegisterEvent(e);
    }, {
      // With highest priority listener we are able to register elements right before
      // running data conversion. Also:
      // * Make sure that priority is higher than the one used by `RealTimeCollaborationClient`,
      // as RTC is stopping event propagation.
      // * Make sure no other features hook into this event before GHS because otherwise the
      // downcast conversion (for these features) could run before GHS registered its converters
      // (https://github.com/ckeditor/ckeditor5/issues/11356).
      priority: be.highest + 1
    });
  }
  /**
   * Registers default element handlers.
   */
  _registerElementHandlers() {
    this.on("register", (e, t) => {
      const i = this.editor.model.schema;
      if (t.isObject && !i.isRegistered(t.model))
        this._registerObjectElement(t);
      else if (t.isBlock)
        this._registerBlockElement(t);
      else if (t.isInline)
        this._registerInlineElement(t);
      else
        throw new d("data-filter-invalid-definition", null, t);
      e.stop();
    }, { priority: "lowest" });
  }
  /**
   * Registers a model post-fixer that is removing coupled GHS attributes of inline elements. Those attributes
   * are removed if a coupled feature attribute is removed.
   *
   * For example, consider following HTML:
   *
   * ```html
   * <a href="foo.html" id="myId">bar</a>
   * ```
   *
   * Which would be upcasted to following text node in the model:
   *
   * ```html
   * <$text linkHref="foo.html" htmlA="{ attributes: { id: 'myId' } }">bar</$text>
   * ```
   *
   * When the user removes the link from that text (using UI), only `linkHref` attribute would be removed:
   *
   * ```html
   * <$text htmlA="{ attributes: { id: 'myId' } }">bar</$text>
   * ```
   *
   * The `htmlA` attribute would stay in the model and would cause GHS to generate an `<a>` element.
   * This is incorrect from UX point of view, as the user wanted to remove the whole link (not only `href`).
   */
  _registerCoupledAttributesPostFixer() {
    const e = this.editor.model;
    e.document.registerPostFixer((t) => {
      const i = e.document.differ.getChanges();
      let s = !1;
      const r = this._getCoupledAttributesMap();
      for (const o of i) {
        if (o.type != "attribute" || o.attributeNewValue !== null)
          continue;
        const a = r.get(o.attributeKey);
        if (a)
          for (const { item: l } of o.range.getWalker({ shallow: !0 }))
            for (const c of a)
              l.hasAttribute(c) && (t.removeAttribute(c, l), s = !0);
      }
      return s;
    });
  }
  /**
   * Removes `html*Attributes` attributes from incompatible elements.
   *
   * For example, consider the following HTML:
   *
   * ```html
   * <heading2 htmlH2Attributes="...">foobar[]</heading2>
   * ```
   *
   * Pressing `enter` creates a new `paragraph` element that inherits
   * the `htmlH2Attributes` attribute from `heading2`.
   *
   * ```html
   * <heading2 htmlH2Attributes="...">foobar</heading2>
   * <paragraph htmlH2Attributes="...">[]</paragraph>
   * ```
   *
   * This postfixer ensures that this doesn't happen, and that elements can
   * only have `html*Attributes` associated with them,
   * e.g.: `htmlPAttributes` for `<p>`, `htmlDivAttributes` for `<div>`, etc.
   *
   * With it enabled, pressing `enter` at the end of `<heading2>` will create
   * a new paragraph without the `htmlH2Attributes` attribute.
   *
   * ```html
   * <heading2 htmlH2Attributes="...">foobar</heading2>
   * <paragraph>[]</paragraph>
   * ```
   */
  _registerAssociatedHtmlAttributesPostFixer() {
    const e = this.editor.model;
    e.document.registerPostFixer((t) => {
      const i = e.document.differ.getChanges();
      let s = !1;
      for (const r of i)
        if (!(r.type !== "insert" || r.name === "$text"))
          for (const o of r.attributes.keys())
            !o.startsWith("html") || !o.endsWith("Attributes") || e.schema.checkAttribute(r.name, o) || (t.removeAttribute(o, r.position.nodeAfter), s = !0);
      return s;
    });
  }
  /**
   * Collects the map of coupled attributes. The returned map is keyed by the feature attribute name
   * and coupled GHS attribute names are stored in the value array.
   */
  _getCoupledAttributesMap() {
    if (this._coupledAttributes)
      return this._coupledAttributes;
    this._coupledAttributes = /* @__PURE__ */ new Map();
    for (const e of this._allowedElements)
      if (e.coupledAttribute && e.model) {
        const t = this._coupledAttributes.get(e.coupledAttribute);
        t ? t.push(e.model) : this._coupledAttributes.set(e.coupledAttribute, [e.model]);
      }
    return this._coupledAttributes;
  }
  /**
   * Fires `register` event for the given element definition.
   */
  _fireRegisterEvent(e) {
    e.view && this._disallowedElements.has(e.view) || this.fire(e.view ? `register:${e.view}` : "register", e);
  }
  /**
   * Registers object element and attribute converters for the given data schema definition.
   */
  _registerObjectElement(e) {
    const t = this.editor, i = t.model.schema, s = t.conversion, { view: r, model: o } = e;
    i.register(o, e.modelSchema);
    /* istanbul ignore next: paranoid check -- @preserve */
    r && (i.extend(e.model, {
      allowAttributes: [Ee(r), "htmlContent"]
    }), t.data.registerRawContentMatcher({
      name: r
    }), s.for("upcast").elementToElement({
      view: r,
      model: oo(e),
      // With a `low` priority, `paragraph` plugin auto-paragraphing mechanism is executed. Make sure
      // this listener is called before it. If not, some elements will be transformed into a paragraph.
      // `+ 2` is used to take priority over `_addDefaultH1Conversion` in the Heading plugin.
      converterPriority: be.low + 2
    }), s.for("upcast").add(Li(e, this)), s.for("editingDowncast").elementToStructure({
      model: {
        name: o,
        attributes: [Ee(r)]
      },
      view: VT(t, e)
    }), s.for("dataDowncast").elementToElement({
      model: o,
      view: (a, { writer: l }) => Un(r, a, l)
    }), s.for("dataDowncast").add($i(e)));
  }
  /**
   * Registers block element and attribute converters for the given data schema definition.
   */
  _registerBlockElement(e) {
    const t = this.editor, i = t.model.schema, s = t.conversion, { view: r, model: o } = e;
    if (!i.isRegistered(e.model)) {
      if (i.register(e.model, e.modelSchema), !r)
        return;
      s.for("upcast").elementToElement({
        model: o,
        view: r,
        // With a `low` priority, `paragraph` plugin auto-paragraphing mechanism is executed. Make sure
        // this listener is called before it. If not, some elements will be transformed into a paragraph.
        // `+ 2` is used to take priority over `_addDefaultH1Conversion` in the Heading plugin.
        converterPriority: be.low + 2
      }), s.for("downcast").elementToElement({
        model: o,
        view: r
      });
    }
    r && (i.extend(e.model, {
      allowAttributes: Ee(r)
    }), s.for("upcast").add(Li(e, this)), s.for("downcast").add($i(e)));
  }
  /**
   * Registers inline element and attribute converters for the given data schema definition.
   *
   * Extends `$text` model schema to allow the given definition model attribute and its properties.
   */
  _registerInlineElement(e) {
    const t = this.editor, i = t.model.schema, s = t.conversion, r = e.model;
    e.appliesToBlock || (i.extend("$text", {
      allowAttributes: r
    }), e.attributeProperties && i.setAttributeProperties(r, e.attributeProperties), s.for("upcast").add(DT(e, this)), s.for("downcast").attributeToElement({
      model: r,
      view: BT(e)
    }));
  }
}
function Ul(n, e, t) {
  const i = NT(n, e, t), { attributes: s, styles: r, classes: o } = $T(i), a = {};
  if (s.size)
    for (const l of s)
      _u(l) || s.delete(l);
  return s.size && (a.attributes = jl(s, (l) => n.getAttribute(l))), r.size && (a.styles = jl(r, (l) => n.getStyle(l))), o.size && (a.classes = Array.from(o)), Object.keys(a).length ? a : null;
}
function NT(n, { consumable: e }, t) {
  const i = t.matchAll(n) || [], s = [];
  for (const r of i)
    LT(e, n, r), delete r.match.name, e.consume(n, r.match), s.push(r);
  return s;
}
function LT(n, e, t) {
  for (const i of ["attributes", "classes", "styles"]) {
    const s = t.match[i];
    if (s)
      for (const r of Array.from(s))
        n.test(e, { [i]: [r] }) || s_(s, r);
  }
}
function $T(n) {
  const e = {
    attributes: /* @__PURE__ */ new Set(),
    classes: /* @__PURE__ */ new Set(),
    styles: /* @__PURE__ */ new Set()
  };
  for (const t of n)
    for (const i in e)
      (t.match[i] || []).forEach((r) => e[i].add(r));
  return e;
}
function jl(n, e) {
  const t = {};
  for (const i of n)
    e(i) !== void 0 && (t[i] = e(i));
  return t;
}
function vs(n, e) {
  const { name: t } = n, i = n[e];
  return de(i) ? Object.entries(i).map(([s, r]) => ({
    name: t,
    [e]: {
      [s]: r
    }
  })) : Array.isArray(i) ? i.map((s) => ({
    name: t,
    [e]: [s]
  })) : [n];
}
function ql(n) {
  const { name: e, attributes: t, classes: i, styles: s } = n, r = [];
  return t && r.push(...vs({ name: e, attributes: t }, "attributes")), i && r.push(...vs({ name: e, classes: i }, "classes")), s && r.push(...vs({ name: e, styles: s }, "styles")), r;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class zT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "CodeBlockElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    if (!this.editor.plugins.has("CodeBlockEditing"))
      return;
    const e = this.editor.plugins.get(ee);
    e.on("register:pre", (t, i) => {
      if (i.model !== "codeBlock")
        return;
      const s = this.editor, r = s.model.schema, o = s.conversion;
      r.extend("codeBlock", {
        allowAttributes: ["htmlPreAttributes", "htmlContentAttributes"]
      }), o.for("upcast").add(HT(e)), o.for("downcast").add(WT()), t.stop();
    });
  }
}
function HT(n) {
  return (e) => {
    e.on("element:code", (t, i, s) => {
      const r = i.viewItem, o = r.parent;
      if (!o || !o.is("element", "pre"))
        return;
      a(o, "htmlPreAttributes"), a(r, "htmlContentAttributes");
      function a(l, c) {
        const u = n.processViewAttributes(l, s);
        u && s.writer.setAttribute(c, u, i.modelRange);
      }
    }, { priority: "low" });
  };
}
function WT() {
  return (n) => {
    n.on("attribute:htmlPreAttributes:codeBlock", (e, t, i) => {
      if (!i.consumable.consume(t.item, e.name))
        return;
      const { attributeOldValue: s, attributeNewValue: r } = t, a = i.mapper.toViewElement(t.item).parent;
      It(i.writer, s, r, a);
    }), n.on("attribute:htmlContentAttributes:codeBlock", (e, t, i) => {
      if (!i.consumable.consume(t.item, e.name))
        return;
      const { attributeOldValue: s, attributeNewValue: r } = t, o = i.mapper.toViewElement(t.item);
      It(i.writer, s, r, o);
    });
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class UT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "DualContentModelElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    this.editor.plugins.get(ee).on("register", (t, i) => {
      const s = i, r = this.editor, o = r.model.schema, a = r.conversion;
      if (!s.paragraphLikeModel || o.isRegistered(s.model) || o.isRegistered(s.paragraphLikeModel))
        return;
      const l = {
        model: s.paragraphLikeModel,
        view: s.view
      };
      o.register(s.model, s.modelSchema), o.register(l.model, {
        inheritAllFrom: "$block"
      }), a.for("upcast").elementToElement({
        view: s.view,
        model: (c, { writer: u }) => this._hasBlockContent(c) ? u.createElement(s.model) : u.createElement(l.model),
        // With a `low` priority, `paragraph` plugin auto-paragraphing mechanism is executed. Make sure
        // this listener is called before it. If not, some elements will be transformed into a paragraph.
        converterPriority: be.low + 0.5
      }), a.for("downcast").elementToElement({
        view: s.view,
        model: s.model
      }), this._addAttributeConversion(s), a.for("downcast").elementToElement({
        view: l.view,
        model: l.model
      }), this._addAttributeConversion(l), t.stop();
    });
  }
  /**
   * Checks whether the given view element includes any other block element.
   */
  _hasBlockContent(e) {
    const t = this.editor.editing.view, i = t.domConverter.blockElements;
    for (const s of t.createRangeIn(e).getItems())
      if (s.is("element") && i.includes(s.name))
        return !0;
    return !1;
  }
  /**
   * Adds attribute filtering conversion for the given data schema.
   */
  _addAttributeConversion(e) {
    const t = this.editor, i = t.conversion, s = t.plugins.get(ee);
    t.model.schema.extend(e.model, {
      allowAttributes: Ee(e.view)
    }), i.for("upcast").add(Li(e, s)), i.for("downcast").add($i(e));
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class jT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ci, to];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "HeadingElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (!e.plugins.has("HeadingEditing"))
      return;
    const t = e.config.get("heading.options");
    this.registerHeadingElements(e, t);
  }
  /**
   * Registers all elements supported by HeadingEditing to enable custom attributes for those elements.
   */
  registerHeadingElements(e, t) {
    const i = e.plugins.get(ci), s = [];
    for (const r of t)
      "model" in r && "view" in r && (i.registerBlockElement({
        view: r.view,
        model: r.model
      }), s.push(r.model));
    i.extendBlockElement({
      model: "htmlHgroup",
      modelSchema: {
        allowChildren: s
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function Tn(n, e, t) {
  const i = n.createRangeOn(e);
  for (const { item: s } of i.getWalker())
    if (s.is("element", t))
      return s;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class qT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (!e.plugins.has("ImageInlineEditing") && !e.plugins.has("ImageBlockEditing"))
      return;
    const t = e.model.schema, i = e.conversion, s = e.plugins.get(ee);
    s.on("register:figure", () => {
      i.for("upcast").add(KT(s));
    }), s.on("register:img", (r, o) => {
      o.model !== "imageBlock" && o.model !== "imageInline" || (t.isRegistered("imageBlock") && t.extend("imageBlock", {
        allowAttributes: [
          "htmlImgAttributes",
          // Figure and Link don't have model counterpart.
          // We will preserve attributes on image model element using these attribute keys.
          "htmlFigureAttributes",
          "htmlLinkAttributes"
        ]
      }), t.isRegistered("imageInline") && t.extend("imageInline", {
        allowAttributes: [
          // `htmlA` is needed for standard GHS link integration.
          "htmlA",
          "htmlImgAttributes"
        ]
      }), i.for("upcast").add(GT(s)), i.for("downcast").add(JT()), r.stop());
    });
  }
}
function GT(n) {
  return (e) => {
    e.on("element:img", (t, i, s) => {
      if (!i.modelRange)
        return;
      const r = i.viewItem, o = r.parent;
      a(r, "htmlImgAttributes"), o.is("element", "a") && l(o);
      function a(c, u) {
        const h = n.processViewAttributes(c, s);
        h && s.writer.setAttribute(u, h, i.modelRange);
      }
      function l(c) {
        i.modelRange && i.modelRange.getContainedElement().is("element", "imageBlock") && a(c, "htmlLinkAttributes");
      }
    }, { priority: "low" });
  };
}
function KT(n) {
  return (e) => {
    e.on("element:figure", (t, i, s) => {
      const r = i.viewItem;
      if (!i.modelRange || !r.hasClass("image"))
        return;
      const o = n.processViewAttributes(r, s);
      o && s.writer.setAttribute("htmlFigureAttributes", o, i.modelRange);
    }, { priority: "low" });
  };
}
function JT() {
  return (n) => {
    e("htmlImgAttributes"), t("img", "htmlImgAttributes"), t("figure", "htmlFigureAttributes"), t("a", "htmlLinkAttributes");
    function e(i) {
      n.on(`attribute:${i}:imageInline`, (s, r, o) => {
        if (!o.consumable.consume(r.item, s.name))
          return;
        const { attributeOldValue: a, attributeNewValue: l } = r, c = o.mapper.toViewElement(r.item);
        It(o.writer, a, l, c);
      }, { priority: "low" });
    }
    function t(i, s) {
      n.on(`attribute:${s}:imageBlock`, (r, o, a) => {
        if (!a.consumable.test(o.item, r.name))
          return;
        const { attributeOldValue: l, attributeNewValue: c } = o, u = a.mapper.toViewElement(o.item), h = Tn(a.writer, u, i);
        h && (It(a.writer, l, c, h), a.consumable.consume(o.item, r.name));
      }, { priority: "low" }), i === "a" && n.on("attribute:linkHref:imageBlock", (r, o, a) => {
        if (!a.consumable.consume(o.item, "attribute:htmlLinkAttributes:imageBlock"))
          return;
        const l = a.mapper.toViewElement(o.item), c = Tn(a.writer, l, "a");
        Je(a.writer, o.item.getAttribute("htmlLinkAttributes"), c);
      }, { priority: "low" });
    }
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ZT extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "MediaEmbedElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (!e.plugins.has("MediaEmbed") || e.config.get("mediaEmbed.previewsInData"))
      return;
    const t = e.model.schema, i = e.conversion, s = this.editor.plugins.get(ee), r = this.editor.plugins.get(ci), o = e.config.get("mediaEmbed.elementName");
    r.registerBlockElement({
      model: "media",
      view: o
    }), s.on("register:figure", () => {
      i.for("upcast").add(XT(s));
    }), s.on(`register:${o}`, (a, l) => {
      l.model === "media" && (t.extend("media", {
        allowAttributes: [
          Ee(o),
          "htmlFigureAttributes"
        ]
      }), i.for("upcast").add(YT(s, o)), i.for("dataDowncast").add(QT(o)), a.stop());
    });
  }
}
function YT(n, e) {
  const t = (i, s, r) => {
    const o = s.viewItem;
    a(o, Ee(e));
    function a(l, c) {
      const u = n.processViewAttributes(l, r);
      u && r.writer.setAttribute(c, u, s.modelRange);
    }
  };
  return (i) => {
    i.on(`element:${e}`, t, { priority: "low" });
  };
}
function XT(n) {
  return (e) => {
    e.on("element:figure", (t, i, s) => {
      const r = i.viewItem;
      if (!i.modelRange || !r.hasClass("media"))
        return;
      const o = n.processViewAttributes(r, s);
      o && s.writer.setAttribute("htmlFigureAttributes", o, i.modelRange);
    }, { priority: "low" });
  };
}
function QT(n) {
  return (e) => {
    t(n, Ee(n)), t("figure", "htmlFigureAttributes");
    function t(i, s) {
      e.on(`attribute:${s}:media`, (r, o, a) => {
        if (!a.consumable.consume(o.item, r.name))
          return;
        const { attributeOldValue: l, attributeNewValue: c } = o, u = a.mapper.toViewElement(o.item), h = Tn(a.writer, u, i);
        It(a.writer, l, c, h);
      });
    }
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class eP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ScriptElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.plugins.get(ee);
    e.on("register:script", (t, i) => {
      const s = this.editor, r = s.model.schema, o = s.conversion;
      r.register("htmlScript", i.modelSchema), r.extend("htmlScript", {
        allowAttributes: ["htmlScriptAttributes", "htmlContent"],
        isContent: !0
      }), s.data.registerRawContentMatcher({
        name: "script"
      }), o.for("upcast").elementToElement({
        view: "script",
        model: oo(i)
      }), o.for("upcast").add(Li(i, e)), o.for("downcast").elementToElement({
        model: "htmlScript",
        view: (a, { writer: l }) => Un("script", a, l)
      }), o.for("downcast").add($i(i)), t.stop();
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class tP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "TableElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (!e.plugins.has("TableEditing"))
      return;
    const t = e.model.schema, i = e.conversion, s = e.plugins.get(ee), r = e.plugins.get("TableUtils");
    s.on("register:figure", () => {
      i.for("upcast").add(sP(s));
    }), s.on("register:table", (o, a) => {
      a.model === "table" && (t.extend("table", {
        allowAttributes: [
          "htmlTableAttributes",
          // Figure, thead and tbody elements don't have model counterparts.
          // We will be preserving attributes on table element using these attribute keys.
          "htmlFigureAttributes",
          "htmlTheadAttributes",
          "htmlTbodyAttributes"
        ]
      }), i.for("upcast").add(nP(s)), i.for("downcast").add(rP()), e.model.document.registerPostFixer(iP(e.model, r)), o.stop());
    });
  }
}
function iP(n, e) {
  return (t) => {
    const i = n.document.differ.getChanges();
    let s = !1;
    for (const r of i) {
      if (r.type != "attribute" || r.attributeKey != "headingRows")
        continue;
      const o = r.range.start.nodeAfter, a = o.getAttribute("htmlTheadAttributes"), l = o.getAttribute("htmlTbodyAttributes");
      a && !r.attributeNewValue ? (t.removeAttribute("htmlTheadAttributes", o), s = !0) : l && r.attributeNewValue == e.getRows(o) && (t.removeAttribute("htmlTbodyAttributes", o), s = !0);
    }
    return s;
  };
}
function nP(n) {
  return (e) => {
    e.on("element:table", (t, i, s) => {
      if (!i.modelRange)
        return;
      const r = i.viewItem;
      o(r, "htmlTableAttributes");
      for (const a of r.getChildren())
        a.is("element", "thead") && o(a, "htmlTheadAttributes"), a.is("element", "tbody") && o(a, "htmlTbodyAttributes");
      function o(a, l) {
        const c = n.processViewAttributes(a, s);
        c && s.writer.setAttribute(l, c, i.modelRange);
      }
    }, { priority: "low" });
  };
}
function sP(n) {
  return (e) => {
    e.on("element:figure", (t, i, s) => {
      const r = i.viewItem;
      if (!i.modelRange || !r.hasClass("table"))
        return;
      const o = n.processViewAttributes(r, s);
      o && s.writer.setAttribute("htmlFigureAttributes", o, i.modelRange);
    }, { priority: "low" });
  };
}
function rP() {
  return (n) => {
    e("table", "htmlTableAttributes"), e("figure", "htmlFigureAttributes"), e("thead", "htmlTheadAttributes"), e("tbody", "htmlTbodyAttributes");
    function e(t, i) {
      n.on(`attribute:${i}:table`, (s, r, o) => {
        if (!o.consumable.test(r.item, s.name))
          return;
        const a = o.mapper.toViewElement(r.item), l = Tn(o.writer, a, t);
        l && (o.consumable.consume(r.item, s.name), It(o.writer, r.attributeOldValue, r.attributeNewValue, l));
      });
    }
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class oP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "StyleElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.plugins.get(ee);
    e.on("register:style", (t, i) => {
      const s = this.editor, r = s.model.schema, o = s.conversion;
      r.register("htmlStyle", i.modelSchema), r.extend("htmlStyle", {
        allowAttributes: ["htmlStyleAttributes", "htmlContent"],
        isContent: !0
      }), s.data.registerRawContentMatcher({
        name: "style"
      }), o.for("upcast").elementToElement({
        view: "style",
        model: oo(i)
      }), o.for("upcast").add(Li(i, e)), o.for("downcast").elementToElement({
        model: "htmlStyle",
        view: (a, { writer: l }) => Un("style", a, l)
      }), o.for("downcast").add($i(i)), t.stop();
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class aP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "DocumentListElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    if (!e.plugins.has("DocumentListEditing"))
      return;
    const t = e.model.schema, i = e.conversion, s = e.plugins.get(ee), r = e.plugins.get("DocumentListEditing"), o = ["ul", "ol", "li"];
    r.registerDowncastStrategy({
      scope: "item",
      attributeName: "htmlLiAttributes",
      setAttributeOnDowncast: Je
    }), r.registerDowncastStrategy({
      scope: "list",
      attributeName: "htmlUlAttributes",
      setAttributeOnDowncast: Je
    }), r.registerDowncastStrategy({
      scope: "list",
      attributeName: "htmlOlAttributes",
      setAttributeOnDowncast: Je
    }), s.on("register", (a, l) => {
      if (!o.includes(l.view) || (a.stop(), t.checkAttribute("$block", "htmlLiAttributes")))
        return;
      const c = o.map((u) => Ee(u));
      t.extend("$block", { allowAttributes: c }), t.extend("$blockObject", { allowAttributes: c }), t.extend("$container", { allowAttributes: c }), i.for("upcast").add((u) => {
        u.on("element:ul", ys("htmlUlAttributes", s), { priority: "low" }), u.on("element:ol", ys("htmlOlAttributes", s), { priority: "low" }), u.on("element:li", ys("htmlLiAttributes", s), { priority: "low" });
      });
    }), r.on("postFixer", (a, { listNodes: l, writer: c }) => {
      const u = [];
      for (const { node: h, previous: f } of l) {
        if (!f)
          continue;
        const m = h.getAttribute("listIndent"), p = f.getAttribute("listIndent");
        let b = null;
        if (m > p ? u[p] = f : m < p ? (b = u[m], u.length = m) : b = f, !!b) {
          if (b.getAttribute("listType") == h.getAttribute("listType")) {
            const E = Gl(b.getAttribute("listType")), A = b.getAttribute(E);
            !gn(h.getAttribute(E), A) && c.model.schema.checkAttribute(h, E) && (c.setAttribute(E, A, h), a.return = !0);
          }
          if (b.getAttribute("listItemId") == h.getAttribute("listItemId")) {
            const E = b.getAttribute("htmlLiAttributes");
            !gn(h.getAttribute("htmlLiAttributes"), E) && c.model.schema.checkAttribute(h, "htmlLiAttributes") && (c.setAttribute("htmlLiAttributes", E, h), a.return = !0);
          }
        }
      }
    }), r.on("postFixer", (a, { listNodes: l, writer: c }) => {
      for (const { node: u } of l) {
        const h = u.getAttribute("listType");
        h === "bulleted" && u.getAttribute("htmlOlAttributes") && (c.removeAttribute("htmlOlAttributes", u), a.return = !0), h === "numbered" && u.getAttribute("htmlUlAttributes") && (c.removeAttribute("htmlUlAttributes", u), a.return = !0);
      }
    });
  }
  /**
   * @inheritDoc
   */
  afterInit() {
    const e = this.editor;
    if (!e.commands.get("indentList"))
      return;
    const t = e.commands.get("indentList");
    this.listenTo(t, "afterExecute", (i, s) => {
      e.model.change((r) => {
        for (const o of s) {
          const a = Gl(o.getAttribute("listType"));
          e.model.schema.checkAttribute(o, a) && r.setAttribute(a, {}, o);
        }
      });
    });
  }
}
function ys(n, e) {
  return (t, i, s) => {
    const r = i.viewItem;
    i.modelRange || Object.assign(i, s.convertChildren(i.viewItem, i.modelCursor));
    const o = e.processViewAttributes(r, s);
    for (const a of i.modelRange.getItems({ shallow: !0 }))
      a.hasAttribute("listItemId") && (a.hasAttribute(n) || s.writer.model.schema.checkAttribute(a, n) && s.writer.setAttribute(n, o || {}, a));
  };
}
function Gl(n) {
  return n === "bulleted" ? "htmlUlAttributes" : "htmlOlAttributes";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class lP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ee, ci];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "CustomElementSupport";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.plugins.get(ee), t = this.editor.plugins.get(ci);
    e.on("register:$customElement", (i, s) => {
      i.stop();
      const r = this.editor, o = r.model.schema, a = r.conversion, l = r.editing.view.domConverter.unsafeElements, c = r.data.htmlProcessor.domConverter.preElements;
      o.register(s.model, s.modelSchema), o.extend(s.model, {
        allowAttributes: ["htmlElementName", "htmlCustomElementAttributes", "htmlContent"],
        isContent: !0
      }), a.for("upcast").elementToElement({
        view: /.*/,
        model: (u, h) => {
          if (u.name == "$comment" || !cP(u.name) || t.getDefinitionsForView(u.name).size)
            return null;
          l.includes(u.name) || l.push(u.name), c.includes(u.name) || c.push(u.name);
          const f = h.writer.createElement(s.model, {
            htmlElementName: u.name
          }), m = e.processViewAttributes(u, h);
          m && h.writer.setAttribute("htmlCustomElementAttributes", m, f);
          const b = new Wr(u.document).createDocumentFragment(u), E = r.data.processor.toData(b);
          h.writer.setAttribute("htmlContent", E, f);
          for (const { item: A } of r.editing.view.createRangeIn(u))
            h.consumable.consume(A, { name: !0 });
          return f;
        },
        converterPriority: "low"
      }), a.for("editingDowncast").elementToElement({
        model: {
          name: s.model,
          attributes: ["htmlElementName", "htmlCustomElementAttributes", "htmlContent"]
        },
        view: (u, { writer: h }) => {
          const f = u.getAttribute("htmlElementName"), m = h.createRawElement(f);
          return u.hasAttribute("htmlCustomElementAttributes") && Je(h, u.getAttribute("htmlCustomElementAttributes"), m), m;
        }
      }), a.for("dataDowncast").elementToElement({
        model: {
          name: s.model,
          attributes: ["htmlElementName", "htmlCustomElementAttributes", "htmlContent"]
        },
        view: (u, { writer: h }) => {
          const f = u.getAttribute("htmlElementName"), m = u.getAttribute("htmlContent"), p = h.createRawElement(f, null, (b, E) => {
            E.setContentOf(b, m);
            const A = b.firstChild;
            for (A.remove(); A.firstChild; )
              b.appendChild(A.firstChild);
          });
          return u.hasAttribute("htmlCustomElementAttributes") && Je(h, u.getAttribute("htmlCustomElementAttributes"), p), p;
        }
      });
    });
  }
}
function cP(n) {
  try {
    document.createElement(n);
  } catch {
    return !1;
  }
  return !0;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class L5 extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "GeneralHtmlSupport";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [
      ee,
      zT,
      UT,
      jT,
      qT,
      ZT,
      eP,
      tP,
      oP,
      aP,
      lP
    ];
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.plugins.get(ee);
    t.loadAllowedConfig(e.config.get("htmlSupport.allow") || []), t.loadDisallowedConfig(e.config.get("htmlSupport.disallow") || []);
  }
  /**
   * Returns a GHS model attribute name related to a given view element name.
   *
   * @internal
   * @param viewElementName A view element name.
   */
  getGhsAttributeNameForElement(e) {
    const t = this.editor.plugins.get("DataSchema"), i = Array.from(t.getDefinitionsForView(e, !1)), s = i.find((r) => r.isInline && !i[0].isObject);
    return s ? s.model : Ee(e);
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it includes the given class name.
   *
   * @internal
   * @param viewElementName A view element name.
   * @param className The css class to add.
   * @param selectable The selection or element to update.
   */
  addModelHtmlClass(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "classes", (l) => {
          for (const c of X(t))
            l.add(c);
        });
    });
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it does not include the given class name.
   *
   * @internal
   * @param viewElementName A view element name.
   * @param className The css class to remove.
   * @param selectable The selection or element to update.
   */
  removeModelHtmlClass(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "classes", (l) => {
          for (const c of X(t))
            l.delete(c);
        });
    });
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it includes the given attribute.
   *
   * @param viewElementName A view element name.
   * @param attributes The object with attributes to set.
   * @param selectable The selection or element to update.
   */
  setModelHtmlAttributes(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "attributes", (l) => {
          for (const [c, u] of Object.entries(t))
            l.set(c, u);
        });
    });
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it does not include the given attribute.
   *
   * @param viewElementName A view element name.
   * @param attributeName The attribute name (or names) to remove.
   * @param selectable The selection or element to update.
   */
  removeModelHtmlAttributes(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "attributes", (l) => {
          for (const c of X(t))
            l.delete(c);
        });
    });
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it includes a given style.
   *
   * @param viewElementName A view element name.
   * @param styles The object with styles to set.
   * @param selectable The selection or element to update.
   */
  setModelHtmlStyles(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "styles", (l) => {
          for (const [c, u] of Object.entries(t))
            l.set(c, u);
        });
    });
  }
  /**
   * Updates GHS model attribute for a specified view element name, so it does not include a given style.
   *
   * @param viewElementName A view element name.
   * @param properties The style (or styles list) to remove.
   * @param selectable The selection or element to update.
   */
  removeModelHtmlStyles(e, t, i) {
    const s = this.editor.model, r = this.getGhsAttributeNameForElement(e);
    s.change((o) => {
      for (const a of Ut(s, i, r))
        Wt(o, a, r, "styles", (l) => {
          for (const c of X(t))
            l.delete(c);
        });
    });
  }
}
function* Ut(n, e, t) {
  if (e)
    if (!(Symbol.iterator in e) && e.is("documentSelection") && e.isCollapsed)
      n.schema.checkAttributeInSelection(e, t) && (yield e);
    else
      for (const i of uP(n, e, t))
        yield* i.getItems({ shallow: !0 });
}
function uP(n, e, t) {
  return !(Symbol.iterator in e) && (e.is("node") || e.is("$text") || e.is("$textProxy")) ? n.schema.checkAttribute(e, t) ? [n.createRangeOn(e)] : [] : n.schema.getValidRanges(n.createSelection(e).getRanges(), t);
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class hP {
  constructor() {
    this._definitions = /* @__PURE__ */ new Set();
  }
  /**
   * Gives information about the number of decorators stored in the {@link module:link/utils/automaticdecorators~AutomaticDecorators}
   * instance.
   */
  get length() {
    return this._definitions.size;
  }
  /**
   * Adds automatic decorator objects or an array with them to be used during downcasting.
   *
   * @param item A configuration object of automatic rules for decorating links. It might also be an array of such objects.
   */
  add(e) {
    Array.isArray(e) ? e.forEach((t) => this._definitions.add(t)) : this._definitions.add(e);
  }
  /**
   * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method.
   *
   * @returns A dispatcher function used as conversion helper in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.
   */
  getDispatcher() {
    return (e) => {
      e.on("attribute:linkHref", (t, i, s) => {
        if (!s.consumable.test(i.item, "attribute:linkHref") || !(i.item.is("selection") || s.schema.isInline(i.item)))
          return;
        const r = s.writer, o = r.document.selection;
        for (const a of this._definitions) {
          const l = r.createAttributeElement("a", a.attributes, {
            priority: 5
          });
          a.classes && r.addClass(a.classes, l);
          for (const c in a.styles)
            r.setStyle(c, a.styles[c], l);
          r.setCustomProperty("link", !0, l), a.callback(i.attributeNewValue) ? i.item.is("selection") ? r.wrap(o.getFirstRange(), l) : r.wrap(s.mapper.toViewRange(i.range), l) : r.unwrap(s.mapper.toViewRange(i.range), l);
        }
      }, { priority: "high" });
    };
  }
  /**
   * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method
   * when linking images.
   *
   * @returns A dispatcher function used as conversion helper in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.
   */
  getDispatcherForLinkedImage() {
    return (e) => {
      e.on("attribute:linkHref:imageBlock", (t, i, { writer: s, mapper: r }) => {
        const o = r.toViewElement(i.item), a = Array.from(o.getChildren()).find((l) => l.is("element", "a"));
        for (const l of this._definitions) {
          const c = Xe(l.attributes);
          if (l.callback(i.attributeNewValue)) {
            for (const [u, h] of c)
              u === "class" ? s.addClass(h, a) : s.setAttribute(u, h, a);
            l.classes && s.addClass(l.classes, a);
            for (const u in l.styles)
              s.setStyle(u, l.styles[u], a);
          } else {
            for (const [u, h] of c)
              u === "class" ? s.removeClass(h, a) : s.removeAttribute(u, a);
            l.classes && s.removeClass(l.classes, a);
            for (const u in l.styles)
              s.removeStyle(u, a);
          }
        }
      });
    };
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const dP = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g, fP = /^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i, mP = /^[\S]+@((?![-_])(?:[-\w\u00a1-\uffff]{0,63}[^-_]\.))+(?:[a-z\u00a1-\uffff]{2,})$/i, gP = /^((\w+:(\/{2,})?)|(\W))/i, ks = "Ctrl+K";
function pP(n) {
  return n.is("attributeElement") && !!n.getCustomProperty("link");
}
function Kl(n, { writer: e }) {
  const t = e.createAttributeElement("a", { href: n }, { priority: 5 });
  return e.setCustomProperty("link", !0, t), t;
}
function wd(n) {
  const e = String(n);
  return wP(e) ? e : "#";
}
function wP(n) {
  return !!n.replace(dP, "").match(fP);
}
function bP(n, e) {
  const t = {
    "Open in a new tab": n("Open in a new tab"),
    Downloadable: n("Downloadable")
  };
  return e.forEach((i) => ("label" in i && t[i.label] && (i.label = t[i.label]), i)), e;
}
function _P(n) {
  const e = [];
  if (n)
    for (const [t, i] of Object.entries(n)) {
      const s = Object.assign({}, i, { id: `link${Bc(t)}` });
      e.push(s);
    }
  return e;
}
function lr(n, e) {
  return n ? e.checkAttribute(n.name, "linkHref") : !1;
}
function vP(n) {
  return mP.test(n);
}
function ao(n, e) {
  const t = vP(n) ? "mailto:" : e, i = !!t && !bd(n);
  return n && i ? t + n : n;
}
function bd(n) {
  return gP.test(n);
}
function Jl(n) {
  window.open(n, "_blank", "noopener");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class yP extends te {
  constructor() {
    super(...arguments), this.manualDecorators = new He(), this.automaticDecorators = new hP();
  }
  /**
   * Synchronizes the state of {@link #manualDecorators} with the currently present elements in the model.
   */
  restoreManualDecoratorStates() {
    for (const e of this.manualDecorators)
      e.value = this._getDecoratorStateFromModel(e.id);
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document.selection, i = t.getSelectedElement() || Te(t.getSelectedBlocks());
    lr(i, e.schema) ? (this.value = i.getAttribute("linkHref"), this.isEnabled = e.schema.checkAttribute(i, "linkHref")) : (this.value = t.getAttribute("linkHref"), this.isEnabled = e.schema.checkAttributeInSelection(t, "linkHref"));
    for (const s of this.manualDecorators)
      s.value = this._getDecoratorStateFromModel(s.id);
  }
  /**
   * Executes the command.
   *
   * When the selection is non-collapsed, the `linkHref` attribute will be applied to nodes inside the selection, but only to
   * those nodes where the `linkHref` attribute is allowed (disallowed nodes will be omitted).
   *
   * When the selection is collapsed and is not inside the text with the `linkHref` attribute, a
   * new {@link module:engine/model/text~Text text node} with the `linkHref` attribute will be inserted in place of the caret, but
   * only if such element is allowed in this place. The `_data` of the inserted text will equal the `href` parameter.
   * The selection will be updated to wrap the just inserted text node.
   *
   * When the selection is collapsed and inside the text with the `linkHref` attribute, the attribute value will be updated.
   *
   * # Decorators and model attribute management
   *
   * There is an optional argument to this command that applies or removes model
   * {@glink framework/architecture/editing-engine#text-attributes text attributes} brought by
   * {@link module:link/utils/manualdecorator~ManualDecorator manual link decorators}.
   *
   * Text attribute names in the model correspond to the entries in the {@link module:link/linkconfig~LinkConfig#decorators
   * configuration}.
   * For every decorator configured, a model text attribute exists with the "link" prefix. For example, a `'linkMyDecorator'` attribute
   * corresponds to `'myDecorator'` in the configuration.
   *
   * To learn more about link decorators, check out the {@link module:link/linkconfig~LinkConfig#decorators `config.link.decorators`}
   * documentation.
   *
   * Here is how to manage decorator attributes with the link command:
   *
   * ```ts
   * const linkCommand = editor.commands.get( 'link' );
   *
   * // Adding a new decorator attribute.
   * linkCommand.execute( 'http://example.com', {
   * 	linkIsExternal: true
   * } );
   *
   * // Removing a decorator attribute from the selection.
   * linkCommand.execute( 'http://example.com', {
   * 	linkIsExternal: false
   * } );
   *
   * // Adding multiple decorator attributes at the same time.
   * linkCommand.execute( 'http://example.com', {
   * 	linkIsExternal: true,
   * 	linkIsDownloadable: true,
   * } );
   *
   * // Removing and adding decorator attributes at the same time.
   * linkCommand.execute( 'http://example.com', {
   * 	linkIsExternal: false,
   * 	linkFoo: true,
   * 	linkIsDownloadable: false,
   * } );
   * ```
   *
   * **Note**: If the decorator attribute name is not specified, its state remains untouched.
   *
   * **Note**: {@link module:link/unlinkcommand~UnlinkCommand#execute `UnlinkCommand#execute()`} removes all
   * decorator attributes.
   *
   * @fires execute
   * @param href Link destination.
   * @param manualDecoratorIds The information about manual decorator attributes to be applied or removed upon execution.
   */
  execute(e, t = {}) {
    const i = this.editor.model, s = i.document.selection, r = [], o = [];
    for (const a in t)
      t[a] ? r.push(a) : o.push(a);
    i.change((a) => {
      if (s.isCollapsed) {
        const l = s.getFirstPosition();
        if (s.hasAttribute("linkHref")) {
          const c = Zl(s);
          let u = li(l, "linkHref", s.getAttribute("linkHref"), i);
          s.getAttribute("linkHref") === c && (u = this._updateLinkContent(i, a, u, e)), a.setAttribute("linkHref", e, u), r.forEach((h) => {
            a.setAttribute(h, !0, u);
          }), o.forEach((h) => {
            a.removeAttribute(h, u);
          }), a.setSelection(a.createPositionAfter(u.end.nodeBefore));
        } else if (e !== "") {
          const c = Xe(s.getAttributes());
          c.set("linkHref", e), r.forEach((h) => {
            c.set(h, !0);
          });
          const { end: u } = i.insertContent(a.createText(e, c), l);
          a.setSelection(u);
        }
        ["linkHref", ...r, ...o].forEach((c) => {
          a.removeSelectionAttribute(c);
        });
      } else {
        const l = i.schema.getValidRanges(s.getRanges(), "linkHref"), c = [];
        for (const h of s.getSelectedBlocks())
          i.schema.checkAttribute(h, "linkHref") && c.push(a.createRangeOn(h));
        const u = c.slice();
        for (const h of l)
          this._isRangeToUpdate(h, c) && u.push(h);
        for (const h of u) {
          let f = h;
          if (u.length === 1) {
            const m = Zl(s);
            s.getAttribute("linkHref") === m && (f = this._updateLinkContent(i, a, h, e), a.setSelection(a.createSelection(f)));
          }
          a.setAttribute("linkHref", e, f), r.forEach((m) => {
            a.setAttribute(m, !0, f);
          }), o.forEach((m) => {
            a.removeAttribute(m, f);
          });
        }
      }
    });
  }
  /**
   * Provides information whether a decorator with a given name is present in the currently processed selection.
   *
   * @param decoratorName The name of the manual decorator used in the model
   * @returns The information whether a given decorator is currently present in the selection.
   */
  _getDecoratorStateFromModel(e) {
    const t = this.editor.model, i = t.document.selection, s = i.getSelectedElement();
    return lr(s, t.schema) ? s.getAttribute(e) : i.getAttribute(e);
  }
  /**
   * Checks whether specified `range` is inside an element that accepts the `linkHref` attribute.
   *
   * @param range A range to check.
   * @param allowedRanges An array of ranges created on elements where the attribute is accepted.
   */
  _isRangeToUpdate(e, t) {
    for (const i of t)
      if (i.containsRange(e))
        return !1;
    return !0;
  }
  /**
   * Updates selected link with a new value as its content and as its href attribute.
   *
   * @param model Model is need to insert content.
   * @param writer Writer is need to create text element in model.
   * @param range A range where should be inserted content.
   * @param href A link value which should be in the href attribute and in the content.
   */
  _updateLinkContent(e, t, i, s) {
    const r = t.createText(s, { linkHref: s });
    return e.insertContent(r, i);
  }
}
function Zl(n) {
  if (n.isCollapsed) {
    const e = n.getFirstPosition();
    return e.textNode && e.textNode.data;
  } else {
    const e = Array.from(n.getFirstRange().getItems());
    if (e.length > 1)
      return null;
    const t = e[0];
    return t.is("$text") || t.is("$textProxy") ? t.data : null;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class kP extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.model, t = e.document.selection, i = t.getSelectedElement();
    lr(i, e.schema) ? this.isEnabled = e.schema.checkAttribute(i, "linkHref") : this.isEnabled = e.schema.checkAttributeInSelection(t, "linkHref");
  }
  /**
   * Executes the command.
   *
   * When the selection is collapsed, it removes the `linkHref` attribute from each node with the same `linkHref` attribute value.
   * When the selection is non-collapsed, it removes the `linkHref` attribute from each node in selected ranges.
   *
   * # Decorators
   *
   * If {@link module:link/linkconfig~LinkConfig#decorators `config.link.decorators`} is specified,
   * all configured decorators are removed together with the `linkHref` attribute.
   *
   * @fires execute
   */
  execute() {
    const e = this.editor, t = this.editor.model, i = t.document.selection, s = e.commands.get("link");
    t.change((r) => {
      const o = i.isCollapsed ? [li(i.getFirstPosition(), "linkHref", i.getAttribute("linkHref"), t)] : t.schema.getValidRanges(i.getRanges(), "linkHref");
      for (const a of o)
        if (r.removeAttribute("linkHref", a), s)
          for (const l of s.manualDecorators)
            r.removeAttribute(l.id, a);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class CP extends z() {
  /**
   * Creates a new instance of {@link module:link/utils/manualdecorator~ManualDecorator}.
   *
   * @param config.id The name of the attribute used in the model that represents a given manual decorator.
   * For example: `'linkIsExternal'`.
   * @param config.label The label used in the user interface to toggle the manual decorator.
   * @param config.attributes A set of attributes added to output data when the decorator is active for a specific link.
   * Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.
   * @param [config.defaultValue] Controls whether the decorator is "on" by default.
   */
  constructor({ id: e, label: t, attributes: i, classes: s, styles: r, defaultValue: o }) {
    super(), this.id = e, this.set("value", void 0), this.defaultValue = o, this.label = t, this.attributes = i, this.classes = s, this.styles = r;
  }
  /**
   * Returns {@link module:engine/view/matcher~MatcherPattern} with decorator attributes.
   *
   * @internal
   */
  _createPattern() {
    return {
      attributes: this.attributes,
      classes: this.classes,
      styles: this.styles
    };
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const EP = "ck-link_selected", Yl = "automatic", AP = "manual", TP = /^(https?:)?\/\//;
class PP extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "LinkEditing";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [_l, id, ut];
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define("link", {
      addTargetToExternalLinks: !1
    });
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.model.schema.extend("$text", { allowAttributes: "linkHref" }), e.conversion.for("dataDowncast").attributeToElement({ model: "linkHref", view: Kl }), e.conversion.for("editingDowncast").attributeToElement({ model: "linkHref", view: (s, r) => Kl(wd(s), r) }), e.conversion.for("upcast").elementToAttribute({
      view: {
        name: "a",
        attributes: {
          href: !0
        }
      },
      model: {
        key: "linkHref",
        value: (s) => s.getAttribute("href")
      }
    }), e.commands.add("link", new yP(e)), e.commands.add("unlink", new kP(e));
    const t = bP(e.t, _P(e.config.get("link.decorators")));
    this._enableAutomaticDecorators(t.filter((s) => s.mode === Yl)), this._enableManualDecorators(t.filter((s) => s.mode === AP)), e.plugins.get(_l).registerAttribute("linkHref"), EE(e, "linkHref", "a", EP), this._enableLinkOpen(), this._enableInsertContentSelectionAttributesFixer(), this._enableClickingAfterLink(), this._enableTypingOverLink(), this._handleDeleteContentAfterLink(), this._enableClipboardIntegration();
  }
  /**
   * Processes an array of configured {@link module:link/linkconfig~LinkDecoratorAutomaticDefinition automatic decorators}
   * and registers a {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast dispatcher}
   * for each one of them. Downcast dispatchers are obtained using the
   * {@link module:link/utils/automaticdecorators~AutomaticDecorators#getDispatcher} method.
   *
   * **Note**: This method also activates the automatic external link decorator if enabled with
   * {@link module:link/linkconfig~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}.
   */
  _enableAutomaticDecorators(e) {
    const t = this.editor, s = t.commands.get("link").automaticDecorators;
    t.config.get("link.addTargetToExternalLinks") && s.add({
      id: "linkIsExternal",
      mode: Yl,
      callback: (r) => !!r && TP.test(r),
      attributes: {
        target: "_blank",
        rel: "noopener noreferrer"
      }
    }), s.add(e), s.length && t.conversion.for("downcast").add(s.getDispatcher());
  }
  /**
   * Processes an array of configured {@link module:link/linkconfig~LinkDecoratorManualDefinition manual decorators},
   * transforms them into {@link module:link/utils/manualdecorator~ManualDecorator} instances and stores them in the
   * {@link module:link/linkcommand~LinkCommand#manualDecorators} collection (a model for manual decorators state).
   *
   * Also registers an {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement attribute-to-element}
   * converter for each manual decorator and extends the {@link module:engine/model/schema~Schema model's schema}
   * with adequate model attributes.
   */
  _enableManualDecorators(e) {
    if (!e.length)
      return;
    const t = this.editor, s = t.commands.get("link").manualDecorators;
    e.forEach((r) => {
      t.model.schema.extend("$text", { allowAttributes: r.id });
      const o = new CP(r);
      s.add(o), t.conversion.for("downcast").attributeToElement({
        model: o.id,
        view: (a, { writer: l, schema: c }, { item: u }) => {
          if ((u.is("selection") || c.isInline(u)) && a) {
            const h = l.createAttributeElement("a", o.attributes, { priority: 5 });
            o.classes && l.addClass(o.classes, h);
            for (const f in o.styles)
              l.setStyle(f, o.styles[f], h);
            return l.setCustomProperty("link", !0, h), h;
          }
        }
      }), t.conversion.for("upcast").elementToAttribute({
        view: {
          name: "a",
          ...o._createPattern()
        },
        model: {
          key: o.id
        }
      });
    });
  }
  /**
   * Attaches handlers for {@link module:engine/view/document~Document#event:enter} and
   * {@link module:engine/view/document~Document#event:click} to enable link following.
   */
  _enableLinkOpen() {
    const e = this.editor, i = e.editing.view.document;
    this.listenTo(i, "click", (s, r) => {
      if (!(S.isMac ? r.domEvent.metaKey : r.domEvent.ctrlKey))
        return;
      let a = r.domTarget;
      if (a.tagName.toLowerCase() != "a" && (a = a.closest("a")), !a)
        return;
      const l = a.getAttribute("href");
      l && (s.stop(), r.preventDefault(), Jl(l));
    }, { context: "$capture" }), this.listenTo(i, "keydown", (s, r) => {
      const a = e.commands.get("link").value;
      a && r.keyCode === R.enter && r.altKey && (s.stop(), Jl(a));
    });
  }
  /**
   * Starts listening to {@link module:engine/model/model~Model#event:insertContent} and corrects the model
   * selection attributes if the selection is at the end of a link after inserting the content.
   *
   * The purpose of this action is to improve the overall UX because the user is no longer "trapped" by the
   * `linkHref` attribute of the selection and they can type a "clean" (`linkHref`–less) text right away.
   *
   * See https://github.com/ckeditor/ckeditor5/issues/6053.
   */
  _enableInsertContentSelectionAttributesFixer() {
    const t = this.editor.model, i = t.document.selection;
    this.listenTo(t, "insertContent", () => {
      const s = i.anchor.nodeBefore, r = i.anchor.nodeAfter;
      i.hasAttribute("linkHref") && s && s.hasAttribute("linkHref") && (r && r.hasAttribute("linkHref") || t.change((o) => {
        Cs(o, Es(t.schema));
      }));
    }, { priority: "low" });
  }
  /**
   * Starts listening to {@link module:engine/view/document~Document#event:mousedown} and
   * {@link module:engine/view/document~Document#event:selectionChange} and puts the selection before/after a link node
   * if clicked at the beginning/ending of the link.
   *
   * The purpose of this action is to allow typing around the link node directly after a click.
   *
   * See https://github.com/ckeditor/ckeditor5/issues/1016.
   */
  _enableClickingAfterLink() {
    const e = this.editor, t = e.model;
    e.editing.view.addObserver(Ln);
    let i = !1;
    this.listenTo(e.editing.view.document, "mousedown", () => {
      i = !0;
    }), this.listenTo(e.editing.view.document, "selectionChange", () => {
      if (!i)
        return;
      i = !1;
      const s = t.document.selection;
      if (!s.isCollapsed || !s.hasAttribute("linkHref"))
        return;
      const r = s.getFirstPosition(), o = li(r, "linkHref", s.getAttribute("linkHref"), t);
      (r.isTouching(o.start) || r.isTouching(o.end)) && t.change((a) => {
        Cs(a, Es(t.schema));
      });
    });
  }
  /**
   * Starts listening to {@link module:engine/model/model~Model#deleteContent} and {@link module:engine/model/model~Model#insertContent}
   * and checks whether typing over the link. If so, attributes of removed text are preserved and applied to the inserted text.
   *
   * The purpose of this action is to allow modifying a text without loosing the `linkHref` attribute (and other).
   *
   * See https://github.com/ckeditor/ckeditor5/issues/4762.
   */
  _enableTypingOverLink() {
    const e = this.editor, t = e.editing.view;
    let i = null, s = !1;
    this.listenTo(t.document, "delete", () => {
      s = !0;
    }, { priority: "high" }), this.listenTo(e.model, "deleteContent", () => {
      const r = e.model.document.selection;
      if (!r.isCollapsed) {
        if (s) {
          s = !1;
          return;
        }
        Xl(e) && xP(e.model) && (i = r.getAttributes());
      }
    }, { priority: "high" }), this.listenTo(e.model, "insertContent", (r, [o]) => {
      s = !1, Xl(e) && i && (e.model.change((a) => {
        for (const [l, c] of i)
          a.setAttribute(l, c, o);
      }), i = null);
    }, { priority: "high" });
  }
  /**
   * Starts listening to {@link module:engine/model/model~Model#deleteContent} and checks whether
   * removing a content right after the "linkHref" attribute.
   *
   * If so, the selection should not preserve the `linkHref` attribute. However, if
   * the {@link module:typing/twostepcaretmovement~TwoStepCaretMovement} plugin is active and
   * the selection has the "linkHref" attribute due to overriden gravity (at the end), the `linkHref` attribute should stay untouched.
   *
   * The purpose of this action is to allow removing the link text and keep the selection outside the link.
   *
   * See https://github.com/ckeditor/ckeditor5/issues/7521.
   */
  _handleDeleteContentAfterLink() {
    const e = this.editor, t = e.model, i = t.document.selection, s = e.editing.view;
    let r = !1, o = !1;
    this.listenTo(s.document, "delete", (a, l) => {
      o = l.direction === "backward";
    }, { priority: "high" }), this.listenTo(t, "deleteContent", () => {
      r = !1;
      const a = i.getFirstPosition(), l = i.getAttribute("linkHref");
      if (!l)
        return;
      const c = li(a, "linkHref", l, t);
      r = c.containsPosition(a) || c.end.isEqual(a);
    }, { priority: "high" }), this.listenTo(t, "deleteContent", () => {
      o && (o = !1, !r && e.model.enqueueChange((a) => {
        Cs(a, Es(t.schema));
      }));
    }, { priority: "low" });
  }
  /**
   * Enables URL fixing on pasting.
   */
  _enableClipboardIntegration() {
    const e = this.editor, t = e.model, i = this.editor.config.get("link.defaultProtocol");
    i && this.listenTo(e.plugins.get("ClipboardPipeline"), "contentInsertion", (s, r) => {
      t.change((o) => {
        const a = o.createRangeIn(r.content);
        for (const l of a.getItems())
          if (l.hasAttribute("linkHref")) {
            const c = ao(l.getAttribute("linkHref"), i);
            o.setAttribute("linkHref", c, l);
          }
      });
    });
  }
}
function Cs(n, e) {
  n.removeSelectionAttribute("linkHref");
  for (const t of e)
    n.removeSelectionAttribute(t);
}
function xP(n) {
  const e = n.document.selection, t = e.getFirstPosition(), i = e.getLastPosition(), s = t.nodeAfter;
  if (!s || !s.is("$text") || !s.hasAttribute("linkHref"))
    return !1;
  const r = i.textNode || i.nodeBefore;
  return s === r ? !0 : li(t, "linkHref", s.getAttribute("linkHref"), n).containsRange(n.createRange(t, i), !0);
}
function Xl(n) {
  return n.model.change((t) => t.batch).isTyping;
}
function Es(n) {
  return n.getDefinition("$text").allowAttributes.filter((t) => t.startsWith("link"));
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class SP extends T {
  /**
   * Creates an instance of the {@link module:link/ui/linkformview~LinkFormView} class.
   *
   * Also see {@link #render}.
   *
   * @param locale The localization services instance.
   * @param linkCommand Reference to {@link module:link/linkcommand~LinkCommand}.
   */
  constructor(e, t) {
    super(e), this.focusTracker = new ye(), this.keystrokes = new Oe(), this._focusables = new nt();
    const i = e.t;
    this.urlInputView = this._createUrlInput(), this.saveButtonView = this._createButton(i("Save"), D.check, "ck-button-save"), this.saveButtonView.type = "submit", this.cancelButtonView = this._createButton(i("Cancel"), D.cancel, "ck-button-cancel", "cancel"), this._manualDecoratorSwitches = this._createManualDecoratorSwitches(t), this.children = this._createFormChildren(t.manualDecorators), this._focusCycler = new Ft({
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate form fields backwards using the Shift + Tab keystroke.
        focusPrevious: "shift + tab",
        // Navigate form fields forwards using the Tab key.
        focusNext: "tab"
      }
    });
    const s = ["ck", "ck-link-form", "ck-responsive-form"];
    t.manualDecorators.length && s.push("ck-link-form_layout-vertical", "ck-vertical-form"), this.setTemplate({
      tag: "form",
      attributes: {
        class: s,
        // https://github.com/ckeditor/ckeditor5-link/issues/90
        tabindex: "-1"
      },
      children: this.children
    });
  }
  /**
   * Obtains the state of the {@link module:ui/button/switchbuttonview~SwitchButtonView switch buttons} representing
   * {@link module:link/linkcommand~LinkCommand#manualDecorators manual link decorators}
   * in the {@link module:link/ui/linkformview~LinkFormView}.
   *
   * @returns Key-value pairs, where the key is the name of the decorator and the value is its state.
   */
  getDecoratorSwitchesState() {
    return Array.from(this._manualDecoratorSwitches).reduce((e, t) => (e[t.name] = t.isOn, e), {});
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), qr({
      view: this
    }), [
      this.urlInputView,
      ...this._manualDecoratorSwitches,
      this.saveButtonView,
      this.cancelButtonView
    ].forEach((t) => {
      this._focusables.add(t), this.focusTracker.add(t.element);
    }), this.keystrokes.listenTo(this.element);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Focuses the fist {@link #_focusables} in the form.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * Creates a labeled input view.
   *
   * @returns Labeled field view instance.
   */
  _createUrlInput() {
    const e = this.locale.t, t = new $n(this.locale, Hn);
    return t.label = e("Link URL"), t;
  }
  /**
   * Creates a button view.
   *
   * @param label The button label.
   * @param icon The button icon.
   * @param className The additional button CSS class name.
   * @param eventName An event name that the `ButtonView#execute` event will be delegated to.
   * @returns The button view instance.
   */
  _createButton(e, t, i, s) {
    const r = new H(this.locale);
    return r.set({
      label: e,
      icon: t,
      tooltip: !0
    }), r.extendTemplate({
      attributes: {
        class: i
      }
    }), s && r.delegate("execute").to(this, s), r;
  }
  /**
   * Populates {@link module:ui/viewcollection~ViewCollection} of {@link module:ui/button/switchbuttonview~SwitchButtonView}
   * made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.
   *
   * @param linkCommand A reference to the link command.
   * @returns ViewCollection of switch buttons.
   */
  _createManualDecoratorSwitches(e) {
    const t = this.createCollection();
    for (const i of e.manualDecorators) {
      const s = new Jr(this.locale);
      s.set({
        name: i.id,
        label: i.label,
        withText: !0
      }), s.bind("isOn").toMany([i, e], "value", (r, o) => o === void 0 && r === void 0 ? !!i.defaultValue : !!r), s.on("execute", () => {
        i.set("value", !s.isOn);
      }), t.add(s);
    }
    return t;
  }
  /**
   * Populates the {@link #children} collection of the form.
   *
   * If {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators} are configured in the editor, it creates an
   * additional `View` wrapping all {@link #_manualDecoratorSwitches} switch buttons corresponding
   * to these decorators.
   *
   * @param manualDecorators A reference to
   * the collection of manual decorators stored in the link command.
   * @returns The children of link form view.
   */
  _createFormChildren(e) {
    const t = this.createCollection();
    if (t.add(this.urlInputView), e.length) {
      const i = new T();
      i.setTemplate({
        tag: "ul",
        children: this._manualDecoratorSwitches.map((s) => ({
          tag: "li",
          children: [s],
          attributes: {
            class: [
              "ck",
              "ck-list__item"
            ]
          }
        })),
        attributes: {
          class: [
            "ck",
            "ck-reset",
            "ck-list"
          ]
        }
      }), t.add(i);
    }
    return t.add(this.saveButtonView), t.add(this.cancelButtonView), t;
  }
}
const IP = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class RP extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this.focusTracker = new ye(), this.keystrokes = new Oe(), this._focusables = new nt();
    const t = e.t;
    this.previewButtonView = this._createPreviewButton(), this.unlinkButtonView = this._createButton(t("Unlink"), IP, "unlink"), this.editButtonView = this._createButton(t("Edit link"), D.pencil, "edit"), this.set("href", void 0), this._focusCycler = new Ft({
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate fields backwards using the Shift + Tab keystroke.
        focusPrevious: "shift + tab",
        // Navigate fields forwards using the Tab key.
        focusNext: "tab"
      }
    }), this.setTemplate({
      tag: "div",
      attributes: {
        class: [
          "ck",
          "ck-link-actions",
          "ck-responsive-form"
        ],
        // https://github.com/ckeditor/ckeditor5-link/issues/90
        tabindex: "-1"
      },
      children: [
        this.previewButtonView,
        this.editButtonView,
        this.unlinkButtonView
      ]
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), [
      this.previewButtonView,
      this.editButtonView,
      this.unlinkButtonView
    ].forEach((t) => {
      this._focusables.add(t), this.focusTracker.add(t.element);
    }), this.keystrokes.listenTo(this.element);
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Focuses the fist {@link #_focusables} in the actions.
   */
  focus() {
    this._focusCycler.focusFirst();
  }
  /**
   * Creates a button view.
   *
   * @param label The button label.
   * @param icon The button icon.
   * @param eventName An event name that the `ButtonView#execute` event will be delegated to.
   * @returns The button view instance.
   */
  _createButton(e, t, i) {
    const s = new H(this.locale);
    return s.set({
      label: e,
      icon: t,
      tooltip: !0
    }), s.delegate("execute").to(this, i), s;
  }
  /**
   * Creates a link href preview button.
   *
   * @returns The button view instance.
   */
  _createPreviewButton() {
    const e = new H(this.locale), t = this.bindTemplate, i = this.t;
    return e.set({
      withText: !0,
      tooltip: i("Open link in new tab")
    }), e.extendTemplate({
      attributes: {
        class: [
          "ck",
          "ck-link-actions__preview"
        ],
        href: t.to("href", (s) => s && wd(s)),
        target: "_blank",
        rel: "noopener noreferrer"
      }
    }), e.bind("label").to(this, "href", (s) => s || i("This link has no URL")), e.bind("isEnabled").to(this, "href", (s) => !!s), e.template.tag = "a", e.template.eventListeners = {}, e;
  }
}
const OP = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>';
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Ve = "link-ui";
class MP extends _ {
  constructor() {
    super(...arguments), this.actionsView = null, this.formView = null;
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Cn];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "LinkUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.editing.view.addObserver(xk), this._balloon = e.plugins.get(Cn), this._createToolbarLinkButton(), this._enableBalloonActivators(), e.conversion.for("editingDowncast").markerToHighlight({
      model: Ve,
      view: {
        classes: ["ck-fake-link-selection"]
      }
    }), e.conversion.for("editingDowncast").markerToElement({
      model: Ve,
      view: {
        name: "span",
        classes: ["ck-fake-link-selection", "ck-fake-link-selection_collapsed"]
      }
    });
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.formView && this.formView.destroy(), this.actionsView && this.actionsView.destroy();
  }
  /**
   * Creates views.
   */
  _createViews() {
    this.actionsView = this._createActionsView(), this.formView = this._createFormView(), this._enableUserBalloonInteractions();
  }
  /**
   * Creates the {@link module:link/ui/linkactionsview~LinkActionsView} instance.
   */
  _createActionsView() {
    const e = this.editor, t = new RP(e.locale), i = e.commands.get("link"), s = e.commands.get("unlink");
    return t.bind("href").to(i, "value"), t.editButtonView.bind("isEnabled").to(i), t.unlinkButtonView.bind("isEnabled").to(s), this.listenTo(t, "edit", () => {
      this._addFormView();
    }), this.listenTo(t, "unlink", () => {
      e.execute("unlink"), this._hideUI();
    }), t.keystrokes.set("Esc", (r, o) => {
      this._hideUI(), o();
    }), t.keystrokes.set(ks, (r, o) => {
      this._addFormView(), o();
    }), t;
  }
  /**
   * Creates the {@link module:link/ui/linkformview~LinkFormView} instance.
   */
  _createFormView() {
    const e = this.editor, t = e.commands.get("link"), i = e.config.get("link.defaultProtocol"), s = new (jr(SP))(e.locale, t);
    return s.urlInputView.fieldView.bind("value").to(t, "value"), s.urlInputView.bind("isEnabled").to(t, "isEnabled"), s.saveButtonView.bind("isEnabled").to(t), this.listenTo(s, "submit", () => {
      const { value: r } = s.urlInputView.fieldView.element, o = ao(r, i);
      e.execute("link", o, s.getDecoratorSwitchesState()), this._closeFormView();
    }), this.listenTo(s, "cancel", () => {
      this._closeFormView();
    }), s.keystrokes.set("Esc", (r, o) => {
      this._closeFormView(), o();
    }), s;
  }
  /**
   * Creates a toolbar Link button. Clicking this button will show
   * a {@link #_balloon} attached to the selection.
   */
  _createToolbarLinkButton() {
    const e = this.editor, t = e.commands.get("link"), i = e.t;
    e.ui.componentFactory.add("link", (s) => {
      const r = new H(s);
      return r.isEnabled = !0, r.label = i("Link"), r.icon = OP, r.keystroke = ks, r.tooltip = !0, r.isToggleable = !0, r.bind("isEnabled").to(t, "isEnabled"), r.bind("isOn").to(t, "value", (o) => !!o), this.listenTo(r, "execute", () => this._showUI(!0)), r;
    });
  }
  /**
   * Attaches actions that control whether the balloon panel containing the
   * {@link #formView} should be displayed.
   */
  _enableBalloonActivators() {
    const e = this.editor, t = e.editing.view.document;
    this.listenTo(t, "click", () => {
      this._getSelectedLinkElement() && this._showUI();
    }), e.keystrokes.set(ks, (i, s) => {
      s(), e.commands.get("link").isEnabled && this._showUI(!0);
    });
  }
  /**
   * Attaches actions that control whether the balloon panel containing the
   * {@link #formView} is visible or not.
   */
  _enableUserBalloonInteractions() {
    this.editor.keystrokes.set("Tab", (e, t) => {
      this._areActionsVisible && !this.actionsView.focusTracker.isFocused && (this.actionsView.focus(), t());
    }, {
      // Use the high priority because the link UI navigation is more important
      // than other feature's actions, e.g. list indentation.
      // https://github.com/ckeditor/ckeditor5-link/issues/146
      priority: "high"
    }), this.editor.keystrokes.set("Esc", (e, t) => {
      this._isUIVisible && (this._hideUI(), t());
    }), Ur({
      emitter: this.formView,
      activator: () => this._isUIInPanel,
      contextElements: () => [this._balloon.view.element],
      callback: () => this._hideUI()
    });
  }
  /**
   * Adds the {@link #actionsView} to the {@link #_balloon}.
   *
   * @internal
   */
  _addActionsView() {
    this.actionsView || this._createViews(), !this._areActionsInPanel && this._balloon.add({
      view: this.actionsView,
      position: this._getBalloonPositionData()
    });
  }
  /**
   * Adds the {@link #formView} to the {@link #_balloon}.
   */
  _addFormView() {
    if (this.formView || this._createViews(), this._isFormInPanel)
      return;
    const t = this.editor.commands.get("link");
    this.formView.disableCssTransitions(), this._balloon.add({
      view: this.formView,
      position: this._getBalloonPositionData()
    }), this._balloon.visibleView === this.formView && this.formView.urlInputView.fieldView.select(), this.formView.enableCssTransitions(), this.formView.urlInputView.fieldView.element.value = t.value || "";
  }
  /**
   * Closes the form view. Decides whether the balloon should be hidden completely or if the action view should be shown. This is
   * decided upon the link command value (which has a value if the document selection is in the link).
   *
   * Additionally, if any {@link module:link/linkconfig~LinkConfig#decorators} are defined in the editor configuration, the state of
   * switch buttons responsible for manual decorator handling is restored.
   */
  _closeFormView() {
    const e = this.editor.commands.get("link");
    e.restoreManualDecoratorStates(), e.value !== void 0 ? this._removeFormView() : this._hideUI();
  }
  /**
   * Removes the {@link #formView} from the {@link #_balloon}.
   */
  _removeFormView() {
    this._isFormInPanel && (this.formView.saveButtonView.focus(), this._balloon.remove(this.formView), this.editor.editing.view.focus(), this._hideFakeVisualSelection());
  }
  /**
   * Shows the correct UI type. It is either {@link #formView} or {@link #actionsView}.
   *
   * @internal
   */
  _showUI(e = !1) {
    this.formView || this._createViews(), this._getSelectedLinkElement() ? (this._areActionsVisible ? this._addFormView() : this._addActionsView(), e && this._balloon.showStack("main")) : (this._showFakeVisualSelection(), this._addActionsView(), e && this._balloon.showStack("main"), this._addFormView()), this._startUpdatingUI();
  }
  /**
   * Removes the {@link #formView} from the {@link #_balloon}.
   *
   * See {@link #_addFormView}, {@link #_addActionsView}.
   */
  _hideUI() {
    if (!this._isUIInPanel)
      return;
    const e = this.editor;
    this.stopListening(e.ui, "update"), this.stopListening(this._balloon, "change:visibleView"), e.editing.view.focus(), this._removeFormView(), this._balloon.remove(this.actionsView), this._hideFakeVisualSelection();
  }
  /**
   * Makes the UI react to the {@link module:ui/editorui/editorui~EditorUI#event:update} event to
   * reposition itself when the editor UI should be refreshed.
   *
   * See: {@link #_hideUI} to learn when the UI stops reacting to the `update` event.
   */
  _startUpdatingUI() {
    const e = this.editor, t = e.editing.view.document;
    let i = this._getSelectedLinkElement(), s = o();
    const r = () => {
      const a = this._getSelectedLinkElement(), l = o();
      i && !a || !i && l !== s ? this._hideUI() : this._isUIVisible && this._balloon.updatePosition(this._getBalloonPositionData()), i = a, s = l;
    };
    function o() {
      return t.selection.focus.getAncestors().reverse().find((a) => a.is("element"));
    }
    this.listenTo(e.ui, "update", r), this.listenTo(this._balloon, "change:visibleView", r);
  }
  /**
   * Returns `true` when {@link #formView} is in the {@link #_balloon}.
   */
  get _isFormInPanel() {
    return !!this.formView && this._balloon.hasView(this.formView);
  }
  /**
   * Returns `true` when {@link #actionsView} is in the {@link #_balloon}.
   */
  get _areActionsInPanel() {
    return !!this.actionsView && this._balloon.hasView(this.actionsView);
  }
  /**
   * Returns `true` when {@link #actionsView} is in the {@link #_balloon} and it is
   * currently visible.
   */
  get _areActionsVisible() {
    return !!this.actionsView && this._balloon.visibleView === this.actionsView;
  }
  /**
   * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon}.
   */
  get _isUIInPanel() {
    return this._isFormInPanel || this._areActionsInPanel;
  }
  /**
   * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon} and it is
   * currently visible.
   */
  get _isUIVisible() {
    const e = this._balloon.visibleView;
    return !!this.formView && e == this.formView || this._areActionsVisible;
  }
  /**
   * Returns positioning options for the {@link #_balloon}. They control the way the balloon is attached
   * to the target element or selection.
   *
   * If the selection is collapsed and inside a link element, the panel will be attached to the
   * entire link element. Otherwise, it will be attached to the selection.
   */
  _getBalloonPositionData() {
    const e = this.editor.editing.view, t = this.editor.model, i = e.document;
    let s;
    if (t.markers.has(Ve)) {
      const r = Array.from(this.editor.editing.mapper.markerNameToElements(Ve)), o = e.createRange(e.createPositionBefore(r[0]), e.createPositionAfter(r[r.length - 1]));
      s = e.domConverter.viewRangeToDom(o);
    } else
      s = () => {
        const r = this._getSelectedLinkElement();
        return r ? (
          // When selection is inside link element, then attach panel to this element.
          e.domConverter.mapViewToDom(r)
        ) : (
          // Otherwise attach panel to the selection.
          e.domConverter.viewRangeToDom(i.selection.getFirstRange())
        );
      };
    return { target: s };
  }
  /**
   * Returns the link {@link module:engine/view/attributeelement~AttributeElement} under
   * the {@link module:engine/view/document~Document editing view's} selection or `null`
   * if there is none.
   *
   * **Note**: For a non–collapsed selection, the link element is returned when **fully**
   * selected and the **only** element within the selection boundaries, or when
   * a linked widget is selected.
   */
  _getSelectedLinkElement() {
    const e = this.editor.editing.view, t = e.document.selection, i = t.getSelectedElement();
    if (t.isCollapsed || i && Y(i))
      return As(t.getFirstPosition());
    {
      const s = t.getFirstRange().getTrimmed(), r = As(s.start), o = As(s.end);
      return !r || r != o ? null : e.createRangeIn(r).getTrimmed().isEqual(s) ? r : null;
    }
  }
  /**
   * Displays a fake visual selection when the contextual balloon is displayed.
   *
   * This adds a 'link-ui' marker into the document that is rendered as a highlight on selected text fragment.
   */
  _showFakeVisualSelection() {
    const e = this.editor.model;
    e.change((t) => {
      const i = e.document.selection.getFirstRange();
      if (e.markers.has(Ve))
        t.updateMarker(Ve, { range: i });
      else if (i.start.isAtEnd) {
        const s = i.start.getLastMatchingPosition(({ item: r }) => !e.schema.isContent(r), { boundaries: i });
        t.addMarker(Ve, {
          usingOperation: !1,
          affectsData: !1,
          range: t.createRange(s, i.end)
        });
      } else
        t.addMarker(Ve, {
          usingOperation: !1,
          affectsData: !1,
          range: i
        });
    });
  }
  /**
   * Hides the fake visual selection created in {@link #_showFakeVisualSelection}.
   */
  _hideFakeVisualSelection() {
    const e = this.editor.model;
    e.markers.has(Ve) && e.change((t) => {
      t.removeMarker(Ve);
    });
  }
}
function As(n) {
  return n.getAncestors().find((e) => pP(e)) || null;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const VP = 4, DP = new RegExp(
  // Group 1: Line start or after a space.
  "(^|\\s)(((?:(?:(?:https?|ftp):)?\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(((?!www\\.)|(www\\.))(?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.)+(?:[a-z\\u00a1-\\uffff]{2,63})))(?::\\d{2,5})?(?:[/?#]\\S*)?)|((www.|(\\S+@))((?![-_])(?:[-_a-z0-9\\u00a1-\\uffff]{1,63}\\.))+(?:[a-z\\u00a1-\\uffff]{2,63})))$",
  "i"
), BP = 2;
class FP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ai];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "AutoLink";
  }
  /**
   * @inheritDoc
   */
  init() {
    const t = this.editor.model.document.selection;
    t.on("change:range", () => {
      this.isEnabled = !t.anchor.parent.is("element", "codeBlock");
    }), this._enableTypingHandling();
  }
  /**
   * @inheritDoc
   */
  afterInit() {
    this._enableEnterHandling(), this._enableShiftEnterHandling();
  }
  /**
   * Enables autolinking on typing.
   */
  _enableTypingHandling() {
    const e = this.editor, t = new kE(e.model, (i) => {
      if (!NP(i))
        return;
      const s = Ql(i.substr(0, i.length - 1));
      if (s)
        return { url: s };
    });
    t.on("matched:data", (i, s) => {
      const { batch: r, range: o, url: a } = s;
      if (!r.isTyping)
        return;
      const l = o.end.getShiftedBy(-1), c = l.getShiftedBy(-a.length), u = e.model.createRange(c, l);
      this._applyAutoLink(a, u);
    }), t.bind("isEnabled").to(this);
  }
  /**
   * Enables autolinking on the <kbd>Enter</kbd> key.
   */
  _enableEnterHandling() {
    const e = this.editor, t = e.model, i = e.commands.get("enter");
    i && i.on("execute", () => {
      const s = t.document.selection.getFirstPosition();
      if (!s.parent.previousSibling)
        return;
      const r = t.createRangeIn(s.parent.previousSibling);
      this._checkAndApplyAutoLinkOnRange(r);
    });
  }
  /**
   * Enables autolinking on the <kbd>Shift</kbd>+<kbd>Enter</kbd> keyboard shortcut.
   */
  _enableShiftEnterHandling() {
    const e = this.editor, t = e.model, i = e.commands.get("shiftEnter");
    i && i.on("execute", () => {
      const s = t.document.selection.getFirstPosition(), r = t.createRange(t.createPositionAt(s.parent, 0), s.getShiftedBy(-1));
      this._checkAndApplyAutoLinkOnRange(r);
    });
  }
  /**
   * Checks if the passed range contains a linkable text.
   */
  _checkAndApplyAutoLinkOnRange(e) {
    const t = this.editor.model, { text: i, range: s } = sd(e, t), r = Ql(i);
    if (r) {
      const o = t.createRange(s.end.getShiftedBy(-r.length), s.end);
      this._applyAutoLink(r, o);
    }
  }
  /**
   * Applies a link on a given range if the link should be applied.
   *
   * @param url The URL to link.
   * @param range The text range to apply the link attribute to.
   */
  _applyAutoLink(e, t) {
    const i = this.editor.model, s = this.editor.config.get("link.defaultProtocol"), r = ao(e, s);
    !this.isEnabled || !LP(t, i) || !bd(r) || $P(t) || this._persistAutoLink(r, t);
  }
  /**
   * Enqueues autolink changes in the model.
   *
   * @param url The URL to link.
   * @param range The text range to apply the link attribute to.
   */
  _persistAutoLink(e, t) {
    const i = this.editor.model, s = this.editor.plugins.get("Delete");
    i.enqueueChange((r) => {
      r.setAttribute("linkHref", e, t), i.enqueueChange(() => {
        s.requestUndoOnBackspace();
      });
    });
  }
}
function NP(n) {
  return n.length > VP && n[n.length - 1] === " " && n[n.length - 2] !== " ";
}
function Ql(n) {
  const e = DP.exec(n);
  return e ? e[BP] : null;
}
function LP(n, e) {
  return e.schema.checkAttributeInSelection(e.createSelection(n), "linkHref");
}
function $P(n) {
  const e = n.start.nodeAfter;
  return !!e && e.hasAttribute("linkHref");
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class $5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [PP, MP, FP];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Link";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function zP(n) {
  return n.createContainerElement("span", { class: "image-inline" }, n.createEmptyElement("img"));
}
function ec(n) {
  return n.createContainerElement("figure", { class: "image" }, [
    n.createEmptyElement("img"),
    n.createSlot("children")
  ]);
}
function _d(n, e) {
  const t = n.plugins.get("ImageUtils"), i = n.plugins.has("ImageInlineEditing") && n.plugins.has("ImageBlockEditing");
  return (r) => t.isInlineImageView(r) ? i && (r.getStyle("display") == "block" || r.findAncestor(t.isBlockImageView) ? "imageBlock" : "imageInline") !== e ? null : s(r) : null;
  function s(r) {
    const o = {
      name: !0
    };
    return r.hasAttribute("src") && (o.attributes = ["src"]), o;
  }
}
function lo(n, e) {
  const t = Te(e.getSelectedBlocks());
  return !t || n.isObject(t) || t.isEmpty && t.name != "listItem" ? "imageBlock" : "imageInline";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class ht extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageUtils";
  }
  /**
   * Checks if the provided model element is an `image` or `imageInline`.
   */
  isImage(e) {
    return this.isInlineImage(e) || this.isBlockImage(e);
  }
  /**
   * Checks if the provided view element represents an inline image.
   *
   * Also, see {@link module:image/imageutils~ImageUtils#isImageWidget}.
   */
  isInlineImageView(e) {
    return !!e && e.is("element", "img");
  }
  /**
   * Checks if the provided view element represents a block image.
   *
   * Also, see {@link module:image/imageutils~ImageUtils#isImageWidget}.
   */
  isBlockImageView(e) {
    return !!e && e.is("element", "figure") && e.hasClass("image");
  }
  /**
   * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionRange}
   * method.
   *
   * ```ts
   * const imageUtils = editor.plugins.get( 'ImageUtils' );
   *
   * imageUtils.insertImage( { src: 'path/to/image.jpg' } );
   * ```
   *
   * @param attributes Attributes of the inserted image.
   * This method filters out the attributes which are disallowed by the {@link module:engine/model/schema~Schema}.
   * @param selectable Place to insert the image. If not specified,
   * the {@link module:widget/utils~findOptimalInsertionRange} logic will be applied for the block images
   * and `model.document.selection` for the inline images.
   *
   * **Note**: If `selectable` is passed, this helper will not be able to set selection attributes (such as `linkHref`)
   * and apply them to the new image. In this case, make sure all selection attributes are passed in `attributes`.
   *
   * @param imageType Image type of inserted image. If not specified,
   * it will be determined automatically depending of editor config or place of the insertion.
   * @return The inserted model image element.
   */
  insertImage(e = {}, t = null, i = null) {
    const s = this.editor, r = s.model, o = r.document.selection;
    i = vd(s, t || o, i), e = {
      ...Object.fromEntries(o.getAttributes()),
      ...e
    };
    for (const a in e)
      r.schema.checkAttribute(i, a) || delete e[a];
    return r.change((a) => {
      const l = a.createElement(i, e);
      return r.insertObject(l, t, null, {
        setSelection: "on",
        // If we want to insert a block image (for whatever reason) then we don't want to split text blocks.
        // This applies only when we don't have the selectable specified (i.e., we insert multiple block images at once).
        findOptimalPosition: !t && i != "imageInline" ? "auto" : void 0
      }), l.parent ? l : null;
    });
  }
  /**
   * Returns an image widget editing view element if one is selected or is among the selection's ancestors.
   */
  getClosestSelectedImageWidget(e) {
    const t = e.getFirstPosition();
    if (!t)
      return null;
    const i = e.getSelectedElement();
    if (i && this.isImageWidget(i))
      return i;
    let s = t.parent;
    for (; s; ) {
      if (s.is("element") && this.isImageWidget(s))
        return s;
      s = s.parent;
    }
    return null;
  }
  /**
   * Returns a image model element if one is selected or is among the selection's ancestors.
   */
  getClosestSelectedImageElement(e) {
    const t = e.getSelectedElement();
    return this.isImage(t) ? t : e.getFirstPosition().findAncestor("imageBlock");
  }
  /**
   * Checks if image can be inserted at current model selection.
   *
   * @internal
   */
  isImageAllowed() {
    const t = this.editor.model.document.selection;
    return HP(this.editor, t) && WP(t);
  }
  /**
   * Converts a given {@link module:engine/view/element~Element} to an image widget:
   * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget
   * element.
   * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
   *
   * @param writer An instance of the view writer.
   * @param label The element's label. It will be concatenated with the image `alt` attribute if one is present.
   */
  toImageWidget(e, t, i) {
    return t.setCustomProperty("image", !0, e), io(e, t, { label: () => {
      const o = this.findViewImgElement(e).getAttribute("alt");
      return o ? `${o} ${i}` : i;
    } });
  }
  /**
   * Checks if a given view element is an image widget.
   */
  isImageWidget(e) {
    return !!e.getCustomProperty("image") && Y(e);
  }
  /**
   * Checks if the provided model element is an `image`.
   */
  isBlockImage(e) {
    return !!e && e.is("element", "imageBlock");
  }
  /**
   * Checks if the provided model element is an `imageInline`.
   */
  isInlineImage(e) {
    return !!e && e.is("element", "imageInline");
  }
  /**
   * Get the view `<img>` from another view element, e.g. a widget (`<figure class="image">`), a link (`<a>`).
   *
   * The `<img>` can be located deep in other elements, so this helper performs a deep tree search.
   */
  findViewImgElement(e) {
    if (this.isInlineImageView(e))
      return e;
    const t = this.editor.editing.view;
    for (const { item: i } of t.createRangeIn(e))
      if (this.isInlineImageView(i))
        return i;
  }
}
function HP(n, e) {
  if (vd(n, e, null) == "imageBlock") {
    const i = UP(e, n.model);
    if (n.model.schema.checkChild(i, "imageBlock"))
      return !0;
  } else if (n.model.schema.checkChild(e.focus, "imageInline"))
    return !0;
  return !1;
}
function WP(n) {
  return [...n.focus.getAncestors()].every((e) => !e.is("element", "imageBlock"));
}
function UP(n, e) {
  const i = ad(n, e).start.parent;
  return i.isEmpty && !i.is("element", "$root") ? i.parent : i;
}
function vd(n, e, t) {
  const i = n.model.schema, s = n.config.get("image.insert.type");
  return n.plugins.has("ImageBlockEditing") ? n.plugins.has("ImageInlineEditing") ? t || (s === "inline" ? "imageInline" : s === "block" ? "imageBlock" : e.is("selection") ? lo(i, e) : i.checkChild(e, "imageInline") ? "imageInline" : "imageBlock") : "imageBlock" : "imageInline";
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class jP extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const i = this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);
    this.isEnabled = !!i, this.isEnabled && i.hasAttribute("alt") ? this.value = i.getAttribute("alt") : this.value = !1;
  }
  /**
   * Executes the command.
   *
   * @fires execute
   * @param options
   * @param options.newValue The new value of the `alt` attribute to set.
   */
  execute(e) {
    const t = this.editor, i = t.plugins.get("ImageUtils"), s = t.model, r = i.getClosestSelectedImageElement(s.document.selection);
    s.change((o) => {
      o.setAttribute("alt", e.newValue, r);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class qP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ht];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageTextAlternativeEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    this.editor.commands.add("imageTextAlternative", new jP(this.editor));
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class GP extends T {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = this.locale.t;
    this.focusTracker = new ye(), this.keystrokes = new Oe(), this.labeledInput = this._createLabeledInputView(), this.saveButtonView = this._createButton(t("Save"), D.check, "ck-button-save"), this.saveButtonView.type = "submit", this.cancelButtonView = this._createButton(t("Cancel"), D.cancel, "ck-button-cancel", "cancel"), this._focusables = new nt(), this._focusCycler = new Ft({
      focusables: this._focusables,
      focusTracker: this.focusTracker,
      keystrokeHandler: this.keystrokes,
      actions: {
        // Navigate form fields backwards using the Shift + Tab keystroke.
        focusPrevious: "shift + tab",
        // Navigate form fields forwards using the Tab key.
        focusNext: "tab"
      }
    }), this.setTemplate({
      tag: "form",
      attributes: {
        class: [
          "ck",
          "ck-text-alternative-form",
          "ck-responsive-form"
        ],
        // https://github.com/ckeditor/ckeditor5-image/issues/40
        tabindex: "-1"
      },
      children: [
        this.labeledInput,
        this.saveButtonView,
        this.cancelButtonView
      ]
    });
  }
  /**
   * @inheritDoc
   */
  render() {
    super.render(), this.keystrokes.listenTo(this.element), qr({ view: this }), [this.labeledInput, this.saveButtonView, this.cancelButtonView].forEach((e) => {
      this._focusables.add(e), this.focusTracker.add(e.element);
    });
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this.focusTracker.destroy(), this.keystrokes.destroy();
  }
  /**
   * Creates the button view.
   *
   * @param label The button label
   * @param icon The button's icon.
   * @param className The additional button CSS class name.
   * @param eventName The event name that the ButtonView#execute event will be delegated to.
   * @returns The button view instance.
   */
  _createButton(e, t, i, s) {
    const r = new H(this.locale);
    return r.set({
      label: e,
      icon: t,
      tooltip: !0
    }), r.extendTemplate({
      attributes: {
        class: i
      }
    }), s && r.delegate("execute").to(this, s), r;
  }
  /**
   * Creates an input with a label.
   *
   * @returns Labeled field view instance.
   */
  _createLabeledInputView() {
    const e = this.locale.t, t = new $n(this.locale, Hn);
    return t.label = e("Text alternative"), t;
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function KP(n) {
  const e = n.plugins.get("ContextualBalloon");
  if (n.plugins.get("ImageUtils").getClosestSelectedImageWidget(n.editing.view.document.selection)) {
    const i = yd(n);
    e.updatePosition(i);
  }
}
function yd(n) {
  const e = n.editing.view, t = ae.defaultPositions, i = n.plugins.get("ImageUtils");
  return {
    target: e.domConverter.mapViewToDom(i.getClosestSelectedImageWidget(e.document.selection)),
    positions: [
      t.northArrowSouth,
      t.northArrowSouthWest,
      t.northArrowSouthEast,
      t.southArrowNorth,
      t.southArrowNorthWest,
      t.southArrowNorthEast,
      t.viewportStickyNorth
    ]
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class JP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Cn];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageTextAlternativeUI";
  }
  /**
   * @inheritDoc
   */
  init() {
    this._createButton();
  }
  /**
   * @inheritDoc
   */
  destroy() {
    super.destroy(), this._form && this._form.destroy();
  }
  /**
   * Creates a button showing the balloon panel for changing the image text alternative and
   * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.
   */
  _createButton() {
    const e = this.editor, t = e.t;
    e.ui.componentFactory.add("imageTextAlternative", (i) => {
      const s = e.commands.get("imageTextAlternative"), r = new H(i);
      return r.set({
        label: t("Change image text alternative"),
        icon: D.lowVision,
        tooltip: !0
      }), r.bind("isEnabled").to(s, "isEnabled"), r.bind("isOn").to(s, "value", (o) => !!o), this.listenTo(r, "execute", () => {
        this._showForm();
      }), r;
    });
  }
  /**
   * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}
   * form.
   */
  _createForm() {
    const e = this.editor, i = e.editing.view.document, s = e.plugins.get("ImageUtils");
    this._balloon = this.editor.plugins.get("ContextualBalloon"), this._form = new (jr(GP))(e.locale), this._form.render(), this.listenTo(this._form, "submit", () => {
      e.execute("imageTextAlternative", {
        newValue: this._form.labeledInput.fieldView.element.value
      }), this._hideForm(!0);
    }), this.listenTo(this._form, "cancel", () => {
      this._hideForm(!0);
    }), this._form.keystrokes.set("Esc", (r, o) => {
      this._hideForm(!0), o();
    }), this.listenTo(e.ui, "update", () => {
      s.getClosestSelectedImageWidget(i.selection) ? this._isVisible && KP(e) : this._hideForm(!0);
    }), Ur({
      emitter: this._form,
      activator: () => this._isVisible,
      contextElements: () => [this._balloon.view.element],
      callback: () => this._hideForm()
    });
  }
  /**
   * Shows the {@link #_form} in the {@link #_balloon}.
   */
  _showForm() {
    if (this._isVisible)
      return;
    this._form || this._createForm();
    const e = this.editor, t = e.commands.get("imageTextAlternative"), i = this._form.labeledInput;
    this._form.disableCssTransitions(), this._isInBalloon || this._balloon.add({
      view: this._form,
      position: yd(e)
    }), i.fieldView.value = i.fieldView.element.value = t.value || "", this._form.labeledInput.fieldView.select(), this._form.enableCssTransitions();
  }
  /**
   * Removes the {@link #_form} from the {@link #_balloon}.
   *
   * @param focusEditable Controls whether the editing view is focused afterwards.
   */
  _hideForm(e = !1) {
    this._isInBalloon && (this._form.focusTracker.isFocused && this._form.saveButtonView.focus(), this._balloon.remove(this._form), e && this.editor.editing.view.focus());
  }
  /**
   * Returns `true` when the {@link #_form} is the visible view in the {@link #_balloon}.
   */
  get _isVisible() {
    return !!this._balloon && this._balloon.visibleView === this._form;
  }
  /**
   * Returns `true` when the {@link #_form} is in the {@link #_balloon}.
   */
  get _isInBalloon() {
    return !!this._balloon && this._balloon.hasView(this._form);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class kd extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [qP, JP];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageTextAlternative";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function ZP(n) {
  const e = (t, i, s) => {
    if (!s.consumable.test(i.viewItem, { name: !0, classes: "image" }))
      return;
    const r = n.findViewImgElement(i.viewItem);
    if (!r || !s.consumable.test(r, { name: !0 }))
      return;
    s.consumable.consume(i.viewItem, { name: !0, classes: "image" });
    const o = s.convertItem(r, i.modelCursor), a = Te(o.modelRange.getItems());
    if (!a) {
      s.consumable.revert(i.viewItem, { name: !0, classes: "image" });
      return;
    }
    s.convertChildren(i.viewItem, a), s.updateConversionResult(a, i);
  };
  return (t) => {
    t.on("element:figure", e);
  };
}
function Cd(n, e) {
  const t = (i, s, r) => {
    if (!r.consumable.consume(s.item, i.name))
      return;
    const o = r.writer, a = r.mapper.toViewElement(s.item), l = n.findViewImgElement(a);
    if (s.attributeNewValue === null) {
      const c = s.attributeOldValue;
      c && c.data && (o.removeAttribute("srcset", l), o.removeAttribute("sizes", l), c.width && o.removeAttribute("width", l));
    } else {
      const c = s.attributeNewValue;
      c && c.data && (o.setAttribute("srcset", c.data, l), o.setAttribute("sizes", "100vw", l), c.width && o.setAttribute("width", c.width, l));
    }
  };
  return (i) => {
    i.on(`attribute:srcset:${e}`, t);
  };
}
function Pn(n, e, t) {
  const i = (s, r, o) => {
    if (!o.consumable.consume(r.item, s.name))
      return;
    const a = o.writer, l = o.mapper.toViewElement(r.item), c = n.findViewImgElement(l);
    a.setAttribute(r.attributeKey, r.attributeNewValue || "", c);
  };
  return (s) => {
    s.on(`attribute:${t}:${e}`, i);
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ed extends We {
  /**
   * @inheritDoc
   */
  observe(e) {
    this.listenTo(e, "load", (t, i) => {
      const s = i.target;
      this.checkShouldIgnoreEventFromTarget(s) || s.tagName == "IMG" && this._fireEvents(i);
    }, { useCapture: !0 });
  }
  /**
   * @inheritDoc
   */
  stopObserving(e) {
    this.stopListening(e);
  }
  /**
   * Fires {@link module:engine/view/document~Document#event:layoutChanged} and
   * {@link module:engine/view/document~Document#event:imageLoaded}
   * if observer {@link #isEnabled is enabled}.
   *
   * @param domEvent The DOM event.
   */
  _fireEvents(e) {
    this.isEnabled && (this.document.fire("layoutChanged"), this.document.fire("imageLoaded", e));
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class YP extends te {
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e);
    const t = e.config.get("image.insert.type");
    e.plugins.has("ImageBlockEditing") || t === "block" && q("image-block-plugin-required"), e.plugins.has("ImageInlineEditing") || t === "inline" && q("image-inline-plugin-required");
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor.plugins.get("ImageUtils");
    this.isEnabled = e.isImageAllowed();
  }
  /**
   * Executes the command.
   *
   * @fires execute
   * @param options Options for the executed command.
   * @param options.source The image source or an array of image sources to insert.
   * See the documentation of the command to learn more about accepted formats.
   */
  execute(e) {
    const t = X(e.source), i = this.editor.model.document.selection, s = this.editor.plugins.get("ImageUtils"), r = Object.fromEntries(i.getAttributes());
    t.forEach((o, a) => {
      const l = i.getSelectedElement();
      if (typeof o == "string" && (o = { src: o }), a && l && s.isImage(l)) {
        const c = this.editor.model.createPositionAfter(l);
        s.insertImage({ ...o, ...r }, c);
      } else
        s.insertImage({ ...o, ...r });
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class XP extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const t = this.editor.plugins.get("ImageUtils"), i = this.editor.model.document.selection.getSelectedElement();
    this.isEnabled = t.isImage(i), this.value = this.isEnabled ? i.getAttribute("src") : null;
  }
  /**
   * Executes the command.
   *
   * @fires execute
   * @param options Options for the executed command.
   * @param options.source The image source to replace.
   */
  execute(e) {
    const t = this.editor.model.document.selection.getSelectedElement();
    this.editor.model.change((i) => {
      i.setAttribute("src", e.source, t), i.removeAttribute("srcset", t), i.removeAttribute("sizes", t);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Ad extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ht];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.conversion;
    e.editing.view.addObserver(Ed), t.for("upcast").attributeToAttribute({
      view: {
        name: "img",
        key: "alt"
      },
      model: "alt"
    }).attributeToAttribute({
      view: {
        name: "img",
        key: "srcset"
      },
      model: {
        key: "srcset",
        value: (r) => {
          const o = {
            data: r.getAttribute("srcset")
          };
          return r.hasAttribute("width") && (o.width = r.getAttribute("width")), o;
        }
      }
    });
    const i = new YP(e), s = new XP(e);
    e.commands.add("insertImage", i), e.commands.add("replaceImageSource", s), e.commands.add("imageInsert", i);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Td extends te {
  /**
   * @inheritDoc
   *
   * @param modelElementName Model element name the command converts to.
   */
  constructor(e, t) {
    super(e), this._modelElementName = t;
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const t = this.editor.plugins.get("ImageUtils"), i = t.getClosestSelectedImageElement(this.editor.model.document.selection);
    this._modelElementName === "imageBlock" ? this.isEnabled = t.isInlineImage(i) : this.isEnabled = t.isBlockImage(i);
  }
  /**
   * Executes the command and changes the type of a selected image.
   *
   * @fires execute
   * @returns An object containing references to old and new model image elements
   * (for before and after the change) so external integrations can hook into the decorated
   * `execute` event and handle this change. `null` if the type change failed.
   */
  execute() {
    const e = this.editor, t = this.editor.model, i = e.plugins.get("ImageUtils"), s = i.getClosestSelectedImageElement(t.document.selection), r = Object.fromEntries(s.getAttributes());
    return !r.src && !r.uploadId ? null : t.change((o) => {
      const a = Array.from(t.markers).filter((u) => u.getRange().containsItem(s)), l = i.insertImage(r, t.createSelection(s, "on"), this._modelElementName);
      if (!l)
        return null;
      const c = o.createRangeOn(l);
      for (const u of a) {
        const h = u.getRange(), f = h.root.rootName != "$graveyard" ? h.getJoined(c, !0) : c;
        o.updateMarker(u, { range: f });
      }
      return {
        oldElement: s,
        newElement: l
      };
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class QP extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Ad, ht, ut];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageBlockEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor;
    e.model.schema.register("imageBlock", {
      inheritAllFrom: "$blockObject",
      allowAttributes: ["alt", "src", "srcset"]
    }), this._setupConversion(), e.plugins.has("ImageInlineEditing") && (e.commands.add("imageTypeBlock", new Td(this.editor, "imageBlock")), this._setupClipboardIntegration());
  }
  /**
   * Configures conversion pipelines to support upcasting and downcasting
   * block images (block image widgets) and their attributes.
   */
  _setupConversion() {
    const e = this.editor, t = e.t, i = e.conversion, s = e.plugins.get("ImageUtils");
    i.for("dataDowncast").elementToStructure({
      model: "imageBlock",
      view: (r, { writer: o }) => ec(o)
    }), i.for("editingDowncast").elementToStructure({
      model: "imageBlock",
      view: (r, { writer: o }) => s.toImageWidget(ec(o), o, t("image widget"))
    }), i.for("downcast").add(Pn(s, "imageBlock", "src")).add(Pn(s, "imageBlock", "alt")).add(Cd(s, "imageBlock")), i.for("upcast").elementToElement({
      view: _d(e, "imageBlock"),
      model: (r, { writer: o }) => o.createElement("imageBlock", r.hasAttribute("src") ? { src: r.getAttribute("src") } : void 0)
    }).add(ZP(s));
  }
  /**
   * Integrates the plugin with the clipboard pipeline.
   *
   * Idea is that the feature should recognize the user's intent when an **inline** image is
   * pasted or dropped. If such an image is pasted/dropped:
   *
   * * into an empty block (e.g. an empty paragraph),
   * * on another object (e.g. some block widget).
   *
   * it gets converted into a block image on the fly. We assume this is the user's intent
   * if they decided to put their image there.
   *
   * See the `ImageInlineEditing` for the similar integration that works in the opposite direction.
   */
  _setupClipboardIntegration() {
    const e = this.editor, t = e.model, i = e.editing.view, s = e.plugins.get("ImageUtils"), r = e.plugins.get("ClipboardPipeline");
    this.listenTo(r, "inputTransformation", (o, a) => {
      const l = Array.from(a.content.getChildren());
      let c;
      if (!l.every(s.isInlineImageView))
        return;
      a.targetRanges ? c = e.editing.mapper.toModelRange(a.targetRanges[0]) : c = t.document.selection.getFirstRange();
      const u = t.createSelection(c);
      if (lo(t.schema, u) === "imageBlock") {
        const h = new Wr(i.document), f = l.map((m) => h.createElement("figure", { class: "image" }, m));
        a.content = h.createDocumentFragment(f);
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class e5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [QP, Wi, kd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageBlock";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class t5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Ad, ht, ut];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageInlineEditing";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.model.schema;
    t.register("imageInline", {
      inheritAllFrom: "$inlineObject",
      allowAttributes: ["alt", "src", "srcset"]
    }), t.addChildCheck((i, s) => {
      if (i.endsWith("caption") && s.name === "imageInline")
        return !1;
    }), this._setupConversion(), e.plugins.has("ImageBlockEditing") && (e.commands.add("imageTypeInline", new Td(this.editor, "imageInline")), this._setupClipboardIntegration());
  }
  /**
   * Configures conversion pipelines to support upcasting and downcasting
   * inline images (inline image widgets) and their attributes.
   */
  _setupConversion() {
    const e = this.editor, t = e.t, i = e.conversion, s = e.plugins.get("ImageUtils");
    i.for("dataDowncast").elementToElement({
      model: "imageInline",
      view: (r, { writer: o }) => o.createEmptyElement("img")
    }), i.for("editingDowncast").elementToStructure({
      model: "imageInline",
      view: (r, { writer: o }) => s.toImageWidget(zP(o), o, t("image widget"))
    }), i.for("downcast").add(Pn(s, "imageInline", "src")).add(Pn(s, "imageInline", "alt")).add(Cd(s, "imageInline")), i.for("upcast").elementToElement({
      view: _d(e, "imageInline"),
      model: (r, { writer: o }) => o.createElement("imageInline", r.hasAttribute("src") ? { src: r.getAttribute("src") } : void 0)
    });
  }
  /**
   * Integrates the plugin with the clipboard pipeline.
   *
   * Idea is that the feature should recognize the user's intent when an **block** image is
   * pasted or dropped. If such an image is pasted/dropped into a non-empty block
   * (e.g. a paragraph with some text) it gets converted into an inline image on the fly.
   *
   * We assume this is the user's intent if they decided to put their image there.
   *
   * **Note**: If a block image has a caption, it will not be converted to an inline image
   * to avoid the confusion. Captions are added on purpose and they should never be lost
   * in the clipboard pipeline.
   *
   * See the `ImageBlockEditing` for the similar integration that works in the opposite direction.
   */
  _setupClipboardIntegration() {
    const e = this.editor, t = e.model, i = e.editing.view, s = e.plugins.get("ImageUtils"), r = e.plugins.get("ClipboardPipeline");
    this.listenTo(r, "inputTransformation", (o, a) => {
      const l = Array.from(a.content.getChildren());
      let c;
      if (!l.every(s.isBlockImageView))
        return;
      a.targetRanges ? c = e.editing.mapper.toModelRange(a.targetRanges[0]) : c = t.document.selection.getFirstRange();
      const u = t.createSelection(c);
      if (lo(t.schema, u) === "imageInline") {
        const h = new Wr(i.document), f = l.map((m) => m.childCount === 1 ? (Array.from(m.getAttributes()).forEach((p) => h.setAttribute(...p, s.findViewImgElement(m))), m.getChild(0)) : m);
        a.content = h.createDocumentFragment(f);
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class i5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [t5, Wi, kd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageInline";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class z5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [e5, i5];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "Image";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class n5 extends te {
  /**
   * @inheritDoc
   */
  refresh() {
    const e = this.editor, i = e.plugins.get("ImageUtils").getClosestSelectedImageElement(e.model.document.selection);
    this.isEnabled = !!i, !i || !i.hasAttribute("width") ? this.value = null : this.value = {
      width: i.getAttribute("width"),
      height: null
    };
  }
  /**
   * Executes the command.
   *
   * ```ts
   * // Sets the width to 50%:
   * editor.execute( 'resizeImage', { width: '50%' } );
   *
   * // Removes the width attribute:
   * editor.execute( 'resizeImage', { width: null } );
   * ```
   *
   * @param options
   * @param options.width The new width of the image.
   * @fires execute
   */
  execute(e) {
    const t = this.editor, i = t.model, r = t.plugins.get("ImageUtils").getClosestSelectedImageElement(i.document.selection);
    this.value = {
      width: e.width,
      height: null
    }, r && i.change((o) => {
      o.setAttribute("width", e.width, r);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Pd extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ht];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageResizeEditing";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), e.config.define("image", {
      resizeUnit: "%",
      resizeOptions: [
        {
          name: "resizeImage:original",
          value: null,
          icon: "original"
        },
        {
          name: "resizeImage:25",
          value: "25",
          icon: "small"
        },
        {
          name: "resizeImage:50",
          value: "50",
          icon: "medium"
        },
        {
          name: "resizeImage:75",
          value: "75",
          icon: "large"
        }
      ]
    });
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = new n5(e);
    this._registerSchema(), this._registerConverters("imageBlock"), this._registerConverters("imageInline"), e.commands.add("resizeImage", t), e.commands.add("imageResize", t);
  }
  _registerSchema() {
    this.editor.plugins.has("ImageBlockEditing") && this.editor.model.schema.extend("imageBlock", { allowAttributes: "width" }), this.editor.plugins.has("ImageInlineEditing") && this.editor.model.schema.extend("imageInline", { allowAttributes: "width" });
  }
  /**
   * Registers image resize converters.
   *
   * @param imageType The type of the image.
   */
  _registerConverters(e) {
    const t = this.editor;
    t.conversion.for("downcast").add((i) => i.on(`attribute:width:${e}`, (s, r, o) => {
      if (!o.consumable.consume(r.item, s.name))
        return;
      const a = o.writer, l = o.mapper.toViewElement(r.item);
      r.attributeNewValue !== null ? (a.setStyle("width", r.attributeNewValue, l), a.addClass("image_resized", l)) : (a.removeStyle("width", l), a.removeClass("image_resized", l));
    })), t.conversion.for("upcast").attributeToAttribute({
      view: {
        name: e === "imageBlock" ? "figure" : "img",
        styles: {
          width: /.+/
        }
      },
      model: {
        key: "width",
        value: (i) => i.getStyle("width")
      }
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const Ts = {
  small: D.objectSizeSmall,
  medium: D.objectSizeMedium,
  large: D.objectSizeLarge,
  original: D.objectSizeFull
};
class s5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Pd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageResizeButtons";
  }
  /**
   * @inheritDoc
   */
  constructor(e) {
    super(e), this._resizeUnit = e.config.get("image.resizeUnit");
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor, t = e.config.get("image.resizeOptions"), i = e.commands.get("resizeImage");
    this.bind("isEnabled").to(i);
    for (const s of t)
      this._registerImageResizeButton(s);
    this._registerImageResizeDropdown(t);
  }
  /**
   * A helper function that creates a standalone button component for the plugin.
   *
   * @param resizeOption A model of the resize option.
   */
  _registerImageResizeButton(e) {
    const t = this.editor, { name: i, value: s, icon: r } = e, o = s ? s + this._resizeUnit : null;
    t.ui.componentFactory.add(i, (a) => {
      const l = new H(a), c = t.commands.get("resizeImage"), u = this._getOptionLabelValue(e, !0);
      if (!Ts[r])
        throw new d("imageresizebuttons-missing-icon", t, e);
      return l.set({
        // Use the `label` property for a verbose description (because of ARIA).
        label: u,
        icon: Ts[r],
        tooltip: u,
        isToggleable: !0
      }), l.bind("isEnabled").to(this), l.bind("isOn").to(c, "value", tc(o)), this.listenTo(l, "execute", () => {
        t.execute("resizeImage", { width: o });
      }), l;
    });
  }
  /**
   * A helper function that creates a dropdown component for the plugin containing all the resize options defined in
   * the editor configuration.
   *
   * @param options An array of configured options.
   */
  _registerImageResizeDropdown(e) {
    const t = this.editor, i = t.t, s = e.find((o) => !o.value), r = (o) => {
      const a = t.commands.get("resizeImage"), l = gt(o, $h), c = l.buttonView, u = i("Resize image");
      return c.set({
        tooltip: u,
        commandValue: s.value,
        icon: Ts.medium,
        isToggleable: !0,
        label: this._getOptionLabelValue(s),
        withText: !0,
        class: "ck-resize-image-button",
        ariaLabel: u,
        ariaLabelledBy: void 0
      }), c.bind("label").to(a, "value", (h) => h && h.width ? h.width : this._getOptionLabelValue(s)), l.bind("isEnabled").to(this), qh(l, () => this._getResizeDropdownListItemDefinitions(e, a), {
        ariaLabel: i("Image resize list"),
        role: "menu"
      }), this.listenTo(l, "execute", (h) => {
        t.execute(h.source.commandName, { width: h.source.commandValue }), t.editing.view.focus();
      }), l;
    };
    t.ui.componentFactory.add("resizeImage", r), t.ui.componentFactory.add("imageResize", r);
  }
  /**
   * A helper function for creating an option label value string.
   *
   * @param option A resize option object.
   * @param forTooltip An optional flag for creating a tooltip label.
   * @returns A user-defined label combined from the numeric value and the resize unit or the default label
   * for reset options (`Original`).
   */
  _getOptionLabelValue(e, t = !1) {
    const i = this.editor.t;
    return e.label ? e.label : t ? e.value ? i("Resize image to %0", e.value + this._resizeUnit) : i("Resize image to the original size") : e.value ? e.value + this._resizeUnit : i("Original");
  }
  /**
   * A helper function that parses the resize options and returns list item definitions ready for use in the dropdown.
   *
   * @param options The resize options.
   * @param command The resize image command.
   * @returns Dropdown item definitions.
   */
  _getResizeDropdownListItemDefinitions(e, t) {
    const i = new He();
    return e.map((s) => {
      const r = s.value ? s.value + this._resizeUnit : null, o = {
        type: "button",
        model: new Qh({
          commandName: "resizeImage",
          commandValue: r,
          label: this._getOptionLabelValue(s),
          role: "menuitemradio",
          withText: !0,
          icon: null
        })
      };
      o.model.bind("isOn").to(t, "value", tc(r)), i.add(o);
    }), i;
  }
}
function tc(n) {
  return (e) => {
    const t = e;
    return n === null && t === n ? !0 : t !== null && t.width === n;
  };
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const r5 = "figure.image.ck-widget > img,figure.image.ck-widget > picture > img,figure.image.ck-widget > a > img,figure.image.ck-widget > a > picture > img,span.image-inline.ck-widget > img,span.image-inline.ck-widget > picture > img", o5 = /(image|image-inline)/, Ps = "image_resized";
class a5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ps];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageResizeHandles";
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.commands.get("resizeImage");
    this.bind("isEnabled").to(e), this._setupResizerCreator();
  }
  /**
   * Attaches the listeners responsible for creating a resizer for each image, except for images inside the HTML embed preview.
   */
  _setupResizerCreator() {
    const e = this.editor, t = e.editing.view;
    t.addObserver(Ed), this.listenTo(t.document, "imageLoaded", (i, s) => {
      if (!s.target.matches(r5))
        return;
      const r = e.editing.view.domConverter, a = r.domToView(s.target).findAncestor({ classes: o5 });
      let l = this.editor.plugins.get(ps).getResizerByViewElement(a);
      if (l) {
        l.redraw();
        return;
      }
      const c = e.editing.mapper, u = c.toModelElement(a);
      l = e.plugins.get(ps).attachTo({
        unit: e.config.get("image.resizeUnit"),
        modelElement: u,
        viewElement: a,
        editor: e,
        getHandleHost(h) {
          return h.querySelector("img");
        },
        getResizeHost() {
          return r.mapViewToDom(c.toViewElement(u.parent));
        },
        // TODO consider other positions.
        isCentered() {
          const h = u.getAttribute("imageStyle");
          return !h || h == "block" || h == "alignCenter";
        },
        onCommit(h) {
          t.change((f) => {
            f.removeClass(Ps, a);
          }), e.execute("resizeImage", { width: h });
        }
      }), l.on("updateSize", () => {
        a.hasClass(Ps) || t.change((h) => {
          h.addClass(Ps, a);
        });
      }), l.bind("isEnabled").to(this);
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class H5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Pd, a5, s5];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageResize";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class l5 extends te {
  /**
   * Creates an instance of the image style command. When executed, the command applies one of
   * {@link module:image/imageconfig~ImageStyleConfig#options style options} to the currently selected image.
   *
   * @param editor The editor instance.
   * @param styles The style options that this command supports.
   */
  constructor(e, t) {
    super(e), this._defaultStyles = {
      imageBlock: !1,
      imageInline: !1
    }, this._styles = new Map(t.map((i) => {
      if (i.isDefault)
        for (const s of i.modelElements)
          this._defaultStyles[s] = i.name;
      return [i.name, i];
    }));
  }
  /**
   * @inheritDoc
   */
  refresh() {
    const i = this.editor.plugins.get("ImageUtils").getClosestSelectedImageElement(this.editor.model.document.selection);
    this.isEnabled = !!i, this.isEnabled ? i.hasAttribute("imageStyle") ? this.value = i.getAttribute("imageStyle") : this.value = this._defaultStyles[i.name] : this.value = !1;
  }
  /**
   * Executes the command and applies the style to the currently selected image:
   *
   * ```ts
   * editor.execute( 'imageStyle', { value: 'side' } );
   * ```
   *
   * **Note**: Executing this command may change the image model element if the desired style requires an image
   * of a different type. Learn more about {@link module:image/imageconfig~ImageStyleOptionDefinition#modelElements model element}
   * configuration for the style option.
   *
   * @param options.value The name of the style (as configured in {@link module:image/imageconfig~ImageStyleConfig#options}).
   * @fires execute
   */
  execute(e = {}) {
    const t = this.editor, i = t.model, s = t.plugins.get("ImageUtils");
    i.change((r) => {
      const o = e.value;
      let a = s.getClosestSelectedImageElement(i.document.selection);
      o && this.shouldConvertImageType(o, a) && (this.editor.execute(s.isBlockImage(a) ? "imageTypeInline" : "imageTypeBlock"), a = s.getClosestSelectedImageElement(i.document.selection)), !o || this._styles.get(o).isDefault ? r.removeAttribute("imageStyle", a) : r.setAttribute("imageStyle", o, a);
    });
  }
  /**
   * Returns `true` if requested style change would trigger the image type change.
   *
   * @param requestedStyle The name of the style (as configured in {@link module:image/imageconfig~ImageStyleConfig#options}).
   * @param imageElement The image model element.
   */
  shouldConvertImageType(e, t) {
    return !this._styles.get(e).modelElements.includes(t.name);
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
const { objectFullWidth: c5, objectInline: xd, objectLeft: Sd, objectRight: cr, objectCenter: ur, objectBlockLeft: Id, objectBlockRight: Rd } = D, un = {
  // This style represents an image placed in the line of text.
  get inline() {
    return {
      name: "inline",
      title: "In line",
      icon: xd,
      modelElements: ["imageInline"],
      isDefault: !0
    };
  },
  // This style represents an image aligned to the left and wrapped with text.
  get alignLeft() {
    return {
      name: "alignLeft",
      title: "Left aligned image",
      icon: Sd,
      modelElements: ["imageBlock", "imageInline"],
      className: "image-style-align-left"
    };
  },
  // This style represents an image aligned to the left.
  get alignBlockLeft() {
    return {
      name: "alignBlockLeft",
      title: "Left aligned image",
      icon: Id,
      modelElements: ["imageBlock"],
      className: "image-style-block-align-left"
    };
  },
  // This style represents a centered image.
  get alignCenter() {
    return {
      name: "alignCenter",
      title: "Centered image",
      icon: ur,
      modelElements: ["imageBlock"],
      className: "image-style-align-center"
    };
  },
  // This style represents an image aligned to the right and wrapped with text.
  get alignRight() {
    return {
      name: "alignRight",
      title: "Right aligned image",
      icon: cr,
      modelElements: ["imageBlock", "imageInline"],
      className: "image-style-align-right"
    };
  },
  // This style represents an image aligned to the right.
  get alignBlockRight() {
    return {
      name: "alignBlockRight",
      title: "Right aligned image",
      icon: Rd,
      modelElements: ["imageBlock"],
      className: "image-style-block-align-right"
    };
  },
  // This option is equal to the situation when no style is applied.
  get block() {
    return {
      name: "block",
      title: "Centered image",
      icon: ur,
      modelElements: ["imageBlock"],
      isDefault: !0
    };
  },
  // This represents a side image.
  get side() {
    return {
      name: "side",
      title: "Side image",
      icon: cr,
      modelElements: ["imageBlock"],
      className: "image-style-side"
    };
  }
}, Od = {
  full: c5,
  left: Id,
  right: Rd,
  center: ur,
  inlineLeft: Sd,
  inlineRight: cr,
  inline: xd
}, Md = [{
  name: "imageStyle:wrapText",
  title: "Wrap text",
  defaultItem: "imageStyle:alignLeft",
  items: ["imageStyle:alignLeft", "imageStyle:alignRight"]
}, {
  name: "imageStyle:breakText",
  title: "Break text",
  defaultItem: "imageStyle:block",
  items: ["imageStyle:alignBlockLeft", "imageStyle:block", "imageStyle:alignBlockRight"]
}];
function u5(n) {
  return (n.configuredStyles.options || []).map((i) => f5(i)).filter((i) => m5(i, n));
}
function h5(n, e) {
  return n && e ? {
    options: [
      "inline",
      "alignLeft",
      "alignRight",
      "alignCenter",
      "alignBlockLeft",
      "alignBlockRight",
      "block",
      "side"
    ]
  } : n ? {
    options: ["block", "side"]
  } : e ? {
    options: ["inline", "alignLeft", "alignRight"]
  } : {};
}
function d5(n) {
  return n.has("ImageBlockEditing") && n.has("ImageInlineEditing") ? [...Md] : [];
}
function f5(n) {
  return typeof n == "string" ? un[n] ? n = { ...un[n] } : n = { name: n } : n = g5(un[n.name], n), typeof n.icon == "string" && (n.icon = Od[n.icon] || n.icon), n;
}
function m5(n, { isBlockPluginLoaded: e, isInlinePluginLoaded: t }) {
  const { modelElements: i, name: s } = n;
  if (!i || !i.length || !s)
    return Vd({ style: n }), !1;
  {
    const r = [e ? "imageBlock" : null, t ? "imageInline" : null];
    if (!i.some((o) => r.includes(o)))
      return q("image-style-missing-dependency", {
        style: n,
        missingPlugins: i.map((o) => o === "imageBlock" ? "ImageBlockEditing" : "ImageInlineEditing")
      }), !1;
  }
  return !0;
}
function g5(n, e) {
  const t = { ...e };
  for (const i in n)
    Object.prototype.hasOwnProperty.call(e, i) || (t[i] = n[i]);
  return t;
}
function Vd(n) {
  q("image-style-configuration-definition-invalid", n);
}
const hr = {
  normalizeStyles: u5,
  getDefaultStylesConfiguration: h5,
  getDefaultDropdownDefinitions: d5,
  warnInvalidStyle: Vd,
  DEFAULT_OPTIONS: un,
  DEFAULT_ICONS: Od,
  DEFAULT_DROPDOWN_DEFINITIONS: Md
};
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
function p5(n) {
  return (e, t, i) => {
    if (!i.consumable.consume(t.item, e.name))
      return;
    const s = ic(t.attributeNewValue, n), r = ic(t.attributeOldValue, n), o = i.mapper.toViewElement(t.item), a = i.writer;
    r && a.removeClass(r.className, o), s && a.addClass(s.className, o);
  };
}
function w5(n) {
  const e = {
    imageInline: n.filter((t) => !t.isDefault && t.modelElements.includes("imageInline")),
    imageBlock: n.filter((t) => !t.isDefault && t.modelElements.includes("imageBlock"))
  };
  return (t, i, s) => {
    if (!i.modelRange)
      return;
    const r = i.viewItem, o = Te(i.modelRange.getItems());
    if (o && s.schema.checkAttribute(o, "imageStyle"))
      for (const a of e[o.name])
        s.consumable.consume(r, { classes: a.className }) && s.writer.setAttribute("imageStyle", a.name, o);
  };
}
function ic(n, e) {
  for (const t of e)
    if (t.name === n)
      return t;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class Dd extends _ {
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageStyleEditing";
  }
  /**
   * @inheritDoc
   */
  static get requires() {
    return [ht];
  }
  /**
   * @inheritDoc
   */
  init() {
    const { normalizeStyles: e, getDefaultStylesConfiguration: t } = hr, i = this.editor, s = i.plugins.has("ImageBlockEditing"), r = i.plugins.has("ImageInlineEditing");
    i.config.define("image.styles", t(s, r)), this.normalizedStyles = e({
      configuredStyles: i.config.get("image.styles"),
      isBlockPluginLoaded: s,
      isInlinePluginLoaded: r
    }), this._setupConversion(s, r), this._setupPostFixer(), i.commands.add("imageStyle", new l5(i, this.normalizedStyles));
  }
  /**
   * Sets the editor conversion taking the presence of
   * {@link module:image/image/imageinlineediting~ImageInlineEditing `ImageInlineEditing`}
   * and {@link module:image/image/imageblockediting~ImageBlockEditing `ImageBlockEditing`} plugins into consideration.
   */
  _setupConversion(e, t) {
    const i = this.editor, s = i.model.schema, r = p5(this.normalizedStyles), o = w5(this.normalizedStyles);
    i.editing.downcastDispatcher.on("attribute:imageStyle", r), i.data.downcastDispatcher.on("attribute:imageStyle", r), e && (s.extend("imageBlock", { allowAttributes: "imageStyle" }), i.data.upcastDispatcher.on("element:figure", o, { priority: "low" })), t && (s.extend("imageInline", { allowAttributes: "imageStyle" }), i.data.upcastDispatcher.on("element:img", o, { priority: "low" }));
  }
  /**
   * Registers a post-fixer that will make sure that the style attribute value is correct for a specific image type (block vs inline).
   */
  _setupPostFixer() {
    const e = this.editor, t = e.model.document, i = e.plugins.get(ht), s = new Map(this.normalizedStyles.map((r) => [r.name, r]));
    t.registerPostFixer((r) => {
      let o = !1;
      for (const a of t.differ.getChanges())
        if (a.type == "insert" || a.type == "attribute" && a.attributeKey == "imageStyle") {
          let l = a.type == "insert" ? a.position.nodeAfter : a.range.start.nodeAfter;
          if (l && l.is("element", "paragraph") && l.childCount > 0 && (l = l.getChild(0)), !i.isImage(l))
            continue;
          const c = l.getAttribute("imageStyle");
          if (!c)
            continue;
          const u = s.get(c);
          (!u || !u.modelElements.includes(l.name)) && (r.removeAttribute("imageStyle", l), o = !0);
        }
      return o;
    });
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class b5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Dd];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageStyleUI";
  }
  /**
   * Returns the default localized style titles provided by the plugin.
   *
   * The following localized titles corresponding with
   * {@link module:image/imagestyle/utils#DEFAULT_OPTIONS} are available:
   *
   * * `'Wrap text'`,
   * * `'Break text'`,
   * * `'In line'`,
   * * `'Full size image'`,
   * * `'Side image'`,
   * * `'Left aligned image'`,
   * * `'Centered image'`,
   * * `'Right aligned image'`
   */
  get localizedDefaultStylesTitles() {
    const e = this.editor.t;
    return {
      "Wrap text": e("Wrap text"),
      "Break text": e("Break text"),
      "In line": e("In line"),
      "Full size image": e("Full size image"),
      "Side image": e("Side image"),
      "Left aligned image": e("Left aligned image"),
      "Centered image": e("Centered image"),
      "Right aligned image": e("Right aligned image")
    };
  }
  /**
   * @inheritDoc
   */
  init() {
    const e = this.editor.plugins, t = this.editor.config.get("image.toolbar") || [], i = e.get("ImageStyleEditing"), s = nc(i.normalizedStyles, this.localizedDefaultStylesTitles);
    for (const o of s)
      this._createButton(o);
    const r = nc([
      ...t.filter(G),
      ...hr.getDefaultDropdownDefinitions(e)
    ], this.localizedDefaultStylesTitles);
    for (const o of r)
      this._createDropdown(o, s);
  }
  /**
   * Creates a dropdown and stores it in the editor {@link module:ui/componentfactory~ComponentFactory}.
   */
  _createDropdown(e, t) {
    const i = this.editor.ui.componentFactory;
    i.add(e.name, (s) => {
      let r;
      const { defaultItem: o, items: a, title: l } = e, c = a.filter((m) => t.find(({ name: p }) => sc(p) === m)).map((m) => {
        const p = i.create(m);
        return m === o && (r = p), p;
      });
      a.length !== c.length && hr.warnInvalidStyle({ dropdown: e });
      const u = gt(s, jh), h = u.buttonView, f = h.arrowView;
      return zn(u, c, { enableActiveItemFocusOnDropdownOpen: !0 }), h.set({
        label: rc(l, r.label),
        class: null,
        tooltip: !0
      }), f.unbind("label"), f.set({
        label: l
      }), h.bind("icon").toMany(c, "isOn", (...m) => {
        const p = m.findIndex(kt);
        return p < 0 ? r.icon : c[p].icon;
      }), h.bind("label").toMany(c, "isOn", (...m) => {
        const p = m.findIndex(kt);
        return rc(l, p < 0 ? r.label : c[p].label);
      }), h.bind("isOn").toMany(c, "isOn", (...m) => m.some(kt)), h.bind("class").toMany(c, "isOn", (...m) => m.some(kt) ? "ck-splitbutton_flatten" : void 0), h.on("execute", () => {
        c.some(({ isOn: m }) => m) ? u.isOpen = !u.isOpen : r.fire("execute");
      }), u.bind("isEnabled").toMany(c, "isEnabled", (...m) => m.some(kt)), this.listenTo(u, "execute", () => {
        this.editor.editing.view.focus();
      }), u;
    });
  }
  /**
   * Creates a button and stores it in the editor {@link module:ui/componentfactory~ComponentFactory}.
   */
  _createButton(e) {
    const t = e.name;
    this.editor.ui.componentFactory.add(sc(t), (i) => {
      const s = this.editor.commands.get("imageStyle"), r = new H(i);
      return r.set({
        label: e.title,
        icon: e.icon,
        tooltip: !0,
        isToggleable: !0
      }), r.bind("isEnabled").to(s, "isEnabled"), r.bind("isOn").to(s, "value", (o) => o === t), r.on("execute", this._executeCommand.bind(this, t)), r;
    });
  }
  _executeCommand(e) {
    this.editor.execute("imageStyle", { value: e }), this.editor.editing.view.focus();
  }
}
function nc(n, e) {
  for (const t of n)
    e[t.title] && (t.title = e[t.title]);
  return n;
}
function sc(n) {
  return `imageStyle:${n}`;
}
function rc(n, e) {
  return (n ? n + ": " : "") + e;
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class W5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Dd, b5];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageStyle";
  }
}
/**
 * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
 */
class U5 extends _ {
  /**
   * @inheritDoc
   */
  static get requires() {
    return [Pl, ht];
  }
  /**
   * @inheritDoc
   */
  static get pluginName() {
    return "ImageToolbar";
  }
  /**
   * @inheritDoc
   */
  afterInit() {
    const e = this.editor, t = e.t, i = e.plugins.get(Pl), s = e.plugins.get("ImageUtils");
    i.register("image", {
      ariaLabel: t("Image toolbar"),
      items: _5(e.config.get("image.toolbar") || []),
      getRelatedElement: (r) => s.getClosestSelectedImageWidget(r)
    });
  }
}
function _5(n) {
  return n.map((e) => G(e) ? e.name : e);
}
export {
  O5 as Alignment,
  M5 as Bold,
  H as ButtonView,
  He as Collection,
  te as Command,
  $h as DropdownButtonView,
  R5 as Essentials,
  F5 as FontColor,
  L5 as GeneralHtmlSupport,
  B5 as Heading,
  z5 as Image,
  H5 as ImageResize,
  W5 as ImageStyle,
  U5 as ImageToolbar,
  ht as ImageUtils,
  Qr as InlineEditor,
  V5 as Italic,
  $5 as Link,
  N5 as MediaEmbed,
  Qh as Model,
  We as Observer,
  Wn as Paragraph,
  _ as Plugin,
  D5 as Underline,
  dd as Undo,
  Wi as Widget,
  ps as WidgetResize,
  Pl as WidgetToolbarRepository,
  qh as addListToDropdown,
  gt as createDropdown,
  ad as findOptimalInsertionRange,
  Y as isWidget,
  io as toWidget,
  I5 as viewToModelPositionOutsideModelElement
};
