var __getOwnPropNames = Object.getOwnPropertyNames;
var __commonJS = (cb, mod) => function __require() {
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var require_sequencer = __commonJS({
  "sequencer.js"(exports, module) {
    const CONSTANTS = {
      MODULE_NAME: "sequencer",
      EFFECTS_FLAG_NAME: "effects",
      SOUNDS_FLAG_NAME: "sounds",
      EFFECTS_LAYER: "sequencerEffects",
      INTERFACE_LAYER: "sequencerInterfaceLayer",
      IS_V13: false,
      COLOR: {
        PRIMARY: 15615023,
        SECONDARY: 6298186
      },
      SHAPES: {
        POLY: "polygon",
        RECT: "rectangle",
        CIRC: "circle",
        ELIP: "ellipse",
        RREC: "roundedRect"
      },
      FEET_REGEX: new RegExp(/\.[0-9]+ft\.*/g),
      ARRAY_REGEX: new RegExp(/\.[0-9]$/g),
      STATUS: {
        READY: 0,
        RUNNING: 1,
        COMPLETE: 2,
        SKIPPED: 3,
        ABORTED: 4
      },
      PLACEMENT_RESTRICTIONS: {
        ANYWHERE: "anywhere",
        LINE_OF_SIGHT: "lineOfSight",
        NO_COLLIDABLES: "noCollidables"
      },
      CALLBACKS: {
        SHOW: "show",
        MOUSE_MOVE: "mouseMove",
        MOVE: "move",
        COLLIDE: "collide",
        STOP_COLLIDING: "stopColliding",
        INVALID_PLACEMENT: "invalidPlacement",
        PLACED: "placed",
        CANCEL: "cancel"
      }
    };
    CONSTANTS.TOOLS = {
      SELECT: `${CONSTANTS.MODULE_NAME}-select-effect`,
      PLAY: `${CONSTANTS.MODULE_NAME}-play-effect`,
      VIEWER: `${CONSTANTS.MODULE_NAME}-effectviewer`,
      DATABASE: `${CONSTANTS.MODULE_NAME}-effectdatabase`
    };
    CONSTANTS.EFFECTS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.${CONSTANTS.EFFECTS_FLAG_NAME}`;
    CONSTANTS.REMOVE_EFFECTS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.-=${CONSTANTS.EFFECTS_FLAG_NAME}`;
    CONSTANTS.SOUNDS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.${CONSTANTS.SOUNDS_FLAG_NAME}`;
    CONSTANTS.REMOVE_SOUNDS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.-=${CONSTANTS.SOUNDS_FLAG_NAME}`;
    function registerEase(easeName, easeFunction, overwrite = false) {
      if (typeof easeName !== "string")
        throw custom_error("registerEase", "easeName must be of type string");
      if (!is_function$1(easeFunction))
        throw custom_error(
          "registerEase",
          "easeFunction must be of type function"
        );
      if (easeFunctions[easeName] !== void 0 && !overwrite) return;
      debug(`registerEase | Registered ease function: ${easeName}`);
      easeFunctions[easeName] = easeFunction;
    }
    const easeFunctions = {
      linear,
      easeInSine,
      easeOutSine,
      easeInOutSine,
      easeInQuad,
      easeOutQuad,
      easeInOutQuad,
      easeInCubic,
      easeOutCubic,
      easeInOutCubic,
      easeInQuart,
      easeOutQuart,
      easeInOutQuart,
      easeInQuint,
      easeOutQuint,
      easeInOutQuint,
      easeInExpo,
      easeOutExpo,
      easeInOutExpo,
      easeInCirc,
      easeOutCirc,
      easeInOutCirc,
      easeInBack,
      easeOutBack,
      easeInOutBack,
      easeInElastic,
      easeOutElastic,
      easeInOutElastic,
      easeInBounce,
      easeOutBounce,
      easeInOutBounce
    };
    const EASE = {
      LINEAR: "linear",
      SINE_IN: "easeInSine",
      SINE_OUT: "easeOutSine",
      SINE_IN_OUT: "easeInOutSine",
      QUAD_IN: "easeInQuad",
      QUAD_OUT: "easeOutQuad",
      QUAD_IN_OUT: "easeInOutQuad",
      CUBIC_IN: "easeInCubic",
      CUBIC_OUT: "easeOutCubic",
      CUBIC_IN_OUT: "easeInOutCubic",
      QUART_IN: "easeInQuart",
      QUART_OUT: "easeOutQuart",
      QUART_IN_OUT: "easeInOutQuart",
      QUINT_IN: "easeInQuint",
      QUINT_OUT: "easeOutQuint",
      QUINT_IN_OUT: "easeInOutQuint",
      EXPO_IN: "easeInExpo",
      EXPO_OUT: "easeOutExpo",
      EXPO_IN_OUT: "easeInOutExpo",
      CIRC_IN: "easeInCirc",
      CIRC_OUT: "easeOutCirc",
      CIRC_IN_OUT: "easeInOutCirc",
      BACK_IN: "easeInBack",
      BACK_OUT: "easeOutBack",
      BACK_IN_OUT: "easeInOutBack",
      ELASTIC_IN: "easeInElastic",
      ELASTIC_OUT: "easeOutElastic",
      ELASTIC_IN_OUT: "easeInOutElastic",
      BOUNCE_IN: "easeInBounce",
      BOUNCE_OUT: "easeOutBounce",
      BOUNCE_IN_OUT: "easeInOutBounce"
    };
    function linear(x) {
      return x;
    }
    function easeInSine(x) {
      return 1 - Math.cos(x * Math.PI / 2);
    }
    function easeOutSine(x) {
      return Math.sin(x * Math.PI / 2);
    }
    function easeInOutSine(x) {
      return -(Math.cos(Math.PI * x) - 1) / 2;
    }
    function easeInQuad(x) {
      return x * x;
    }
    function easeOutQuad(x) {
      return 1 - (1 - x) * (1 - x);
    }
    function easeInOutQuad(x) {
      return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
    }
    function easeInCubic(x) {
      return x * x * x;
    }
    function easeOutCubic(x) {
      return 1 - Math.pow(1 - x, 3);
    }
    function easeInOutCubic(x) {
      return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
    }
    function easeInQuart(x) {
      return x * x * x * x;
    }
    function easeOutQuart(x) {
      return 1 - Math.pow(1 - x, 4);
    }
    function easeInOutQuart(x) {
      return x < 0.5 ? 8 * x * x * x * x : 1 - Math.pow(-2 * x + 2, 4) / 2;
    }
    function easeInQuint(x) {
      return x * x * x * x * x;
    }
    function easeOutQuint(x) {
      return 1 - Math.pow(1 - x, 5);
    }
    function easeInOutQuint(x) {
      return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
    }
    function easeInExpo(x) {
      return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
    }
    function easeOutExpo(x) {
      return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
    }
    function easeInOutExpo(x) {
      return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? Math.pow(2, 20 * x - 10) / 2 : (2 - Math.pow(2, -20 * x + 10)) / 2;
    }
    function easeInCirc(x) {
      return 1 - Math.sqrt(1 - Math.pow(x, 2));
    }
    function easeOutCirc(x) {
      return Math.sqrt(1 - Math.pow(x - 1, 2));
    }
    function easeInOutCirc(x) {
      return x < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * x, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * x + 2, 2)) + 1) / 2;
    }
    function easeInBack(x) {
      const c1 = 1.70158;
      const c3 = c1 + 1;
      return c3 * x * x * x - c1 * x * x;
    }
    function easeOutBack(x) {
      const c1 = 1.70158;
      const c3 = c1 + 1;
      return 1 + c3 * Math.pow(x - 1, 3) + c1 * Math.pow(x - 1, 2);
    }
    function easeInOutBack(x) {
      const c1 = 1.70158;
      const c2 = c1 * 1.525;
      return x < 0.5 ? Math.pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2) / 2 : (Math.pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2;
    }
    function easeInElastic(x) {
      const c4 = 2 * Math.PI / 3;
      return x === 0 ? 0 : x === 1 ? 1 : -Math.pow(2, 10 * x - 10) * Math.sin((x * 10 - 10.75) * c4);
    }
    function easeOutElastic(x) {
      const c4 = 2 * Math.PI / 3;
      return x === 0 ? 0 : x === 1 ? 1 : Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
    }
    function easeInOutElastic(x) {
      const c5 = 2 * Math.PI / 4.5;
      return x === 0 ? 0 : x === 1 ? 1 : x < 0.5 ? -(Math.pow(2, 20 * x - 10) * Math.sin((20 * x - 11.125) * c5)) / 2 : Math.pow(2, -20 * x + 10) * Math.sin((20 * x - 11.125) * c5) / 2 + 1;
    }
    function easeInBounce(x) {
      return 1 - easeOutBounce(1 - x);
    }
    function easeOutBounce(x) {
      const n1 = 7.5625;
      const d1 = 2.75;
      if (x < 1 / d1) {
        return n1 * x * x;
      } else if (x < 2 / d1) {
        return n1 * (x -= 1.5 / d1) * x + 0.75;
      } else if (x < 2.5 / d1) {
        return n1 * (x -= 2.25 / d1) * x + 0.9375;
      } else {
        return n1 * (x -= 2.625 / d1) * x + 0.984375;
      }
    }
    function easeInOutBounce(x) {
      return x < 0.5 ? (1 - easeOutBounce(1 - 2 * x)) / 2 : (1 + easeOutBounce(2 * x - 1)) / 2;
    }
    async function getFiles(inFile, { applyWildCard = false, softFail = false } = {}) {
      let source = "data";
      const browseOptions = { wildcard: applyWildCard };
      if (/\.s3\./.test(inFile)) {
        source = "s3";
        const { bucket, keyPrefix } = foundry.utils.parseS3URL(inFile);
        if (bucket) {
          browseOptions.bucket = bucket;
          inFile = keyPrefix;
        }
      }
      try {
        return (await FilePicker.browse(source, inFile, browseOptions)).files;
      } catch (err) {
        if (softFail) return false;
        throw custom_error("Sequencer", `getFiles | ${err}`);
      }
    }
    function interpolate(p1, p2, t, ease = "linear") {
      const easeFunction = is_function$1(ease) ? ease : easeFunctions[ease];
      return p1 + (p2 - p1) * easeFunction(t);
    }
    function random_float_between(min, max, twister = false) {
      const random = twister ? twister.random() : Math.random();
      const _max = Math.max(max, min);
      const _min = Math.min(max, min);
      return random * (_max - _min) + _min;
    }
    function random_int_between(min, max, twister = false) {
      return Math.floor(random_float_between(min, max, twister));
    }
    function flip_negate(num_1, num_2) {
      if (num_1 > 0) {
        num_1 -= num_2;
      } else {
        num_1 += num_2;
      }
      return num_1;
    }
    function shuffle_array(inArray, twister = false) {
      let shuffled = [...inArray];
      const randomMethod = twister?.random ?? Math.random;
      for (let i = shuffled.length - 1; i > 0; i--) {
        let j = Math.floor(randomMethod() * (i + 1));
        let temp = shuffled[i];
        shuffled[i] = shuffled[j];
        shuffled[j] = temp;
      }
      return shuffled;
    }
    function is_function$1(inFunc) {
      return inFunc && ({}.toString.call(inFunc) === "[object Function]" || {}.toString.call(inFunc) === "[object AsyncFunction]");
    }
    function random_array_element(inArray, { recurse = false, twister = false, index = false } = {}) {
      const chosenIndex = random_int_between(0, inArray.length, twister);
      let choice = inArray[chosenIndex];
      if (recurse && Array.isArray(choice)) {
        return random_array_element(choice, { recurse, twister, index });
      }
      if (index) {
        return chosenIndex;
      }
      return choice;
    }
    function random_object_element(inObject, { recurse = false, twister = false } = {}) {
      let keys = Object.keys(inObject).filter((k) => !k.startsWith("_"));
      let choice = inObject[random_array_element(keys, { twister })];
      if (typeof choice === "object" && recurse) {
        return random_object_element(choice, { recurse: true });
      }
      return choice;
    }
    function is_real_number(inNumber) {
      return !isNaN(inNumber) && typeof inNumber === "number" && isFinite(inNumber);
    }
    function normalize_alpha_number(inNumber) {
      if (!is_real_number(inNumber)) return void 0;
      inNumber = Math.abs(inNumber);
      while (inNumber > 1) inNumber /= 10;
      return inNumber;
    }
    function deep_get(obj, path) {
      if (!Array.isArray(path)) path = path.split(".");
      try {
        let i;
        for (i = 0; i < path.length - 1; i++) {
          obj = obj[path[i]];
        }
        return obj[path[i]];
      } catch (err) {
      }
    }
    function deep_set(obj, path, value) {
      if (!Array.isArray(path)) path = path.split(".");
      try {
        let i;
        for (i = 0; i < path.length - 1; i++) {
          obj = obj[path[i]];
        }
        if (is_function$1(obj[path[i]])) {
          obj[path[i]](value);
        } else {
          obj[path[i]] = value;
        }
      } catch (err) {
      }
    }
    function flatten_object(obj) {
      let toReturn = [];
      for (let i in obj) {
        if (i.startsWith("_")) continue;
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == "object") {
          let flatObject = flatten_object(obj[i]);
          for (let x in flatObject) {
            if (!flatObject.hasOwnProperty(x)) continue;
            toReturn[i + "." + x] = flatObject[x];
          }
        } else {
          toReturn[i] = obj[i];
        }
      }
      return toReturn;
    }
    function wait$1(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    function clamp$1(num, min, max) {
      const _max = Math.max(min, max);
      const _min = Math.min(min, max);
      return Math.max(_min, Math.min(_max, num));
    }
    function is_UUID(inId) {
      return typeof inId === "string" && (inId.startsWith("Scene") || inId.startsWith("Actor") || inId.startsWith("Item")) && (inId.match(/\./g) || []).length && !inId.endsWith(".");
    }
    function get_object_from_scene(inObjectId, inSceneId = game.user.viewedScene) {
      let tryUUID = is_UUID(inObjectId);
      if (tryUUID) {
        const obj = fromUuidSync(inObjectId);
        if (obj) return obj;
        tryUUID = false;
      }
      const allDocs = get_all_documents_from_scene(inSceneId);
      return allDocs.find((obj) => {
        return get_object_identifier(obj, tryUUID) === inObjectId;
      });
    }
    function get_all_documents_from_scene(inSceneId = false) {
      const scene = inSceneId ? game.scenes.get(inSceneId) : game.scenes.get(game.user?.viewedScene);
      if (!scene) return [];
      return [
        ...canvas.layers.map((layer2) => layer2?.children ?? [].concat(layer2?.preview?.children ?? [])),
        ...Array.from(scene?.tokens ?? []),
        ...Array.from(scene?.lights ?? []),
        ...Array.from(scene?.sounds ?? []),
        ...Array.from(scene?.templates ?? []),
        ...Array.from(scene?.tiles ?? []),
        ...Array.from(scene?.walls ?? []),
        ...Array.from(scene?.drawings ?? [])
      ].deepFlatten().filter(Boolean);
    }
    function validate_document(inObject) {
      const document2 = inObject?.document ?? inObject;
      return is_UUID(document2?.uuid) ? document2 : inObject;
    }
    function get_object_identifier(inObject, tryUUID = true) {
      const uuid = tryUUID && is_UUID(inObject?.uuid) ? inObject?.uuid : void 0;
      return uuid ?? inObject?.id ?? inObject?.document?.name ?? inObject?.name ?? (inObject?.tag !== "" ? inObject?.tag : void 0) ?? (inObject?.label !== "" ? inObject?.label : void 0) ?? inObject?.sound_id;
    }
    function make_array_unique(inArray) {
      return Array.from(new Set(inArray));
    }
    function debug(msg, args = "") {
      if (game.settings.get(CONSTANTS.MODULE_NAME, "debug"))
        console.log(`DEBUG | Sequencer | ${msg}`, args);
    }
    function debug_error(msg, args) {
      if (game.settings.get(CONSTANTS.MODULE_NAME, "debug"))
        console.error(`DEBUG | Sequencer | ${msg}`, args);
    }
    function custom_warning(inClassName, warning, notify = false) {
      inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
      warning = `${inClassName} | ${warning}`;
      if (notify) ui.notifications.warn(warning, { console: false });
      console.warn(warning.replace("<br>", "\n"));
    }
    const throttledWarnings = {};
    function throttled_custom_warning(inClassName, warning, delay = 1e4, notify = false) {
      inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
      warning = `${inClassName} | ${warning}`;
      if (throttledWarnings[warning]) return;
      throttledWarnings[warning] = true;
      if (notify) ui.notifications.warn(warning, { console: false });
      console.warn(warning.replace("<br>", "\n"));
      setTimeout(() => {
        delete throttledWarnings[warning];
      }, delay);
    }
    function custom_error(inClassName, error, notify = true) {
      inClassName = inClassName !== "Sequencer" ? "Sequencer | Module: " + inClassName : inClassName;
      error = `${inClassName} | ${error}`;
      if (notify) ui.notifications.error(error, { console: false });
      return new Error(error.replace("<br>", "\n"));
    }
    function user_can_do(inSetting) {
      return game.user.role > game.settings.get(CONSTANTS.MODULE_NAME, inSetting);
    }
    function group_by(xs, key) {
      return xs.reduce(function(acc, obj) {
        let property = foundry.utils.getProperty(obj, key);
        acc[property] = acc[property] || [];
        acc[property].push(obj);
        return acc;
      }, {});
    }
    function objHasProperty(obj, prop) {
      return obj.constructor.prototype.hasOwnProperty(prop);
    }
    function sequence_proxy_wrap(inSequence) {
      return new Proxy(inSequence, {
        get: function(target, prop) {
          if (!objHasProperty(target, prop)) {
            if (Sequencer.SectionManager.externalSections[prop] === void 0) {
              const section = target.sections[target.sections.length - 1];
              if (section && objHasProperty(section, prop)) {
                const targetProperty = Reflect.get(section, prop);
                return is_function$1(targetProperty) ? targetProperty.bind(section) : targetProperty;
              }
              return Reflect.get(target, prop);
            }
            target.sectionToCreate = Sequencer.SectionManager.externalSections[prop];
            return Reflect.get(target, "_createCustomSection");
          }
          return Reflect.get(target, prop);
        }
      });
    }
    function section_proxy_wrap(inClass) {
      return new Proxy(inClass, {
        get: function(target, prop) {
          if (!objHasProperty(target, prop) && objHasProperty(target.sequence, prop)) {
            const targetProperty = Reflect.get(target.sequence, prop);
            return is_function$1(targetProperty) ? targetProperty.bind(target.sequence) : targetProperty;
          }
          return Reflect.get(target, prop);
        }
      });
    }
    function str_to_search_regex_str(str) {
      return str.trim().replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*+/g, ".*?");
    }
    function safe_str(str) {
      return str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
    }
    function get_hash(input) {
      let hash2 = 0;
      const len = input.length;
      for (let i = 0; i < len; i++) {
        hash2 = (hash2 << 5) - hash2 + input.charCodeAt(i);
        hash2 |= 0;
      }
      return hash2;
    }
    function parseColor(inColor) {
      return {
        hexadecimal: is_real_number(inColor) ? inColor.toString(16) : inColor,
        decimal: typeof inColor === "string" && inColor.startsWith("#") ? parseInt(inColor.slice(1), 16) : inColor
      };
    }
    function getCanvasMouse() {
      return canvas?.app?.renderer?.events?.pointer ?? canvas?.app?.renderer?.plugins?.interaction?.pointer;
    }
    function createMersenneTwister(seed) {
      const twister = foundry?.dice?.MersenneTwister ?? MersenneTwister;
      return new twister(seed);
    }
    function set(obj, key, val) {
      if (typeof val.value === "object") val.value = klona(val.value);
      if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === "__proto__") {
        Object.defineProperty(obj, key, val);
      } else obj[key] = val.value;
    }
    function klona(x) {
      if (typeof x !== "object") return x;
      var i = 0, k, list, tmp, str = Object.prototype.toString.call(x);
      if (str === "[object Object]") {
        tmp = Object.create(x.__proto__ || null);
      } else if (str === "[object Array]") {
        tmp = Array(x.length);
      } else if (str === "[object Set]") {
        tmp = /* @__PURE__ */ new Set();
        x.forEach(function(val) {
          tmp.add(klona(val));
        });
      } else if (str === "[object Map]") {
        tmp = /* @__PURE__ */ new Map();
        x.forEach(function(val, key) {
          tmp.set(klona(key), klona(val));
        });
      } else if (str === "[object Date]") {
        tmp = /* @__PURE__ */ new Date(+x);
      } else if (str === "[object RegExp]") {
        tmp = new RegExp(x.source, x.flags);
      } else if (str === "[object DataView]") {
        tmp = new x.constructor(klona(x.buffer));
      } else if (str === "[object ArrayBuffer]") {
        tmp = x.slice(0);
      } else if (str.slice(-6) === "Array]") {
        tmp = new x.constructor(x);
      }
      if (tmp) {
        for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
          set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
        }
        for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
          if (Object.hasOwnProperty.call(tmp, k = list[i]) && tmp[k] === x[k]) continue;
          set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
        }
      }
      return tmp || x;
    }
    function deepMerge(target, ...sourceObj) {
      if (Object.prototype.toString.call(target) !== "[object Object]") {
        throw new TypeError(`deepMerge error: 'target' is not an object.`);
      }
      if (sourceObj.length === 0) {
        throw new TypeError(`deepMerge error: 'sourceObj' is not an object.`);
      }
      for (let cntr = 0; cntr < sourceObj.length; cntr++) {
        if (Object.prototype.toString.call(sourceObj[cntr]) !== "[object Object]") {
          throw new TypeError(`deepMerge error: 'sourceObj[${cntr}]' is not an object.`);
        }
      }
      if (sourceObj.length === 1) {
        const stack = [];
        for (const obj of sourceObj) {
          stack.push({ target, source: obj });
        }
        while (stack.length > 0) {
          const { target: target2, source } = stack.pop();
          for (const prop in source) {
            if (Object.hasOwn(source, prop)) {
              const sourceValue = source[prop];
              const targetValue = target2[prop];
              if (Object.hasOwn(target2, prop) && targetValue?.constructor === Object && sourceValue?.constructor === Object) {
                stack.push({ target: targetValue, source: sourceValue });
              } else {
                target2[prop] = sourceValue;
              }
            }
          }
        }
      } else {
        const stack = [{ target, sources: sourceObj }];
        while (stack.length > 0) {
          const { target: target2, sources } = stack.pop();
          for (const source of sources) {
            for (const prop in source) {
              if (Object.hasOwn(source, prop)) {
                const sourceValue = source[prop];
                const targetValue = target2[prop];
                if (Object.hasOwn(target2, prop) && targetValue?.constructor === Object && sourceValue?.constructor === Object) {
                  target2[prop] = Object.assign({}, targetValue);
                  stack.push({ target: target2[prop], sources: [sourceValue] });
                } else {
                  target2[prop] = sourceValue;
                }
              }
            }
          }
        }
      }
      return target;
    }
    function hasGetter(object, accessor) {
      if (typeof object !== "object" || object === null || object === void 0) {
        return false;
      }
      const iDescriptor = Object.getOwnPropertyDescriptor(object, accessor);
      if (iDescriptor !== void 0 && iDescriptor.get !== void 0) {
        return true;
      }
      for (let o = Object.getPrototypeOf(object); o; o = Object.getPrototypeOf(o)) {
        const descriptor = Object.getOwnPropertyDescriptor(o, accessor);
        if (descriptor !== void 0 && descriptor.get !== void 0) {
          return true;
        }
      }
      return false;
    }
    function isIterable(value) {
      if (value === null || value === void 0 || typeof value !== "object") {
        return false;
      }
      return Symbol.iterator in value;
    }
    function isObject(value) {
      return value !== null && typeof value === "object" && !Array.isArray(value);
    }
    function isPlainObject(value) {
      if (Object.prototype.toString.call(value) !== "[object Object]") {
        return false;
      }
      const prototype = Object.getPrototypeOf(value);
      return prototype === null || prototype === Object.prototype;
    }
    function safeAccess(data, accessor, defaultValue) {
      if (typeof data !== "object" || data === null) {
        return defaultValue;
      }
      if (typeof accessor !== "string") {
        return defaultValue;
      }
      const keys = accessor.split(".");
      let result = data;
      for (let cntr = 0; cntr < keys.length; cntr++) {
        if (result[keys[cntr]] === void 0 || result[keys[cntr]] === null) {
          return defaultValue;
        }
        result = result[keys[cntr]];
      }
      return result;
    }
    function safeSet(data, accessor, value, { operation = "set", createMissing = false } = {}) {
      if (typeof data !== "object" || data === null) {
        throw new TypeError(`safeSet error: 'data' is not an object.`);
      }
      if (typeof accessor !== "string") {
        throw new TypeError(`safeSet error: 'accessor' is not a string.`);
      }
      if (typeof operation !== "string") {
        throw new TypeError(`safeSet error: 'options.operation' is not a string.`);
      }
      if (operation !== "add" && operation !== "div" && operation !== "mult" && operation !== "set" && operation !== "set-undefined" && operation !== "sub") {
        throw new Error(`safeSet error: Unknown 'options.operation'.`);
      }
      if (typeof createMissing !== "boolean") {
        throw new TypeError(`safeSet error: 'options.createMissing' is not a boolean.`);
      }
      const access = accessor.split(".");
      let result = false;
      if (access.length === 1 && !createMissing && !(access[0] in data)) {
        return false;
      }
      for (let cntr = 0; cntr < access.length; cntr++) {
        if (Array.isArray(data)) {
          const number = +access[cntr];
          if (!Number.isInteger(number) || number < 0) {
            return false;
          }
        }
        if (cntr === access.length - 1) {
          switch (operation) {
            case "add":
              data[access[cntr]] += value;
              result = true;
              break;
            case "div":
              data[access[cntr]] /= value;
              result = true;
              break;
            case "mult":
              data[access[cntr]] *= value;
              result = true;
              break;
            case "set":
              data[access[cntr]] = value;
              result = true;
              break;
            case "set-undefined":
              if (data[access[cntr]] === void 0) {
                data[access[cntr]] = value;
              }
              result = true;
              break;
            case "sub":
              data[access[cntr]] -= value;
              result = true;
              break;
          }
        } else {
          if (createMissing && data[access[cntr]] === void 0) {
            data[access[cntr]] = {};
          }
          if (data[access[cntr]] === null || typeof data[access[cntr]] !== "object") {
            return false;
          }
          data = data[access[cntr]];
        }
      }
      return result;
    }
    function noop() {
    }
    const identity = (x) => x;
    function assign(tar, src) {
      for (const k in src) tar[k] = src[k];
      return (
        /** @type {T & S} */
        tar
      );
    }
    function run(fn) {
      return fn();
    }
    function blank_object() {
      return /* @__PURE__ */ Object.create(null);
    }
    function run_all(fns) {
      fns.forEach(run);
    }
    function is_function(thing) {
      return typeof thing === "function";
    }
    function safe_not_equal(a, b) {
      return a != a ? b == b : a !== b || a && typeof a === "object" || typeof a === "function";
    }
    let src_url_equal_anchor;
    function src_url_equal(element_src, url) {
      if (element_src === url) return true;
      if (!src_url_equal_anchor) {
        src_url_equal_anchor = document.createElement("a");
      }
      src_url_equal_anchor.href = url;
      return element_src === src_url_equal_anchor.href;
    }
    function is_empty(obj) {
      return Object.keys(obj).length === 0;
    }
    function subscribe(store, ...callbacks) {
      if (store == null) {
        for (const callback of callbacks) {
          callback(void 0);
        }
        return noop;
      }
      const unsub = store.subscribe(...callbacks);
      return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub;
    }
    function get_store_value(store) {
      let value;
      subscribe(store, (_) => value = _)();
      return value;
    }
    function component_subscribe(component, store, callback) {
      component.$$.on_destroy.push(subscribe(store, callback));
    }
    function create_slot(definition, ctx, $$scope, fn) {
      if (definition) {
        const slot_ctx = get_slot_context(definition, ctx, $$scope, fn);
        return definition[0](slot_ctx);
      }
    }
    function get_slot_context(definition, ctx, $$scope, fn) {
      return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx;
    }
    function get_slot_changes(definition, $$scope, dirty, fn) {
      if (definition[2] && fn) {
        const lets = definition[2](fn(dirty));
        if ($$scope.dirty === void 0) {
          return lets;
        }
        if (typeof lets === "object") {
          const merged = [];
          const len = Math.max($$scope.dirty.length, lets.length);
          for (let i = 0; i < len; i += 1) {
            merged[i] = $$scope.dirty[i] | lets[i];
          }
          return merged;
        }
        return $$scope.dirty | lets;
      }
      return $$scope.dirty;
    }
    function update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn) {
      if (slot_changes) {
        const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn);
        slot.p(slot_context, slot_changes);
      }
    }
    function get_all_dirty_from_scope($$scope) {
      if ($$scope.ctx.length > 32) {
        const dirty = [];
        const length = $$scope.ctx.length / 32;
        for (let i = 0; i < length; i++) {
          dirty[i] = -1;
        }
        return dirty;
      }
      return -1;
    }
    function exclude_internal_props(props) {
      const result = {};
      for (const k in props) if (k[0] !== "$") result[k] = props[k];
      return result;
    }
    function compute_slots(slots) {
      const result = {};
      for (const key in slots) {
        result[key] = true;
      }
      return result;
    }
    function set_store_value(store, ret, value) {
      store.set(value);
      return ret;
    }
    function action_destroyer(action_result) {
      return action_result && is_function(action_result.destroy) ? action_result.destroy : noop;
    }
    const is_client = typeof window !== "undefined";
    let now = is_client ? () => window.performance.now() : () => Date.now();
    let raf = is_client ? (cb) => requestAnimationFrame(cb) : noop;
    const tasks = /* @__PURE__ */ new Set();
    function run_tasks(now2) {
      tasks.forEach((task) => {
        if (!task.c(now2)) {
          tasks.delete(task);
          task.f();
        }
      });
      if (tasks.size !== 0) raf(run_tasks);
    }
    function loop(callback) {
      let task;
      if (tasks.size === 0) raf(run_tasks);
      return {
        promise: new Promise((fulfill) => {
          tasks.add(task = { c: callback, f: fulfill });
        }),
        abort() {
          tasks.delete(task);
        }
      };
    }
    function append(target, node) {
      target.appendChild(node);
    }
    function get_root_for_style(node) {
      if (!node) return document;
      const root = node.getRootNode ? node.getRootNode() : node.ownerDocument;
      if (root && /** @type {ShadowRoot} */
      root.host) {
        return (
          /** @type {ShadowRoot} */
          root
        );
      }
      return node.ownerDocument;
    }
    function append_empty_stylesheet(node) {
      const style_element = element("style");
      style_element.textContent = "/* empty */";
      append_stylesheet(get_root_for_style(node), style_element);
      return style_element.sheet;
    }
    function append_stylesheet(node, style) {
      append(
        /** @type {Document} */
        node.head || node,
        style
      );
      return style.sheet;
    }
    function insert(target, node, anchor) {
      target.insertBefore(node, anchor || null);
    }
    function detach(node) {
      if (node.parentNode) {
        node.parentNode.removeChild(node);
      }
    }
    function destroy_each(iterations, detaching) {
      for (let i = 0; i < iterations.length; i += 1) {
        if (iterations[i]) iterations[i].d(detaching);
      }
    }
    function element(name2) {
      return document.createElement(name2);
    }
    function svg_element(name2) {
      return document.createElementNS("http://www.w3.org/2000/svg", name2);
    }
    function text$1(data) {
      return document.createTextNode(data);
    }
    function space() {
      return text$1(" ");
    }
    function empty() {
      return text$1("");
    }
    function listen(node, event, handler, options) {
      node.addEventListener(event, handler, options);
      return () => node.removeEventListener(event, handler, options);
    }
    function prevent_default(fn) {
      return function(event) {
        event.preventDefault();
        return fn.call(this, event);
      };
    }
    function stop_propagation(fn) {
      return function(event) {
        event.stopPropagation();
        return fn.call(this, event);
      };
    }
    function attr(node, attribute, value) {
      if (value == null) node.removeAttribute(attribute);
      else if (node.getAttribute(attribute) !== value) node.setAttribute(attribute, value);
    }
    function to_number(value) {
      return value === "" ? null : +value;
    }
    function children(element2) {
      return Array.from(element2.childNodes);
    }
    function set_data(text2, data) {
      data = "" + data;
      if (text2.data === data) return;
      text2.data = /** @type {string} */
      data;
    }
    function set_input_value(input, value) {
      input.value = value == null ? "" : value;
    }
    function set_style(node, key, value, important) {
      if (value == null) {
        node.style.removeProperty(key);
      } else {
        node.style.setProperty(key, value, "");
      }
    }
    function select_option(select, value, mounting) {
      for (let i = 0; i < select.options.length; i += 1) {
        const option = select.options[i];
        if (option.__value === value) {
          option.selected = true;
          return;
        }
      }
      if (!mounting || value !== void 0) {
        select.selectedIndex = -1;
      }
    }
    function select_options(select, value) {
      for (let i = 0; i < select.options.length; i += 1) {
        const option = select.options[i];
        option.selected = ~value.indexOf(option.__value);
      }
    }
    function select_value(select) {
      const selected_option = select.querySelector(":checked");
      return selected_option && selected_option.__value;
    }
    function select_multiple_value(select) {
      return [].map.call(select.querySelectorAll(":checked"), (option) => option.__value);
    }
    function toggle_class(element2, name2, toggle) {
      element2.classList.toggle(name2, !!toggle);
    }
    function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
      return new CustomEvent(type, { detail, bubbles, cancelable });
    }
    class HtmlTag {
      /**
       * @private
       * @default false
       */
      is_svg = false;
      /** parent for creating node */
      e = void 0;
      /** html tag nodes */
      n = void 0;
      /** target */
      t = void 0;
      /** anchor */
      a = void 0;
      constructor(is_svg = false) {
        this.is_svg = is_svg;
        this.e = this.n = null;
      }
      /**
       * @param {string} html
       * @returns {void}
       */
      c(html) {
        this.h(html);
      }
      /**
       * @param {string} html
       * @param {HTMLElement | SVGElement} target
       * @param {HTMLElement | SVGElement} anchor
       * @returns {void}
       */
      m(html, target, anchor = null) {
        if (!this.e) {
          if (this.is_svg)
            this.e = svg_element(
              /** @type {keyof SVGElementTagNameMap} */
              target.nodeName
            );
          else
            this.e = element(
              /** @type {keyof HTMLElementTagNameMap} */
              target.nodeType === 11 ? "TEMPLATE" : target.nodeName
            );
          this.t = target.tagName !== "TEMPLATE" ? target : (
            /** @type {HTMLTemplateElement} */
            target.content
          );
          this.c(html);
        }
        this.i(anchor);
      }
      /**
       * @param {string} html
       * @returns {void}
       */
      h(html) {
        this.e.innerHTML = html;
        this.n = Array.from(
          this.e.nodeName === "TEMPLATE" ? this.e.content.childNodes : this.e.childNodes
        );
      }
      /**
       * @returns {void} */
      i(anchor) {
        for (let i = 0; i < this.n.length; i += 1) {
          insert(this.t, this.n[i], anchor);
        }
      }
      /**
       * @param {string} html
       * @returns {void}
       */
      p(html) {
        this.d();
        this.h(html);
        this.i(this.a);
      }
      /**
       * @returns {void} */
      d() {
        this.n.forEach(detach);
      }
    }
    function construct_svelte_component(component, props) {
      return new component(props);
    }
    const managed_styles = /* @__PURE__ */ new Map();
    let active = 0;
    function hash(str) {
      let hash2 = 5381;
      let i = str.length;
      while (i--) hash2 = (hash2 << 5) - hash2 ^ str.charCodeAt(i);
      return hash2 >>> 0;
    }
    function create_style_information(doc, node) {
      const info = { stylesheet: append_empty_stylesheet(node), rules: {} };
      managed_styles.set(doc, info);
      return info;
    }
    function create_rule(node, a, b, duration, delay, ease, fn, uid = 0) {
      const step = 16.666 / duration;
      let keyframes = "{\n";
      for (let p = 0; p <= 1; p += step) {
        const t = a + (b - a) * ease(p);
        keyframes += p * 100 + `%{${fn(t, 1 - t)}}
`;
      }
      const rule = keyframes + `100% {${fn(b, 1 - b)}}
}`;
      const name2 = `__svelte_${hash(rule)}_${uid}`;
      const doc = get_root_for_style(node);
      const { stylesheet, rules } = managed_styles.get(doc) || create_style_information(doc, node);
      if (!rules[name2]) {
        rules[name2] = true;
        stylesheet.insertRule(`@keyframes ${name2} ${rule}`, stylesheet.cssRules.length);
      }
      const animation2 = node.style.animation || "";
      node.style.animation = `${animation2 ? `${animation2}, ` : ""}${name2} ${duration}ms linear ${delay}ms 1 both`;
      active += 1;
      return name2;
    }
    function delete_rule(node, name2) {
      const previous = (node.style.animation || "").split(", ");
      const next = previous.filter(
        name2 ? (anim) => anim.indexOf(name2) < 0 : (anim) => anim.indexOf("__svelte") === -1
        // remove all Svelte animations
      );
      const deleted = previous.length - next.length;
      if (deleted) {
        node.style.animation = next.join(", ");
        active -= deleted;
        if (!active) clear_rules();
      }
    }
    function clear_rules() {
      raf(() => {
        if (active) return;
        managed_styles.forEach((info) => {
          const { ownerNode } = info.stylesheet;
          if (ownerNode) detach(ownerNode);
        });
        managed_styles.clear();
      });
    }
    let current_component;
    function set_current_component(component) {
      current_component = component;
    }
    function get_current_component() {
      if (!current_component) throw new Error("Function called outside component initialization");
      return current_component;
    }
    function onMount(fn) {
      get_current_component().$$.on_mount.push(fn);
    }
    function afterUpdate(fn) {
      get_current_component().$$.after_update.push(fn);
    }
    function onDestroy(fn) {
      get_current_component().$$.on_destroy.push(fn);
    }
    function createEventDispatcher() {
      const component = get_current_component();
      return (type, detail, { cancelable = false } = {}) => {
        const callbacks = component.$$.callbacks[type];
        if (callbacks) {
          const event = custom_event(
            /** @type {string} */
            type,
            detail,
            { cancelable }
          );
          callbacks.slice().forEach((fn) => {
            fn.call(component, event);
          });
          return !event.defaultPrevented;
        }
        return true;
      };
    }
    function setContext(key, context) {
      get_current_component().$$.context.set(key, context);
      return context;
    }
    function getContext(key) {
      return get_current_component().$$.context.get(key);
    }
    function bubble(component, event) {
      const callbacks = component.$$.callbacks[event.type];
      if (callbacks) {
        callbacks.slice().forEach((fn) => fn.call(this, event));
      }
    }
    const dirty_components = [];
    const binding_callbacks = [];
    let render_callbacks = [];
    const flush_callbacks = [];
    const resolved_promise = /* @__PURE__ */ Promise.resolve();
    let update_scheduled = false;
    function schedule_update() {
      if (!update_scheduled) {
        update_scheduled = true;
        resolved_promise.then(flush);
      }
    }
    function add_render_callback(fn) {
      render_callbacks.push(fn);
    }
    function add_flush_callback(fn) {
      flush_callbacks.push(fn);
    }
    const seen_callbacks = /* @__PURE__ */ new Set();
    let flushidx = 0;
    function flush() {
      if (flushidx !== 0) {
        return;
      }
      const saved_component = current_component;
      do {
        try {
          while (flushidx < dirty_components.length) {
            const component = dirty_components[flushidx];
            flushidx++;
            set_current_component(component);
            update(component.$$);
          }
        } catch (e) {
          dirty_components.length = 0;
          flushidx = 0;
          throw e;
        }
        set_current_component(null);
        dirty_components.length = 0;
        flushidx = 0;
        while (binding_callbacks.length) binding_callbacks.pop()();
        for (let i = 0; i < render_callbacks.length; i += 1) {
          const callback = render_callbacks[i];
          if (!seen_callbacks.has(callback)) {
            seen_callbacks.add(callback);
            callback();
          }
        }
        render_callbacks.length = 0;
      } while (dirty_components.length);
      while (flush_callbacks.length) {
        flush_callbacks.pop()();
      }
      update_scheduled = false;
      seen_callbacks.clear();
      set_current_component(saved_component);
    }
    function update($$) {
      if ($$.fragment !== null) {
        $$.update();
        run_all($$.before_update);
        const dirty = $$.dirty;
        $$.dirty = [-1];
        $$.fragment && $$.fragment.p($$.ctx, dirty);
        $$.after_update.forEach(add_render_callback);
      }
    }
    function flush_render_callbacks(fns) {
      const filtered = [];
      const targets = [];
      render_callbacks.forEach((c) => fns.indexOf(c) === -1 ? filtered.push(c) : targets.push(c));
      targets.forEach((c) => c());
      render_callbacks = filtered;
    }
    let promise;
    function wait() {
      if (!promise) {
        promise = Promise.resolve();
        promise.then(() => {
          promise = null;
        });
      }
      return promise;
    }
    function dispatch(node, direction, kind) {
      node.dispatchEvent(custom_event(`${direction ? "intro" : "outro"}${kind}`));
    }
    const outroing = /* @__PURE__ */ new Set();
    let outros;
    function group_outros() {
      outros = {
        r: 0,
        c: [],
        p: outros
        // parent group
      };
    }
    function check_outros() {
      if (!outros.r) {
        run_all(outros.c);
      }
      outros = outros.p;
    }
    function transition_in(block, local) {
      if (block && block.i) {
        outroing.delete(block);
        block.i(local);
      }
    }
    function transition_out(block, local, detach2, callback) {
      if (block && block.o) {
        if (outroing.has(block)) return;
        outroing.add(block);
        outros.c.push(() => {
          outroing.delete(block);
          if (callback) {
            if (detach2) block.d(1);
            callback();
          }
        });
        block.o(local);
      } else if (callback) {
        callback();
      }
    }
    const null_transition = { duration: 0 };
    function create_in_transition(node, fn, params) {
      const options = { direction: "in" };
      let config = fn(node, params, options);
      let running = false;
      let animation_name;
      let task;
      let uid = 0;
      function cleanup() {
        if (animation_name) delete_rule(node, animation_name);
      }
      function go() {
        const {
          delay = 0,
          duration = 300,
          easing = identity,
          tick = noop,
          css
        } = config || null_transition;
        if (css) animation_name = create_rule(node, 0, 1, duration, delay, easing, css, uid++);
        tick(0, 1);
        const start_time = now() + delay;
        const end_time = start_time + duration;
        if (task) task.abort();
        running = true;
        add_render_callback(() => dispatch(node, true, "start"));
        task = loop((now2) => {
          if (running) {
            if (now2 >= end_time) {
              tick(1, 0);
              dispatch(node, true, "end");
              cleanup();
              return running = false;
            }
            if (now2 >= start_time) {
              const t = easing((now2 - start_time) / duration);
              tick(t, 1 - t);
            }
          }
          return running;
        });
      }
      let started = false;
      return {
        start() {
          if (started) return;
          started = true;
          delete_rule(node);
          if (is_function(config)) {
            config = config(options);
            wait().then(go);
          } else {
            go();
          }
        },
        invalidate() {
          started = false;
        },
        end() {
          if (running) {
            cleanup();
            running = false;
          }
        }
      };
    }
    function create_out_transition(node, fn, params) {
      const options = { direction: "out" };
      let config = fn(node, params, options);
      let running = true;
      let animation_name;
      const group = outros;
      group.r += 1;
      let original_inert_value;
      function go() {
        const {
          delay = 0,
          duration = 300,
          easing = identity,
          tick = noop,
          css
        } = config || null_transition;
        if (css) animation_name = create_rule(node, 1, 0, duration, delay, easing, css);
        const start_time = now() + delay;
        const end_time = start_time + duration;
        add_render_callback(() => dispatch(node, false, "start"));
        if ("inert" in node) {
          original_inert_value = /** @type {HTMLElement} */
          node.inert;
          node.inert = true;
        }
        loop((now2) => {
          if (running) {
            if (now2 >= end_time) {
              tick(0, 1);
              dispatch(node, false, "end");
              if (!--group.r) {
                run_all(group.c);
              }
              return false;
            }
            if (now2 >= start_time) {
              const t = easing((now2 - start_time) / duration);
              tick(1 - t, t);
            }
          }
          return running;
        });
      }
      if (is_function(config)) {
        wait().then(() => {
          config = config(options);
          go();
        });
      } else {
        go();
      }
      return {
        end(reset) {
          if (reset && "inert" in node) {
            node.inert = original_inert_value;
          }
          if (reset && config.tick) {
            config.tick(1, 0);
          }
          if (running) {
            if (animation_name) delete_rule(node, animation_name);
            running = false;
          }
        }
      };
    }
    function ensure_array_like(array_like_or_iterator) {
      return array_like_or_iterator?.length !== void 0 ? array_like_or_iterator : Array.from(array_like_or_iterator);
    }
    function destroy_block(block, lookup) {
      block.d(1);
      lookup.delete(block.key);
    }
    function outro_and_destroy_block(block, lookup) {
      transition_out(block, 1, 1, () => {
        lookup.delete(block.key);
      });
    }
    function update_keyed_each(old_blocks, dirty, get_key, dynamic, ctx, list, lookup, node, destroy, create_each_block2, next, get_context) {
      let o = old_blocks.length;
      let n = list.length;
      let i = o;
      const old_indexes = {};
      while (i--) old_indexes[old_blocks[i].key] = i;
      const new_blocks = [];
      const new_lookup = /* @__PURE__ */ new Map();
      const deltas = /* @__PURE__ */ new Map();
      const updates = [];
      i = n;
      while (i--) {
        const child_ctx = get_context(ctx, list, i);
        const key = get_key(child_ctx);
        let block = lookup.get(key);
        if (!block) {
          block = create_each_block2(key, child_ctx);
          block.c();
        } else {
          updates.push(() => block.p(child_ctx, dirty));
        }
        new_lookup.set(key, new_blocks[i] = block);
        if (key in old_indexes) deltas.set(key, Math.abs(i - old_indexes[key]));
      }
      const will_move = /* @__PURE__ */ new Set();
      const did_move = /* @__PURE__ */ new Set();
      function insert2(block) {
        transition_in(block, 1);
        block.m(node, next);
        lookup.set(block.key, block);
        next = block.first;
        n--;
      }
      while (o && n) {
        const new_block = new_blocks[n - 1];
        const old_block = old_blocks[o - 1];
        const new_key = new_block.key;
        const old_key = old_block.key;
        if (new_block === old_block) {
          next = new_block.first;
          o--;
          n--;
        } else if (!new_lookup.has(old_key)) {
          destroy(old_block, lookup);
          o--;
        } else if (!lookup.has(new_key) || will_move.has(new_key)) {
          insert2(new_block);
        } else if (did_move.has(old_key)) {
          o--;
        } else if (deltas.get(new_key) > deltas.get(old_key)) {
          did_move.add(new_key);
          insert2(new_block);
        } else {
          will_move.add(old_key);
          o--;
        }
      }
      while (o--) {
        const old_block = old_blocks[o];
        if (!new_lookup.has(old_block.key)) destroy(old_block, lookup);
      }
      while (n) insert2(new_blocks[n - 1]);
      run_all(updates);
      return new_blocks;
    }
    function get_spread_update(levels, updates) {
      const update2 = {};
      const to_null_out = {};
      const accounted_for = { $$scope: 1 };
      let i = levels.length;
      while (i--) {
        const o = levels[i];
        const n = updates[i];
        if (n) {
          for (const key in o) {
            if (!(key in n)) to_null_out[key] = 1;
          }
          for (const key in n) {
            if (!accounted_for[key]) {
              update2[key] = n[key];
              accounted_for[key] = 1;
            }
          }
          levels[i] = n;
        } else {
          for (const key in o) {
            accounted_for[key] = 1;
          }
        }
      }
      for (const key in to_null_out) {
        if (!(key in update2)) update2[key] = void 0;
      }
      return update2;
    }
    function get_spread_object(spread_props) {
      return typeof spread_props === "object" && spread_props !== null ? spread_props : {};
    }
    function bind(component, name2, callback) {
      const index = component.$$.props[name2];
      if (index !== void 0) {
        component.$$.bound[index] = callback;
        callback(component.$$.ctx[index]);
      }
    }
    function create_component(block) {
      block && block.c();
    }
    function mount_component(component, target, anchor) {
      const { fragment, after_update } = component.$$;
      fragment && fragment.m(target, anchor);
      add_render_callback(() => {
        const new_on_destroy = component.$$.on_mount.map(run).filter(is_function);
        if (component.$$.on_destroy) {
          component.$$.on_destroy.push(...new_on_destroy);
        } else {
          run_all(new_on_destroy);
        }
        component.$$.on_mount = [];
      });
      after_update.forEach(add_render_callback);
    }
    function destroy_component(component, detaching) {
      const $$ = component.$$;
      if ($$.fragment !== null) {
        flush_render_callbacks($$.after_update);
        run_all($$.on_destroy);
        $$.fragment && $$.fragment.d(detaching);
        $$.on_destroy = $$.fragment = null;
        $$.ctx = [];
      }
    }
    function make_dirty(component, i) {
      if (component.$$.dirty[0] === -1) {
        dirty_components.push(component);
        schedule_update();
        component.$$.dirty.fill(0);
      }
      component.$$.dirty[i / 31 | 0] |= 1 << i % 31;
    }
    function init(component, options, instance2, create_fragment2, not_equal, props, append_styles = null, dirty = [-1]) {
      const parent_component = current_component;
      set_current_component(component);
      const $$ = component.$$ = {
        fragment: null,
        ctx: [],
        // state
        props,
        update: noop,
        not_equal,
        bound: blank_object(),
        // lifecycle
        on_mount: [],
        on_destroy: [],
        on_disconnect: [],
        before_update: [],
        after_update: [],
        context: new Map(options.context || (parent_component ? parent_component.$$.context : [])),
        // everything else
        callbacks: blank_object(),
        dirty,
        skip_bound: false,
        root: options.target || parent_component.$$.root
      };
      append_styles && append_styles($$.root);
      let ready = false;
      $$.ctx = instance2 ? instance2(component, options.props || {}, (i, ret, ...rest) => {
        const value = rest.length ? rest[0] : ret;
        if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
          if (!$$.skip_bound && $$.bound[i]) $$.bound[i](value);
          if (ready) make_dirty(component, i);
        }
        return ret;
      }) : [];
      $$.update();
      ready = true;
      run_all($$.before_update);
      $$.fragment = create_fragment2 ? create_fragment2($$.ctx) : false;
      if (options.target) {
        if (options.hydrate) {
          const nodes = children(options.target);
          $$.fragment && $$.fragment.l(nodes);
          nodes.forEach(detach);
        } else {
          $$.fragment && $$.fragment.c();
        }
        if (options.intro) transition_in(component.$$.fragment);
        mount_component(component, options.target, options.anchor);
        flush();
      }
      set_current_component(parent_component);
    }
    class SvelteComponent {
      /**
       * ### PRIVATE API
       *
       * Do not use, may change at any time
       *
       * @type {any}
       */
      $$ = void 0;
      /**
       * ### PRIVATE API
       *
       * Do not use, may change at any time
       *
       * @type {any}
       */
      $$set = void 0;
      /** @returns {void} */
      $destroy() {
        destroy_component(this, 1);
        this.$destroy = noop;
      }
      /**
       * @template {Extract<keyof Events, string>} K
       * @param {K} type
       * @param {((e: Events[K]) => void) | null | undefined} callback
       * @returns {() => void}
       */
      $on(type, callback) {
        if (!is_function(callback)) {
          return noop;
        }
        const callbacks = this.$$.callbacks[type] || (this.$$.callbacks[type] = []);
        callbacks.push(callback);
        return () => {
          const index = callbacks.indexOf(callback);
          if (index !== -1) callbacks.splice(index, 1);
        };
      }
      /**
       * @param {Partial<Props>} props
       * @returns {void}
       */
      $set(props) {
        if (this.$$set && !is_empty(props)) {
          this.$$.skip_bound = true;
          this.$$set(props);
          this.$$.skip_bound = false;
        }
      }
    }
    const PUBLIC_VERSION = "4";
    const subscriber_queue = [];
    function readable(value, start) {
      return {
        subscribe: writable(value, start).subscribe
      };
    }
    function writable(value, start = noop) {
      let stop;
      const subscribers = /* @__PURE__ */ new Set();
      function set2(new_value) {
        if (safe_not_equal(value, new_value)) {
          value = new_value;
          if (stop) {
            const run_queue = !subscriber_queue.length;
            for (const subscriber of subscribers) {
              subscriber[1]();
              subscriber_queue.push(subscriber, value);
            }
            if (run_queue) {
              for (let i = 0; i < subscriber_queue.length; i += 2) {
                subscriber_queue[i][0](subscriber_queue[i + 1]);
              }
              subscriber_queue.length = 0;
            }
          }
        }
      }
      function update2(fn) {
        set2(fn(value));
      }
      function subscribe2(run2, invalidate = noop) {
        const subscriber = [run2, invalidate];
        subscribers.add(subscriber);
        if (subscribers.size === 1) {
          stop = start(set2, update2) || noop;
        }
        run2(value);
        return () => {
          subscribers.delete(subscriber);
          if (subscribers.size === 0 && stop) {
            stop();
            stop = null;
          }
        };
      }
      return { set: set2, update: update2, subscribe: subscribe2 };
    }
    function derived(stores, fn, initial_value) {
      const single = !Array.isArray(stores);
      const stores_array = single ? [stores] : stores;
      if (!stores_array.every(Boolean)) {
        throw new Error("derived() expects stores as input, got a falsy value");
      }
      const auto = fn.length < 2;
      return readable(initial_value, (set2, update2) => {
        let started = false;
        const values = [];
        let pending = 0;
        let cleanup = noop;
        const sync = () => {
          if (pending) {
            return;
          }
          cleanup();
          const result = fn(single ? values[0] : values, set2, update2);
          if (auto) {
            set2(result);
          } else {
            cleanup = is_function(result) ? result : noop;
          }
        };
        const unsubscribers = stores_array.map(
          (store, i) => subscribe(
            store,
            (value) => {
              values[i] = value;
              pending &= ~(1 << i);
              if (started) {
                sync();
              }
            },
            () => {
              pending |= 1 << i;
            }
          )
        );
        started = true;
        sync();
        return function stop() {
          run_all(unsubscribers);
          cleanup();
          started = false;
        };
      });
    }
    function isWritableStore(store) {
      if (store === null || store === void 0) {
        return false;
      }
      switch (typeof store) {
        case "function":
        case "object":
          return typeof store.subscribe === "function" && typeof store.set === "function" && typeof store.update === "function";
      }
      return false;
    }
    function subscribeIgnoreFirst(store, update2) {
      let firedFirst = false;
      return store.subscribe((value) => {
        if (!firedFirst) {
          firedFirst = true;
        } else {
          update2(value);
        }
      });
    }
    class CrossWindow {
      /**
       * @private
       */
      constructor() {
      }
      // eslint-disable-line no-useless-constructor
      /**
       * Class names for all focusable element types.
       *
       * @type {string[]}
       */
      static #FocusableElementClassNames = [
        "HTMLAnchorElement",
        "HTMLButtonElement",
        "HTMLDetailsElement",
        "HTMLEmbedElement",
        "HTMLIFrameElement",
        "HTMLInputElement",
        "HTMLObjectElement",
        "HTMLSelectElement",
        "HTMLTextAreaElement"
      ];
      /**
       * DOM nodes with defined `ownerDocument` property.
       *
       * @type {Set<number>}
       */
      static #NodesWithOwnerDocument = /* @__PURE__ */ new Set([
        Node.ELEMENT_NODE,
        Node.TEXT_NODE,
        Node.COMMENT_NODE,
        Node.DOCUMENT_FRAGMENT_NODE
      ]);
      // Various UI Event sets for duck typing by constructor name.
      /**
       * Duck typing class names for pointer events.
       *
       * @type {Set<string>}
       */
      static #PointerEventSet = /* @__PURE__ */ new Set(["MouseEvent", "PointerEvent"]);
      /**
       * Duck typing class names for all UIEvents.
       *
       * @type {Set<string>}
       */
      static #UIEventSet = /* @__PURE__ */ new Set([
        "UIEvent",
        "FocusEvent",
        "MouseEvent",
        "WheelEvent",
        "KeyboardEvent",
        "PointerEvent",
        "TouchEvent",
        "InputEvent",
        "CompositionEvent",
        "DragEvent"
      ]);
      /**
       * Duck typing class names for events considered as user input.
       *
       * @type {Set<string>}
       */
      static #UserInputEventSet = /* @__PURE__ */ new Set(["KeyboardEvent", "MouseEvent", "PointerEvent"]);
      /**
       * Internal options used by `#checkDOMInstanceType` when retrieving the Window reference from a Node that doesn't
       * define `ownerDocument`.
       *
       * @type {{throws: boolean}}
       */
      static #optionsInternalCheckDOM = { throws: false };
      // DOM Querying ---------------------------------------------------------------------------------------------------
      /**
       * Convenience method to retrieve the `document.activeElement` value in the current Window context of a DOM Node /
       * Element, EventTarget, Document, or Window.
       *
       * @param {Document | EventTarget | Node | UIEvent | Window}  target - DOM Node / Element, EventTarget, Document,
       *        UIEvent or Window to query.
       *
       * @param {object} [options] - Options.
       *
       * @param {boolean} [options.throws=true] - When `true` and target is invalid throw an exception. If `false` and the
       *        target is invalid `undefined` is returned; default: `true`.
       *
       * @returns {Element | null} Active element or `undefined` when `throws` option is `false` and the target is invalid.
       *
       * @throws {@link TypeError} Target must be a DOM Node / Element, Document, UIEvent, or Window.
       */
      static getActiveElement(target, { throws = true } = {}) {
        if (this.#NodesWithOwnerDocument.has(target?.nodeType)) {
          return target?.ownerDocument?.activeElement ?? null;
        }
        if (this.isUIEvent(target) && isObject(target?.view)) {
          return target?.view?.document?.activeElement ?? null;
        }
        if (isObject(target?.defaultView)) {
          return target?.activeElement ?? null;
        }
        if (isObject(target?.document) && isObject(target?.location)) {
          return target?.document?.activeElement ?? null;
        }
        if (throws) {
          throw new TypeError(`'target' must be a DOM Node / Element, Document, UIEvent, or Window.`);
        }
        return void 0;
      }
      /**
       * Convenience method to retrieve the `Document` value in the current context of a DOM Node / Element, EventTarget,
       * Document, UIEvent, or Window.
       *
       * @param {Document | EventTarget | Node | UIEvent | Window}  target - DOM Node / Element, EventTarget, Document,
       *        UIEvent or Window to query.
       *
       * @param {object} [options] - Options.
       *
       * @param {boolean} [options.throws=true] - When `true` and target is invalid throw an exception. If `false` and the
       *        target is invalid `undefined` is returned; default: `true`.
       *
       * @returns {Document} Active document or `undefined` when `throws` option is `false` and the target is invalid.
       *
       * @throws {@link TypeError} Target must be a DOM Node / Element, Document, UIEvent, or Window.
       */
      static getDocument(target, { throws = true } = {}) {
        if (this.#NodesWithOwnerDocument.has(target?.nodeType)) {
          return target?.ownerDocument;
        }
        if (this.isUIEvent(target) && isObject(target?.view)) {
          return target?.view?.document;
        }
        if (isObject(target?.defaultView)) {
          return target;
        }
        if (isObject(target?.document) && isObject(target?.location)) {
          return target?.document;
        }
        if (throws) {
          throw new TypeError(`'target' must be a DOM Node / Element, Document, UIEvent, or Window.`);
        }
        return void 0;
      }
      /**
       * Convenience method to retrieve the `Window` value in the current context of a DOM Node / Element, EventTarget,
       * Document, or Window.
       *
       * @param {Document | EventTarget | Node | UIEvent | Window}  target - DOM Node / Element, EventTarget, Document,
       *        UIEvent or Window to query.
       *
       * @param {object} [options] - Options.
       *
       * @param {boolean} [options.throws=true] - When `true` and target is invalid throw an exception. If `false` and the
       *        target is invalid `undefined` is returned; default: `true`.
       *
       * @returns {Window} Active window or `undefined` when `throws` option is `false` and the target is invalid.
       *
       * @throws {@link TypeError} Target must be a DOM Node / Element, Document, UIEvent, or Window.
       */
      static getWindow(target, { throws = true } = {}) {
        if (this.#NodesWithOwnerDocument.has(target?.nodeType)) {
          return target.ownerDocument?.defaultView ?? globalThis;
        }
        if (this.isUIEvent(target) && isObject(target?.view)) {
          return target.view ?? globalThis;
        }
        if (isObject(target?.defaultView)) {
          return target.defaultView ?? globalThis;
        }
        if (isObject(target?.document) && isObject(target?.location)) {
          return target;
        }
        if (throws) {
          throw new TypeError(`'target' must be a DOM Node / Element, Document, UIEvent, or Window.`);
        }
        return void 0;
      }
      // ES / Browser API basic prototype tests -------------------------------------------------------------------------
      /**
       * Provides basic prototype string type checking if `target` is a Document.
       *
       * @param {unknown}  target - A potential Document to test.
       *
       * @returns {target is Document} Is `target` a Document.
       */
      static isDocument(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object Document]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a Map.
       *
       * @param {unknown}  target - A potential Map to test.
       *
       * @returns {target is Map} Is `target` a Map.
       */
      static isMap(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object Map]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a Promise.
       *
       * @param {unknown}  target - A potential Promise to test.
       *
       * @returns {target is Promise} Is `target` a Promise.
       */
      static isPromise(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object Promise]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a RegExp.
       *
       * @param {unknown}  target - A potential RegExp to test.
       *
       * @returns {target is RegExp} Is `target` a RegExp.
       */
      static isRegExp(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object RegExp]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a Set.
       *
       * @param {unknown}  target - A potential Set to test.
       *
       * @returns {target is Set} Is `target` a Set.
       */
      static isSet(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object Set]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a URL.
       *
       * @param {unknown}  target - A potential URL to test.
       *
       * @returns {target is URL} Is `target` a URL.
       */
      static isURL(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object URL]";
      }
      /**
       * Provides basic prototype string type checking if `target` is a Window.
       *
       * @param {unknown}  target - A potential Window to test.
       *
       * @returns {target is Window} Is `target` a Window.
       */
      static isWindow(target) {
        return isObject(target) && Object.prototype.toString.call(target) === "[object Window]";
      }
      // DOM Element typing ---------------------------------------------------------------------------------------------
      /**
       * Ensures that the given target is an `instanceof` all known DOM elements that are focusable. Please note that
       * additional checks are required regarding focusable state; use {@link A11yHelper.isFocusable} for a complete check.
       *
       * @param {unknown}  target - Target to test for `instanceof` focusable HTML element.
       *
       * @returns {boolean} Is target an `instanceof` a focusable DOM element.
       */
      static isFocusableHTMLElement(target) {
        for (let cntr = this.#FocusableElementClassNames.length; --cntr >= 0; ) {
          if (this.#checkDOMInstanceType(target, Node.ELEMENT_NODE, this.#FocusableElementClassNames[cntr])) {
            return true;
          }
        }
        return false;
      }
      /**
       * Provides precise type checking if `target` is a DocumentFragment.
       *
       * @param {unknown}  target - A potential DocumentFragment to test.
       *
       * @returns {target is DocumentFragment} Is `target` a DocumentFragment.
       */
      static isDocumentFragment(target) {
        return this.#checkDOMInstanceType(target, Node.DOCUMENT_FRAGMENT_NODE, "DocumentFragment");
      }
      /**
       * Provides precise type checking if `target` is an Element.
       *
       * @param {unknown}  target - A potential Element to test.
       *
       * @returns {target is Element} Is `target` an Element.
       */
      static isElement(target) {
        return this.#checkDOMInstanceType(target, Node.ELEMENT_NODE, "Element");
      }
      /**
       * Provides precise type checking if `target` is a HTMLAnchorElement.
       *
       * @param {unknown}  target - A potential HTMLAnchorElement to test.
       *
       * @returns {target is HTMLAnchorElement} Is `target` a HTMLAnchorElement.
       */
      static isHTMLAnchorElement(target) {
        return this.#checkDOMInstanceType(target, Node.ELEMENT_NODE, "HTMLAnchorElement");
      }
      /**
       * Provides precise type checking if `target` is a HTMLElement.
       *
       * @param {unknown}  target - A potential HTMLElement to test.
       *
       * @returns {target is HTMLElement} Is `target` a HTMLElement.
       */
      static isHTMLElement(target) {
        return this.#checkDOMInstanceType(target, Node.ELEMENT_NODE, "HTMLElement");
      }
      /**
       * Provides precise type checking if `target` is a Node.
       *
       * @param {unknown}  target - A potential Node to test.
       *
       * @returns {target is Node} Is `target` a DOM Node.
       */
      static isNode(target) {
        if (typeof target?.nodeType !== "number") {
          return false;
        }
        if (target instanceof globalThis.Node) {
          return true;
        }
        const activeWindow = this.getWindow(target, this.#optionsInternalCheckDOM);
        const TargetNode = activeWindow?.Node;
        return TargetNode && target instanceof TargetNode;
      }
      /**
       * Provides precise type checking if `target` is a ShadowRoot.
       *
       * @param {unknown}  target - A potential ShadowRoot to test.
       *
       * @returns {target is ShadowRoot} Is `target` a ShadowRoot.
       */
      static isShadowRoot(target) {
        return this.#checkDOMInstanceType(target, Node.DOCUMENT_FRAGMENT_NODE, "ShadowRoot");
      }
      /**
       * Provides precise type checking if `target` is a SVGElement.
       *
       * @param {unknown}  target - A potential SVGElement to test.
       *
       * @returns {target is SVGElement} Is `target` a SVGElement.
       */
      static isSVGElement(target) {
        return this.#checkDOMInstanceType(target, Node.ELEMENT_NODE, "SVGElement");
      }
      // Event typing ---------------------------------------------------------------------------------------------------
      /**
       * Provides basic duck type checking for `Event` signature and optional constructor name(s).
       *
       * @param {unknown}  target - A potential DOM event to test.
       *
       * @param {string | Set<string>} [types] Specific constructor name or Set of constructor names to match.
       *
       * @returns {target is Event} Is `target` an Event with optional constructor name check.
       */
      static isEvent(target, types) {
        if (typeof target?.type !== "string" || typeof target?.defaultPrevented !== "boolean" || typeof target?.stopPropagation !== "function") {
          return false;
        }
        return types !== void 0 ? this.isCtorName(target, types) : true;
      }
      /**
       * Provides basic duck type checking for `Event` signature for standard mouse / pointer events including
       * `MouseEvent` and `PointerEvent`.
       *
       * @param {unknown}  target - A potential DOM event to test.
       *
       * @returns {target is PointerEvent} Is `target` a MouseEvent or PointerEvent.
       */
      static isPointerEvent(target) {
        return this.isEvent(target, this.#PointerEventSet);
      }
      /**
       * Provides basic duck type checking for `Event` signature for all UI events.
       *
       * @param {unknown}  target - A potential DOM event to test.
       *
       * @returns {target is UIEvent} Is `target` a UIEvent.
       * @see https://developer.mozilla.org/en-US/docs/Web/API/UIEvent
       */
      static isUIEvent(target) {
        return this.isEvent(target, this.#UIEventSet);
      }
      /**
       * Provides basic duck type checking for `Event` signature for standard user input events including `KeyboardEvent`,
       * `MouseEvent`, and `PointerEvent`.
       *
       * @param {unknown}  target - A potential DOM event to test.
       *
       * @returns {target is KeyboardEvent | MouseEvent | PointerEvent} Is `target` a Keyboard, MouseEvent, or
       *          PointerEvent.
       */
      static isUserInputEvent(target) {
        return this.isEvent(target, this.#UserInputEventSet);
      }
      // Generic typing -------------------------------------------------------------------------------------------------
      /**
       * Provides basic type checking by constructor name(s) for objects. This can be useful when checking multiple
       * constructor names against a provided Set.
       *
       * @param {unknown}  target - Object to test for constructor name.
       *
       * @param {string | Set<string>} types Specific constructor name or Set of constructor names to match.
       *
       * @returns {boolean} Does the provided object constructor name match the types provided.
       */
      static isCtorName(target, types) {
        if (!isObject(target)) {
          return false;
        }
        if (typeof types === "string" && target?.constructor?.name === types) {
          return true;
        }
        return !!types?.has(target?.constructor?.name);
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Internal generic DOM `instanceof` check. First will attempt to find the class name by `globalThis` falling back
       * to the {@link Window} associated with the DOM node.
       *
       * @param {unknown}  target - Target to test.
       *
       * @param {number}   nodeType - Node type constant.
       *
       * @param {string}   className - DOM class name for instanceof check.
       *
       * @returns {boolean} Is the target the given nodeType and instance of class name.
       */
      static #checkDOMInstanceType(target, nodeType, className) {
        if (!isObject(target)) {
          return false;
        }
        if (target.nodeType !== nodeType) {
          return false;
        }
        const GlobalClass = globalThis[className];
        if (GlobalClass && target instanceof GlobalClass) {
          return true;
        }
        const activeWindow = this.#NodesWithOwnerDocument.has(target.nodeType) ? target?.ownerDocument?.defaultView : this.getWindow(target, this.#optionsInternalCheckDOM);
        const TargetClass = activeWindow?.[className];
        return TargetClass && target instanceof TargetClass;
      }
    }
    function storeGenerator({ storage, serialize = JSON.stringify, deserialize = JSON.parse }) {
      function isSimpleDeriver(deriver) {
        return deriver.length < 2;
      }
      function storageReadable(key, value, start) {
        return {
          subscribe: storageWritable(key, value, start).subscribe
        };
      }
      function storageWritable(key, value, start) {
        function wrap_start(ogSet) {
          return start(function wrap_set(new_value) {
            if (storage) {
              storage.setItem(key, serialize(new_value));
            }
            return ogSet(new_value);
          }, function wrap_update(fn) {
            set2(fn(get_store_value(ogStore)));
          });
        }
        if (storage) {
          const storageValue = storage.getItem(key);
          try {
            if (storageValue) {
              value = deserialize(storageValue);
            }
          } catch (err) {
          }
          storage.setItem(key, serialize(value));
        }
        const ogStore = writable(value, start ? wrap_start : void 0);
        function set2(new_value) {
          if (storage) {
            storage.setItem(key, serialize(new_value));
          }
          ogStore.set(new_value);
        }
        function update2(fn) {
          set2(fn(get_store_value(ogStore)));
        }
        function subscribe2(run2, invalidate) {
          return ogStore.subscribe(run2, invalidate);
        }
        return { set: set2, update: update2, subscribe: subscribe2 };
      }
      function storageDerived(key, stores, fn, initial_value) {
        const single = !Array.isArray(stores);
        const stores_array = single ? [stores] : stores;
        if (storage && storage.getItem(key)) {
          try {
            initial_value = deserialize(storage.getItem(key));
          } catch (err) {
          }
        }
        return storageReadable(key, initial_value, (set2, update2) => {
          let inited = false;
          const values = [];
          let pending = 0;
          let cleanup;
          const sync = () => {
            if (pending) {
              return;
            }
            cleanup?.();
            const input = single ? values[0] : values;
            if (isSimpleDeriver(fn)) {
              set2(fn(input));
            } else {
              const result = fn(input, set2, update2);
              if (typeof result === "function") {
                cleanup = result;
              }
            }
          };
          const unsubscribers = stores_array.map((store, i) => store.subscribe((value) => {
            values[i] = value;
            pending &= ~(1 << i);
            if (inited) {
              sync();
            }
          }, () => {
            pending |= 1 << i;
          }));
          inited = true;
          sync();
          return function stop() {
            unsubscribers.forEach((unsubscriber) => unsubscriber());
            cleanup?.();
          };
        });
      }
      return {
        readable: storageReadable,
        writable: storageWritable,
        derived: storageDerived,
        storage,
        serialize,
        deserialize
      };
    }
    const sessionStores = storeGenerator({ storage: globalThis?.sessionStorage });
    class TJSWebStorage {
      /** @type {import('./').StorageStores} */
      #storageStores;
      /**
       * @type {(Map<string, {
       *    store: import('svelte/store').Writable,
       *    deserialize?: (value: string, ...rest: any[]) => any,
       *    serialize?: (value: any, ...rest: any[]) => string
       * }>)}
       */
      #stores = /* @__PURE__ */ new Map();
      /**
       * @param {import('./').StorageStores} storageStores - Provides a complete set of
       *        storage API store helper functions and the associated storage API instance and serializations strategy.
       */
      constructor(storageStores) {
        this.#storageStores = storageStores;
      }
      /**
       * Creates a new store for the given key.
       *
       * @template T
       *
       * @param {string}   key - Key to lookup in stores map.
       *
       * @param {T}        [defaultValue] - A default value to set for the store.
       *
       * @param {import('./').StorageStores} [storageStores] - Additional store creation options.
       *
       * @returns {import('svelte/store').Writable<T>} The new store.
       */
      #createStore(key, defaultValue = void 0, storageStores) {
        try {
          const value = this.#storageStores.storage.getItem(key);
          if (value !== null) {
            const deserialize = storageStores?.deserialize ?? this.#storageStores.deserialize;
            defaultValue = deserialize(value);
          }
        } catch (err) {
        }
        const writable2 = storageStores?.writable ?? this.#storageStores.writable;
        return writable2(key, defaultValue);
      }
      /**
       * @param {string}   key - Storage key.
       *
       * @returns {(value: string, ...rest: any[]) => any} Deserialize function.
       */
      #getDeserialize(key) {
        return this.#stores.get(key)?.deserialize ?? this.#storageStores.deserialize;
      }
      /**
       * @param {string}   key - Storage key.
       *
       * @returns {(value: any, ...rest: any[]) => string} Serialize function.
       */
      #getSerialize(key) {
        return this.#stores.get(key)?.serialize ?? this.#storageStores.serialize;
      }
      /**
       * Gets a store from the `stores` Map or creates a new store for the key and a given default value.
       *
       * @template T
       *
       * @param {string}   key - Key to lookup in stores map.
       *
       * @param {T}        [defaultValue] - A default value to set for the store.
       *
       * @param {import('./').StorageStores} [storageStores] - Additional store creation options.
       *
       * @returns {import('svelte/store').Writable<T>} The store for the given key.
       */
      #getStore(key, defaultValue = void 0, storageStores) {
        const storeEntry = this.#stores.get(key);
        if (storeEntry) {
          return storeEntry.store;
        }
        const store = this.#createStore(key, defaultValue, storageStores);
        this.#stores.set(key, {
          store,
          deserialize: storageStores?.deserialize,
          serialize: storageStores?.serialize
        });
        return store;
      }
      /**
       * Get value from the storage API.
       *
       * @param {string}   key - Key to lookup in storage API.
       *
       * @param {*}        [defaultValue] - A default value to return if key not present in session storage.
       *
       * @returns {*} Value from session storage or if not defined any default value provided.
       */
      getItem(key, defaultValue) {
        let value = defaultValue;
        const storageValue = this.#storageStores.storage.getItem(key);
        if (storageValue !== null) {
          try {
            value = this.#getDeserialize(key)(storageValue);
          } catch (err) {
            value = defaultValue;
          }
        } else if (defaultValue !== void 0) {
          try {
            const newValue = this.#getSerialize(key)(defaultValue);
            this.#storageStores.storage.setItem(key, newValue);
          } catch (err) {
          }
        }
        return value;
      }
      /**
       * Returns the backing Svelte store for the given key; potentially sets a default value if the key
       * is not already set.
       *
       * @template T
       *
       * @param {string}   key - Key to lookup in storage API.
       *
       * @param {T}        [defaultValue] - A default value to return if key not present in session storage.
       *
       * @param {import('./').StorageStores} [storageStores] - Additional store creation options.
       *
       * @returns {import('svelte/store').Writable<T>} The Svelte store for this key.
       */
      getStore(key, defaultValue, storageStores) {
        return this.#getStore(key, defaultValue, storageStores);
      }
      /**
       * Returns whether a store has already been created for the given key.
       *
       * @param {string}   key - Key to lookup in storage API.
       */
      hasStore(key) {
        return this.#stores.has(key);
      }
      /**
       * Sets the value for the given key in storage API.
       *
       * @param {string}   key - Key to lookup in storage API.
       *
       * @param {*}        value - A value to set for this key.
       */
      setItem(key, value) {
        const store = this.#getStore(key);
        store.set(value);
      }
      /**
       * Convenience method to swap a boolean value stored in storage API updating the associated store value.
       *
       * @param {string}   key - Key to lookup in storage API.
       *
       * @param {boolean}  [defaultValue] - A default value to return if key not present in session storage.
       *
       * @returns {boolean} The boolean swap for the given key.
       */
      swapItemBoolean(key, defaultValue) {
        const store = this.#getStore(key, defaultValue);
        let currentValue = false;
        try {
          currentValue = !!this.#getDeserialize(key)(this.#storageStores.storage.getItem(key));
        } catch (err) {
        }
        const newValue = typeof currentValue === "boolean" ? !currentValue : false;
        store.set(newValue);
        return newValue;
      }
      // Iterators ------------------------------------------------------------------------------------------------------
      /**
       * @template T
       *
       * Returns an iterable for the session storage keys and stores.
       *
       * @param {RegExp} [regex] - Optional regular expression to filter by storage keys.
       *
       * @returns {IterableIterator<[string, import('svelte/store').Writable<T>]>} Iterable iterator of keys and stores.
       * @yields {import('svelte/store').Writable<[string, Writable<T>]>}
       */
      *entries(regex = void 0) {
        if (regex !== void 0 && !CrossWindow.isRegExp(regex)) {
          throw new TypeError(`'regex' is not a RegExp`);
        }
        if (!this.#stores.size) {
          return void 0;
        }
        if (regex) {
          for (const key of this.#stores.keys()) {
            if (regex.test(key)) {
              yield [key, this.getStore(key)];
            }
          }
        } else {
          for (const key of this.#stores.keys()) {
            yield [key, this.getStore(key)];
          }
        }
      }
      /**
       * Returns an iterable for the session storage keys from existing stores.
       *
       * @param {RegExp} [regex] - Optional regular expression to filter by storage keys.
       *
       * @returns {IterableIterator<string>} Iterable iterator of session storage keys.
       * @yields {string}
       */
      *keys(regex = void 0) {
        if (regex !== void 0 && !CrossWindow.isRegExp(regex)) {
          throw new TypeError(`'regex' is not a RegExp`);
        }
        if (!this.#stores.size) {
          return void 0;
        }
        if (regex) {
          for (const key of this.#stores.keys()) {
            if (regex.test(key)) {
              yield key;
            }
          }
        } else {
          for (const key of this.#stores.keys()) {
            yield key;
          }
        }
      }
      /**
       * @template T
       *
       * Returns an iterable for the session storage stores.
       *
       * @param {RegExp} [regex] - Optional regular expression to filter by storage keys.
       *
       * @returns {IterableIterator<import('svelte/store').Writable<T>>} Iterable iterator of stores.
       * @yields {import('svelte/store').Writable<T>}
       */
      *stores(regex = void 0) {
        if (regex !== void 0 && !CrossWindow.isRegExp(regex)) {
          throw new TypeError(`'regex' is not a RegExp`);
        }
        if (!this.#stores.size) {
          return void 0;
        }
        if (regex) {
          for (const key of this.#stores.keys()) {
            if (regex.test(key)) {
              yield this.getStore(key);
            }
          }
        } else {
          for (const key of this.#stores.keys()) {
            yield this.getStore(key);
          }
        }
      }
    }
    class TJSSessionStorage extends TJSWebStorage {
      constructor() {
        super(sessionStores);
      }
    }
    function writableDerived(origins, derive, reflect, initial) {
      var childDerivedSetter, originValues, blockNextDerive = false;
      var reflectOldValues = reflect.length >= 2;
      var wrappedDerive = (got, set2, update3) => {
        childDerivedSetter = set2;
        if (reflectOldValues) {
          originValues = got;
        }
        if (!blockNextDerive) {
          let returned = derive(got, set2, update3);
          if (derive.length < 2) {
            set2(returned);
          } else {
            return returned;
          }
        }
        blockNextDerive = false;
      };
      var childDerived = derived(origins, wrappedDerive, initial);
      var singleOrigin = !Array.isArray(origins);
      function doReflect(reflecting) {
        var setWith = reflect(reflecting, originValues);
        if (singleOrigin) {
          blockNextDerive = true;
          origins.set(setWith);
        } else {
          setWith.forEach((value, i) => {
            blockNextDerive = true;
            origins[i].set(value);
          });
        }
        blockNextDerive = false;
      }
      var tryingSet = false;
      function update2(fn) {
        var isUpdated, mutatedBySubscriptions, oldValue, newValue;
        if (tryingSet) {
          newValue = fn(get_store_value(childDerived));
          childDerivedSetter(newValue);
          return;
        }
        var unsubscribe = childDerived.subscribe((value) => {
          if (!tryingSet) {
            oldValue = value;
          } else if (!isUpdated) {
            isUpdated = true;
          } else {
            mutatedBySubscriptions = true;
          }
        });
        newValue = fn(oldValue);
        tryingSet = true;
        childDerivedSetter(newValue);
        unsubscribe();
        tryingSet = false;
        if (mutatedBySubscriptions) {
          newValue = get_store_value(childDerived);
        }
        if (isUpdated) {
          doReflect(newValue);
        }
      }
      return {
        subscribe: childDerived.subscribe,
        set(value) {
          update2(() => value);
        },
        update: update2
      };
    }
    function propertyStore(origin, propName) {
      if (!Array.isArray(propName)) {
        return writableDerived(
          origin,
          (object) => object[propName],
          (reflecting, object) => {
            object[propName] = reflecting;
            return object;
          }
        );
      } else {
        let props = propName.concat();
        return writableDerived(
          origin,
          (value) => {
            for (let i = 0; i < props.length; ++i) {
              value = value[props[i]];
            }
            return value;
          },
          (reflecting, object) => {
            let target = object;
            for (let i = 0; i < props.length - 1; ++i) {
              target = target[props[i]];
            }
            target[props[props.length - 1]] = reflecting;
            return object;
          }
        );
      }
    }
    class APIConfig {
      constructor() {
      }
      /**
       * Validates `config` argument whether it is a valid {@link TJSSvelte.Config.Dynamic} or
       * {@link TJSSvelte.Config.Standard} configuration object suitable for parsing by
       * {@link TJSSvelte.API.Config.parseConfig}.
       *
       * @param config - The potential config object to validate.
       *
       * @param [options] - Options.
       *
       * @param [options.raiseException=false] - If validation fails raise an exception.
       *
       * @returns Is the config a valid TJSSvelte.Config.Dynamic or TJSSvelte.Config.Standard configuration object.
       *
       * @throws {TypeError}  Any validation error when `raiseException` is enabled.
       */
      static isConfig(config, { raiseException = false } = {}) {
        if (!isObject(config)) {
          if (raiseException) {
            throw new TypeError(`TJSSvelte.config.isConfig error: 'config' is not an object.`);
          }
          return false;
        }
        if (!TJSSvelte.util.isComponent(config.class)) {
          if (raiseException) {
            throw new TypeError(`TJSSvelte.config.isConfig error: 'config.class' is not a Svelte component constructor.`);
          }
          return false;
        }
        return true;
      }
      /**
       * Validates `config` argument whether it is a valid {@link TJSSvelte.Config.Embed} configuration object
       * suitable for directly mounting via the `<svelte:component>` directive.
       *
       * @param config - The potential config object to validate.
       *
       * @param [options] - Options.
       *
       * @param [options.raiseException=false] - If validation fails raise an exception.
       *
       * @returns Is the config a valid TJSSvelte.Config.Embed configuration object.
       *
       * @throws {TypeError}  Any validation error when `raiseException` is enabled.
       */
      static isConfigEmbed(config, { raiseException = false } = {}) {
        if (!isObject(config)) {
          if (raiseException) {
            throw new TypeError(`TJSSvelte.config.isConfigEmbed error: 'config' is not an object.`);
          }
          return false;
        }
        if (!TJSSvelte.util.isComponent(config.class)) {
          if (raiseException) {
            throw new TypeError(`TJSSvelte.config.isConfigEmbed error: 'config.class' is not a Svelte component constructor.`);
          }
          return false;
        }
        if (config.props !== void 0 && !isObject(config.props)) {
          if (raiseException) {
            throw new TypeError(`TJSSvelte.config.isConfigEmbed error: 'config.props' is not an object.`);
          }
          return false;
        }
        return true;
      }
      /**
       * Parses a TyphonJS Svelte dynamic or standard config object ensuring that the class specified is a Svelte
       * component, loads any dynamic defined `context` or `props` preparing the config object for loading into the
       * Svelte component.
       *
       * @param config - Svelte config object.
       *
       * @param [options] - Options.
       *
       * @param [options.contextExternal] - When true any context data provided will be loaded into `#external`
       *        context separating it from any internal context created by the component.
       *
       * @param [options.thisArg] - `This` reference to set for invoking any `context` or `props` defined as
       *        functions for {@link Config.Dynamic} configuration objects.
       *
       * @returns The processed Svelte config object turned with parsed `props` & `context` converted into the format
       *          supported by Svelte.
       */
      static parseConfig(config, { contextExternal = false, thisArg = void 0 } = {}) {
        if (!isObject(config)) {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'config' is not an object:
${JSON.stringify(config)}.`);
        }
        if (!TJSSvelte.util.isComponent(config.class)) {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'class' is not a Svelte component constructor for config:
${JSON.stringify(config)}.`);
        }
        if (config.hydrate !== void 0 && typeof config.hydrate !== "boolean") {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'hydrate' is not a boolean for config:
${JSON.stringify(config)}.`);
        }
        if (config.intro !== void 0 && typeof config.intro !== "boolean") {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'intro' is not a boolean for config:
${JSON.stringify(config)}.`);
        }
        if (config.target !== void 0 && !CrossWindow.isElement(config.target) && !CrossWindow.isShadowRoot(config.target) && !CrossWindow.isDocumentFragment(config.target)) {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'target' is not a Element, ShadowRoot, or DocumentFragment for config:
${JSON.stringify(config)}.`);
        }
        if (config.anchor !== void 0 && !CrossWindow.isElement(config.anchor) && !CrossWindow.isShadowRoot(config.anchor) && !CrossWindow.isDocumentFragment(config.anchor)) {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'anchor' is not a string, Element for config:
${JSON.stringify(config)}.`);
        }
        if (config.context !== void 0 && typeof config.context !== "function" && !isObject(config.context)) {
          throw new TypeError(`TJSSvelte.config.parseConfig - 'context' is not a function or object for config:
${JSON.stringify(config)}.`);
        }
        const svelteConfig = { ...config };
        let context = {};
        if (typeof svelteConfig.context === "function") {
          const contextFunc = svelteConfig.context;
          delete svelteConfig.context;
          const result = contextFunc.call(thisArg);
          if (isObject(result)) {
            context = { ...result };
          } else {
            throw new Error(`TJSSvelte.config.parseConfig - 'context' is a function that did not return an object for config:
${JSON.stringify(config)}`);
          }
        } else if (isObject(svelteConfig.context)) {
          context = svelteConfig.context;
          delete svelteConfig.context;
        }
        svelteConfig.props = this.#processProps(svelteConfig.props, thisArg, config);
        if (contextExternal) {
          svelteConfig.context = /* @__PURE__ */ new Map();
          svelteConfig.context.set("#external", context);
        } else {
          svelteConfig.context = new Map(Object.entries(context));
        }
        return svelteConfig;
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Processes Svelte props. Potentially props can be a function to invoke with `thisArg`.
       *
       * @param props - Svelte props.
       *
       * @param thisArg - `This` reference to set for invoking any props function.
       *
       * @param config - Svelte config
       *
       * @returns Svelte props.
       */
      static #processProps(props, thisArg, config) {
        if (typeof props === "function") {
          const result = props.call(thisArg);
          if (isObject(result)) {
            return result;
          } else {
            throw new Error(`TJSSvelte.config.parseConfig - 'props' is a function that did not return an object for config:
${JSON.stringify(config)}`);
          }
        } else if (isObject(props)) {
          return props;
        } else if (props !== void 0) {
          throw new Error(`TJSSvelte.config.parseConfig - 'props' is not a function or an object for config:
${JSON.stringify(config)}`);
        }
        return {};
      }
    }
    Object.seal(APIConfig);
    class APIUtil {
      constructor() {
      }
      /**
       * Provides basic duck typing to determine if the provided function is a constructor function for a Svelte
       * component.
       *
       * @param comp - Data to check as a Svelte component.
       *
       * @returns Whether basic duck typing succeeds.
       */
      static isComponent(comp) {
        if (comp === null || comp === void 0 || typeof comp !== "function") {
          return false;
        }
        const prototypeName = comp?.prototype?.constructor?.name;
        if (typeof prototypeName === "string" && (prototypeName.startsWith("Proxy<") || prototypeName === "ProxyComponent")) {
          return true;
        }
        return typeof window !== "undefined" ? typeof comp?.prototype?.$destroy === "function" && typeof comp?.prototype?.$on === "function" : (
          // client-side
          typeof comp?.prototype?.render === "function"
        );
      }
      /**
       * Provides basic duck typing to determine if the provided object is a HMR ProxyComponent instance or class.
       *
       * @param {unknown}  comp - Data to check as a HMR proxy component.
       *
       * @returns {boolean} Whether basic duck typing succeeds.
       */
      static isHMRProxy(comp) {
        const instanceName = comp?.constructor?.name;
        if (typeof instanceName === "string" && (instanceName.startsWith("Proxy<") || instanceName === "ProxyComponent")) {
          return true;
        }
        const prototypeName = comp?.prototype?.constructor?.name;
        return typeof prototypeName === "string" && (prototypeName.startsWith("Proxy<") || prototypeName === "ProxyComponent");
      }
      /**
       * Runs outro transition then destroys Svelte component.
       *
       * Workaround for https://github.com/sveltejs/svelte/issues/4056
       *
       * @param instance - A Svelte component.
       *
       * @returns Promise returned after outro transition completed and component destroyed.
       */
      static async outroAndDestroy(instance2) {
        if (instance2 === void 0 || instance2 === null) {
          return Promise.resolve();
        }
        return new Promise((resolve) => {
          if (instance2?.$$?.fragment && instance2?.$$?.fragment?.o) {
            group_outros();
            transition_out(instance2.$$.fragment, 0, 0, () => {
              instance2?.$destroy?.();
              resolve();
            });
            check_outros();
          } else {
            instance2?.$destroy?.();
            resolve();
          }
        });
      }
    }
    Object.seal(APIUtil);
    class TJSSvelte {
      constructor() {
      }
      static get config() {
        return APIConfig;
      }
      /**
       * @returns The utility API.
       */
      static get util() {
        return APIUtil;
      }
    }
    Object.seal(TJSSvelte);
    function backInOut(t) {
      const s = 1.70158 * 1.525;
      if ((t *= 2) < 1) return 0.5 * (t * t * ((s + 1) * t - s));
      return 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2);
    }
    function backIn(t) {
      const s = 1.70158;
      return t * t * ((s + 1) * t - s);
    }
    function backOut(t) {
      const s = 1.70158;
      return --t * t * ((s + 1) * t + s) + 1;
    }
    function bounceOut(t) {
      const a = 4 / 11;
      const b = 8 / 11;
      const c = 9 / 10;
      const ca = 4356 / 361;
      const cb = 35442 / 1805;
      const cc = 16061 / 1805;
      const t2 = t * t;
      return t < a ? 7.5625 * t2 : t < b ? 9.075 * t2 - 9.9 * t + 3.4 : t < c ? ca * t2 - cb * t + cc : 10.8 * t * t - 20.52 * t + 10.72;
    }
    function bounceInOut(t) {
      return t < 0.5 ? 0.5 * (1 - bounceOut(1 - t * 2)) : 0.5 * bounceOut(t * 2 - 1) + 0.5;
    }
    function bounceIn(t) {
      return 1 - bounceOut(1 - t);
    }
    function circInOut(t) {
      if ((t *= 2) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);
      return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
    }
    function circIn(t) {
      return 1 - Math.sqrt(1 - t * t);
    }
    function circOut(t) {
      return Math.sqrt(1 - --t * t);
    }
    function cubicInOut(t) {
      return t < 0.5 ? 4 * t * t * t : 0.5 * Math.pow(2 * t - 2, 3) + 1;
    }
    function cubicIn(t) {
      return t * t * t;
    }
    function cubicOut(t) {
      const f = t - 1;
      return f * f * f + 1;
    }
    function elasticInOut(t) {
      return t < 0.5 ? 0.5 * Math.sin(13 * Math.PI / 2 * 2 * t) * Math.pow(2, 10 * (2 * t - 1)) : 0.5 * Math.sin(-13 * Math.PI / 2 * (2 * t - 1 + 1)) * Math.pow(2, -10 * (2 * t - 1)) + 1;
    }
    function elasticIn(t) {
      return Math.sin(13 * t * Math.PI / 2) * Math.pow(2, 10 * (t - 1));
    }
    function elasticOut(t) {
      return Math.sin(-13 * (t + 1) * Math.PI / 2) * Math.pow(2, -10 * t) + 1;
    }
    function expoInOut(t) {
      return t === 0 || t === 1 ? t : t < 0.5 ? 0.5 * Math.pow(2, 20 * t - 10) : -0.5 * Math.pow(2, 10 - t * 20) + 1;
    }
    function expoIn(t) {
      return t === 0 ? t : Math.pow(2, 10 * (t - 1));
    }
    function expoOut(t) {
      return t === 1 ? t : 1 - Math.pow(2, -10 * t);
    }
    function quadInOut(t) {
      t /= 0.5;
      if (t < 1) return 0.5 * t * t;
      t--;
      return -0.5 * (t * (t - 2) - 1);
    }
    function quadIn(t) {
      return t * t;
    }
    function quadOut(t) {
      return -t * (t - 2);
    }
    function quartInOut(t) {
      return t < 0.5 ? 8 * Math.pow(t, 4) : -8 * Math.pow(t - 1, 4) + 1;
    }
    function quartIn(t) {
      return Math.pow(t, 4);
    }
    function quartOut(t) {
      return Math.pow(t - 1, 3) * (1 - t) + 1;
    }
    function quintInOut(t) {
      if ((t *= 2) < 1) return 0.5 * t * t * t * t * t;
      return 0.5 * ((t -= 2) * t * t * t * t + 2);
    }
    function quintIn(t) {
      return t * t * t * t * t;
    }
    function quintOut(t) {
      return --t * t * t * t * t + 1;
    }
    function sineInOut(t) {
      return -0.5 * (Math.cos(Math.PI * t) - 1);
    }
    function sineIn(t) {
      const v = Math.cos(t * Math.PI * 0.5);
      if (Math.abs(v) < 1e-14) return 1;
      else return 1 - v;
    }
    function sineOut(t) {
      return Math.sin(t * Math.PI / 2);
    }
    const svelteEasingFunc = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
      __proto__: null,
      backIn,
      backInOut,
      backOut,
      bounceIn,
      bounceInOut,
      bounceOut,
      circIn,
      circInOut,
      circOut,
      cubicIn,
      cubicInOut,
      cubicOut,
      elasticIn,
      elasticInOut,
      elasticOut,
      expoIn,
      expoInOut,
      expoOut,
      linear: identity,
      quadIn,
      quadInOut,
      quadOut,
      quartIn,
      quartInOut,
      quartOut,
      quintIn,
      quintInOut,
      quintOut,
      sineIn,
      sineInOut,
      sineOut
    }, Symbol.toStringTag, { value: "Module" }));
    const easingFunc = svelteEasingFunc;
    function getEasingFunc(easingRef, options) {
      if (typeof easingRef === "function") {
        return easingRef;
      }
      const easingFn = easingFunc[easingRef];
      return easingFn ? easingFn : easingFunc[options?.default ?? "linear"];
    }
    class A11yHelper {
      /**
       * You can set global focus debugging enabled by setting `A11yHelper.debug = true`.
       *
       * @type {boolean}
       */
      static #globalDebug = false;
      /**
       * @returns {boolean} Global debugging enabled.
       */
      static get debug() {
        return this.#globalDebug;
      }
      /**
       * @param {boolean}  debug - Global debug enabled
       */
      static set debug(debug2) {
        if (typeof debug2 !== "boolean") {
          throw new TypeError(`'debug' is not a boolean.`);
        }
        this.#globalDebug = debug2;
      }
      /**
       * Runs a media query to determine if the user / OS configuration is set up for reduced motion / animation.
       *
       * @returns {boolean} User prefers reduced motion.
       */
      static get prefersReducedMotion() {
        return globalThis?.matchMedia("(prefers-reduced-motion: reduce)")?.matches ?? false;
      }
      /**
       * Apply focus to the HTMLElement / SVGElement targets in a given A11yFocusSource data object. An iterable list
       * `options.focusEl` can contain HTMLElement / SVGElements or selector strings. If multiple focus targets are
       * provided in a list then the first valid target found will be focused. If focus target is a string then a lookup
       * via `document.querySelector` is performed. In this case you should provide a unique selector for the desired
       * focus target.
       *
       * Note: The body of this method is postponed to the next clock tick to allow any changes in the DOM to occur that
       * might alter focus targets before applying.
       *
       * @param {A11yFocusSource | { focusSource: A11yFocusSource }}   options - The focus options instance to apply.
       */
      static applyFocusSource(options) {
        if (!isObject(options)) {
          return;
        }
        const focusOpts = isObject(options?.focusSource) ? options.focusSource : options;
        setTimeout(() => {
          const debug2 = typeof focusOpts.debug === "boolean" ? this.debug || focusOpts.debug : this.debug;
          if (isIterable(focusOpts.focusEl)) {
            if (debug2) {
              console.debug(
                `A11yHelper.applyFocusSource debug - Attempting to apply focus target: `,
                focusOpts.focusEl
              );
            }
            for (const target of focusOpts.focusEl) {
              if (target?.nodeType === Node.ELEMENT_NODE && target?.isConnected) {
                target?.focus();
                if (debug2) {
                  console.debug(`A11yHelper.applyFocusSource debug - Applied focus to target: `, target);
                }
                break;
              } else if (typeof target === "string") {
                const element2 = document.querySelector(target);
                if (element2?.nodeType === Node.ELEMENT_NODE && element2?.isConnected) {
                  element2?.focus();
                  if (debug2) {
                    console.debug(`A11yHelper.applyFocusSource debug - Applied focus to target: `, element2);
                  }
                  break;
                } else if (debug2) {
                  console.debug(`A11yHelper.applyFocusSource debug - Could not query selector: `, target);
                }
              }
            }
          } else if (debug2) {
            console.debug(`A11yHelper.applyFocusSource debug - No focus targets defined.`);
          }
        }, 0);
      }
      /**
       * Returns first focusable element within a specified element.
       *
       * @param {Element | Document} [element=document] - Optional element to start query.
       *
       * @param {FocusableElementOptions} [options] - Optional parameters.
       *
       * @returns {FocusableElement} First focusable child element.
       */
      static getFirstFocusableElement(element2 = document, options) {
        const focusableElements = this.getFocusableElements(element2, options);
        return focusableElements.length > 0 ? focusableElements[0] : void 0;
      }
      /**
       * Returns all focusable elements within a specified element.
       *
       * @param {Element | Document} [element=document] Optional element to start query.
       *
       * @param {FocusableElementOptions} [options] - Optional parameters.
       *
       * @returns {Array<FocusableElement>} Child keyboard focusable elements.
       */
      static getFocusableElements(element2 = document, {
        anchorHref = true,
        ignoreClasses,
        ignoreElements,
        parentHidden = false,
        selectors
      } = {}) {
        if (element2?.nodeType !== Node.ELEMENT_NODE && element2?.nodeType !== Node.DOCUMENT_NODE) {
          throw new TypeError(`'element' is not a HTMLElement, SVGElement, or Document instance.`);
        }
        if (typeof anchorHref !== "boolean") {
          throw new TypeError(`'anchorHref' is not a boolean.`);
        }
        if (ignoreClasses !== void 0 && !isIterable(ignoreClasses)) {
          throw new TypeError(`'ignoreClasses' is not an iterable list.`);
        }
        if (ignoreElements !== void 0 && !CrossWindow.isSet(ignoreElements)) {
          throw new TypeError(`'ignoreElements' is not a Set.`);
        }
        if (selectors !== void 0 && typeof selectors !== "string") {
          throw new TypeError(`'selectors' is not a string.`);
        }
        const selectorQuery = selectors ?? this.#getFocusableSelectors(anchorHref);
        let allElements = [...element2.querySelectorAll(selectorQuery)];
        if (ignoreElements && ignoreClasses) {
          allElements = allElements.filter((el) => {
            let hasIgnoreClass = false;
            for (const ignoreClass of ignoreClasses) {
              if (el.classList.contains(ignoreClass)) {
                hasIgnoreClass = true;
                break;
              }
            }
            return !hasIgnoreClass && !ignoreElements.has(el) && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
          });
        } else if (ignoreClasses) {
          allElements = allElements.filter((el) => {
            let hasIgnoreClass = false;
            for (const ignoreClass of ignoreClasses) {
              if (el.classList.contains(ignoreClass)) {
                hasIgnoreClass = true;
                break;
              }
            }
            return !hasIgnoreClass && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
          });
        } else if (ignoreElements) {
          allElements = allElements.filter((el) => {
            return !ignoreElements.has(el) && el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
          });
        } else {
          allElements = allElements.filter((el) => {
            return el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
          });
        }
        if (parentHidden) {
          allElements = allElements.filter((el) => {
            return !this.isParentHidden(el, element2);
          });
        }
        return allElements;
      }
      /**
       * Returns the default focusable selectors query.
       *
       * @param {boolean}  [anchorHref=true] - When true anchors must have an HREF.
       *
       * @returns {string} Focusable selectors for `querySelectorAll`.
       */
      static #getFocusableSelectors(anchorHref = true) {
        return `button, [contenteditable=""], [contenteditable="true"], details summary:not([tabindex="-1"]), embed, a${anchorHref ? "[href]" : ""}, iframe, object, input:not([type=hidden]), select, textarea, [tabindex]:not([tabindex="-1"])`;
      }
      /**
       * Gets a A11yFocusSource object from the given DOM event allowing for optional X / Y screen space overrides.
       * Browsers (Firefox / Chrome) forwards a mouse event for the context menu keyboard button. Provides detection of
       * when the context menu event is from the keyboard. Firefox as of (1/23) does not provide the correct screen space
       * coordinates, so for keyboard context menu presses coordinates are generated from the centroid point of the
       * element.
       *
       * A default fallback element or selector string may be provided to provide the focus target. If the event comes from
       * the keyboard however the source focused element is inserted as the target with the fallback value appended to the
       * list of focus targets. When A11yFocusSource is applied by {@link A11yHelper.applyFocusSource} the target focus
       * list is iterated through until a connected target is found and focus applied.
       *
       * @param {object} options - Options
       *
       * @param {KeyboardEvent | MouseEvent}   [options.event] - The source DOM event.
       *
       * @param {boolean} [options.debug] - When true {@link A11yHelper.applyFocusSource} logs focus target data.
       *
       * @param {FocusableElement | string} [options.focusEl] - A specific HTMLElement / SVGElement or selector
       *        string as the focus target.
       *
       * @param {number}   [options.x] - Used when an event isn't provided; integer of event source in screen space.
       *
       * @param {number}   [options.y] - Used when an event isn't provided; integer of event source in screen space.
       *
       * @returns {A11yFocusSource} A A11yFocusSource object.
       *
       * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1426671
       * @see https://bugzilla.mozilla.org/show_bug.cgi?id=314314
       *
       * @privateRemarks
       * TODO: Evaluate / test against touch input devices.
       */
      static getFocusSource({ event, x, y, focusEl, debug: debug2 = false }) {
        if (focusEl !== void 0 && !this.isFocusSource(focusEl)) {
          throw new TypeError(
            `A11yHelper.getFocusSource error: 'focusEl' is not a HTMLElement, SVGElement, or string.`
          );
        }
        if (debug2 !== void 0 && typeof debug2 !== "boolean") {
          throw new TypeError(`A11yHelper.getFocusSource error: 'debug' is not a boolean.`);
        }
        const debugEnabled = typeof debug2 === "boolean" ? this.debug || debug2 : this.debug;
        if (event === void 0) {
          if (typeof x !== "number") {
            throw new TypeError(`A11yHelper.getFocusSource error: 'event' not defined and 'x' is not a number.`);
          }
          if (typeof y !== "number") {
            throw new TypeError(`A11yHelper.getFocusSource error: 'event' not defined and 'y' is not a number.`);
          }
          const result2 = {
            debug: debug2,
            focusEl: focusEl !== void 0 ? [focusEl] : void 0,
            x,
            y
          };
          if (debugEnabled) {
            console.debug(`A11yHelper.getFocusSource debug: generated 'focusSource' without event: `, result2);
          }
          return result2;
        }
        if (event !== void 0 && !CrossWindow.isUserInputEvent(event)) {
          throw new TypeError(
            `A11yHelper.getFocusSource error: 'event' is not a KeyboardEvent, MouseEvent, or PointerEvent.`
          );
        }
        if (x !== void 0 && !Number.isInteger(x)) {
          throw new TypeError(`A11yHelper.getFocusSource error: 'x' is not a number.`);
        }
        if (y !== void 0 && !Number.isInteger(y)) {
          throw new TypeError(`A11yHelper.getFocusSource error: 'y' is not a number.`);
        }
        let targetEl;
        if (event) {
          if (A11yHelper.isFocusable(event.target)) {
            targetEl = event.target;
            if (debugEnabled) {
              console.debug(`A11yHelper.getFocusSource debug: 'targetEl' set to event.target: `, targetEl);
            }
          } else if (A11yHelper.isFocusable(event.currentTarget)) {
            targetEl = event.currentTarget;
            if (debugEnabled) {
              console.debug(`A11yHelper.getFocusSource debug: 'targetEl' set to event.currentTarget: `, targetEl);
            }
          } else {
            if (debugEnabled) {
              console.debug(
                `A11yHelper.getFocusSource debug: 'event.target' / 'event.currentTarget' are not focusable.`
              );
              console.debug(`A11yHelper.getFocusSource debug: 'event.target': `, event.target);
              console.debug(`A11yHelper.getFocusSource debug: 'event.currentTarget': `, event.currentTarget);
            }
          }
          if (targetEl) {
            if (targetEl?.nodeType !== Node.ELEMENT_NODE && typeof targetEl?.focus !== "function") {
              throw new TypeError(`A11yHelper.getFocusSource error: 'targetEl' is not an HTMLElement or SVGElement.`);
            }
          }
        }
        const result = { debug: debug2 };
        if (CrossWindow.isPointerEvent(event)) {
          if (event?.button !== 2 && event.type === "contextmenu") {
            const rectTarget = targetEl ?? event.target;
            const rect = rectTarget.getBoundingClientRect();
            result.source = "keyboard";
            result.x = x ?? rect.left + rect.width / 2;
            result.y = y ?? rect.top + rect.height / 2;
            result.focusEl = targetEl ? [targetEl] : [];
            if (focusEl) {
              result.focusEl.push(focusEl);
            }
          } else {
            result.source = "pointer";
            result.x = x ?? event.pageX;
            result.y = y ?? event.pageY;
            result.focusEl = targetEl ? [targetEl] : [];
            if (focusEl) {
              result.focusEl.push(focusEl);
            }
          }
        } else {
          const rectTarget = targetEl ?? event?.target;
          if (rectTarget) {
            const rect = rectTarget.getBoundingClientRect();
            result.source = "keyboard";
            result.x = x ?? rect.left + rect.width / 2;
            result.y = y ?? rect.top + rect.height / 2;
            result.focusEl = targetEl ? [targetEl] : [];
          }
          if (focusEl) {
            result.focusEl.push(focusEl);
          }
        }
        if (debugEnabled) {
          console.debug(`A11yHelper.getFocusSource debug: generated 'focusSource' with event: `, result);
        }
        return result;
      }
      /**
       * Returns first focusable element within a specified element.
       *
       * @param {Element | Document} [element=document] - Optional element to start query.
       *
       * @param {FocusableElementOptions} [options] - Optional parameters.
       *
       * @returns {FocusableElement} Last focusable child element.
       */
      static getLastFocusableElement(element2 = document, options) {
        const focusableElements = this.getFocusableElements(element2, options);
        return focusableElements.length > 0 ? focusableElements[focusableElements.length - 1] : void 0;
      }
      /**
       * Tests if the given element is focusable.
       *
       * @param {unknown} el - Element to test.
       *
       * @param {object} [options] - Optional parameters.
       *
       * @param {boolean} [options.anchorHref=true] - When true anchors must have an HREF.
       *
       * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
       *
       * @returns {boolean} Element is focusable.
       */
      static isFocusable(el, { anchorHref = true, ignoreClasses } = {}) {
        if (el === void 0 || el === null || el?.hidden || !el?.isConnected || el?.nodeType !== Node.ELEMENT_NODE || typeof el?.focus !== "function") {
          return false;
        }
        if (typeof anchorHref !== "boolean") {
          throw new TypeError(`'anchorHref' is not a boolean.`);
        }
        if (ignoreClasses !== void 0 && !isIterable(ignoreClasses)) {
          throw new TypeError(`'ignoreClasses' is not an iterable list.`);
        }
        const contenteditableAttr = el.getAttribute("contenteditable");
        const contenteditableFocusable = typeof contenteditableAttr === "string" && (contenteditableAttr === "" || contenteditableAttr === "true");
        const tabindexAttr = globalThis.parseInt(el.getAttribute("tabindex"));
        const tabindexFocusable = Number.isInteger(tabindexAttr) && tabindexAttr >= 0;
        if (contenteditableFocusable || tabindexFocusable || CrossWindow.isFocusableHTMLElement(el)) {
          if (anchorHref && !tabindexFocusable && CrossWindow.isHTMLAnchorElement(el) && typeof el.getAttribute("href") !== "string") {
            return false;
          }
          return el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
        }
        return false;
      }
      /**
       * Convenience method to check if the given data is a valid focus source.
       *
       * @param {Element | EventTarget | string}   data - Either an HTMLElement, SVGElement, or selector string.
       *
       * @returns {boolean} Is valid focus source.
       */
      static isFocusSource(data) {
        return typeof data === "string" || data?.nodeType === Node.ELEMENT_NODE && typeof data?.focus === "function";
      }
      /**
       * Tests if the given `element` is a Element node and has a `focus` method.
       *
       * @param {unknown}  element - Element to test for focus method.
       *
       * @returns {element is FocusableElement} Whether the element has a focus method.
       */
      static isFocusTarget(element2) {
        return element2 !== void 0 && element2 !== null && element2?.nodeType === Node.ELEMENT_NODE && typeof element2?.focus === "function";
      }
      /**
       * Perform a parent traversal from the current active element attempting to match the given element to test whether
       * current active element is within that element.
       *
       * @param {Element}  element - An element to match in parent traversal from the active element.
       *
       * @returns {boolean} Whether there is focus within the given element.
       */
      static isFocusWithin(element2) {
        if (!isObject(element2) || element2?.hidden || !element2?.isConnected) {
          return false;
        }
        let active2 = CrossWindow.getActiveElement(element2);
        if (!active2) {
          return false;
        }
        while (active2) {
          if (active2 === element2) {
            return true;
          }
          active2 = active2.parentElement;
        }
        return false;
      }
      /**
       * Traverses the given element's parent elements to check if any parent has `offsetWidth` and `offsetHeight` of 0,
       * indicating that a parent element is hidden. If a parent element is hidden, the given element is also considered
       * hidden. This is a reasonably efficient check and can be enabled as a filter step in conjunction with focusable
       * element detection methods like {@link A11yHelper.getFocusableElements}.
       *
       * @param {Element}  element - The starting element to check.
       *
       * @param {Element}  [stopElement] - The stopping parent element for traversal. If not defined, `document.body` is
       *        used as the stopping element.
       *
       * @returns {boolean} `true` if a parent element of the given element is hidden; otherwise, `false`.
       */
      static isParentHidden(element2, stopElement) {
        if (!CrossWindow.isElement(element2)) {
          throw new TypeError(`'element' is not an Element.`);
        }
        stopElement = stopElement ?? CrossWindow.getDocument(element2)?.body;
        if (!CrossWindow.isElement(stopElement)) {
          throw new TypeError(`'stopElement' must be an Element.`);
        }
        let current = element2.parentElement;
        while (current) {
          if (current === stopElement) {
            break;
          }
          if (current.offsetWidth === 0 && current.offsetHeight === 0) {
            return true;
          }
          current = current.parentElement;
        }
        return false;
      }
    }
    function clamp(value = 0, min = 0, max = 0) {
      return Math.min(Math.max(value, min), max);
    }
    function degToRad(deg) {
      return deg * (Math.PI / 180);
    }
    function radToDeg(rad) {
      return rad * (180 / Math.PI);
    }
    function lerp(start, end, amount) {
      return (1 - amount) * start + amount * end;
    }
    // @license MIT (https://github.com/toji/gl-matrix/blob/master/LICENSE.md)
    var GLM_EPSILON = 1e-6;
    var Mat4 = class _Mat4 extends Float32Array {
      static #IDENTITY_4X4 = new Float32Array([
        1,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        1,
        0,
        0,
        0,
        0,
        1
      ]);
      /**
       * Temporary variable to prevent repeated allocations in the algorithms within Mat4.
       * These are declared as TypedArrays to aid in tree-shaking.
       */
      static #TMP_VEC3 = new Float32Array(3);
      /**
       * Create a {@link Mat4}.
       *
       * @category Constructor
       */
      constructor(...values) {
        switch (values.length) {
          case 16:
            super(values);
            break;
          case 2:
            super(values[0], values[1], 16);
            break;
          case 1:
            const v = values[0];
            if (typeof v === "number") {
              super([
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v,
                v
              ]);
            } else {
              super(v, 0, 16);
            }
            break;
          default:
            super(_Mat4.#IDENTITY_4X4);
            break;
        }
      }
      // ============
      // Accessors
      // ============
      /**
       * A string representation of `this`
       * Equivalent to `Mat4.str(this);`
       *
       * @category Accessors
       */
      get str() {
        return _Mat4.str(this);
      }
      // ===================
      // Instance methods
      // ===================
      /**
       * Copy the values from another {@link Mat4} into `this`.
       * @category Methods
       *
       * @param a the source vector
       * @returns `this`
       */
      copy(a) {
        this.set(a);
        return this;
      }
      /**
       * Set `this` to the identity matrix
       * Equivalent to Mat4.identity(this)
       * @category Methods
       *
       * @returns `this`
       */
      identity() {
        this.set(_Mat4.#IDENTITY_4X4);
        return this;
      }
      /**
       * Multiplies this {@link Mat4} against another one
       * Equivalent to `Mat4.multiply(this, this, b);`
       * @category Methods
       *
       * @param b - The second operand
       * @returns `this`
       */
      multiply(b) {
        return _Mat4.multiply(this, this, b);
      }
      /**
       * Alias for {@link Mat4.multiply}
       * @category Methods
       */
      mul(b) {
        return this;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Transpose this {@link Mat4}
       * Equivalent to `Mat4.transpose(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      transpose() {
        return _Mat4.transpose(this, this);
      }
      /**
       * Inverts this {@link Mat4}
       * Equivalent to `Mat4.invert(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      invert() {
        return _Mat4.invert(this, this);
      }
      /**
       * Translate this {@link Mat4} by the given vector
       * Equivalent to `Mat4.translate(this, this, v);`
       * @category Methods
       *
       * @param v - The {@link Vec3} to translate by
       * @returns `this`
       */
      translate(v) {
        return _Mat4.translate(this, this, v);
      }
      /**
       * Rotates this {@link Mat4} by the given angle around the given axis
       * Equivalent to `Mat4.rotate(this, this, rad, axis);`
       * @category Methods
       *
       * @param rad - the angle to rotate the matrix by
       * @param axis - the axis to rotate around
       * @returns `this`
       */
      rotate(rad, axis) {
        return _Mat4.rotate(this, this, rad, axis);
      }
      /**
       * Scales this {@link Mat4} by the dimensions in the given vec3 not using vectorization
       * Equivalent to `Mat4.scale(this, this, v);`
       * @category Methods
       *
       * @param v - The {@link Vec3} to scale the matrix by
       * @returns `this`
       */
      scale(v) {
        return _Mat4.scale(this, this, v);
      }
      /**
       * Rotates this {@link Mat4} by the given angle around the X axis
       * Equivalent to `Mat4.rotateX(this, this, rad);`
       * @category Methods
       *
       * @param rad - the angle to rotate the matrix by
       * @returns `this`
       */
      rotateX(rad) {
        return _Mat4.rotateX(this, this, rad);
      }
      /**
       * Rotates this {@link Mat4} by the given angle around the Y axis
       * Equivalent to `Mat4.rotateY(this, this, rad);`
       * @category Methods
       *
       * @param rad - the angle to rotate the matrix by
       * @returns `this`
       */
      rotateY(rad) {
        return _Mat4.rotateY(this, this, rad);
      }
      /**
       * Rotates this {@link Mat4} by the given angle around the Z axis
       * Equivalent to `Mat4.rotateZ(this, this, rad);`
       * @category Methods
       *
       * @param rad - the angle to rotate the matrix by
       * @returns `this`
       */
      rotateZ(rad) {
        return _Mat4.rotateZ(this, this, rad);
      }
      /**
       * Generates a perspective projection matrix with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [-1, 1],
       * which matches WebGL/OpenGL's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * Equivalent to `Mat4.perspectiveNO(this, fovy, aspect, near, far);`
       * @category Methods
       *
       * @param fovy - Vertical field of view in radians
       * @param aspect - Aspect ratio. typically viewport width/height
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum, can be null or Infinity
       * @returns `this`
       */
      perspectiveNO(fovy, aspect, near, far) {
        return _Mat4.perspectiveNO(this, fovy, aspect, near, far);
      }
      /**
       * Generates a perspective projection matrix suitable for WebGPU with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [0, 1],
       * which matches WebGPU/Vulkan/DirectX/Metal's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * Equivalent to `Mat4.perspectiveZO(this, fovy, aspect, near, far);`
       * @category Methods
       *
       * @param fovy - Vertical field of view in radians
       * @param aspect - Aspect ratio. typically viewport width/height
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum, can be null or Infinity
       * @returns `this`
       */
      perspectiveZO(fovy, aspect, near, far) {
        return _Mat4.perspectiveZO(this, fovy, aspect, near, far);
      }
      /**
       * Generates a orthogonal projection matrix with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [-1, 1],
       * which matches WebGL/OpenGL's clip volume.
       * Equivalent to `Mat4.orthoNO(this, left, right, bottom, top, near, far);`
       * @category Methods
       *
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum
       * @returns `this`
       */
      orthoNO(left, right, bottom, top, near, far) {
        return _Mat4.orthoNO(this, left, right, bottom, top, near, far);
      }
      /**
       * Generates a orthogonal projection matrix with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [0, 1],
       * which matches WebGPU/Vulkan/DirectX/Metal's clip volume.
       * Equivalent to `Mat4.orthoZO(this, left, right, bottom, top, near, far);`
       * @category Methods
       *
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum
       * @returns `this`
       */
      orthoZO(left, right, bottom, top, near, far) {
        return _Mat4.orthoZO(this, left, right, bottom, top, near, far);
      }
      // ===================
      // Static accessors
      // ===================
      /**
       * @category Static
       *
       * @returns The number of bytes in a {@link Mat4}.
       */
      static get BYTE_LENGTH() {
        return 16 * Float32Array.BYTES_PER_ELEMENT;
      }
      // ===================
      // Static methods
      // ===================
      /**
       * Creates a new, identity {@link Mat4}
       * @category Static
       *
       * @returns A new {@link Mat4}
       */
      static create() {
        return new _Mat4();
      }
      /**
       * Creates a new {@link Mat4} initialized with values from an existing matrix
       * @category Static
       *
       * @param a - Matrix to clone
       * @returns A new {@link Mat4}
       */
      static clone(a) {
        return new _Mat4(a);
      }
      /**
       * Copy the values from one {@link Mat4} to another
       * @category Static
       *
       * @param out - The receiving Matrix
       * @param a - Matrix to copy
       * @returns `out`
       */
      static copy(out, a) {
        out[0] = a[0];
        out[1] = a[1];
        out[2] = a[2];
        out[3] = a[3];
        out[4] = a[4];
        out[5] = a[5];
        out[6] = a[6];
        out[7] = a[7];
        out[8] = a[8];
        out[9] = a[9];
        out[10] = a[10];
        out[11] = a[11];
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
        return out;
      }
      /**
       * Create a new mat4 with the given values
       * @category Static
       *
       * @param values - Matrix components
       * @returns A new {@link Mat4}
       */
      static fromValues(...values) {
        return new _Mat4(...values);
      }
      /**
       * Set the components of a mat4 to the given values
       * @category Static
       *
       * @param out - The receiving matrix
       * @param values - Matrix components
       * @returns `out`
       */
      static set(out, ...values) {
        out[0] = values[0];
        out[1] = values[1];
        out[2] = values[2];
        out[3] = values[3];
        out[4] = values[4];
        out[5] = values[5];
        out[6] = values[6];
        out[7] = values[7];
        out[8] = values[8];
        out[9] = values[9];
        out[10] = values[10];
        out[11] = values[11];
        out[12] = values[12];
        out[13] = values[13];
        out[14] = values[14];
        out[15] = values[15];
        return out;
      }
      /**
       * Set a {@link Mat4} to the identity matrix
       * @category Static
       *
       * @param out - The receiving Matrix
       * @returns `out`
       */
      static identity(out) {
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = 1;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 1;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Transpose the values of a {@link Mat4}
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the source matrix
       * @returns `out`
       */
      static transpose(out, a) {
        if (out === a) {
          const a01 = a[1], a02 = a[2], a03 = a[3];
          const a12 = a[6], a13 = a[7];
          const a23 = a[11];
          out[1] = a[4];
          out[2] = a[8];
          out[3] = a[12];
          out[4] = a01;
          out[6] = a[9];
          out[7] = a[13];
          out[8] = a02;
          out[9] = a12;
          out[11] = a[14];
          out[12] = a03;
          out[13] = a13;
          out[14] = a23;
        } else {
          out[0] = a[0];
          out[1] = a[4];
          out[2] = a[8];
          out[3] = a[12];
          out[4] = a[1];
          out[5] = a[5];
          out[6] = a[9];
          out[7] = a[13];
          out[8] = a[2];
          out[9] = a[6];
          out[10] = a[10];
          out[11] = a[14];
          out[12] = a[3];
          out[13] = a[7];
          out[14] = a[11];
          out[15] = a[15];
        }
        return out;
      }
      /**
       * Inverts a {@link Mat4}
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the source matrix
       * @returns `out` or `null` if the matrix is not invertible
       */
      static invert(out, a) {
        const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
        const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
        const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
        const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
        const b00 = a00 * a11 - a01 * a10;
        const b01 = a00 * a12 - a02 * a10;
        const b02 = a00 * a13 - a03 * a10;
        const b03 = a01 * a12 - a02 * a11;
        const b04 = a01 * a13 - a03 * a11;
        const b05 = a02 * a13 - a03 * a12;
        const b06 = a20 * a31 - a21 * a30;
        const b07 = a20 * a32 - a22 * a30;
        const b08 = a20 * a33 - a23 * a30;
        const b09 = a21 * a32 - a22 * a31;
        const b10 = a21 * a33 - a23 * a31;
        const b11 = a22 * a33 - a23 * a32;
        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
        if (!det) {
          return null;
        }
        det = 1 / det;
        out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
        out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
        out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
        out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
        out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
        out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
        out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
        out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
        out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
        out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
        out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
        out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
        out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
        out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
        out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
        out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
        return out;
      }
      /**
       * Calculates the adjugate of a {@link Mat4}
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the source matrix
       * @returns `out`
       */
      static adjoint(out, a) {
        const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
        const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
        const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
        const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
        const b00 = a00 * a11 - a01 * a10;
        const b01 = a00 * a12 - a02 * a10;
        const b02 = a00 * a13 - a03 * a10;
        const b03 = a01 * a12 - a02 * a11;
        const b04 = a01 * a13 - a03 * a11;
        const b05 = a02 * a13 - a03 * a12;
        const b06 = a20 * a31 - a21 * a30;
        const b07 = a20 * a32 - a22 * a30;
        const b08 = a20 * a33 - a23 * a30;
        const b09 = a21 * a32 - a22 * a31;
        const b10 = a21 * a33 - a23 * a31;
        const b11 = a22 * a33 - a23 * a32;
        out[0] = a11 * b11 - a12 * b10 + a13 * b09;
        out[1] = a02 * b10 - a01 * b11 - a03 * b09;
        out[2] = a31 * b05 - a32 * b04 + a33 * b03;
        out[3] = a22 * b04 - a21 * b05 - a23 * b03;
        out[4] = a12 * b08 - a10 * b11 - a13 * b07;
        out[5] = a00 * b11 - a02 * b08 + a03 * b07;
        out[6] = a32 * b02 - a30 * b05 - a33 * b01;
        out[7] = a20 * b05 - a22 * b02 + a23 * b01;
        out[8] = a10 * b10 - a11 * b08 + a13 * b06;
        out[9] = a01 * b08 - a00 * b10 - a03 * b06;
        out[10] = a30 * b04 - a31 * b02 + a33 * b00;
        out[11] = a21 * b02 - a20 * b04 - a23 * b00;
        out[12] = a11 * b07 - a10 * b09 - a12 * b06;
        out[13] = a00 * b09 - a01 * b07 + a02 * b06;
        out[14] = a31 * b01 - a30 * b03 - a32 * b00;
        out[15] = a20 * b03 - a21 * b01 + a22 * b00;
        return out;
      }
      /**
       * Calculates the determinant of a {@link Mat4}
       * @category Static
       *
       * @param a - the source matrix
       * @returns determinant of a
       */
      static determinant(a) {
        const a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
        const a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
        const a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
        const a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
        const b0 = a00 * a11 - a01 * a10;
        const b1 = a00 * a12 - a02 * a10;
        const b2 = a01 * a12 - a02 * a11;
        const b3 = a20 * a31 - a21 * a30;
        const b4 = a20 * a32 - a22 * a30;
        const b5 = a21 * a32 - a22 * a31;
        const b6 = a00 * b5 - a01 * b4 + a02 * b3;
        const b7 = a10 * b5 - a11 * b4 + a12 * b3;
        const b8 = a20 * b2 - a21 * b1 + a22 * b0;
        const b9 = a30 * b2 - a31 * b1 + a32 * b0;
        return a13 * b6 - a03 * b7 + a33 * b8 - a23 * b9;
      }
      /**
       * Multiplies two {@link Mat4}s
       * @category Static
       *
       * @param out - The receiving Matrix
       * @param a - The first operand
       * @param b - The second operand
       * @returns `out`
       */
      static multiply(out, a, b) {
        const a00 = a[0];
        const a01 = a[1];
        const a02 = a[2];
        const a03 = a[3];
        const a10 = a[4];
        const a11 = a[5];
        const a12 = a[6];
        const a13 = a[7];
        const a20 = a[8];
        const a21 = a[9];
        const a22 = a[10];
        const a23 = a[11];
        const a30 = a[12];
        const a31 = a[13];
        const a32 = a[14];
        const a33 = a[15];
        let b0 = b[0];
        let b1 = b[1];
        let b2 = b[2];
        let b3 = b[3];
        out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[4];
        b1 = b[5];
        b2 = b[6];
        b3 = b[7];
        out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[8];
        b1 = b[9];
        b2 = b[10];
        b3 = b[11];
        out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        b0 = b[12];
        b1 = b[13];
        b2 = b[14];
        b3 = b[15];
        out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
        out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
        out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
        out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
        return out;
      }
      /**
       * Alias for {@link Mat4.multiply}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static mul(out, a, b) {
        return out;
      }
      /**
       * Translate a {@link Mat4} by the given vector
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to translate
       * @param v - vector to translate by
       * @returns `out`
       */
      static translate(out, a, v) {
        const x = v[0];
        const y = v[1];
        const z = v[2];
        if (a === out) {
          out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
          out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
          out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
          out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
        } else {
          const a00 = a[0];
          const a01 = a[1];
          const a02 = a[2];
          const a03 = a[3];
          const a10 = a[4];
          const a11 = a[5];
          const a12 = a[6];
          const a13 = a[7];
          const a20 = a[8];
          const a21 = a[9];
          const a22 = a[10];
          const a23 = a[11];
          out[0] = a00;
          out[1] = a01;
          out[2] = a02;
          out[3] = a03;
          out[4] = a10;
          out[5] = a11;
          out[6] = a12;
          out[7] = a13;
          out[8] = a20;
          out[9] = a21;
          out[10] = a22;
          out[11] = a23;
          out[12] = a00 * x + a10 * y + a20 * z + a[12];
          out[13] = a01 * x + a11 * y + a21 * z + a[13];
          out[14] = a02 * x + a12 * y + a22 * z + a[14];
          out[15] = a03 * x + a13 * y + a23 * z + a[15];
        }
        return out;
      }
      /**
       * Scales the {@link Mat4} by the dimensions in the given {@link Vec3} not using vectorization
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to scale
       * @param v - the {@link Vec3} to scale the matrix by
       * @returns `out`
       **/
      static scale(out, a, v) {
        const x = v[0];
        const y = v[1];
        const z = v[2];
        out[0] = a[0] * x;
        out[1] = a[1] * x;
        out[2] = a[2] * x;
        out[3] = a[3] * x;
        out[4] = a[4] * y;
        out[5] = a[5] * y;
        out[6] = a[6] * y;
        out[7] = a[7] * y;
        out[8] = a[8] * z;
        out[9] = a[9] * z;
        out[10] = a[10] * z;
        out[11] = a[11] * z;
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
        return out;
      }
      /**
       * Rotates a {@link Mat4} by the given angle around the given axis
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to rotate
       * @param rad - the angle to rotate the matrix by
       * @param axis - the axis to rotate around
       * @returns `out` or `null` if axis has a length of 0
       */
      static rotate(out, a, rad, axis) {
        let x = axis[0];
        let y = axis[1];
        let z = axis[2];
        let len = Math.sqrt(x * x + y * y + z * z);
        if (len < GLM_EPSILON) {
          return null;
        }
        len = 1 / len;
        x *= len;
        y *= len;
        z *= len;
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        const t = 1 - c;
        const a00 = a[0];
        const a01 = a[1];
        const a02 = a[2];
        const a03 = a[3];
        const a10 = a[4];
        const a11 = a[5];
        const a12 = a[6];
        const a13 = a[7];
        const a20 = a[8];
        const a21 = a[9];
        const a22 = a[10];
        const a23 = a[11];
        const b00 = x * x * t + c;
        const b01 = y * x * t + z * s;
        const b02 = z * x * t - y * s;
        const b10 = x * y * t - z * s;
        const b11 = y * y * t + c;
        const b12 = z * y * t + x * s;
        const b20 = x * z * t + y * s;
        const b21 = y * z * t - x * s;
        const b22 = z * z * t + c;
        out[0] = a00 * b00 + a10 * b01 + a20 * b02;
        out[1] = a01 * b00 + a11 * b01 + a21 * b02;
        out[2] = a02 * b00 + a12 * b01 + a22 * b02;
        out[3] = a03 * b00 + a13 * b01 + a23 * b02;
        out[4] = a00 * b10 + a10 * b11 + a20 * b12;
        out[5] = a01 * b10 + a11 * b11 + a21 * b12;
        out[6] = a02 * b10 + a12 * b11 + a22 * b12;
        out[7] = a03 * b10 + a13 * b11 + a23 * b12;
        out[8] = a00 * b20 + a10 * b21 + a20 * b22;
        out[9] = a01 * b20 + a11 * b21 + a21 * b22;
        out[10] = a02 * b20 + a12 * b21 + a22 * b22;
        out[11] = a03 * b20 + a13 * b21 + a23 * b22;
        if (a !== out) {
          out[12] = a[12];
          out[13] = a[13];
          out[14] = a[14];
          out[15] = a[15];
        }
        return out;
      }
      /**
       * Rotates a matrix by the given angle around the X axis
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to rotate
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static rotateX(out, a, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        const a10 = a[4];
        const a11 = a[5];
        const a12 = a[6];
        const a13 = a[7];
        const a20 = a[8];
        const a21 = a[9];
        const a22 = a[10];
        const a23 = a[11];
        if (a !== out) {
          out[0] = a[0];
          out[1] = a[1];
          out[2] = a[2];
          out[3] = a[3];
          out[12] = a[12];
          out[13] = a[13];
          out[14] = a[14];
          out[15] = a[15];
        }
        out[4] = a10 * c + a20 * s;
        out[5] = a11 * c + a21 * s;
        out[6] = a12 * c + a22 * s;
        out[7] = a13 * c + a23 * s;
        out[8] = a20 * c - a10 * s;
        out[9] = a21 * c - a11 * s;
        out[10] = a22 * c - a12 * s;
        out[11] = a23 * c - a13 * s;
        return out;
      }
      /**
       * Rotates a matrix by the given angle around the Y axis
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to rotate
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static rotateY(out, a, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        const a00 = a[0];
        const a01 = a[1];
        const a02 = a[2];
        const a03 = a[3];
        const a20 = a[8];
        const a21 = a[9];
        const a22 = a[10];
        const a23 = a[11];
        if (a !== out) {
          out[4] = a[4];
          out[5] = a[5];
          out[6] = a[6];
          out[7] = a[7];
          out[12] = a[12];
          out[13] = a[13];
          out[14] = a[14];
          out[15] = a[15];
        }
        out[0] = a00 * c - a20 * s;
        out[1] = a01 * c - a21 * s;
        out[2] = a02 * c - a22 * s;
        out[3] = a03 * c - a23 * s;
        out[8] = a00 * s + a20 * c;
        out[9] = a01 * s + a21 * c;
        out[10] = a02 * s + a22 * c;
        out[11] = a03 * s + a23 * c;
        return out;
      }
      /**
       * Rotates a matrix by the given angle around the Z axis
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to rotate
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static rotateZ(out, a, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        const a00 = a[0];
        const a01 = a[1];
        const a02 = a[2];
        const a03 = a[3];
        const a10 = a[4];
        const a11 = a[5];
        const a12 = a[6];
        const a13 = a[7];
        if (a !== out) {
          out[8] = a[8];
          out[9] = a[9];
          out[10] = a[10];
          out[11] = a[11];
          out[12] = a[12];
          out[13] = a[13];
          out[14] = a[14];
          out[15] = a[15];
        }
        out[0] = a00 * c + a10 * s;
        out[1] = a01 * c + a11 * s;
        out[2] = a02 * c + a12 * s;
        out[3] = a03 * c + a13 * s;
        out[4] = a10 * c - a00 * s;
        out[5] = a11 * c - a01 * s;
        out[6] = a12 * c - a02 * s;
        out[7] = a13 * c - a03 * s;
        return out;
      }
      /**
       * Creates a {@link Mat4} from a vector translation
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.translate(dest, dest, vec);
       * ```
       * @category Static
       *
       * @param out - {@link Mat4} receiving operation result
       * @param v - Translation vector
       * @returns `out`
       */
      static fromTranslation(out, v) {
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = 1;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 1;
        out[11] = 0;
        out[12] = v[0];
        out[13] = v[1];
        out[14] = v[2];
        out[15] = 1;
        return out;
      }
      /**
       * Creates a {@link Mat4} from a vector scaling
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.scale(dest, dest, vec);
       * ```
       * @category Static
       *
       * @param out - {@link Mat4} receiving operation result
       * @param v - Scaling vector
       * @returns `out`
       */
      static fromScaling(out, v) {
        out[0] = v[0];
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = v[1];
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = v[2];
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Creates a {@link Mat4} from a given angle around a given axis
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.rotate(dest, dest, rad, axis);
       * ```
       * @category Static
       *
       * @param out - {@link Mat4} receiving operation result
       * @param rad - the angle to rotate the matrix by
       * @param axis - the axis to rotate around
       * @returns `out` or `null` if `axis` has a length of 0
       */
      static fromRotation(out, rad, axis) {
        let x = axis[0];
        let y = axis[1];
        let z = axis[2];
        let len = Math.sqrt(x * x + y * y + z * z);
        if (len < GLM_EPSILON) {
          return null;
        }
        len = 1 / len;
        x *= len;
        y *= len;
        z *= len;
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        const t = 1 - c;
        out[0] = x * x * t + c;
        out[1] = y * x * t + z * s;
        out[2] = z * x * t - y * s;
        out[3] = 0;
        out[4] = x * y * t - z * s;
        out[5] = y * y * t + c;
        out[6] = z * y * t + x * s;
        out[7] = 0;
        out[8] = x * z * t + y * s;
        out[9] = y * z * t - x * s;
        out[10] = z * z * t + c;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Creates a matrix from the given angle around the X axis
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.rotateX(dest, dest, rad);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static fromXRotation(out, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        out[0] = 1;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = c;
        out[6] = s;
        out[7] = 0;
        out[8] = 0;
        out[9] = -s;
        out[10] = c;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Creates a matrix from the given angle around the Y axis
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.rotateY(dest, dest, rad);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static fromYRotation(out, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        out[0] = c;
        out[1] = 0;
        out[2] = -s;
        out[3] = 0;
        out[4] = 0;
        out[5] = 1;
        out[6] = 0;
        out[7] = 0;
        out[8] = s;
        out[9] = 0;
        out[10] = c;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Creates a matrix from the given angle around the Z axis
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.rotateZ(dest, dest, rad);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param rad - the angle to rotate the matrix by
       * @returns `out`
       */
      static fromZRotation(out, rad) {
        const s = Math.sin(rad);
        const c = Math.cos(rad);
        out[0] = c;
        out[1] = s;
        out[2] = 0;
        out[3] = 0;
        out[4] = -s;
        out[5] = c;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 1;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Creates a matrix from a quaternion rotation and vector translation
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.translate(dest, vec);
       *   let quatMat = mat4.create();
       *   quat4.toMat4(quat, quatMat);
       *   mat4.multiply(dest, quatMat);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param q - Rotation quaternion
       * @param v - Translation vector
       * @returns `out`
       */
      static fromRotationTranslation(out, q, v) {
        const x = q[0];
        const y = q[1];
        const z = q[2];
        const w = q[3];
        const x2 = x + x;
        const y2 = y + y;
        const z2 = z + z;
        const xx = x * x2;
        const xy = x * y2;
        const xz = x * z2;
        const yy = y * y2;
        const yz = y * z2;
        const zz = z * z2;
        const wx = w * x2;
        const wy = w * y2;
        const wz = w * z2;
        out[0] = 1 - (yy + zz);
        out[1] = xy + wz;
        out[2] = xz - wy;
        out[3] = 0;
        out[4] = xy - wz;
        out[5] = 1 - (xx + zz);
        out[6] = yz + wx;
        out[7] = 0;
        out[8] = xz + wy;
        out[9] = yz - wx;
        out[10] = 1 - (xx + yy);
        out[11] = 0;
        out[12] = v[0];
        out[13] = v[1];
        out[14] = v[2];
        out[15] = 1;
        return out;
      }
      /**
       * Sets a {@link Mat4} from a {@link Quat2}.
       * @category Static
       *
       * @param out - Matrix
       * @param a - Dual Quaternion
       * @returns `out`
       */
      static fromQuat2(out, a) {
        const bx = -a[0];
        const by = -a[1];
        const bz = -a[2];
        const bw = a[3];
        const ax = a[4];
        const ay = a[5];
        const az = a[6];
        const aw = a[7];
        const magnitude = bx * bx + by * by + bz * bz + bw * bw;
        if (magnitude > 0) {
          _Mat4.#TMP_VEC3[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
          _Mat4.#TMP_VEC3[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
          _Mat4.#TMP_VEC3[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
        } else {
          _Mat4.#TMP_VEC3[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
          _Mat4.#TMP_VEC3[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
          _Mat4.#TMP_VEC3[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
        }
        _Mat4.fromRotationTranslation(out, a, _Mat4.#TMP_VEC3);
        return out;
      }
      /**
       * Calculates a {@link Mat4} normal matrix (transpose inverse) from a {@link Mat4}
       * @category Static
       *
       * @param out - Matrix receiving operation result
       * @param a - Mat4 to derive the normal matrix from
       * @returns `out` or `null` if the matrix is not invertible
       */
      static normalFromMat4(out, a) {
        const a00 = a[0];
        const a01 = a[1];
        const a02 = a[2];
        const a03 = a[3];
        const a10 = a[4];
        const a11 = a[5];
        const a12 = a[6];
        const a13 = a[7];
        const a20 = a[8];
        const a21 = a[9];
        const a22 = a[10];
        const a23 = a[11];
        const a30 = a[12];
        const a31 = a[13];
        const a32 = a[14];
        const a33 = a[15];
        const b00 = a00 * a11 - a01 * a10;
        const b01 = a00 * a12 - a02 * a10;
        const b02 = a00 * a13 - a03 * a10;
        const b03 = a01 * a12 - a02 * a11;
        const b04 = a01 * a13 - a03 * a11;
        const b05 = a02 * a13 - a03 * a12;
        const b06 = a20 * a31 - a21 * a30;
        const b07 = a20 * a32 - a22 * a30;
        const b08 = a20 * a33 - a23 * a30;
        const b09 = a21 * a32 - a22 * a31;
        const b10 = a21 * a33 - a23 * a31;
        const b11 = a22 * a33 - a23 * a32;
        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
        if (!det) {
          return null;
        }
        det = 1 / det;
        out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
        out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
        out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
        out[3] = 0;
        out[4] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
        out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
        out[6] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
        out[7] = 0;
        out[8] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
        out[9] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
        out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Calculates a {@link Mat4} normal matrix (transpose inverse) from a {@link Mat4}
       * This version omits the calculation of the constant factor (1/determinant), so
       * any normals transformed with it will need to be renormalized.
       * From https://stackoverflow.com/a/27616419/25968
       * @category Static
       *
       * @param out - Matrix receiving operation result
       * @param a - Mat4 to derive the normal matrix from
       * @returns `out`
       */
      static normalFromMat4Fast(out, a) {
        const ax = a[0];
        const ay = a[1];
        const az = a[2];
        const bx = a[4];
        const by = a[5];
        const bz = a[6];
        const cx = a[8];
        const cy = a[9];
        const cz = a[10];
        out[0] = by * cz - cz * cy;
        out[1] = bz * cx - cx * cz;
        out[2] = bx * cy - cy * cx;
        out[3] = 0;
        out[4] = cy * az - cz * ay;
        out[5] = cz * ax - cx * az;
        out[6] = cx * ay - cy * ax;
        out[7] = 0;
        out[8] = ay * bz - az * by;
        out[9] = az * bx - ax * bz;
        out[10] = ax * by - ay * bx;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Returns the translation vector component of a transformation
       * matrix. If a matrix is built with fromRotationTranslation,
       * the returned vector will be the same as the translation vector
       * originally supplied.
       * @category Static
       *
       * @param  {vec3} out Vector to receive translation component
       * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
       * @return {vec3} out
       */
      static getTranslation(out, mat) {
        out[0] = mat[12];
        out[1] = mat[13];
        out[2] = mat[14];
        return out;
      }
      /**
       * Returns the scaling factor component of a transformation
       * matrix. If a matrix is built with fromRotationTranslationScale
       * with a normalized Quaternion parameter, the returned vector will be
       * the same as the scaling vector
       * originally supplied.
       * @category Static
       *
       * @param  {vec3} out Vector to receive scaling factor component
       * @param  {ReadonlyMat4} mat Matrix to be decomposed (input)
       * @return {vec3} out
       */
      static getScaling(out, mat) {
        const m11 = mat[0];
        const m12 = mat[1];
        const m13 = mat[2];
        const m21 = mat[4];
        const m22 = mat[5];
        const m23 = mat[6];
        const m31 = mat[8];
        const m32 = mat[9];
        const m33 = mat[10];
        out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
        out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
        out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
        return out;
      }
      /**
       * Returns a quaternion representing the rotational component
       * of a transformation matrix. If a matrix is built with
       * fromRotationTranslation, the returned quaternion will be the
       * same as the quaternion originally supplied.
       * @category Static
       *
       * @param out - Quaternion to receive the rotation component
       * @param mat - Matrix to be decomposed (input)
       * @return `out`
       */
      static getRotation(out, mat) {
        _Mat4.getScaling(_Mat4.#TMP_VEC3, mat);
        const is1 = 1 / _Mat4.#TMP_VEC3[0];
        const is2 = 1 / _Mat4.#TMP_VEC3[1];
        const is3 = 1 / _Mat4.#TMP_VEC3[2];
        const sm11 = mat[0] * is1;
        const sm12 = mat[1] * is2;
        const sm13 = mat[2] * is3;
        const sm21 = mat[4] * is1;
        const sm22 = mat[5] * is2;
        const sm23 = mat[6] * is3;
        const sm31 = mat[8] * is1;
        const sm32 = mat[9] * is2;
        const sm33 = mat[10] * is3;
        const trace = sm11 + sm22 + sm33;
        let S = 0;
        if (trace > 0) {
          S = Math.sqrt(trace + 1) * 2;
          out[3] = 0.25 * S;
          out[0] = (sm23 - sm32) / S;
          out[1] = (sm31 - sm13) / S;
          out[2] = (sm12 - sm21) / S;
        } else if (sm11 > sm22 && sm11 > sm33) {
          S = Math.sqrt(1 + sm11 - sm22 - sm33) * 2;
          out[3] = (sm23 - sm32) / S;
          out[0] = 0.25 * S;
          out[1] = (sm12 + sm21) / S;
          out[2] = (sm31 + sm13) / S;
        } else if (sm22 > sm33) {
          S = Math.sqrt(1 + sm22 - sm11 - sm33) * 2;
          out[3] = (sm31 - sm13) / S;
          out[0] = (sm12 + sm21) / S;
          out[1] = 0.25 * S;
          out[2] = (sm23 + sm32) / S;
        } else {
          S = Math.sqrt(1 + sm33 - sm11 - sm22) * 2;
          out[3] = (sm12 - sm21) / S;
          out[0] = (sm31 + sm13) / S;
          out[1] = (sm23 + sm32) / S;
          out[2] = 0.25 * S;
        }
        return out;
      }
      /**
       * Decomposes a transformation matrix into its rotation, translation
       * and scale components. Returns only the rotation component
       * @category Static
       *
       * @param out_r - Quaternion to receive the rotation component
       * @param out_t - Vector to receive the translation vector
       * @param out_s - Vector to receive the scaling factor
       * @param mat - Matrix to be decomposed (input)
       * @returns `out_r`
       */
      static decompose(out_r, out_t, out_s, mat) {
        out_t[0] = mat[12];
        out_t[1] = mat[13];
        out_t[2] = mat[14];
        const m11 = mat[0];
        const m12 = mat[1];
        const m13 = mat[2];
        const m21 = mat[4];
        const m22 = mat[5];
        const m23 = mat[6];
        const m31 = mat[8];
        const m32 = mat[9];
        const m33 = mat[10];
        out_s[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13);
        out_s[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23);
        out_s[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33);
        const is1 = 1 / out_s[0];
        const is2 = 1 / out_s[1];
        const is3 = 1 / out_s[2];
        const sm11 = m11 * is1;
        const sm12 = m12 * is2;
        const sm13 = m13 * is3;
        const sm21 = m21 * is1;
        const sm22 = m22 * is2;
        const sm23 = m23 * is3;
        const sm31 = m31 * is1;
        const sm32 = m32 * is2;
        const sm33 = m33 * is3;
        const trace = sm11 + sm22 + sm33;
        let S = 0;
        if (trace > 0) {
          S = Math.sqrt(trace + 1) * 2;
          out_r[3] = 0.25 * S;
          out_r[0] = (sm23 - sm32) / S;
          out_r[1] = (sm31 - sm13) / S;
          out_r[2] = (sm12 - sm21) / S;
        } else if (sm11 > sm22 && sm11 > sm33) {
          S = Math.sqrt(1 + sm11 - sm22 - sm33) * 2;
          out_r[3] = (sm23 - sm32) / S;
          out_r[0] = 0.25 * S;
          out_r[1] = (sm12 + sm21) / S;
          out_r[2] = (sm31 + sm13) / S;
        } else if (sm22 > sm33) {
          S = Math.sqrt(1 + sm22 - sm11 - sm33) * 2;
          out_r[3] = (sm31 - sm13) / S;
          out_r[0] = (sm12 + sm21) / S;
          out_r[1] = 0.25 * S;
          out_r[2] = (sm23 + sm32) / S;
        } else {
          S = Math.sqrt(1 + sm33 - sm11 - sm22) * 2;
          out_r[3] = (sm12 - sm21) / S;
          out_r[0] = (sm31 + sm13) / S;
          out_r[1] = (sm23 + sm32) / S;
          out_r[2] = 0.25 * S;
        }
        return out_r;
      }
      /**
       * Creates a matrix from a quaternion rotation, vector translation and vector scale
       * This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.translate(dest, vec);
       *   let quatMat = mat4.create();
       *   quat4.toMat4(quat, quatMat);
       *   mat4.multiply(dest, quatMat);
       *   mat4.scale(dest, scale);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param q - Rotation quaternion
       * @param v - Translation vector
       * @param s - Scaling vector
       * @returns `out`
       */
      static fromRotationTranslationScale(out, q, v, s) {
        const x = q[0];
        const y = q[1];
        const z = q[2];
        const w = q[3];
        const x2 = x + x;
        const y2 = y + y;
        const z2 = z + z;
        const xx = x * x2;
        const xy = x * y2;
        const xz = x * z2;
        const yy = y * y2;
        const yz = y * z2;
        const zz = z * z2;
        const wx = w * x2;
        const wy = w * y2;
        const wz = w * z2;
        const sx = s[0];
        const sy = s[1];
        const sz = s[2];
        out[0] = (1 - (yy + zz)) * sx;
        out[1] = (xy + wz) * sx;
        out[2] = (xz - wy) * sx;
        out[3] = 0;
        out[4] = (xy - wz) * sy;
        out[5] = (1 - (xx + zz)) * sy;
        out[6] = (yz + wx) * sy;
        out[7] = 0;
        out[8] = (xz + wy) * sz;
        out[9] = (yz - wx) * sz;
        out[10] = (1 - (xx + yy)) * sz;
        out[11] = 0;
        out[12] = v[0];
        out[13] = v[1];
        out[14] = v[2];
        out[15] = 1;
        return out;
      }
      /**
       * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the
       * given origin. This is equivalent to (but much faster than):
       * ```js
       *   mat4.identity(dest);
       *   mat4.translate(dest, vec);
       *   mat4.translate(dest, origin);
       *   let quatMat = mat4.create();
       *   quat4.toMat4(quat, quatMat);
       *   mat4.multiply(dest, quatMat);
       *   mat4.scale(dest, scale)
       *   mat4.translate(dest, negativeOrigin);
       * ```
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param q - Rotation quaternion
       * @param v - Translation vector
       * @param s - Scaling vector
       * @param o - The origin vector around which to scale and rotate
       * @returns `out`
       */
      static fromRotationTranslationScaleOrigin(out, q, v, s, o) {
        const x = q[0];
        const y = q[1];
        const z = q[2];
        const w = q[3];
        const x2 = x + x;
        const y2 = y + y;
        const z2 = z + z;
        const xx = x * x2;
        const xy = x * y2;
        const xz = x * z2;
        const yy = y * y2;
        const yz = y * z2;
        const zz = z * z2;
        const wx = w * x2;
        const wy = w * y2;
        const wz = w * z2;
        const sx = s[0];
        const sy = s[1];
        const sz = s[2];
        const ox = o[0];
        const oy = o[1];
        const oz = o[2];
        const out0 = (1 - (yy + zz)) * sx;
        const out1 = (xy + wz) * sx;
        const out2 = (xz - wy) * sx;
        const out4 = (xy - wz) * sy;
        const out5 = (1 - (xx + zz)) * sy;
        const out6 = (yz + wx) * sy;
        const out8 = (xz + wy) * sz;
        const out9 = (yz - wx) * sz;
        const out10 = (1 - (xx + yy)) * sz;
        out[0] = out0;
        out[1] = out1;
        out[2] = out2;
        out[3] = 0;
        out[4] = out4;
        out[5] = out5;
        out[6] = out6;
        out[7] = 0;
        out[8] = out8;
        out[9] = out9;
        out[10] = out10;
        out[11] = 0;
        out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz);
        out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz);
        out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz);
        out[15] = 1;
        return out;
      }
      /**
       * Calculates a 4x4 matrix from the given quaternion
       * @category Static
       *
       * @param out - mat4 receiving operation result
       * @param q - Quaternion to create matrix from
       * @returns `out`
       */
      static fromQuat(out, q) {
        const x = q[0];
        const y = q[1];
        const z = q[2];
        const w = q[3];
        const x2 = x + x;
        const y2 = y + y;
        const z2 = z + z;
        const xx = x * x2;
        const yx = y * x2;
        const yy = y * y2;
        const zx = z * x2;
        const zy = z * y2;
        const zz = z * z2;
        const wx = w * x2;
        const wy = w * y2;
        const wz = w * z2;
        out[0] = 1 - yy - zz;
        out[1] = yx + wz;
        out[2] = zx - wy;
        out[3] = 0;
        out[4] = yx - wz;
        out[5] = 1 - xx - zz;
        out[6] = zy + wx;
        out[7] = 0;
        out[8] = zx + wy;
        out[9] = zy - wx;
        out[10] = 1 - xx - yy;
        out[11] = 0;
        out[12] = 0;
        out[13] = 0;
        out[14] = 0;
        out[15] = 1;
        return out;
      }
      /**
       * Generates a frustum matrix with the given bounds
       * The near/far clip planes correspond to a normalized device coordinate Z range of [-1, 1],
       * which matches WebGL/OpenGL's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far -  Far bound of the frustum, can be null or Infinity
       * @returns `out`
       */
      static frustumNO(out, left, right, bottom, top, near, far = Infinity) {
        const rl = 1 / (right - left);
        const tb = 1 / (top - bottom);
        out[0] = near * 2 * rl;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = near * 2 * tb;
        out[6] = 0;
        out[7] = 0;
        out[8] = (right + left) * rl;
        out[9] = (top + bottom) * tb;
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[15] = 0;
        if (far != null && far !== Infinity) {
          const nf = 1 / (near - far);
          out[10] = (far + near) * nf;
          out[14] = 2 * far * near * nf;
        } else {
          out[10] = -1;
          out[14] = -2 * near;
        }
        return out;
      }
      /**
       * Alias for {@link Mat4.frustumNO}
       * @category Static
       * @deprecated Use {@link Mat4.frustumNO} or {@link Mat4.frustumZO} explicitly
       */
      static frustum(out, left, right, bottom, top, near, far = Infinity) {
        return out;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Generates a frustum matrix with the given bounds
       * The near/far clip planes correspond to a normalized device coordinate Z range of [0, 1],
       * which matches WebGPU/Vulkan/DirectX/Metal's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum, can be null or Infinity
       * @returns `out`
       */
      static frustumZO(out, left, right, bottom, top, near, far = Infinity) {
        const rl = 1 / (right - left);
        const tb = 1 / (top - bottom);
        out[0] = near * 2 * rl;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = near * 2 * tb;
        out[6] = 0;
        out[7] = 0;
        out[8] = (right + left) * rl;
        out[9] = (top + bottom) * tb;
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[15] = 0;
        if (far != null && far !== Infinity) {
          const nf = 1 / (near - far);
          out[10] = far * nf;
          out[14] = far * near * nf;
        } else {
          out[10] = -1;
          out[14] = -near;
        }
        return out;
      }
      /**
       * Generates a perspective projection matrix with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [-1, 1],
       * which matches WebGL/OpenGL's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param fovy - Vertical field of view in radians
       * @param aspect - Aspect ratio. typically viewport width/height
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum, can be null or Infinity
       * @returns `out`
       */
      static perspectiveNO(out, fovy, aspect, near, far = Infinity) {
        const f = 1 / Math.tan(fovy / 2);
        out[0] = f / aspect;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = f;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[15] = 0;
        if (far != null && far !== Infinity) {
          const nf = 1 / (near - far);
          out[10] = (far + near) * nf;
          out[14] = 2 * far * near * nf;
        } else {
          out[10] = -1;
          out[14] = -2 * near;
        }
        return out;
      }
      /**
       * Alias for {@link Mat4.perspectiveNO}
       * @category Static
       * @deprecated Use {@link Mat4.perspectiveNO} or {@link Mat4.perspectiveZO} explicitly
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static perspective(out, fovy, aspect, near, far = Infinity) {
        return out;
      }
      /**
       * Generates a perspective projection matrix suitable for WebGPU with the given bounds.
       * The near/far clip planes correspond to a normalized device coordinate Z range of [0, 1],
       * which matches WebGPU/Vulkan/DirectX/Metal's clip volume.
       * Passing null/undefined/no value for far will generate infinite projection matrix.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param fovy - Vertical field of view in radians
       * @param aspect - Aspect ratio. typically viewport width/height
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum, can be null or Infinity
       * @returns `out`
       */
      static perspectiveZO(out, fovy, aspect, near, far = Infinity) {
        const f = 1 / Math.tan(fovy / 2);
        out[0] = f / aspect;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = f;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[15] = 0;
        if (far != null && far !== Infinity) {
          const nf = 1 / (near - far);
          out[10] = far * nf;
          out[14] = far * near * nf;
        } else {
          out[10] = -1;
          out[14] = -near;
        }
        return out;
      }
      /**
       * Generates a perspective projection matrix with the given field of view. This is primarily useful for generating
       * projection matrices to be used with the still experimental WebVR API.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param fov - Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum
       * @returns `out`
       * @deprecated
       */
      static perspectiveFromFieldOfView(out, fov, near, far) {
        const upTan = Math.tan(fov.upDegrees * Math.PI / 180);
        const downTan = Math.tan(fov.downDegrees * Math.PI / 180);
        const leftTan = Math.tan(fov.leftDegrees * Math.PI / 180);
        const rightTan = Math.tan(fov.rightDegrees * Math.PI / 180);
        const xScale = 2 / (leftTan + rightTan);
        const yScale = 2 / (upTan + downTan);
        out[0] = xScale;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = yScale;
        out[6] = 0;
        out[7] = 0;
        out[8] = -((leftTan - rightTan) * xScale * 0.5);
        out[9] = (upTan - downTan) * yScale * 0.5;
        out[10] = far / (near - far);
        out[11] = -1;
        out[12] = 0;
        out[13] = 0;
        out[14] = far * near / (near - far);
        out[15] = 0;
        return out;
      }
      /**
       * Generates an orthogonal projection matrix with the given bounds. The near / far clip planes correspond to a
       * normalized device coordinate Z range of [-1, 1], which matches WebGL / OpenGLs clip volume.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum
       * @returns `out`
       */
      static orthoNO(out, left, right, bottom, top, near, far) {
        const lr = 1 / (left - right);
        const bt = 1 / (bottom - top);
        const nf = 1 / (near - far);
        out[0] = -2 * lr;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = -2 * bt;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = 2 * nf;
        out[11] = 0;
        out[12] = (left + right) * lr;
        out[13] = (top + bottom) * bt;
        out[14] = (far + near) * nf;
        out[15] = 1;
        return out;
      }
      /**
       * Alias for {@link Mat4.orthoNO}
       * @category Static
       * @deprecated Use {@link Mat4.orthoNO} or {@link Mat4.orthoZO} explicitly
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static ortho(out, left, right, bottom, top, near, far) {
        return out;
      }
      /**
       * Generates a orthogonal projection matrix with the given bounds. The near / far clip planes correspond to a
       * normalized device coordinate Z range of [0, 1], which matches WebGPU / Vulkan / DirectX / Metal's clip volume.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param left - Left bound of the frustum
       * @param right - Right bound of the frustum
       * @param bottom - Bottom bound of the frustum
       * @param top - Top bound of the frustum
       * @param near - Near bound of the frustum
       * @param far - Far bound of the frustum
       * @returns `out`
       */
      static orthoZO(out, left, right, bottom, top, near, far) {
        const lr = 1 / (left - right);
        const bt = 1 / (bottom - top);
        const nf = 1 / (near - far);
        out[0] = -2 * lr;
        out[1] = 0;
        out[2] = 0;
        out[3] = 0;
        out[4] = 0;
        out[5] = -2 * bt;
        out[6] = 0;
        out[7] = 0;
        out[8] = 0;
        out[9] = 0;
        out[10] = nf;
        out[11] = 0;
        out[12] = (left + right) * lr;
        out[13] = (top + bottom) * bt;
        out[14] = near * nf;
        out[15] = 1;
        return out;
      }
      /**
       * Generates a look-at matrix with the given eye position, focal point, and up axis. If you want a matrix that
       * actually makes an object look at another object, you should use targetTo instead.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param eye - Position of the viewer
       * @param center - Point the viewer is looking at
       * @param up - vec3 pointing up
       * @returns `out`
       */
      static lookAt(out, eye, center, up) {
        const eyex = eye[0];
        const eyey = eye[1];
        const eyez = eye[2];
        const upx = up[0];
        const upy = up[1];
        const upz = up[2];
        const centerx = center[0];
        const centery = center[1];
        const centerz = center[2];
        if (Math.abs(eyex - centerx) < GLM_EPSILON && Math.abs(eyey - centery) < GLM_EPSILON && Math.abs(eyez - centerz) < GLM_EPSILON) {
          return _Mat4.identity(out);
        }
        let z0 = eyex - centerx;
        let z1 = eyey - centery;
        let z2 = eyez - centerz;
        let len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
        z0 *= len;
        z1 *= len;
        z2 *= len;
        let x0 = upy * z2 - upz * z1;
        let x1 = upz * z0 - upx * z2;
        let x2 = upx * z1 - upy * z0;
        len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
        if (!len) {
          x0 = 0;
          x1 = 0;
          x2 = 0;
        } else {
          len = 1 / len;
          x0 *= len;
          x1 *= len;
          x2 *= len;
        }
        let y0 = z1 * x2 - z2 * x1;
        let y1 = z2 * x0 - z0 * x2;
        let y2 = z0 * x1 - z1 * x0;
        len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
        if (!len) {
          y0 = 0;
          y1 = 0;
          y2 = 0;
        } else {
          len = 1 / len;
          y0 *= len;
          y1 *= len;
          y2 *= len;
        }
        out[0] = x0;
        out[1] = y0;
        out[2] = z0;
        out[3] = 0;
        out[4] = x1;
        out[5] = y1;
        out[6] = z1;
        out[7] = 0;
        out[8] = x2;
        out[9] = y2;
        out[10] = z2;
        out[11] = 0;
        out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
        out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
        out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
        out[15] = 1;
        return out;
      }
      /**
       * Generates a matrix that makes something look at something else.
       * @category Static
       *
       * @param out - mat4 frustum matrix will be written into
       * @param eye - Position of the viewer
       * @param target - Point the viewer is looking at
       * @param up - vec3 pointing up
       * @returns `out`
       */
      static targetTo(out, eye, target, up) {
        const eyex = eye[0];
        const eyey = eye[1];
        const eyez = eye[2];
        const upx = up[0];
        const upy = up[1];
        const upz = up[2];
        let z0 = eyex - target[0];
        let z1 = eyey - target[1];
        let z2 = eyez - target[2];
        let len = z0 * z0 + z1 * z1 + z2 * z2;
        if (len > 0) {
          len = 1 / Math.sqrt(len);
          z0 *= len;
          z1 *= len;
          z2 *= len;
        }
        let x0 = upy * z2 - upz * z1;
        let x1 = upz * z0 - upx * z2;
        let x2 = upx * z1 - upy * z0;
        len = x0 * x0 + x1 * x1 + x2 * x2;
        if (len > 0) {
          len = 1 / Math.sqrt(len);
          x0 *= len;
          x1 *= len;
          x2 *= len;
        }
        out[0] = x0;
        out[1] = x1;
        out[2] = x2;
        out[3] = 0;
        out[4] = z1 * x2 - z2 * x1;
        out[5] = z2 * x0 - z0 * x2;
        out[6] = z0 * x1 - z1 * x0;
        out[7] = 0;
        out[8] = z0;
        out[9] = z1;
        out[10] = z2;
        out[11] = 0;
        out[12] = eyex;
        out[13] = eyey;
        out[14] = eyez;
        out[15] = 1;
        return out;
      }
      /**
       * Returns Frobenius norm of a {@link Mat4}
       * @category Static
       *
       * @param a - the matrix to calculate Frobenius norm of
       * @returns Frobenius norm
       */
      static frob(a) {
        return Math.sqrt(
          a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3] + a[4] * a[4] + a[5] * a[5] + a[6] * a[6] + a[7] * a[7] + a[8] * a[8] + a[9] * a[9] + a[10] * a[10] + a[11] * a[11] + a[12] * a[12] + a[13] * a[13] + a[14] * a[14] + a[15] * a[15]
        );
      }
      /**
       * Adds two {@link Mat4}'s
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static add(out, a, b) {
        out[0] = a[0] + b[0];
        out[1] = a[1] + b[1];
        out[2] = a[2] + b[2];
        out[3] = a[3] + b[3];
        out[4] = a[4] + b[4];
        out[5] = a[5] + b[5];
        out[6] = a[6] + b[6];
        out[7] = a[7] + b[7];
        out[8] = a[8] + b[8];
        out[9] = a[9] + b[9];
        out[10] = a[10] + b[10];
        out[11] = a[11] + b[11];
        out[12] = a[12] + b[12];
        out[13] = a[13] + b[13];
        out[14] = a[14] + b[14];
        out[15] = a[15] + b[15];
        return out;
      }
      /**
       * Subtracts matrix b from matrix a
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static subtract(out, a, b) {
        out[0] = a[0] - b[0];
        out[1] = a[1] - b[1];
        out[2] = a[2] - b[2];
        out[3] = a[3] - b[3];
        out[4] = a[4] - b[4];
        out[5] = a[5] - b[5];
        out[6] = a[6] - b[6];
        out[7] = a[7] - b[7];
        out[8] = a[8] - b[8];
        out[9] = a[9] - b[9];
        out[10] = a[10] - b[10];
        out[11] = a[11] - b[11];
        out[12] = a[12] - b[12];
        out[13] = a[13] - b[13];
        out[14] = a[14] - b[14];
        out[15] = a[15] - b[15];
        return out;
      }
      /**
       * Alias for {@link Mat4.subtract}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static sub(out, a, b) {
        return out;
      }
      /**
       * Multiply each element of the matrix by a scalar.
       * @category Static
       *
       * @param out - the receiving matrix
       * @param a - the matrix to scale
       * @param b - amount to scale the matrix's elements by
       * @returns `out`
       */
      static multiplyScalar(out, a, b) {
        out[0] = a[0] * b;
        out[1] = a[1] * b;
        out[2] = a[2] * b;
        out[3] = a[3] * b;
        out[4] = a[4] * b;
        out[5] = a[5] * b;
        out[6] = a[6] * b;
        out[7] = a[7] * b;
        out[8] = a[8] * b;
        out[9] = a[9] * b;
        out[10] = a[10] * b;
        out[11] = a[11] * b;
        out[12] = a[12] * b;
        out[13] = a[13] * b;
        out[14] = a[14] * b;
        out[15] = a[15] * b;
        return out;
      }
      /**
       * Adds two mat4's after multiplying each element of the second operand by a scalar value.
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param scale - the amount to scale b's elements by before adding
       * @returns `out`
       */
      static multiplyScalarAndAdd(out, a, b, scale2) {
        out[0] = a[0] + b[0] * scale2;
        out[1] = a[1] + b[1] * scale2;
        out[2] = a[2] + b[2] * scale2;
        out[3] = a[3] + b[3] * scale2;
        out[4] = a[4] + b[4] * scale2;
        out[5] = a[5] + b[5] * scale2;
        out[6] = a[6] + b[6] * scale2;
        out[7] = a[7] + b[7] * scale2;
        out[8] = a[8] + b[8] * scale2;
        out[9] = a[9] + b[9] * scale2;
        out[10] = a[10] + b[10] * scale2;
        out[11] = a[11] + b[11] * scale2;
        out[12] = a[12] + b[12] * scale2;
        out[13] = a[13] + b[13] * scale2;
        out[14] = a[14] + b[14] * scale2;
        out[15] = a[15] + b[15] * scale2;
        return out;
      }
      /**
       * Returns whether two {@link Mat4}s have exactly the same elements in the same position (when compared with ===).
       * @category Static
       *
       * @param a - The first matrix.
       * @param b - The second matrix.
       * @returns True if the matrices are equal, false otherwise.
       */
      static exactEquals(a, b) {
        return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
      }
      /**
       * Returns whether two {@link Mat4}s have approximately the same elements in the same position.
       * @category Static
       *
       * @param a - The first matrix.
       * @param b - The second matrix.
       * @returns True if the matrices are equal, false otherwise.
       */
      static equals(a, b) {
        const a0 = a[0];
        const a1 = a[1];
        const a2 = a[2];
        const a3 = a[3];
        const a4 = a[4];
        const a5 = a[5];
        const a6 = a[6];
        const a7 = a[7];
        const a8 = a[8];
        const a9 = a[9];
        const a10 = a[10];
        const a11 = a[11];
        const a12 = a[12];
        const a13 = a[13];
        const a14 = a[14];
        const a15 = a[15];
        const b0 = b[0];
        const b1 = b[1];
        const b2 = b[2];
        const b3 = b[3];
        const b4 = b[4];
        const b5 = b[5];
        const b6 = b[6];
        const b7 = b[7];
        const b8 = b[8];
        const b9 = b[9];
        const b10 = b[10];
        const b11 = b[11];
        const b12 = b[12];
        const b13 = b[13];
        const b14 = b[14];
        const b15 = b[15];
        return Math.abs(a0 - b0) <= GLM_EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= GLM_EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= GLM_EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= GLM_EPSILON * Math.max(1, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= GLM_EPSILON * Math.max(1, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= GLM_EPSILON * Math.max(1, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= GLM_EPSILON * Math.max(1, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= GLM_EPSILON * Math.max(1, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= GLM_EPSILON * Math.max(1, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= GLM_EPSILON * Math.max(1, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= GLM_EPSILON * Math.max(1, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= GLM_EPSILON * Math.max(1, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= GLM_EPSILON * Math.max(1, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= GLM_EPSILON * Math.max(1, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= GLM_EPSILON * Math.max(1, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= GLM_EPSILON * Math.max(1, Math.abs(a15), Math.abs(b15));
      }
      /**
       * Returns a string representation of a {@link Mat4}
       * @category Static
       *
       * @param a - matrix to represent as a string
       * @returns string representation of the matrix
       */
      static str(a) {
        return `Mat4(${a.join(", ")})`;
      }
    };
    Mat4.prototype.mul = Mat4.prototype.multiply;
    Mat4.sub = Mat4.subtract;
    Mat4.mul = Mat4.multiply;
    Mat4.frustum = Mat4.frustumNO;
    Mat4.perspective = Mat4.perspectiveNO;
    Mat4.ortho = Mat4.orthoNO;
    var Vec3 = class _Vec3 extends Float32Array {
      /**
       * Create a {@link Vec3}.
       *
       * @category Constructor
       */
      constructor(...values) {
        switch (values.length) {
          case 3:
            super(values);
            break;
          case 2:
            super(values[0], values[1], 3);
            break;
          case 1: {
            const v = values[0];
            if (typeof v === "number") {
              super([v, v, v]);
            } else {
              super(v, 0, 3);
            }
            break;
          }
          default:
            super(3);
            break;
        }
      }
      // ============
      // Accessors
      // ============
      // Getters and setters to make component access read better.
      // These are likely to be a little bit slower than direct array access.
      /**
       * The x component of the vector. Equivalent to `this[0];`
       * @category Vector Components
       */
      get x() {
        return this[0];
      }
      set x(value) {
        this[0] = value;
      }
      /**
       * The y component of the vector. Equivalent to `this[1];`
       * @category Vector Components
       */
      get y() {
        return this[1];
      }
      set y(value) {
        this[1] = value;
      }
      /**
       * The z component of the vector. Equivalent to `this[2];`
       * @category Vector Components
       */
      get z() {
        return this[2];
      }
      set z(value) {
        this[2] = value;
      }
      // Alternate set of getters and setters in case this is being used to define
      // a color.
      /**
       * The r component of the vector. Equivalent to `this[0];`
       * @category Color Components
       */
      get r() {
        return this[0];
      }
      set r(value) {
        this[0] = value;
      }
      /**
       * The g component of the vector. Equivalent to `this[1];`
       * @category Color Components
       */
      get g() {
        return this[1];
      }
      set g(value) {
        this[1] = value;
      }
      /**
       * The b component of the vector. Equivalent to `this[2];`
       * @category Color Components
       */
      get b() {
        return this[2];
      }
      set b(value) {
        this[2] = value;
      }
      /**
       * The magnitude (length) of this.
       * Equivalent to `Vec3.magnitude(this);`
       *
       * Magnitude is used because the `length` attribute is already defined by
       * TypedArrays to mean the number of elements in the array.
       *
       * @category Accessors
       */
      get magnitude() {
        const x = this[0];
        const y = this[1];
        const z = this[2];
        return Math.sqrt(x * x + y * y + z * z);
      }
      /**
       * Alias for {@link Vec3.magnitude}
       *
       * @category Accessors
       */
      get mag() {
        return this.magnitude;
      }
      /**
       * The squared magnitude (length) of `this`.
       * Equivalent to `Vec3.squaredMagnitude(this);`
       *
       * @category Accessors
       */
      get squaredMagnitude() {
        const x = this[0];
        const y = this[1];
        const z = this[2];
        return x * x + y * y + z * z;
      }
      /**
       * Alias for {@link Vec3.squaredMagnitude}
       *
       * @category Accessors
       */
      get sqrMag() {
        return this.squaredMagnitude;
      }
      /**
       * A string representation of `this`
       * Equivalent to `Vec3.str(this);`
       *
       * @category Accessors
       */
      get str() {
        return _Vec3.str(this);
      }
      // ===================
      // Instances methods
      // ===================
      /**
       * Copy the values from another {@link Vec3} into `this`.
       * @category Methods
       *
       * @param a the source vector
       * @returns `this`
       */
      copy(a) {
        this.set(a);
        return this;
      }
      /**
       * Adds a {@link Vec3} to `this`.
       * Equivalent to `Vec3.add(this, this, b);`
       * @category Methods
       *
       * @param b - The vector to add to `this`
       * @returns `this`
       */
      add(b) {
        this[0] += b[0];
        this[1] += b[1];
        this[2] += b[2];
        return this;
      }
      /**
       * Subtracts a {@link Vec3} from `this`.
       * Equivalent to `Vec3.subtract(this, this, b);`
       * @category Methods
       *
       * @param b - The vector to subtract from `this`
       * @returns `this`
       */
      subtract(b) {
        this[0] -= b[0];
        this[1] -= b[1];
        this[2] -= b[2];
        return this;
      }
      /**
       * Alias for {@link Vec3.subtract}
       * @category Methods
       */
      sub(b) {
        return this;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Multiplies `this` by a {@link Vec3}.
       * Equivalent to `Vec3.multiply(this, this, b);`
       * @category Methods
       *
       * @param b - The vector to multiply `this` by
       * @returns `this`
       */
      multiply(b) {
        this[0] *= b[0];
        this[1] *= b[1];
        this[2] *= b[2];
        return this;
      }
      /**
       * Alias for {@link Vec3.multiply}
       * @category Methods
       */
      mul(b) {
        return this;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Divides `this` by a {@link Vec3}.
       * Equivalent to `Vec3.divide(this, this, b);`
       * @category Methods
       *
       * @param b - The vector to divide `this` by
       * @returns `this`
       */
      divide(b) {
        this[0] /= b[0];
        this[1] /= b[1];
        this[2] /= b[2];
        return this;
      }
      /**
       * Alias for {@link Vec3.divide}
       * @category Methods
       */
      div(b) {
        return this;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Scales `this` by a scalar number.
       * Equivalent to `Vec3.scale(this, this, b);`
       * @category Methods
       *
       * @param b - Amount to scale `this` by
       * @returns `this`
       */
      scale(b) {
        this[0] *= b;
        this[1] *= b;
        this[2] *= b;
        return this;
      }
      /**
       * Calculates `this` scaled by a scalar value then adds the result to `this`.
       * Equivalent to `Vec3.scaleAndAdd(this, this, b, scale);`
       * @category Methods
       *
       * @param b - The vector to add to `this`
       * @param scale - The amount to scale `b` by before adding
       * @returns `this`
       */
      scaleAndAdd(b, scale2) {
        this[0] += b[0] * scale2;
        this[1] += b[1] * scale2;
        this[2] += b[2] * scale2;
        return this;
      }
      /**
       * Calculates the Euclidean distance between another {@link Vec3} and `this`.
       * Equivalent to `Vec3.distance(this, b);`
       * @category Methods
       *
       * @param b - The vector to calculate the distance to
       * @returns Distance between `this` and `b`
       */
      distance(b) {
        return _Vec3.distance(this, b);
      }
      /**
       * Alias for {@link Vec3.distance}
       * @category Methods
       */
      dist(b) {
        return 0;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Calculates the squared Euclidean distance between another {@link Vec3} and `this`.
       * Equivalent to `Vec3.squaredDistance(this, b);`
       * @category Methods
       *
       * @param b The vector to calculate the squared distance to
       * @returns Squared distance between `this` and `b`
       */
      squaredDistance(b) {
        return _Vec3.squaredDistance(this, b);
      }
      /**
       * Alias for {@link Vec3.squaredDistance}
       * @category Methods
       */
      sqrDist(b) {
        return 0;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Negates the components of `this`.
       * Equivalent to `Vec3.negate(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      negate() {
        this[0] *= -1;
        this[1] *= -1;
        this[2] *= -1;
        return this;
      }
      /**
       * Inverts the components of `this`.
       * Equivalent to `Vec3.inverse(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      invert() {
        this[0] = 1 / this[0];
        this[1] = 1 / this[1];
        this[2] = 1 / this[2];
        return this;
      }
      /**
       * Sets each component of `this` to its absolute value.
       * Equivalent to `Vec3.abs(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      abs() {
        this[0] = Math.abs(this[0]);
        this[1] = Math.abs(this[1]);
        this[2] = Math.abs(this[2]);
        return this;
      }
      /**
       * Calculates the dot product of this and another {@link Vec3}.
       * Equivalent to `Vec3.dot(this, b);`
       * @category Methods
       *
       * @param b - The second operand
       * @returns Dot product of `this` and `b`
       */
      dot(b) {
        return this[0] * b[0] + this[1] * b[1] + this[2] * b[2];
      }
      /**
       * Normalize `this`.
       * Equivalent to `Vec3.normalize(this, this);`
       * @category Methods
       *
       * @returns `this`
       */
      normalize() {
        return _Vec3.normalize(this, this);
      }
      // ===================
      // Static accessors
      // ===================
      /**
       * @category Static
       *
       * @returns The number of bytes in a {@link Vec3}.
       */
      static get BYTE_LENGTH() {
        return 3 * Float32Array.BYTES_PER_ELEMENT;
      }
      // ===================
      // Static methods
      // ===================
      /**
       * Creates a new, empty vec3
       * @category Static
       *
       * @returns a new 3D vector
       */
      static create() {
        return new _Vec3();
      }
      /**
       * Creates a new vec3 initialized with values from an existing vector
       * @category Static
       *
       * @param a - vector to clone
       * @returns a new 3D vector
       */
      static clone(a) {
        return new _Vec3(a);
      }
      /**
       * Calculates the magnitude (length) of a {@link Vec3}
       * @category Static
       *
       * @param a - Vector to calculate magnitude of
       * @returns Magnitude of a
       */
      static magnitude(a) {
        const x = a[0];
        const y = a[1];
        const z = a[2];
        return Math.sqrt(x * x + y * y + z * z);
      }
      /**
       * Alias for {@link Vec3.magnitude}
       * @category Static
       */
      static mag(a) {
        return 0;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Alias for {@link Vec3.magnitude}
       * @category Static
       * @deprecated Use {@link Vec3.magnitude} to avoid conflicts with builtin `length` methods/attribs
       *
       * @param a - vector to calculate length of
       * @returns length of a
       */
      // Length conflicts with Function.length
      static length(a) {
        return 0;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Alias for {@link Vec3.magnitude}
       * @category Static
       * @deprecated Use {@link Vec3.mag}
       */
      static len(a) {
        return 0;
      }
      // eslint-disable-line @typescript-eslint/no-unused-vars
      /**
       * Creates a new vec3 initialized with the given values
       * @category Static
       *
       * @param x - X component
       * @param y - Y component
       * @param z - Z component
       * @returns a new 3D vector
       */
      static fromValues(x, y, z) {
        return new _Vec3(x, y, z);
      }
      /**
       * Copy the values from one vec3 to another
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the source vector
       * @returns `out`
       */
      static copy(out, a) {
        out[0] = a[0];
        out[1] = a[1];
        out[2] = a[2];
        return out;
      }
      /**
       * Set the components of a vec3 to the given values
       * @category Static
       *
       * @param out - the receiving vector
       * @param x - X component
       * @param y - Y component
       * @param z - Z component
       * @returns `out`
       */
      static set(out, x, y, z) {
        out[0] = x;
        out[1] = y;
        out[2] = z;
        return out;
      }
      /**
       * Adds two {@link Vec3}s
       * @category Static
       *
       * @param out - The receiving vector
       * @param a - The first operand
       * @param b - The second operand
       * @returns `out`
       */
      static add(out, a, b) {
        out[0] = a[0] + b[0];
        out[1] = a[1] + b[1];
        out[2] = a[2] + b[2];
        return out;
      }
      /**
       * Subtracts vector b from vector a
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static subtract(out, a, b) {
        out[0] = a[0] - b[0];
        out[1] = a[1] - b[1];
        out[2] = a[2] - b[2];
        return out;
      }
      /**
       * Alias for {@link Vec3.subtract}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static sub(out, a, b) {
        return [0, 0, 0];
      }
      /**
       * Multiplies two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static multiply(out, a, b) {
        out[0] = a[0] * b[0];
        out[1] = a[1] * b[1];
        out[2] = a[2] * b[2];
        return out;
      }
      /**
       * Alias for {@link Vec3.multiply}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static mul(out, a, b) {
        return [0, 0, 0];
      }
      /**
       * Divides two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static divide(out, a, b) {
        out[0] = a[0] / b[0];
        out[1] = a[1] / b[1];
        out[2] = a[2] / b[2];
        return out;
      }
      /**
       * Alias for {@link Vec3.divide}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static div(out, a, b) {
        return [0, 0, 0];
      }
      /**
       * Math.ceil the components of a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to ceil
       * @returns `out`
       */
      static ceil(out, a) {
        out[0] = Math.ceil(a[0]);
        out[1] = Math.ceil(a[1]);
        out[2] = Math.ceil(a[2]);
        return out;
      }
      /**
       * Math.floor the components of a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to floor
       * @returns `out`
       */
      static floor(out, a) {
        out[0] = Math.floor(a[0]);
        out[1] = Math.floor(a[1]);
        out[2] = Math.floor(a[2]);
        return out;
      }
      /**
       * Returns the minimum of two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static min(out, a, b) {
        out[0] = Math.min(a[0], b[0]);
        out[1] = Math.min(a[1], b[1]);
        out[2] = Math.min(a[2], b[2]);
        return out;
      }
      /**
       * Returns the maximum of two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static max(out, a, b) {
        out[0] = Math.max(a[0], b[0]);
        out[1] = Math.max(a[1], b[1]);
        out[2] = Math.max(a[2], b[2]);
        return out;
      }
      /**
       * symmetric round the components of a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to round
       * @returns `out`
       */
      /*
        static round(out: Vec3Like, a: Readonly<Vec3Like>): Vec3Like {
        out[0] = glMatrix.round(a[0]);
        out[1] = glMatrix.round(a[1]);
        out[2] = glMatrix.round(a[2]);
        return out;
      }*/
      /**
       * Scales a vec3 by a scalar number
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the vector to scale
       * @param scale - amount to scale the vector by
       * @returns `out`
       */
      static scale(out, a, scale2) {
        out[0] = a[0] * scale2;
        out[1] = a[1] * scale2;
        out[2] = a[2] * scale2;
        return out;
      }
      /**
       * Adds two vec3's after scaling the second operand by a scalar value
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param scale - the amount to scale b by before adding
       * @returns `out`
       */
      static scaleAndAdd(out, a, b, scale2) {
        out[0] = a[0] + b[0] * scale2;
        out[1] = a[1] + b[1] * scale2;
        out[2] = a[2] + b[2] * scale2;
        return out;
      }
      /**
       * Calculates the Euclidean distance between two vec3's
       * @category Static
       *
       * @param a - the first operand
       * @param b - the second operand
       * @returns distance between a and b
       */
      static distance(a, b) {
        const x = b[0] - a[0];
        const y = b[1] - a[1];
        const z = b[2] - a[2];
        return Math.sqrt(x * x + y * y + z * z);
      }
      /**
       * Alias for {@link Vec3.distance}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static dist(a, b) {
        return 0;
      }
      /**
       * Calculates the squared Euclidean distance between two vec3's
       * @category Static
       *
       * @param a - the first operand
       * @param b - the second operand
       * @returns squared distance between a and b
       */
      static squaredDistance(a, b) {
        const x = b[0] - a[0];
        const y = b[1] - a[1];
        const z = b[2] - a[2];
        return x * x + y * y + z * z;
      }
      /**
       * Alias for {@link Vec3.squaredDistance}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static sqrDist(a, b) {
        return 0;
      }
      /**
       * Calculates the squared length of a vec3
       * @category Static
       *
       * @param a - vector to calculate squared length of
       * @returns squared length of a
       */
      static squaredLength(a) {
        const x = a[0];
        const y = a[1];
        const z = a[2];
        return x * x + y * y + z * z;
      }
      /**
       * Alias for {@link Vec3.squaredLength}
       * @category Static
       */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      static sqrLen(a, b) {
        return 0;
      }
      /**
       * Negates the components of a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to negate
       * @returns `out`
       */
      static negate(out, a) {
        out[0] = -a[0];
        out[1] = -a[1];
        out[2] = -a[2];
        return out;
      }
      /**
       * Returns the inverse of the components of a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to invert
       * @returns `out`
       */
      static inverse(out, a) {
        out[0] = 1 / a[0];
        out[1] = 1 / a[1];
        out[2] = 1 / a[2];
        return out;
      }
      /**
       * Returns the absolute value of the components of a {@link Vec3}
       * @category Static
       *
       * @param out - The receiving vector
       * @param a - Vector to compute the absolute values of
       * @returns `out`
       */
      static abs(out, a) {
        out[0] = Math.abs(a[0]);
        out[1] = Math.abs(a[1]);
        out[2] = Math.abs(a[2]);
        return out;
      }
      /**
       * Normalize a vec3
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - vector to normalize
       * @returns `out`
       */
      static normalize(out, a) {
        const x = a[0];
        const y = a[1];
        const z = a[2];
        let len = x * x + y * y + z * z;
        if (len > 0) {
          len = 1 / Math.sqrt(len);
        }
        out[0] = a[0] * len;
        out[1] = a[1] * len;
        out[2] = a[2] * len;
        return out;
      }
      /**
       * Calculates the dot product of two vec3's
       * @category Static
       *
       * @param a - the first operand
       * @param b - the second operand
       * @returns dot product of a and b
       */
      static dot(a, b) {
        return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
      }
      /**
       * Computes the cross product of two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @returns `out`
       */
      static cross(out, a, b) {
        const ax = a[0], ay = a[1], az = a[2];
        const bx = b[0], by = b[1], bz = b[2];
        out[0] = ay * bz - az * by;
        out[1] = az * bx - ax * bz;
        out[2] = ax * by - ay * bx;
        return out;
      }
      /**
       * Performs a linear interpolation between two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param t - interpolation amount, in the range [0-1], between the two inputs
       * @returns `out`
       */
      static lerp(out, a, b, t) {
        const ax = a[0];
        const ay = a[1];
        const az = a[2];
        out[0] = ax + t * (b[0] - ax);
        out[1] = ay + t * (b[1] - ay);
        out[2] = az + t * (b[2] - az);
        return out;
      }
      /**
       * Performs a spherical linear interpolation between two vec3's
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param t - interpolation amount, in the range [0-1], between the two inputs
       * @returns `out`
       */
      static slerp(out, a, b, t) {
        const angle = Math.acos(Math.min(Math.max(_Vec3.dot(a, b), -1), 1));
        const sinTotal = Math.sin(angle);
        const ratioA = Math.sin((1 - t) * angle) / sinTotal;
        const ratioB = Math.sin(t * angle) / sinTotal;
        out[0] = ratioA * a[0] + ratioB * b[0];
        out[1] = ratioA * a[1] + ratioB * b[1];
        out[2] = ratioA * a[2] + ratioB * b[2];
        return out;
      }
      /**
       * Performs a hermite interpolation with two control points
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param c - the third operand
       * @param d - the fourth operand
       * @param t - interpolation amount, in the range [0-1], between the two inputs
       * @returns `out`
       */
      static hermite(out, a, b, c, d, t) {
        const factorTimes2 = t * t;
        const factor1 = factorTimes2 * (2 * t - 3) + 1;
        const factor2 = factorTimes2 * (t - 2) + t;
        const factor3 = factorTimes2 * (t - 1);
        const factor4 = factorTimes2 * (3 - 2 * t);
        out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
        out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
        out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
        return out;
      }
      /**
       * Performs a bezier interpolation with two control points
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the first operand
       * @param b - the second operand
       * @param c - the third operand
       * @param d - the fourth operand
       * @param t - interpolation amount, in the range [0-1], between the two inputs
       * @returns `out`
       */
      static bezier(out, a, b, c, d, t) {
        const inverseFactor = 1 - t;
        const inverseFactorTimesTwo = inverseFactor * inverseFactor;
        const factorTimes2 = t * t;
        const factor1 = inverseFactorTimesTwo * inverseFactor;
        const factor2 = 3 * t * inverseFactorTimesTwo;
        const factor3 = 3 * factorTimes2 * inverseFactor;
        const factor4 = factorTimes2 * t;
        out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4;
        out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4;
        out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4;
        return out;
      }
      /**
       * Generates a random vector with the given scale
       * @category Static
       *
       * @param out - the receiving vector
       * @param {Number} [scale] Length of the resulting vector. If omitted, a unit vector will be returned
       * @returns `out`
       */
      /*
          static random(out: Vec3Like, scale) {
          scale = scale === undefined ? 1.0 : scale;
      
          let r = glMatrix.RANDOM() * 2.0 * Math.PI;
          let z = glMatrix.RANDOM() * 2.0 - 1.0;
          let zScale = Math.sqrt(1.0 - z * z) * scale;
      
          out[0] = Math.cos(r) * zScale;
          out[1] = Math.sin(r) * zScale;
          out[2] = z * scale;
          return out;
        }*/
      /**
       * Transforms the vec3 with a mat4.
       * 4th vector component is implicitly '1'
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the vector to transform
       * @param m - matrix to transform with
       * @returns `out`
       */
      static transformMat4(out, a, m) {
        const x = a[0], y = a[1], z = a[2];
        const w = m[3] * x + m[7] * y + m[11] * z + m[15] || 1;
        out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
        out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
        out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
        return out;
      }
      /**
       * Transforms the vec3 with a mat3.
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the vector to transform
       * @param m - the 3x3 matrix to transform with
       * @returns `out`
       */
      static transformMat3(out, a, m) {
        const x = a[0], y = a[1], z = a[2];
        out[0] = x * m[0] + y * m[3] + z * m[6];
        out[1] = x * m[1] + y * m[4] + z * m[7];
        out[2] = x * m[2] + y * m[5] + z * m[8];
        return out;
      }
      /**
       * Transforms the vec3 with a quat
       * Can also be used for dual quaternions. (Multiply it with the real part)
       * @category Static
       *
       * @param out - the receiving vector
       * @param a - the vector to transform
       * @param q - quaternion to transform with
       * @returns `out`
       */
      static transformQuat(out, a, q) {
        const qx = q[0];
        const qy = q[1];
        const qz = q[2];
        const w2 = q[3] * 2;
        const x = a[0];
        const y = a[1];
        const z = a[2];
        const uvx = qy * z - qz * y;
        const uvy = qz * x - qx * z;
        const uvz = qx * y - qy * x;
        const uuvx = (qy * uvz - qz * uvy) * 2;
        const uuvy = (qz * uvx - qx * uvz) * 2;
        const uuvz = (qx * uvy - qy * uvx) * 2;
        out[0] = x + uvx * w2 + uuvx;
        out[1] = y + uvy * w2 + uuvy;
        out[2] = z + uvz * w2 + uuvz;
        return out;
      }
      /**
       * Rotate a 3D vector around the x-axis
       * @category Static
       *
       * @param out - The receiving vec3
       * @param a - The vec3 point to rotate
       * @param b - The origin of the rotation
       * @param rad - The angle of rotation in radians
       * @returns `out`
       */
      static rotateX(out, a, b, rad) {
        const by = b[1];
        const bz = b[2];
        const py = a[1] - by;
        const pz = a[2] - bz;
        out[0] = a[0];
        out[1] = py * Math.cos(rad) - pz * Math.sin(rad) + by;
        out[2] = py * Math.sin(rad) + pz * Math.cos(rad) + bz;
        return out;
      }
      /**
       * Rotate a 3D vector around the y-axis
       * @category Static
       *
       * @param out - The receiving vec3
       * @param a - The vec3 point to rotate
       * @param b - The origin of the rotation
       * @param rad - The angle of rotation in radians
       * @returns `out`
       */
      static rotateY(out, a, b, rad) {
        const bx = b[0];
        const bz = b[2];
        const px = a[0] - bx;
        const pz = a[2] - bz;
        out[0] = pz * Math.sin(rad) + px * Math.cos(rad) + bx;
        out[1] = a[1];
        out[2] = pz * Math.cos(rad) - px * Math.sin(rad) + bz;
        return out;
      }
      /**
       * Rotate a 3D vector around the z-axis
       * @category Static
       *
       * @param out - The receiving vec3
       * @param a - The vec3 point to rotate
       * @param b - The origin of the rotation
       * @param rad - The angle of rotation in radians
       * @returns `out`
       */
      static rotateZ(out, a, b, rad) {
        const bx = b[0];
        const by = b[1];
        const px = a[0] - bx;
        const py = a[1] - by;
        out[0] = px * Math.cos(rad) - py * Math.sin(rad) + bx;
        out[1] = px * Math.sin(rad) + py * Math.cos(rad) + by;
        out[2] = b[2];
        return out;
      }
      /**
       * Get the angle between two 3D vectors
       * @category Static
       *
       * @param a - The first operand
       * @param b - The second operand
       * @returns The angle in radians
       */
      static angle(a, b) {
        const ax = a[0];
        const ay = a[1];
        const az = a[2];
        const bx = b[0];
        const by = b[1];
        const bz = b[2];
        const mag = Math.sqrt((ax * ax + ay * ay + az * az) * (bx * bx + by * by + bz * bz));
        const cosine = mag && _Vec3.dot(a, b) / mag;
        return Math.acos(Math.min(Math.max(cosine, -1), 1));
      }
      /**
       * Set the components of a vec3 to zero
       * @category Static
       *
       * @param out - the receiving vector
       * @returns `out`
       */
      static zero(out) {
        out[0] = 0;
        out[1] = 0;
        out[2] = 0;
        return out;
      }
      /**
       * Returns a string representation of a vector
       * @category Static
       *
       * @param a - vector to represent as a string
       * @returns string representation of the vector
       */
      static str(a) {
        return `Vec3(${a.join(", ")})`;
      }
      /**
       * Returns whether the vectors have exactly the same elements in the same position (when compared with ===)
       * @category Static
       *
       * @param a - The first vector.
       * @param b - The second vector.
       * @returns True if the vectors are equal, false otherwise.
       */
      static exactEquals(a, b) {
        return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
      }
      /**
       * Returns whether the vectors have approximately the same elements in the same position.
       * @category Static
       *
       * @param a - The first vector.
       * @param b - The second vector.
       * @returns True if the vectors are equal, false otherwise.
       */
      static equals(a, b) {
        const a0 = a[0];
        const a1 = a[1];
        const a2 = a[2];
        const b0 = b[0];
        const b1 = b[1];
        const b2 = b[2];
        return Math.abs(a0 - b0) <= GLM_EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= GLM_EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= GLM_EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2));
      }
    };
    Vec3.prototype.sub = Vec3.prototype.subtract;
    Vec3.prototype.mul = Vec3.prototype.multiply;
    Vec3.prototype.div = Vec3.prototype.divide;
    Vec3.prototype.dist = Vec3.prototype.distance;
    Vec3.prototype.sqrDist = Vec3.prototype.squaredDistance;
    Vec3.sub = Vec3.subtract;
    Vec3.mul = Vec3.multiply;
    Vec3.div = Vec3.divide;
    Vec3.dist = Vec3.distance;
    Vec3.sqrDist = Vec3.squaredDistance;
    Vec3.sqrLen = Vec3.squaredLength;
    Vec3.mag = Vec3.magnitude;
    Vec3.length = Vec3.magnitude;
    Vec3.len = Vec3.magnitude;
    class StyleParse {
      static #regexPixels = /(\d+)\s*px/;
      /**
       * Parses a pixel string / computed styles. Ex. `100px` returns `100`.
       *
       * @param {string}   value - Value to parse.
       *
       * @returns {number|undefined} The integer component of a pixel string.
       */
      static pixels(value) {
        if (typeof value !== "string") {
          return void 0;
        }
        const isPixels = this.#regexPixels.test(value);
        const number = parseInt(value);
        return isPixels && Number.isFinite(number) ? number : void 0;
      }
      /**
       * Returns the pixel value for `1rem` based on the root document element. You may apply an optional multiplier.
       *
       * @param {number} [multiplier=1] - Optional multiplier to apply to `rem` pixel value; default: 1.
       *
       * @param {object} [options] - Optional parameters.
       *
       * @param {Document} [options.targetDocument=document] The target DOM {@link Document} if different from the main
       *        browser global `document`.
       *
       * @returns {number} The pixel value for `1rem` with or without a multiplier based on the root document element.
       */
      static remPixels(multiplier = 1, { targetDocument = document } = {}) {
        return targetDocument?.documentElement ? multiplier * parseFloat(globalThis.getComputedStyle(targetDocument.documentElement).fontSize) : void 0;
      }
    }
    class TJSStyleManager {
      /** @type {CSSStyleRule} */
      #cssRule;
      /** @type {string} */
      #docKey;
      /** @type {string} */
      #selector;
      /** @type {HTMLStyleElement} */
      #styleElement;
      /** @type {number} */
      #version;
      /**
       *
       * @param {object}   opts - Options.
       *
       * @param {string}   opts.docKey - Required key providing a link to a specific style sheet element.
       *
       * @param {string}   [opts.selector=:root] - Selector element.
       *
       * @param {Document} [opts.document] - Target document to load styles into.
       *
       * @param {number}   [opts.version] - An integer representing the version / level of styles being managed.
       */
      constructor({ docKey, selector = ":root", document: document2 = globalThis.document, version } = {}) {
        if (typeof docKey !== "string") {
          throw new TypeError(`StyleManager error: 'docKey' is not a string.`);
        }
        if (Object.prototype.toString.call(document2) !== "[object HTMLDocument]") {
          throw new TypeError(`TJSStyleManager error: 'document' is not an instance of HTMLDocument.`);
        }
        if (typeof selector !== "string") {
          throw new TypeError(`StyleManager error: 'selector' is not a string.`);
        }
        if (version !== void 0 && !Number.isSafeInteger(version) && version < 1) {
          throw new TypeError(`StyleManager error: 'version' is defined and is not a positive integer >= 1.`);
        }
        this.#selector = selector;
        this.#docKey = docKey;
        this.#version = version;
        if (document2[this.#docKey] === void 0) {
          this.#styleElement = document2.createElement("style");
          document2.head.append(this.#styleElement);
          this.#styleElement._STYLE_MANAGER_VERSION = version;
          this.#styleElement.sheet.insertRule(`${selector} {}`, 0);
          this.#cssRule = this.#styleElement.sheet.cssRules[0];
          document2[docKey] = this.#styleElement;
        } else {
          this.#styleElement = document2[docKey];
          this.#cssRule = this.#styleElement.sheet.cssRules[0];
          if (version) {
            const existingVersion = this.#styleElement._STYLE_MANAGER_VERSION ?? 0;
            if (version > existingVersion) {
              this.#cssRule.style.cssText = "";
            }
          }
        }
      }
      /**
       * @returns {string} Provides an accessor to get the `cssText` for the style sheet.
       */
      get cssText() {
        return this.#cssRule.style.cssText;
      }
      /**
       * @returns {number} Returns the version of this instance.
       */
      get version() {
        return this.#version;
      }
      /**
       * Provides a copy constructor to duplicate an existing TJSStyleManager instance into a new document.
       *
       * Note: This is used to support the `PopOut` module.
       *
       * @param {Document} [document] Target browser document to clone into.
       *
       * @returns {TJSStyleManager} New style manager instance.
       */
      clone(document2 = globalThis.document) {
        const newStyleManager = new TJSStyleManager({
          selector: this.#selector,
          docKey: this.#docKey,
          document: document2,
          version: this.#version
        });
        newStyleManager.#cssRule.style.cssText = this.#cssRule.style.cssText;
        return newStyleManager;
      }
      get() {
        const cssText = this.#cssRule.style.cssText;
        const result = {};
        if (cssText !== "") {
          for (const entry of cssText.split(";")) {
            if (entry !== "") {
              const values = entry.split(":");
              result[values[0].trim()] = values[1];
            }
          }
        }
        return result;
      }
      /**
       * Gets a particular CSS variable.
       *
       * @param {string}   key - CSS variable property key.
       *
       * @returns {string} Returns CSS variable value.
       */
      getProperty(key) {
        if (typeof key !== "string") {
          throw new TypeError(`StyleManager error: 'key' is not a string.`);
        }
        return this.#cssRule.style.getPropertyValue(key);
      }
      /**
       * Set rules by property / value; useful for CSS variables.
       *
       * @param {{ [key: string]: string }}  rules - An object with property / value string pairs to load.
       *
       * @param {boolean}                 [overwrite=true] - When true overwrites any existing values.
       */
      setProperties(rules, overwrite = true) {
        if (!isObject(rules)) {
          throw new TypeError(`StyleManager error: 'rules' is not an object.`);
        }
        if (typeof overwrite !== "boolean") {
          throw new TypeError(`StyleManager error: 'overwrite' is not a boolean.`);
        }
        if (overwrite) {
          for (const [key, value] of Object.entries(rules)) {
            this.#cssRule.style.setProperty(key, value);
          }
        } else {
          for (const [key, value] of Object.entries(rules)) {
            if (this.#cssRule.style.getPropertyValue(key) === "") {
              this.#cssRule.style.setProperty(key, value);
            }
          }
        }
      }
      /**
       * Sets a particular property.
       *
       * @param {string}   key - CSS variable property key.
       *
       * @param {string}   value - CSS variable value.
       *
       * @param {boolean}  [overwrite=true] - Overwrite any existing value.
       */
      setProperty(key, value, overwrite = true) {
        if (typeof key !== "string") {
          throw new TypeError(`StyleManager error: 'key' is not a string.`);
        }
        if (typeof value !== "string") {
          throw new TypeError(`StyleManager error: 'value' is not a string.`);
        }
        if (typeof overwrite !== "boolean") {
          throw new TypeError(`StyleManager error: 'overwrite' is not a boolean.`);
        }
        if (overwrite) {
          this.#cssRule.style.setProperty(key, value);
        } else {
          if (this.#cssRule.style.getPropertyValue(key) === "") {
            this.#cssRule.style.setProperty(key, value);
          }
        }
      }
      /**
       * Removes the property keys specified. If `keys` is an iterable list then all property keys in the list are removed.
       *
       * @param {Iterable<string>} keys - The property keys to remove.
       */
      removeProperties(keys) {
        if (!isIterable(keys)) {
          throw new TypeError(`StyleManager error: 'keys' is not an iterable list.`);
        }
        for (const key of keys) {
          if (typeof key === "string") {
            this.#cssRule.style.removeProperty(key);
          }
        }
      }
      /**
       * Removes a particular CSS variable.
       *
       * @param {string}   key - CSS variable property key.
       *
       * @returns {string} CSS variable value when removed.
       */
      removeProperty(key) {
        if (typeof key !== "string") {
          throw new TypeError(`StyleManager error: 'key' is not a string.`);
        }
        return this.#cssRule.style.removeProperty(key);
      }
    }
    async function nextAnimationFrame(cntr = 1) {
      if (!Number.isInteger(cntr) || cntr < 1) {
        throw new TypeError(`nextAnimationFrame error: 'cntr' must be a positive integer greater than 0.`);
      }
      let currentTime;
      for (; --cntr >= 0; ) {
        currentTime = await new Promise((resolve) => requestAnimationFrame(resolve));
      }
      return currentTime;
    }
    function draggable(node, { position, enabled = true, button = 0, storeDragging = void 0, tween = false, tweenOptions = { duration: 1, ease: "cubicOut" }, hasTargetClassList, ignoreTargetClassList }) {
      if (hasTargetClassList !== void 0 && !isIterable(hasTargetClassList)) {
        throw new TypeError(`'hasTargetClassList' is not iterable.`);
      }
      if (ignoreTargetClassList !== void 0 && !isIterable(ignoreTargetClassList)) {
        throw new TypeError(`'ignoreTargetClassList' is not iterable.`);
      }
      const positionData = { left: 0, top: 0 };
      let actualPosition = position?.position ?? position;
      let initialPosition = null;
      let initialDragPoint = { x: 0, y: 0 };
      let dragging = false;
      let quickTo = actualPosition.animate.quickTo(["top", "left"], tweenOptions);
      const handlers = {
        dragDown: ["pointerdown", onDragPointerDown, false],
        dragMove: ["pointermove", onDragPointerChange, false],
        dragUp: ["pointerup", onDragPointerUp, false]
      };
      function activateListeners() {
        node.addEventListener(...handlers.dragDown);
        node.classList.add("draggable");
      }
      function removeListeners() {
        if (typeof storeDragging?.set === "function") {
          storeDragging.set(false);
        }
        node.removeEventListener(...handlers.dragDown);
        node.removeEventListener(...handlers.dragMove);
        node.removeEventListener(...handlers.dragUp);
        node.classList.remove("draggable");
      }
      if (enabled) {
        activateListeners();
      }
      function onDragPointerDown(event) {
        if (event.button !== button || !event.isPrimary) {
          return;
        }
        if (!actualPosition.enabled) {
          return;
        }
        if (ignoreTargetClassList !== void 0 && A11yHelper.isFocusTarget(event.target)) {
          for (const targetClass of ignoreTargetClassList) {
            if (event.target.classList.contains(targetClass)) {
              return;
            }
          }
        }
        if (hasTargetClassList !== void 0 && A11yHelper.isFocusTarget(event.target)) {
          let foundTarget = false;
          for (const targetClass of hasTargetClassList) {
            if (event.target.classList.contains(targetClass)) {
              foundTarget = true;
              break;
            }
          }
          if (!foundTarget) {
            return;
          }
        }
        event.preventDefault();
        dragging = false;
        initialPosition = actualPosition.get();
        initialDragPoint = { x: event.clientX, y: event.clientY };
        node.addEventListener(...handlers.dragMove);
        node.addEventListener(...handlers.dragUp);
        node.setPointerCapture(event.pointerId);
      }
      function onDragPointerChange(event) {
        if ((event.buttons & 1) === 0) {
          onDragPointerUp(event);
          return;
        }
        if (event.button !== -1 || !event.isPrimary) {
          return;
        }
        event.preventDefault();
        if (!dragging && typeof storeDragging?.set === "function") {
          dragging = true;
          storeDragging.set(true);
        }
        const newLeft = initialPosition?.left + (event.clientX - initialDragPoint.x);
        const newTop = initialPosition?.top + (event.clientY - initialDragPoint.y);
        if (tween) {
          quickTo(newTop, newLeft);
        } else {
          positionData.left = newLeft;
          positionData.top = newTop;
          actualPosition.set(positionData);
        }
      }
      function onDragPointerUp(event) {
        event.preventDefault();
        dragging = false;
        if (typeof storeDragging?.set === "function") {
          storeDragging.set(false);
        }
        node.removeEventListener(...handlers.dragMove);
        node.removeEventListener(...handlers.dragUp);
      }
      return {
        // The default of enabled being true won't automatically add listeners twice.
        update: (options) => {
          if (options.position !== void 0) {
            const newPosition = options.position?.position ?? options.position;
            if (newPosition !== actualPosition) {
              actualPosition = newPosition;
              quickTo = actualPosition.animate.quickTo(["top", "left"], tweenOptions);
            }
          }
          if (typeof options.enabled === "boolean") {
            enabled = options.enabled;
            if (enabled) {
              activateListeners();
            } else {
              removeListeners();
            }
          }
          if (typeof options.button === "number") {
            button = options.button;
          }
          if (typeof options.tween === "boolean") {
            tween = options.tween;
          }
          if (isObject(options.tweenOptions)) {
            tweenOptions = options.tweenOptions;
            quickTo.options(tweenOptions);
          }
          if (options.hasTargetClassList !== void 0) {
            if (!isIterable(options.hasTargetClassList)) {
              throw new TypeError(`'hasTargetClassList' is not iterable.`);
            } else {
              hasTargetClassList = options.hasTargetClassList;
            }
          }
          if (options.ignoreTargetClassList !== void 0) {
            if (!isIterable(options.ignoreTargetClassList)) {
              throw new TypeError(`'ignoreTargetClassList' is not iterable.`);
            } else {
              ignoreTargetClassList = options.ignoreTargetClassList;
            }
          }
        },
        destroy: () => removeListeners()
      };
    }
    class DraggableOptionsStore {
      tween;
      tweenOptions;
      #initialTween;
      /**
       */
      #initialTweenOptions;
      #tween = false;
      /**
       */
      #tweenOptions = { duration: 1, ease: "cubicOut" };
      /**
       * Stores the subscribers.
       */
      #subscribers = [];
      /**
       * @param [opts] - Optional parameters.
       *
       * @param [opts.tween = false] - Tween enabled.
       *
       * @param [opts.tweenOptions] - Quick tween options.
       */
      constructor({ tween = false, tweenOptions } = {}) {
        Object.defineProperty(this, "tween", {
          get: () => {
            return this.#tween;
          },
          set: (newTween) => {
            if (typeof newTween !== "boolean") {
              throw new TypeError(`'tween' is not a boolean.`);
            }
            this.#tween = newTween;
            this.#updateSubscribers();
          },
          enumerable: true
        });
        Object.defineProperty(this, "tweenOptions", {
          get: () => {
            return this.#tweenOptions;
          },
          set: (newTweenOptions) => {
            if (!isObject(newTweenOptions)) {
              throw new TypeError(`'tweenOptions' is not an object.`);
            }
            if (newTweenOptions.duration !== void 0) {
              if (!Number.isFinite(newTweenOptions.duration)) {
                throw new TypeError(`'tweenOptions.duration' is not a finite number.`);
              }
              if (newTweenOptions.duration < 0) {
                this.#tweenOptions.duration = 0;
              } else {
                this.#tweenOptions.duration = newTweenOptions.duration;
              }
            }
            if (newTweenOptions.ease !== void 0) {
              const easeFn = getEasingFunc(newTweenOptions.ease);
              if (typeof easeFn !== "function") {
                throw new TypeError(`'tweenOptions.ease' is not a function or Svelte easing function name.`);
              }
              this.#tweenOptions.ease = newTweenOptions.ease;
            }
            this.#updateSubscribers();
          },
          enumerable: true
        });
        if (tween !== void 0) {
          this.tween = tween;
        }
        if (tweenOptions !== void 0) {
          this.tweenOptions = tweenOptions;
        }
        this.#initialTween = this.#tween;
        this.#initialTweenOptions = Object.assign({}, this.#tweenOptions);
      }
      /**
       * @returns Get tween duration.
       */
      get tweenDuration() {
        return this.#tweenOptions.duration;
      }
      /**
       * @returns Get easing function or easing function name.
       */
      get tweenEase() {
        return this.#tweenOptions.ease;
      }
      /**
       * @param duration - Set tween duration.
       */
      set tweenDuration(duration) {
        if (!Number.isFinite(duration)) {
          throw new TypeError(`'duration' is not a finite number.`);
        }
        if (duration < 0) {
          duration = 0;
        }
        this.#tweenOptions.duration = duration;
        this.#updateSubscribers();
      }
      /**
       * @param ease - Set easing function by name or direct function.
       */
      set tweenEase(ease) {
        const easeFn = getEasingFunc(ease);
        if (typeof easeFn !== "function") {
          throw new TypeError(`'ease' is not a function or Svelte easing function name.`);
        }
        this.#tweenOptions.ease = ease;
        this.#updateSubscribers();
      }
      /**
       * Resets all options data to initial values.
       */
      reset() {
        this.#tween = this.#initialTween;
        this.#tweenOptions = Object.assign({}, this.#initialTweenOptions);
        this.#updateSubscribers();
      }
      /**
       * Resets tween enabled state to initial value.
       */
      resetTween() {
        this.#tween = this.#initialTween;
        this.#updateSubscribers();
      }
      /**
       * Resets tween options to initial values.
       */
      resetTweenOptions() {
        this.#tweenOptions = Object.assign({}, this.#initialTweenOptions);
        this.#updateSubscribers();
      }
      /**
       * Store subscribe method.
       *
       * @param handler - Callback function that is invoked on update / changes. Receives the DraggableOptionsStore
       *        instance.
       *
       * @returns Unsubscribe function.
       */
      subscribe(handler) {
        const currentIdx = this.#subscribers.findIndex((entry) => entry === handler);
        if (currentIdx === -1) {
          this.#subscribers.push(handler);
          handler(this);
        }
        return () => {
          const existingIdx = this.#subscribers.findIndex((entry) => entry === handler);
          if (existingIdx !== -1) {
            this.#subscribers.splice(existingIdx, 1);
          }
        };
      }
      #updateSubscribers() {
        const subscriptions = this.#subscribers;
        if (subscriptions.length > 0) {
          for (let cntr = 0; cntr < subscriptions.length; cntr++) {
            subscriptions[cntr](this);
          }
        }
      }
    }
    draggable.options = (options) => new DraggableOptionsStore(options);
    class AnimationControl {
      /**
       */
      #animationData;
      /**
       */
      #finishedPromise;
      /**
       */
      #willFinish;
      /**
       * Defines a static empty / void animation control.
       */
      static #voidControl = new AnimationControl(null);
      /**
       * Provides a static void / undefined AnimationControl that is automatically resolved.
       */
      static get voidControl() {
        return this.#voidControl;
      }
      /**
       * @param [animationData] - Animation data.
       *
       * @param [willFinish] - Promise that tracks animation finished state.
       */
      constructor(animationData, willFinish = false) {
        this.#animationData = animationData;
        this.#willFinish = willFinish;
        if (isObject(animationData)) {
          animationData.control = this;
        }
      }
      /**
       * Get a promise that resolves when animation is finished.
       *
       * @returns Animation finished Promise.
       */
      get finished() {
        if (!CrossWindow.isPromise(this.#finishedPromise)) {
          this.#finishedPromise = this.#willFinish ? new Promise((resolve) => this.#animationData.resolve = resolve) : Promise.resolve({ cancelled: false });
        }
        return this.#finishedPromise;
      }
      /**
       * Returns whether this animation is currently active / animating.
       *
       * Note: a delayed animation may not be started / active yet. Use {@link AnimationControl.isFinished} to determine
       * if an animation is actually finished.
       *
       * @returns Animation active state.
       */
      get isActive() {
        return this.#animationData?.active ?? false;
      }
      /**
       * Returns whether this animation is completely finished.
       *
       * @returns Animation finished state.
       */
      get isFinished() {
        return this.#animationData?.finished ?? true;
      }
      /**
       * Cancels the animation.
       */
      cancel() {
        const animationData = this.#animationData;
        if (animationData === null || animationData === void 0) {
          return;
        }
        animationData.cancelled = true;
      }
    }
    class AnimationManager {
      /**
       * Cancels all animations except `quickTo` animations.
       */
      static cancelFn = (data) => data?.quickTo !== true;
      /**
       * Cancels all animations.
       */
      static cancelAllFn = () => true;
      /**
       * Defines the options used for {@link TJSPosition.set}.
       */
      static #tjsPositionSetOptions = Object.freeze({ immediateElementUpdate: true });
      /**
       */
      static #activeList = [];
      /**
       * Provides the `this` context for {@link AnimationManager.animate} to be scheduled on rAF.
       */
      static #animateBound = (timeFrame) => this.animate(timeFrame);
      /**
       */
      static #pendingList = [];
      /**
       * Tracks whether a requestAnimationFrame callback is pending via {@link AnimationManager.add};
       */
      static #rafPending = false;
      /**
       * Time of last `rAF` callback.
       */
      static #timeFrame;
      /**
       * Time of `performance.now()` at last `rAF` callback.
       */
      static #timeNow;
      /**
       * @returns Time of last `rAF` callback.
       */
      static get timeFrame() {
        return this.#timeFrame;
      }
      /**
       * @returns Time of `performance.now()` at last `rAF` callback.
       */
      static get timeNow() {
        return this.#timeNow;
      }
      /**
       * Add animation data.
       *
       * @param data -
       */
      static add(data) {
        if (data.cancelled) {
          this.#cleanupData(data);
          return;
        }
        AnimationManager.#pendingList.push(data);
        if (!AnimationManager.#rafPending) {
          AnimationManager.#rafPending = true;
          globalThis.requestAnimationFrame(this.#animateBound);
        }
      }
      /**
       * Manage all animation.
       *
       * @param timeFrame - rAF callback time.
       */
      static animate(timeFrame) {
        AnimationManager.#rafPending = false;
        AnimationManager.#timeNow = globalThis.performance.now();
        AnimationManager.#timeFrame = timeFrame;
        if (AnimationManager.#activeList.length === 0 && AnimationManager.#pendingList.length === 0) {
          return;
        }
        if (AnimationManager.#pendingList.length) {
          for (let cntr = AnimationManager.#pendingList.length; --cntr >= 0; ) {
            const data = AnimationManager.#pendingList[cntr];
            if (data.cancelled || data.el !== void 0 && !data.el.isConnected) {
              AnimationManager.#pendingList.splice(cntr, 1);
              this.#cleanupData(data);
            }
            if (data.active) {
              if (data.transformOrigin) {
                data.position.set({ transformOrigin: data.transformOrigin });
              }
              data.start = AnimationManager.#timeFrame;
              AnimationManager.#pendingList.splice(cntr, 1);
              AnimationManager.#activeList.push(data);
            }
          }
        }
        for (let cntr = AnimationManager.#activeList.length; --cntr >= 0; ) {
          const data = AnimationManager.#activeList[cntr];
          if (data.cancelled || data.el !== void 0 && !data.el.isConnected) {
            AnimationManager.#activeList.splice(cntr, 1);
            this.#cleanupData(data);
            continue;
          }
          data.current = timeFrame - data.start;
          if (data.current >= data.duration) {
            for (let dataCntr = data.keys.length; --dataCntr >= 0; ) {
              const key = data.keys[dataCntr];
              data.newData[key] = data.destination[key];
            }
            data.position.set(data.newData, AnimationManager.#tjsPositionSetOptions);
            AnimationManager.#activeList.splice(cntr, 1);
            this.#cleanupData(data);
            continue;
          }
          const easedTime = data.ease(data.current / data.duration);
          for (let dataCntr = data.keys.length; --dataCntr >= 0; ) {
            const key = data.keys[dataCntr];
            data.newData[key] = data.interpolate(data.initial[key], data.destination[key], easedTime);
          }
          data.position.set(data.newData, AnimationManager.#tjsPositionSetOptions);
        }
        globalThis.requestAnimationFrame(this.#animateBound);
      }
      /**
       * Cancels all animations for given TJSPosition instance.
       *
       * @param position - TJSPosition instance.
       *
       * @param [cancelFn] - An optional function to control cancelling animations.
       */
      static cancel(position, cancelFn = AnimationManager.cancelFn) {
        for (let cntr = AnimationManager.#activeList.length; --cntr >= 0; ) {
          const data = AnimationManager.#activeList[cntr];
          if (data.position === position && cancelFn(data)) {
            AnimationManager.#activeList.splice(cntr, 1);
            data.cancelled = true;
            this.#cleanupData(data);
          }
        }
        for (let cntr = AnimationManager.#pendingList.length; --cntr >= 0; ) {
          const data = AnimationManager.#pendingList[cntr];
          if (data.position === position && cancelFn(data)) {
            AnimationManager.#pendingList.splice(cntr, 1);
            data.cancelled = true;
            this.#cleanupData(data);
          }
        }
      }
      /**
       * Cancels all active and delayed animations.
       */
      static cancelAll() {
        for (let cntr = AnimationManager.#activeList.length; --cntr >= 0; ) {
          const data = AnimationManager.#activeList[cntr];
          data.cancelled = true;
          this.#cleanupData(data);
        }
        for (let cntr = AnimationManager.#pendingList.length; --cntr >= 0; ) {
          const data = AnimationManager.#pendingList[cntr];
          data.cancelled = true;
          this.#cleanupData(data);
        }
        AnimationManager.#activeList.length = 0;
        AnimationManager.#pendingList.length = 0;
      }
      /**
       * @param data - Animation data to cleanup.
       */
      static #cleanupData(data) {
        data.active = false;
        data.finished = true;
        if (data.transformOriginInitial) {
          data.position.set({ transformOrigin: data.transformOriginInitial });
        }
        if (typeof data.cleanup === "function") {
          data.cleanup(data);
        }
        if (typeof data.resolve === "function") {
          data.resolve({ cancelled: data.cancelled });
        }
        if (!data.quickTo) {
          data.cleanup = void 0;
          data.control = void 0;
          data.destination = void 0;
          data.el = void 0;
          data.ease = void 0;
          data.initial = void 0;
          data.interpolate = void 0;
          data.keys = void 0;
          data.newData = void 0;
          data.position = void 0;
          data.resolve = void 0;
        }
      }
      /**
       * Gets all {@link AnimationControl} instances for a given TJSPosition instance.
       *
       * @param position - TJSPosition instance.
       *
       * @returns All scheduled AnimationControl instances for the given TJSPosition instance.
       */
      static getScheduled(position) {
        const results = [];
        for (let cntr = AnimationManager.#activeList.length; --cntr >= 0; ) {
          const data = AnimationManager.#activeList[cntr];
          if (data.position === position && data.control) {
            results.push(data.control);
          }
        }
        for (let cntr = AnimationManager.#pendingList.length; --cntr >= 0; ) {
          const data = AnimationManager.#pendingList[cntr];
          if (data.position === position && data.control) {
            results.push(data.control);
          }
        }
        return results;
      }
      /**
       * Returns the status of any scheduled or pending animations for the given {@link TJSPosition} instance.
       *
       * @param position - TJSPosition instance.
       *
       * @param [options] - Scheduling options.
       *
       * @returns True if scheduled / false if not.
       */
      static isScheduled(position, { active: active2 = true, pending = true } = {}) {
        if (active2) {
          for (let cntr = AnimationManager.#activeList.length; --cntr >= 0; ) {
            if (AnimationManager.#activeList[cntr].position === position) {
              return true;
            }
          }
        }
        if (pending) {
          for (let cntr = AnimationManager.#pendingList.length; --cntr >= 0; ) {
            if (AnimationManager.#pendingList[cntr].position === position) {
              return true;
            }
          }
        }
        return false;
      }
    }
    class TJSPositionData {
      height;
      left;
      maxHeight;
      maxWidth;
      minHeight;
      minWidth;
      rotateX;
      rotateY;
      rotateZ;
      scale;
      top;
      transformOrigin;
      translateX;
      translateY;
      translateZ;
      width;
      zIndex;
      /**
       * @param [opts] - Options.
       *
       * @param [opts.height] -
       *
       * @param [opts.left] -
       *
       * @param [opts.maxHeight] -
       *
       * @param [opts.maxWidth] -
       *
       * @param [opts.minHeight] -
       *
       * @param [opts.minWidth] -
       *
       * @param [opts.rotateX] -
       *
       * @param [opts.rotateY] -
       *
       * @param [opts.rotateZ] -
       *
       * @param [opts.scale] -
       *
       * @param [opts.translateX] -
       *
       * @param [opts.translateY] -
       *
       * @param [opts.translateZ] -
       *
       * @param [opts.top] -
       *
       * @param [opts.transformOrigin] -
       *
       * @param [opts.width] -
       *
       * @param [opts.zIndex] -
       *
       * @param [opts.rotation] - Alias for `rotateZ`.
       */
      constructor({ height = null, left = null, maxHeight = null, maxWidth = null, minHeight = null, minWidth = null, rotateX = null, rotateY = null, rotateZ = null, scale: scale2 = null, translateX = null, translateY = null, translateZ = null, top = null, transformOrigin = null, width: width2 = null, zIndex = null } = {}) {
        this.height = height;
        this.left = left;
        this.maxHeight = maxHeight;
        this.maxWidth = maxWidth;
        this.minHeight = minHeight;
        this.minWidth = minWidth;
        this.rotateX = rotateX;
        this.rotateY = rotateY;
        this.rotateZ = rotateZ;
        this.scale = scale2;
        this.top = top;
        this.transformOrigin = transformOrigin;
        this.translateX = translateX;
        this.translateY = translateY;
        this.translateZ = translateZ;
        this.width = width2;
        this.zIndex = zIndex;
      }
    }
    class TJSPositionDataUtil {
      /**
       * Stores the TJSPositionData properties that can be animated.
       */
      static #animateKeys = Object.freeze(/* @__PURE__ */ new Set([
        // Main keys
        "left",
        "top",
        "maxWidth",
        "maxHeight",
        "minWidth",
        "minHeight",
        "width",
        "height",
        "rotateX",
        "rotateY",
        "rotateZ",
        "scale",
        "translateX",
        "translateY",
        "translateZ",
        "zIndex",
        // Aliases
        "rotation"
      ]));
      /**
       * Stores the TJSPositionData property aliases that can be animated.
       */
      static #animateKeyAliases = Object.freeze(/* @__PURE__ */ new Map([["rotation", "rotateZ"]]));
      /**
       * Provides numeric defaults for all parameters. This is used by {@link TJSPosition.get} to optionally provide
       * numeric defaults.
       */
      static #numericDefaults = Object.freeze({
        // Other keys
        height: 0,
        left: 0,
        maxHeight: null,
        maxWidth: null,
        minHeight: null,
        minWidth: null,
        top: 0,
        transformOrigin: null,
        width: 0,
        zIndex: null,
        rotateX: 0,
        rotateY: 0,
        rotateZ: 0,
        scale: 1,
        translateX: 0,
        translateY: 0,
        translateZ: 0
      });
      /**
       * Convenience to copy from source to target of two TJSPositionData like objects. If a target is not supplied a new
       * {@link TJSPositionData} instance is created.
       *
       * @param source - The source instance to copy from.
       *
       * @param [target] - Target TJSPositionData like object; if one is not provided a new instance is created.
       *
       * @returns The target instance with all TJSPositionData fields.
       */
      static copyData(source, target = new TJSPositionData()) {
        target.height = source.height ?? null;
        target.left = source.left ?? null;
        target.maxHeight = source.maxHeight ?? null;
        target.maxWidth = source.maxWidth ?? null;
        target.minHeight = source.minHeight ?? null;
        target.minWidth = source.minWidth ?? null;
        target.rotateX = source.rotateX ?? null;
        target.rotateY = source.rotateY ?? null;
        target.rotateZ = source.rotateZ ?? null;
        target.scale = source.scale ?? null;
        target.top = source.top ?? null;
        target.transformOrigin = source.transformOrigin ?? null;
        target.translateX = source.translateX ?? null;
        target.translateY = source.translateY ?? null;
        target.translateZ = source.translateZ ?? null;
        target.width = source.width ?? null;
        target.zIndex = source.zIndex ?? null;
        return target;
      }
      /**
       * Returns the non-aliased animation key.
       *
       * @param key - Animation key / possibly aliased key.
       *
       * @returns Actual non-aliased animation key.
       */
      static getAnimationKey(key) {
        return this.#animateKeyAliases.get(key) ?? key;
      }
      /**
       * Queries an object by the given key or otherwise returns any numeric default.
       *
       * @param data - An object to query for the given animation key.
       *
       * @param key - Animation key.
       *
       * @returns Data at key or numeric default.
       */
      static getDataOrDefault(data, key) {
        key = this.#animateKeyAliases.get(key) ?? key;
        return data[key] ?? this.#numericDefaults[key];
      }
      /**
       * Tests if the given key is an animation key.
       *
       * @param key - A potential animation key.
       *
       * @returns Is animation key.
       */
      static isAnimationKey(key) {
        return this.#animateKeys.has(key);
      }
      /**
       * Sets numeric defaults for a {@link TJSPositionData} like object.
       *
       * @param data - A TJSPositionData like object.
       */
      static setNumericDefaults(data) {
        if (data.rotateX === null) {
          data.rotateX = 0;
        }
        if (data.rotateY === null) {
          data.rotateY = 0;
        }
        if (data.rotateZ === null) {
          data.rotateZ = 0;
        }
        if (data.translateX === null) {
          data.translateX = 0;
        }
        if (data.translateY === null) {
          data.translateY = 0;
        }
        if (data.translateZ === null) {
          data.translateZ = 0;
        }
        if (data.scale === null) {
          data.scale = 1;
        }
      }
    }
    class ConvertStringData {
      /**
       * Animation keys for different processing categories.
       */
      static #animKeyTypes = {
        // Animation keys that can be specified in `px` converted to a number.
        numPx: Object.freeze(/* @__PURE__ */ new Set([
          "left",
          "top",
          "maxWidth",
          "maxHeight",
          "minWidth",
          "minHeight",
          "width",
          "height",
          "translateX",
          "translateY",
          "translateZ"
        ])),
        // Animation keys that can be specified in percentage of parent element constraint.
        percentParent: Object.freeze(/* @__PURE__ */ new Set([
          "left",
          "top",
          "maxWidth",
          "maxHeight",
          "minWidth",
          "minHeight",
          "width",
          "height"
        ])),
        // Only rotation animation keys can be specified in `rad` / `turn` converted to a number.
        rotationRadTurn: Object.freeze(/* @__PURE__ */ new Set(["rotateX", "rotateY", "rotateZ", "rotation"]))
      };
      /**
       * Parses string data values. Relative values must start with leading values '+=', '-=', or '*=' followed by a
       * float / numeric value. IE `+=45` or for percentage '+=10%'. Also handles exact percent value such as `10` or
       * `10%`. Percentage values are based on the current value, parent element constraints, or constraints of the type
       * of value like rotation being bound by 360 degrees.
       *
       * @privateRemarks
       * TODO: In the future support more specific CSS unit types.
       */
      static #regexStringData = /^(?<operation>[-+*]=)?(?<value>-?\d*\.?\d+)(?<unit>%|%~|px|rad|turn)?$/;
      /**
       * Stores the results for match groups from `regexStringData`;
       */
      static #matchResults = Object.seal({
        operation: void 0,
        value: 0,
        unit: void 0
      });
      /**
       * Converts any relative string values for animatable keys to actual updates performed against current data.
       *
       * @param data - position data.
       *
       * @param position - The source position data.
       *
       * @param el - Target positioned element.
       *
       * @returns Converted data.
       */
      static process(data, position, el) {
        let parentClientHeight = Number.NaN;
        let parentClientWidth = Number.NaN;
        for (const key in data) {
          if (TJSPositionDataUtil.isAnimationKey(key)) {
            const value = data[key];
            if (typeof value !== "string") {
              continue;
            }
            if (value === "auto" || value === "inherit") {
              continue;
            }
            const animKey = key;
            const regexResults = this.#regexStringData.exec(value);
            let handled = false;
            if (regexResults && regexResults.groups) {
              const results = this.#matchResults;
              results.operation = regexResults.groups.operation;
              results.value = parseFloat(regexResults.groups.value);
              results.unit = regexResults.groups.unit;
              const current = TJSPositionDataUtil.getDataOrDefault(position, key);
              switch (results.unit) {
                case "%": {
                  if (this.#animKeyTypes.percentParent.has(key) && (Number.isNaN(parentClientHeight) || Number.isNaN(parentClientWidth))) {
                    if (el?.parentElement?.isConnected) {
                      parentClientHeight = el.parentElement.clientHeight;
                      parentClientWidth = el.parentElement.clientWidth;
                    } else {
                      parentClientHeight = 0;
                      parentClientWidth = 0;
                      console.warn(`TJSPosition - ConvertStringData warning: could not determine parent constraints for key '${key}' with value '${value}'.`);
                      data[key] = void 0;
                      continue;
                    }
                  }
                  handled = this.#handlePercent(animKey, current, data, results, parentClientHeight, parentClientWidth);
                  break;
                }
                case "%~":
                  handled = this.#handleRelativePercent(animKey, current, data, results);
                  break;
                case "px":
                  handled = this.#animKeyTypes.numPx.has(key) ? this.#applyResultsValue(animKey, current, data, results) : false;
                  break;
                case "rad":
                case "turn":
                  handled = this.#animKeyTypes.rotationRadTurn.has(key) ? this.#handleRotationRadTurn(animKey, current, data, results) : false;
                  break;
                default:
                  handled = this.#applyResultsValue(animKey, current, data, results);
                  break;
              }
            }
            if (!regexResults || !handled) {
              console.warn(`TJSPosition - ConvertStringData warning: malformed key '${key}' with value '${value}'.`);
              data[key] = void 0;
            }
          }
        }
        return data;
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Provides the common update to source data after `results.value` has been converted to the proper value
       * respectively.
       *
       * @param key - Animation key.
       *
       * @param current - Current value
       *
       * @param data - Source data to convert.
       *
       * @param results - Match results.
       *
       * @returns Adjustment successful.
       */
      static #applyResultsValue(key, current, data, results) {
        if (!results.operation) {
          data[key] = results.value;
          return true;
        }
        switch (results.operation) {
          case "-=":
            data[key] = current - results.value;
            break;
          case "+=":
            data[key] = current + results.value;
            break;
          case "*=":
            data[key] = current * results.value;
            break;
          default:
            return false;
        }
        return true;
      }
      /**
       * Handles the `%` unit type where values are adjusted against the parent element client width / height or in the
       * case of rotation the percentage of 360 degrees.
       *
       * @param key - Animation key.
       *
       * @param current - Current value
       *
       * @param data - Source data to convert.
       *
       * @param results - Match results.
       *
       * @param parentClientHeight - Parent element client height.
       *
       * @param parentClientWidth - Parent element client width.
       *
       * @returns Adjustment successful.
       */
      static #handlePercent(key, current, data, results, parentClientHeight, parentClientWidth) {
        switch (key) {
          case "left":
          case "maxWidth":
          case "minWidth":
          case "width":
          case "translateX":
            results.value = parentClientWidth * (results.value / 100);
            break;
          case "top":
          case "maxHeight":
          case "minHeight":
          case "height":
          case "translateY":
            results.value = parentClientHeight * (results.value / 100);
            break;
          case "rotateX":
          case "rotateY":
          case "rotateZ":
          case "rotation":
            results.value = 360 * (results.value / 100);
            break;
          default:
            return false;
        }
        return this.#applyResultsValue(key, current, data, results);
      }
      /**
       * Handles the `%~` unit type where values are adjusted against the current value for the given key.
       *
       * @param key - Animation key.
       *
       * @param current - Current value
       *
       * @param data - Source data to convert.
       *
       * @param results - Match results.
       *
       * @returns Adjustment successful.
       */
      static #handleRelativePercent(key, current, data, results) {
        results.value = results.value / 100;
        if (!results.operation) {
          data[key] = current * results.value;
          return true;
        }
        switch (results.operation) {
          case "-=":
            data[key] = current - current * results.value;
            break;
          case "+=":
            data[key] = current + current * results.value;
            break;
          case "*=":
            data[key] = current * (current * results.value);
            break;
          default:
            return false;
        }
        return true;
      }
      /**
       * Handles the `rad` / `turn` unit types for rotation animation keys.
       *
       * @param key - Animation key.
       *
       * @param current - Current value
       *
       * @param data - Source data to convert.
       *
       * @param results - Match results.
       *
       * @returns Adjustment successful.
       */
      static #handleRotationRadTurn(key, current, data, results) {
        switch (results.unit) {
          case "rad":
            results.value = radToDeg(results.value);
            break;
          case "turn":
            results.value = 360 * results.value;
            break;
        }
        return this.#applyResultsValue(key, current, data, results);
      }
    }
    class TJSTransformData {
      constructor() {
        Object.seal(this);
      }
      /**
       * Stores the calculated bounding rectangle.
       */
      #boundingRect = new DOMRect();
      /**
       * Stores the individual transformed corner points of the window in screen space clockwise from:
       * top left -> top right -> bottom right -> bottom left.
       */
      #corners = [new Vec3(), new Vec3(), new Vec3(), new Vec3()];
      /**
       * Stores the current gl-matrix Mat4 data.
       */
      #mat4 = new Mat4();
      /**
       * Stores the pre-origin & post-origin translations to apply to matrix transforms.
       */
      #originTranslations = [new Mat4(), new Mat4()];
      /**
       * @returns The bounding rectangle.
       */
      get boundingRect() {
        return this.#boundingRect;
      }
      /**
       * @returns The transformed corner points as Vec3 in screen space.
       */
      get corners() {
        return this.#corners;
      }
      /**
       * @returns Returns the CSS style string for the transform matrix.
       */
      get css() {
        return `matrix3d(${this.mat4.join(",")})`;
      }
      /**
       * @returns The transform matrix.
       */
      get mat4() {
        return this.#mat4;
      }
      /**
       * @returns The pre / post translation matrices for origin translation.
       */
      get originTranslations() {
        return this.#originTranslations;
      }
    }
    class NumberGuard {
      constructor() {
      }
      static isFinite(value) {
        return typeof value === "number" && Number.isFinite(value);
      }
      static isFiniteOrNull(value) {
        return value === null || typeof value === "number" && Number.isFinite(value);
      }
    }
    class TJSPositionStyleCache {
      el;
      computed;
      marginLeft;
      marginTop;
      maxHeight;
      maxWidth;
      minHeight;
      minWidth;
      hasWillChange;
      stores;
      resizeObserved;
      constructor() {
        this.el = void 0;
        this.computed = void 0;
        this.marginLeft = void 0;
        this.marginTop = void 0;
        this.maxHeight = void 0;
        this.maxWidth = void 0;
        this.minHeight = void 0;
        this.minWidth = void 0;
        this.hasWillChange = false;
        this.resizeObserved = Object.seal({
          contentHeight: void 0,
          contentWidth: void 0,
          offsetHeight: void 0,
          offsetWidth: void 0
        });
        const storeResizeObserved = writable(this.resizeObserved);
        this.stores = {
          element: writable(this.el),
          resizeContentHeight: propertyStore(storeResizeObserved, "contentHeight"),
          resizeContentWidth: propertyStore(storeResizeObserved, "contentWidth"),
          resizeObserved: storeResizeObserved,
          resizeObservable: writable(false),
          resizeOffsetHeight: propertyStore(storeResizeObserved, "offsetHeight"),
          resizeOffsetWidth: propertyStore(storeResizeObserved, "offsetWidth")
        };
      }
      /**
       * Returns the cached offsetHeight from any attached `resizeObserver` action otherwise gets the offsetHeight from
       * the element directly. The more optimized path is using `resizeObserver` as getting it from the element
       * directly is more expensive and alters the execution order of an animation frame.
       *
       * @returns The element offsetHeight.
       */
      get offsetHeight() {
        if (this.el !== void 0 && A11yHelper.isFocusTarget(this.el)) {
          return this.resizeObserved.offsetHeight !== void 0 ? this.resizeObserved.offsetHeight : this.el.offsetHeight;
        }
        throw new Error(`TJSPositionStyleCache - get offsetHeight error: no element assigned.`);
      }
      /**
       * Returns the cached offsetWidth from any attached `resizeObserver` action otherwise gets the offsetWidth from
       * the element directly. The more optimized path is using `resizeObserver` as getting it from the element
       * directly is more expensive and alters the execution order of an animation frame.
       *
       * @returns The element offsetHeight.
       */
      get offsetWidth() {
        if (this.el !== void 0 && A11yHelper.isFocusTarget(this.el)) {
          return this.resizeObserved.offsetWidth !== void 0 ? this.resizeObserved.offsetWidth : this.el.offsetWidth;
        }
        throw new Error(`TJSPositionStyleCache - get offsetWidth error: no element assigned.`);
      }
      /**
       * @param el -
       *
       * @returns Does element match cached element.
       */
      hasData(el) {
        return this.el === el;
      }
      /**
       * Resets the style cache.
       */
      reset() {
        if (this.el !== void 0 && A11yHelper.isFocusTarget(this.el) && this.el.isConnected && !this.hasWillChange) {
          this.el.style.willChange = "";
        }
        this.el = void 0;
        this.computed = void 0;
        this.marginLeft = void 0;
        this.marginTop = void 0;
        this.maxHeight = void 0;
        this.maxWidth = void 0;
        this.minHeight = void 0;
        this.minWidth = void 0;
        this.hasWillChange = false;
        this.resizeObserved.contentHeight = void 0;
        this.resizeObserved.contentWidth = void 0;
        this.resizeObserved.offsetHeight = void 0;
        this.resizeObserved.offsetWidth = void 0;
        this.stores.element.set(void 0);
      }
      /**
       * Updates the style cache with new data from the given element.
       *
       * @param el - An HTML element.
       */
      update(el) {
        this.el = el;
        this.computed = globalThis.getComputedStyle(el);
        this.marginLeft = StyleParse.pixels(el.style.marginLeft) ?? StyleParse.pixels(this.computed.marginLeft);
        this.marginTop = StyleParse.pixels(el.style.marginTop) ?? StyleParse.pixels(this.computed.marginTop);
        this.maxHeight = StyleParse.pixels(el.style.maxHeight) ?? StyleParse.pixels(this.computed.maxHeight);
        this.maxWidth = StyleParse.pixels(el.style.maxWidth) ?? StyleParse.pixels(this.computed.maxWidth);
        this.minHeight = StyleParse.pixels(el.style.minHeight) ?? StyleParse.pixels(this.computed.minHeight);
        this.minWidth = StyleParse.pixels(el.style.minWidth) ?? StyleParse.pixels(this.computed.minWidth);
        const willChange = el.style.willChange !== "" ? el.style.willChange : this.computed.willChange ?? "";
        this.hasWillChange = willChange !== "" && willChange !== "auto";
        this.stores.element.set(el);
      }
    }
    class TJSTransforms {
      /**
       * Stores transform data.
       */
      #data = {};
      /**
       * Stores the transform keys in the order added.
       */
      #orderList = [];
      /**
       * Defines the keys of TJSPositionData that are transform keys.
       */
      static #transformKeys = Object.freeze([
        "rotateX",
        "rotateY",
        "rotateZ",
        "scale",
        "translateX",
        "translateY",
        "translateZ"
      ]);
      /**
       * Validates that a given key is a transform key.
       *
       * @param key - A potential transform key.
       */
      static #isTransformKey(key) {
        return this.#transformKeys.includes(key);
      }
      /**
       * Defines bitwise keys for transforms used in {@link TJSTransforms.getMat4}.
       */
      static #transformKeysBitwise = Object.freeze({
        rotateX: 1,
        rotateY: 2,
        rotateZ: 4,
        scale: 8,
        translateX: 16,
        translateY: 32,
        translateZ: 64
      });
      /**
       * Defines the default transform origin.
       */
      static #transformOriginDefault = "top left";
      /**
       * Defines the valid transform origins.
       */
      static #transformOrigins = Object.freeze([
        "top left",
        "top center",
        "top right",
        "center left",
        "center",
        "center right",
        "bottom left",
        "bottom center",
        "bottom right"
      ]);
      /**
       * Defines a valid Set of transform origins.
       */
      static #transformOriginsSet = Object.freeze(new Set(this.#transformOrigins));
      // Temporary variables --------------------------------------------------------------------------------------------
      /**
       */
      static #mat4Result = new Mat4();
      /**
       */
      static #mat4Temp = new Mat4();
      /**
       */
      static #vec3Temp = new Vec3();
      /**
       */
      static #vectorScale = [1, 1, 1];
      /**
       */
      static #vectorTranslate = [0, 0, 0];
      /**
       * Returns a list of supported transform origins.
       *
       * @returns The supported transform origin strings.
       */
      static get transformOrigins() {
        return this.#transformOrigins;
      }
      /**
       * Returns whether the given string is a {@link TransformAPI.TransformOrigin}.
       *
       * @param origin - A potential transform origin string.
       *
       * @returns True if origin is a TransformOrigin string.
       */
      static isTransformOrigin(origin) {
        return this.#transformOriginsSet.has(origin);
      }
      /**
       * @returns Whether there are active transforms in local data.
       */
      get isActive() {
        return this.#orderList.length > 0;
      }
      /**
       * @returns Any local rotateX data.
       */
      get rotateX() {
        return this.#data.rotateX;
      }
      /**
       * @returns Any local rotateY data.
       */
      get rotateY() {
        return this.#data.rotateY;
      }
      /**
       * @returns Any local rotateZ data.
       */
      get rotateZ() {
        return this.#data.rotateZ;
      }
      /**
       * @returns Any local rotateZ scale.
       */
      get scale() {
        return this.#data.scale;
      }
      /**
       * @returns Any local translateZ data.
       */
      get translateX() {
        return this.#data.translateX;
      }
      /**
       * @returns Any local translateZ data.
       */
      get translateY() {
        return this.#data.translateY;
      }
      /**
       * @returns Any local translateZ data.
       */
      get translateZ() {
        return this.#data.translateZ;
      }
      /**
       * Sets the local rotateX data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set rotateX(value) {
        if (Number.isFinite(value)) {
          if (this.#data.rotateX === void 0) {
            this.#orderList.push("rotateX");
          }
          this.#data.rotateX = value;
        } else {
          if (this.#data.rotateX !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "rotateX");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.rotateX;
        }
      }
      /**
       * Sets the local rotateY data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set rotateY(value) {
        if (Number.isFinite(value)) {
          if (this.#data.rotateY === void 0) {
            this.#orderList.push("rotateY");
          }
          this.#data.rotateY = value;
        } else {
          if (this.#data.rotateY !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "rotateY");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.rotateY;
        }
      }
      /**
       * Sets the local rotateZ data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set rotateZ(value) {
        if (Number.isFinite(value)) {
          if (this.#data.rotateZ === void 0) {
            this.#orderList.push("rotateZ");
          }
          this.#data.rotateZ = value;
        } else {
          if (this.#data.rotateZ !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "rotateZ");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.rotateZ;
        }
      }
      /**
       * Sets the local scale data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set scale(value) {
        if (Number.isFinite(value)) {
          if (this.#data.scale === void 0) {
            this.#orderList.push("scale");
          }
          this.#data.scale = value;
        } else {
          if (this.#data.scale !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "scale");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.scale;
        }
      }
      /**
       * Sets the local translateX data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set translateX(value) {
        if (Number.isFinite(value)) {
          if (this.#data.translateX === void 0) {
            this.#orderList.push("translateX");
          }
          this.#data.translateX = value;
        } else {
          if (this.#data.translateX !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "translateX");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.translateX;
        }
      }
      /**
       * Sets the local translateY data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set translateY(value) {
        if (Number.isFinite(value)) {
          if (this.#data.translateY === void 0) {
            this.#orderList.push("translateY");
          }
          this.#data.translateY = value;
        } else {
          if (this.#data.translateY !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "translateY");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.translateY;
        }
      }
      /**
       * Sets the local translateZ data if the value is a finite number otherwise removes the local data.
       *
       * @param value - A value to set.
       */
      set translateZ(value) {
        if (Number.isFinite(value)) {
          if (this.#data.translateZ === void 0) {
            this.#orderList.push("translateZ");
          }
          this.#data.translateZ = value;
        } else {
          if (this.#data.translateZ !== void 0) {
            const index = this.#orderList.findIndex((entry) => entry === "translateZ");
            if (index >= 0) {
              this.#orderList.splice(index, 1);
            }
          }
          delete this.#data.translateZ;
        }
      }
      /**
       * Returns the `matrix3d` CSS transform for the given position / transform data.
       *
       * @param [data] - Optional position data otherwise use local stored transform data.
       *
       * @returns The CSS `matrix3d` string.
       */
      getCSS(data = this.#data) {
        return `matrix3d(${this.getMat4(data, TJSTransforms.#mat4Result).join(",")})`;
      }
      /**
       * Returns the `matrix3d` CSS transform for the given position / transform data.
       *
       * @param [data] - Optional position data otherwise use local stored transform data.
       *
       * @returns The CSS `matrix3d` string.
       */
      getCSSOrtho(data = this.#data) {
        return `matrix3d(${this.getMat4Ortho(data, TJSTransforms.#mat4Result).join(",")})`;
      }
      /**
       * Collects all data including a bounding rect, transform matrix, and points array of the given
       * {@link TJSPositionData} instance with the applied local transform data.
       *
       * @param position - The position data to process.
       *
       * @param [output] - Optional TJSTransformData output instance.
       *
       * @param [validationData] - Optional validation data for adjustment parameters.
       *
       * @returns The output TJSTransformData instance.
       */
      getData(position, output = new TJSTransformData(), validationData) {
        const valWidth = validationData?.width ?? 0;
        const valHeight = validationData?.height ?? 0;
        const valOffsetTop = validationData?.offsetTop ?? validationData?.marginTop ?? 0;
        const valOffsetLeft = validationData?.offsetLeft ?? validationData?.marginLeft ?? 0;
        position.top += valOffsetTop;
        position.left += valOffsetLeft;
        const width2 = NumberGuard.isFinite(position.width) ? position.width : valWidth;
        const height = NumberGuard.isFinite(position.height) ? position.height : valHeight;
        const rect = output.corners;
        if (this.hasTransform(position)) {
          rect[0][0] = rect[0][1] = rect[0][2] = 0;
          rect[1][0] = width2;
          rect[1][1] = rect[1][2] = 0;
          rect[2][0] = width2;
          rect[2][1] = height;
          rect[2][2] = 0;
          rect[3][0] = 0;
          rect[3][1] = height;
          rect[3][2] = 0;
          const matrix = this.getMat4(position, output.mat4);
          const translate = TJSTransforms.#getOriginTranslation(position.transformOrigin, width2, height, output.originTranslations);
          if (TJSTransforms.#transformOriginDefault === position.transformOrigin) {
            Vec3.transformMat4(rect[0], rect[0], matrix);
            Vec3.transformMat4(rect[1], rect[1], matrix);
            Vec3.transformMat4(rect[2], rect[2], matrix);
            Vec3.transformMat4(rect[3], rect[3], matrix);
          } else {
            Vec3.transformMat4(rect[0], rect[0], translate[0]);
            Vec3.transformMat4(rect[0], rect[0], matrix);
            Vec3.transformMat4(rect[0], rect[0], translate[1]);
            Vec3.transformMat4(rect[1], rect[1], translate[0]);
            Vec3.transformMat4(rect[1], rect[1], matrix);
            Vec3.transformMat4(rect[1], rect[1], translate[1]);
            Vec3.transformMat4(rect[2], rect[2], translate[0]);
            Vec3.transformMat4(rect[2], rect[2], matrix);
            Vec3.transformMat4(rect[2], rect[2], translate[1]);
            Vec3.transformMat4(rect[3], rect[3], translate[0]);
            Vec3.transformMat4(rect[3], rect[3], matrix);
            Vec3.transformMat4(rect[3], rect[3], translate[1]);
          }
          rect[0][0] = position.left + rect[0][0];
          rect[0][1] = position.top + rect[0][1];
          rect[1][0] = position.left + rect[1][0];
          rect[1][1] = position.top + rect[1][1];
          rect[2][0] = position.left + rect[2][0];
          rect[2][1] = position.top + rect[2][1];
          rect[3][0] = position.left + rect[3][0];
          rect[3][1] = position.top + rect[3][1];
        } else {
          rect[0][0] = position.left;
          rect[0][1] = position.top;
          rect[1][0] = position.left + width2;
          rect[1][1] = position.top;
          rect[2][0] = position.left + width2;
          rect[2][1] = position.top + height;
          rect[3][0] = position.left;
          rect[3][1] = position.top + height;
          Mat4.identity(output.mat4);
        }
        let maxX = Number.MIN_SAFE_INTEGER;
        let maxY = Number.MIN_SAFE_INTEGER;
        let minX = Number.MAX_SAFE_INTEGER;
        let minY = Number.MAX_SAFE_INTEGER;
        for (let cntr = 4; --cntr >= 0; ) {
          if (rect[cntr][0] > maxX) {
            maxX = rect[cntr][0];
          }
          if (rect[cntr][0] < minX) {
            minX = rect[cntr][0];
          }
          if (rect[cntr][1] > maxY) {
            maxY = rect[cntr][1];
          }
          if (rect[cntr][1] < minY) {
            minY = rect[cntr][1];
          }
        }
        const boundingRect = output.boundingRect;
        boundingRect.x = minX;
        boundingRect.y = minY;
        boundingRect.width = maxX - minX;
        boundingRect.height = maxY - minY;
        position.top -= valOffsetTop;
        position.left -= valOffsetLeft;
        return output;
      }
      /**
       * Creates a transform matrix based on local data applied in order it was added.
       *
       * If no data object is provided then the source is the local transform data. If another data object is supplied
       * then the stored local transform order is applied then all remaining transform keys are applied. This allows the
       * construction of a transform matrix in advance of setting local data and is useful in collision detection.
       *
       * @param [data] - TJSPositionData instance or local transform data.
       *
       * @param [output] - The output mat4 instance.
       *
       * @returns Transform matrix.
       */
      getMat4(data = this.#data, output = new Mat4()) {
        const matrix = Mat4.identity(output);
        let seenKeys = 0;
        const orderList = this.#orderList;
        for (let cntr = 0; cntr < orderList.length; cntr++) {
          const key = orderList[cntr];
          switch (key) {
            case "rotateX":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateX;
              Mat4.multiply(matrix, matrix, Mat4.fromXRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
            case "rotateY":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateY;
              Mat4.multiply(matrix, matrix, Mat4.fromYRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
            case "rotateZ":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateZ;
              Mat4.multiply(matrix, matrix, Mat4.fromZRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
            case "scale":
              seenKeys |= TJSTransforms.#transformKeysBitwise.scale;
              TJSTransforms.#vectorScale[0] = TJSTransforms.#vectorScale[1] = data[key] ?? 0;
              Mat4.multiply(matrix, matrix, Mat4.fromScaling(TJSTransforms.#mat4Temp, TJSTransforms.#vectorScale));
              break;
            case "translateX":
              seenKeys |= TJSTransforms.#transformKeysBitwise.translateX;
              TJSTransforms.#vectorTranslate[0] = data.translateX ?? 0;
              TJSTransforms.#vectorTranslate[1] = 0;
              TJSTransforms.#vectorTranslate[2] = 0;
              Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
              break;
            case "translateY":
              seenKeys |= TJSTransforms.#transformKeysBitwise.translateY;
              TJSTransforms.#vectorTranslate[0] = 0;
              TJSTransforms.#vectorTranslate[1] = data.translateY ?? 0;
              TJSTransforms.#vectorTranslate[2] = 0;
              Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
              break;
            case "translateZ":
              seenKeys |= TJSTransforms.#transformKeysBitwise.translateZ;
              TJSTransforms.#vectorTranslate[0] = 0;
              TJSTransforms.#vectorTranslate[1] = 0;
              TJSTransforms.#vectorTranslate[2] = data.translateZ ?? 0;
              Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
              break;
          }
        }
        if (data !== this.#data) {
          for (let cntr = 0; cntr < TJSTransforms.#transformKeys.length; cntr++) {
            const key = TJSTransforms.#transformKeys[cntr];
            if (data[key] === null || (seenKeys & TJSTransforms.#transformKeysBitwise[key]) > 0) {
              continue;
            }
            const value = data[key];
            switch (key) {
              case "rotateX":
                Mat4.multiply(matrix, matrix, Mat4.fromXRotation(TJSTransforms.#mat4Temp, degToRad(value)));
                break;
              case "rotateY":
                Mat4.multiply(matrix, matrix, Mat4.fromYRotation(TJSTransforms.#mat4Temp, degToRad(value)));
                break;
              case "rotateZ":
                Mat4.multiply(matrix, matrix, Mat4.fromZRotation(TJSTransforms.#mat4Temp, degToRad(value)));
                break;
              case "scale":
                TJSTransforms.#vectorScale[0] = TJSTransforms.#vectorScale[1] = value;
                Mat4.multiply(matrix, matrix, Mat4.fromScaling(TJSTransforms.#mat4Temp, TJSTransforms.#vectorScale));
                break;
              case "translateX":
                TJSTransforms.#vectorTranslate[0] = value;
                TJSTransforms.#vectorTranslate[1] = 0;
                TJSTransforms.#vectorTranslate[2] = 0;
                Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
                break;
              case "translateY":
                TJSTransforms.#vectorTranslate[0] = 0;
                TJSTransforms.#vectorTranslate[1] = value;
                TJSTransforms.#vectorTranslate[2] = 0;
                Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
                break;
              case "translateZ":
                TJSTransforms.#vectorTranslate[0] = 0;
                TJSTransforms.#vectorTranslate[1] = 0;
                TJSTransforms.#vectorTranslate[2] = value;
                Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
                break;
            }
          }
        }
        return matrix;
      }
      /**
       * Provides an orthographic enhancement to convert left / top positional data to a translate operation.
       *
       * This transform matrix takes into account that the remaining operations are , but adds any left / top attributes
       * from passed in data to translate X / Y.
       *
       * If no data object is provided then the source is the local transform data. If another data object is supplied
       * then the stored local transform order is applied then all remaining transform keys are applied. This allows the
       * construction of a transform matrix in advance of setting local data and is useful in collision detection.
       *
       * @param [data] - TJSPositionData instance or local transform data.
       *
       * @param [output] - The output mat4 instance.
       *
       * @returns Transform matrix.
       */
      getMat4Ortho(data = this.#data, output = new Mat4()) {
        const matrix = Mat4.identity(output);
        TJSTransforms.#vectorTranslate[0] = (data.left ?? 0) + (data.translateX ?? 0);
        TJSTransforms.#vectorTranslate[1] = (data.top ?? 0) + (data.translateY ?? 0);
        TJSTransforms.#vectorTranslate[2] = data.translateZ ?? 0;
        Mat4.multiply(matrix, matrix, Mat4.fromTranslation(TJSTransforms.#mat4Temp, TJSTransforms.#vectorTranslate));
        if (data.scale !== null && data.scale !== void 0) {
          TJSTransforms.#vectorScale[0] = TJSTransforms.#vectorScale[1] = data.scale;
          Mat4.multiply(matrix, matrix, Mat4.fromScaling(TJSTransforms.#mat4Temp, TJSTransforms.#vectorScale));
        }
        if (data.rotateX === null && data.rotateY === null && data.rotateZ === null) {
          return matrix;
        }
        let seenKeys = 0;
        const orderList = this.#orderList;
        for (let cntr = 0; cntr < orderList.length; cntr++) {
          const key = orderList[cntr];
          switch (key) {
            case "rotateX":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateX;
              Mat4.multiply(matrix, matrix, Mat4.fromXRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
            case "rotateY":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateY;
              Mat4.multiply(matrix, matrix, Mat4.fromYRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
            case "rotateZ":
              seenKeys |= TJSTransforms.#transformKeysBitwise.rotateZ;
              Mat4.multiply(matrix, matrix, Mat4.fromZRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
              break;
          }
        }
        if (data !== this.#data) {
          for (let cntr = 0; cntr < TJSTransforms.#transformKeys.length; cntr++) {
            const key = TJSTransforms.#transformKeys[cntr];
            if (data[key] === null || (seenKeys & TJSTransforms.#transformKeysBitwise[key]) > 0) {
              continue;
            }
            switch (key) {
              case "rotateX":
                Mat4.multiply(matrix, matrix, Mat4.fromXRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
                break;
              case "rotateY":
                Mat4.multiply(matrix, matrix, Mat4.fromYRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
                break;
              case "rotateZ":
                Mat4.multiply(matrix, matrix, Mat4.fromZRotation(TJSTransforms.#mat4Temp, degToRad(data[key] ?? 0)));
                break;
            }
          }
        }
        return matrix;
      }
      /**
       * Tests an object if it contains transform keys and the values are finite numbers.
       *
       * @param data - An object to test for transform data.
       *
       * @returns Whether the given TJSPositionData has transforms.
       */
      hasTransform(data) {
        for (const key of TJSTransforms.#transformKeys) {
          if (Number.isFinite(data[key])) {
            return true;
          }
        }
        return false;
      }
      /**
       * Resets internal data from the given object containing valid transform keys.
       *
       * @param data - An object with transform data.
       */
      reset(data) {
        for (const key in data) {
          if (TJSTransforms.#isTransformKey(key)) {
            const value = data[key];
            if (NumberGuard.isFinite(value)) {
              this.#data[key] = value;
            } else {
              const index = this.#orderList.findIndex((entry) => entry === key);
              if (index >= 0) {
                this.#orderList.splice(index, 1);
              }
              delete this.#data[key];
            }
          }
        }
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Returns the translations necessary to translate a matrix operation based on the `transformOrigin` parameter of the
       * given position instance. The first entry / index 0 is the pre-translation and last entry / index 1 is the post-
       * translation.
       *
       * This method is used internally, but may be useful if you need the origin translation matrices to transform
       * bespoke points based on any `transformOrigin` set in {@link TJSPositionData}.
       *
       * @param transformOrigin - The transform origin attribute from TJSPositionData.
       *
       * @param width - The TJSPositionData width or validation data width when 'auto'.
       *
       * @param height - The TJSPositionData height or validation data height when 'auto'.
       *
       * @param output - Output Mat4 array.
       *
       * @returns Output Mat4 array.
       */
      static #getOriginTranslation(transformOrigin, width2, height, output) {
        const vector = TJSTransforms.#vec3Temp;
        switch (transformOrigin) {
          case "top left":
            vector[0] = vector[1] = 0;
            Mat4.fromTranslation(output[0], vector);
            Mat4.fromTranslation(output[1], vector);
            break;
          case "top center":
            vector[0] = -width2 * 0.5;
            vector[1] = 0;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2 * 0.5;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "top right":
            vector[0] = -width2;
            vector[1] = 0;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "center left":
            vector[0] = 0;
            vector[1] = -height * 0.5;
            Mat4.fromTranslation(output[0], vector);
            vector[1] = height * 0.5;
            Mat4.fromTranslation(output[1], vector);
            break;
          case null:
          case "center":
            vector[0] = -width2 * 0.5;
            vector[1] = -height * 0.5;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2 * 0.5;
            vector[1] = height * 0.5;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "center right":
            vector[0] = -width2;
            vector[1] = -height * 0.5;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2;
            vector[1] = height * 0.5;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "bottom left":
            vector[0] = 0;
            vector[1] = -height;
            Mat4.fromTranslation(output[0], vector);
            vector[1] = height;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "bottom center":
            vector[0] = -width2 * 0.5;
            vector[1] = -height;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2 * 0.5;
            vector[1] = height;
            Mat4.fromTranslation(output[1], vector);
            break;
          case "bottom right":
            vector[0] = -width2;
            vector[1] = -height;
            Mat4.fromTranslation(output[0], vector);
            vector[0] = width2;
            vector[1] = height;
            Mat4.fromTranslation(output[1], vector);
            break;
          default:
            Mat4.identity(output[0]);
            Mat4.identity(output[1]);
            break;
        }
        return output;
      }
    }
    class AnimationScheduler {
      /**
       * Used to copy data from a TJSPosition instance.
       */
      static #data = {};
      static #getEaseOptions = Object.freeze({ default: false });
      /**
       * Adds / schedules an animation w/ the AnimationManager. This contains the final steps common to all tweens.
       *
       * @param position -
       *
       * @param initial -
       *
       * @param destination -
       *
       * @param duration -
       *
       * @param el -
       *
       * @param delay -
       *
       * @param ease -
       *
       * @param [interpolate=lerp] -
       *
       * @param [transformOrigin] -
       *
       * @param [transformOriginInitial] -
       *
       * @param [cleanup] -
       *
       * @returns An AnimationControl instance or null if none created.
       */
      static #addAnimation(position, initial, destination, duration, el, delay, ease, interpolate2 = lerp, transformOrigin, transformOriginInitial, cleanup) {
        TJSPositionDataUtil.setNumericDefaults(initial);
        TJSPositionDataUtil.setNumericDefaults(destination);
        for (const key in initial) {
          if (!Number.isFinite(initial[key])) {
            delete initial[key];
          }
        }
        const keys = Object.keys(initial);
        const newData = Object.assign({}, initial);
        if (keys.length === 0) {
          return null;
        }
        const animationData = {
          active: true,
          cleanup,
          cancelled: false,
          control: void 0,
          current: 0,
          destination,
          duration: duration * 1e3,
          // Internally the AnimationManager works in ms.
          ease,
          el,
          finished: false,
          initial,
          interpolate: interpolate2,
          keys,
          newData,
          position,
          resolve: void 0,
          start: void 0,
          transformOrigin,
          transformOriginInitial,
          quickTo: false
        };
        if (delay > 0) {
          animationData.active = false;
          setTimeout(() => animationData.active = true, delay * 1e3);
        }
        AnimationManager.add(animationData);
        return new AnimationControl(animationData, true);
      }
      /**
       * Provides a tween from given position data to the current position.
       *
       * @param position - The target position instance.
       *
       * @param fromData - The starting position.
       *
       * @param options - Tween options.
       *
       * @param [cleanup] - Custom animation cleanup function.
       *
       * @returns An AnimationControl instance or null if none created.
       */
      static from(position, fromData, options = {}, cleanup) {
        if (!isObject(fromData)) {
          throw new TypeError(`AnimationAPI.from error: 'fromData' is not an object.`);
        }
        const parent = position.parent;
        if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
          return null;
        }
        let { delay = 0, duration = 1, ease = "cubicOut", strategy, transformOrigin } = options;
        if (strategy !== void 0) {
          if (this.#handleStrategy(position, strategy) === null) {
            return null;
          }
        }
        const targetEl = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
        const el = A11yHelper.isFocusTarget(targetEl) && targetEl.isConnected ? targetEl : void 0;
        if (!Number.isFinite(delay) || delay < 0) {
          throw new TypeError(`AnimationScheduler.from error: 'delay' is not a positive number.`);
        }
        if (!Number.isFinite(duration) || duration < 0) {
          throw new TypeError(`AnimationScheduler.from error: 'duration' is not a positive number.`);
        }
        ease = getEasingFunc(ease, this.#getEaseOptions);
        if (typeof ease !== "function") {
          throw new TypeError(`AnimationScheduler.from error: 'ease' is not a function or valid Svelte easing function name.`);
        }
        const initial = {};
        const destination = {};
        position.get(this.#data);
        transformOrigin = TJSTransforms.isTransformOrigin(transformOrigin) ? transformOrigin : void 0;
        const transformOriginInitial = transformOrigin !== void 0 ? this.#data.transformOrigin : void 0;
        for (const key in fromData) {
          const animKey = TJSPositionDataUtil.getAnimationKey(key);
          if (this.#data[animKey] !== void 0 && fromData[key] !== this.#data[animKey]) {
            initial[key] = fromData[key];
            destination[key] = this.#data[animKey];
          }
        }
        ConvertStringData.process(initial, this.#data, el);
        return this.#addAnimation(position, initial, destination, duration, el, delay, ease, lerp, transformOrigin, transformOriginInitial, cleanup);
      }
      /**
       * Provides a tween from given position data to the given position.
       *
       * @param position - The target position instance.
       *
       * @param fromData - The starting position.
       *
       * @param toData - The ending position.
       *
       * @param options - Tween options.
       *
       * @param [cleanup] - Custom animation cleanup function.
       *
       * @returns An AnimationControl instance or null if none created.
       */
      static fromTo(position, fromData, toData, options = {}, cleanup) {
        if (!isObject(fromData)) {
          throw new TypeError(`AnimationScheduler.fromTo error: 'fromData' is not an object.`);
        }
        if (!isObject(toData)) {
          throw new TypeError(`AnimationScheduler.fromTo error: 'toData' is not an object.`);
        }
        const parent = position.parent;
        if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
          return null;
        }
        let { delay = 0, duration = 1, ease = "cubicOut", strategy, transformOrigin } = options;
        if (strategy !== void 0) {
          if (this.#handleStrategy(position, strategy) === null) {
            return null;
          }
        }
        const targetEl = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
        const el = A11yHelper.isFocusTarget(targetEl) && targetEl.isConnected ? targetEl : void 0;
        if (!Number.isFinite(delay) || delay < 0) {
          throw new TypeError(`AnimationScheduler.fromTo error: 'delay' is not a positive number.`);
        }
        if (!Number.isFinite(duration) || duration < 0) {
          throw new TypeError(`AnimationScheduler.fromTo error: 'duration' is not a positive number.`);
        }
        ease = getEasingFunc(ease, this.#getEaseOptions);
        if (typeof ease !== "function") {
          throw new TypeError(`AnimationScheduler.fromTo error: 'ease' is not a function or valid Svelte easing function name.`);
        }
        const initial = {};
        const destination = {};
        position.get(this.#data);
        transformOrigin = TJSTransforms.isTransformOrigin(transformOrigin) ? transformOrigin : void 0;
        const transformOriginInitial = transformOrigin !== void 0 ? this.#data.transformOrigin : void 0;
        for (const key in fromData) {
          if (toData[key] === void 0) {
            console.warn(`AnimationScheduler.fromTo warning: skipping key ('${key}') from 'fromData' as it is missing in 'toData'.`);
            continue;
          }
          const animKey = TJSPositionDataUtil.getAnimationKey(key);
          if (this.#data[animKey] !== void 0) {
            initial[key] = fromData[key];
            destination[key] = toData[key];
          }
        }
        ConvertStringData.process(initial, this.#data, el);
        ConvertStringData.process(destination, this.#data, el);
        return this.#addAnimation(position, initial, destination, duration, el, delay, ease, lerp, transformOrigin, transformOriginInitial, cleanup);
      }
      /**
       * Provides a tween to given position data from the current position.
       *
       * @param position - The target position instance.
       *
       * @param toData - The destination position.
       *
       * @param options - Tween options.
       *
       * @param [cleanup] - Custom animation cleanup function.
       *
       * @returns An AnimationControl instance or null if none created.
       */
      static to(position, toData, options, cleanup) {
        if (!isObject(toData)) {
          throw new TypeError(`AnimationScheduler.to error: 'toData' is not an object.`);
        }
        const parent = position.parent;
        if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
          return null;
        }
        let { delay = 0, duration = 1, ease = "cubicOut", strategy, transformOrigin } = options;
        if (strategy !== void 0) {
          if (this.#handleStrategy(position, strategy) === null) {
            return null;
          }
        }
        const targetEl = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
        const el = A11yHelper.isFocusTarget(targetEl) && targetEl.isConnected ? targetEl : void 0;
        if (!Number.isFinite(delay) || delay < 0) {
          throw new TypeError(`AnimationScheduler.to error: 'delay' is not a positive number.`);
        }
        if (!Number.isFinite(duration) || duration < 0) {
          throw new TypeError(`AnimationScheduler.to error: 'duration' is not a positive number.`);
        }
        ease = getEasingFunc(ease, this.#getEaseOptions);
        if (typeof ease !== "function") {
          throw new TypeError(`AnimationScheduler.to error: 'ease' is not a function or valid Svelte easing function name.`);
        }
        const initial = {};
        const destination = {};
        position.get(this.#data);
        transformOrigin = TJSTransforms.isTransformOrigin(transformOrigin) ? transformOrigin : void 0;
        const transformOriginInitial = transformOrigin !== void 0 ? this.#data.transformOrigin : void 0;
        for (const key in toData) {
          const animKey = TJSPositionDataUtil.getAnimationKey(key);
          if (this.#data[animKey] !== void 0 && toData[key] !== this.#data[animKey]) {
            destination[key] = toData[key];
            initial[key] = this.#data[animKey];
          }
        }
        ConvertStringData.process(destination, this.#data, el);
        return this.#addAnimation(position, initial, destination, duration, el, delay, ease, lerp, transformOrigin, transformOriginInitial, cleanup);
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Handle any defined scheduling strategy allowing existing scheduled animations for the same position instance
       * to be controlled.
       *
       * @param position - The target position instance.
       *
       * @param strategy - A scheduling strategy to apply.
       *
       * @returns Returns null to abort scheduling current animation.
       */
      static #handleStrategy(position, strategy) {
        switch (strategy) {
          case "cancel":
            if (AnimationManager.isScheduled(position)) {
              AnimationManager.cancel(position);
            }
            break;
          case "cancelAll":
            if (AnimationManager.isScheduled(position)) {
              AnimationManager.cancel(position, AnimationManager.cancelAllFn);
            }
            break;
          case "exclusive":
            if (AnimationManager.isScheduled(position)) {
              return null;
            }
            break;
          default:
            console.warn(`AnimationScheduler error: 'strategy' is not 'cancel', 'cancelAll', or 'exclusive'.`);
            return null;
        }
      }
    }
    class AnimationAPIImpl {
      static #getEaseOptions = Object.freeze({ default: false });
      /**
       */
      #data;
      #position;
      /**
       * @param position -
       *
       * @param data -
       */
      constructor(position, data) {
        this.#position = position;
        this.#data = data;
        Object.seal(this);
      }
      /**
       * Returns if there are scheduled animations whether active or pending for this TJSPosition instance.
       *
       * @returns Are there scheduled animations.
       */
      get isScheduled() {
        return AnimationManager.isScheduled(this.#position);
      }
      /**
       * Cancels all animation instances for this TJSPosition instance.
       */
      cancel() {
        AnimationManager.cancel(this.#position, AnimationManager.cancelAllFn);
      }
      /**
       * Returns all currently scheduled AnimationControl instances for this TJSPosition instance.
       *
       * @returns All currently scheduled animation controls for this TJSPosition instance.
       */
      getScheduled() {
        return AnimationManager.getScheduled(this.#position);
      }
      /**
       * Provides a tween from given position data to the current position.
       *
       * @param fromData - The starting position.
       *
       * @param [options] - Optional tween parameters.
       *
       * @returns A control object that can cancel animation and provides a `finished` Promise.
       */
      from(fromData, options) {
        const animationControl = AnimationScheduler.from(this.#position, fromData, options);
        return animationControl ? animationControl : AnimationControl.voidControl;
      }
      /**
       * Provides a tween from given position data to the given position.
       *
       * @param fromData - The starting position.
       *
       * @param toData - The ending position.
       *
       * @param [options] - Optional tween parameters.
       *
       * @returns A control object that can cancel animation and provides a `finished` Promise.
       */
      fromTo(fromData, toData, options) {
        const animationControl = AnimationScheduler.fromTo(this.#position, fromData, toData, options);
        return animationControl ? animationControl : AnimationControl.voidControl;
      }
      /**
       * Provides a tween to given position data from the current position.
       *
       * @param toData - The destination position.
       *
       * @param [options] - Optional tween parameters.
       *
       * @returns A control object that can cancel animation and provides a `finished` Promise.
       */
      to(toData, options) {
        const animationControl = AnimationScheduler.to(this.#position, toData, options);
        return animationControl ? animationControl : AnimationControl.voidControl;
      }
      /**
       * Returns a function that provides an optimized way to constantly update a to-tween.
       *
       * @param keys - The keys for quickTo.
       *
       * @param [options] - Optional quick tween parameters.
       *
       * @returns quick-to tween function.
       */
      quickTo(keys, options = {}) {
        if (!isIterable(keys)) {
          throw new TypeError(`AnimationAPI.quickTo error: 'keys' is not an iterable list.`);
        }
        const parent = this.#position.parent;
        if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
          throw new Error(`AnimationAPI.quickTo error: 'parent' is not positionable.`);
        }
        let { duration = 1, ease = "cubicOut" } = options;
        if (!Number.isFinite(duration) || duration < 0) {
          throw new TypeError(`AnimationAPI.quickTo error: 'duration' is not a positive number.`);
        }
        ease = getEasingFunc(ease, AnimationAPIImpl.#getEaseOptions);
        if (typeof ease !== "function") {
          throw new TypeError(`AnimationAPI.quickTo error: 'ease' is not a function or valid Svelte easing function name.`);
        }
        const initial = {};
        const destination = {};
        const data = this.#data;
        for (const key of keys) {
          if (typeof key !== "string") {
            throw new TypeError(`AnimationAPI.quickTo error: key ('${key}') is not a string.`);
          }
          if (!TJSPositionDataUtil.isAnimationKey(key)) {
            throw new Error(`AnimationAPI.quickTo error: key ('${key}') is not animatable.`);
          }
          const value = TJSPositionDataUtil.getDataOrDefault(data, key);
          if (value !== null) {
            destination[key] = value;
            initial[key] = value;
          }
        }
        const keysArray = [...keys];
        Object.freeze(keysArray);
        const newData = Object.assign({}, initial);
        const animationData = {
          active: true,
          cancelled: false,
          control: void 0,
          current: 0,
          destination,
          duration: duration * 1e3,
          // Internally the AnimationManager works in ms.
          ease,
          el: void 0,
          finished: true,
          // Note: start in finished state to add to AnimationManager on first callback.
          initial,
          interpolate: lerp,
          keys: keysArray,
          newData,
          position: this.#position,
          resolve: void 0,
          start: 0,
          quickTo: true
        };
        const quickToCB = (...args) => {
          const argsLength = args.length;
          if (argsLength === 0) {
            return;
          }
          for (let cntr = keysArray.length; --cntr >= 0; ) {
            const key = keysArray[cntr];
            const animKey = TJSPositionDataUtil.getAnimationKey(key);
            if (data[animKey] !== void 0) {
              initial[key] = data[animKey];
            }
          }
          if (isObject(args[0])) {
            const objData = args[0];
            for (const key in objData) {
              if (destination[key] !== void 0) {
                destination[key] = objData[key];
              }
            }
          } else {
            for (let cntr = 0; cntr < argsLength && cntr < keysArray.length; cntr++) {
              const key = keysArray[cntr];
              if (destination[key] !== void 0) {
                destination[key] = args[cntr];
              }
            }
          }
          TJSPositionDataUtil.setNumericDefaults(initial);
          TJSPositionDataUtil.setNumericDefaults(destination);
          const targetEl = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
          animationData.el = A11yHelper.isFocusTarget(targetEl) && targetEl.isConnected ? targetEl : void 0;
          ConvertStringData.process(destination, data, animationData.el);
          if (animationData.finished) {
            animationData.cancelled = false;
            animationData.finished = false;
            animationData.active = true;
            animationData.current = 0;
            AnimationManager.add(animationData);
          } else {
            const now2 = globalThis.performance.now();
            animationData.cancelled = false;
            animationData.current = 0;
            animationData.start = now2 + (AnimationManager.timeNow - now2);
          }
        };
        Object.defineProperty(quickToCB, "keys", {
          value: keysArray,
          writable: false,
          configurable: false
        });
        Object.defineProperty(quickToCB, "options", {
          value: (optionsCB) => {
            let { duration: duration2, ease: ease2 } = optionsCB;
            if (duration2 !== void 0 && (!Number.isFinite(duration2) || duration2 < 0)) {
              throw new TypeError(`AnimationAPI.quickTo.options error: 'duration' is not a positive number.`);
            }
            ease2 = getEasingFunc(ease2, AnimationAPIImpl.#getEaseOptions);
            if (ease2 !== void 0 && typeof ease2 !== "function") {
              throw new TypeError(`AnimationAPI.quickTo.options error: 'ease' is not a function or valid Svelte easing function name.`);
            }
            if (NumberGuard.isFinite(duration2) && duration2 >= 0) {
              animationData.duration = duration2 * 1e3;
            }
            if (ease2) {
              animationData.ease = ease2;
            }
            return quickToCB;
          },
          writable: false,
          configurable: false
        });
        return quickToCB;
      }
    }
    class AnimationGroupControl {
      /**
       */
      #animationControls;
      /**
       */
      #finishedPromise;
      /**
       * Defines a static empty / void animation control.
       */
      static #voidControl = new AnimationGroupControl(null);
      /**
       * Provides a static void / undefined AnimationGroupControl that is automatically resolved.
       */
      static get voidControl() {
        return this.#voidControl;
      }
      /**
       * @param animationControls - A Set of AnimationControl instances.
       */
      constructor(animationControls) {
        this.#animationControls = animationControls;
      }
      /**
       * Get a promise that resolves when all animations are finished.
       *
       * @returns Finished Promise for all animations.
       */
      get finished() {
        const animationControls = this.#animationControls;
        if (!CrossWindow.isPromise(this.#finishedPromise)) {
          if (animationControls === null || animationControls === void 0 || animationControls.size === 0) {
            this.#finishedPromise = Promise.resolve({ cancelled: false });
          } else {
            const promises = [];
            for (const animationControl of animationControls) {
              promises.push(animationControl.finished);
            }
            this.#finishedPromise = Promise.allSettled(promises).then((results) => {
              const anyCancelled = results.some((result) => result.status === "rejected" || result.status === "fulfilled" && result.value.cancelled);
              return { cancelled: anyCancelled };
            });
          }
        }
        return this.#finishedPromise;
      }
      /**
       * Returns whether there are active animation instances for this group.
       *
       * Note: a delayed animation may not be started / active yet. Use {@link AnimationGroupControl.isFinished} to
       * determine if all animations in the group are finished.
       *
       * @returns Are there active animation instances.
       */
      get isActive() {
        const animationControls = this.#animationControls;
        if (animationControls === null || animationControls === void 0 || animationControls.size === 0) {
          return false;
        }
        for (const animationControl of animationControls) {
          if (animationControl.isActive) {
            return true;
          }
        }
        return false;
      }
      /**
       * Returns whether all animations in the group are finished.
       *
       * @returns Are all animation instances finished.
       */
      get isFinished() {
        const animationControls = this.#animationControls;
        if (animationControls === null || animationControls === void 0 || animationControls.size === 0) {
          return true;
        }
        for (const animationControl of animationControls) {
          if (!animationControl.isFinished) {
            return false;
          }
        }
        return true;
      }
      /**
       * Cancels the all animations.
       */
      cancel() {
        const animationControls = this.#animationControls;
        if (animationControls === null || animationControls === void 0 || animationControls.size === 0) {
          return;
        }
        for (const animationControl of animationControls) {
          animationControl.cancel();
        }
      }
    }
    class AnimationGroupAPIImpl {
      constructor() {
      }
      /**
       * Returns the TJSPosition instance for the possible given positionable by checking the instance by checking for
       * AnimationAPI.
       *
       * @param positionable - Possible position group entry.
       *
       * @returns Returns actual TJSPosition instance.
       */
      static #getPosition(positionable) {
        if (!isObject(positionable)) {
          return null;
        }
        if (positionable.animate instanceof AnimationAPIImpl) {
          return positionable;
        }
        if (positionable.position?.animate instanceof AnimationAPIImpl) {
          return positionable.position;
        }
        return null;
      }
      /**
       * Cancels any animation for given TJSPosition.PositionGroup data.
       *
       * @param positionGroup - The position group to cancel.
       */
      static cancel(positionGroup) {
        if (isIterable(positionGroup)) {
          let index = -1;
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.cancel warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            AnimationManager.cancel(actualPosition);
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.cancel warning: No TJSPosition instance found.`);
            return;
          }
          AnimationManager.cancel(actualPosition);
        }
      }
      /**
       * Cancels all TJSPosition animation.
       */
      static cancelAll() {
        AnimationManager.cancelAll();
      }
      /**
       * Gets all animation controls for the given position group data.
       *
       * @param positionGroup - A position group.
       *
       * @returns Results array.
       */
      static getScheduled(positionGroup) {
        const results = [];
        if (isIterable(positionGroup)) {
          let index = -1;
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.getScheduled warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            const controls = AnimationManager.getScheduled(actualPosition);
            results.push({
              position: actualPosition,
              entry: actualPosition !== entry ? entry : void 0,
              controls
            });
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.getScheduled warning: No TJSPosition instance found.`);
            return results;
          }
          const controls = AnimationManager.getScheduled(actualPosition);
          results.push({
            position: actualPosition,
            entry: actualPosition !== positionGroup ? positionGroup : void 0,
            controls
          });
        }
        return results;
      }
      /**
       * Provides a type guard to test in the given key is an {@link AnimationAPIImpl.AnimationKey}.
       *
       * @param key - A key value to test.
       *
       * @returns Whether the given key is an animation key.
       */
      static isAnimationKey(key) {
        return TJSPositionDataUtil.isAnimationKey(key);
      }
      /**
       * Returns the status _for the entire position group_ specified if all position instances of the group are scheduled.
       *
       * @param positionGroup - A position group.
       *
       * @param [options] - Options.
       *
       * @returns True if all are scheduled / false if just one position instance in the group is not scheduled.
       */
      static isScheduled(positionGroup, options) {
        if (isIterable(positionGroup)) {
          let index = -1;
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.isScheduled warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            if (!AnimationManager.isScheduled(actualPosition, options)) {
              return false;
            }
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.isScheduled warning: No TJSPosition instance found.`);
            return false;
          }
          if (!AnimationManager.isScheduled(actualPosition, options)) {
            return false;
          }
        }
        return true;
      }
      /**
       * Provides the `from` animation tween for one or more positionable instances as a group.
       *
       * @param positionGroup - A position group.
       *
       * @param fromData - A position data object assigned to all positionable instances or a callback function invoked for
       *        unique data for each instance.
       *
       * @param [options] - Tween options assigned to all positionable instances or a callback function invoked for unique
       *        options for each instance.
       *
       * @returns Basic animation control.
       */
      static from(positionGroup, fromData, options) {
        if (!isObject(fromData) && typeof fromData !== "function") {
          throw new TypeError(`AnimationGroupAPI.from error: 'fromData' is not an object or function.`);
        }
        if (options !== void 0 && !isObject(options) && typeof options !== "function") {
          throw new TypeError(`AnimationGroupAPI.from error: 'options' is not an object or function.`);
        }
        const animationControls = /* @__PURE__ */ new Set();
        const cleanupFn = (data) => animationControls.delete(data.control);
        let index = -1;
        let callbackOptions;
        const hasDataCallback = typeof fromData === "function";
        const hasOptionCallback = typeof options === "function";
        const hasCallback = hasDataCallback || hasOptionCallback;
        if (hasCallback) {
          callbackOptions = { index, position: void 0, entry: void 0 };
        }
        let actualFromData = fromData;
        let actualOptions = isObject(options) ? options : void 0;
        if (isIterable(positionGroup)) {
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.from warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            if (hasCallback) {
              callbackOptions.index = index;
              callbackOptions.position = actualPosition;
              callbackOptions.entry = actualPosition !== entry ? entry : void 0;
            }
            if (hasDataCallback && typeof fromData === "function") {
              actualFromData = fromData(callbackOptions);
              if (actualFromData === null || actualFromData === void 0) {
                continue;
              }
              if (!isObject(actualFromData)) {
                throw new TypeError(`AnimationGroupAPI.from error: 'fromData' callback function iteration(${index}) failed to return an object.`);
              }
            }
            if (hasOptionCallback && typeof options === "function") {
              actualOptions = options(callbackOptions);
              if (actualOptions === null || actualOptions === void 0) {
                continue;
              }
              if (!isObject(actualOptions)) {
                throw new TypeError(`AnimationGroupAPI.from error: 'options' callback function iteration(${index}) failed to return an object.`);
              }
            }
            const animationControl = AnimationScheduler.from(actualPosition, actualFromData, actualOptions, cleanupFn);
            if (animationControl) {
              animationControls.add(animationControl);
            }
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.from warning: No TJSPosition instance found.`);
            return AnimationGroupControl.voidControl;
          }
          if (hasCallback) {
            callbackOptions.index = 0;
            callbackOptions.position = actualPosition;
            callbackOptions.entry = actualPosition !== positionGroup ? positionGroup : void 0;
          }
          if (hasDataCallback && typeof fromData === "function") {
            actualFromData = fromData(callbackOptions);
            if (actualFromData === null || actualFromData === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualFromData)) {
              throw new TypeError(`AnimationGroupAPI.from error: 'fromData' callback function failed to return an object.`);
            }
          }
          if (hasOptionCallback && typeof options === "function") {
            actualOptions = options(callbackOptions);
            if (actualOptions === null || actualOptions === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualOptions)) {
              throw new TypeError(`AnimationGroupAPI.from error: 'options' callback function failed to return an object.`);
            }
          }
          const animationControl = AnimationScheduler.from(actualPosition, actualFromData, actualOptions, cleanupFn);
          if (animationControl) {
            animationControls.add(animationControl);
          }
        }
        return new AnimationGroupControl(animationControls);
      }
      /**
       * Provides the `fromTo` animation tween for one or more positionable instances as a group.
       *
       * @param positionGroup - A position group.
       *
       * @param fromData - A position data object assigned to all positionable instances or a callback function invoked for
       *        unique data for each instance.
       *
       * @param toData - A position data object assigned to all positionable instances or a callback function invoked for
       *        unique data for each instance.
       *
       * @param [options] - Tween options assigned to all positionable instances or a callback function invoked for unique
       *        options for each instance.
       *
       * @returns Basic animation control.
       */
      static fromTo(positionGroup, fromData, toData, options) {
        if (!isObject(fromData) && typeof fromData !== "function") {
          throw new TypeError(`AnimationGroupAPI.fromTo error: 'fromData' is not an object or function.`);
        }
        if (!isObject(toData) && typeof toData !== "function") {
          throw new TypeError(`AnimationGroupAPI.fromTo error: 'toData' is not an object or function.`);
        }
        if (options !== void 0 && !isObject(options) && typeof options !== "function") {
          throw new TypeError(`AnimationGroupAPI.fromTo error: 'options' is not an object or function.`);
        }
        const animationControls = /* @__PURE__ */ new Set();
        const cleanupFn = (data) => animationControls.delete(data.control);
        let index = -1;
        let callbackOptions;
        const hasFromCallback = typeof fromData === "function";
        const hasToCallback = typeof toData === "function";
        const hasOptionCallback = typeof options === "function";
        const hasCallback = hasFromCallback || hasToCallback || hasOptionCallback;
        if (hasCallback) {
          callbackOptions = { index, position: void 0, entry: void 0 };
        }
        let actualFromData = fromData;
        let actualToData = toData;
        let actualOptions = isObject(options) ? options : void 0;
        if (isIterable(positionGroup)) {
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.fromTo warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            if (hasCallback) {
              callbackOptions.index = index;
              callbackOptions.position = actualPosition;
              callbackOptions.entry = actualPosition !== entry ? entry : void 0;
            }
            if (hasFromCallback && typeof fromData === "function") {
              actualFromData = fromData(callbackOptions);
              if (actualFromData === null || actualFromData === void 0) {
                continue;
              }
              if (!isObject(actualFromData)) {
                throw new TypeError(`AnimationGroupAPI.fromTo error: 'fromData' callback function iteration(${index}) failed to return an object.`);
              }
            }
            if (hasToCallback && typeof toData === "function") {
              actualToData = toData(callbackOptions);
              if (actualToData === null || actualToData === void 0) {
                continue;
              }
              if (!isObject(actualToData)) {
                throw new TypeError(`AnimationGroupAPI.fromTo error: 'toData' callback function iteration(${index}) failed to return an object.`);
              }
            }
            if (hasOptionCallback && typeof options === "function") {
              actualOptions = options(callbackOptions);
              if (actualOptions === null || actualOptions === void 0) {
                continue;
              }
              if (!isObject(actualOptions)) {
                throw new TypeError(`AnimationGroupAPI.fromTo error: 'options' callback function iteration(${index}) failed to return an object.`);
              }
            }
            const animationControl = AnimationScheduler.fromTo(actualPosition, actualFromData, actualToData, actualOptions, cleanupFn);
            if (animationControl) {
              animationControls.add(animationControl);
            }
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.fromTo warning: No TJSPosition instance found.`);
            return AnimationGroupControl.voidControl;
          }
          if (hasCallback) {
            callbackOptions.index = 0;
            callbackOptions.position = actualPosition;
            callbackOptions.entry = actualPosition !== positionGroup ? positionGroup : void 0;
          }
          if (hasFromCallback && typeof fromData === "function") {
            actualFromData = fromData(callbackOptions);
            if (actualFromData === null || actualFromData === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualFromData)) {
              throw new TypeError(`AnimationGroupAPI.fromTo error: 'fromData' callback function failed to return an object.`);
            }
          }
          if (hasToCallback && typeof toData === "function") {
            actualToData = toData(callbackOptions);
            if (actualToData === null || actualToData === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualToData)) {
              throw new TypeError(`AnimationGroupAPI.fromTo error: 'toData' callback function failed to return an object.`);
            }
          }
          if (hasOptionCallback && typeof options === "function") {
            actualOptions = options(callbackOptions);
            if (actualOptions === null || actualOptions === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualOptions)) {
              throw new TypeError(`AnimationGroupAPI.fromTo error: 'options' callback function failed to return an object.`);
            }
          }
          const animationControl = AnimationScheduler.fromTo(actualPosition, actualFromData, actualToData, actualOptions, cleanupFn);
          if (animationControl) {
            animationControls.add(animationControl);
          }
        }
        return new AnimationGroupControl(animationControls);
      }
      /**
       * Provides the `to` animation tween for one or more positionable instances as a group.
       *
       * @param positionGroup - A position group.
       *
       * @param toData - A position data object assigned to all positionable instances or a callback function invoked for
       *        unique data for each instance.
       *
       * @param [options] - Tween options assigned to all positionable instances or a callback function invoked for unique
       *        options for each instance.
       *
       * @returns Basic animation control.
       */
      static to(positionGroup, toData, options) {
        if (!isObject(toData) && typeof toData !== "function") {
          throw new TypeError(`AnimationGroupAPI.to error: 'toData' is not an object or function.`);
        }
        if (options !== void 0 && !isObject(options) && typeof options !== "function") {
          throw new TypeError(`AnimationGroupAPI.to error: 'options' is not an object or function.`);
        }
        const animationControls = /* @__PURE__ */ new Set();
        const cleanupFn = (data) => animationControls.delete(data.control);
        let index = -1;
        let callbackOptions;
        const hasDataCallback = typeof toData === "function";
        const hasOptionCallback = typeof options === "function";
        const hasCallback = hasDataCallback || hasOptionCallback;
        if (hasCallback) {
          callbackOptions = { index, position: void 0, entry: void 0 };
        }
        let actualToData = toData;
        let actualOptions = isObject(options) ? options : void 0;
        if (isIterable(positionGroup)) {
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.to warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            if (hasCallback) {
              callbackOptions.index = index;
              callbackOptions.position = actualPosition;
              callbackOptions.entry = actualPosition !== entry ? entry : void 0;
            }
            if (hasDataCallback && typeof toData === "function") {
              actualToData = toData(callbackOptions);
              if (actualToData === null || actualToData === void 0) {
                continue;
              }
              if (!isObject(actualToData)) {
                throw new TypeError(`AnimationGroupAPI.to error: 'toData' callback function iteration(${index}) failed to return an object.`);
              }
            }
            if (hasOptionCallback && typeof options === "function") {
              actualOptions = options(callbackOptions);
              if (actualOptions === null || actualOptions === void 0) {
                continue;
              }
              if (!isObject(actualOptions)) {
                throw new TypeError(`AnimationGroupAPI.to error: 'options' callback function iteration(${index}) failed to return an object.`);
              }
            }
            const animationControl = AnimationScheduler.to(actualPosition, actualToData, actualOptions, cleanupFn);
            if (animationControl) {
              animationControls.add(animationControl);
            }
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.to warning: No TJSPosition instance found.`);
            return AnimationGroupControl.voidControl;
          }
          if (hasCallback) {
            callbackOptions.index = 0;
            callbackOptions.position = actualPosition;
            callbackOptions.entry = actualPosition !== positionGroup ? positionGroup : void 0;
          }
          if (hasDataCallback && typeof toData === "function") {
            actualToData = toData(callbackOptions);
            if (actualToData === null || actualToData === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualToData)) {
              throw new TypeError(`AnimationGroupAPI.to error: 'toData' callback function failed to return an object.`);
            }
          }
          if (hasOptionCallback && typeof options === "function") {
            actualOptions = options(callbackOptions);
            if (actualOptions === null || actualOptions === void 0) {
              return AnimationGroupControl.voidControl;
            }
            if (!isObject(actualOptions)) {
              throw new TypeError(`AnimationGroupAPI.to error: 'options' callback function failed to return an object.`);
            }
          }
          const animationControl = AnimationScheduler.to(actualPosition, actualToData, actualOptions, cleanupFn);
          if (animationControl) {
            animationControls.add(animationControl);
          }
        }
        return new AnimationGroupControl(animationControls);
      }
      /**
       * Provides the `quickTo` animation tweening function for one or more positionable instances as a group.
       *
       * @param positionGroup - A position group.
       *
       * @param keys - Animation keys to target.
       *
       * @param [options] - Quick tween options assigned to all positionable instances or a callback function invoked for
       *        unique options for each instance.
       *
       * @returns quick-to tween function.
       */
      static quickTo(positionGroup, keys, options) {
        if (!isIterable(keys)) {
          throw new TypeError(`AnimationGroupAPI.quickTo error: 'keys' is not an iterable list.`);
        }
        if (options !== void 0 && !isObject(options) && typeof options !== "function") {
          throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' is not an object or function.`);
        }
        const quickToCallbacks = [];
        let index = -1;
        const hasOptionCallback = typeof options === "function";
        const callbackOptions = { index, position: void 0, entry: void 0 };
        let actualOptions = isObject(options) ? options : void 0;
        if (isIterable(positionGroup)) {
          for (const entry of positionGroup) {
            index++;
            const actualPosition = this.#getPosition(entry);
            if (!actualPosition) {
              console.warn(`AnimationGroupAPI.quickTo warning: No TJSPosition instance found at index: ${index}.`);
              continue;
            }
            callbackOptions.index = index;
            callbackOptions.position = actualPosition;
            callbackOptions.entry = actualPosition !== entry ? entry : void 0;
            if (hasOptionCallback && typeof options === "function") {
              actualOptions = options(callbackOptions);
              if (actualOptions === null || actualOptions === void 0) {
                continue;
              }
              if (!isObject(actualOptions)) {
                throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' callback function iteration(${index}) failed to return an object.`);
              }
            }
            quickToCallbacks.push(actualPosition.animate.quickTo(keys, actualOptions));
          }
        } else {
          const actualPosition = this.#getPosition(positionGroup);
          if (!actualPosition) {
            console.warn(`AnimationGroupAPI.quickTo warning: No TJSPosition instance found.`);
            return;
          }
          callbackOptions.index = 0;
          callbackOptions.position = actualPosition;
          callbackOptions.entry = actualPosition !== positionGroup ? positionGroup : void 0;
          if (hasOptionCallback && typeof options === "function") {
            actualOptions = options(callbackOptions);
            if (actualOptions === null || actualOptions === void 0) {
              return;
            }
            if (!isObject(actualOptions)) {
              throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' callback function failed to return an object.`);
            }
          }
          quickToCallbacks.push(actualPosition.animate.quickTo(keys, actualOptions));
        }
        const keysArray = [...keys];
        Object.freeze(keysArray);
        const quickToCB = (...args) => {
          const argsLength = args.length;
          if (argsLength === 0) {
            return;
          }
          if (typeof args[0] === "function") {
            const dataCallback = args[0];
            index = -1;
            let cntr = 0;
            if (isIterable(positionGroup)) {
              for (const entry of positionGroup) {
                index++;
                const actualPosition = this.#getPosition(entry);
                if (!actualPosition) {
                  continue;
                }
                callbackOptions.index = index;
                callbackOptions.position = actualPosition;
                callbackOptions.entry = actualPosition !== entry ? entry : void 0;
                const toData = dataCallback(callbackOptions);
                if (toData === null || toData === void 0) {
                  continue;
                }
                const toDataIterable = isIterable(toData);
                if (!Number.isFinite(toData) && !toDataIterable && !isObject(toData)) {
                  throw new TypeError(`AnimationGroupAPI.quickTo error: 'toData' callback function iteration(${index}) failed to return a finite number, iterable list, or object.`);
                }
                if (toDataIterable) {
                  quickToCallbacks[cntr++](...toData);
                } else {
                  quickToCallbacks[cntr++](toData);
                }
              }
            } else {
              const actualPosition = this.#getPosition(positionGroup);
              if (!actualPosition) {
                return;
              }
              callbackOptions.index = 0;
              callbackOptions.position = actualPosition;
              callbackOptions.entry = actualPosition !== positionGroup ? positionGroup : void 0;
              const toData = dataCallback(callbackOptions);
              if (toData === null || toData === void 0) {
                return;
              }
              const toDataIterable = isIterable(toData);
              if (!Number.isFinite(toData) && !toDataIterable && !isObject(toData)) {
                throw new TypeError(`AnimationGroupAPI.quickTo error: 'toData' callback function iteration(${index}) failed to return a finite number, iterable list, or object.`);
              }
              if (toDataIterable) {
                quickToCallbacks[cntr++](...toData);
              } else {
                quickToCallbacks[cntr++](toData);
              }
            }
          } else {
            for (let cntr = quickToCallbacks.length; --cntr >= 0; ) {
              quickToCallbacks[cntr](...args);
            }
          }
        };
        Object.defineProperty(quickToCB, "keys", {
          value: keysArray,
          writable: false,
          configurable: false
        });
        Object.defineProperty(quickToCB, "options", {
          /**
           * Sets options of quickTo tween.
           * @param options -
           */
          value: (options2) => {
            if (options2 !== void 0 && !isObject(options2)) {
              throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' is not an object.`);
            }
            if (isObject(options2)) {
              for (let cntr = quickToCallbacks.length; --cntr >= 0; ) {
                quickToCallbacks[cntr].options(options2);
              }
            }
            return quickToCB;
          },
          writable: false,
          configurable: false
        });
        return quickToCB;
      }
    }
    Object.seal(AnimationGroupAPIImpl);
    class PositionStateAPI {
      /**
       */
      #data;
      /**
       */
      #dataSaved = /* @__PURE__ */ new Map();
      /**
       */
      #position;
      /**
       */
      #transforms;
      constructor(position, data, transforms) {
        this.#position = position;
        this.#data = data;
        this.#transforms = transforms;
        Object.seal(this);
      }
      /**
       * Clears all saved position data except any default state.
       */
      clear() {
        for (const key of this.#dataSaved.keys()) {
          if (key !== "#defaultData") {
            this.#dataSaved.delete(key);
          }
        }
      }
      /**
       * Returns any stored save state by name.
       *
       * @param options - Options.
       *
       * @param options.name - Saved data name.
       *
       * @returns Any saved position data.
       */
      get({ name: name2 }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`TJSPosition - get error: 'name' is not a string.`);
        }
        return this.#dataSaved.get(name2);
      }
      /**
       * Returns any associated default position data.
       *
       * @returns Any saved default position data.
       */
      getDefault() {
        return this.#dataSaved.get("#defaultData");
      }
      /**
       * @returns The saved position data names / keys.
       */
      keys() {
        return this.#dataSaved.keys();
      }
      /**
       * Removes and returns any position data by name.
       *
       * @param options - Options.
       *
       * @param options.name - Name to remove and retrieve.
       *
       * @returns Any saved position data.
       */
      remove({ name: name2 }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`TJSPosition - remove: 'name' is not a string.`);
        }
        const data = this.#dataSaved.get(name2);
        this.#dataSaved.delete(name2);
        return data;
      }
      /**
       * Resets position instance to default data and invokes set.
       *
       * @param [options] - Optional parameters.
       *
       * @param [options.keepZIndex=false] - When true keeps current z-index.
       *
       * @param [options.invokeSet=true] - When true invokes set method.
       *
       * @returns Operation successful.
       */
      reset({ keepZIndex = false, invokeSet = true } = {}) {
        const defaultData = this.#dataSaved.get("#defaultData");
        if (!isObject(defaultData)) {
          return false;
        }
        if (this.#position.animate.isScheduled) {
          this.#position.animate.cancel();
        }
        const zIndex = this.#position.zIndex;
        const data = Object.assign({}, defaultData);
        if (keepZIndex) {
          data.zIndex = zIndex;
        }
        this.#transforms.reset(data);
        const parent = this.#position.parent;
        if (parent?.reactive?.minimized) {
          parent?.maximize?.({ animate: false, duration: 0 });
        }
        if (invokeSet) {
          setTimeout(() => this.#position.set(data), 0);
        }
        return true;
      }
      /**
       * Restores a saved positional state returning the data. Several optional parameters are available to control
       * whether the restore action occurs silently (no store / inline styles updates), animates to the stored data, or
       * simply sets the stored data. Restoring via {@link AnimationAPI.to} allows specification of the duration and
       * easing along with configuring a Promise to be returned if awaiting the end of the animation.
       *
       * @param options - Parameters
       *
       * @param options.name - Saved data set name.
       *
       * @param [options.remove=false] - Deletes data set.
       *
       * @param [options.properties] - Specific properties to set / animate.
       *
       * @param [options.silent] - Set position data directly; no store or style updates.
       *
       * @param [options.async=false] - If animating return a Promise that resolves with any saved data.
       *
       * @param [options.animateTo=false] - Animate to restore data.
       *
       * @param [options.duration=0.1] - Duration in seconds.
       *
       * @param [options.ease='linear'] - Easing function name or function.
       *
       * @returns Any saved position data.
       */
      restore({ name: name2, remove = false, properties, silent = false, async = false, animateTo = false, duration = 0.1, ease = "linear" }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`TJSPosition - restore error: 'name' is not a string.`);
        }
        const dataSaved = this.#dataSaved.get(name2);
        if (dataSaved) {
          if (remove) {
            this.#dataSaved.delete(name2);
          }
          let data = dataSaved;
          if (isIterable(properties)) {
            data = {};
            for (const property of properties) {
              data[property] = dataSaved[property];
            }
          }
          if (silent) {
            for (const property in data) {
              if (property in this.#data) {
                this.#data[property] = data[property];
              }
            }
            return dataSaved;
          } else if (animateTo) {
            if (data.transformOrigin !== this.#position.transformOrigin) {
              this.#position.transformOrigin = data.transformOrigin;
            }
            if (async) {
              return this.#position.animate.to(data, { duration, ease }).finished.then(() => dataSaved);
            } else {
              this.#position.animate.to(data, { duration, ease });
            }
          } else {
            this.#position.set(data);
          }
        }
        return async ? Promise.resolve(dataSaved) : dataSaved;
      }
      /**
       * Saves current position state with the opportunity to add extra data to the saved state. Simply include extra
       * properties in `options` to save extra data.
       *
       * @param options - Options.
       *
       * @param options.name - name to index this saved data.
       *
       * @param [optionsGet] - Additional options for {@link TJSPosition.get} when serializing position state. By default,
       *        `nullable` values are included.
       *
       * @returns Current position data plus any extra data stored.
       */
      save({ name: name2, ...extra }, optionsGet) {
        if (typeof name2 !== "string") {
          throw new TypeError(`TJSPosition - save error: 'name' is not a string.`);
        }
        const data = this.#position.get(extra, optionsGet);
        this.#dataSaved.set(name2, data);
        return data;
      }
      /**
       * Directly sets a saved position state. Simply include extra properties in `options` to set extra data.
       *
       * @param opts - Options.
       *
       * @param opts.name - name to index this saved data.
       */
      set({ name: name2, ...data }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`TJSPosition - set error: 'name' is not a string.`);
        }
        this.#dataSaved.set(name2, data);
      }
    }
    class SystemBase {
      /**
       * When true constrains the min / max width or height to element.
       */
      #constrain;
      /**
       */
      #element;
      /**
       * When true the validator is active.
       */
      #enabled;
      /**
       * Provides a manual setting of the element height. As things go `offsetHeight` causes a browser layout and is not
       * performance oriented. If manually set this height is used instead of `offsetHeight`.
       */
      #height;
      /**
       * Set from an optional value in the constructor to lock accessors preventing modification.
       */
      #lock;
      /**
       * Stores the subscribers.
       */
      #subscribers = [];
      /**
       * Provides a manual setting of the element width. As things go `offsetWidth` causes a browser layout and is not
       * performance oriented. If manually set this width is used instead of `offsetWidth`.
       */
      #width;
      /**
       * @param [options] - Initial options.
       *
       * @param [options.constrain=true] - Initial constrained state.
       *
       * @param [options.element] - Target element.
       *
       * @param [options.enabled=true] - Enabled state.
       *
       * @param [options.lock=false] - Lock parameters from being set.
       *
       * @param [options.width] - Manual width.
       *
       * @param [options.height] - Manual height.
       */
      constructor({ constrain = true, element: element2, enabled = true, lock = false, width: width2, height } = {}) {
        this.#constrain = true;
        this.#enabled = true;
        this.constrain = constrain;
        this.element = element2;
        this.enabled = enabled;
        this.width = width2;
        this.height = height;
        this.#lock = typeof lock === "boolean" ? lock : false;
      }
      /**
       * @returns The current constrain state.
       */
      get constrain() {
        return this.#constrain;
      }
      /**
       * @returns Target element.
       */
      get element() {
        return this.#element;
      }
      /**
       * @returns The current enabled state.
       */
      get enabled() {
        return this.#enabled;
      }
      /**
       * @returns Get manual height.
       */
      get height() {
        return this.#height;
      }
      /**
       * @return Get locked state.
       */
      get locked() {
        return this.#lock;
      }
      /**
       * @returns Get manual width.
       */
      get width() {
        return this.#width;
      }
      /**
       * @param constrain - New constrain state.
       */
      set constrain(constrain) {
        if (this.#lock) {
          return;
        }
        if (typeof constrain !== "boolean") {
          throw new TypeError(`'constrain' is not a boolean.`);
        }
        this.#constrain = constrain;
        this.#updateSubscribers();
      }
      /**
       * @param element - Set target element.
       */
      set element(element2) {
        if (this.#lock) {
          return;
        }
        if (element2 === void 0 || element2 === null || A11yHelper.isFocusTarget(element2)) {
          this.#element = element2;
        } else {
          throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
        }
        this.#updateSubscribers();
      }
      /**
       * @param enabled - New enabled state.
       */
      set enabled(enabled) {
        if (this.#lock) {
          return;
        }
        if (typeof enabled !== "boolean") {
          throw new TypeError(`'enabled' is not a boolean.`);
        }
        this.#enabled = enabled;
        this.#updateSubscribers();
      }
      /**
       * @param height - Set manual height.
       */
      set height(height) {
        if (this.#lock) {
          return;
        }
        if (height === void 0 || Number.isFinite(height)) {
          this.#height = height;
        } else {
          throw new TypeError(`'height' is not a finite number or undefined.`);
        }
        this.#updateSubscribers();
      }
      /**
       * @param width - Set manual width.
       */
      set width(width2) {
        if (this.#lock) {
          return;
        }
        if (width2 === void 0 || Number.isFinite(width2)) {
          this.#width = width2;
        } else {
          throw new TypeError(`'width' is not a finite number or undefined.`);
        }
        this.#updateSubscribers();
      }
      /**
       * Set manual width & height.
       *
       * @param width - New manual width.
       *
       * @param height - New manual height.
       */
      setDimension(width2, height) {
        if (this.#lock) {
          return;
        }
        if (width2 === void 0 || Number.isFinite(width2)) {
          this.#width = width2;
        } else {
          throw new TypeError(`'width' is not a finite number or undefined.`);
        }
        if (height === void 0 || Number.isFinite(height)) {
          this.#height = height;
        } else {
          throw new TypeError(`'height' is not a finite number or undefined.`);
        }
        this.#updateSubscribers();
      }
      /**
       * @param handler - Callback function that is invoked on update / changes. Receives a copy of the TJSPositionData.
       *
       * @returns Unsubscribe function.
       */
      subscribe(handler) {
        const currentIdx = this.#subscribers.findIndex((entry) => entry === handler);
        if (currentIdx === -1) {
          this.#subscribers.push(handler);
          handler(this);
        }
        return () => {
          const existingIdx = this.#subscribers.findIndex((entry) => entry === handler);
          if (existingIdx !== -1) {
            this.#subscribers.splice(existingIdx, 1);
          }
        };
      }
      /**
       * Updates subscribers on changes.
       */
      #updateSubscribers() {
        for (let cntr = 0; cntr < this.#subscribers.length; cntr++) {
          this.#subscribers[cntr](this);
        }
      }
    }
    class Centered extends SystemBase {
      /**
       * Get the left constraint based on any manual target values or the browser inner width.
       *
       * @param width - Target width.
       *
       * @returns Calculated left constraint.
       */
      getLeft(width2) {
        const boundsWidth = this.width ?? this.element?.offsetWidth ?? globalThis.innerWidth;
        return (boundsWidth - width2) / 2;
      }
      /**
       * Get the top constraint based on any manual target values or the browser inner height.
       *
       * @param height - Target height.
       *
       * @returns Calculated top constraint.
       */
      getTop(height) {
        const boundsHeight = this.height ?? this.element?.offsetHeight ?? globalThis.innerHeight;
        return (boundsHeight - height) / 2;
      }
    }
    class AdapterValidators {
      /**
       */
      #enabled = true;
      /**
       */
      #validatorData;
      /**
       */
      #mapUnsubscribe = /* @__PURE__ */ new Map();
      #updateFn;
      /**
       * @returns Returns this and internal storage for validator adapter.
       */
      static create(updateFn) {
        const validatorAPI = new AdapterValidators(updateFn);
        return [validatorAPI, validatorAPI.#validatorData];
      }
      /**
       */
      constructor(updateFn) {
        this.#validatorData = [];
        this.#updateFn = updateFn;
        Object.seal(this);
      }
      /**
       * @returns Returns the enabled state.
       */
      get enabled() {
        return this.#enabled;
      }
      /**
       * @returns Returns the length of the validators array.
       */
      get length() {
        return this.#validatorData.length;
      }
      /**
       * @param enabled - Sets enabled state.
       */
      set enabled(enabled) {
        if (typeof enabled !== "boolean") {
          throw new TypeError(`'enabled' is not a boolean.`);
        }
        this.#enabled = enabled;
      }
      /**
       * Provides an iterator for validators.
       *
       * @returns iterator.
       */
      *[Symbol.iterator]() {
        if (this.#validatorData.length === 0) {
          return;
        }
        for (const entry of this.#validatorData) {
          yield { ...entry };
        }
      }
      /**
       * Adds the given validators.
       *
       * @param validators - Validators to add.
       */
      add(...validators) {
        let subscribeCount = 0;
        for (const validator of validators) {
          const validatorType = typeof validator;
          if (validatorType !== "function" && validatorType !== "object" || validator === null) {
            throw new TypeError(`AdapterValidator error: 'validator' is not a function or object.`);
          }
          let data = void 0;
          let subscribeFn = void 0;
          switch (validatorType) {
            case "function":
              data = {
                id: void 0,
                validate: validator,
                weight: 1
              };
              subscribeFn = validator.subscribe;
              break;
            case "object":
              if ("validate" in validator) {
                if (typeof validator.validate !== "function") {
                  throw new TypeError(`AdapterValidator error: 'validate' attribute is not a function.`);
                }
                if (validator.weight !== void 0 && typeof validator.weight !== "number" || (validator?.weight < 0 || validator?.weight > 1)) {
                  throw new TypeError(`AdapterValidator error: 'weight' attribute is not a number between '0 - 1' inclusive.`);
                }
                data = {
                  id: validator.id !== void 0 ? validator.id : void 0,
                  validate: validator.validate.bind(validator),
                  weight: validator.weight || 1
                };
                subscribeFn = validator.validate.subscribe ?? validator.subscribe;
              } else {
                throw new TypeError(`AdapterValidator error: 'validate' attribute is not a function.`);
              }
              break;
          }
          const index = this.#validatorData.findIndex((value) => data.weight < value.weight);
          if (index >= 0) {
            this.#validatorData.splice(index, 0, data);
          } else {
            this.#validatorData.push(data);
          }
          if (typeof subscribeFn === "function") {
            const unsubscribe = subscribeFn.call(validator, this.#updateFn);
            if (typeof unsubscribe !== "function") {
              throw new TypeError("AdapterValidator error: Validator has subscribe function, but no unsubscribe function is returned.");
            }
            if (this.#mapUnsubscribe.has(data.validate)) {
              throw new Error("AdapterValidator error: Validator added already has an unsubscribe function registered.");
            }
            this.#mapUnsubscribe.set(data.validate, unsubscribe);
            subscribeCount++;
          }
        }
        if (subscribeCount < validators.length) {
          this.#updateFn();
        }
      }
      /**
       * Clears / removes all validators.
       */
      clear() {
        this.#validatorData.length = 0;
        for (const unsubscribe of this.#mapUnsubscribe.values()) {
          unsubscribe();
        }
        this.#mapUnsubscribe.clear();
        this.#updateFn();
      }
      /**
       * Removes one or more given validators.
       *
       * @param validators - Validators to remove.
       */
      remove(...validators) {
        const length = this.#validatorData.length;
        if (length === 0) {
          return;
        }
        for (const data of validators) {
          const actualValidator = typeof data === "function" ? data : isObject(data) ? data.validate : void 0;
          if (!actualValidator) {
            continue;
          }
          for (let cntr = this.#validatorData.length; --cntr >= 0; ) {
            if (this.#validatorData[cntr].validate === actualValidator) {
              this.#validatorData.splice(cntr, 1);
              let unsubscribe = void 0;
              if (typeof (unsubscribe = this.#mapUnsubscribe.get(actualValidator)) === "function") {
                unsubscribe();
                this.#mapUnsubscribe.delete(actualValidator);
              }
            }
          }
        }
        if (length !== this.#validatorData.length) {
          this.#updateFn();
        }
      }
      /**
       * Remove validators by the provided callback. The callback takes 3 parameters: `id`, `validator`, and `weight`.
       * Any truthy value returned will remove that validator.
       *
       * @param callback - Callback function to evaluate each validator entry.
       */
      removeBy(callback) {
        const length = this.#validatorData.length;
        if (length === 0) {
          return;
        }
        if (typeof callback !== "function") {
          throw new TypeError(`AdapterValidator error: 'callback' is not a function.`);
        }
        this.#validatorData = this.#validatorData.filter((data) => {
          const remove = callback.call(callback, { ...data });
          if (remove) {
            let unsubscribe;
            if (typeof (unsubscribe = this.#mapUnsubscribe.get(data.validate)) === "function") {
              unsubscribe();
              this.#mapUnsubscribe.delete(data.validate);
            }
          }
          return !remove;
        });
        if (length !== this.#validatorData.length) {
          this.#updateFn();
        }
      }
      /**
       * Removes any validators with matching IDs.
       *
       * @param ids - IDs to remove.
       */
      removeById(...ids) {
        const length = this.#validatorData.length;
        if (length === 0) {
          return;
        }
        this.#validatorData = this.#validatorData.filter((data) => {
          let remove = false;
          for (const id of ids) {
            remove ||= data.id === id;
          }
          if (remove) {
            let unsubscribe;
            if (typeof (unsubscribe = this.#mapUnsubscribe.get(data.validate)) === "function") {
              unsubscribe();
              this.#mapUnsubscribe.delete(data.validate);
            }
          }
          return !remove;
        });
        if (length !== this.#validatorData.length) {
          this.#updateFn();
        }
      }
    }
    class TransformBounds extends SystemBase {
      static #TRANSFORM_DATA = new TJSTransformData();
      /**
       * Provides a validator that respects transforms in positional data constraining the position to within the target
       * elements bounds.
       *
       * @param valData - The associated validation data for position updates.
       *
       * @returns Potentially adjusted position data.
       */
      validate(valData) {
        if (!this.enabled) {
          return valData.position;
        }
        const boundsWidth = this.width ?? this.element?.offsetWidth ?? globalThis.innerWidth;
        const boundsHeight = this.height ?? this.element?.offsetHeight ?? globalThis.innerHeight;
        if (typeof valData.position.width === "number") {
          const maxW = valData.maxWidth ?? (this.constrain ? boundsWidth : Number.MAX_SAFE_INTEGER);
          valData.position.width = clamp(valData.width, valData.minWidth, maxW);
        }
        if (typeof valData.position.height === "number") {
          const maxH = valData.maxHeight ?? (this.constrain ? boundsHeight : Number.MAX_SAFE_INTEGER);
          valData.position.height = clamp(valData.height, valData.minHeight, maxH);
        }
        const data = valData.transforms.getData(valData.position, TransformBounds.#TRANSFORM_DATA, valData);
        const initialX = data.boundingRect.x;
        const initialY = data.boundingRect.y;
        const marginTop = valData.marginTop ?? 0;
        const marginLeft = valData.marginLeft ?? 0;
        if (data.boundingRect.bottom + marginTop > boundsHeight) {
          data.boundingRect.y += boundsHeight - data.boundingRect.bottom - marginTop;
        }
        if (data.boundingRect.right + marginLeft > boundsWidth) {
          data.boundingRect.x += boundsWidth - data.boundingRect.right - marginLeft;
        }
        if (data.boundingRect.top - marginTop < 0) {
          data.boundingRect.y += Math.abs(data.boundingRect.top - marginTop);
        }
        if (data.boundingRect.left - marginLeft < 0) {
          data.boundingRect.x += Math.abs(data.boundingRect.left - marginLeft);
        }
        valData.position.left -= initialX - data.boundingRect.x;
        valData.position.top -= initialY - data.boundingRect.y;
        return valData.position;
      }
    }
    class PositionChangeSet {
      left;
      top;
      width;
      height;
      maxHeight;
      maxWidth;
      minHeight;
      minWidth;
      zIndex;
      transform;
      transformOrigin;
      constructor() {
        this.left = false;
        this.top = false;
        this.width = false;
        this.height = false;
        this.maxHeight = false;
        this.maxWidth = false;
        this.minHeight = false;
        this.minWidth = false;
        this.zIndex = false;
        this.transform = false;
        this.transformOrigin = false;
      }
      hasChange() {
        return this.left || this.top || this.width || this.height || this.maxHeight || this.maxWidth || this.minHeight || this.minWidth || this.zIndex || this.transform || this.transformOrigin;
      }
      set(value) {
        this.left = value;
        this.top = value;
        this.width = value;
        this.height = value;
        this.maxHeight = value;
        this.maxWidth = value;
        this.minHeight = value;
        this.minWidth = value;
        this.zIndex = value;
        this.transform = value;
        this.transformOrigin = value;
      }
    }
    class UpdateElementData {
      changeSet;
      data;
      dataSubscribers;
      dimensionData;
      options;
      queued;
      storeDimension;
      storeTransform;
      styleCache;
      subscribers;
      transforms;
      transformData;
      constructor(changeSet, data, options, styleCache, subscribers, transforms) {
        this.changeSet = changeSet;
        this.data = data;
        this.dataSubscribers = Object.seal(new TJSPositionData());
        this.dimensionData = Object.seal({ width: 0, height: 0 });
        this.options = options;
        this.queued = false;
        this.styleCache = styleCache;
        this.storeDimension = writable(this.dimensionData);
        this.subscribers = subscribers;
        this.transforms = transforms;
        this.transformData = new TJSTransformData();
        this.storeTransform = writable(this.transformData, () => {
          this.options.transformSubscribed = true;
          return () => this.options.transformSubscribed = false;
        });
      }
    }
    class UpdateElementManager {
      /**
       * Stores the active list of all TJSPosition instances currently updating. The list entries are recycled between
       * updates.
       */
      static list = [];
      /**
       * Tracks the current position in the list.
       */
      static listCntr = 0;
      static updatePromise;
      /**
       * Potentially adds the given element and internal updateData instance to the list.
       *
       * @param el - An HTMLElement instance.
       *
       * @param updateData - An UpdateElementData instance.
       *
       * @returns The unified next frame update promise. Returns `currentTime`.
       */
      static add(el, updateData) {
        if (this.listCntr < this.list.length) {
          const entry = this.list[this.listCntr];
          entry[0] = el;
          entry[1] = updateData;
        } else {
          this.list.push([el, updateData]);
        }
        this.listCntr++;
        updateData.queued = true;
        if (!this.updatePromise) {
          this.updatePromise = this.wait();
        }
        return this.updatePromise;
      }
      /**
       * Await on `nextAnimationFrame` and iterate over list map invoking callback functions.
       *
       * @returns The next frame Promise / currentTime from nextAnimationFrame.
       */
      static async wait() {
        const currentTime = await nextAnimationFrame();
        this.updatePromise = void 0;
        for (let cntr = this.listCntr; --cntr >= 0; ) {
          const entry = this.list[cntr];
          const el = entry[0];
          const updateData = entry[1];
          entry[0] = void 0;
          entry[1] = void 0;
          updateData.queued = false;
          if (!el.isConnected) {
            continue;
          }
          if (updateData.options.ortho) {
            UpdateElementManager.#updateElementOrtho(el, updateData);
          } else {
            UpdateElementManager.#updateElement(el, updateData);
          }
          if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
            UpdateElementManager.#updateTransform(updateData);
          }
          this.updateSubscribers(updateData);
        }
        this.listCntr = 0;
        return currentTime;
      }
      /**
       * Potentially immediately updates the given element.
       *
       * @param el - An HTMLElement instance.
       *
       * @param updateData - An UpdateElementData instance.
       */
      static immediate(el, updateData) {
        if (!el.isConnected) {
          return;
        }
        if (updateData.options.ortho) {
          UpdateElementManager.#updateElementOrtho(el, updateData);
        } else {
          UpdateElementManager.#updateElement(el, updateData);
        }
        if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
          UpdateElementManager.#updateTransform(updateData);
        }
        this.updateSubscribers(updateData);
      }
      /**
       * @param updateData - Data change set.
       */
      static updateSubscribers(updateData) {
        const data = updateData.data;
        const changeSet = updateData.changeSet;
        if (!changeSet.hasChange()) {
          return;
        }
        const output = TJSPositionDataUtil.copyData(data, updateData.dataSubscribers);
        const subscribers = updateData.subscribers;
        if (subscribers.length > 0) {
          for (let cntr = 0; cntr < subscribers.length; cntr++) {
            subscribers[cntr](output);
          }
        }
        if (changeSet.width || changeSet.height) {
          updateData.dimensionData.width = data.width;
          updateData.dimensionData.height = data.height;
          updateData.storeDimension.set(updateData.dimensionData);
        }
        changeSet.set(false);
      }
      // Internal Implementation ----------------------------------------------------------------------------------------
      /**
       * Temporary data for validation.
       */
      static #validationData = Object.seal({
        height: 0,
        width: 0,
        marginLeft: 0,
        marginTop: 0
      });
      /**
       * Decouples updates to any parent target HTMLElement inline styles. Invoke {@link TJSPosition.elementUpdated} to
       * await on the returned promise that is resolved with the current render time via `nextAnimationFrame` /
       * `requestAnimationFrame`. This allows the underlying data model to be updated immediately while updates to the
       * element are in sync with the browser and potentially in the future be further throttled.
       *
       * @param el - The target HTMLElement.
       *
       * @param updateData - Update data.
       */
      static #updateElement(el, updateData) {
        const changeSet = updateData.changeSet;
        const data = updateData.data;
        if (changeSet.left) {
          el.style.left = `${data.left}px`;
        }
        if (changeSet.top) {
          el.style.top = `${data.top}px`;
        }
        if (changeSet.zIndex) {
          el.style.zIndex = typeof data.zIndex === "number" ? `${data.zIndex}` : "";
        }
        if (changeSet.width) {
          el.style.width = typeof data.width === "number" ? `${data.width}px` : data.width;
        }
        if (changeSet.height) {
          el.style.height = typeof data.height === "number" ? `${data.height}px` : data.height;
        }
        if (changeSet.transformOrigin) {
          el.style.transformOrigin = data.transformOrigin;
        }
        if (changeSet.transform) {
          el.style.transform = updateData.transforms.isActive ? updateData.transforms.getCSS() : "";
        }
      }
      /**
       * Decouples updates to any parent target HTMLElement inline styles. Invoke {@link TJSPosition.elementUpdated} to
       * await on the returned promise that is resolved with the current render time via `nextAnimationFrame` /
       * `requestAnimationFrame`. This allows the underlying data model to be updated immediately while updates to the
       * element are in sync with the browser and potentially in the future be further throttled.
       *
       * @param el - The target HTMLElement.
       *
       * @param updateData - Update data.
       */
      static #updateElementOrtho(el, updateData) {
        const changeSet = updateData.changeSet;
        const data = updateData.data;
        if (changeSet.zIndex) {
          el.style.zIndex = typeof data.zIndex === "number" ? `${data.zIndex}` : "";
        }
        if (changeSet.width) {
          el.style.width = typeof data.width === "number" ? `${data.width}px` : data.width;
        }
        if (changeSet.height) {
          el.style.height = typeof data.height === "number" ? `${data.height}px` : data.height;
        }
        if (changeSet.transformOrigin) {
          el.style.transformOrigin = data.transformOrigin;
        }
        if (changeSet.left || changeSet.top || changeSet.transform) {
          el.style.transform = updateData.transforms.getCSSOrtho(data);
        }
      }
      /**
       * Updates the applied transform data and sets the readable `transform` store.
       *
       * @param updateData - Update element data.
       */
      static #updateTransform(updateData) {
        const validationData = this.#validationData;
        validationData.height = updateData.data.height !== "auto" && updateData.data.height !== "inherit" ? updateData.data.height : updateData.styleCache.offsetHeight;
        validationData.width = updateData.data.width !== "auto" && updateData.data.width !== "inherit" ? updateData.data.width : updateData.styleCache.offsetWidth;
        validationData.marginLeft = updateData.styleCache.marginLeft;
        validationData.marginTop = updateData.styleCache.marginTop;
        updateData.transforms.getData(updateData.data, updateData.transformData, validationData);
        updateData.storeTransform.set(updateData.transformData);
      }
    }
    var _a;
    class TJSPosition {
      /**
       * Public API for {@link TJSPosition.Initial}.
       */
      static #positionInitial = Object.freeze({
        browserCentered: new Centered({ lock: true }),
        Centered
      });
      /**
       * Public API for {@link TJSPosition.Validators}
       */
      static #positionValidators = Object.freeze({
        TransformBounds,
        transformWindow: new TransformBounds({ lock: true })
      });
      /**
       * Stores all position data / properties.
       */
      #data = Object.seal(new TJSPositionData());
      /**
       * Provides the animation API.
       */
      #animate = new AnimationAPIImpl(this, this.#data);
      /**
       * Provides a way to turn on / off the position handling.
       */
      #enabled = true;
      /**
       * Stores ongoing options that are set in the constructor or by transform store subscription.
       */
      #options = {
        calculateTransform: false,
        initial: void 0,
        ortho: true,
        transformSubscribed: false
      };
      /**
       * The associated parent for positional data tracking. Used in validators.
       */
      #parent;
      /**
       * Stores the style attributes that changed on update.
       */
      #positionChangeSet = new PositionChangeSet();
      /**
       * Tracks the current state if this position instance is a candidate for resize observation by the `resizeObserver`
       * action. This is `true` when `width` or `height` is `auto` or `inherit`.
       */
      #resizeObservable = false;
      /**
       */
      #stores;
      /**
       * Stores an instance of the computer styles for the target element.
       */
      #styleCache;
      /**
       * Stores the subscribers.
       */
      #subscribers = [];
      /**
       */
      #transforms = new TJSTransforms();
      /**
       */
      #updateElementData;
      /**
       * Stores the UpdateElementManager wait promise.
       */
      #updateElementPromise;
      /**
       */
      #validators;
      /**
       */
      #validatorData;
      /**
       */
      #state = new PositionStateAPI(this, this.#data, this.#transforms);
      /**
       * @returns Public Animation Group API.
       */
      static get Animate() {
        return AnimationGroupAPIImpl;
      }
      /**
       * @returns TJSPositionData constructor.
       */
      static get Data() {
        return TJSPositionData;
      }
      /**
       * @returns TJSPosition default initial systems.
       */
      static get Initial() {
        return this.#positionInitial;
      }
      /**
       * @returns `SystemBase` constructor.
       */
      static get SystemBase() {
        return SystemBase;
      }
      /**
       * Returns TJSTransformData class / constructor.
       *
       * @returns TransformData class / constructor.
       */
      static get TransformData() {
        return TJSTransformData;
      }
      /**
       * Returns default validator systems.
       *
       * @returns Available validators.
       */
      static get Validators() {
        return this.#positionValidators;
      }
      /**
       * Returns a list of supported transform origins.
       *
       * @returns The supported transform origin strings.
       */
      static get transformOrigins() {
        return TJSTransforms.transformOrigins;
      }
      /**
       * Convenience to copy from source to target of two TJSPositionData like objects. If a target is not supplied a new
       * {@link TJSPositionData} instance is created.
       *
       * @param source - The source instance to copy from.
       *
       * @param [target] - Target TJSPositionData like object; if one is not provided a new instance is created.
       *
       * @returns The target instance with all TJSPositionData fields.
       */
      static copyData(source, target) {
        return TJSPositionDataUtil.copyData(source, target);
      }
      /**
       * Returns a duplicate of a given position instance copying any options and validators. The position parent is not
       * copied and a new one must be set manually via the {@link TJSPosition.parent} setter.
       *
       * @param position - A position instance.
       *
       * @param [options] - Unique new options to set.
       *
       * @returns A duplicate position instance.
       */
      static duplicate(position, options = {}) {
        if (!(position instanceof _a)) {
          throw new TypeError(`'position' is not an instance of TJSPosition.`);
        }
        const newPosition = new _a(options);
        newPosition.#options = Object.assign({}, position.#options, options);
        newPosition.#validators.add(...position.#validators);
        newPosition.set(position.#data);
        return newPosition;
      }
      /**
       * @param [parentOrOptions] - A  potential parent element or object w/ `elementTarget` accessor. You may also forego
       *        setting the parent and pass in the options object.
       *
       * @param [options] - The options object.
       */
      constructor(parentOrOptions, options) {
        if (isPlainObject(parentOrOptions)) {
          options = parentOrOptions;
        } else {
          this.#parent = parentOrOptions;
        }
        this.#styleCache = new TJSPositionStyleCache();
        const updateData = new UpdateElementData(this.#positionChangeSet, this.#data, this.#options, this.#styleCache, this.#subscribers, this.#transforms);
        this.#updateElementData = updateData;
        if (typeof options?.calculateTransform === "boolean") {
          this.#options.calculateTransform = options.calculateTransform;
        }
        if (typeof options?.ortho === "boolean") {
          this.#options.ortho = options.ortho;
        }
        this.#stores = Object.freeze({
          // The main properties for manipulating TJSPosition.
          height: propertyStore(this, "height"),
          left: propertyStore(this, "left"),
          rotateX: propertyStore(this, "rotateX"),
          rotateY: propertyStore(this, "rotateY"),
          rotateZ: propertyStore(this, "rotateZ"),
          scale: propertyStore(this, "scale"),
          top: propertyStore(this, "top"),
          transformOrigin: propertyStore(this, "transformOrigin"),
          translateX: propertyStore(this, "translateX"),
          translateY: propertyStore(this, "translateY"),
          translateZ: propertyStore(this, "translateZ"),
          width: propertyStore(this, "width"),
          zIndex: propertyStore(this, "zIndex"),
          // Stores that control validation when width / height is not `auto`.
          maxHeight: propertyStore(this, "maxHeight"),
          maxWidth: propertyStore(this, "maxWidth"),
          minHeight: propertyStore(this, "minHeight"),
          minWidth: propertyStore(this, "minWidth"),
          // Readable stores based on updates or from resize observer changes.
          dimension: { subscribe: updateData.storeDimension.subscribe },
          element: { subscribe: this.#styleCache.stores.element.subscribe },
          resizeContentHeight: { subscribe: this.#styleCache.stores.resizeContentHeight.subscribe },
          resizeContentWidth: { subscribe: this.#styleCache.stores.resizeContentWidth.subscribe },
          resizeObservable: { subscribe: this.#styleCache.stores.resizeObservable.subscribe },
          resizeOffsetHeight: { subscribe: this.#styleCache.stores.resizeOffsetHeight.subscribe },
          resizeOffsetWidth: { subscribe: this.#styleCache.stores.resizeOffsetWidth.subscribe },
          transform: { subscribe: updateData.storeTransform.subscribe },
          // Protected store that should only be set by resizeObserver action.
          resizeObserved: this.#styleCache.stores.resizeObserved
        });
        Object.defineProperty(this.#stores.transformOrigin, "values", {
          get: () => _a.transformOrigins
        });
        subscribeIgnoreFirst(this.#stores.resizeObserved, (resizeData) => {
          const parent = this.#parent;
          const el = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
          if (A11yHelper.isFocusTarget(el) && Number.isFinite(resizeData?.offsetWidth) && Number.isFinite(resizeData?.offsetHeight)) {
            this.set();
          }
        });
        [this.#validators, this.#validatorData] = AdapterValidators.create(() => this.set());
        if (options?.initial) {
          const initial = options.initial;
          if (typeof initial?.getLeft !== "function" || typeof initial?.getTop !== "function") {
            throw new Error(`'options.initial' position helper does not contain 'getLeft' and / or 'getTop' functions.`);
          }
          this.#options.initial = initial;
        }
        if (options?.validator) {
          if (isIterable(options?.validator)) {
            this.validators.add(...options.validator);
          } else {
            const validatorFn = options.validator;
            this.validators.add(validatorFn);
          }
        }
        Object.seal(this);
        if (isObject(options)) {
          this.set(options);
        }
      }
      /**
       * Returns the animation API.
       *
       * @returns Animation instance API.
       */
      get animate() {
        return this.#animate;
      }
      /**
       * Returns the dimension data for the readable store.
       *
       * @returns Dimension data.
       */
      get dimension() {
        return this.#updateElementData.dimensionData;
      }
      /**
       * Returns the enabled state.
       *
       * @returns Enabled state.
       */
      get enabled() {
        return this.#enabled;
      }
      /**
       * Returns the current HTMLElement being positioned.
       *
       * @returns Current HTMLElement being positioned.
       */
      get element() {
        return this.#styleCache.el;
      }
      /**
       * Returns a promise that is resolved on the next element update with the time of the update.
       *
       * @returns Promise resolved on element update.
       */
      get elementUpdated() {
        return this.#updateElementPromise;
      }
      /**
       * Returns the associated {@link TJSPosition.PositionParent} instance.
       *
       * @returns The current position parent instance.
       */
      get parent() {
        return this.#parent;
      }
      /**
       * Returns the state API.
       *
       * @returns TJSPosition state API.
       */
      get state() {
        return this.#state;
      }
      /**
       * Returns the derived writable stores for individual data variables.
       *
       * @returns Derived / writable stores.
       */
      get stores() {
        return this.#stores;
      }
      /**
       * Returns the transform data for the readable store.
       *
       * @returns Transform Data.
       */
      get transform() {
        return this.#updateElementData.transformData;
      }
      /**
       * Returns the validators.
       *
       * @returns Validators API
       */
      get validators() {
        return this.#validators;
      }
      /**
       * Sets the enabled state.
       *
       * @param enabled - New enabled state.
       */
      set enabled(enabled) {
        if (typeof enabled !== "boolean") {
          throw new TypeError(`'enabled' is not a boolean.`);
        }
        this.#enabled = enabled;
      }
      /**
       * Sets the associated {@link TJSPosition.PositionParent} instance. Resets the style cache and default data.
       *
       * @param parent - A PositionParent instance or undefined to disassociate
       */
      set parent(parent) {
        if (parent !== void 0 && !A11yHelper.isFocusTarget(parent) && !isObject(parent)) {
          throw new TypeError(`'parent' is not an HTMLElement, object, or undefined.`);
        }
        this.#parent = parent;
        this.#state.remove({ name: "#defaultData" });
        this.#styleCache.reset();
        if (parent) {
          this.set(this.#data);
        }
      }
      // Data accessors ----------------------------------------------------------------------------------------------------
      /**
       * @returns height
       */
      get height() {
        return this.#data.height;
      }
      /**
       * @returns left
       */
      get left() {
        return this.#data.left;
      }
      /**
       * @returns maxHeight
       */
      get maxHeight() {
        return this.#data.maxHeight;
      }
      /**
       * @returns maxWidth
       */
      get maxWidth() {
        return this.#data.maxWidth;
      }
      /**
       * @returns minHeight
       */
      get minHeight() {
        return this.#data.minHeight;
      }
      /**
       * @returns minWidth
       */
      get minWidth() {
        return this.#data.minWidth;
      }
      /**
       * @returns rotateX
       */
      get rotateX() {
        return this.#data.rotateX;
      }
      /**
       * @returns rotateY
       */
      get rotateY() {
        return this.#data.rotateY;
      }
      /**
       * @returns rotateZ
       */
      get rotateZ() {
        return this.#data.rotateZ;
      }
      /**
       * @returns Alias for rotateZ
       */
      get rotation() {
        return this.#data.rotateZ;
      }
      /**
       * @returns scale
       */
      get scale() {
        return this.#data.scale;
      }
      /**
       * @returns top
       */
      get top() {
        return this.#data.top;
      }
      /**
       * @returns transformOrigin
       */
      get transformOrigin() {
        return this.#data.transformOrigin;
      }
      /**
       * @returns translateX
       */
      get translateX() {
        return this.#data.translateX;
      }
      /**
       * @returns translateY
       */
      get translateY() {
        return this.#data.translateY;
      }
      /**
       * @returns translateZ
       */
      get translateZ() {
        return this.#data.translateZ;
      }
      /**
       * @returns width
       */
      get width() {
        return this.#data.width;
      }
      /**
       * @returns z-index
       */
      get zIndex() {
        return this.#data.zIndex;
      }
      /**
       * @param height -
       */
      set height(height) {
        this.#stores.height.set(height);
      }
      /**
       * @param left -
       */
      set left(left) {
        this.#stores.left.set(left);
      }
      /**
       * @param maxHeight -
       */
      set maxHeight(maxHeight) {
        this.#stores.maxHeight.set(maxHeight);
      }
      /**
       * @param maxWidth -
       */
      set maxWidth(maxWidth) {
        this.#stores.maxWidth.set(maxWidth);
      }
      /**
       * @param minHeight -
       */
      set minHeight(minHeight) {
        this.#stores.minHeight.set(minHeight);
      }
      /**
       * @param minWidth -
       */
      set minWidth(minWidth) {
        this.#stores.minWidth.set(minWidth);
      }
      /**
       * @param rotateX -
       */
      set rotateX(rotateX) {
        this.#stores.rotateX.set(rotateX);
      }
      /**
       * @param rotateY -
       */
      set rotateY(rotateY) {
        this.#stores.rotateY.set(rotateY);
      }
      /**
       * @param rotateZ -
       */
      set rotateZ(rotateZ) {
        this.#stores.rotateZ.set(rotateZ);
      }
      /**
       * @param  rotateZ - alias for rotateZ
       */
      set rotation(rotateZ) {
        this.#stores.rotateZ.set(rotateZ);
      }
      /**
       * @param scale -
       */
      set scale(scale2) {
        this.#stores.scale.set(scale2);
      }
      /**
       * @param top -
       */
      set top(top) {
        this.#stores.top.set(top);
      }
      /**
       * @param transformOrigin -
       */
      set transformOrigin(transformOrigin) {
        if (TJSTransforms.transformOrigins.includes(transformOrigin)) {
          this.#stores.transformOrigin.set(transformOrigin);
        }
      }
      /**
       * @param translateX -
       */
      set translateX(translateX) {
        this.#stores.translateX.set(translateX);
      }
      /**
       * @param translateY -
       */
      set translateY(translateY) {
        this.#stores.translateY.set(translateY);
      }
      /**
       * @param translateZ -
       */
      set translateZ(translateZ) {
        this.#stores.translateZ.set(translateZ);
      }
      /**
       * @param width -
       */
      set width(width2) {
        this.#stores.width.set(width2);
      }
      /**
       * @param zIndex -
       */
      set zIndex(zIndex) {
        this.#stores.zIndex.set(zIndex);
      }
      /**
       * Assigns current position data to given object `data` object. By default, `null` position data is not assigned.
       * Other options allow configuration of the data assigned including setting default numeric values for any properties
       * that are null.
       *
       * @param [data] - Target to assign current position data.
       *
       * @param [options] - Defines options for specific keys and substituting null for numeric default values. By
       *        default, nullable keys are included.
       *
       * @returns Passed in object with current position data.
       */
      get(data = {}, options = {}) {
        const keys = options?.keys;
        const excludeKeys = options?.exclude;
        const nullable = options?.nullable ?? true;
        const numeric = options?.numeric ?? false;
        if (isIterable(keys)) {
          for (const key of keys) {
            data[key] = numeric ? TJSPositionDataUtil.getDataOrDefault(this, key) : this[key];
            if (!nullable && data[key] === null) {
              delete data[key];
            }
          }
          if (isIterable(excludeKeys)) {
            for (const key of excludeKeys) {
              delete data[key];
            }
          }
          return data;
        } else {
          data = Object.assign(data, this.#data);
          if (isIterable(excludeKeys)) {
            for (const key of excludeKeys) {
              delete data[key];
            }
          }
          if (numeric) {
            TJSPositionDataUtil.setNumericDefaults(data);
          }
          if (!nullable) {
            for (const key in data) {
              if (data[key] === null) {
                delete data[key];
              }
            }
          }
          return data;
        }
      }
      /**
       * @returns Current position data.
       */
      toJSON() {
        return Object.assign({}, this.#data);
      }
      /**
       * All calculation and updates of position are implemented in {@link TJSPosition}. This allows position to be fully
       * reactive and in control of updating inline styles for a connected {@link HTMLElement}.
       *
       * The initial set call with a target element will always set width / height as this is necessary for correct
       * calculations.
       *
       * When a target element is present updated styles are applied after validation. To modify the behavior of set
       * implement one or more validator functions and add them via the validator API available from
       * {@link TJSPosition.validators}.
       *
       * Updates to any target element are decoupled from the underlying TJSPosition data. This method returns this
       * instance that you can then await on the target element inline style update by using
       * {@link TJSPosition.elementUpdated}.
       *
       * Relative updates to any property of {@link TJSPositionData} are possible by specifying properties as strings.
       * This string should be in the form of '+=', '-=', or '*=' and float / numeric value. IE '+=0.2'.
       * {@link TJSPosition.set} will apply the `addition`, `subtraction`, or `multiplication` operation specified against
       * the current value of the given property. Please see {@link Data.TJSPositionDataRelative} for a detailed
       * description.
       *
       * @param [position] - TJSPosition data to set.
       *
       * @param [options] - Additional options.
       *
       * @returns This TJSPosition instance.
       */
      set(position = {}, options = {}) {
        if (!isObject(position)) {
          throw new TypeError(`TJSPosition - set error: 'position' is not an object.`);
        }
        const parent = this.#parent;
        if (!this.#enabled) {
          return this;
        }
        if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
          return this;
        }
        const immediateElementUpdate = options?.immediateElementUpdate ?? false;
        const data = this.#data;
        const transforms = this.#transforms;
        const targetEl = A11yHelper.isFocusTarget(parent) ? parent : parent?.elementTarget;
        const el = A11yHelper.isFocusTarget(targetEl) && targetEl.isConnected ? targetEl : void 0;
        const changeSet = this.#positionChangeSet;
        const styleCache = this.#styleCache;
        if (el) {
          if (!styleCache.hasData(el)) {
            styleCache.update(el);
            if (!styleCache.hasWillChange) ;
            changeSet.set(true);
            this.#updateElementData.queued = false;
          }
          ConvertStringData.process(position, this.#data, el);
          position = this.#updatePosition(position, parent, el, styleCache);
          if (position === null) {
            return this;
          }
        }
        if (NumberGuard.isFinite(position.left)) {
          position.left = Math.round(position.left);
          if (data.left !== position.left) {
            data.left = position.left;
            changeSet.left = true;
          }
        }
        if (NumberGuard.isFinite(position.top)) {
          position.top = Math.round(position.top);
          if (data.top !== position.top) {
            data.top = position.top;
            changeSet.top = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.maxHeight)) {
          position.maxHeight = typeof position.maxHeight === "number" ? Math.round(position.maxHeight) : null;
          if (data.maxHeight !== position.maxHeight) {
            data.maxHeight = position.maxHeight;
            changeSet.maxHeight = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.maxWidth)) {
          position.maxWidth = typeof position.maxWidth === "number" ? Math.round(position.maxWidth) : null;
          if (data.maxWidth !== position.maxWidth) {
            data.maxWidth = position.maxWidth;
            changeSet.maxWidth = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.minHeight)) {
          position.minHeight = typeof position.minHeight === "number" ? Math.round(position.minHeight) : null;
          if (data.minHeight !== position.minHeight) {
            data.minHeight = position.minHeight;
            changeSet.minHeight = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.minWidth)) {
          position.minWidth = typeof position.minWidth === "number" ? Math.round(position.minWidth) : null;
          if (data.minWidth !== position.minWidth) {
            data.minWidth = position.minWidth;
            changeSet.minWidth = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.rotateX)) {
          if (data.rotateX !== position.rotateX) {
            data.rotateX = transforms.rotateX = position.rotateX;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.rotateY)) {
          if (data.rotateY !== position.rotateY) {
            data.rotateY = transforms.rotateY = position.rotateY;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.rotateZ)) {
          if (data.rotateZ !== position.rotateZ) {
            data.rotateZ = transforms.rotateZ = position.rotateZ;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.scale)) {
          position.scale = typeof position.scale === "number" ? clamp(position.scale, 0, 1e3) : null;
          if (data.scale !== position.scale) {
            data.scale = transforms.scale = position.scale;
            changeSet.transform = true;
          }
        }
        if (typeof position.transformOrigin === "string" && TJSTransforms.transformOrigins.includes(position.transformOrigin) || position.transformOrigin === null) {
          if (data.transformOrigin !== position.transformOrigin) {
            data.transformOrigin = position.transformOrigin;
            changeSet.transformOrigin = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.translateX)) {
          if (data.translateX !== position.translateX) {
            data.translateX = transforms.translateX = position.translateX;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.translateY)) {
          if (data.translateY !== position.translateY) {
            data.translateY = transforms.translateY = position.translateY;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFiniteOrNull(position.translateZ)) {
          if (data.translateZ !== position.translateZ) {
            data.translateZ = transforms.translateZ = position.translateZ;
            changeSet.transform = true;
          }
        }
        if (NumberGuard.isFinite(position.zIndex)) {
          position.zIndex = Math.round(position.zIndex);
          if (data.zIndex !== position.zIndex) {
            data.zIndex = position.zIndex;
            changeSet.zIndex = true;
          }
        }
        const widthIsObservable = position.width === "auto" || position.width === "inherit";
        if (NumberGuard.isFiniteOrNull(position.width) || widthIsObservable) {
          position.width = typeof position.width === "number" ? Math.round(position.width) : position.width;
          if (data.width !== position.width) {
            data.width = position.width;
            changeSet.width = true;
          }
        }
        const heightIsObservable = position.height === "auto" || position.height === "inherit";
        if (NumberGuard.isFiniteOrNull(position.height) || heightIsObservable) {
          position.height = typeof position.height === "number" ? Math.round(position.height) : position.height;
          if (data.height !== position.height) {
            data.height = position.height;
            changeSet.height = true;
          }
        }
        const resizeObservable = widthIsObservable || heightIsObservable;
        if (this.#resizeObservable !== resizeObservable) {
          this.#resizeObservable = resizeObservable;
          this.#styleCache.stores.resizeObservable.set(resizeObservable);
        }
        if (el) {
          const defaultData = this.#state.getDefault();
          if (!isObject(defaultData)) {
            this.#state.save({ name: "#defaultData", ...Object.assign({}, data) });
          }
          if (immediateElementUpdate) {
            UpdateElementManager.immediate(el, this.#updateElementData);
            this.#updateElementPromise = Promise.resolve(globalThis.performance.now());
          } else if (!this.#updateElementData.queued) {
            this.#updateElementPromise = UpdateElementManager.add(el, this.#updateElementData);
          }
        } else {
          UpdateElementManager.updateSubscribers(this.#updateElementData);
        }
        return this;
      }
      /**
       * @param handler - Callback function that is invoked on update / changes. Receives a readonly copy of the
       *        TJSPositionData.
       *
       * @returns Unsubscribe function.
       */
      subscribe(handler) {
        const currentIdx = this.#subscribers.findIndex((entry) => entry === handler);
        if (currentIdx === -1) {
          this.#subscribers.push(handler);
          handler(Object.assign({}, this.#data));
        }
        return () => {
          const existingIdx = this.#subscribers.findIndex((entry) => entry === handler);
          if (existingIdx !== -1) {
            this.#subscribers.splice(existingIdx, 1);
          }
        };
      }
      /**
       * Provides the {@link Writable} store `update` method. Receive and return a {@link TJSPositionData} instance to
       * update the position state. You may manipulate numeric properties by providing relative adjustments described in
       * {@link TJSPositionDataRelative}.
       *
       * @param updater -
       */
      update(updater) {
        const result = updater(this.get());
        if (!isObject(result)) {
          throw new TypeError(`'result' of 'updater' is not an object.`);
        }
        this.set(result);
      }
      // Internal Implementation ----------------------------------------------------------------------------------------
      /**
       * Temporary data storage for `TJSPosition.#updatePosition`.
       */
      static #updateDataCopy = Object.seal(new TJSPositionData());
      /**
       * Temporary data storage for `TJSPosition.#updatePosition`.
       */
      static #validationData = Object.seal({
        position: void 0,
        parent: void 0,
        el: void 0,
        computed: void 0,
        transforms: void 0,
        height: void 0,
        width: void 0,
        marginLeft: void 0,
        marginTop: void 0,
        maxHeight: void 0,
        maxWidth: void 0,
        minHeight: void 0,
        minWidth: void 0,
        rest: void 0
      });
      /**
       * @param data -
       *
       * @param parent -
       *
       * @param el -
       *
       * @param styleCache -
       *
       * @returns Updated position data or null if validation fails.
       */
      #updatePosition({
        // Directly supported parameters
        left,
        top,
        maxWidth,
        maxHeight,
        minWidth,
        minHeight,
        width: width2,
        height,
        rotateX,
        rotateY,
        rotateZ,
        scale: scale2,
        transformOrigin,
        translateX,
        translateY,
        translateZ,
        zIndex,
        // Aliased parameters
        rotation: rotation2,
        ...rest
      }, parent, el, styleCache) {
        let currentPosition = TJSPositionDataUtil.copyData(this.#data, _a.#updateDataCopy);
        if (width2 !== void 0 || el.style.width === "") {
          const widthValid = width2 === null || Number.isFinite(width2);
          if (width2 === "auto" || currentPosition.width === "auto" && !widthValid) {
            currentPosition.width = "auto";
            width2 = styleCache.offsetWidth;
          } else if (width2 === "inherit" || currentPosition.width === "inherit" && !widthValid) {
            currentPosition.width = "inherit";
            width2 = styleCache.offsetWidth;
          } else {
            const newWidth = NumberGuard.isFinite(width2) ? width2 : currentPosition.width;
            currentPosition.width = width2 = NumberGuard.isFinite(newWidth) ? Math.round(newWidth) : styleCache.offsetWidth;
          }
        } else {
          width2 = Number.isFinite(currentPosition.width) ? currentPosition.width : styleCache.offsetWidth;
        }
        if (height !== void 0 || el.style.height === "") {
          const heightValid = height === null || Number.isFinite(height);
          if (height === "auto" || currentPosition.height === "auto" && !heightValid) {
            currentPosition.height = "auto";
            height = styleCache.offsetHeight;
          } else if (height === "inherit" || currentPosition.height === "inherit" && !heightValid) {
            currentPosition.height = "inherit";
            height = styleCache.offsetHeight;
          } else {
            const newHeight = NumberGuard.isFinite(height) ? height : currentPosition.height;
            currentPosition.height = height = NumberGuard.isFinite(newHeight) ? Math.round(newHeight) : styleCache.offsetHeight;
          }
        } else {
          height = Number.isFinite(currentPosition.height) ? currentPosition.height : styleCache.offsetHeight;
        }
        if (NumberGuard.isFinite(left)) {
          currentPosition.left = left;
        } else if (!Number.isFinite(currentPosition.left)) {
          currentPosition.left = typeof this.#options?.initial?.getLeft === "function" ? this.#options.initial.getLeft(width2) : 0;
        }
        if (Number.isFinite(top)) {
          currentPosition.top = top;
        } else if (!Number.isFinite(currentPosition.top)) {
          currentPosition.top = typeof this.#options?.initial?.getTop === "function" ? this.#options.initial.getTop(height) : 0;
        }
        if (NumberGuard.isFiniteOrNull(maxHeight)) {
          currentPosition.maxHeight = NumberGuard.isFinite(maxHeight) ? Math.round(maxHeight) : null;
        }
        if (NumberGuard.isFiniteOrNull(maxWidth)) {
          currentPosition.maxWidth = NumberGuard.isFinite(maxWidth) ? Math.round(maxWidth) : null;
        }
        if (NumberGuard.isFiniteOrNull(minHeight)) {
          currentPosition.minHeight = NumberGuard.isFinite(minHeight) ? Math.round(minHeight) : null;
        }
        if (NumberGuard.isFiniteOrNull(minWidth)) {
          currentPosition.minWidth = NumberGuard.isFinite(minWidth) ? Math.round(minWidth) : null;
        }
        if (NumberGuard.isFiniteOrNull(rotateX)) {
          currentPosition.rotateX = rotateX;
        }
        if (NumberGuard.isFiniteOrNull(rotateY)) {
          currentPosition.rotateY = rotateY;
        }
        if (rotateZ !== currentPosition.rotateZ && NumberGuard.isFiniteOrNull(rotateZ)) {
          currentPosition.rotateZ = rotateZ;
        } else if (rotation2 !== currentPosition.rotateZ && NumberGuard.isFiniteOrNull(rotation2)) {
          currentPosition.rotateZ = rotation2;
        }
        if (NumberGuard.isFiniteOrNull(translateX)) {
          currentPosition.translateX = translateX;
        }
        if (NumberGuard.isFiniteOrNull(translateY)) {
          currentPosition.translateY = translateY;
        }
        if (NumberGuard.isFiniteOrNull(translateZ)) {
          currentPosition.translateZ = translateZ;
        }
        if (NumberGuard.isFiniteOrNull(scale2)) {
          currentPosition.scale = typeof scale2 === "number" ? clamp(scale2, 0, 1e3) : null;
        }
        if (typeof transformOrigin === "string" || transformOrigin === null) {
          currentPosition.transformOrigin = TJSTransforms.transformOrigins.includes(transformOrigin) ? transformOrigin : null;
        }
        if (NumberGuard.isFiniteOrNull(zIndex)) {
          currentPosition.zIndex = typeof zIndex === "number" ? Math.round(zIndex) : zIndex;
        }
        const validatorData = this.#validatorData;
        if (this.#validators.enabled && validatorData.length) {
          const validationData = _a.#validationData;
          validationData.parent = parent;
          validationData.el = el;
          validationData.computed = styleCache.computed;
          validationData.transforms = this.#transforms;
          validationData.height = height;
          validationData.width = width2;
          validationData.marginLeft = styleCache.marginLeft;
          validationData.marginTop = styleCache.marginTop;
          validationData.maxHeight = styleCache.maxHeight ?? currentPosition.maxHeight;
          validationData.maxWidth = styleCache.maxWidth ?? currentPosition.maxWidth;
          const isMinimized = parent?.reactive?.minimized ?? false;
          validationData.minHeight = isMinimized ? currentPosition.minHeight ?? 0 : styleCache.minHeight || (currentPosition.minHeight ?? 0);
          validationData.minWidth = isMinimized ? currentPosition.minWidth ?? 0 : styleCache.minWidth || (currentPosition.minWidth ?? 0);
          for (let cntr = 0; cntr < validatorData.length; cntr++) {
            validationData.position = currentPosition;
            validationData.rest = rest;
            currentPosition = validatorData[cntr].validate(validationData);
            if (currentPosition === null) {
              return null;
            }
          }
        }
        return currentPosition;
      }
    }
    _a = TJSPosition;
    if (typeof window !== "undefined")
      (window.__svelte || (window.__svelte = { v: /* @__PURE__ */ new Set() })).v.add(PUBLIC_VERSION);
    function fade(node, { delay = 0, duration = 400, easing = identity } = {}) {
      const o = +getComputedStyle(node).opacity;
      return {
        delay,
        duration,
        easing,
        css: (t) => `opacity: ${t * o}`
      };
    }
    const cssVariables = new TJSStyleManager({ docKey: "#__trl-root-styles", version: 1 });
    class ResizeObserverManager {
      /** @type {Map<HTMLElement, import('./types-local').ResizeObserverSubscriber[]>} */
      #elMap = /* @__PURE__ */ new Map();
      /** @type {ResizeObserver} */
      #resizeObserver;
      /**
       * Defines the various shape / update type of the given target.
       *
       * @type {{ [key: string]: number }}
       */
      static #updateTypes = Object.freeze({
        none: 0,
        attribute: 1,
        function: 2,
        resizeObserved: 3,
        setContentBounds: 4,
        setDimension: 5,
        storeObject: 6,
        storesObject: 7
      });
      constructor() {
        this.#resizeObserver = new ResizeObserver((entries) => {
          for (const entry of entries) {
            const subscribers = this.#elMap.get(entry?.target);
            if (Array.isArray(subscribers)) {
              const contentWidth = entry.contentRect.width;
              const contentHeight = entry.contentRect.height;
              for (const subscriber of subscribers) {
                ResizeObserverManager.#updateSubscriber(subscriber, contentWidth, contentHeight);
              }
            }
          }
        });
      }
      /**
       * Add an {@link HTMLElement} and {@link ResizeObserverData.ResizeTarget} instance for monitoring. Create cached
       * style attributes for the given element include border & padding dimensions for offset width / height calculations.
       *
       * @param {HTMLElement}    el - The element to observe.
       *
       * @param {import('./types').ResizeObserverData.ResizeTarget} target - A target that contains one of several
       *        mechanisms for updating resize data.
       */
      add(el, target) {
        if (!CrossWindow.isHTMLElement(el)) {
          throw new TypeError(`ResizeObserverManager.add error: 'el' is not a HTMLElement.`);
        }
        if (this.#hasTarget(el, target)) {
          return;
        }
        const updateType = ResizeObserverManager.#getUpdateType(target);
        if (updateType === 0) {
          throw new Error(`ResizeObserverManager.add error: 'target' is not a valid ResizeObserverManager target.`);
        }
        const computed = globalThis.getComputedStyle(el);
        const borderBottom = StyleParse.pixels(el.style.borderBottom) ?? StyleParse.pixels(computed.borderBottom) ?? 0;
        const borderLeft = StyleParse.pixels(el.style.borderLeft) ?? StyleParse.pixels(computed.borderLeft) ?? 0;
        const borderRight = StyleParse.pixels(el.style.borderRight) ?? StyleParse.pixels(computed.borderRight) ?? 0;
        const borderTop = StyleParse.pixels(el.style.borderTop) ?? StyleParse.pixels(computed.borderTop) ?? 0;
        const paddingBottom = StyleParse.pixels(el.style.paddingBottom) ?? StyleParse.pixels(computed.paddingBottom) ?? 0;
        const paddingLeft = StyleParse.pixels(el.style.paddingLeft) ?? StyleParse.pixels(computed.paddingLeft) ?? 0;
        const paddingRight = StyleParse.pixels(el.style.paddingRight) ?? StyleParse.pixels(computed.paddingRight) ?? 0;
        const paddingTop = StyleParse.pixels(el.style.paddingTop) ?? StyleParse.pixels(computed.paddingTop) ?? 0;
        const data = {
          updateType,
          target,
          // Stores most recent contentRect.width and contentRect.height values from ResizeObserver.
          contentWidth: 0,
          contentHeight: 0,
          // Convenience data for total border & padding for offset width & height calculations.
          styles: {
            additionalWidth: borderLeft + borderRight + paddingLeft + paddingRight,
            additionalHeight: borderTop + borderBottom + paddingTop + paddingBottom
          }
        };
        if (this.#elMap.has(el)) {
          const subscribers = this.#elMap.get(el);
          subscribers.push(data);
        } else {
          this.#elMap.set(el, [data]);
        }
        this.#resizeObserver.observe(el);
      }
      /**
       * Clears and unobserves all currently tracked elements and managed targets.
       */
      clear() {
        for (const el of this.#elMap.keys()) {
          this.#resizeObserver.unobserve(el);
        }
        this.#elMap.clear();
      }
      /**
       * Removes all {@link ResizeObserverData.ResizeTarget} instances for the given element from monitoring when just an
       * element is provided otherwise removes a specific target from the monitoring map. If no more targets remain then
       * the element is removed from monitoring.
       *
       * @param {HTMLElement} el - Element to remove from monitoring.
       *
       * @param {import('./types').ResizeObserverData.ResizeTarget} [target] - A specific target to remove from monitoring.
       */
      remove(el, target = void 0) {
        const subscribers = this.#elMap.get(el);
        if (Array.isArray(subscribers)) {
          if (target !== void 0) {
            const index = subscribers.findIndex((entry) => entry.target === target);
            if (index >= 0) {
              subscribers.splice(index, 1);
            }
          } else {
            subscribers.length = 0;
          }
          if (subscribers.length === 0) {
            this.#elMap.delete(el);
            this.#resizeObserver.unobserve(el);
          }
        }
      }
      /**
       * Provides a function that when invoked with an element updates the cached styles for each subscriber of the
       * element.
       *
       * The style attributes cached to calculate offset height / width include border & padding dimensions. You only need
       * to update the cache if you change border or padding attributes of the element.
       *
       * @param {HTMLElement} el - A HTML element.
       */
      updateCache(el) {
        const subscribers = this.#elMap.get(el);
        if (Array.isArray(subscribers)) {
          const computed = globalThis.getComputedStyle(el);
          const borderBottom = StyleParse.pixels(el.style.borderBottom) ?? StyleParse.pixels(computed.borderBottom) ?? 0;
          const borderLeft = StyleParse.pixels(el.style.borderLeft) ?? StyleParse.pixels(computed.borderLeft) ?? 0;
          const borderRight = StyleParse.pixels(el.style.borderRight) ?? StyleParse.pixels(computed.borderRight) ?? 0;
          const borderTop = StyleParse.pixels(el.style.borderTop) ?? StyleParse.pixels(computed.borderTop) ?? 0;
          const paddingBottom = StyleParse.pixels(el.style.paddingBottom) ?? StyleParse.pixels(computed.paddingBottom) ?? 0;
          const paddingLeft = StyleParse.pixels(el.style.paddingLeft) ?? StyleParse.pixels(computed.paddingLeft) ?? 0;
          const paddingRight = StyleParse.pixels(el.style.paddingRight) ?? StyleParse.pixels(computed.paddingRight) ?? 0;
          const paddingTop = StyleParse.pixels(el.style.paddingTop) ?? StyleParse.pixels(computed.paddingTop) ?? 0;
          const additionalWidth = borderLeft + borderRight + paddingLeft + paddingRight;
          const additionalHeight = borderTop + borderBottom + paddingTop + paddingBottom;
          for (const subscriber of subscribers) {
            subscriber.styles.additionalWidth = additionalWidth;
            subscriber.styles.additionalHeight = additionalHeight;
            ResizeObserverManager.#updateSubscriber(subscriber, subscriber.contentWidth, subscriber.contentHeight);
          }
        }
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Determines the shape of the target instance regarding valid update mechanisms to set width & height changes.
       *
       * @param {import('./types').ResizeObserverData.ResizeTarget}  target - The target instance.
       *
       * @returns {number} Update type value.
       */
      static #getUpdateType(target) {
        if (typeof target?.resizeObserved === "function") {
          return this.#updateTypes.resizeObserved;
        }
        if (typeof target?.setDimension === "function") {
          return this.#updateTypes.setDimension;
        }
        if (typeof target?.setContentBounds === "function") {
          return this.#updateTypes.setContentBounds;
        }
        const targetType = typeof target;
        if (targetType !== null && (targetType === "object" || targetType === "function")) {
          if (isWritableStore(target.resizeObserved)) {
            return this.#updateTypes.storeObject;
          }
          const stores = target?.stores;
          if (isObject(stores) || typeof stores === "function") {
            if (isWritableStore(stores.resizeObserved)) {
              return this.#updateTypes.storesObject;
            }
          }
        }
        if (targetType !== null && targetType === "object") {
          return this.#updateTypes.attribute;
        }
        if (targetType === "function") {
          return this.#updateTypes.function;
        }
        return this.#updateTypes.none;
      }
      /**
       * Determines if a given element and target is already being observed.
       *
       * @param {HTMLElement} el - A HTMLElement.
       *
       * @param {import('./types').ResizeObserverData.ResizeTarget} [target] - A specific target to find.
       *
       * @returns {boolean} Whether the target is already being tracked for the given element.
       */
      #hasTarget(el, target) {
        if (target === void 0 || target === null) {
          return false;
        }
        const subscribers = this.#elMap.get(el);
        if (Array.isArray(subscribers)) {
          return subscribers.findIndex((entry) => entry.target === target) >= 0;
        }
        return false;
      }
      /**
       * Updates a subscriber target with given content width & height values. Offset width & height is calculated from
       * the content values + cached styles.
       *
       * @param {import('./types-local').ResizeObserverSubscriber} subscriber - Internal data about subscriber.
       *
       * @param {number|undefined}  contentWidth - ResizeObserver `contentRect.width` value or undefined.
       *
       * @param {number|undefined}  contentHeight - ResizeObserver `contentRect.height` value or undefined.
       */
      static #updateSubscriber(subscriber, contentWidth, contentHeight) {
        const styles = subscriber.styles;
        subscriber.contentWidth = contentWidth;
        subscriber.contentHeight = contentHeight;
        const offsetWidth = Number.isFinite(contentWidth) ? contentWidth + styles.additionalWidth : void 0;
        const offsetHeight = Number.isFinite(contentHeight) ? contentHeight + styles.additionalHeight : void 0;
        const target = subscriber.target;
        switch (subscriber.updateType) {
          case this.#updateTypes.attribute:
            target.contentWidth = contentWidth;
            target.contentHeight = contentHeight;
            target.offsetWidth = offsetWidth;
            target.offsetHeight = offsetHeight;
            break;
          case this.#updateTypes.function:
            target?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
            break;
          case this.#updateTypes.resizeObserved:
            target.resizeObserved?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
            break;
          case this.#updateTypes.setContentBounds:
            target.setContentBounds?.(contentWidth, contentHeight);
            break;
          case this.#updateTypes.setDimension:
            target.setDimension?.(offsetWidth, offsetHeight);
            break;
          case this.#updateTypes.storeObject:
            target.resizeObserved.update((object) => {
              object.contentHeight = contentHeight;
              object.contentWidth = contentWidth;
              object.offsetHeight = offsetHeight;
              object.offsetWidth = offsetWidth;
              return object;
            });
            break;
          case this.#updateTypes.storesObject:
            target.stores.resizeObserved.update((object) => {
              object.contentHeight = contentHeight;
              object.contentWidth = contentWidth;
              object.offsetHeight = offsetHeight;
              object.offsetWidth = offsetWidth;
              return object;
            });
            break;
        }
      }
    }
    const resizeObserverActionManager = new ResizeObserverManager();
    function resizeObserver(node, target) {
      resizeObserverActionManager.add(node, target);
      return {
        /**
         * @param {import('#runtime/util/dom/observer').ResizeObserverData.ResizeTarget} newTarget - A
         *        {@link ResizeObserverManager} target to update with observed width & height changes.
         */
        update: (newTarget) => {
          resizeObserverActionManager.remove(node, target);
          target = newTarget;
          resizeObserverActionManager.add(node, target);
        },
        destroy: () => {
          resizeObserverActionManager.remove(node, target);
        }
      };
    }
    resizeObserver.updateCache = function(el) {
      resizeObserverActionManager.updateCache(el);
    };
    function applyStyles(node, properties) {
      function setProperties() {
        if (!isObject(properties)) {
          return;
        }
        for (const prop of Object.keys(properties)) {
          node.style.setProperty(`${prop}`, properties[prop]);
        }
      }
      setProperties();
      return {
        /**
         * @param {{ [key: string]: string | null }}  newProperties - Key / value object of properties to set.
         */
        update: (newProperties) => {
          properties = newProperties;
          setProperties();
        }
      };
    }
    function dynamicAction(node, { action, data } = {}) {
      let actionResult;
      if (typeof action === "function") {
        actionResult = action(node, data);
      }
      return {
        /**
         * @param {import('./types').DynamicActionOptions} newOptions - Defines the new action to dynamically mount.
         */
        update: (newOptions) => {
          if (!isObject(newOptions)) {
            actionResult?.destroy?.();
            action = void 0;
            data = void 0;
            return;
          }
          const { action: newAction, data: newData } = newOptions;
          if (typeof newAction !== "function") {
            console.warn(`dynamicAction.update warning: Aborting as 'action' is not a function.`);
            return;
          }
          const hasNewData = newData !== data;
          if (hasNewData) {
            data = newData;
          }
          if (newAction !== action) {
            actionResult?.destroy?.();
            action = newAction;
            actionResult = action(node, data);
          } else if (hasNewData) {
            actionResult?.update?.(data);
          }
        },
        destroy: () => {
          actionResult?.destroy?.();
          action = void 0;
          data = void 0;
          actionResult = void 0;
        }
      };
    }
    class TJSDefaultTransition {
      static #options = {};
      static #default = () => void 0;
      /**
       * @returns {() => undefined} Default empty transition.
       */
      static get default() {
        return this.#default;
      }
      /**
       * @returns {{}} Default empty options.
       */
      static get options() {
        return this.#options;
      }
    }
    class AppShellContextInternal {
      /** @type {import('./types').AppShell.Context.Internal.stores} */
      #stores;
      constructor() {
        this.#stores = {
          elementContent: writable(void 0),
          elementRoot: writable(void 0)
        };
        Object.freeze(this.#stores);
        Object.seal(this);
      }
      /**
       * @returns {import('./types').AppShell.Context.Internal.stores} The internal context stores for `elementContent` /
       *          `elementRoot`
       */
      get stores() {
        return this.#stores;
      }
    }
    function localize(stringId, data) {
      const result = !isObject(data) ? globalThis.game.i18n.localize(stringId) : globalThis.game.i18n.format(stringId, data);
      return result !== void 0 ? result : "";
    }
    function create_if_block$d(ctx) {
      let span;
      let t;
      return {
        c() {
          span = element("span");
          t = text$1(
            /*label*/
            ctx[3]
          );
          attr(span, "class", "svelte-seq-acci");
          toggle_class(
            span,
            "has-icon",
            /*icon*/
            ctx[4] !== void 0
          );
        },
        m(target, anchor) {
          insert(target, span, anchor);
          append(span, t);
        },
        p(ctx2, dirty) {
          if (dirty & /*label*/
          8) set_data(
            t,
            /*label*/
            ctx2[3]
          );
          if (dirty & /*icon*/
          16) {
            toggle_class(
              span,
              "has-icon",
              /*icon*/
              ctx2[4] !== void 0
            );
          }
        },
        d(detaching) {
          if (detaching) {
            detach(span);
          }
        }
      };
    }
    function create_fragment$t(ctx) {
      let a;
      let html_tag;
      let html_anchor;
      let a_class_value;
      let applyStyles_action;
      let mounted;
      let dispose;
      let if_block = (
        /*label*/
        ctx[3] && create_if_block$d(ctx)
      );
      return {
        c() {
          a = element("a");
          html_tag = new HtmlTag(false);
          html_anchor = empty();
          if (if_block) if_block.c();
          html_tag.a = html_anchor;
          attr(a, "class", a_class_value = "header-button " + /*button*/
          ctx[0].class + " svelte-seq-acci");
          attr(
            a,
            "aria-label",
            /*label*/
            ctx[3]
          );
          attr(a, "tabindex", "0");
          attr(a, "role", "button");
          toggle_class(
            a,
            "keep-minimized",
            /*keepMinimized*/
            ctx[2]
          );
        },
        m(target, anchor) {
          insert(target, a, anchor);
          html_tag.m(
            /*icon*/
            ctx[4],
            a
          );
          append(a, html_anchor);
          if (if_block) if_block.m(a, null);
          if (!mounted) {
            dispose = [
              listen(a, "click", stop_propagation(prevent_default(
                /*onClick*/
                ctx[5]
              ))),
              listen(a, "contextmenu", stop_propagation(prevent_default(
                /*onContextMenu*/
                ctx[6]
              ))),
              listen(
                a,
                "keydown",
                /*onKeydown*/
                ctx[7]
              ),
              listen(
                a,
                "keyup",
                /*onKeyup*/
                ctx[8]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                a,
                /*styles*/
                ctx[1]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*icon*/
          16) html_tag.p(
            /*icon*/
            ctx2[4]
          );
          if (
            /*label*/
            ctx2[3]
          ) {
            if (if_block) {
              if_block.p(ctx2, dirty);
            } else {
              if_block = create_if_block$d(ctx2);
              if_block.c();
              if_block.m(a, null);
            }
          } else if (if_block) {
            if_block.d(1);
            if_block = null;
          }
          if (dirty & /*button*/
          1 && a_class_value !== (a_class_value = "header-button " + /*button*/
          ctx2[0].class + " svelte-seq-acci")) {
            attr(a, "class", a_class_value);
          }
          if (dirty & /*label*/
          8) {
            attr(
              a,
              "aria-label",
              /*label*/
              ctx2[3]
            );
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          2) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx2[1]
          );
          if (dirty & /*button, keepMinimized*/
          5) {
            toggle_class(
              a,
              "keep-minimized",
              /*keepMinimized*/
              ctx2[2]
            );
          }
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(a);
          }
          if (if_block) if_block.d();
          mounted = false;
          run_all(dispose);
        }
      };
    }
    const s_REGEX_HTML$1 = /^\s*<.*>$/;
    function instance$s($$self, $$props, $$invalidate) {
      let title;
      let icon;
      let label;
      let keepMinimized;
      let keyCode;
      let styles;
      let { button = void 0 } = $$props;
      function onClick(event) {
        const invoke = button?.onPress ?? button?.onclick;
        if (typeof invoke === "function") {
          invoke({ button, event });
          $$invalidate(0, button);
        }
      }
      function onContextMenu(event) {
        if (button?.onContextMenu === "function") {
          button.onContextMenu({ button, event });
          $$invalidate(0, button);
        }
      }
      function onKeydown(event) {
        if (event.code === keyCode) {
          event.preventDefault();
          event.stopPropagation();
        }
      }
      function onKeyup(event) {
        if (event.code === keyCode) {
          const invoke = button.onPress ?? button.onclick;
          if (typeof invoke === "function") {
            invoke({ button, event });
            $$invalidate(0, button);
          }
          event.preventDefault();
          event.stopPropagation();
        }
      }
      $$self.$$set = ($$props2) => {
        if ("button" in $$props2) $$invalidate(0, button = $$props2.button);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*button*/
        1) {
          $$invalidate(9, title = isObject(button) && typeof button.title === "string" ? localize(button.title) : "");
        }
        if ($$self.$$.dirty & /*button, title*/
        513) {
          $$invalidate(4, icon = isObject(button) && typeof button.icon !== "string" ? void 0 : s_REGEX_HTML$1.test(button.icon) ? button.icon : `<i class="${button.icon}" title="${title}"></i>`);
        }
        if ($$self.$$.dirty & /*button*/
        1) {
          $$invalidate(3, label = isObject(button) && typeof button.label === "string" ? localize(button.label) : void 0);
        }
        if ($$self.$$.dirty & /*button*/
        1) {
          $$invalidate(2, keepMinimized = isObject(button) && typeof button.keepMinimized === "boolean" ? button.keepMinimized : false);
        }
        if ($$self.$$.dirty & /*button*/
        1) {
          keyCode = isObject(button) && typeof button.keyCode === "string" ? button.keyCode : "Enter";
        }
        if ($$self.$$.dirty & /*button*/
        1) {
          $$invalidate(1, styles = isObject(button) && isObject(button.styles) ? button.styles : void 0);
        }
      };
      return [
        button,
        styles,
        keepMinimized,
        label,
        icon,
        onClick,
        onContextMenu,
        onKeydown,
        onKeyup,
        title
      ];
    }
    class TJSHeaderButton extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$s, create_fragment$t, safe_not_equal, { button: 0 });
      }
      get button() {
        return this.$$.ctx[0];
      }
      set button(button) {
        this.$$set({ button });
        flush();
      }
    }
    function get_each_context$8(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[31] = list[i];
      return child_ctx;
    }
    function get_each_context_1$2(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[31] = list[i];
      return child_ctx;
    }
    function create_if_block$c(ctx) {
      let img;
      let img_src_value;
      return {
        c() {
          img = element("img");
          attr(img, "class", "tjs-app-icon keep-minimized svelte-seq-5lh4qo");
          if (!src_url_equal(img.src, img_src_value = /*$storeHeaderIcon*/
          ctx[6])) attr(img, "src", img_src_value);
          attr(img, "alt", "icon");
        },
        m(target, anchor) {
          insert(target, img, anchor);
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*$storeHeaderIcon*/
          64 && !src_url_equal(img.src, img_src_value = /*$storeHeaderIcon*/
          ctx2[6])) {
            attr(img, "src", img_src_value);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(img);
          }
        }
      };
    }
    function create_each_block_1$2(ctx) {
      let switch_instance;
      let switch_instance_anchor;
      let current;
      const switch_instance_spread_levels = [
        /*button*/
        ctx[31].props
      ];
      var switch_value = (
        /*button*/
        ctx[31].class
      );
      function switch_props(ctx2, dirty) {
        let switch_instance_props = {};
        for (let i = 0; i < switch_instance_spread_levels.length; i += 1) {
          switch_instance_props = assign(switch_instance_props, switch_instance_spread_levels[i]);
        }
        if (dirty !== void 0 && dirty[0] & /*buttonsLeft*/
        2) {
          switch_instance_props = assign(switch_instance_props, get_spread_update(switch_instance_spread_levels, [get_spread_object(
            /*button*/
            ctx2[31].props
          )]));
        }
        return { props: switch_instance_props };
      }
      if (switch_value) {
        switch_instance = construct_svelte_component(switch_value, switch_props(ctx));
      }
      return {
        c() {
          if (switch_instance) create_component(switch_instance.$$.fragment);
          switch_instance_anchor = empty();
        },
        m(target, anchor) {
          if (switch_instance) mount_component(switch_instance, target, anchor);
          insert(target, switch_instance_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*buttonsLeft*/
          2 && switch_value !== (switch_value = /*button*/
          ctx2[31].class)) {
            if (switch_instance) {
              group_outros();
              const old_component = switch_instance;
              transition_out(old_component.$$.fragment, 1, 0, () => {
                destroy_component(old_component, 1);
              });
              check_outros();
            }
            if (switch_value) {
              switch_instance = construct_svelte_component(switch_value, switch_props(ctx2, dirty));
              create_component(switch_instance.$$.fragment);
              transition_in(switch_instance.$$.fragment, 1);
              mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
            } else {
              switch_instance = null;
            }
          } else if (switch_value) {
            const switch_instance_changes = dirty[0] & /*buttonsLeft*/
            2 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
              /*button*/
              ctx2[31].props
            )]) : {};
            switch_instance.$set(switch_instance_changes);
          }
        },
        i(local) {
          if (current) return;
          if (switch_instance) transition_in(switch_instance.$$.fragment, local);
          current = true;
        },
        o(local) {
          if (switch_instance) transition_out(switch_instance.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(switch_instance_anchor);
          }
          if (switch_instance) destroy_component(switch_instance, detaching);
        }
      };
    }
    function create_each_block$8(ctx) {
      let switch_instance;
      let switch_instance_anchor;
      let current;
      const switch_instance_spread_levels = [
        /*button*/
        ctx[31].props
      ];
      var switch_value = (
        /*button*/
        ctx[31].class
      );
      function switch_props(ctx2, dirty) {
        let switch_instance_props = {};
        for (let i = 0; i < switch_instance_spread_levels.length; i += 1) {
          switch_instance_props = assign(switch_instance_props, switch_instance_spread_levels[i]);
        }
        if (dirty !== void 0 && dirty[0] & /*buttonsRight*/
        4) {
          switch_instance_props = assign(switch_instance_props, get_spread_update(switch_instance_spread_levels, [get_spread_object(
            /*button*/
            ctx2[31].props
          )]));
        }
        return { props: switch_instance_props };
      }
      if (switch_value) {
        switch_instance = construct_svelte_component(switch_value, switch_props(ctx));
      }
      return {
        c() {
          if (switch_instance) create_component(switch_instance.$$.fragment);
          switch_instance_anchor = empty();
        },
        m(target, anchor) {
          if (switch_instance) mount_component(switch_instance, target, anchor);
          insert(target, switch_instance_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*buttonsRight*/
          4 && switch_value !== (switch_value = /*button*/
          ctx2[31].class)) {
            if (switch_instance) {
              group_outros();
              const old_component = switch_instance;
              transition_out(old_component.$$.fragment, 1, 0, () => {
                destroy_component(old_component, 1);
              });
              check_outros();
            }
            if (switch_value) {
              switch_instance = construct_svelte_component(switch_value, switch_props(ctx2, dirty));
              create_component(switch_instance.$$.fragment);
              transition_in(switch_instance.$$.fragment, 1);
              mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
            } else {
              switch_instance = null;
            }
          } else if (switch_value) {
            const switch_instance_changes = dirty[0] & /*buttonsRight*/
            4 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
              /*button*/
              ctx2[31].props
            )]) : {};
            switch_instance.$set(switch_instance_changes);
          }
        },
        i(local) {
          if (current) return;
          if (switch_instance) transition_in(switch_instance.$$.fragment, local);
          current = true;
        },
        o(local) {
          if (switch_instance) transition_out(switch_instance.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(switch_instance_anchor);
          }
          if (switch_instance) destroy_component(switch_instance, detaching);
        }
      };
    }
    function create_key_block(ctx) {
      let header;
      let t0;
      let h4;
      let t1_value = localize(
        /*$storeTitle*/
        ctx[7]
      ) + "";
      let t1;
      let t2;
      let t3;
      let span;
      let t4;
      let draggable_action;
      let minimizable_action;
      let current;
      let mounted;
      let dispose;
      let if_block = typeof /*$storeHeaderIcon*/
      ctx[6] === "string" && create_if_block$c(ctx);
      let each_value_1 = ensure_array_like(
        /*buttonsLeft*/
        ctx[1]
      );
      let each_blocks_1 = [];
      for (let i = 0; i < each_value_1.length; i += 1) {
        each_blocks_1[i] = create_each_block_1$2(get_each_context_1$2(ctx, each_value_1, i));
      }
      const out = (i) => transition_out(each_blocks_1[i], 1, 1, () => {
        each_blocks_1[i] = null;
      });
      let each_value = ensure_array_like(
        /*buttonsRight*/
        ctx[2]
      );
      let each_blocks = [];
      for (let i = 0; i < each_value.length; i += 1) {
        each_blocks[i] = create_each_block$8(get_each_context$8(ctx, each_value, i));
      }
      const out_1 = (i) => transition_out(each_blocks[i], 1, 1, () => {
        each_blocks[i] = null;
      });
      return {
        c() {
          header = element("header");
          if (if_block) if_block.c();
          t0 = space();
          h4 = element("h4");
          t1 = text$1(t1_value);
          t2 = space();
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            each_blocks_1[i].c();
          }
          t3 = space();
          span = element("span");
          t4 = space();
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          attr(h4, "class", "window-title svelte-seq-5lh4qo");
          set_style(
            h4,
            "display",
            /*displayHeaderTitle*/
            ctx[4]
          );
          attr(span, "class", "tjs-window-header-spacer keep-minimized svelte-seq-5lh4qo");
          attr(header, "class", "window-header flexrow svelte-seq-5lh4qo");
        },
        m(target, anchor) {
          insert(target, header, anchor);
          if (if_block) if_block.m(header, null);
          append(header, t0);
          append(header, h4);
          append(h4, t1);
          append(header, t2);
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            if (each_blocks_1[i]) {
              each_blocks_1[i].m(header, null);
            }
          }
          append(header, t3);
          append(header, span);
          append(header, t4);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(header, null);
            }
          }
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                header,
                "pointerdown",
                /*onPointerdown*/
                ctx[19]
              ),
              action_destroyer(draggable_action = /*draggable*/
              ctx[0].call(
                null,
                header,
                /*dragOptions*/
                ctx[3]
              )),
              action_destroyer(minimizable_action = /*minimizable*/
              ctx[18].call(
                null,
                header,
                /*$storeMinimizable*/
                ctx[5]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (typeof /*$storeHeaderIcon*/
          ctx2[6] === "string") {
            if (if_block) {
              if_block.p(ctx2, dirty);
            } else {
              if_block = create_if_block$c(ctx2);
              if_block.c();
              if_block.m(header, t0);
            }
          } else if (if_block) {
            if_block.d(1);
            if_block = null;
          }
          if ((!current || dirty[0] & /*$storeTitle*/
          128) && t1_value !== (t1_value = localize(
            /*$storeTitle*/
            ctx2[7]
          ) + "")) set_data(t1, t1_value);
          if (dirty[0] & /*displayHeaderTitle*/
          16) {
            set_style(
              h4,
              "display",
              /*displayHeaderTitle*/
              ctx2[4]
            );
          }
          if (dirty[0] & /*buttonsLeft*/
          2) {
            each_value_1 = ensure_array_like(
              /*buttonsLeft*/
              ctx2[1]
            );
            let i;
            for (i = 0; i < each_value_1.length; i += 1) {
              const child_ctx = get_each_context_1$2(ctx2, each_value_1, i);
              if (each_blocks_1[i]) {
                each_blocks_1[i].p(child_ctx, dirty);
                transition_in(each_blocks_1[i], 1);
              } else {
                each_blocks_1[i] = create_each_block_1$2(child_ctx);
                each_blocks_1[i].c();
                transition_in(each_blocks_1[i], 1);
                each_blocks_1[i].m(header, t3);
              }
            }
            group_outros();
            for (i = each_value_1.length; i < each_blocks_1.length; i += 1) {
              out(i);
            }
            check_outros();
          }
          if (dirty[0] & /*buttonsRight*/
          4) {
            each_value = ensure_array_like(
              /*buttonsRight*/
              ctx2[2]
            );
            let i;
            for (i = 0; i < each_value.length; i += 1) {
              const child_ctx = get_each_context$8(ctx2, each_value, i);
              if (each_blocks[i]) {
                each_blocks[i].p(child_ctx, dirty);
                transition_in(each_blocks[i], 1);
              } else {
                each_blocks[i] = create_each_block$8(child_ctx);
                each_blocks[i].c();
                transition_in(each_blocks[i], 1);
                each_blocks[i].m(header, null);
              }
            }
            group_outros();
            for (i = each_value.length; i < each_blocks.length; i += 1) {
              out_1(i);
            }
            check_outros();
          }
          if (draggable_action && is_function(draggable_action.update) && dirty[0] & /*dragOptions*/
          8) draggable_action.update.call(
            null,
            /*dragOptions*/
            ctx2[3]
          );
          if (minimizable_action && is_function(minimizable_action.update) && dirty[0] & /*$storeMinimizable*/
          32) minimizable_action.update.call(
            null,
            /*$storeMinimizable*/
            ctx2[5]
          );
        },
        i(local) {
          if (current) return;
          for (let i = 0; i < each_value_1.length; i += 1) {
            transition_in(each_blocks_1[i]);
          }
          for (let i = 0; i < each_value.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          each_blocks_1 = each_blocks_1.filter(Boolean);
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            transition_out(each_blocks_1[i]);
          }
          each_blocks = each_blocks.filter(Boolean);
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(header);
          }
          if (if_block) if_block.d();
          destroy_each(each_blocks_1, detaching);
          destroy_each(each_blocks, detaching);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_fragment$s(ctx) {
      let previous_key = (
        /*draggable*/
        ctx[0]
      );
      let key_block_anchor;
      let current;
      let key_block = create_key_block(ctx);
      return {
        c() {
          key_block.c();
          key_block_anchor = empty();
        },
        m(target, anchor) {
          key_block.m(target, anchor);
          insert(target, key_block_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*draggable*/
          1 && safe_not_equal(previous_key, previous_key = /*draggable*/
          ctx2[0])) {
            group_outros();
            transition_out(key_block, 1, 1, noop);
            check_outros();
            key_block = create_key_block(ctx2);
            key_block.c();
            transition_in(key_block, 1);
            key_block.m(key_block_anchor.parentNode, key_block_anchor);
          } else {
            key_block.p(ctx2, dirty);
          }
        },
        i(local) {
          if (current) return;
          transition_in(key_block);
          current = true;
        },
        o(local) {
          transition_out(key_block);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(key_block_anchor);
          }
          key_block.d(detaching);
        }
      };
    }
    function instance$r($$self, $$props, $$invalidate) {
      let $focusKeep;
      let $focusAuto;
      let $elementRoot;
      let $storeHeaderButtons;
      let $storeMinimized;
      let $storeHeaderNoTitleMinimized;
      let $storeDraggable;
      let $storeMinimizable;
      let $storeHeaderIcon;
      let $storeTitle;
      let { draggable: draggable$1 = void 0 } = $$props;
      let { draggableOptions = void 0 } = $$props;
      const application = getContext("#external")?.application;
      const { focusAuto, focusKeep } = application.reactive.storeAppOptions;
      component_subscribe($$self, focusAuto, (value) => $$invalidate(26, $focusAuto = value));
      component_subscribe($$self, focusKeep, (value) => $$invalidate(25, $focusKeep = value));
      const { elementRoot } = getContext("#internal").stores;
      component_subscribe($$self, elementRoot, (value) => $$invalidate(27, $elementRoot = value));
      const storeTitle = application.reactive.storeAppOptions.title;
      component_subscribe($$self, storeTitle, (value) => $$invalidate(7, $storeTitle = value));
      const storeDraggable = application.reactive.storeAppOptions.draggable;
      component_subscribe($$self, storeDraggable, (value) => $$invalidate(24, $storeDraggable = value));
      const storeDragging = application.reactive.storeUIState.dragging;
      const storeHeaderButtons = application.reactive.storeUIState.headerButtons;
      component_subscribe($$self, storeHeaderButtons, (value) => $$invalidate(21, $storeHeaderButtons = value));
      const storeHeaderIcon = application.reactive.storeAppOptions.headerIcon;
      component_subscribe($$self, storeHeaderIcon, (value) => $$invalidate(6, $storeHeaderIcon = value));
      const storeHeaderNoTitleMinimized = application.reactive.storeAppOptions.headerNoTitleMinimized;
      component_subscribe($$self, storeHeaderNoTitleMinimized, (value) => $$invalidate(23, $storeHeaderNoTitleMinimized = value));
      const storeMinimizable = application.reactive.storeAppOptions.minimizable;
      component_subscribe($$self, storeMinimizable, (value) => $$invalidate(5, $storeMinimizable = value));
      const storeMinimized = application.reactive.storeUIState.minimized;
      component_subscribe($$self, storeMinimized, (value) => $$invalidate(22, $storeMinimized = value));
      const s_DRAG_TARGET_CLASSLIST = Object.freeze(["tjs-app-icon", "tjs-window-header-spacer", "window-header", "window-title"]);
      let dragOptions;
      let displayHeaderTitle;
      let buttonsLeft;
      let buttonsRight;
      function minimizable(node, booleanStore) {
        const callback = (event) => {
          if (event.target.classList.contains("window-title") || event.target.classList.contains("window-header") || event.target.classList.contains("keep-minimized")) {
            application._onToggleMinimize(event);
          }
        };
        function activateListeners() {
          node.addEventListener("dblclick", callback);
        }
        function removeListeners() {
          node.removeEventListener("dblclick", callback);
        }
        if (booleanStore) {
          activateListeners();
        }
        return {
          update: (booleanStore2) => {
            if (booleanStore2) {
              activateListeners();
            } else {
              removeListeners();
            }
          },
          destroy: () => removeListeners()
        };
      }
      function onPointerdown(event) {
        const rootEl = $elementRoot;
        application.position.animate.cancel();
        if ($focusAuto && A11yHelper.isFocusTarget(rootEl) && rootEl?.isConnected) {
          if ($focusKeep) {
            const activeWindow = application.reactive.activeWindow;
            const focusOutside = A11yHelper.isFocusTarget(activeWindow.document.activeElement) && !rootEl.contains(activeWindow.document.activeElement);
            if (focusOutside) {
              rootEl.focus();
            } else {
              event.preventDefault();
            }
          } else {
            rootEl.focus();
          }
        }
      }
      $$self.$$set = ($$props2) => {
        if ("draggable" in $$props2) $$invalidate(0, draggable$1 = $$props2.draggable);
        if ("draggableOptions" in $$props2) $$invalidate(20, draggableOptions = $$props2.draggableOptions);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty[0] & /*draggable*/
        1) {
          $$invalidate(0, draggable$1 = typeof draggable$1 === "function" ? draggable$1 : draggable);
        }
        if ($$self.$$.dirty[0] & /*draggableOptions, $storeDraggable*/
        17825792) {
          $$invalidate(3, dragOptions = Object.assign(
            {},
            {
              tween: true,
              tweenOptions: { duration: 0.06, ease: "cubicOut" }
            },
            isObject(draggableOptions) ? draggableOptions : {},
            {
              position: application.position,
              enabled: $storeDraggable,
              storeDragging,
              hasTargetClassList: s_DRAG_TARGET_CLASSLIST
            }
          ));
        }
        if ($$self.$$.dirty[0] & /*$storeHeaderNoTitleMinimized, $storeMinimized*/
        12582912) {
          $$invalidate(4, displayHeaderTitle = $storeHeaderNoTitleMinimized && $storeMinimized ? "none" : null);
        }
        if ($$self.$$.dirty[0] & /*$storeHeaderButtons, buttonsLeft, buttonsRight*/
        2097158) {
          {
            $$invalidate(1, buttonsLeft = []);
            $$invalidate(2, buttonsRight = []);
            for (const button of $storeHeaderButtons) {
              const buttonsList = typeof button?.alignLeft === "boolean" && button?.alignLeft ? buttonsLeft : buttonsRight;
              buttonsList.push(TJSSvelte.config.isConfigEmbed(button?.svelte) ? { ...button.svelte } : {
                class: TJSHeaderButton,
                props: { button }
              });
            }
          }
        }
      };
      return [
        draggable$1,
        buttonsLeft,
        buttonsRight,
        dragOptions,
        displayHeaderTitle,
        $storeMinimizable,
        $storeHeaderIcon,
        $storeTitle,
        focusAuto,
        focusKeep,
        elementRoot,
        storeTitle,
        storeDraggable,
        storeHeaderButtons,
        storeHeaderIcon,
        storeHeaderNoTitleMinimized,
        storeMinimizable,
        storeMinimized,
        minimizable,
        onPointerdown,
        draggableOptions,
        $storeHeaderButtons,
        $storeMinimized,
        $storeHeaderNoTitleMinimized,
        $storeDraggable
      ];
    }
    class TJSApplicationHeader extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$r, create_fragment$s, safe_not_equal, { draggable: 0, draggableOptions: 20 }, null, [-1, -1]);
      }
    }
    class ResizeHandleTransform {
      /**
       * Stores inverted app transform matrix.
       */
      static #invMat = new Mat4();
      /**
       * Stores converted world delta width & height change.
       */
      static #pDeltaLocal = new Vec3();
      /**
       * Stores point down in local space.
       */
      static #pLocalDown = new Vec3();
      /**
       * Stores point drag in local space.
       */
      static #pLocalDrag = new Vec3();
      /**
       * Stores point down in world space.
       */
      static #pScreenDown = new Vec3();
      /**
       * Stores point drag in world space.
       */
      static #pScreenDrag = new Vec3();
      /**
       * Compute the delta width and height in local space given the app transform matrix and initial pointer down and
       * drag screen coordinates.
       *
       * @param {Mat4} transformMat - App transform matrix.
       *
       * @param {number} pScreenDownX - Pointer down X position in screen coords.
       *
       * @param {number} pScreenDownY - Pointer down Y position in screen coords.
       *
       * @param {number} pScreenDragX - Current pointer drag X position in screen coords.
       *
       * @param {number} pScreenDragY - Current pointer drag Y position in screen coords.
       *
       * @returns {Vec3} Output vector for width & height changes (x = deltaWidth, y = deltaHeight).
       */
      static computeDelta(transformMat, pScreenDownX, pScreenDownY, pScreenDragX, pScreenDragY) {
        Mat4.invert(this.#invMat, transformMat);
        this.#pScreenDown[0] = pScreenDownX;
        this.#pScreenDown[1] = pScreenDownY;
        this.#pScreenDrag[0] = pScreenDragX;
        this.#pScreenDrag[1] = pScreenDragY;
        Vec3.transformMat4(this.#pLocalDown, this.#pScreenDown, this.#invMat);
        Vec3.transformMat4(this.#pLocalDrag, this.#pScreenDrag, this.#invMat);
        this.#pDeltaLocal[0] = this.#pLocalDrag[0] - this.#pLocalDown[0];
        this.#pDeltaLocal[1] = this.#pLocalDrag[1] - this.#pLocalDown[1];
        return this.#pDeltaLocal;
      }
    }
    function create_fragment$r(ctx) {
      let div;
      let resizable_action;
      let mounted;
      let dispose;
      return {
        c() {
          div = element("div");
          div.innerHTML = `<i class="fas fa-arrows-alt-h svelte-seq-gtiiil"></i>`;
          attr(div, "class", "window-resizable-handle svelte-seq-gtiiil");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          ctx[11](div);
          if (!mounted) {
            dispose = [
              listen(
                div,
                "pointerdown",
                /*onPointerdown*/
                ctx[6]
              ),
              action_destroyer(resizable_action = /*resizable*/
              ctx[7].call(null, div, {
                active: (
                  /*$storeResizable*/
                  ctx[1]
                ),
                storeResizing: (
                  /*storeResizing*/
                  ctx[5]
                )
              }))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (resizable_action && is_function(resizable_action.update) && dirty & /*$storeResizable*/
          2) resizable_action.update.call(null, {
            active: (
              /*$storeResizable*/
              ctx2[1]
            ),
            storeResizing: (
              /*storeResizing*/
              ctx2[5]
            )
          });
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          ctx[11](null);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$q($$self, $$props, $$invalidate) {
      let $storeElementRoot;
      let $storeMinimized;
      let $storeResizable;
      let { isResizable = false } = $$props;
      const application = getContext("#external")?.application;
      const storeElementRoot = getContext("#internal").stores.elementRoot;
      component_subscribe($$self, storeElementRoot, (value) => $$invalidate(9, $storeElementRoot = value));
      const storeResizable = application.reactive.storeAppOptions.resizable;
      component_subscribe($$self, storeResizable, (value) => $$invalidate(1, $storeResizable = value));
      const storeMinimized = application.reactive.storeUIState.minimized;
      component_subscribe($$self, storeMinimized, (value) => $$invalidate(10, $storeMinimized = value));
      const storeResizing = application.reactive.storeUIState.resizing;
      let elementResize;
      function onPointerdown() {
        application.position.animate.cancel();
      }
      function resizable(node, { active: active2 = true, storeResizing: storeResizing2 = void 0 } = {}) {
        let position = null;
        let resizing = false;
        let pScreenDownX = 0;
        let pScreenDownY = 0;
        const handlers = {
          resizeDown: ["pointerdown", (e) => onResizePointerDown(e), false],
          resizeMove: ["pointermove", (e) => onResizePointerMove(e), false],
          resizeUp: ["pointerup", (e) => onResizePointerUp(e), false]
        };
        function activateListeners() {
          node.addEventListener(...handlers.resizeDown);
          $$invalidate(8, isResizable = true);
          node.style.display = "block";
        }
        function removeListeners() {
          if (typeof storeResizing2?.set === "function") {
            storeResizing2.set(false);
          }
          node.removeEventListener(...handlers.resizeDown);
          node.removeEventListener(...handlers.resizeMove);
          node.removeEventListener(...handlers.resizeUp);
          node.style.display = "none";
          $$invalidate(8, isResizable = false);
        }
        if (active2) {
          activateListeners();
        } else {
          node.style.display = "none";
        }
        function onResizePointerDown(event) {
          event.preventDefault();
          resizing = false;
          position = application.position.get();
          if (position.height === "auto") {
            position.height = $storeElementRoot.clientHeight;
          }
          if (position.width === "auto") {
            position.width = $storeElementRoot.clientWidth;
          }
          pScreenDownX = event.clientX;
          pScreenDownY = event.clientY;
          node.addEventListener(...handlers.resizeMove);
          node.addEventListener(...handlers.resizeUp);
          node.setPointerCapture(event.pointerId);
        }
        function onResizePointerMove(event) {
          event.preventDefault();
          if (!resizing && typeof storeResizing2?.set === "function") {
            resizing = true;
            storeResizing2.set(true);
          }
          const pDeltaLocal = ResizeHandleTransform.computeDelta(application.position.transform.mat4, pScreenDownX, pScreenDownY, event.clientX, event.clientY);
          application.position.set({
            width: position.width + pDeltaLocal[0],
            height: position.height + pDeltaLocal[1]
          });
        }
        function onResizePointerUp(event) {
          resizing = false;
          if (typeof storeResizing2?.set === "function") {
            storeResizing2.set(false);
          }
          event.preventDefault();
          node.removeEventListener(...handlers.resizeMove);
          node.removeEventListener(...handlers.resizeUp);
          application?._onResize?.(event);
        }
        return {
          update: ({ active: active3 }) => {
            if (active3) {
              activateListeners();
            } else {
              removeListeners();
            }
          },
          destroy: () => removeListeners()
        };
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          elementResize = $$value;
          $$invalidate(0, elementResize), $$invalidate(8, isResizable), $$invalidate(10, $storeMinimized), $$invalidate(9, $storeElementRoot);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("isResizable" in $$props2) $$invalidate(8, isResizable = $$props2.isResizable);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*elementResize, isResizable, $storeMinimized, $storeElementRoot*/
        1793) {
          if (elementResize) {
            $$invalidate(0, elementResize.style.display = isResizable && !$storeMinimized ? "block" : "none", elementResize);
            const elementRoot = $storeElementRoot;
            if (elementRoot) {
              elementRoot.classList[isResizable ? "add" : "remove"]("resizable");
            }
          }
        }
      };
      return [
        elementResize,
        $storeResizable,
        storeElementRoot,
        storeResizable,
        storeMinimized,
        storeResizing,
        onPointerdown,
        resizable,
        isResizable,
        $storeElementRoot,
        $storeMinimized,
        div_binding
      ];
    }
    class ResizableHandle extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$q, create_fragment$r, safe_not_equal, { isResizable: 8 });
      }
    }
    function create_fragment$q(ctx) {
      let div;
      let mounted;
      let dispose;
      return {
        c() {
          div = element("div");
          attr(div, "class", "tjs-focus-wrap svelte-seq-kjcljd");
          attr(div, "tabindex", "0");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          ctx[4](div);
          if (!mounted) {
            dispose = listen(
              div,
              "focus",
              /*onFocus*/
              ctx[1]
            );
            mounted = true;
          }
        },
        p: noop,
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          ctx[4](null);
          mounted = false;
          dispose();
        }
      };
    }
    function instance$p($$self, $$props, $$invalidate) {
      let { elementRoot = void 0 } = $$props;
      let { enabled = true } = $$props;
      let ignoreElements, wrapEl;
      function onFocus() {
        if (!enabled) {
          return;
        }
        if (A11yHelper.isFocusTarget(elementRoot)) {
          const firstFocusEl = A11yHelper.getFirstFocusableElement(elementRoot, ignoreElements);
          if (A11yHelper.isFocusTarget(firstFocusEl) && firstFocusEl !== wrapEl) {
            firstFocusEl.focus();
          } else {
            elementRoot.focus();
          }
        }
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          wrapEl = $$value;
          $$invalidate(0, wrapEl);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("elementRoot" in $$props2) $$invalidate(2, elementRoot = $$props2.elementRoot);
        if ("enabled" in $$props2) $$invalidate(3, enabled = $$props2.enabled);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*wrapEl*/
        1) {
          if (wrapEl) {
            ignoreElements = /* @__PURE__ */ new Set([wrapEl]);
          }
        }
      };
      return [wrapEl, onFocus, elementRoot, enabled, div_binding];
    }
    class TJSFocusWrap extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$p, create_fragment$q, safe_not_equal, { elementRoot: 2, enabled: 3 });
      }
    }
    function create_else_block$4(ctx) {
      let div;
      let tjsapplicationheader;
      let t0;
      let section;
      let applyStyles_action;
      let t1;
      let resizablehandle;
      let t2;
      let tjsfocuswrap;
      let div_id_value;
      let div_class_value;
      let div_data_appid_value;
      let applyStyles_action_1;
      let dynamicAction_action;
      let current;
      let mounted;
      let dispose;
      tjsapplicationheader = new TJSApplicationHeader({
        props: {
          draggable: (
            /*draggable*/
            ctx[6]
          ),
          draggableOptions: (
            /*draggableOptions*/
            ctx[7]
          )
        }
      });
      const default_slot_template = (
        /*#slots*/
        ctx[37].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[36],
        null
      );
      resizablehandle = new ResizableHandle({});
      tjsfocuswrap = new TJSFocusWrap({
        props: {
          elementRoot: (
            /*elementRoot*/
            ctx[1]
          ),
          enabled: (
            /*focusWrapEnabled*/
            ctx[11]
          )
        }
      });
      return {
        c() {
          div = element("div");
          create_component(tjsapplicationheader.$$.fragment);
          t0 = space();
          section = element("section");
          if (default_slot) default_slot.c();
          t1 = space();
          create_component(resizablehandle.$$.fragment);
          t2 = space();
          create_component(tjsfocuswrap.$$.fragment);
          attr(section, "class", "window-content svelte-seq-90z1oq");
          attr(section, "tabindex", "-1");
          attr(div, "id", div_id_value = /*application*/
          ctx[10].id);
          attr(div, "class", div_class_value = "app window-app " + /*application*/
          ctx[10].options.classes.join(" ") + " svelte-seq-90z1oq");
          attr(div, "data-appid", div_data_appid_value = /*application*/
          ctx[10].appId);
          attr(div, "role", "application");
          attr(div, "tabindex", "-1");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          mount_component(tjsapplicationheader, div, null);
          append(div, t0);
          append(div, section);
          if (default_slot) {
            default_slot.m(section, null);
          }
          ctx[40](section);
          append(div, t1);
          mount_component(resizablehandle, div, null);
          append(div, t2);
          mount_component(tjsfocuswrap, div, null);
          ctx[41](div);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                section,
                "pointerdown",
                /*onPointerdownContent*/
                ctx[22]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                section,
                /*stylesContent*/
                ctx[9]
              )),
              action_destroyer(
                /*contentResizeObserver*/
                ctx[18].call(
                  null,
                  section,
                  /*resizeObservedContent*/
                  ctx[23]
                )
              ),
              listen(div, "close:popup", stop_propagation(prevent_default(
                /*onClosePopup*/
                ctx[19]
              ))),
              listen(
                div,
                "keydown",
                /*onKeydown*/
                ctx[20]
              ),
              listen(
                div,
                "pointerdown",
                /*onPointerdownApp*/
                ctx[21],
                true
              ),
              action_destroyer(applyStyles_action_1 = applyStyles.call(
                null,
                div,
                /*stylesApp*/
                ctx[8]
              )),
              action_destroyer(dynamicAction_action = dynamicAction.call(
                null,
                div,
                /*appResizeObserver*/
                ctx[12]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          const tjsapplicationheader_changes = {};
          if (dirty[0] & /*draggable*/
          64) tjsapplicationheader_changes.draggable = /*draggable*/
          ctx2[6];
          if (dirty[0] & /*draggableOptions*/
          128) tjsapplicationheader_changes.draggableOptions = /*draggableOptions*/
          ctx2[7];
          tjsapplicationheader.$set(tjsapplicationheader_changes);
          if (default_slot) {
            if (default_slot.p && (!current || dirty[1] & /*$$scope*/
            32)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx2,
                /*$$scope*/
                ctx2[36],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx2[36]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx2[36],
                  dirty,
                  null
                ),
                null
              );
            }
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty[0] & /*stylesContent*/
          512) applyStyles_action.update.call(
            null,
            /*stylesContent*/
            ctx2[9]
          );
          const tjsfocuswrap_changes = {};
          if (dirty[0] & /*elementRoot*/
          2) tjsfocuswrap_changes.elementRoot = /*elementRoot*/
          ctx2[1];
          if (dirty[0] & /*focusWrapEnabled*/
          2048) tjsfocuswrap_changes.enabled = /*focusWrapEnabled*/
          ctx2[11];
          tjsfocuswrap.$set(tjsfocuswrap_changes);
          if (!current || dirty[0] & /*application*/
          1024 && div_id_value !== (div_id_value = /*application*/
          ctx2[10].id)) {
            attr(div, "id", div_id_value);
          }
          if (!current || dirty[0] & /*application*/
          1024 && div_class_value !== (div_class_value = "app window-app " + /*application*/
          ctx2[10].options.classes.join(" ") + " svelte-seq-90z1oq")) {
            attr(div, "class", div_class_value);
          }
          if (!current || dirty[0] & /*application*/
          1024 && div_data_appid_value !== (div_data_appid_value = /*application*/
          ctx2[10].appId)) {
            attr(div, "data-appid", div_data_appid_value);
          }
          if (applyStyles_action_1 && is_function(applyStyles_action_1.update) && dirty[0] & /*stylesApp*/
          256) applyStyles_action_1.update.call(
            null,
            /*stylesApp*/
            ctx2[8]
          );
          if (dynamicAction_action && is_function(dynamicAction_action.update) && dirty[0] & /*appResizeObserver*/
          4096) dynamicAction_action.update.call(
            null,
            /*appResizeObserver*/
            ctx2[12]
          );
        },
        i(local) {
          if (current) return;
          transition_in(tjsapplicationheader.$$.fragment, local);
          transition_in(default_slot, local);
          transition_in(resizablehandle.$$.fragment, local);
          transition_in(tjsfocuswrap.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(tjsapplicationheader.$$.fragment, local);
          transition_out(default_slot, local);
          transition_out(resizablehandle.$$.fragment, local);
          transition_out(tjsfocuswrap.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          destroy_component(tjsapplicationheader);
          if (default_slot) default_slot.d(detaching);
          ctx[40](null);
          destroy_component(resizablehandle);
          destroy_component(tjsfocuswrap);
          ctx[41](null);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_if_block$b(ctx) {
      let div;
      let tjsapplicationheader;
      let t0;
      let section;
      let applyStyles_action;
      let t1;
      let resizablehandle;
      let t2;
      let tjsfocuswrap;
      let div_id_value;
      let div_class_value;
      let div_data_appid_value;
      let applyStyles_action_1;
      let dynamicAction_action;
      let div_intro;
      let div_outro;
      let current;
      let mounted;
      let dispose;
      tjsapplicationheader = new TJSApplicationHeader({
        props: {
          draggable: (
            /*draggable*/
            ctx[6]
          ),
          draggableOptions: (
            /*draggableOptions*/
            ctx[7]
          )
        }
      });
      const default_slot_template = (
        /*#slots*/
        ctx[37].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[36],
        null
      );
      resizablehandle = new ResizableHandle({});
      tjsfocuswrap = new TJSFocusWrap({
        props: { elementRoot: (
          /*elementRoot*/
          ctx[1]
        ) }
      });
      return {
        c() {
          div = element("div");
          create_component(tjsapplicationheader.$$.fragment);
          t0 = space();
          section = element("section");
          if (default_slot) default_slot.c();
          t1 = space();
          create_component(resizablehandle.$$.fragment);
          t2 = space();
          create_component(tjsfocuswrap.$$.fragment);
          attr(section, "class", "window-content svelte-seq-90z1oq");
          attr(section, "tabindex", "-1");
          attr(div, "id", div_id_value = /*application*/
          ctx[10].id);
          attr(div, "class", div_class_value = "app window-app " + /*application*/
          ctx[10].options.classes.join(" ") + " svelte-seq-90z1oq");
          attr(div, "data-appid", div_data_appid_value = /*application*/
          ctx[10].appId);
          attr(div, "role", "application");
          attr(div, "tabindex", "-1");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          mount_component(tjsapplicationheader, div, null);
          append(div, t0);
          append(div, section);
          if (default_slot) {
            default_slot.m(section, null);
          }
          ctx[38](section);
          append(div, t1);
          mount_component(resizablehandle, div, null);
          append(div, t2);
          mount_component(tjsfocuswrap, div, null);
          ctx[39](div);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                section,
                "pointerdown",
                /*onPointerdownContent*/
                ctx[22]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                section,
                /*stylesContent*/
                ctx[9]
              )),
              action_destroyer(
                /*contentResizeObserver*/
                ctx[18].call(
                  null,
                  section,
                  /*resizeObservedContent*/
                  ctx[23]
                )
              ),
              listen(div, "close:popup", stop_propagation(prevent_default(
                /*onClosePopup*/
                ctx[19]
              ))),
              listen(
                div,
                "keydown",
                /*onKeydown*/
                ctx[20]
              ),
              listen(
                div,
                "pointerdown",
                /*onPointerdownApp*/
                ctx[21],
                true
              ),
              action_destroyer(applyStyles_action_1 = applyStyles.call(
                null,
                div,
                /*stylesApp*/
                ctx[8]
              )),
              action_destroyer(dynamicAction_action = dynamicAction.call(
                null,
                div,
                /*appResizeObserver*/
                ctx[12]
              ))
            ];
            mounted = true;
          }
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const tjsapplicationheader_changes = {};
          if (dirty[0] & /*draggable*/
          64) tjsapplicationheader_changes.draggable = /*draggable*/
          ctx[6];
          if (dirty[0] & /*draggableOptions*/
          128) tjsapplicationheader_changes.draggableOptions = /*draggableOptions*/
          ctx[7];
          tjsapplicationheader.$set(tjsapplicationheader_changes);
          if (default_slot) {
            if (default_slot.p && (!current || dirty[1] & /*$$scope*/
            32)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx,
                /*$$scope*/
                ctx[36],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx[36]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx[36],
                  dirty,
                  null
                ),
                null
              );
            }
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty[0] & /*stylesContent*/
          512) applyStyles_action.update.call(
            null,
            /*stylesContent*/
            ctx[9]
          );
          const tjsfocuswrap_changes = {};
          if (dirty[0] & /*elementRoot*/
          2) tjsfocuswrap_changes.elementRoot = /*elementRoot*/
          ctx[1];
          tjsfocuswrap.$set(tjsfocuswrap_changes);
          if (!current || dirty[0] & /*application*/
          1024 && div_id_value !== (div_id_value = /*application*/
          ctx[10].id)) {
            attr(div, "id", div_id_value);
          }
          if (!current || dirty[0] & /*application*/
          1024 && div_class_value !== (div_class_value = "app window-app " + /*application*/
          ctx[10].options.classes.join(" ") + " svelte-seq-90z1oq")) {
            attr(div, "class", div_class_value);
          }
          if (!current || dirty[0] & /*application*/
          1024 && div_data_appid_value !== (div_data_appid_value = /*application*/
          ctx[10].appId)) {
            attr(div, "data-appid", div_data_appid_value);
          }
          if (applyStyles_action_1 && is_function(applyStyles_action_1.update) && dirty[0] & /*stylesApp*/
          256) applyStyles_action_1.update.call(
            null,
            /*stylesApp*/
            ctx[8]
          );
          if (dynamicAction_action && is_function(dynamicAction_action.update) && dirty[0] & /*appResizeObserver*/
          4096) dynamicAction_action.update.call(
            null,
            /*appResizeObserver*/
            ctx[12]
          );
        },
        i(local) {
          if (current) return;
          transition_in(tjsapplicationheader.$$.fragment, local);
          transition_in(default_slot, local);
          transition_in(resizablehandle.$$.fragment, local);
          transition_in(tjsfocuswrap.$$.fragment, local);
          add_render_callback(() => {
            if (!current) return;
            if (div_outro) div_outro.end(1);
            div_intro = create_in_transition(
              div,
              /*inTransition*/
              ctx[2],
              /*inTransitionOptions*/
              ctx[4]
            );
            div_intro.start();
          });
          current = true;
        },
        o(local) {
          transition_out(tjsapplicationheader.$$.fragment, local);
          transition_out(default_slot, local);
          transition_out(resizablehandle.$$.fragment, local);
          transition_out(tjsfocuswrap.$$.fragment, local);
          if (div_intro) div_intro.invalidate();
          div_outro = create_out_transition(
            div,
            /*outTransition*/
            ctx[3],
            /*outTransitionOptions*/
            ctx[5]
          );
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          destroy_component(tjsapplicationheader);
          if (default_slot) default_slot.d(detaching);
          ctx[38](null);
          destroy_component(resizablehandle);
          destroy_component(tjsfocuswrap);
          ctx[39](null);
          if (detaching && div_outro) div_outro.end();
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_fragment$p(ctx) {
      let current_block_type_index;
      let if_block;
      let if_block_anchor;
      let current;
      const if_block_creators = [create_if_block$b, create_else_block$4];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (
          /*inTransition*/
          ctx2[2] !== TJSDefaultTransition.default || /*outTransition*/
          ctx2[3] !== TJSDefaultTransition.default
        ) return 0;
        return 1;
      }
      current_block_type_index = select_block_type(ctx);
      if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      return {
        c() {
          if_block.c();
          if_block_anchor = empty();
        },
        m(target, anchor) {
          if_blocks[current_block_type_index].m(target, anchor);
          insert(target, if_block_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if_blocks[current_block_type_index].p(ctx2, dirty);
          } else {
            group_outros();
            transition_out(if_blocks[previous_block_index], 1, 1, () => {
              if_blocks[previous_block_index] = null;
            });
            check_outros();
            if_block = if_blocks[current_block_type_index];
            if (!if_block) {
              if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
              if_block.c();
            } else {
              if_block.p(ctx2, dirty);
            }
            transition_in(if_block, 1);
            if_block.m(if_block_anchor.parentNode, if_block_anchor);
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block);
          current = true;
        },
        o(local) {
          transition_out(if_block);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(if_block_anchor);
          }
          if_blocks[current_block_type_index].d(detaching);
        }
      };
    }
    function instance$o($$self, $$props, $$invalidate) {
      let appResizeObserver;
      let $focusKeep;
      let $focusAuto;
      let $minimized;
      let $focusTrap;
      let $resizeObservable;
      let { $$slots: slots = {}, $$scope } = $$props;
      let { elementContent = void 0 } = $$props;
      let { elementRoot = void 0 } = $$props;
      let { draggable: draggable2 = void 0 } = $$props;
      let { draggableOptions = void 0 } = $$props;
      let { stylesApp = void 0 } = $$props;
      let { stylesContent = void 0 } = $$props;
      const application = getContext("#external")?.application;
      const { focusAuto, focusKeep, focusTrap } = application.reactive.storeAppOptions;
      component_subscribe($$self, focusAuto, (value) => $$invalidate(32, $focusAuto = value));
      component_subscribe($$self, focusKeep, (value) => $$invalidate(42, $focusKeep = value));
      component_subscribe($$self, focusTrap, (value) => $$invalidate(34, $focusTrap = value));
      const { minimized } = application.reactive.storeUIState;
      component_subscribe($$self, minimized, (value) => $$invalidate(33, $minimized = value));
      const { resizeObservable } = application.position.stores;
      component_subscribe($$self, resizeObservable, (value) => $$invalidate(35, $resizeObservable = value));
      let { appOffsetHeight = false } = $$props;
      let { appOffsetWidth = false } = $$props;
      const initialAppResizeObserver = !!appOffsetHeight || !!appOffsetWidth;
      let { contentOffsetHeight = false } = $$props;
      let { contentOffsetWidth = false } = $$props;
      const contentResizeObserver = !!contentOffsetHeight || !!contentOffsetWidth ? resizeObserver : () => null;
      const internal = new AppShellContextInternal();
      const s_IGNORE_CLASSES = { ignoreClasses: ["tjs-focus-wrap"] };
      setContext("#internal", internal);
      let focusWrapEnabled;
      let { transition = TJSDefaultTransition.default } = $$props;
      let { inTransition = TJSDefaultTransition.default } = $$props;
      let { outTransition = TJSDefaultTransition.default } = $$props;
      let { transitionOptions = void 0 } = $$props;
      let { inTransitionOptions = TJSDefaultTransition.options } = $$props;
      let { outTransitionOptions = TJSDefaultTransition.options } = $$props;
      let oldTransition = TJSDefaultTransition.default;
      let oldTransitionOptions = void 0;
      onMount(() => elementRoot.focus());
      function onClosePopup(event) {
        if (!$focusAuto) {
          return;
        }
        const targetEl = event?.detail?.target;
        if (!A11yHelper.isFocusTarget(targetEl)) {
          return;
        }
        if (A11yHelper.isFocusable(targetEl)) {
          return;
        }
        const elementRootContains = elementRoot.contains(targetEl);
        if (targetEl === elementRoot) {
          elementRoot.focus();
        } else if (targetEl === elementContent) {
          elementContent.focus();
        } else if (elementRootContains) {
          if (elementContent.contains(targetEl)) {
            elementContent.focus();
          } else {
            elementRoot.focus();
          }
        }
      }
      function onKeydown(event) {
        if ((event.target === elementRoot || event.target === elementContent) && KeyboardManager && KeyboardManager?._getMatchingActions?.(KeyboardManager?.getKeyboardEventContext?.(event))?.length) {
          event.target?.blur();
          return;
        }
        if (focusWrapEnabled && event.shiftKey && event.code === "Tab") {
          const allFocusable = A11yHelper.getFocusableElements(elementRoot, s_IGNORE_CLASSES);
          const firstFocusEl = allFocusable.length > 0 ? allFocusable[0] : void 0;
          const lastFocusEl = allFocusable.length > 0 ? allFocusable[allFocusable.length - 1] : void 0;
          const activeWindow = application.reactive.activeWindow;
          if (elementRoot === activeWindow.document.activeElement || firstFocusEl === activeWindow.document.activeElement) {
            if (A11yHelper.isFocusTarget(lastFocusEl) && firstFocusEl !== lastFocusEl) {
              lastFocusEl.focus();
            }
            event.preventDefault();
            event.stopPropagation();
          }
        }
        if (typeof application?.options?.popOut === "boolean" && application.options.popOut && application !== globalThis.ui?.activeWindow) {
          application.bringToTop.call(application);
        }
      }
      function onPointerdownApp() {
        if (typeof application?.options?.popOut === "boolean" && application.options.popOut && application !== globalThis.ui?.activeWindow) {
          application.bringToTop.call(application);
        }
      }
      function onPointerdownContent(event) {
        const focusable = A11yHelper.isFocusable(event.target);
        if (!focusable && $focusAuto) {
          if ($focusKeep) {
            const activeWindow = application.reactive.activeWindow;
            const focusOutside = !elementRoot.contains(activeWindow.document.activeElement);
            if (focusOutside) {
              elementContent.focus();
            } else {
              event.preventDefault();
            }
          } else {
            elementContent.focus();
          }
        }
      }
      function resizeObservedContent(offsetWidth, offsetHeight) {
        $$invalidate(27, contentOffsetWidth = offsetWidth);
        $$invalidate(26, contentOffsetHeight = offsetHeight);
      }
      function resizeObservedApp(offsetWidth, offsetHeight, contentWidth, contentHeight) {
        application.position.stores.resizeObserved.update((object) => {
          object.contentWidth = contentWidth;
          object.contentHeight = contentHeight;
          object.offsetWidth = offsetWidth;
          object.offsetHeight = offsetHeight;
          return object;
        });
        $$invalidate(24, appOffsetHeight = offsetHeight);
        $$invalidate(25, appOffsetWidth = offsetWidth);
      }
      function section_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          elementContent = $$value;
          $$invalidate(0, elementContent);
        });
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          elementRoot = $$value;
          $$invalidate(1, elementRoot);
        });
      }
      function section_binding_1($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          elementContent = $$value;
          $$invalidate(0, elementContent);
        });
      }
      function div_binding_1($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          elementRoot = $$value;
          $$invalidate(1, elementRoot);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("elementContent" in $$props2) $$invalidate(0, elementContent = $$props2.elementContent);
        if ("elementRoot" in $$props2) $$invalidate(1, elementRoot = $$props2.elementRoot);
        if ("draggable" in $$props2) $$invalidate(6, draggable2 = $$props2.draggable);
        if ("draggableOptions" in $$props2) $$invalidate(7, draggableOptions = $$props2.draggableOptions);
        if ("stylesApp" in $$props2) $$invalidate(8, stylesApp = $$props2.stylesApp);
        if ("stylesContent" in $$props2) $$invalidate(9, stylesContent = $$props2.stylesContent);
        if ("appOffsetHeight" in $$props2) $$invalidate(24, appOffsetHeight = $$props2.appOffsetHeight);
        if ("appOffsetWidth" in $$props2) $$invalidate(25, appOffsetWidth = $$props2.appOffsetWidth);
        if ("contentOffsetHeight" in $$props2) $$invalidate(26, contentOffsetHeight = $$props2.contentOffsetHeight);
        if ("contentOffsetWidth" in $$props2) $$invalidate(27, contentOffsetWidth = $$props2.contentOffsetWidth);
        if ("transition" in $$props2) $$invalidate(28, transition = $$props2.transition);
        if ("inTransition" in $$props2) $$invalidate(2, inTransition = $$props2.inTransition);
        if ("outTransition" in $$props2) $$invalidate(3, outTransition = $$props2.outTransition);
        if ("transitionOptions" in $$props2) $$invalidate(29, transitionOptions = $$props2.transitionOptions);
        if ("inTransitionOptions" in $$props2) $$invalidate(4, inTransitionOptions = $$props2.inTransitionOptions);
        if ("outTransitionOptions" in $$props2) $$invalidate(5, outTransitionOptions = $$props2.outTransitionOptions);
        if ("$$scope" in $$props2) $$invalidate(36, $$scope = $$props2.$$scope);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty[1] & /*$resizeObservable*/
        16) {
          $$invalidate(12, appResizeObserver = initialAppResizeObserver || $resizeObservable ? {
            action: resizeObserver,
            data: resizeObservedApp
          } : void 0);
        }
        if ($$self.$$.dirty[0] & /*elementContent*/
        1) {
          if (elementContent !== void 0 && elementContent !== null) {
            getContext("#internal").stores.elementContent.set(elementContent);
          }
        }
        if ($$self.$$.dirty[0] & /*elementRoot*/
        2) {
          if (elementRoot !== void 0 && elementRoot !== null) {
            getContext("#internal").stores.elementRoot.set(elementRoot);
          }
        }
        if ($$self.$$.dirty[1] & /*$focusAuto, $focusTrap, $minimized*/
        14) {
          $$invalidate(11, focusWrapEnabled = $focusAuto && $focusTrap && !$minimized);
        }
        if ($$self.$$.dirty[0] & /*oldTransition, transition*/
        1342177280) {
          if (oldTransition !== transition) {
            const newTransition = typeof transition === "function" ? transition : TJSDefaultTransition.default;
            $$invalidate(2, inTransition = newTransition);
            $$invalidate(3, outTransition = newTransition);
            $$invalidate(30, oldTransition = newTransition);
          }
        }
        if ($$self.$$.dirty[0] & /*transitionOptions*/
        536870912 | $$self.$$.dirty[1] & /*oldTransitionOptions*/
        1) {
          if (oldTransitionOptions !== transitionOptions) {
            const newOptions = transitionOptions !== TJSDefaultTransition.options && isObject(transitionOptions) ? transitionOptions : TJSDefaultTransition.options;
            $$invalidate(4, inTransitionOptions = newOptions);
            $$invalidate(5, outTransitionOptions = newOptions);
            $$invalidate(31, oldTransitionOptions = newOptions);
          }
        }
        if ($$self.$$.dirty[0] & /*inTransition*/
        4) {
          if (typeof inTransition !== "function") {
            $$invalidate(2, inTransition = TJSDefaultTransition.default);
          }
        }
        if ($$self.$$.dirty[0] & /*outTransition, application*/
        1032) {
          {
            if (typeof outTransition !== "function") {
              $$invalidate(3, outTransition = TJSDefaultTransition.default);
            }
            const defaultCloseAnimation = application?.options?.defaultCloseAnimation;
            if (typeof defaultCloseAnimation === "boolean" && defaultCloseAnimation && outTransition !== TJSDefaultTransition.default) {
              $$invalidate(10, application.options.defaultCloseAnimation = false, application);
            }
          }
        }
        if ($$self.$$.dirty[0] & /*inTransitionOptions*/
        16) {
          if (!isObject(inTransitionOptions)) {
            $$invalidate(4, inTransitionOptions = TJSDefaultTransition.options);
          }
        }
        if ($$self.$$.dirty[0] & /*outTransitionOptions*/
        32) {
          if (!isObject(outTransitionOptions)) {
            $$invalidate(5, outTransitionOptions = TJSDefaultTransition.options);
          }
        }
      };
      return [
        elementContent,
        elementRoot,
        inTransition,
        outTransition,
        inTransitionOptions,
        outTransitionOptions,
        draggable2,
        draggableOptions,
        stylesApp,
        stylesContent,
        application,
        focusWrapEnabled,
        appResizeObserver,
        focusAuto,
        focusKeep,
        focusTrap,
        minimized,
        resizeObservable,
        contentResizeObserver,
        onClosePopup,
        onKeydown,
        onPointerdownApp,
        onPointerdownContent,
        resizeObservedContent,
        appOffsetHeight,
        appOffsetWidth,
        contentOffsetHeight,
        contentOffsetWidth,
        transition,
        transitionOptions,
        oldTransition,
        oldTransitionOptions,
        $focusAuto,
        $minimized,
        $focusTrap,
        $resizeObservable,
        $$scope,
        slots,
        section_binding,
        div_binding,
        section_binding_1,
        div_binding_1
      ];
    }
    class ApplicationShell extends SvelteComponent {
      constructor(options) {
        super();
        init(
          this,
          options,
          instance$o,
          create_fragment$p,
          safe_not_equal,
          {
            elementContent: 0,
            elementRoot: 1,
            draggable: 6,
            draggableOptions: 7,
            stylesApp: 8,
            stylesContent: 9,
            appOffsetHeight: 24,
            appOffsetWidth: 25,
            contentOffsetHeight: 26,
            contentOffsetWidth: 27,
            transition: 28,
            inTransition: 2,
            outTransition: 3,
            transitionOptions: 29,
            inTransitionOptions: 4,
            outTransitionOptions: 5
          },
          null,
          [-1, -1]
        );
      }
      get elementContent() {
        return this.$$.ctx[0];
      }
      set elementContent(elementContent) {
        this.$$set({ elementContent });
        flush();
      }
      get elementRoot() {
        return this.$$.ctx[1];
      }
      set elementRoot(elementRoot) {
        this.$$set({ elementRoot });
        flush();
      }
      get draggable() {
        return this.$$.ctx[6];
      }
      set draggable(draggable2) {
        this.$$set({ draggable: draggable2 });
        flush();
      }
      get draggableOptions() {
        return this.$$.ctx[7];
      }
      set draggableOptions(draggableOptions) {
        this.$$set({ draggableOptions });
        flush();
      }
      get stylesApp() {
        return this.$$.ctx[8];
      }
      set stylesApp(stylesApp) {
        this.$$set({ stylesApp });
        flush();
      }
      get stylesContent() {
        return this.$$.ctx[9];
      }
      set stylesContent(stylesContent) {
        this.$$set({ stylesContent });
        flush();
      }
      get appOffsetHeight() {
        return this.$$.ctx[24];
      }
      set appOffsetHeight(appOffsetHeight) {
        this.$$set({ appOffsetHeight });
        flush();
      }
      get appOffsetWidth() {
        return this.$$.ctx[25];
      }
      set appOffsetWidth(appOffsetWidth) {
        this.$$set({ appOffsetWidth });
        flush();
      }
      get contentOffsetHeight() {
        return this.$$.ctx[26];
      }
      set contentOffsetHeight(contentOffsetHeight) {
        this.$$set({ contentOffsetHeight });
        flush();
      }
      get contentOffsetWidth() {
        return this.$$.ctx[27];
      }
      set contentOffsetWidth(contentOffsetWidth) {
        this.$$set({ contentOffsetWidth });
        flush();
      }
      get transition() {
        return this.$$.ctx[28];
      }
      set transition(transition) {
        this.$$set({ transition });
        flush();
      }
      get inTransition() {
        return this.$$.ctx[2];
      }
      set inTransition(inTransition) {
        this.$$set({ inTransition });
        flush();
      }
      get outTransition() {
        return this.$$.ctx[3];
      }
      set outTransition(outTransition) {
        this.$$set({ outTransition });
        flush();
      }
      get transitionOptions() {
        return this.$$.ctx[29];
      }
      set transitionOptions(transitionOptions) {
        this.$$set({ transitionOptions });
        flush();
      }
      get inTransitionOptions() {
        return this.$$.ctx[4];
      }
      set inTransitionOptions(inTransitionOptions) {
        this.$$set({ inTransitionOptions });
        flush();
      }
      get outTransitionOptions() {
        return this.$$.ctx[5];
      }
      set outTransitionOptions(outTransitionOptions) {
        this.$$set({ outTransitionOptions });
        flush();
      }
    }
    function create_else_block$3(ctx) {
      let div;
      let applyStyles_action;
      let div_intro;
      let div_outro;
      let current;
      let mounted;
      let dispose;
      const default_slot_template = (
        /*#slots*/
        ctx[20].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[19],
        null
      );
      return {
        c() {
          div = element("div");
          if (default_slot) default_slot.c();
          attr(div, "class", "tjs-glass-pane-background tjs-glass-pane-container svelte-seq-hqedxf");
          set_style(
            div,
            "background",
            /*background*/
            ctx[5]
          );
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if (default_slot) {
            default_slot.m(div, null);
          }
          ctx[26](div);
          current = true;
          if (!mounted) {
            dispose = action_destroyer(applyStyles_action = applyStyles.call(
              null,
              div,
              /*styles*/
              ctx[7]
            ));
            mounted = true;
          }
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          if (default_slot) {
            if (default_slot.p && (!current || dirty & /*$$scope*/
            524288)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx,
                /*$$scope*/
                ctx[19],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx[19]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx[19],
                  dirty,
                  null
                ),
                null
              );
            }
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          128) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx[7]
          );
          if (dirty & /*background*/
          32) {
            set_style(
              div,
              "background",
              /*background*/
              ctx[5]
            );
          }
        },
        i(local) {
          if (current) return;
          transition_in(default_slot, local);
          add_render_callback(() => {
            if (!current) return;
            if (div_outro) div_outro.end(1);
            div_intro = create_in_transition(
              div,
              /*inTransition*/
              ctx[1],
              /*inTransitionOptions*/
              ctx[3]
            );
            div_intro.start();
          });
          current = true;
        },
        o(local) {
          transition_out(default_slot, local);
          if (div_intro) div_intro.invalidate();
          div_outro = create_out_transition(
            div,
            /*outTransition*/
            ctx[2],
            /*outTransitionOptions*/
            ctx[4]
          );
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if (default_slot) default_slot.d(detaching);
          ctx[26](null);
          if (detaching && div_outro) div_outro.end();
          mounted = false;
          dispose();
        }
      };
    }
    function create_if_block$a(ctx) {
      let div0;
      let applyStyles_action;
      let div0_intro;
      let div0_outro;
      let t;
      let div1;
      let current;
      let mounted;
      let dispose;
      const default_slot_template = (
        /*#slots*/
        ctx[20].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[19],
        null
      );
      return {
        c() {
          div0 = element("div");
          t = space();
          div1 = element("div");
          if (default_slot) default_slot.c();
          attr(div0, "class", "tjs-glass-pane-background svelte-seq-hqedxf");
          set_style(
            div0,
            "background",
            /*background*/
            ctx[5]
          );
          attr(div1, "class", "tjs-glass-pane-container svelte-seq-hqedxf");
        },
        m(target, anchor) {
          insert(target, div0, anchor);
          ctx[24](div0);
          insert(target, t, anchor);
          insert(target, div1, anchor);
          if (default_slot) {
            default_slot.m(div1, null);
          }
          ctx[25](div1);
          current = true;
          if (!mounted) {
            dispose = action_destroyer(applyStyles_action = applyStyles.call(
              null,
              div0,
              /*styles*/
              ctx[7]
            ));
            mounted = true;
          }
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          128) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx[7]
          );
          if (dirty & /*background*/
          32) {
            set_style(
              div0,
              "background",
              /*background*/
              ctx[5]
            );
          }
          if (default_slot) {
            if (default_slot.p && (!current || dirty & /*$$scope*/
            524288)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx,
                /*$$scope*/
                ctx[19],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx[19]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx[19],
                  dirty,
                  null
                ),
                null
              );
            }
          }
        },
        i(local) {
          if (current) return;
          add_render_callback(() => {
            if (!current) return;
            if (div0_outro) div0_outro.end(1);
            div0_intro = create_in_transition(
              div0,
              /*inTransition*/
              ctx[1],
              /*inTransitionOptions*/
              ctx[3]
            );
            div0_intro.start();
          });
          transition_in(default_slot, local);
          current = true;
        },
        o(local) {
          if (div0_intro) div0_intro.invalidate();
          div0_outro = create_out_transition(
            div0,
            /*outTransition*/
            ctx[2],
            /*outTransitionOptions*/
            ctx[4]
          );
          transition_out(default_slot, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div0);
            detach(t);
            detach(div1);
          }
          ctx[24](null);
          if (detaching && div0_outro) div0_outro.end();
          if (default_slot) default_slot.d(detaching);
          ctx[25](null);
          mounted = false;
          dispose();
        }
      };
    }
    function create_fragment$o(ctx) {
      let div;
      let current_block_type_index;
      let if_block;
      let current;
      let mounted;
      let dispose;
      const if_block_creators = [create_if_block$a, create_else_block$3];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (
          /*slotSeparate*/
          ctx2[0]
        ) return 0;
        return 1;
      }
      current_block_type_index = select_block_type(ctx);
      if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      return {
        c() {
          div = element("div");
          if_block.c();
          attr(
            div,
            "id",
            /*id*/
            ctx[6]
          );
          attr(div, "class", "tjs-glass-pane svelte-seq-hqedxf");
          set_style(
            div,
            "z-index",
            /*zIndex*/
            ctx[8]
          );
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if_blocks[current_block_type_index].m(div, null);
          ctx[27](div);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                window,
                "contextmenu",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "dblclick",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "keydown",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "keyup",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "mousedown",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "mousemove",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "mouseup",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "pointerdown",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "pointermove",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "pointerup",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "touchend",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "touchmove",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "touchstart",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                window,
                "wheel",
                /*swallow*/
                ctx[12],
                true
              ),
              listen(
                div,
                "glasspane:close",
                /*glasspane_close_handler*/
                ctx[21]
              ),
              listen(
                div,
                "glasspane:keydown:escape",
                /*glasspane_keydown_escape_handler*/
                ctx[22]
              ),
              listen(
                div,
                "glasspane:pointerdown",
                /*glasspane_pointerdown_handler*/
                ctx[23]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if_blocks[current_block_type_index].p(ctx2, dirty);
          } else {
            group_outros();
            transition_out(if_blocks[previous_block_index], 1, 1, () => {
              if_blocks[previous_block_index] = null;
            });
            check_outros();
            if_block = if_blocks[current_block_type_index];
            if (!if_block) {
              if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
              if_block.c();
            } else {
              if_block.p(ctx2, dirty);
            }
            transition_in(if_block, 1);
            if_block.m(div, null);
          }
          if (!current || dirty & /*id*/
          64) {
            attr(
              div,
              "id",
              /*id*/
              ctx2[6]
            );
          }
          if (dirty & /*zIndex*/
          256) {
            set_style(
              div,
              "z-index",
              /*zIndex*/
              ctx2[8]
            );
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block);
          current = true;
        },
        o(local) {
          transition_out(if_block);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if_blocks[current_block_type_index].d();
          ctx[27](null);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$n($$self, $$props, $$invalidate) {
      let { $$slots: slots = {}, $$scope } = $$props;
      let { background = "#50505080" } = $$props;
      let { captureInput = true } = $$props;
      let { closeOnInput = void 0 } = $$props;
      let { id = void 0 } = $$props;
      let { slotSeparate = void 0 } = $$props;
      let { styles = void 0 } = $$props;
      let { zIndex = Number.MAX_SAFE_INTEGER } = $$props;
      let backgroundEl, containerEl, glassPaneEl;
      let { transition = void 0 } = $$props;
      let { inTransition = void 0 } = $$props;
      let { outTransition = void 0 } = $$props;
      let { transitionOptions = void 0 } = $$props;
      let { inTransitionOptions = TJSDefaultTransition.options } = $$props;
      let { outTransitionOptions = TJSDefaultTransition.options } = $$props;
      let oldTransition = void 0;
      let oldTransitionOptions = void 0;
      function swallow(event) {
        const targetEl = event.target;
        if (event?.type === "keydown" && event?.code === "Escape") {
          glassPaneEl.dispatchEvent(new CustomEvent("glasspane:keydown:escape", { bubbles: true, cancelable: true }));
        }
        if (targetEl !== glassPaneEl && targetEl !== backgroundEl && targetEl !== containerEl && glassPaneEl.contains(CrossWindow.isNode(targetEl) ? targetEl : null)) {
          return;
        }
        if (captureInput) {
          if (event?.type !== "wheel") {
            event.preventDefault();
          }
          event.stopImmediatePropagation();
        }
        if (event?.type === "pointerdown") {
          glassPaneEl.dispatchEvent(new CustomEvent("glasspane:pointerdown", { bubbles: true, cancelable: true }));
          if (closeOnInput) {
            glassPaneEl.dispatchEvent(new CustomEvent("glasspane:close", { bubbles: true, cancelable: true }));
          }
        }
      }
      function glasspane_close_handler(event) {
        bubble.call(this, $$self, event);
      }
      function glasspane_keydown_escape_handler(event) {
        bubble.call(this, $$self, event);
      }
      function glasspane_pointerdown_handler(event) {
        bubble.call(this, $$self, event);
      }
      function div0_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          backgroundEl = $$value;
          $$invalidate(9, backgroundEl);
        });
      }
      function div1_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          containerEl = $$value;
          $$invalidate(10, containerEl);
        });
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          backgroundEl = $$value;
          $$invalidate(9, backgroundEl);
        });
      }
      function div_binding_1($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          glassPaneEl = $$value;
          $$invalidate(11, glassPaneEl);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("background" in $$props2) $$invalidate(5, background = $$props2.background);
        if ("captureInput" in $$props2) $$invalidate(13, captureInput = $$props2.captureInput);
        if ("closeOnInput" in $$props2) $$invalidate(14, closeOnInput = $$props2.closeOnInput);
        if ("id" in $$props2) $$invalidate(6, id = $$props2.id);
        if ("slotSeparate" in $$props2) $$invalidate(0, slotSeparate = $$props2.slotSeparate);
        if ("styles" in $$props2) $$invalidate(7, styles = $$props2.styles);
        if ("zIndex" in $$props2) $$invalidate(8, zIndex = $$props2.zIndex);
        if ("transition" in $$props2) $$invalidate(15, transition = $$props2.transition);
        if ("inTransition" in $$props2) $$invalidate(1, inTransition = $$props2.inTransition);
        if ("outTransition" in $$props2) $$invalidate(2, outTransition = $$props2.outTransition);
        if ("transitionOptions" in $$props2) $$invalidate(16, transitionOptions = $$props2.transitionOptions);
        if ("inTransitionOptions" in $$props2) $$invalidate(3, inTransitionOptions = $$props2.inTransitionOptions);
        if ("outTransitionOptions" in $$props2) $$invalidate(4, outTransitionOptions = $$props2.outTransitionOptions);
        if ("$$scope" in $$props2) $$invalidate(19, $$scope = $$props2.$$scope);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*slotSeparate*/
        1) {
          $$invalidate(0, slotSeparate = typeof slotSeparate === "boolean" ? slotSeparate : false);
        }
        if ($$self.$$.dirty & /*oldTransition, transition*/
        163840) {
          if (oldTransition !== transition) {
            const newTransition = typeof transition === "function" ? transition : void 0;
            $$invalidate(1, inTransition = newTransition);
            $$invalidate(2, outTransition = newTransition);
            $$invalidate(17, oldTransition = newTransition);
          }
        }
        if ($$self.$$.dirty & /*oldTransitionOptions, transitionOptions*/
        327680) {
          if (oldTransitionOptions !== transitionOptions) {
            const newOptions = transitionOptions !== TJSDefaultTransition.options && isObject(transitionOptions) ? transitionOptions : TJSDefaultTransition.options;
            $$invalidate(3, inTransitionOptions = newOptions);
            $$invalidate(4, outTransitionOptions = newOptions);
            $$invalidate(18, oldTransitionOptions = newOptions);
          }
        }
        if ($$self.$$.dirty & /*inTransition*/
        2) {
          if (typeof inTransition !== "function") {
            $$invalidate(1, inTransition = void 0);
          }
        }
        if ($$self.$$.dirty & /*outTransition*/
        4) {
          if (typeof outTransition !== "function") {
            $$invalidate(2, outTransition = void 0);
          }
        }
        if ($$self.$$.dirty & /*inTransitionOptions*/
        8) {
          if (!isObject(inTransitionOptions)) {
            $$invalidate(3, inTransitionOptions = TJSDefaultTransition.options);
          }
        }
        if ($$self.$$.dirty & /*outTransitionOptions*/
        16) {
          if (!isObject(outTransitionOptions)) {
            $$invalidate(4, outTransitionOptions = TJSDefaultTransition.options);
          }
        }
      };
      return [
        slotSeparate,
        inTransition,
        outTransition,
        inTransitionOptions,
        outTransitionOptions,
        background,
        id,
        styles,
        zIndex,
        backgroundEl,
        containerEl,
        glassPaneEl,
        swallow,
        captureInput,
        closeOnInput,
        transition,
        transitionOptions,
        oldTransition,
        oldTransitionOptions,
        $$scope,
        slots,
        glasspane_close_handler,
        glasspane_keydown_escape_handler,
        glasspane_pointerdown_handler,
        div0_binding,
        div1_binding,
        div_binding,
        div_binding_1
      ];
    }
    class TJSGlassPane extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$n, create_fragment$o, safe_not_equal, {
          background: 5,
          captureInput: 13,
          closeOnInput: 14,
          id: 6,
          slotSeparate: 0,
          styles: 7,
          zIndex: 8,
          transition: 15,
          inTransition: 1,
          outTransition: 2,
          transitionOptions: 16,
          inTransitionOptions: 3,
          outTransitionOptions: 4
        });
      }
    }
    cssVariables.setProperties({
      // Anchor text shadow / header buttons
      "--tjs-default-text-shadow-focus-hover": "0 0 8px var(--color-shadow-primary)",
      // TJSApplicationShell app background.
      "--tjs-app-background": `url("${globalThis.foundry.utils.getRoute("/ui/denim075.png")}")`
    }, false);
    function get_each_context$7(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[26] = list[i];
      return child_ctx;
    }
    function create_if_block_3$1(ctx) {
      let switch_instance;
      let switch_instance_anchor;
      let current;
      const switch_instance_spread_levels = [
        /*dialogProps*/
        ctx[7]
      ];
      var switch_value = (
        /*dialogClass*/
        ctx[6]
      );
      function switch_props(ctx2, dirty) {
        let switch_instance_props = {};
        for (let i = 0; i < switch_instance_spread_levels.length; i += 1) {
          switch_instance_props = assign(switch_instance_props, switch_instance_spread_levels[i]);
        }
        if (dirty !== void 0 && dirty & /*dialogProps*/
        128) {
          switch_instance_props = assign(switch_instance_props, get_spread_update(switch_instance_spread_levels, [get_spread_object(
            /*dialogProps*/
            ctx2[7]
          )]));
        }
        return { props: switch_instance_props };
      }
      if (switch_value) {
        switch_instance = construct_svelte_component(switch_value, switch_props(ctx));
        ctx[16](switch_instance);
      }
      return {
        c() {
          if (switch_instance) create_component(switch_instance.$$.fragment);
          switch_instance_anchor = empty();
        },
        m(target, anchor) {
          if (switch_instance) mount_component(switch_instance, target, anchor);
          insert(target, switch_instance_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty & /*dialogClass*/
          64 && switch_value !== (switch_value = /*dialogClass*/
          ctx2[6])) {
            if (switch_instance) {
              group_outros();
              const old_component = switch_instance;
              transition_out(old_component.$$.fragment, 1, 0, () => {
                destroy_component(old_component, 1);
              });
              check_outros();
            }
            if (switch_value) {
              switch_instance = construct_svelte_component(switch_value, switch_props(ctx2, dirty));
              ctx2[16](switch_instance);
              create_component(switch_instance.$$.fragment);
              transition_in(switch_instance.$$.fragment, 1);
              mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
            } else {
              switch_instance = null;
            }
          } else if (switch_value) {
            const switch_instance_changes = dirty & /*dialogProps*/
            128 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
              /*dialogProps*/
              ctx2[7]
            )]) : {};
            switch_instance.$set(switch_instance_changes);
          }
        },
        i(local) {
          if (current) return;
          if (switch_instance) transition_in(switch_instance.$$.fragment, local);
          current = true;
        },
        o(local) {
          if (switch_instance) transition_out(switch_instance.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(switch_instance_anchor);
          }
          ctx[16](null);
          if (switch_instance) destroy_component(switch_instance, detaching);
        }
      };
    }
    function create_if_block_2$2(ctx) {
      let html_tag;
      let html_anchor;
      return {
        c() {
          html_tag = new HtmlTag(false);
          html_anchor = empty();
          html_tag.a = html_anchor;
        },
        m(target, anchor) {
          html_tag.m(
            /*content*/
            ctx[3],
            target,
            anchor
          );
          insert(target, html_anchor, anchor);
        },
        p(ctx2, dirty) {
          if (dirty & /*content*/
          8) html_tag.p(
            /*content*/
            ctx2[3]
          );
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(html_anchor);
            html_tag.d();
          }
        }
      };
    }
    function create_if_block$9(ctx) {
      let div;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let each_value = ensure_array_like(
        /*buttons*/
        ctx[1]
      );
      const get_key = (ctx2) => (
        /*button*/
        ctx2[26].id
      );
      for (let i = 0; i < each_value.length; i += 1) {
        let child_ctx = get_each_context$7(ctx, each_value, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block$7(key, child_ctx));
      }
      return {
        c() {
          div = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          attr(div, "class", "dialog-buttons tjs-dialog-buttons svelte-seq-1ez4adq");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div, null);
            }
          }
          ctx[20](div);
        },
        p(ctx2, dirty) {
          if (dirty & /*buttons, onClick, currentButtonId*/
          530) {
            each_value = ensure_array_like(
              /*buttons*/
              ctx2[1]
            );
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div, destroy_block, create_each_block$7, null, get_each_context$7);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
          ctx[20](null);
        }
      };
    }
    function create_if_block_1$5(ctx) {
      let html_tag;
      let raw_value = (
        /*button*/
        ctx[26].icon + ""
      );
      let html_anchor;
      return {
        c() {
          html_tag = new HtmlTag(false);
          html_anchor = empty();
          html_tag.a = html_anchor;
        },
        m(target, anchor) {
          html_tag.m(raw_value, target, anchor);
          insert(target, html_anchor, anchor);
        },
        p(ctx2, dirty) {
          if (dirty & /*buttons*/
          2 && raw_value !== (raw_value = /*button*/
          ctx2[26].icon + "")) html_tag.p(raw_value);
        },
        d(detaching) {
          if (detaching) {
            detach(html_anchor);
            html_tag.d();
          }
        }
      };
    }
    function create_each_block$7(key_1, ctx) {
      let button_1;
      let span;
      let t0_value = (
        /*button*/
        ctx[26].label + ""
      );
      let t0;
      let span_title_value;
      let t1;
      let button_1_class_value;
      let button_1_disabled_value;
      let applyStyles_action;
      let mounted;
      let dispose;
      let if_block = (
        /*button*/
        ctx[26].icon && create_if_block_1$5(ctx)
      );
      function click_handler() {
        return (
          /*click_handler*/
          ctx[18](
            /*button*/
            ctx[26]
          )
        );
      }
      function focus_handler() {
        return (
          /*focus_handler*/
          ctx[19](
            /*button*/
            ctx[26]
          )
        );
      }
      return {
        key: key_1,
        first: null,
        c() {
          button_1 = element("button");
          span = element("span");
          if (if_block) if_block.c();
          t0 = text$1(t0_value);
          t1 = space();
          attr(span, "title", span_title_value = /*button*/
          ctx[26].title);
          attr(button_1, "class", button_1_class_value = "dialog-button tjs-dialog-button " + /*button*/
          ctx[26].id + " svelte-seq-1ez4adq");
          button_1.disabled = button_1_disabled_value = /*button*/
          ctx[26].disabled;
          this.first = button_1;
        },
        m(target, anchor) {
          insert(target, button_1, anchor);
          append(button_1, span);
          if (if_block) if_block.m(span, null);
          append(span, t0);
          append(button_1, t1);
          if (!mounted) {
            dispose = [
              listen(button_1, "click", stop_propagation(prevent_default(click_handler))),
              listen(button_1, "focus", focus_handler),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                button_1,
                /*button*/
                ctx[26].styles
              ))
            ];
            mounted = true;
          }
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          if (
            /*button*/
            ctx[26].icon
          ) {
            if (if_block) {
              if_block.p(ctx, dirty);
            } else {
              if_block = create_if_block_1$5(ctx);
              if_block.c();
              if_block.m(span, t0);
            }
          } else if (if_block) {
            if_block.d(1);
            if_block = null;
          }
          if (dirty & /*buttons*/
          2 && t0_value !== (t0_value = /*button*/
          ctx[26].label + "")) set_data(t0, t0_value);
          if (dirty & /*buttons*/
          2 && span_title_value !== (span_title_value = /*button*/
          ctx[26].title)) {
            attr(span, "title", span_title_value);
          }
          if (dirty & /*buttons*/
          2 && button_1_class_value !== (button_1_class_value = "dialog-button tjs-dialog-button " + /*button*/
          ctx[26].id + " svelte-seq-1ez4adq")) {
            attr(button_1, "class", button_1_class_value);
          }
          if (dirty & /*buttons*/
          2 && button_1_disabled_value !== (button_1_disabled_value = /*button*/
          ctx[26].disabled)) {
            button_1.disabled = button_1_disabled_value;
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*buttons*/
          2) applyStyles_action.update.call(
            null,
            /*button*/
            ctx[26].styles
          );
        },
        d(detaching) {
          if (detaching) {
            detach(button_1);
          }
          if (if_block) if_block.d();
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_fragment$n(ctx) {
      let main;
      let div;
      let current_block_type_index;
      let if_block0;
      let t;
      let current;
      const if_block_creators = [create_if_block_2$2, create_if_block_3$1];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (typeof /*content*/
        ctx2[3] === "string") return 0;
        if (
          /*dialogClass*/
          ctx2[6]
        ) return 1;
        return -1;
      }
      if (~(current_block_type_index = select_block_type(ctx))) {
        if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      }
      let if_block1 = (
        /*buttons*/
        ctx[1].length && create_if_block$9(ctx)
      );
      return {
        c() {
          main = element("main");
          div = element("div");
          if (if_block0) if_block0.c();
          t = space();
          if (if_block1) if_block1.c();
          attr(div, "class", "dialog-content");
        },
        m(target, anchor) {
          insert(target, main, anchor);
          append(main, div);
          if (~current_block_type_index) {
            if_blocks[current_block_type_index].m(div, null);
          }
          ctx[17](div);
          append(main, t);
          if (if_block1) if_block1.m(main, null);
          current = true;
        },
        p(ctx2, [dirty]) {
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if (~current_block_type_index) {
              if_blocks[current_block_type_index].p(ctx2, dirty);
            }
          } else {
            if (if_block0) {
              group_outros();
              transition_out(if_blocks[previous_block_index], 1, 1, () => {
                if_blocks[previous_block_index] = null;
              });
              check_outros();
            }
            if (~current_block_type_index) {
              if_block0 = if_blocks[current_block_type_index];
              if (!if_block0) {
                if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
                if_block0.c();
              } else {
                if_block0.p(ctx2, dirty);
              }
              transition_in(if_block0, 1);
              if_block0.m(div, null);
            } else {
              if_block0 = null;
            }
          }
          if (
            /*buttons*/
            ctx2[1].length
          ) {
            if (if_block1) {
              if_block1.p(ctx2, dirty);
            } else {
              if_block1 = create_if_block$9(ctx2);
              if_block1.c();
              if_block1.m(main, null);
            }
          } else if (if_block1) {
            if_block1.d(1);
            if_block1 = null;
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block0);
          current = true;
        },
        o(local) {
          transition_out(if_block0);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(main);
          }
          if (~current_block_type_index) {
            if_blocks[current_block_type_index].d();
          }
          ctx[17](null);
          if (if_block1) if_block1.d();
        }
      };
    }
    const s_REGEX_HTML = /^\s*<.*>$/;
    function instance$m($$self, $$props, $$invalidate) {
      let autoClose;
      let focusFirst;
      let resolveId;
      let $elementRoot;
      let { data = void 0 } = $$props;
      let { preventDefault = false } = $$props;
      let { stopPropagation = false } = $$props;
      let { dialogComponent = void 0 } = $$props;
      const { elementRoot } = getContext("#internal").stores;
      component_subscribe($$self, elementRoot, (value) => $$invalidate(15, $elementRoot = value));
      const application = getContext("#external")?.application;
      const managedPromise = getContext("#managedPromise");
      let buttons;
      let contentEl;
      let buttonsEl;
      let content = void 0;
      let dialogClass;
      let dialogProps = {};
      let currentButtonId = data.default;
      onDestroy(() => {
        const rootEl = $elementRoot;
        if (A11yHelper.isFocusTarget(rootEl)) {
          rootEl.removeEventListener("keydown", onKeydown);
          rootEl.removeEventListener("keyup", onKeyup);
        }
      });
      onMount(() => {
        if (focusFirst) {
          const focusEl = A11yHelper.getFirstFocusableElement(contentEl);
          if (A11yHelper.isFocusTarget(focusEl)) {
            setTimeout(() => focusEl.focus(), 0);
          }
        }
      });
      function onClick(button) {
        try {
          let result = void 0;
          const callback = button?.onPress;
          switch (typeof callback) {
            case "function":
              result = callback({ application });
              break;
            case "string":
              if (dialogComponent !== void 0 && typeof dialogComponent[callback] === "function") {
                result = dialogComponent[callback]({ application });
              } else {
                if (dialogComponent === void 0) {
                  console.warn(`[TRL] TJSDialog warning: 'onPress' defined as a string with no associated content Svelte component.`);
                } else if (typeof dialogComponent?.[callback] !== "function") {
                  console.warn(`[TRL] TJSDialog warning: The content Svelte component does not contain an associated function '${callback}'. Did you remember to add '<svelte:options accessors={true} />' and export the function?`);
                }
              }
              break;
          }
          if (button.autoClose && autoClose) {
            if (resolveId && result === void 0) {
              result = button.id;
            }
            managedPromise.resolve(result);
          }
        } catch (err) {
          const notifyError = typeof data.notifyError === "boolean" ? data.notifyError : true;
          if (notifyError) {
            globalThis.ui.notifications.error(err, { console: false });
          }
          if (!managedPromise.reject(err)) {
            throw err;
          }
        } finally {
          if (button.autoClose && autoClose) {
            application.close();
          }
        }
      }
      function onKeydown(event) {
        switch (event.code) {
          case "ArrowLeft":
          case "ArrowRight":
          case "Enter":
            event.stopPropagation();
            break;
          case "Tab":
            event.stopPropagation();
            setTimeout(
              () => {
                const activeWindow = application.reactive.activeWindow;
                const activeElement = activeWindow.document.activeElement;
                if (A11yHelper.isFocusTarget(activeElement) && A11yHelper.isFocusTarget(buttonsEl) && buttonsEl.contains(activeElement)) {
                  for (let cntr = 0; cntr < activeElement.classList.length; cntr++) {
                    const item = activeElement.classList.item(cntr);
                    if (item !== "dialog-button" && item !== "default" && typeof data.buttons[item] !== void 0) {
                      $$invalidate(4, currentButtonId = item);
                      break;
                    }
                  }
                }
              },
              0
            );
            break;
          default:
            if (preventDefault) {
              event.preventDefault();
            }
            if (stopPropagation) {
              event.stopPropagation();
            }
            break;
        }
      }
      function onKeyup(event) {
        switch (event.code) {
          case "ArrowLeft": {
            event.preventDefault();
            event.stopPropagation();
            const activeWindow = application.reactive.activeWindow;
            const activeEl = activeWindow.document.activeElement;
            if (A11yHelper.isFocusTarget(buttonsEl)) {
              if (A11yHelper.isFocusTarget(activeEl) && buttonsEl.contains(activeEl)) {
                const currentIndex = buttons.findIndex((button) => button.id === currentButtonId);
                if (buttons.length && currentIndex > 0) {
                  $$invalidate(4, currentButtonId = buttons[currentIndex - 1].id);
                }
              }
              const buttonEl = buttonsEl.querySelector(`.${currentButtonId}`);
              if (A11yHelper.isFocusTarget(buttonEl)) {
                buttonEl.focus();
              }
            }
            break;
          }
          case "ArrowRight": {
            event.preventDefault();
            event.stopPropagation();
            const activeWindow = application.reactive.activeWindow;
            const activeEl = activeWindow.document.activeElement;
            if (A11yHelper.isFocusTarget(buttonsEl)) {
              if (A11yHelper.isFocusTarget(activeEl) && (buttonsEl.contains(activeEl) || currentButtonId === void 0)) {
                const currentIndex = buttons.findIndex((button) => button.id === currentButtonId);
                if (buttons.length && currentIndex < buttons.length - 1) {
                  $$invalidate(4, currentButtonId = buttons[currentIndex + 1].id);
                }
              }
              const buttonEl = buttonsEl.querySelector(`.${currentButtonId}`);
              if (A11yHelper.isFocusTarget(buttonEl)) {
                buttonEl.focus();
              }
            }
            break;
          }
          case "Enter":
            event.preventDefault();
            event.stopPropagation();
            break;
          default:
            if (preventDefault) {
              event.preventDefault();
            }
            if (stopPropagation) {
              event.stopPropagation();
            }
            break;
        }
      }
      function switch_instance_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          dialogComponent = $$value;
          $$invalidate(0, dialogComponent);
        });
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          contentEl = $$value;
          $$invalidate(5, contentEl);
        });
      }
      const click_handler = (button) => onClick(button);
      const focus_handler = (button) => $$invalidate(4, currentButtonId = button.id);
      function div_binding_1($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          buttonsEl = $$value;
          $$invalidate(2, buttonsEl);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("data" in $$props2) $$invalidate(10, data = $$props2.data);
        if ("preventDefault" in $$props2) $$invalidate(11, preventDefault = $$props2.preventDefault);
        if ("stopPropagation" in $$props2) $$invalidate(12, stopPropagation = $$props2.stopPropagation);
        if ("dialogComponent" in $$props2) $$invalidate(0, dialogComponent = $$props2.dialogComponent);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*$elementRoot*/
        32768) {
          if ($elementRoot) {
            const rootEl = $elementRoot;
            if (A11yHelper.isFocusTarget(rootEl)) {
              rootEl.addEventListener("keydown", onKeydown);
              rootEl.addEventListener("keyup", onKeyup);
            }
          }
        }
        if ($$self.$$.dirty & /*data*/
        1024) {
          $$invalidate(13, autoClose = typeof data.autoClose === "boolean" ? data.autoClose : true);
        }
        if ($$self.$$.dirty & /*data*/
        1024) {
          $$invalidate(14, focusFirst = typeof data.focusFirst === "boolean" ? data.focusFirst : false);
        }
        if ($$self.$$.dirty & /*data*/
        1024) {
          {
            $$invalidate(1, buttons = !isObject(data.buttons) ? [] : Object.keys(data.buttons).reduce(
              (array, key) => {
                const b = data.buttons[key];
                const icon = typeof b.icon !== "string" ? void 0 : s_REGEX_HTML.test(b.icon) ? b.icon : `<i class="${b.icon}"></i>`;
                const autoClose2 = typeof b.autoClose === "boolean" ? b.autoClose : true;
                const disabled = typeof b.disabled === "boolean" ? b.disabled : false;
                const label = typeof b.label === "string" ? `${icon !== void 0 ? " " : ""}${localize(b.label)}` : "";
                const title = typeof b.title === "string" ? localize(b.title) : void 0;
                const condition = typeof b.condition === "function" ? b.condition.call(b) : b.condition ?? true;
                if (condition) {
                  array.push({
                    ...b,
                    id: key,
                    autoClose: autoClose2,
                    icon,
                    label,
                    title,
                    disabled
                  });
                }
                return array;
              },
              []
            ));
          }
        }
        if ($$self.$$.dirty & /*buttons, currentButtonId*/
        18) {
          if (!buttons.find((button) => button.id === currentButtonId)) {
            $$invalidate(4, currentButtonId = void 0);
          }
        }
        if ($$self.$$.dirty & /*focusFirst, buttonsEl, currentButtonId*/
        16404) {
          if (!focusFirst && A11yHelper.isFocusTarget(buttonsEl)) {
            const buttonEl = buttonsEl.querySelector(`.${currentButtonId}`);
            if (A11yHelper.isFocusTarget(buttonEl)) {
              buttonEl.focus();
            }
          }
        }
        if ($$self.$$.dirty & /*data*/
        1024) {
          resolveId = typeof data.resolveId === "boolean" ? data.resolveId : false;
        }
        if ($$self.$$.dirty & /*content, data*/
        1032) {
          if (content !== data.content) {
            $$invalidate(
              3,
              content = data.content
            );
            try {
              if (TJSSvelte.config.isConfigEmbed(content)) {
                $$invalidate(6, dialogClass = content.class);
                $$invalidate(7, dialogProps = content.props);
              } else {
                $$invalidate(6, dialogClass = void 0);
                $$invalidate(7, dialogProps = {});
              }
            } catch (err) {
              $$invalidate(6, dialogClass = void 0);
              $$invalidate(7, dialogProps = {});
              $$invalidate(3, content = err.message);
              console.error(err);
            }
          }
        }
      };
      return [
        dialogComponent,
        buttons,
        buttonsEl,
        content,
        currentButtonId,
        contentEl,
        dialogClass,
        dialogProps,
        elementRoot,
        onClick,
        data,
        preventDefault,
        stopPropagation,
        autoClose,
        focusFirst,
        $elementRoot,
        switch_instance_binding,
        div_binding,
        click_handler,
        focus_handler,
        div_binding_1
      ];
    }
    class DialogContent extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$m, create_fragment$n, safe_not_equal, {
          data: 10,
          preventDefault: 11,
          stopPropagation: 12,
          dialogComponent: 0
        });
      }
    }
    function create_else_block$2(ctx) {
      let applicationshell;
      let updating_elementRoot;
      let updating_elementContent;
      let current;
      const applicationshell_spread_levels = [
        /*appProps*/
        ctx[6]
      ];
      function applicationshell_elementRoot_binding_1(value) {
        ctx[16](value);
      }
      function applicationshell_elementContent_binding_1(value) {
        ctx[17](value);
      }
      let applicationshell_props = {
        $$slots: { default: [create_default_slot_2$2] },
        $$scope: { ctx }
      };
      for (let i = 0; i < applicationshell_spread_levels.length; i += 1) {
        applicationshell_props = assign(applicationshell_props, applicationshell_spread_levels[i]);
      }
      if (
        /*elementRoot*/
        ctx[0] !== void 0
      ) {
        applicationshell_props.elementRoot = /*elementRoot*/
        ctx[0];
      }
      if (
        /*elementContent*/
        ctx[1] !== void 0
      ) {
        applicationshell_props.elementContent = /*elementContent*/
        ctx[1];
      }
      applicationshell = new ApplicationShell({ props: applicationshell_props });
      binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding_1));
      binding_callbacks.push(() => bind(applicationshell, "elementContent", applicationshell_elementContent_binding_1));
      return {
        c() {
          create_component(applicationshell.$$.fragment);
        },
        m(target, anchor) {
          mount_component(applicationshell, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const applicationshell_changes = dirty & /*appProps*/
          64 ? get_spread_update(applicationshell_spread_levels, [get_spread_object(
            /*appProps*/
            ctx2[6]
          )]) : {};
          if (dirty & /*$$scope, data, dialogComponent*/
          8388620) {
            applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
          }
          if (!updating_elementRoot && dirty & /*elementRoot*/
          1) {
            updating_elementRoot = true;
            applicationshell_changes.elementRoot = /*elementRoot*/
            ctx2[0];
            add_flush_callback(() => updating_elementRoot = false);
          }
          if (!updating_elementContent && dirty & /*elementContent*/
          2) {
            updating_elementContent = true;
            applicationshell_changes.elementContent = /*elementContent*/
            ctx2[1];
            add_flush_callback(() => updating_elementContent = false);
          }
          applicationshell.$set(applicationshell_changes);
        },
        i(local) {
          if (current) return;
          transition_in(applicationshell.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(applicationshell.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(applicationshell, detaching);
        }
      };
    }
    function create_if_block$8(ctx) {
      let tjsglasspane;
      let current;
      const tjsglasspane_spread_levels = [
        {
          id: `${/*application*/
          ctx[4].id}-glasspane`
        },
        /*modalProps*/
        ctx[7],
        { zIndex: (
          /*zIndex*/
          ctx[8]
        ) }
      ];
      let tjsglasspane_props = {
        $$slots: { default: [create_default_slot$3] },
        $$scope: { ctx }
      };
      for (let i = 0; i < tjsglasspane_spread_levels.length; i += 1) {
        tjsglasspane_props = assign(tjsglasspane_props, tjsglasspane_spread_levels[i]);
      }
      tjsglasspane = new TJSGlassPane({ props: tjsglasspane_props });
      tjsglasspane.$on(
        "glasspane:close",
        /*glasspane_close_handler*/
        ctx[13]
      );
      tjsglasspane.$on(
        "glasspane:keydown:escape",
        /*glasspane_keydown_escape_handler*/
        ctx[14]
      );
      return {
        c() {
          create_component(tjsglasspane.$$.fragment);
        },
        m(target, anchor) {
          mount_component(tjsglasspane, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const tjsglasspane_changes = dirty & /*application, modalProps, zIndex*/
          400 ? get_spread_update(tjsglasspane_spread_levels, [
            dirty & /*application*/
            16 && {
              id: `${/*application*/
              ctx2[4].id}-glasspane`
            },
            dirty & /*modalProps*/
            128 && get_spread_object(
              /*modalProps*/
              ctx2[7]
            ),
            dirty & /*zIndex*/
            256 && { zIndex: (
              /*zIndex*/
              ctx2[8]
            ) }
          ]) : {};
          if (dirty & /*$$scope, appProps, elementRoot, elementContent, data, dialogComponent*/
          8388687) {
            tjsglasspane_changes.$$scope = { dirty, ctx: ctx2 };
          }
          tjsglasspane.$set(tjsglasspane_changes);
        },
        i(local) {
          if (current) return;
          transition_in(tjsglasspane.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(tjsglasspane.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(tjsglasspane, detaching);
        }
      };
    }
    function create_default_slot_2$2(ctx) {
      let dialogcontent;
      let updating_dialogComponent;
      let current;
      function dialogcontent_dialogComponent_binding_1(value) {
        ctx[15](value);
      }
      let dialogcontent_props = { data: (
        /*data*/
        ctx[3]
      ) };
      if (
        /*dialogComponent*/
        ctx[2] !== void 0
      ) {
        dialogcontent_props.dialogComponent = /*dialogComponent*/
        ctx[2];
      }
      dialogcontent = new DialogContent({ props: dialogcontent_props });
      binding_callbacks.push(() => bind(dialogcontent, "dialogComponent", dialogcontent_dialogComponent_binding_1));
      return {
        c() {
          create_component(dialogcontent.$$.fragment);
        },
        m(target, anchor) {
          mount_component(dialogcontent, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const dialogcontent_changes = {};
          if (dirty & /*data*/
          8) dialogcontent_changes.data = /*data*/
          ctx2[3];
          if (!updating_dialogComponent && dirty & /*dialogComponent*/
          4) {
            updating_dialogComponent = true;
            dialogcontent_changes.dialogComponent = /*dialogComponent*/
            ctx2[2];
            add_flush_callback(() => updating_dialogComponent = false);
          }
          dialogcontent.$set(dialogcontent_changes);
        },
        i(local) {
          if (current) return;
          transition_in(dialogcontent.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(dialogcontent.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(dialogcontent, detaching);
        }
      };
    }
    function create_default_slot_1$2(ctx) {
      let dialogcontent;
      let updating_dialogComponent;
      let current;
      function dialogcontent_dialogComponent_binding(value) {
        ctx[10](value);
      }
      let dialogcontent_props = {
        data: (
          /*data*/
          ctx[3]
        ),
        stopPropagation: true
      };
      if (
        /*dialogComponent*/
        ctx[2] !== void 0
      ) {
        dialogcontent_props.dialogComponent = /*dialogComponent*/
        ctx[2];
      }
      dialogcontent = new DialogContent({ props: dialogcontent_props });
      binding_callbacks.push(() => bind(dialogcontent, "dialogComponent", dialogcontent_dialogComponent_binding));
      return {
        c() {
          create_component(dialogcontent.$$.fragment);
        },
        m(target, anchor) {
          mount_component(dialogcontent, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const dialogcontent_changes = {};
          if (dirty & /*data*/
          8) dialogcontent_changes.data = /*data*/
          ctx2[3];
          if (!updating_dialogComponent && dirty & /*dialogComponent*/
          4) {
            updating_dialogComponent = true;
            dialogcontent_changes.dialogComponent = /*dialogComponent*/
            ctx2[2];
            add_flush_callback(() => updating_dialogComponent = false);
          }
          dialogcontent.$set(dialogcontent_changes);
        },
        i(local) {
          if (current) return;
          transition_in(dialogcontent.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(dialogcontent.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(dialogcontent, detaching);
        }
      };
    }
    function create_default_slot$3(ctx) {
      let applicationshell;
      let updating_elementRoot;
      let updating_elementContent;
      let current;
      const applicationshell_spread_levels = [
        /*appProps*/
        ctx[6]
      ];
      function applicationshell_elementRoot_binding(value) {
        ctx[11](value);
      }
      function applicationshell_elementContent_binding(value) {
        ctx[12](value);
      }
      let applicationshell_props = {
        $$slots: { default: [create_default_slot_1$2] },
        $$scope: { ctx }
      };
      for (let i = 0; i < applicationshell_spread_levels.length; i += 1) {
        applicationshell_props = assign(applicationshell_props, applicationshell_spread_levels[i]);
      }
      if (
        /*elementRoot*/
        ctx[0] !== void 0
      ) {
        applicationshell_props.elementRoot = /*elementRoot*/
        ctx[0];
      }
      if (
        /*elementContent*/
        ctx[1] !== void 0
      ) {
        applicationshell_props.elementContent = /*elementContent*/
        ctx[1];
      }
      applicationshell = new ApplicationShell({ props: applicationshell_props });
      binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding));
      binding_callbacks.push(() => bind(applicationshell, "elementContent", applicationshell_elementContent_binding));
      return {
        c() {
          create_component(applicationshell.$$.fragment);
        },
        m(target, anchor) {
          mount_component(applicationshell, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const applicationshell_changes = dirty & /*appProps*/
          64 ? get_spread_update(applicationshell_spread_levels, [get_spread_object(
            /*appProps*/
            ctx2[6]
          )]) : {};
          if (dirty & /*$$scope, data, dialogComponent*/
          8388620) {
            applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
          }
          if (!updating_elementRoot && dirty & /*elementRoot*/
          1) {
            updating_elementRoot = true;
            applicationshell_changes.elementRoot = /*elementRoot*/
            ctx2[0];
            add_flush_callback(() => updating_elementRoot = false);
          }
          if (!updating_elementContent && dirty & /*elementContent*/
          2) {
            updating_elementContent = true;
            applicationshell_changes.elementContent = /*elementContent*/
            ctx2[1];
            add_flush_callback(() => updating_elementContent = false);
          }
          applicationshell.$set(applicationshell_changes);
        },
        i(local) {
          if (current) return;
          transition_in(applicationshell.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(applicationshell.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(applicationshell, detaching);
        }
      };
    }
    function create_fragment$m(ctx) {
      let current_block_type_index;
      let if_block;
      let if_block_anchor;
      let current;
      const if_block_creators = [create_if_block$8, create_else_block$2];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (
          /*modal*/
          ctx2[5]
        ) return 0;
        return 1;
      }
      current_block_type_index = select_block_type(ctx);
      if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      return {
        c() {
          if_block.c();
          if_block_anchor = empty();
        },
        m(target, anchor) {
          if_blocks[current_block_type_index].m(target, anchor);
          insert(target, if_block_anchor, anchor);
          current = true;
        },
        p(ctx2, [dirty]) {
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if_blocks[current_block_type_index].p(ctx2, dirty);
          } else {
            group_outros();
            transition_out(if_blocks[previous_block_index], 1, 1, () => {
              if_blocks[previous_block_index] = null;
            });
            check_outros();
            if_block = if_blocks[current_block_type_index];
            if (!if_block) {
              if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
              if_block.c();
            } else {
              if_block.p(ctx2, dirty);
            }
            transition_in(if_block, 1);
            if_block.m(if_block_anchor.parentNode, if_block_anchor);
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block);
          current = true;
        },
        o(local) {
          transition_out(if_block);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(if_block_anchor);
          }
          if_blocks[current_block_type_index].d(detaching);
        }
      };
    }
    const s_MODAL_BACKGROUND = "#50505080";
    function instance$l($$self, $$props, $$invalidate) {
      let { elementContent = void 0 } = $$props;
      let { elementRoot = void 0 } = $$props;
      let { data = {} } = $$props;
      let { dialogComponent = void 0 } = $$props;
      let { managedPromise = void 0 } = $$props;
      const application = getContext("#external")?.application;
      const dialogOptions = writable({});
      setContext("#managedPromise", managedPromise);
      setContext("#dialogOptions", dialogOptions);
      const s_MODAL_TRANSITION = fade;
      const s_MODAL_TRANSITION_OPTIONS = { duration: 200 };
      let modal = void 0;
      const appProps = {
        // Stores any transition functions.
        transition: void 0,
        inTransition: void 0,
        outTransition: void 0,
        // Stores properties to set for options for any transitions.
        transitionOptions: void 0,
        inTransitionOptions: void 0,
        outTransitionOptions: void 0,
        // Stores any style overrides for application shell.
        stylesApp: void 0,
        stylesContent: void 0
      };
      const modalProps = {
        // Background CSS style string.
        background: void 0,
        slotSeparate: void 0,
        styles: void 0,
        // Close modal on glasspane input.
        closeOnInput: void 0,
        // Stores any transition functions.
        transition: void 0,
        inTransition: void 0,
        outTransition: void 0,
        // Stores properties to set for options for any transitions.
        transitionOptions: void 0,
        inTransitionOptions: void 0,
        outTransitionOptions: void 0
      };
      let zIndex = void 0;
      if (modal === void 0) {
        modal = typeof data?.modal === "boolean" ? data.modal : false;
      }
      const activeWindow = application.reactive.activeWindow;
      if (!modal) {
        onDestroy(() => activeWindow.document.removeEventListener("keydown", onKeydown));
        onMount(() => activeWindow.document.addEventListener("keydown", onKeydown));
      }
      function onKeydown(event) {
        if (event.code === "Escape") {
          event.preventDefault();
          event.stopPropagation();
          application.close();
        }
      }
      function dialogcontent_dialogComponent_binding(value) {
        dialogComponent = value;
        $$invalidate(2, dialogComponent);
      }
      function applicationshell_elementRoot_binding(value) {
        elementRoot = value;
        $$invalidate(0, elementRoot);
      }
      function applicationshell_elementContent_binding(value) {
        elementContent = value;
        $$invalidate(1, elementContent);
      }
      const glasspane_close_handler = () => application.close();
      const glasspane_keydown_escape_handler = () => application.close();
      function dialogcontent_dialogComponent_binding_1(value) {
        dialogComponent = value;
        $$invalidate(2, dialogComponent);
      }
      function applicationshell_elementRoot_binding_1(value) {
        elementRoot = value;
        $$invalidate(0, elementRoot);
      }
      function applicationshell_elementContent_binding_1(value) {
        elementContent = value;
        $$invalidate(1, elementContent);
      }
      $$self.$$set = ($$props2) => {
        if ("elementContent" in $$props2) $$invalidate(1, elementContent = $$props2.elementContent);
        if ("elementRoot" in $$props2) $$invalidate(0, elementRoot = $$props2.elementRoot);
        if ("data" in $$props2) $$invalidate(3, data = $$props2.data);
        if ("dialogComponent" in $$props2) $$invalidate(2, dialogComponent = $$props2.dialogComponent);
        if ("managedPromise" in $$props2) $$invalidate(9, managedPromise = $$props2.managedPromise);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*elementRoot, modal*/
        33) {
          if (A11yHelper.isFocusTarget(elementRoot)) {
            elementRoot.setAttribute("role", "dialog");
            if (modal) {
              elementRoot.setAttribute("aria-modal", "true");
            }
          }
        }
        if ($$self.$$.dirty & /*data, modal, zIndex, application*/
        312) {
          if (isObject(data)) {
            dialogOptions.set(data);
            const newZIndex = Number.isInteger(data.zIndex) || data.zIndex === null ? data.zIndex : modal ? Number.MAX_SAFE_INTEGER : Number.MAX_SAFE_INTEGER - 1;
            if (zIndex !== newZIndex) {
              $$invalidate(8, zIndex = newZIndex);
            }
            const newDraggable = typeof data.draggable === "boolean" ? data.draggable : void 0;
            if (newDraggable !== void 0 && application.reactive.draggable !== newDraggable) {
              $$invalidate(4, application.reactive.draggable = newDraggable, application);
            }
            const newFocusAuto = typeof data.focusAuto === "boolean" ? data.focusAuto : void 0;
            if (newFocusAuto !== void 0 && application.reactive.focusAuto !== newFocusAuto) {
              $$invalidate(4, application.reactive.focusAuto = newFocusAuto, application);
            }
            const newFocusKeep = typeof data.focusKeep === "boolean" ? data.focusKeep : void 0;
            if (newFocusKeep !== void 0 && application.reactive.focusKeep !== newFocusKeep) {
              $$invalidate(4, application.reactive.focusKeep = newFocusKeep, application);
            }
            const newFocusTrap = typeof data.focusTrap === "boolean" ? data.focusTrap : void 0;
            if (newFocusTrap !== void 0 && application.reactive.focusTrap !== newFocusTrap) {
              $$invalidate(4, application.reactive.focusTrap = newFocusTrap, application);
            }
            const newMinimizable = typeof data.minimizable === "boolean" ? data.minimizable : void 0;
            if (newMinimizable !== void 0 && application.reactive.minimizable !== newMinimizable) {
              $$invalidate(4, application.reactive.minimizable = newMinimizable, application);
            }
            const newResizable = typeof data.resizable === "boolean" ? data.resizable : void 0;
            if (newResizable !== void 0 && application.reactive.resizable !== newResizable) {
              $$invalidate(4, application.reactive.resizable = newResizable, application);
            }
            const newTitle = data.title ?? "Dialog";
            if (newTitle !== application?.options?.title) {
              $$invalidate(4, application.reactive.title = newTitle, application);
            }
            if (application.position.zIndex !== zIndex) {
              $$invalidate(4, application.position.zIndex = zIndex, application);
            }
          }
        }
        if ($$self.$$.dirty & /*data, appProps*/
        72) {
          if (isObject(data?.transition)) {
            const d = data.transition;
            if (d?.transition !== appProps.transition) {
              $$invalidate(6, appProps.transition = d.transition, appProps);
            }
            if (d?.inTransition !== appProps.inTransition) {
              $$invalidate(6, appProps.inTransition = d.inTransition, appProps);
            }
            if (d?.outTransition !== appProps.outTransition) {
              $$invalidate(6, appProps.outTransition = d.outTransition, appProps);
            }
            if (d?.transitionOptions !== appProps.transitionOptions) {
              $$invalidate(6, appProps.transitionOptions = d.transitionOptions, appProps);
            }
            if (d?.inTransitionOptions !== appProps.inTransitionOptions) {
              $$invalidate(6, appProps.inTransitionOptions = d.inTransitionOptions, appProps);
            }
            if (d?.outTransitionOptions !== appProps.outTransitionOptions) {
              $$invalidate(6, appProps.outTransitionOptions = d.outTransitionOptions, appProps);
            }
          }
        }
        if ($$self.$$.dirty & /*data, modalProps*/
        136) {
          {
            const newModalBackground = typeof data?.modalOptions?.background === "string" ? data.modalOptions.background : s_MODAL_BACKGROUND;
            if (newModalBackground !== modalProps.background) {
              $$invalidate(7, modalProps.background = newModalBackground, modalProps);
            }
          }
        }
        if ($$self.$$.dirty & /*data, modalProps*/
        136) {
          {
            const newModalSlotSeparate = typeof data?.modalOptions?.slotSeparate === "boolean" ? data.modalOptions.slotSeparate : void 0;
            if (newModalSlotSeparate !== modalProps.slotSeparate) {
              $$invalidate(7, modalProps.slotSeparate = newModalSlotSeparate, modalProps);
            }
          }
        }
        if ($$self.$$.dirty & /*data, modalProps*/
        136) {
          {
            const newModalStyles = isObject(data?.modalOptions?.styles) ? data.modalOptions.styles : void 0;
            if (newModalStyles !== modalProps.styles) {
              $$invalidate(7, modalProps.styles = newModalStyles, modalProps);
            }
          }
        }
        if ($$self.$$.dirty & /*data, modalProps*/
        136) {
          {
            const newModalCloseOnInput = typeof data?.modalOptions?.closeOnInput === "boolean" ? data.modalOptions.closeOnInput : void 0;
            if (newModalCloseOnInput !== modalProps.closeOnInput) {
              $$invalidate(7, modalProps.closeOnInput = newModalCloseOnInput, modalProps);
            }
          }
        }
        if ($$self.$$.dirty & /*data, modalProps*/
        136) {
          if (isObject(data?.modalOptions?.transition)) {
            const d = data.modalOptions.transition;
            if (d?.transition !== modalProps.transition) {
              $$invalidate(
                7,
                modalProps.transition = typeof d?.transition === "function" ? d.transition : s_MODAL_TRANSITION,
                modalProps
              );
            }
            if (d?.inTransition !== modalProps.inTransition) {
              $$invalidate(7, modalProps.inTransition = d.inTransition, modalProps);
            }
            if (d?.outTransition !== modalProps.outTransition) {
              $$invalidate(7, modalProps.outTransition = d.outTransition, modalProps);
            }
            if (d?.transitionOptions !== modalProps.transitionOptions) {
              $$invalidate(
                7,
                modalProps.transitionOptions = isObject(d?.transitionOptions) ? d.transitionOptions : s_MODAL_TRANSITION_OPTIONS,
                modalProps
              );
            }
            if (d?.inTransitionOptions !== modalProps.inTransitionOptions) {
              $$invalidate(7, modalProps.inTransitionOptions = d.inTransitionOptions, modalProps);
            }
            if (d?.outTransitionOptions !== modalProps.outTransitionOptions) {
              $$invalidate(7, modalProps.outTransitionOptions = d.outTransitionOptions, modalProps);
            }
          } else {
            const newModalTransition = typeof data?.modalOptions?.transition?.transition === "function" ? data.modalOptions.transition.transition : s_MODAL_TRANSITION;
            if (newModalTransition !== modalProps.transition) {
              $$invalidate(7, modalProps.transition = newModalTransition, modalProps);
            }
            const newModalTransitionOptions = isObject(data?.modalOptions?.transitionOptions) ? data.modalOptions.transitionOptions : s_MODAL_TRANSITION_OPTIONS;
            if (newModalTransitionOptions !== modalProps.transitionOptions) {
              $$invalidate(7, modalProps.transitionOptions = newModalTransitionOptions, modalProps);
            }
          }
        }
      };
      return [
        elementRoot,
        elementContent,
        dialogComponent,
        data,
        application,
        modal,
        appProps,
        modalProps,
        zIndex,
        managedPromise,
        dialogcontent_dialogComponent_binding,
        applicationshell_elementRoot_binding,
        applicationshell_elementContent_binding,
        glasspane_close_handler,
        glasspane_keydown_escape_handler,
        dialogcontent_dialogComponent_binding_1,
        applicationshell_elementRoot_binding_1,
        applicationshell_elementContent_binding_1
      ];
    }
    class DialogShell extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$l, create_fragment$m, safe_not_equal, {
          elementContent: 1,
          elementRoot: 0,
          data: 3,
          dialogComponent: 2,
          managedPromise: 9
        });
      }
      get elementContent() {
        return this.$$.ctx[1];
      }
      set elementContent(elementContent) {
        this.$$set({ elementContent });
        flush();
      }
      get elementRoot() {
        return this.$$.ctx[0];
      }
      set elementRoot(elementRoot) {
        this.$$set({ elementRoot });
        flush();
      }
      get data() {
        return this.$$.ctx[3];
      }
      set data(data) {
        this.$$set({ data });
        flush();
      }
      get dialogComponent() {
        return this.$$.ctx[2];
      }
      set dialogComponent(dialogComponent) {
        this.$$set({ dialogComponent });
        flush();
      }
      get managedPromise() {
        return this.$$.ctx[9];
      }
      set managedPromise(managedPromise) {
        this.$$set({ managedPromise });
        flush();
      }
    }
    class ManagedPromise {
      /** @type {boolean} */
      static #logging = false;
      /** @type {{ isProcessing?: boolean, promise?: Promise, reject: Function, resolve: Function }} */
      #current;
      /**
       * @returns {boolean} Whether global logging is enabled.
       */
      static get logging() {
        return this.#logging;
      }
      /**
       * @returns {boolean} Whether there is an active managed Promise.
       */
      get isActive() {
        return this.#current !== void 0;
      }
      /**
       * @returns {boolean} Whether there is an active managed Promise and resolution is currently being processed.
       */
      get isProcessing() {
        return this.#current !== void 0 ? this.#current.isProcessing : false;
      }
      /**
       * Sets global logging enabled state.
       *
       * @param {boolean}  logging - New logging enabled state.
       */
      static set logging(logging) {
        if (typeof logging !== "boolean") {
          throw new TypeError(`[TRL] ManagedPromise.logging error: 'logging' is not a boolean.`);
        }
        this.#logging = logging;
      }
      // ----------------------------------------------------------------------------------------------------------------
      /**
       * Resolves any current Promise with undefined and creates a new current Promise.
       *
       * @template T
       *
       * @param {object} opts - Options.
       *
       * @param {boolean}  [opts.reuse=false] - When true if there is an existing live Promise it is returned immediately.
       *
       * @returns {Promise<T>} The new current managed Promise.
       */
      create({ reuse = false } = {}) {
        if (typeof reuse !== "boolean") {
          throw new TypeError(`[TRL] ManagedPromise.create error: 'reuse' is not a boolean.`);
        }
        if (reuse && this.#current !== void 0 && CrossWindow.isPromise(this.#current.promise)) {
          if (ManagedPromise.#logging) {
            console.warn(`[TRL] ManagedPromise.create info: Reusing / returning existing managed Promise.`);
          }
          return this.#current.promise;
        }
        if (this.#current !== void 0) {
          if (ManagedPromise.#logging) {
            console.warn(
              `[TRL] ManagedPromise.create info: Creating a new Promise and resolving existing immediately.`
            );
          }
          this.#current.resolve(void 0);
          this.#current = void 0;
        }
        const promise2 = new Promise((resolve, reject) => {
          this.#current = {
            isProcessing: false,
            reject,
            resolve
          };
        });
        this.#current.promise = promise2;
        return promise2;
      }
      /**
       * Gets the current Promise if any.
       *
       * @returns {Promise<any>} Current Promise.
       */
      get() {
        return this.#current ? this.#current.promise : void 0;
      }
      /**
       * Rejects the current Promise if applicable.
       *
       * @param {*}  [result] - Result to reject.
       *
       * @returns {boolean} Was the promise rejected.
       */
      reject(result = void 0) {
        if (this.#current !== void 0 && this.#current.isProcessing) {
          if (ManagedPromise.#logging) {
            console.warn(`[TRL] ManagedPromise.reject info: Currently processing promise.`);
          }
          return true;
        }
        if (this.#current !== void 0) {
          this.#current.isProcessing = true;
          if (CrossWindow.isPromise(result)) {
            result.then((value) => {
              this.#current.reject(value);
              this.#current = void 0;
            }).catch((err) => {
              this.#current.reject(err);
              this.#current = void 0;
            });
          } else {
            this.#current.reject(result);
            this.#current = void 0;
          }
          return true;
        } else {
          if (ManagedPromise.#logging) {
            console.warn(`[TRL] ManagedPromise.reject warning: No current managed Promise to reject.`);
          }
          return false;
        }
      }
      /**
       * Resolves the current Promise if applicable.
       *
       * @param {*}  [result] - Result to resolve.
       *
       * @returns {boolean} Was the promise resolved.
       */
      resolve(result = void 0) {
        if (this.#current !== void 0 && this.#current.isProcessing) {
          if (ManagedPromise.#logging) {
            console.warn(`[TRL] ManagedPromise.resolve info: Currently processing promise.`);
          }
          return true;
        }
        if (this.#current !== void 0) {
          if (CrossWindow.isPromise(result)) {
            this.#current.isProcessing = true;
            result.then((value) => {
              this.#current.resolve(value);
              this.#current = void 0;
            }).catch((err) => {
              this.#current.reject(err);
              this.#current = void 0;
            });
          } else {
            this.#current.resolve(result);
            this.#current = void 0;
          }
          return true;
        } else {
          if (ManagedPromise.#logging) {
            console.warn(`[TRL] ManagedPromise.resolve warning: No current managed Promise to resolve.`);
          }
          return false;
        }
      }
    }
    class ApplicationState {
      /** @type {import('../../SvelteApp.js').SvelteApp} */
      #application;
      /**
       * Stores the current save state key being restored by animating. When a restore is already being animated with the
       * same name the subsequent restore animation is ignored.
       *
       * @type {string | undefined}
       */
      #currentRestoreKey;
      /** @type {Map<string, import('../../types').SvelteApp.API.State.Data>} */
      #dataSaved = /* @__PURE__ */ new Map();
      /**
       * @param {import('../../SvelteApp.js').SvelteApp}   application - The application.
       */
      constructor(application) {
        this.#application = application;
        Object.seal(this);
      }
      /**
       * Clears all saved application state.
       */
      clear() {
        this.#dataSaved.clear();
      }
      /**
       * Returns current application state along with any extra data passed into method.
       *
       * @param {object} [extra] - Extra data to add to application state.
       *
       * @returns {import('../../types').SvelteApp.API.State.Data} Passed in object with current application state.
       */
      current(extra = {}) {
        return Object.assign(extra, {
          position: this.#application?.position?.get(),
          beforeMinimized: this.#application?.position?.state.get({ name: "#beforeMinimized" }),
          options: this.#application?.reactive?.toJSON(),
          ui: { minimized: this.#application?.reactive?.minimized }
        });
      }
      /**
       * Gets any saved application state by name.
       *
       * @param {object}   options - Options.
       *
       * @param {string}   options.name - Saved data set name.
       *
       * @returns {import('../../types').SvelteApp.API.State.Data | undefined} Any saved application state.
       */
      get({ name: name2 }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`[SvelteApp.state.get] error: 'name' is not a string.`);
        }
        return this.#dataSaved.get(name2);
      }
      /**
       * @returns {IterableIterator<string>} The saved application state names / keys.
       */
      keys() {
        return this.#dataSaved.keys();
      }
      /**
       * Removes and returns any saved application state by name.
       *
       * @param {object}   options - Options.
       *
       * @param {string}   options.name - Name to remove and retrieve.
       *
       * @returns {import('../../types').SvelteApp.API.State.Data | undefined} Any saved application state.
       */
      remove({ name: name2 }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`[SvelteApp.state.remove] error: 'name' is not a string.`);
        }
        const data = this.#dataSaved.get(name2);
        this.#dataSaved.delete(name2);
        return data;
      }
      /**
       * Restores a previously saved application state by `name` returning the data. Several optional parameters are
       * available to animate / tween to the new state. When `animateTo` is true an animation is scheduled via
       * {@link #runtime/svelte/store/position!TJSPosition.API.Animation.to} and the duration and easing name or function may be
       * specified.
       *
       * @param {object}            options - Options.
       *
       * @param {string}            options.name - Saved data set name.
       *
       * @param {boolean}           [options.remove=false] - Remove data set.
       *
       * @param {boolean}           [options.animateTo=false] - Animate to restore data.
       *
       * @param {number}            [options.duration=0.1] - Duration in seconds.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/easing').EasingReference} [options.ease='linear'] - Easing function or easing
       *        function name.
       *
       * @returns {import('../../types').SvelteApp.API.State.Data | undefined} Any saved application state.
       */
      restore({ name: name2, remove = false, animateTo = false, duration = 0.1, ease = "linear" }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`[SvelteApp.state.restore] error: 'name' is not a string.`);
        }
        const dataSaved = this.#dataSaved.get(name2);
        if (dataSaved) {
          if (remove) {
            this.#dataSaved.delete(name2);
          }
          if (animateTo && name2 !== this.#currentRestoreKey) {
            this.#currentRestoreKey = name2;
            this.#setImpl(dataSaved, {
              animateTo,
              async: true,
              duration,
              ease
            }).then(() => {
              if (name2 === this.#currentRestoreKey) {
                this.#currentRestoreKey = void 0;
              }
            });
          }
        }
        return dataSaved;
      }
      /**
       * Saves current application state with the opportunity to add extra data to the saved state.
       *
       * @param {object}   options - Options.
       *
       * @param {string}   options.name - Name to index this saved state.
       *
       * @returns {import('../../types').SvelteApp.API.State.Data} Current saved application state.
       */
      save({ name: name2, ...extra }) {
        if (typeof name2 !== "string") {
          throw new TypeError(`[SvelteApp.state.save] error: 'name' is not a string.`);
        }
        const data = this.current(extra);
        this.#dataSaved.set(name2, data);
        return data;
      }
      /**
       * Sets application state from the given `SvelteApp.API.State.Data` instance. Several optional parameters are
       * available to animate / tween to the new state. When `animateTo` is true an animation is scheduled via
       * {@link #runtime/svelte/store/position!AnimationAPI.to} and the duration and easing name or function may be
       * specified.
       *
       * Note: If serializing application state any minimized apps will use the before minimized state on initial render
       * of the app as it is currently not possible to render apps with Foundry VTT core API in the minimized state.
       *
       * @param {import('../../types').SvelteApp.API.State.Data}   data - Saved data set name.
       *
       * @param {object}         [options] - Optional parameters
       *
       * @param {boolean}        [options.animateTo=false] - Animate to restore data.
       *
       * @param {number}         [options.duration=0.1] - Duration in seconds.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/easing').EasingReference} [options.ease='linear'] - Easing function or easing
       *        function name.
       */
      set(data, options = {}) {
        this.#setImpl(data, { ...options, async: false });
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Sets application state from the given `SvelteApp.API.State.Data` instance. Several optional parameters are
       * available to animate / tween to the new state. When `animateTo` is true an animation is scheduled via
       * {@link #runtime/svelte/store/position!AnimationAPI.to} and the duration and easing name or function may be
       * specified.
       *
       * Note: If serializing application state any minimized apps will use the before minimized state on initial render
       * of the app as it is currently not possible to render apps with Foundry VTT core API in the minimized state.
       *
       * @privateRemarks
       * TODO: THIS METHOD NEEDS TO BE REFACTORED WHEN TRL IS MADE INTO A STANDALONE FRAMEWORK.
       *
       * @param {import('../../types').SvelteApp.API.State.Data}   data - Saved data set name.
       *
       * @param {object}            [opts] - Optional parameters
       *
       * @param {boolean}           [opts.async=false] - If animating return a Promise that resolves with any saved data.
       *
       * @param {boolean}           [opts.animateTo=false] - Animate to restore data.
       *
       * @param {number}            [opts.duration=0.1] - Duration in seconds.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/easing').EasingReference} [opts.ease='linear'] - Easing function or easing
       *        function name.
       *
       * @returns {undefined | Promise<void>} When asynchronous the animation Promise.
       */
      #setImpl(data, { async = false, animateTo = false, duration = 0.1, ease = "linear" } = {}) {
        if (!isObject(data)) {
          throw new TypeError(`[SvelteApp.state.set] error: 'data' is not an object.`);
        }
        const application = this.#application;
        if (!isObject(data?.position)) {
          console.warn(`[SvelteApp.state.set] warning: 'data.position' is not an object.`);
          return;
        }
        const rendered = application.rendered;
        if (animateTo) {
          if (!rendered) {
            console.warn(`[SvelteApp.state.set] warning: application is not rendered and 'animateTo' is true.`);
            return;
          }
          if (data.position.transformOrigin !== application.position.transformOrigin) {
            application.position.transformOrigin = data.position.transformOrigin;
          }
          if (isObject(data?.ui)) {
            const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
            if (application?.reactive?.minimized && !minimized) {
              application.maximize({ animate: false, duration: 0 });
            }
          }
          const promise2 = application.position.animate.to(data.position, {
            duration,
            ease,
            strategy: "cancelAll"
          }).finished.then(({ cancelled }) => {
            if (cancelled) {
              return;
            }
            if (isObject(data?.options)) {
              application?.reactive.mergeOptions(data.options);
            }
            if (isObject(data?.ui)) {
              const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
              if (!application?.reactive?.minimized && minimized) {
                application.minimize({ animate: false, duration: 0 });
              }
            }
            if (isObject(data?.beforeMinimized)) {
              application.position.state.set({ name: "#beforeMinimized", ...data.beforeMinimized });
            }
          });
          if (async) {
            return promise2;
          }
        } else {
          if (rendered) {
            if (isObject(data?.options)) {
              application?.reactive.mergeOptions(data.options);
            }
            if (isObject(data?.ui)) {
              const minimized = typeof data.ui?.minimized === "boolean" ? data.ui.minimized : false;
              if (application?.reactive?.minimized && !minimized) {
                application.maximize({ animate: false, duration: 0 });
              } else if (!application?.reactive?.minimized && minimized) {
                application.minimize({ animate: false, duration });
              }
            }
            if (isObject(data?.beforeMinimized)) {
              application.position.state.set({ name: "#beforeMinimized", ...data.beforeMinimized });
            }
            application.position.set(data.position);
          } else {
            let positionData = data.position;
            if (isObject(data.beforeMinimized)) {
              positionData = data.beforeMinimized;
              positionData.left = data.position.left;
              positionData.top = data.position.top;
            }
            application.position.set(positionData);
          }
        }
      }
    }
    class GetSvelteData {
      /** @type {import('svelte').SvelteComponent[] | null[]} */
      #applicationShellHolder;
      /** @type {import('./types').SvelteData[]} */
      #svelteData;
      /**
       * Keep a direct reference to the SvelteData array in an associated {@link SvelteApp}.
       *
       * @param {import('svelte').SvelteComponent[] | null[]}  applicationShellHolder - A reference to the mounted app shell.
       *
       * @param {import('./types').SvelteData[]}  svelteData - A reference to the SvelteData array of mounted components.
       */
      constructor(applicationShellHolder, svelteData) {
        this.#applicationShellHolder = applicationShellHolder;
        this.#svelteData = svelteData;
      }
      /**
       * Returns any mounted application shell.
       *
       * @returns {import('svelte').SvelteComponent} Any mounted application shell.
       */
      get appShell() {
        return this.#applicationShellHolder[0];
      }
      /**
       * Returns any mounted application shell.
       *
       * @deprecated Use {@link GetSvelteData.appShell}; since `0.2.0` removal in `0.5.0`.
       *
       * @returns {import('svelte').SvelteComponent} Any mounted application shell.
       */
      get applicationShell() {
        return this.#applicationShellHolder[0];
      }
      /**
       * Returns mounted application shell data / config.
       *
       * @internal
       *
       * @returns {import('./types').SvelteData} Any mounted application shell data.
       */
      get appShellData() {
        return this.#svelteData[0];
      }
    }
    class SvelteReactive {
      /**
       * @type {import('../SvelteApp').SvelteApp}
       */
      #application;
      /**
       * @type {boolean}
       */
      #initialized = false;
      /** @type {import('@typhonjs-fvtt/runtime/svelte/store/web-storage').WebStorage} */
      #sessionStorage;
      /**
       * The Application option store which is injected into mounted Svelte component context under the `external` key.
       *
       * @type {import('./types').StoreAppOptions}
       */
      #storeAppOptions;
      /**
       * Stores the update function for `#storeAppOptions`.
       *
       * @type {(this: void, updater: import('svelte/store').Updater<object>) => void}
       */
      #storeAppOptionsUpdate;
      /**
       * Stores the UI state data to make it accessible via getters.
       *
       * @type {object}
       */
      #dataUIState;
      /**
       * The UI option store which is injected into mounted Svelte component context under the `external` key.
       *
       * @type {import('./types').StoreUIOptions}
       */
      #storeUIState;
      /**
       * Stores the update function for `#storeUIState`.
       *
       * @type {(this: void, updater: import('svelte/store').Updater<object>) => void}
       */
      #storeUIStateUpdate;
      /**
       * Stores the unsubscribe functions from local store subscriptions.
       *
       * @type {import('svelte/store').Unsubscriber[]}
       */
      #storeUnsubscribe = [];
      /**
       * @param {import('../SvelteApp').SvelteApp} application - The host Foundry application.
       */
      constructor(application) {
        this.#application = application;
        const optionsSessionStorage = application?.options?.sessionStorage;
        if (optionsSessionStorage !== void 0 && !(optionsSessionStorage instanceof TJSWebStorage)) {
          throw new TypeError(`'options.sessionStorage' is not an instance of TJSWebStorage.`);
        }
        this.#sessionStorage = optionsSessionStorage !== void 0 ? optionsSessionStorage : new TJSSessionStorage();
      }
      /**
       * Initializes reactive support. Package private for internal use.
       *
       * @returns {import('./types-local').SvelteReactiveStores | undefined} Internal methods to interact with Svelte
       * stores.
       *
       * @package
       * @internal
       */
      initialize() {
        if (this.#initialized) {
          return;
        }
        this.#initialized = true;
        this.#storesInitialize();
        return {
          appOptionsUpdate: this.#storeAppOptionsUpdate,
          uiStateUpdate: this.#storeUIStateUpdate,
          subscribe: this.#storesSubscribe.bind(this),
          unsubscribe: this.#storesUnsubscribe.bind(this)
        };
      }
      // Store getters -----------------------------------------------------------------------------------------------------
      /**
       * @returns {import('@typhonjs-fvtt/runtime/svelte/store/web-storage').WebStorage} Returns WebStorage (session) instance.
       */
      get sessionStorage() {
        return this.#sessionStorage;
      }
      /**
       * Returns the store for app options.
       *
       * @returns {import('../../types').SvelteApp.API.Reactive.AppOptions} App options store.
       */
      get storeAppOptions() {
        return this.#storeAppOptions;
      }
      /**
       * Returns the store for UI options.
       *
       * @returns {import('../../types').SvelteApp.API.Reactive.UIState} UI options store.
       */
      get storeUIState() {
        return this.#storeUIState;
      }
      // Only reactive getters ---------------------------------------------------------------------------------------------
      /**
       * Returns the current active Window / WindowProxy UI state.
       *
       * @returns {Window} Active window UI state.
       */
      get activeWindow() {
        return this.#dataUIState.activeWindow ?? globalThis;
      }
      /**
       * Returns the current dragging UI state.
       *
       * @returns {boolean} Dragging UI state.
       */
      get dragging() {
        return this.#dataUIState.dragging;
      }
      /**
       * Returns the current minimized UI state.
       *
       * @returns {boolean} Minimized UI state.
       */
      get minimized() {
        return this.#dataUIState.minimized;
      }
      /**
       * Returns the current resizing UI state.
       *
       * @returns {boolean} Resizing UI state.
       */
      get resizing() {
        return this.#dataUIState.resizing;
      }
      /**
       * Sets the current active Window / WindowProxy UI state.
       *
       * Note: This is protected usage and used internally.
       *
       * @param {Window} activeWindow - Active Window / WindowProxy UI state.
       *
       * @hidden
       */
      set activeWindow(activeWindow) {
        if (activeWindow === void 0 || activeWindow === null || Object.prototype.toString.call(activeWindow) === "[object Window]") {
          this.#storeUIStateUpdate((options) => deepMerge(options, { activeWindow: activeWindow ?? globalThis }));
        }
      }
      // Reactive getter / setters -----------------------------------------------------------------------------------------
      /**
       * Returns the draggable app option.
       *
       * @returns {boolean} Draggable app option.
       */
      get draggable() {
        return this.#application?.options?.draggable;
      }
      /**
       * Returns the focusAuto app option.
       *
       * @returns {boolean} When true auto-management of app focus is enabled.
       */
      get focusAuto() {
        return this.#application?.options?.focusAuto;
      }
      /**
       * Returns the focusKeep app option.
       *
       * @returns {boolean} When `focusAuto` and `focusKeep` is true; keeps internal focus.
       */
      get focusKeep() {
        return this.#application?.options?.focusKeep;
      }
      /**
       * Returns the focusTrap app option.
       *
       * @returns {boolean} When true focus trapping / wrapping is enabled keeping focus inside app.
       */
      get focusTrap() {
        return this.#application?.options?.focusTrap;
      }
      /**
       * Returns the headerButtonNoClose app option.
       *
       * @returns {boolean} Remove the close the button in header app option.
       */
      get headerButtonNoClose() {
        return this.#application?.options?.headerButtonNoClose;
      }
      /**
       * Returns the headerButtonNoLabel app option.
       *
       * @returns {boolean} Remove the labels from buttons in header app option.
       */
      get headerButtonNoLabel() {
        return this.#application?.options?.headerButtonNoLabel;
      }
      /**
       * Returns the headerIcon app option.
       *
       * @returns {string|void} URL for header app icon.
       */
      get headerIcon() {
        return this.#application?.options?.headerIcon;
      }
      /**
       * Returns the headerNoTitleMinimized app option.
       *
       * @returns {boolean} When true removes the header title when minimized.
       */
      get headerNoTitleMinimized() {
        return this.#application?.options?.headerNoTitleMinimized;
      }
      /**
       * Returns the minimizable app option.
       *
       * @returns {boolean} Minimizable app option.
       */
      get minimizable() {
        return this.#application?.options?.minimizable;
      }
      /**
       * Returns the Foundry popOut state; {@link Application.popOut}
       *
       * @returns {boolean} Positionable app option.
       */
      get popOut() {
        return this.#application.popOut;
      }
      /**
       * Returns the positionable app option; {@link SvelteApp.Options.positionable}
       *
       * @returns {boolean} Positionable app option.
       */
      get positionable() {
        return this.#application?.options?.positionable;
      }
      /**
       * Returns the resizable option.
       *
       * @returns {boolean} Resizable app option.
       */
      get resizable() {
        return this.#application?.options?.resizable;
      }
      /**
       * Returns the title accessor from the parent Application class; {@link Application.title}
       *
       * @privateRemarks
       * TODO: Application v2; note that super.title localizes `this.options.title`; IMHO it shouldn't.    *
       *
       * @returns {string} Title.
       */
      get title() {
        return this.#application.title;
      }
      /**
       * Sets `this.options.draggable` which is reactive for application shells.
       *
       * @param {boolean}  draggable - Sets the draggable option.
       */
      set draggable(draggable2) {
        if (typeof draggable2 === "boolean") {
          this.setOptions("draggable", draggable2);
        }
      }
      /**
       * Sets `this.options.focusAuto` which is reactive for application shells.
       *
       * @param {boolean}  focusAuto - Sets the focusAuto option.
       */
      set focusAuto(focusAuto) {
        if (typeof focusAuto === "boolean") {
          this.setOptions("focusAuto", focusAuto);
        }
      }
      /**
       * Sets `this.options.focusKeep` which is reactive for application shells.
       *
       * @param {boolean}  focusKeep - Sets the focusKeep option.
       */
      set focusKeep(focusKeep) {
        if (typeof focusKeep === "boolean") {
          this.setOptions("focusKeep", focusKeep);
        }
      }
      /**
       * Sets `this.options.focusTrap` which is reactive for application shells.
       *
       * @param {boolean}  focusTrap - Sets the focusTrap option.
       */
      set focusTrap(focusTrap) {
        if (typeof focusTrap === "boolean") {
          this.setOptions("focusTrap", focusTrap);
        }
      }
      /**
       * Sets `this.options.headerButtonNoClose` which is reactive for application shells.
       *
       * @param {boolean}  headerButtonNoClose - Sets the headerButtonNoClose option.
       */
      set headerButtonNoClose(headerButtonNoClose) {
        if (typeof headerButtonNoClose === "boolean") {
          this.setOptions("headerButtonNoClose", headerButtonNoClose);
        }
      }
      /**
       * Sets `this.options.headerButtonNoLabel` which is reactive for application shells.
       *
       * @param {boolean}  headerButtonNoLabel - Sets the headerButtonNoLabel option.
       */
      set headerButtonNoLabel(headerButtonNoLabel) {
        if (typeof headerButtonNoLabel === "boolean") {
          this.setOptions("headerButtonNoLabel", headerButtonNoLabel);
        }
      }
      /**
       * Sets `this.options.headerIcon` which is reactive for application shells.
       *
       * @param {string | undefined}  headerIcon - Sets the headerButtonNoLabel option.
       */
      set headerIcon(headerIcon) {
        if (headerIcon === void 0 || typeof headerIcon === "string") {
          this.setOptions("headerIcon", headerIcon);
        }
      }
      /**
       * Sets `this.options.headerNoTitleMinimized` which is reactive for application shells.
       *
       * @param {boolean}  headerNoTitleMinimized - Sets the headerNoTitleMinimized option.
       */
      set headerNoTitleMinimized(headerNoTitleMinimized) {
        if (typeof headerNoTitleMinimized === "boolean") {
          this.setOptions("headerNoTitleMinimized", headerNoTitleMinimized);
        }
      }
      /**
       * Sets `this.options.minimizable` which is reactive for application shells that are also pop out.
       *
       * @param {boolean}  minimizable - Sets the minimizable option.
       */
      set minimizable(minimizable) {
        if (typeof minimizable === "boolean") {
          this.setOptions("minimizable", minimizable);
        }
      }
      /**
       * Sets `this.options.popOut` which is reactive for application shells. This will add / remove this application
       * from `ui.windows`.
       *
       * @param {boolean}  popOut - Sets the popOut option.
       */
      set popOut(popOut) {
        if (typeof popOut === "boolean") {
          this.setOptions("popOut", popOut);
        }
      }
      /**
       * Sets `this.options.positionable` enabling / disabling {@link SvelteApp.position}.
       *
       * @param {boolean}  positionable - Sets the positionable option.
       */
      set positionable(positionable) {
        if (typeof positionable === "boolean") {
          this.setOptions("positionable", positionable);
        }
      }
      /**
       * Sets `this.options.resizable` which is reactive for application shells.
       *
       * @param {boolean}  resizable - Sets the resizable option.
       */
      set resizable(resizable) {
        if (typeof resizable === "boolean") {
          this.setOptions("resizable", resizable);
        }
      }
      /**
       * Sets `this.options.title` which is reactive for application shells.
       *
       * Note: Will set empty string if title is undefined or null.
       *
       * @param {string | undefined | null}   title - Application title; will be localized, so a translation key is fine.
       */
      set title(title) {
        if (typeof title === "string") {
          this.setOptions("title", title);
        } else if (title === void 0 || title === null) {
          this.setOptions("title", "");
        }
      }
      // Reactive Options API -------------------------------------------------------------------------------------------
      /**
       * Provides a way to safely get this applications options given an accessor string which describes the
       * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
       * to walk.
       *
       * // TODO DOCUMENT the accessor in more detail.
       *
       * @param {string}   accessor - The path / key to set. You can set multiple levels.
       *
       * @param {*}        [defaultValue] - A default value returned if the accessor is not found.
       *
       * @returns {*} Value at the accessor.
       */
      getOptions(accessor, defaultValue) {
        return safeAccess(this.#application.options, accessor, defaultValue);
      }
      /**
       * Provides a way to merge `options` into this applications options and update the appOptions store.
       *
       * @param {object}   options - The options object to merge with `this.options`.
       */
      mergeOptions(options) {
        this.#storeAppOptionsUpdate((instanceOptions) => deepMerge(instanceOptions, options));
      }
      /**
       * Provides a way to safely set this applications options given an accessor string which describes the
       * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
       * to walk.
       *
       * Additionally, if an application shell Svelte component is mounted and exports the `appOptions` property then
       * the application options is set to `appOptions` potentially updating the application shell / Svelte component.
       *
       * @param {string}   accessor - The path / key to set. You can set multiple levels.
       *
       * @param {any}      value - Value to set.
       */
      setOptions(accessor, value) {
        const success = safeSet(this.#application.options, accessor, value, { createMissing: true });
        if (success) {
          this.#storeAppOptionsUpdate(() => this.#application.options);
        }
      }
      /**
       * Serializes the main {@link SvelteApp.Options} for common application state.
       *
       * @returns {import('../../types').SvelteApp.API.Reactive.Data} Common application state.
       */
      toJSON() {
        return {
          draggable: this.#application?.options?.draggable ?? true,
          focusAuto: this.#application?.options?.focusAuto ?? true,
          focusKeep: this.#application?.options?.focusKeep ?? false,
          focusTrap: this.#application?.options?.focusTrap ?? true,
          headerButtonNoClose: this.#application?.options?.headerButtonNoClose ?? false,
          headerButtonNoLabel: this.#application?.options?.headerButtonNoLabel ?? false,
          headerNoTitleMinimized: this.#application?.options?.headerNoTitleMinimized ?? false,
          minimizable: this.#application?.options?.minimizable ?? true,
          positionable: this.#application?.options?.positionable ?? true,
          resizable: this.#application?.options?.resizable ?? true
        };
      }
      /**
       * Updates the UI Options store with the current header buttons. You may dynamically add / remove header buttons
       * if using an application shell Svelte component. In either overriding `_getHeaderButtons` or responding to the
       * Hooks fired return a new button array and the uiOptions store is updated and the application shell will render
       * the new buttons.
       *
       * Optionally you can set in the SvelteApp app options {@link SvelteApp.Options.headerButtonNoClose}
       * to remove the close button and {@link SvelteApp.Options.headerButtonNoLabel} to true and labels will be
       * removed from the header buttons.
       *
       * @param {object} [opts] - Optional parameters (for internal use)
       *
       * @param {boolean} [opts.headerButtonNoClose] - The value for `headerButtonNoClose`.
       *
       * @param {boolean} [opts.headerButtonNoLabel] - The value for `headerButtonNoLabel`.
       */
      updateHeaderButtons({
        headerButtonNoClose = this.#application.options.headerButtonNoClose,
        headerButtonNoLabel = this.#application.options.headerButtonNoLabel
      } = {}) {
        let buttons = this.#application._getHeaderButtons();
        if (typeof headerButtonNoClose === "boolean" && headerButtonNoClose) {
          buttons = buttons.filter((button) => button.class !== "close");
        }
        if (typeof headerButtonNoLabel === "boolean" && headerButtonNoLabel) {
          for (const button of buttons) {
            button.label = void 0;
          }
        }
        this.#storeUIStateUpdate((options) => {
          options.headerButtons = buttons;
          return options;
        });
      }
      // Internal implementation ----------------------------------------------------------------------------------------
      /**
       * Initializes the Svelte stores and derived stores for the application options and UI state.
       *
       * While writable stores are created the update method is stored in private variables locally and derived Readable
       * stores are provided for essential options which are commonly used.
       *
       * These stores are injected into all Svelte components mounted under the `external` context: `storeAppOptions` and
       * `storeUIState`.
       */
      #storesInitialize() {
        const writableAppOptions = writable(this.#application.options);
        this.#storeAppOptionsUpdate = writableAppOptions.update;
        const storeAppOptions = {
          subscribe: writableAppOptions.subscribe,
          draggable: propertyStore(writableAppOptions, "draggable"),
          focusAuto: propertyStore(writableAppOptions, "focusAuto"),
          focusKeep: propertyStore(writableAppOptions, "focusKeep"),
          focusTrap: propertyStore(writableAppOptions, "focusTrap"),
          headerButtonNoClose: propertyStore(writableAppOptions, "headerButtonNoClose"),
          headerButtonNoLabel: propertyStore(writableAppOptions, "headerButtonNoLabel"),
          headerIcon: propertyStore(writableAppOptions, "headerIcon"),
          headerNoTitleMinimized: propertyStore(writableAppOptions, "headerNoTitleMinimized"),
          minimizable: propertyStore(writableAppOptions, "minimizable"),
          popOut: propertyStore(writableAppOptions, "popOut"),
          positionable: propertyStore(writableAppOptions, "positionable"),
          resizable: propertyStore(writableAppOptions, "resizable"),
          title: propertyStore(writableAppOptions, "title")
        };
        Object.freeze(storeAppOptions);
        this.#storeAppOptions = storeAppOptions;
        this.#dataUIState = {
          activeWindow: globalThis,
          dragging: false,
          headerButtons: [],
          minimized: this.#application._minimized,
          resizing: false
        };
        const writableUIOptions = writable(this.#dataUIState);
        this.#storeUIStateUpdate = writableUIOptions.update;
        const storeUIState = {
          subscribe: writableUIOptions.subscribe,
          // activeWindow: propertyStore(writableUIOptions, 'activeWindow'),
          activeWindow: derived(writableUIOptions, ($options, set2) => set2($options.activeWindow)),
          dragging: propertyStore(writableUIOptions, "dragging"),
          headerButtons: derived(writableUIOptions, ($options, set2) => set2($options.headerButtons)),
          minimized: derived(writableUIOptions, ($options, set2) => set2($options.minimized)),
          resizing: propertyStore(writableUIOptions, "resizing")
        };
        Object.freeze(storeUIState);
        this.#storeUIState = storeUIState;
      }
      /**
       * Registers local store subscriptions for app options. `popOut` controls registering this app with `ui.windows`.
       *
       * @see SvelteApp._injectHTML
       */
      #storesSubscribe() {
        this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.headerButtonNoClose, (value) => {
          this.updateHeaderButtons({ headerButtonNoClose: value });
        }));
        this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.headerButtonNoLabel, (value) => {
          this.updateHeaderButtons({ headerButtonNoLabel: value });
        }));
        this.#storeUnsubscribe.push(subscribeIgnoreFirst(this.#storeAppOptions.popOut, (value) => {
          if (value && this.#application.rendered) {
            globalThis.ui.windows[this.#application.appId] = this.#application;
          } else {
            delete globalThis.ui.windows[this.#application.appId];
          }
        }));
      }
      /**
       * Unsubscribes from any locally monitored stores.
       *
       * @see SvelteApp.close
       */
      #storesUnsubscribe() {
        this.#storeUnsubscribe.forEach((unsubscribe) => unsubscribe());
        this.#storeUnsubscribe = [];
      }
    }
    const applicationShellContract = ["elementRoot"];
    Object.freeze(applicationShellContract);
    function isApplicationShell(component) {
      if (component === null || component === void 0) {
        return false;
      }
      let compHasContract = true;
      let protoHasContract = true;
      for (const accessor of applicationShellContract) {
        const descriptor = Object.getOwnPropertyDescriptor(component, accessor);
        if (descriptor === void 0 || descriptor.get === void 0 || descriptor.set === void 0) {
          compHasContract = false;
        }
      }
      const prototype = Object.getPrototypeOf(component);
      for (const accessor of applicationShellContract) {
        const descriptor = Object.getOwnPropertyDescriptor(prototype, accessor);
        if (descriptor === void 0 || descriptor.get === void 0 || descriptor.set === void 0) {
          protoHasContract = false;
        }
      }
      return compHasContract || protoHasContract;
    }
    function loadSvelteConfig({ app, config, elementRootUpdate } = {}) {
      let target;
      if (CrossWindow.isHTMLElement(config.target)) {
        target = config.target;
      } else if (typeof config.target === "string") {
        const activeWindow = app?.reactive?.activeWindow;
        target = activeWindow?.document?.querySelector(config.target);
      }
      if (!CrossWindow.isHTMLElement(target)) {
        console.log(
          `%c[TRL] loadSvelteConfig error - Could not find target, '${config.target}', for config:
`,
          "background: rgb(57,34,34)",
          config
        );
        throw new Error();
      }
      const NewSvelteComponent = config.class;
      const svelteConfig = TJSSvelte.config.parseConfig({ ...config, target }, { contextExternal: true, thisArg: app });
      const externalContext = svelteConfig.context.get("#external");
      externalContext.application = app;
      externalContext.elementRootUpdate = elementRootUpdate;
      externalContext.sessionStorage = app.reactive.sessionStorage;
      let eventbus;
      if (isObject(app._eventbus) && typeof app._eventbus.createProxy === "function") {
        eventbus = app._eventbus.createProxy();
        externalContext.eventbus = eventbus;
      }
      Object.seal(externalContext);
      const component = new NewSvelteComponent(svelteConfig);
      svelteConfig.eventbus = eventbus;
      let element2;
      if (isApplicationShell(component)) {
        element2 = component.elementRoot;
      }
      if (!CrossWindow.isHTMLElement(element2)) {
        console.log(
          `%c[TRL] loadSvelteConfig error - No application shell contract found. Did you bind and export a HTMLElement as 'elementRoot' and include '<svelte:options accessors={true}/>'?

Offending config:
`,
          "background: rgb(57,34,34)",
          config
        );
        throw new Error();
      }
      return { config: svelteConfig, component, element: element2 };
    }
    class TJSAppIndex {
      /**
       * Stores all visible / rendered apps.
       *
       * @type {Map<string, import('@typhonjs-fvtt/runtime/svelte/application').SvelteApp>}
       */
      static #visibleApps = /* @__PURE__ */ new Map();
      /**
       * Adds a SvelteApp to all visible apps tracked.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/application').SvelteApp} app - A SvelteApp
       *
       * @package
       */
      static add(app) {
        this.#visibleApps.set(app.id, app);
      }
      /**
       * Removes a SvelteApp from all visible apps tracked.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/application').SvelteApp} app - A SvelteApp
       *
       * @package
       */
      static delete(app) {
        this.#visibleApps.delete(app.id);
      }
      /**
       * Gets a particular app by ID.
       *
       * @param {string}   key - App ID.
       *
       * @returns {import('@typhonjs-fvtt/runtime/svelte/application').SvelteApp} Associated app.
       */
      static get(key) {
        return this.#visibleApps.get(key);
      }
      /**
       * Returns whether an associated app by ID is being tracked.
       *
       * @param {string}   key - App ID.
       *
       * @returns {boolean} The given App ID is visible.
       */
      static has(key) {
        return this.#visibleApps.has(key);
      }
      /**
       * @returns {IterableIterator<string>} All visible app IDs.
       */
      static keys() {
        return this.#visibleApps.keys();
      }
      /**
       * @returns {IterableIterator<import('@typhonjs-fvtt/runtime/svelte/application').SvelteApp>} All visible apps.
       */
      static values() {
        return this.#visibleApps.values();
      }
    }
    class SvelteApp extends Application {
      /**
       * Stores the first mounted component which follows the application shell contract.
       *
       * @type {import('svelte').SvelteComponent[] | null[]} Application shell.
       */
      #applicationShellHolder = [null];
      /**
       * Stores and manages application state for saving / restoring / serializing.
       *
       * @type {import('./types').SvelteApp.API.State}
       */
      #applicationState;
      /**
       * Stores the target element which may not necessarily be the main element.
       *
       * @type {HTMLElement}
       */
      #elementTarget = null;
      /**
       * Stores the content element which is set for application shells.
       *
       * @type {HTMLElement}
       */
      #elementContent = null;
      /**
       * On initial render gating of `setPosition` invoked by `Application._render` occurs, so that percentage values
       * can correctly be positioned with initial helper constraints (centered).
       *
       * @type {boolean}
       */
      #gateSetPosition = false;
      /**
       * Stores initial z-index from `_renderOuter` to set to target element / Svelte component.
       *
       * @type {number}
       */
      #initialZIndex = 95;
      /**
       * Stores on mount state which is checked in _render to trigger onSvelteMount callback.
       *
       * @type {boolean}
       */
      #onMount = false;
      /**
       * The position store.
       *
       * @type {TJSPosition}
       */
      #position;
      /**
       * Contains the Svelte stores and reactive accessors.
       *
       * @type {SvelteReactive}
       */
      #reactive;
      /**
       * Stores SvelteData entries with instantiated Svelte components.
       *
       * @type {import('./internal/state-svelte/types').SvelteData[] | null[]}
       */
      #svelteData = [null];
      /**
       * Provides a helper class that combines multiple methods for interacting with the mounted components tracked in
       * #svelteData.
       *
       * @type {import('./types').SvelteApp.API.Svelte<Options>}
       */
      #getSvelteData = new GetSvelteData(this.#applicationShellHolder, this.#svelteData);
      /**
       * Contains methods to interact with the Svelte stores.
       *
       * @type {import('./internal/state-reactive/types-local').SvelteReactiveStores}
       */
      #stores;
      /**
       * @param {Partial<import('./types').SvelteApp.Options>} [options] - The options for the application.
       */
      constructor(options = {}) {
        super(options);
        if (!isObject(this.options.svelte)) {
          throw new Error(`SvelteApp - constructor - No Svelte configuration object found in 'options'.`);
        }
        this.#applicationState = new ApplicationState(this);
        this.#position = new TJSPosition(this, {
          ...this.position,
          ...this.options,
          initial: this.options.positionInitial,
          ortho: this.options.positionOrtho,
          validator: this.options.positionValidator
        });
        delete this.position;
        Object.defineProperty(this, "position", {
          get: () => this.#position,
          set: (position) => {
            if (isObject(position)) {
              this.#position.set(position);
            }
          }
        });
        this.#reactive = new SvelteReactive(this);
        this.#stores = this.#reactive.initialize();
      }
      /**
       * Specifies the default options that SvelteApp supports.
       *
       * @returns {import('./types').SvelteApp.Options} options - Application options.
       * @see https://foundryvtt.com/api/interfaces/client.ApplicationOptions.html
       */
      static get defaultOptions() {
        return (
          /** @type {import('./types').SvelteApp.Options} */
          deepMerge(super.defaultOptions, {
            defaultCloseAnimation: true,
            // If false the default slide close animation is not run.
            draggable: true,
            // If true then application shells are draggable.
            focusAuto: true,
            // When true auto-management of app focus is enabled.
            focusKeep: false,
            // When `focusAuto` and `focusKeep` is true; keeps internal focus.
            focusSource: void 0,
            // Stores any A11yFocusSource data that is applied when app is closed.
            focusTrap: true,
            // When true focus trapping / wrapping is enabled keeping focus inside app.
            headerButtonNoClose: false,
            // If true then the close header button is removed.
            headerButtonNoLabel: false,
            // If true then header button labels are removed for application shells.
            headerIcon: void 0,
            // Sets a header icon given an image URL.
            headerNoTitleMinimized: false,
            // If true then header title is hidden when application is minimized.
            minHeight: MIN_WINDOW_HEIGHT,
            // Assigned to position. Number specifying minimum window height.
            minWidth: MIN_WINDOW_WIDTH,
            // Assigned to position. Number specifying minimum window width.
            positionable: true,
            // If false then `position.set` does not take effect.
            positionInitial: TJSPosition.Initial.browserCentered,
            // A helper for initial position placement.
            positionOrtho: true,
            // When true TJSPosition is optimized for orthographic use.
            positionValidator: TJSPosition.Validators.transformWindow,
            // A function providing the default validator.
            sessionStorage: void 0,
            // An instance of WebStorage (session) to share across SvelteApps.
            svelte: void 0,
            // A Svelte configuration object.
            transformOrigin: "top left"
            // By default, 'top / left' respects rotation when minimizing.
          })
        );
      }
      /**
       * Returns the content element if an application shell is mounted.
       *
       * @returns {HTMLElement} Content element.
       */
      get elementContent() {
        return this.#elementContent;
      }
      /**
       * Returns the target element or main element if no target defined.
       *
       * @returns {HTMLElement} Target element.
       */
      get elementTarget() {
        return this.#elementTarget;
      }
      /**
       * Returns the reactive accessors & Svelte stores for SvelteApp.
       *
       * @returns {import('./types').SvelteApp.API.Reactive} The reactive accessors & Svelte stores.
       */
      get reactive() {
        return this.#reactive;
      }
      /**
       * Returns the application state manager.
       *
       * @returns {import('./types').SvelteApp.API.State} The application state manager.
       */
      get state() {
        return this.#applicationState;
      }
      /**
       * Returns the `Svelte` helper class w/ various methods to access the mounted application shell component.
       *
       * @returns {import('./types').SvelteApp.API.Svelte<Options>} `Svelte` / mounted application shell API.
       */
      get svelte() {
        return this.#getSvelteData;
      }
      /**
       * In this case of when a template is defined in app options `html` references the inner HTML / template. However,
       * to activate classic v1 tabs for a Svelte component the element target is passed as an array simulating JQuery as
       * the element is retrieved immediately and the core listeners use standard DOM queries.
       *
       * @protected
       * @ignore
       * @internal
       */
      _activateCoreListeners(html) {
        super._activateCoreListeners(typeof this.options.template === "string" ? html : [this.popOut ? this.#elementTarget?.firstChild : this.#elementTarget]);
      }
      /**
       * Provide an override to set this application as the active window regardless of z-index. Changes behaviour from
       * Foundry core.
       *
       * @param {object} [opts] - Optional parameters.
       *
       * @param {boolean} [opts.focus=true] - When true and the active element is not contained in the app `elementTarget`
       *        is focused..
       *
       * @param {boolean} [opts.force=false] - Force bring to top; will increment z-index by popOut order.
       *
       * @ignore
       * @internal
       */
      bringToTop({ focus = true, force = false } = {}) {
        if (this.reactive.activeWindow !== globalThis) {
          return;
        }
        if (force || this.popOut) {
          super.bringToTop();
        }
        const elementTarget = this.elementTarget;
        const activeElement = document.activeElement;
        if (focus && elementTarget && activeElement !== elementTarget && !elementTarget?.contains(activeElement)) {
          if (A11yHelper.isFocusTarget(activeElement)) {
            activeElement.blur();
          }
          elementTarget?.focus();
        }
        globalThis.ui.activeWindow = this;
      }
      /**
       * Note: This method is fully overridden and duplicated as Svelte components need to be destroyed manually and the
       * best visual result is to destroy them after the default slide up animation occurs, but before the element
       * is removed from the DOM.
       *
       * If you destroy the Svelte components before the slide up animation the Svelte elements are removed immediately
       * from the DOM. The purpose of overriding ensures the slide up animation is always completed before
       * the Svelte components are destroyed and then the element is removed from the DOM.
       *
       * Close the application and unregisters references to it within UI mappings.
       * This function returns a Promise which resolves once the window closing animation concludes.
       *
       * @param {object}   [options] - Optional parameters.
       *
       * @param {boolean}  [options.force] - Force close regardless of render state.
       *
       * @returns {Promise<void>}    A Promise which resolves once the application is closed.
       *
       * @ignore
       * @internal
       */
      async close(options = {}) {
        const states = Application.RENDER_STATES;
        if (!options.force && ![states.RENDERED, states.ERROR].includes(this._state)) {
          return;
        }
        const el = this.#elementTarget;
        if (!el) {
          this._state = states.CLOSED;
          return;
        }
        if (CrossWindow.getWindow(el, { throws: false }) !== globalThis) {
          return;
        }
        this._state = states.CLOSING;
        this.#stores.unsubscribe();
        const content = el.querySelector(".window-content");
        if (content) {
          content.style.overflow = "hidden";
          for (let cntr = content.children.length; --cntr >= 0; ) {
            content.children[cntr].style.overflow = "hidden";
          }
        }
        for (const cls of this.constructor._getInheritanceChain()) {
          Hooks.call(`close${cls.name}`, this, $(el));
        }
        const animate = typeof this.options.defaultCloseAnimation === "boolean" ? this.options.defaultCloseAnimation : true;
        if (animate) {
          el.style.minHeight = "0";
          const { paddingBottom, paddingTop } = globalThis.getComputedStyle(el);
          await el.animate([
            { maxHeight: `${el.clientHeight}px`, paddingTop, paddingBottom },
            { maxHeight: 0, paddingTop: 0, paddingBottom: 0 }
          ], { duration: 250, easing: "ease-in", fill: "forwards" }).finished;
        }
        const svelteDestroyPromises = [];
        for (const entry of this.#svelteData) {
          if (!isObject(entry)) {
            continue;
          }
          svelteDestroyPromises.push(TJSSvelte.util.outroAndDestroy(entry.component));
          const eventbus = entry.config.eventbus;
          if (isObject(eventbus) && typeof eventbus.off === "function") {
            eventbus.off();
            entry.config.eventbus = void 0;
          }
        }
        await Promise.allSettled(svelteDestroyPromises);
        TJSAppIndex.delete(this);
        this.#svelteData[0] = null;
        el.remove();
        this.position.state.restore({
          name: "#beforeMinimized",
          properties: ["width", "height"],
          silent: true,
          remove: true
        });
        this.#applicationShellHolder[0] = null;
        this._element = null;
        this.#elementContent = null;
        this.#elementTarget = null;
        delete globalThis.ui.windows[this.appId];
        this._minimized = false;
        this._scrollPositions = null;
        this._state = states.CLOSED;
        this.#onMount = false;
        this.#stores.uiStateUpdate((storeOptions) => deepMerge(storeOptions, { minimized: this._minimized }));
        A11yHelper.applyFocusSource(this.options.focusSource);
        delete this.options.focusSource;
      }
      /**
       * Specify the set of config buttons which should appear in the SvelteApp header. Buttons should be returned as
       * an Array of objects. The header buttons which are added to the application can be modified by the
       * `getApplicationHeaderButtons` hook.
       *
       * SvelteApp extends the button functionality with full reactivity for state changes during callbacks. Callbacks
       * receive the button data and can modify it to update the button state.
       *
       * @privateRemarks Provide a basic override implementation to extend types with additional SvelteApp functionality.
       *
       * @returns {import('./types').SvelteApp.HeaderButton[]} All header buttons.
       * @protected
       */
      _getHeaderButtons() {
        return super._getHeaderButtons();
      }
      /**
       * Inject the Svelte components defined in `this.options.svelte`. The Svelte component can attach to the existing
       * pop-out of Application or provide no template and render into a document fragment which is then attached to the
       * DOM.
       *
       * @protected
       * @ignore
       * @internal
       */
      _injectHTML() {
        this.reactive.updateHeaderButtons();
        const elementRootUpdate = () => {
          let cntr = 0;
          return (elementRoot) => {
            if (elementRoot !== null && elementRoot !== void 0 && cntr++ > 0) {
              this.#updateApplicationShell();
              return true;
            }
            return false;
          };
        };
        if (!isObject(this.options.svelte)) {
          throw new Error(`SvelteApp - _injectHTML - No Svelte configuration object found in 'options'.`);
        }
        const svelteData = loadSvelteConfig({
          app: this,
          config: this.options.svelte,
          elementRootUpdate
        });
        if (this.svelte.appShell !== null) {
          throw new Error(
            `SvelteApp - _injectHTML - An application shell is already mounted; offending config:
${JSON.stringify(this.options.svelte)}`
          );
        }
        this.#applicationShellHolder[0] = svelteData.component;
        if (TJSSvelte.util.isHMRProxy(svelteData.component) && Array.isArray(svelteData.component?.$$?.on_hmr)) {
          svelteData.component.$$.on_hmr.push(() => () => this.#updateApplicationShell());
        }
        this.#svelteData[0] = svelteData;
        this._element = $(this.svelte.appShell.elementRoot);
        this.#elementContent = hasGetter(this.svelte.appShell, "elementContent") ? this.svelte.appShell.elementContent : null;
        this.#elementTarget = hasGetter(this.svelte.appShell, "elementTarget") ? this.svelte.appShell.elementTarget : this.svelte.appShell.elementRoot;
        if (typeof this.options.positionable === "boolean" && this.options.positionable) {
          this.#elementTarget.style.zIndex = typeof this.options.zIndex === "number" ? this.options.zIndex : this.#initialZIndex ?? 95;
        }
        this.#stores.subscribe();
      }
      /**
       * Provides a mechanism to update the UI options store for maximized.
       *
       * Note: the sanity check is duplicated from {@link Application.maximize} the store is updated _before_
       * performing the rest of animations. This allows application shells to remove / show any resize handlers
       * correctly. Extra constraint data is stored in a saved position state in {@link SvelteApp.minimize}
       * to animate the content area.
       *
       * @param {object}   [opts] - Optional parameters.
       *
       * @param {boolean}  [opts.animate=true] - When true perform default maximizing animation.
       *
       * @param {number}   [opts.duration=0.1] - Controls content area animation duration in seconds.
       */
      async maximize({ animate = true, duration = 0.1 } = {}) {
        if (!this.popOut || [false, null].includes(this._minimized)) {
          return;
        }
        this._minimized = null;
        const durationMS = duration * 1e3;
        const element2 = this.elementTarget;
        const header = element2.querySelector(".window-header");
        const content = element2.querySelector(".window-content");
        const positionBefore = this.position.state.get({ name: "#beforeMinimized" });
        if (animate) {
          await this.position.state.restore({
            name: "#beforeMinimized",
            async: true,
            animateTo: true,
            properties: ["width"],
            duration: 0.1
          });
        }
        element2.classList.remove("minimized");
        for (let cntr = header.children.length; --cntr >= 0; ) {
          header.children[cntr].style.display = null;
        }
        content.style.display = null;
        let constraints;
        if (animate) {
          ({ constraints } = this.position.state.restore({
            name: "#beforeMinimized",
            animateTo: true,
            properties: ["height"],
            remove: true,
            duration
          }));
        } else {
          ({ constraints } = this.position.state.remove({ name: "#beforeMinimized" }));
        }
        await content.animate([
          { maxHeight: 0, paddingTop: 0, paddingBottom: 0, offset: 0 },
          { ...constraints, offset: 1 },
          { maxHeight: "100%", offset: 1 }
        ], { duration: durationMS, fill: "forwards" }).finished;
        this.position.set({
          minHeight: positionBefore.minHeight ?? this.options?.minHeight ?? MIN_WINDOW_HEIGHT,
          minWidth: positionBefore.minWidth ?? this.options?.minWidth ?? MIN_WINDOW_WIDTH
        });
        element2.style.minWidth = null;
        element2.style.minHeight = null;
        this._minimized = false;
        setTimeout(() => {
          content.style.overflow = null;
          for (let cntr = content.children.length; --cntr >= 0; ) {
            content.children[cntr].style.overflow = null;
          }
        }, 50);
        this.#stores.uiStateUpdate((options) => deepMerge(options, { minimized: false }));
      }
      /**
       * Provides a mechanism to update the UI options store for minimized.
       *
       * Note: the sanity check is duplicated from {@link Application.minimize} the store is updated _before_
       * performing the rest of animations. This allows application shells to remove / show any resize handlers
       * correctly. Extra constraint data is stored in a saved position state in {@link SvelteApp.minimize}
       * to animate the content area.
       *
       * @param {object}   [opts] - Optional parameters.
       *
       * @param {boolean}  [opts.animate=true] - When true perform default minimizing animation.
       *
       * @param {number}   [opts.duration=0.1] - Controls content area animation duration in seconds.
       */
      async minimize({ animate = true, duration = 0.1 } = {}) {
        if (!this.rendered || !this.popOut || [true, null].includes(this._minimized)) {
          return;
        }
        this.#stores.uiStateUpdate((options) => deepMerge(options, { minimized: true }));
        this._minimized = null;
        const durationMS = duration * 1e3;
        const element2 = this.elementTarget;
        const header = element2.querySelector(".window-header");
        const content = element2.querySelector(".window-content");
        const beforeMinWidth = this.position.minWidth;
        const beforeMinHeight = this.position.minHeight;
        this.position.set({ minWidth: 100, minHeight: 30 });
        element2.style.minWidth = "100px";
        element2.style.minHeight = "30px";
        if (content) {
          content.style.overflow = "hidden";
          for (let cntr = content.children.length; --cntr >= 0; ) {
            content.children[cntr].style.overflow = "hidden";
          }
        }
        const { paddingBottom, paddingTop } = globalThis.getComputedStyle(content);
        const constraints = {
          maxHeight: `${content.clientHeight}px`,
          paddingTop,
          paddingBottom
        };
        if (animate) {
          const animation2 = content.animate([
            constraints,
            { maxHeight: 0, paddingTop: 0, paddingBottom: 0 }
          ], { duration: durationMS, fill: "forwards" });
          animation2.finished.then(() => content.style.display = "none");
        } else {
          setTimeout(() => content.style.display = "none", durationMS);
        }
        const saved = this.position.state.save({ name: "#beforeMinimized", constraints });
        saved.minWidth = beforeMinWidth;
        saved.minHeight = beforeMinHeight;
        const headerOffsetHeight = header.offsetHeight;
        this.position.minHeight = headerOffsetHeight;
        if (animate) {
          await this.position.animate.to({ height: headerOffsetHeight }, { duration }).finished;
        }
        for (let cntr = header.children.length; --cntr >= 0; ) {
          const className = header.children[cntr].className;
          if (className.includes("window-title") || className.includes("close")) {
            continue;
          }
          if (className.includes("keep-minimized")) {
            header.children[cntr].style.display = "block";
            continue;
          }
          header.children[cntr].style.display = "none";
        }
        if (animate) {
          await this.position.animate.to({ width: MIN_WINDOW_WIDTH }, { duration: 0.1 }).finished;
        }
        element2.classList.add("minimized");
        this._minimized = true;
      }
      /**
       * Provides a callback after all Svelte components are initialized.
       */
      onSvelteMount() {
      }
      // eslint-disable-line no-unused-vars
      /**
       * Provides a callback after the main application shell is remounted. This may occur during HMR / hot module
       * replacement or directly invoked from the `elementRootUpdate` callback passed to the application shell component
       * context.
       */
      onSvelteRemount() {
      }
      // eslint-disable-line no-unused-vars
      /**
       * Override replacing HTML as Svelte components control the rendering process. Only potentially change the outer
       * application frame / title for pop-out applications.
       *
       * @protected
       * @ignore
       * @internal
       */
      _replaceHTML(element2, html) {
        if (!element2.length) {
          return;
        }
        this.reactive.updateHeaderButtons();
      }
      /**
       * Provides an override verifying that a new Application being rendered for the first time doesn't have a
       * corresponding DOM element already loaded. This is a check that only occurs when `this._state` is
       * `Application.RENDER_STATES.NONE`. It is useful in particular when SvelteApp has a static ID
       * explicitly set in `this.options.id` and long intro / outro transitions are assigned. If a new application
       * sharing this static ID attempts to open / render for the first time while an existing DOM element sharing
       * this static ID exists then the initial render is cancelled below rather than crashing later in the render
       * cycle {@link TJSPosition.set}.
       *
       * @protected
       * @ignore
       * @internal
       */
      async _render(force = false, options = {}) {
        if (isObject(options?.focusSource)) {
          this.options.focusSource = options.focusSource;
        }
        const activeWindow = this.reactive.activeWindow;
        try {
          if (this._state === Application.RENDER_STATES.NONE && A11yHelper.isFocusTarget(activeWindow.document.querySelector(`#${this.id}`))) {
            console.warn(`SvelteApp - _render: A DOM element already exists for CSS ID '${this.id}'. Cancelling initial render for new application with appId '${this.appId}'.`);
            return;
          }
        } catch (err) {
          console.warn(`SvelteApp - _render: Potentially malformed application ID '${this.id}'. Cancelling initial render for new application with appId '${this.appId}'.`);
          return;
        }
        this.#gateSetPosition = true;
        await super._render(force, options);
        this.#gateSetPosition = false;
        if ([Application.RENDER_STATES.CLOSING, Application.RENDER_STATES.RENDERING].includes(this._state)) {
          return;
        }
        if (!force && this._state <= Application.RENDER_STATES.NONE) {
          return;
        }
        if (!this._minimized) {
          this.#position.set({
            left: typeof this.options?.left === "string" ? this.options.left : void 0,
            height: typeof this.options?.height === "string" ? this.options.height : void 0,
            maxHeight: typeof this.options?.maxHeight === "string" ? this.options.maxHeight : void 0,
            maxWidth: typeof this.options?.maxWidth === "string" ? this.options.maxWidth : void 0,
            minHeight: typeof this.options?.minHeight === "string" ? this.options.minHeight : void 0,
            minWidth: typeof this.options?.minWidth === "string" ? this.options.minWidth : void 0,
            rotateX: typeof this.options?.rotateX === "string" ? this.options.rotateX : void 0,
            rotateY: typeof this.options?.rotateY === "string" ? this.options.rotateY : void 0,
            rotateZ: typeof this.options?.rotateZ === "string" ? this.options.rotateZ : void 0,
            rotation: typeof this.options?.rotation === "string" ? this.options.rotation : void 0,
            top: typeof this.options?.top === "string" ? this.options.top : void 0,
            width: typeof this.options?.width === "string" ? this.options.width : void 0,
            ...options
          });
        }
        if (!this.#onMount) {
          TJSAppIndex.add(this);
          this.onSvelteMount();
          this.#onMount = true;
        }
      }
      /**
       * Render the inner application content. Provide an empty JQuery element per the core Foundry API.
       *
       * @protected
       * @ignore
       * @internal
       */
      async _renderInner() {
        const activeWindow = this.reactive.activeWindow;
        const html = activeWindow.document.createDocumentFragment();
        return $(html);
      }
      /**
       * Stores the initial z-index set in `_renderOuter` which is used in `_injectHTML` to set the target element
       * z-index after the Svelte component is mounted.
       *
       * @protected
       * @ignore
       * @internal
       */
      async _renderOuter() {
        const html = await super._renderOuter();
        this.#initialZIndex = html[0].style.zIndex;
        return html;
      }
      /**
       * All calculation and updates of position are implemented in {@link TJSPosition.set}.
       * This allows position to be fully reactive and in control of updating inline styles for the application.
       *
       * This method remains for backward compatibility with Foundry. If you have a custom override quite likely you need
       * to update to using the {@link TJSPosition.validators} / ValidatorAPI functionality.
       *
       * @param {TJSPosition.API.Data.TJSPositionDataRelative}   [position] - TJSPosition data.
       *
       * @returns {TJSPosition} The updated position object for the application containing the new values.
       * @ignore
       */
      setPosition(position) {
        return !this.#gateSetPosition ? this.position.set(position) : this.position;
      }
      /**
       * This method is invoked by the `elementRootUpdate` callback that is added to the external context passed to
       * Svelte components. When invoked it updates the local element roots tracked by SvelteApp.
       *
       * This method may also be invoked by HMR / hot module replacement via `svelte-hmr`.
       */
      #updateApplicationShell() {
        const applicationShell = this.svelte.appShell;
        if (applicationShell !== null) {
          this._element = $(applicationShell.elementRoot);
          this.#elementContent = hasGetter(applicationShell, "elementContent") ? applicationShell.elementContent : null;
          this.#elementTarget = hasGetter(applicationShell, "elementTarget") ? applicationShell.elementTarget : null;
          if (this.#elementTarget === null) {
            this.#elementTarget = typeof this.options.selectorTarget === "string" ? this._element[0].querySelector(this.options.selectorTarget) : this._element[0];
          }
          if (typeof this.options.positionable === "boolean" && this.options.positionable) {
            this.#elementTarget.style.zIndex = typeof this.options.zIndex === "number" ? this.options.zIndex : this.#initialZIndex ?? 95;
            super.bringToTop();
            this.position.set(this.position.get());
          }
          super._activateCoreListeners([this.popOut ? this.#elementTarget?.firstChild : this.#elementTarget]);
          this.onSvelteRemount();
        }
      }
    }
    class PopoutSupport {
      static initialize() {
        Hooks.on("PopOut:loading", (app, popout) => {
          if (app instanceof SvelteApp) {
            app.position.enabled = false;
            app.state.save({
              name: "#beforePopout",
              headerButtonNoClose: app.reactive.headerButtonNoClose
            });
            app.reactive.activeWindow = popout;
            app.reactive.headerButtonNoClose = true;
          }
        });
        Hooks.on("PopOut:popin", (app) => this.#handleRejoin(app));
        Hooks.on("PopOut:close", (app) => this.#handleRejoin(app));
      }
      /**
       * Handles rejoining the app to main browser window.
       *
       * @param {Application} app - The target app.
       */
      static #handleRejoin(app) {
        if (app instanceof SvelteApp) {
          app.position.enabled = true;
          const beforeData = app.state.remove({ name: "#beforePopout" });
          if (beforeData) {
            app.reactive.headerButtonNoClose = beforeData?.headerButtonNoClose ?? false;
          }
          app.reactive.activeWindow = void 0;
        }
      }
    }
    class TJSDialogData {
      /**
       * @type {import('../../index.js').SvelteApp}
       */
      #application;
      /**
       * Stores the dialog options data.
       *
       * @type {import('./types').TJSDialog.OptionsData}
       */
      #internal = {};
      /**
       * @param {import('../../index.js').SvelteApp} application - The host Foundry application.
       */
      constructor(application) {
        this.#application = application;
        Object.seal(this);
      }
      /**
       * @returns {{ [key: string]: import('./types').TJSDialogButtonData }} The dialog button configuration.
       */
      get buttons() {
        return this.#internal.buttons;
      }
      /**
       * Set the dialog button configuration.
       *
       * @param {string} buttons - New dialog button configuration.
       */
      set buttons(buttons) {
        this.#internal.buttons = buttons;
        this.#updateComponent();
      }
      /**
       * @returns {import('@typhonjs-fvtt/runtime/svelte/util').TJSSvelte.Config.Minimal | string} The Svelte configuration object or HTML string
       *          content.
       */
      get content() {
        return this.#internal.content;
      }
      /**
       * Set the Svelte configuration object or HTML string content.
       *
       * @param {import('@typhonjs-fvtt/runtime/svelte/util').TJSSvelte.Config.Minimal | string} content - New Svelte configuration object or
       *        HTML string content.
       */
      set content(content) {
        this.#internal.content = content;
        this.#updateComponent();
      }
      /**
       * @returns {string} The default button ID to focus initially.
       */
      get default() {
        return this.#internal.default;
      }
      /**
       * Set the default button ID to focus initially.
       *
       * @param {string} newDefault - New default button ID to focus initially.
       */
      set default(newDefault) {
        this.#internal.default = newDefault;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} The dialog draggable state; draggable when true.
       */
      get draggable() {
        return this.#internal.draggable;
      }
      /**
       * Set the dialog state; draggable when true.
       *
       * @param {boolean} draggable - New dialog draggable state; draggable when true.
       */
      set draggable(draggable2) {
        this.#internal.draggable = draggable2;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true auto-management of app focus is enabled.
       */
      get focusAuto() {
        return this.#internal.focusAuto;
      }
      /**
       * Set the dialog auto-management of app focus.
       *
       * @param {boolean} focusAuto - New dialog auto-management of app focus.
       */
      set focusAuto(focusAuto) {
        this.#internal.focusAuto = focusAuto;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true the first focusable element that isn't a button is focused.
       */
      get focusFirst() {
        return this.#internal.focusFirst;
      }
      /**
       * Set the dialog first focusable element state.
       *
       * @param {boolean} focusFirst - New dialog first focusable element state.
       */
      set focusFirst(focusFirst) {
        this.#internal.focusFirst = focusFirst;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When `focusAuto` and `focusKeep` is true; keeps internal focus.
       */
      get focusKeep() {
        return this.#internal.focusKeep;
      }
      /**
       * Set the dialog `focusKeep` state. When `focusAuto` and `focusKeep` is true; keeps internal focus.
       *
       * @param {boolean} focusKeep - New dialog `focusKeep` state.
       */
      set focusKeep(focusKeep) {
        this.#internal.focusKeep = focusKeep;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true the dialog is minimizable.
       */
      get minimizable() {
        return this.#internal.minimizable;
      }
      /**
       * Set the dialog `minimizable` state. When true the dialog is minimizable.
       *
       * @param {boolean} minimizable - New dialog `minimizable` state.
       */
      set minimizable(minimizable) {
        this.#internal.minimizable = minimizable;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true a modal dialog is displayed.
       */
      get modal() {
        return this.#internal.modal;
      }
      /**
       * Set the dialog `modal` state. When true a modal dialog is displayed.
       *
       * @param {boolean} modal - New dialog `modal` state.
       */
      set modal(modal) {
        this.#internal.modal = modal;
        this.#updateComponent();
      }
      /**
       * @returns {import('./types').TJSDialog.OptionsModal} Additional options for modal dialog display.
       */
      get modalOptions() {
        return this.#internal.modalOptions;
      }
      /**
       * Set additional options for modal dialog display.
       *
       * @param {import('./types').TJSDialog.OptionsModal} modalOptions - New additional options for modal dialog display.
       */
      set modalOptions(modalOptions) {
        this.#internal.modalOptions = modalOptions;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true and an error is raised in dialog callback functions post a UI error notification.
       */
      get notifyError() {
        return this.#internal.notifyError;
      }
      /**
       * Set the dialog `notifyError` state. When true and an error is raised in dialog callback functions post a UI error
       * notification.
       *
       * @param {boolean} notifyError - New dialog `notifyError` state.
       */
      set notifyError(notifyError) {
        this.#internal.notifyError = notifyError;
        this.#updateComponent();
      }
      /**
       * @returns {string | ((data?: { application?: import('../../index.js').TJSDialog }) => any)} Callback invoked when
       *          dialog is closed; no button option selected. When defined as a string any matching function by name
       *          exported from content Svelte component is invoked.
       */
      get onClose() {
        return this.#internal.onClose;
      }
      /**
       * Set callback invoked when dialog is closed; no button option selected. When defined as a string any matching
       * function by name exported from content Svelte component is invoked..
       *
       * @param {string | ((data?: { application?: import('../../index.js').TJSDialog }) => any)} onClose - New dialog
       *        `onClose` state.
       */
      set onClose(onClose) {
        this.#internal.onClose = onClose;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} Dialog `rejectClose` state. When true and a Promise has been created by {@link TJSDialog.wait}
       *          and the Promise is not in the process of being resolved or rejected on close of the dialog any `onClose`
       *          function is invoked and any result that is undefined will cause the Promise to then be rejected..
       */
      get rejectClose() {
        return this.#internal.rejectClose;
      }
      /**
       * Set the dialog `rejectClose` state.
       *
       * @param {boolean} rejectClose - New dialog `rejectClose` state.
       */
      set rejectClose(rejectClose) {
        this.#internal.rejectClose = rejectClose;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true the dialog is resizable.
       */
      get resizable() {
        return this.#internal.resizable;
      }
      /**
       * Set the dialog `resizable` state. When true the dialog is resizable.
       *
       * @param {boolean} resizable - New dialog `resizable` state.
       */
      set resizable(resizable) {
        this.#internal.resizable = resizable;
        this.#updateComponent();
      }
      /**
       * @returns {boolean} When true and resolving any Promises and there are undefined results from any button callbacks
       *          the button ID is resolved.
       */
      get resolveId() {
        return this.#internal.resolveId;
      }
      /**
       * Set the dialog `resolveId` state. When true and resolving any Promises and there are undefined results from any
       * button callbacks the button ID is resolved.
       *
       * @param {boolean} resolveId - New dialog `resolveId` state.
       */
      set resolveId(resolveId) {
        this.#internal.resolveId = resolveId;
        this.#updateComponent();
      }
      /**
       * @returns {string} The dialog window title.
       */
      get title() {
        return this.#internal.title;
      }
      /**
       * Set the dialog window title.
       *
       * @param {string} title - New dialog window title.
       */
      set title(title) {
        this.#internal.title = title;
        this.#updateComponent();
      }
      /**
       * @returns {import('./types').TJSDialog.OptionsTransition} Transition options for the dialog.
       */
      get transition() {
        return this.#internal.transition;
      }
      /**
       * Set transition options for the dialog.
       *
       * @param {import('./types').TJSDialog.OptionsTransition} transition - New transition options for the dialog.
       */
      set transition(transition) {
        this.#internal.transition = transition;
        this.#updateComponent();
      }
      /**
       * @returns {number | null} A specific z-index for the dialog. Pass null for the dialog to act like other
       *          applications in regard bringing to top when activated.
       */
      get zIndex() {
        return this.#internal.zIndex;
      }
      /**
       * Set specific z-index for the dialog.
       *
       * @param {number | null} zIndex - New z-index for the dialog.
       */
      set zIndex(zIndex) {
        this.#internal.zIndex = zIndex;
        this.#updateComponent();
      }
      /**
       * Provides a cloned copy of the dialog data.
       * Note: The content attribute is not cloned as complex / props may be present.
       *
       * @returns {import('./types').TJSDialog.OptionsData} A clone of the dialog data.
       */
      clone() {
        const shallowCopy = { ...this.#internal };
        delete shallowCopy.content;
        const cData = klona(shallowCopy);
        cData.content = this.#internal.content;
        return cData;
      }
      /**
       * Provides a way to safely get this dialogs data given an accessor string which describes the
       * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
       * to walk.
       *
       * @param {string}   accessor - The path / key to set. You can set multiple levels.
       *
       * @param {any}      [defaultValue] - A default value returned if the accessor is not found.
       *
       * @returns {any} Value at the accessor.
       */
      get(accessor, defaultValue) {
        return safeAccess(this.#internal, accessor, defaultValue);
      }
      /**
       * @param {import('./types').TJSDialog.OptionsData} data - Merge provided data object into Dialog data.
       */
      merge(data) {
        deepMerge(this.#internal, data);
        this.#updateComponent();
      }
      /**
       * Sets the dialog data; this is reactive.
       *
       * @param {import('./types').TJSDialog.OptionsData}   data - Dialog data.
       */
      replace(data) {
        if (!isObject(data)) {
          throw new TypeError(`TJSDialogData replace error: 'data' is not an object'.`);
        }
        this.#internal = {};
        this.merge(data);
      }
      /**
       * Provides a way to safely set this dialogs data given an accessor string which describes the
       * entries to walk. To access deeper entries into the object format the accessor string with `.` between entries
       * to walk.
       *
       * Automatically the dialog data will be updated in the associated DialogShell Svelte component.
       *
       * @param {string}   accessor - The path / key to set. You can set multiple levels.
       *
       * @param {any}      value - Value to set.
       *
       * @returns {boolean} True if successful.
       */
      set(accessor, value) {
        const success = safeSet(this.#internal, accessor, value, { createMissing: true });
        if (success) {
          this.#updateComponent();
        }
        return success;
      }
      /**
       * Updates the data in the Svelte dialog component.
       */
      #updateComponent() {
        const component = this.#application.svelte.appShell;
        if (component?.data) {
          component.data = this.clone();
        }
      }
    }
    class TJSDialog extends SvelteApp {
      /** @type {TJSDialogData} */
      #data;
      /** @type {ManagedPromise} */
      #managedPromise;
      /**
       * @param {import('./internal/state-dialog/types').TJSDialog.OptionsData} data - Dialog options.
       *
       * @param {import('./types').SvelteApp.OptionsCore}   [options] - SvelteApp options.
       */
      constructor(data, options = {}) {
        super({ popOutModuleDisable: typeof data?.modal === "boolean" ? data.modal : false, ...options });
        this.#managedPromise = new ManagedPromise();
        this.#data = new TJSDialogData(this);
        this.#data.replace(data);
      }
      /**
       * Default options for TJSDialog. Provides a default width and setting `height` to `auto` to always display dialog
       * content even if it changes. The default `DialogShell` / `svelte` options should not be changed and instead mount
       * the dialog content component by supplying a Svelte configuration object to dialog data `content` field.
       *
       * @returns {import('./types').SvelteApp.Options} Default options
       */
      static get defaultOptions() {
        return (
          /** @type {import('./types').SvelteApp.Options} */
          deepMerge(super.defaultOptions, {
            classes: ["dialog", "tjs-dialog"],
            width: 400,
            height: "auto",
            svelte: {
              class: DialogShell,
              intro: true,
              target: document.body,
              /**
               * `this` is the TJSDialog instance when invoked.
               *
               * @this {TJSDialog}
               *
               * @returns {{data: import('./types').TJSDialog.OptionsData, managedPromise: ManagedPromise}} Props
               */
              props: function() {
                return {
                  data: this.#data.clone(),
                  managedPromise: this.#managedPromise
                };
              }
            }
          })
        );
      }
      /**
       * Returns the dialog data.
       *
       * @returns {import('./internal/state-dialog/types').TJSDialog.Data} Dialog data.
       */
      get data() {
        return this.#data;
      }
      /**
       * @returns {import('@typhonjs-fvtt/runtime/util/async').ManagedPromise} Returns the managed promise.
       */
      get managedPromise() {
        return this.#managedPromise;
      }
      /**
       * Close the dialog and un-register references to it within UI mappings.
       * This function returns a Promise which resolves once the window closing animation concludes.
       *
       * @param {object}   [options] - Optional parameters.
       *
       * @param {boolean}  [options.force] - Force close regardless of render state.
       *
       * @returns {Promise<void>} A Promise which resolves once the application is closed with the callback value or
       *                          `true`.
       */
      async close(options) {
        try {
          if (this.#managedPromise.isActive && !this.#managedPromise.isProcessing) {
            const result = TJSDialog.#invokeFn(this.#data.onClose, this, null);
            const rejectClose = typeof this.#data.rejectClose === "boolean" ? this.#data.rejectClose : false;
            if (rejectClose && result === null) {
              this.#managedPromise.reject(new Error("TJSDialog was closed without a choice being made."));
            } else {
              this.#managedPromise.resolve(result);
            }
          }
        } catch (err) {
          const notifyError = typeof this.#data.notifyError === "boolean" ? this.#data.notifyError : true;
          if (notifyError) {
            globalThis.ui.notifications.error(err, { console: false });
          }
          if (!this.#managedPromise.reject(err)) {
            throw err;
          }
        } finally {
          await super.close(options);
        }
      }
      /**
       * Brings to top or renders this dialog returning a Promise that is resolved any button pressed or when the dialog
       * is closed.
       *
       * Creates an anonymous data defined TJSDialog returning a Promise that can be awaited upon for the user to make a
       * choice.
       *
       * Note: `null` is returned if the dialog is closed without a user making a choice.
       *
       * @template T
       *
       * @param {object}   [options] - Options.
       *
       * @param {boolean}  [options.reuse=false] - When true if there is an existing managed Promise this allows multiple
       *        sources to await on the same result.
       *
       * @returns {Promise<T>} A promise for dialog resolution.
       */
      async wait(options) {
        if (this.rendered) {
          this.bringToTop();
        } else {
          this.render(true, { focus: true });
        }
        return this.#managedPromise.create(options);
      }
      // ---------------------------------------------------------------------------------------------------------------
      /**
       * A helper factory method to create simple confirmation dialog windows which consist of simple yes / no prompts.
       * If you require more flexibility, a custom TJSDialog instance is preferred. The default focused button is 'yes'.
       * You can change the default focused button by setting `default` to `yes` or `no`.
       *
       * @template T
       *
       * @param {import('./internal/state-dialog/types').TJSDialog.OptionsData & {
       *    onYes?: string | ((data?: { application?: TJSDialog }) => any),
       *    onNo?: string | ((data?: { application?: TJSDialog }) => any)
       * }} [data] - Confirm dialog options.
       *
       * @param {string|((data?: { application?: TJSDialog }) => any)} [data.onYes] - Callback function upon `yes`; may be
       *        an async function. When defined as a string any matching function by name exported from content Svelte
       *        component is invoked.
       *
       * @param {string|((data?: { application?: TJSDialog }) => any)} [data.onNo] - Callback function upon `no`; may be an
       *        async function. When defined as a string any matching function by name exported from content Svelte
       *        component is invoked.
       *
       * @param {import('./types').SvelteApp.OptionsCore}  [options]  SvelteApp options passed to the
       *        TJSDialog constructor.
       *
       * @returns {Promise<T>} A promise which resolves with result of yes / no callbacks or true / false.
       *
       * @example
       * const result = await TJSDialog.confirm({
       *  title: 'A Yes or No Question',
       *  content: '<p>Choose wisely.</p>',
       *  onYes: () => 'YES Result',
       *  onNo: () => 'NO Result'
       * });
       *
       * // Logs 'YES result', 'NO Result', or null if the user closed the dialog without making a selection.
       * console.log(result);
       */
      static async confirm({ onYes, onNo, ...data } = {}, options = {}) {
        const mergedButtons = deepMerge({
          yes: {
            icon: "fas fa-check",
            label: "Yes"
          },
          no: {
            icon: "fas fa-times",
            label: "No"
          }
        }, data.buttons ?? {});
        return this.wait({
          ...data,
          buttons: deepMerge(mergedButtons, {
            yes: {
              onPress: ({ application }) => this.#invokeFn(onYes, application, true)
            },
            no: {
              onPress: ({ application }) => this.#invokeFn(onNo, application, false)
            }
          }),
          default: data.default ?? "yes"
        }, options);
      }
      /**
       * A helper method to invoke a callback function directly or lookup an exported function with the same name from any
       * content Svelte component to invoke. This is used internally to apply default values for `confirm` and `prompt`.
       *
       * @param {string|((data?: { application?: TJSDialog }) => any)} callback - Callback function to invoke; may be an
       *        async function. When defined as a string any matching function by name exported from content Svelte
       *        component is invoked.
       *
       * @param {TJSDialog} application - TJSDialog instance passed to callback.
       *
       * @param {*} [defaultResult] - An optional default result to return; undefined if not specified.
       *
       * @returns {*} Result.
       *
       * @internal
       */
      static #invokeFn(callback, application, defaultResult = void 0) {
        let result = defaultResult;
        switch (typeof callback) {
          case "function":
            result = callback({ application });
            break;
          case "string": {
            const dialogComponent = application?.svelte?.appShell?.dialogComponent;
            if (dialogComponent !== void 0 && typeof dialogComponent?.[callback] === "function") {
              result = dialogComponent?.[callback]({ application });
            } else {
              if (dialogComponent === void 0) {
                console.warn(`[TRL] TJSDialog warning: 'onPress' defined as a string with no associated content Svelte component.`);
              } else if (typeof dialogComponent?.[callback] !== "function") {
                console.warn(`[TRL] TJSDialog warning: The content Svelte component does not contain an associated function '${callback}'. Did you remember to add '<svelte:options accessors={true} />' and export the function?`);
              }
            }
            break;
          }
        }
        return result;
      }
      /**
       * A helper factory method to display a basic "prompt" style TJSDialog with a single button.
       *
       * @template T
       *
       * @param {import('./internal/state-dialog/types').TJSDialog.OptionsData & {
       *    onOk?: string | ((data?: { application?: TJSDialog }) => any),
       *    label?: string,
       *    icon?: string
       * }} [data] - Prompt dialog options that includes any TJSDialog options along with the following optional fields:
       *
       * @param {string|((data?: { application?: TJSDialog }) => any)} [data.onOk] - Callback function upon `ok`; may be
       *        an async function. When defined as a string any matching function by name exported from content Svelte
       *        component is invoked.
       *
       * @param {string}   [data.label] - The OK prompt button text.
       *
       * @param {string}   [data.icon="fas fa-check"] - Set another icon besides `fas fa-check` for button.
       *
       * @param {import('./types').SvelteApp.OptionsCore}  [options]  SvelteApp options passed to the
       *        TJSDialog constructor.
       *
       * @returns {Promise<T>} The returned value from the provided callback function or `true` if the button
       *          is pressed.
       *
       * @example
       * const result = await TJSDialog.prompt({
       *  title: 'Are you OK?',
       *  content: '<p>Are you OK?.</p>',
       *  label: 'Feeling Fine!',
       *  onOk: () => 'OK'
       * });
       *
       * // Logs 'OK' or null if the user closed the dialog without making a selection.
       * console.log(result);
       */
      static async prompt({ onOk, label, icon = "fas fa-check", ...data } = {}, options = {}) {
        return this.wait({
          ...data,
          buttons: {
            ok: {
              icon,
              label,
              onPress: ({ application }) => this.#invokeFn(onOk, application, true)
            }
          },
          default: "ok"
        }, options);
      }
      /**
       * Creates an anonymous data defined TJSDialog returning a Promise that can be awaited upon for the user to make a
       * choice.
       *
       * Note: By default `null` is returned if the dialog is closed without a user making a choice.
       *
       * @template T
       *
       * @param {import('./internal/state-dialog/types').TJSDialog.OptionsData}  data - Dialog data passed to the
       *        TJSDialog constructor.
       *
       * @param {import('./types').SvelteApp.OptionsCore}  [options]  SvelteApp options passed to the
       *        TJSDialog constructor.
       *
       * @returns {Promise<T>} A Promise that resolves to the chosen result.
       */
      static async wait(data, options = {}) {
        if (!isObject(data)) {
          throw new TypeError(`TJSDialog.wait error: 'data' is not an object'.`);
        }
        return new this({ ...data }, options).wait();
      }
    }
    PopoutSupport.initialize();
    class loading_bar {
      constructor() {
        this.total = 0;
        this.current = 0;
        this.lastPct = 0;
      }
      init(context, total) {
        this.context = context;
        this.total = total;
        this.current = 0;
        this.lastPct = 0;
        SceneNavigation.displayProgressBar({ label: this.context, pct: 1 });
      }
      incrementProgress() {
        this.current += 1;
        const pct = Math.round(this.current / this.total * 100);
        if (pct !== this.lastPct) {
          debug(`${pct}% loaded...`);
          SceneNavigation.displayProgressBar({ label: this.context, pct });
        }
        this.lastPct = pct;
      }
    }
    const LoadingBar = new loading_bar();
    const FoundryShim = {
      PlaceableObject: foundry?.canvas?.placeables?.PlaceableObject ?? PlaceableObject,
      Token: foundry?.canvas?.placeables?.Token ?? Token,
      MeasuredTemplate: foundry?.canvas?.placeables?.MeasuredTemplate ?? MeasuredTemplate,
      Drawing: foundry?.canvas?.placeables?.Drawing ?? Drawing,
      Tile: foundry?.canvas?.placeables?.Tile ?? Tile,
      SpriteMesh: foundry?.canvas?.containers?.SpriteMesh ?? SpriteMesh,
      InteractionLayer: foundry?.canvas?.layers?.InteractionLayer ?? InteractionLayer,
      srcExists: foundry?.canvas?.srcExists ?? srcExists,
      loadTexture: foundry?.canvas?.loadTexture ?? loadTexture,
      BatchShaderGenerator: foundry?.canvas?.rendering?.batching?.BatchShaderGenerator ?? BatchShaderGenerator,
      BaseSamplerShader: foundry?.canvas?.rendering?.shaders?.BaseSamplerShader ?? BaseSamplerShader,
      AbstractBaseFilter: foundry?.canvas?.rendering?.filters?.AbstractBaseFilter ?? AbstractBaseFilter,
      CanvasAnimation: foundry?.canvas?.animation?.CanvasAnimation ?? CanvasAnimation,
      Canvas: foundry?.canvas?.Canvas ?? Canvas
    };
    const SequencerFileCache = {
      _videos: {},
      _preloadedFiles: /* @__PURE__ */ new Set(),
      _totalCacheSize: 0,
      _validTypes: ["video/webm", "video/x-webm", "application/octet-stream", "binary/octet-stream"],
      /** @type {Map<string, PIXI.Spritesheet>} */
      _spritesheets: /* @__PURE__ */ new Map(),
      /** @type {Map<string, Promise<{spritesheet: PIXI.Spritesheet, scale: number}> | null>} */
      _generateSpritesheetJobs: /* @__PURE__ */ new Map(),
      /** @type {Promise<import("../lib/spritesheets/SpritesheetGenerator.js").SpritesheetGenerator> | null} */
      _spritesheetGenerator: null,
      /**
       *
       * @param {string} inSrc
       * @returns {Promise<Blob>} the video blob
       */
      async loadVideo(inSrc) {
        if (!this._videos[inSrc]) {
          const blob = await fetch(inSrc, {
            mode: "cors",
            credentials: "same-origin"
          }).then((r) => r.blob()).catch((err) => {
            console.error(err);
          });
          if (this._validTypes.indexOf(blob?.type) === -1) return false;
          while (this._totalCacheSize + blob.size > 524288e3) {
            const entries = Object.entries(this._videos);
            entries.sort((a, b) => {
              return b[1].lastUsed - a[1].lastUsed;
            });
            const [oldSrc] = entries[0];
            this._preloadedFiles.delete(oldSrc);
            this._totalCacheSize -= this._videos[oldSrc].blob.size;
            delete this._videos[oldSrc];
          }
          this._totalCacheSize += blob.size;
          this._preloadedFiles.add(inSrc);
          this._videos[inSrc] = {
            blob,
            lastUsed: +/* @__PURE__ */ new Date()
          };
        }
        this._videos[inSrc].lastUsed = +/* @__PURE__ */ new Date();
        return this._videos[inSrc].blob;
      },
      srcExists(inSrc) {
        if (this._preloadedFiles.has(inSrc)) {
          return true;
        }
        return FoundryShim.srcExists(inSrc);
      },
      async loadFile(inSrc, preload = false) {
        if (inSrc.toLowerCase().endsWith(".webm")) {
          let blob = await this.loadVideo(inSrc);
          if (!blob) return false;
          this._preloadedFiles.add(inSrc);
          if (preload) return true;
          return get_video_texture(blob);
        } else if (foundry.audio.AudioHelper.hasAudioExtension(inSrc)) {
          try {
            const audio2 = await foundry.audio.AudioHelper.preloadSound(inSrc);
            if (audio2) {
              this._preloadedFiles.add(inSrc);
            }
            return audio2;
          } catch (err) {
            console.error(`Failed to load audio: ${inSrc}`);
            return false;
          }
        }
        const texture = await FoundryShim.loadTexture(inSrc);
        if (texture) {
          this._preloadedFiles.add(inSrc);
        }
        return texture;
      },
      /**
       * @param {string} inSrc
       * @param {Object} options
       * @param {number} options.minimumScale
       * @return {Promise<PIXI.Spritesheet | undefined>} the compiled spritesheet or
       * undefined if it cannot be generated
       */
      async requestCompiledSpritesheet(inSrc, { minimumScale }) {
        if (!inSrc.toLowerCase().endsWith(".webm")) {
          return;
        }
        if (this._spritesheetGenerator == null) {
          this._spritesheetGenerator = import("./SpritesheetGenerator-n0EQ8ruS.js").then((m) => m.SpritesheetGenerator.create());
        }
        const generator = await this._spritesheetGenerator;
        if (!generator) {
          return;
        }
        let job = this._generateSpritesheetJobs.get(inSrc);
        if (!job) {
          job = new Promise(async (resolve) => {
            const timeStart = Date.now();
            debug(
              `Spritesheets | generating ${inSrc}. Required scale ${minimumScale}`
            );
            const blob = await this.loadVideo(inSrc);
            const buffer = await blob.arrayBuffer();
            let spritesheet = null;
            let scale2 = 1;
            try {
              const result2 = await generator.spritesheetFromBuffer({
                buffer,
                id: inSrc,
                minimumScale
              });
              spritesheet = result2.spritesheet;
              scale2 = result2.scale;
            } catch (error) {
              console.warn(error);
              resolve(null);
              return;
            }
            const w = spritesheet.baseTexture.width;
            const h = spritesheet.baseTexture.height;
            const megaBytes = Math.round(
              spritesheet.baseTexture.resource._levelBuffers.reduce(
                (acc, cur) => acc + cur.levelBuffer.byteLength,
                0
              ) / 1e5
            ) / 10;
            const time2 = Math.round((Date.now() - timeStart) / 100) / 10;
            debug(
              `Spritesheets | ${inSrc} generated in ${time2}s. ${w}x${h} ${megaBytes}mb`
            );
            resolve({ spritesheet, scale: scale2 });
          });
          this._generateSpritesheetJobs.set(inSrc, job);
        }
        const result = await job;
        if (result && result.scale < minimumScale) {
          debug(
            `Spritesheets | ${inSrc} minimum scale of ${minimumScale} requested but only scale ${result.scale} is available`
          );
          return void 0;
        }
        return result?.spritesheet;
      },
      registerSpritesheet(inSrc, inSpriteSheet) {
        const existingSheetRef = this._spritesheets.get(inSrc);
        if (existingSheetRef) {
          existingSheetRef[1] += 1;
        } else {
          this._spritesheets.set(inSrc, [inSpriteSheet, 1]);
        }
      },
      /**
       *
       * @param {string} inSrc
       * @returns {void}
       */
      async unloadSpritesheet(inSrc) {
        const existingSheetRef = this._spritesheets.get(inSrc);
        if (!existingSheetRef) {
          console.error("trying to unlaod spritesheet that was not loaded:", inSrc);
          return;
        }
        existingSheetRef[1] -= 1;
        if (existingSheetRef[1] > 0) {
          return;
        }
        this._generateSpritesheetJobs.delete(inSrc);
        this._spritesheets.delete(inSrc);
        const sheet = existingSheetRef[0];
        sheet.data?.meta?.related_multi_packs ?? [];
        sheet.linkedSheets;
        const cacheKeys = [
          get_sheet_image_url(inSrc, sheet),
          foundry.utils.getRoute(inSrc)
        ];
        await PIXI.Assets.unload(cacheKeys.filter((src) => !!src));
        if (sheet.textures) {
          Object.values(sheet.textures).forEach((t) => t.destroy());
        }
        sheet.baseTexture?.destroy();
      }
    };
    function get_sheet_image_url(inSrc, sheet) {
      const imageName = sheet?.data?.meta?.image;
      if (!imageName) {
        return;
      }
      const srcPrefix = inSrc.split("/").slice(0, -1).join("/");
      const sheetSrc = `${srcPrefix}/${imageName}`;
      return foundry.utils.getRoute(sheetSrc);
    }
    async function get_video_texture(inBlob) {
      return new Promise(async (resolve, reject) => {
        const video = document.createElement("video");
        video.preload = "auto";
        video.crossOrigin = "anonymous";
        video.controls = true;
        video.autoplay = false;
        video.autoload = true;
        video.muted = true;
        video.src = URL.createObjectURL(inBlob);
        let canplay = true;
        video.oncanplay = async () => {
          if (!canplay) return;
          canplay = false;
          video.height = video.videoHeight;
          video.width = video.videoWidth;
          const baseTexture = PIXI.BaseTexture.from(video, {
            resourceOptions: { autoPlay: false }
          });
          if (game.settings.get(CONSTANTS.MODULE_NAME, "enable-fix-pixi")) {
            baseTexture.alphaMode = PIXI.ALPHA_MODES.PREMULTIPLIED_ALPHA;
          }
          const texture = new PIXI.Texture(baseTexture);
          resolve(texture);
          video.oncanplay = null;
        };
        video.onerror = () => {
          URL.revokeObjectURL(video.src);
          reject();
        };
      });
    }
    class SequencerFileBase {
      static make(inData, inDBPath, inMetadata) {
        if (typeof inData === "string" && !inDBPath && !inMetadata) {
          return new SequencerFilePlain(inData);
        }
        const originalFile = inData?.file ?? inData;
        const file = foundry.utils.duplicate(originalFile);
        const isRangeFind = typeof file !== "string" && !Array.isArray(originalFile) ? Object.keys(originalFile).filter((key) => key.endsWith("ft")).length > 0 : false;
        return isRangeFind ? new SequencerFileRangeFind(inData, inDBPath, inMetadata) : new SequencerFile(inData, inDBPath, inMetadata);
      }
    }
    class SequencerFilePlain extends SequencerFileBase {
      #file;
      rangeFind = false;
      constructor(inData) {
        super();
        this.#file = inData;
      }
      getFileForDistance() {
        return this.getFile();
      }
      getFile() {
        return this.#file;
      }
      getAllFiles() {
        return [this.#file];
      }
      async validate() {
        return Promise.resolve(!!this.#file);
      }
      clone() {
        return new SequencerFilePlain(this.#file);
      }
      getTimestamps() {
        return void 0;
      }
    }
    class SequencerFile extends SequencerFileBase {
      rangeFind = false;
      get isFlipbook() {
        return this.originalMetadata?.flipbook;
      }
      constructor(inData, inDBPath, inMetadata) {
        super();
        inData = foundry.utils.duplicate(inData);
        inMetadata = foundry.utils.duplicate(inMetadata);
        this.originalData = inData;
        this.originalMetadata = inMetadata;
        for (let [key, value] of Object.entries(inMetadata)) {
          this[key] = value;
        }
        this.dbPath = inDBPath;
        this.moduleName = inDBPath.split(".")[0];
        this.originalFile = inData?.file ?? inData;
        this.file = foundry.utils.duplicate(this.originalFile);
        this.fileIndex = null;
        this.twister = false;
      }
      clone() {
        return SequencerFile.make(
          this.originalData,
          this.dbPath,
          this.originalMetadata
        );
      }
      async validate() {
        let isValid = true;
        const directories = {};
        const allFiles = this.getAllFiles();
        for (const file of allFiles) {
          let directory = file.split("/");
          directory.pop();
          directory = directory.join("/");
          if (directories[directory] === void 0) {
            directories[directory] = await getFiles(directory);
          }
        }
        for (const file of allFiles) {
          let directory = file.split("/");
          directory.pop();
          directory = directory.join("/");
          if (directories[directory].indexOf(file) === -1) {
            console.warn(
              `"${this.dbPath}" has an incorrect file path, could not find file. Points to:
${file}`
            );
            isValid = false;
          }
        }
        return isValid;
      }
      getAllFiles() {
        return [this.file].deepFlatten();
      }
      getFile() {
        if (Array.isArray(this.file)) {
          this.fileIndex = is_real_number(this.fileIndex) ? this.fileIndex : random_array_element(this.file, {
            twister: this.twister,
            index: true
          });
          return this.file[this.fileIndex];
        }
        return this.file;
      }
      getTimestamps() {
        if (Array.isArray(this.originalMetadata?.timestamps)) {
          return this.originalMetadata?.timestamps?.[this.fileIndex] ?? this.originalMetadata?.timestamps[0];
        }
        return this.originalMetadata?.timestamps;
      }
      getPreviewFile(entry) {
        let parts = entry.split(".");
        let files2 = this.getAllFiles();
        if (Array.isArray(files2)) {
          if (is_real_number(parts[parts.length - 1])) {
            files2 = files2[parts[parts.length - 1]];
          } else {
            const index = Math.floor(interpolate(0, files2.length - 1, 0.5));
            files2 = files2?.[index - 1] ?? files2[index];
          }
        }
        return files2;
      }
      getFileForDistance() {
        return this.getFile();
      }
    }
    class SequencerFileRangeFind extends SequencerFile {
      rangeFind = true;
      constructor(...args) {
        super(...args);
        this._fileDistanceMap = false;
      }
      static get ftToDistanceMap() {
        return {
          "90ft": canvas.grid.size * 15,
          "60ft": canvas.grid.size * 9,
          "30ft": canvas.grid.size * 5,
          "15ft": canvas.grid.size * 2,
          "05ft": 0
        };
      }
      get _gridSizeDiff() {
        return canvas.grid.size / this.template[0];
      }
      getAllFiles() {
        return Object.values(this.file).deepFlatten();
      }
      getFile(inFt = "15ft") {
        if (inFt && this.file[inFt]) {
          if (Array.isArray(this.file[inFt])) {
            const fileIndex = is_real_number(this.fileIndex) ? Math.min(this.file[inFt].length - 1, this.fileIndex) : random_array_element(this.file[inFt], {
              twister: this.twister,
              index: true
            });
            return this.file[inFt][fileIndex];
          }
          return this.file[inFt];
        }
        return this.file;
      }
      getPreviewFile(entry) {
        let parts = entry.split(".");
        const ft = parts.find(
          (part) => Object.keys(SequencerFileRangeFind.ftToDistanceMap).indexOf(part) > -1
        );
        if (!ft) {
          return super.getPreviewFile(entry);
        }
        const fileIndex = parts.slice(parts.indexOf(ft) + 1)?.[0];
        if (is_real_number(Number(fileIndex))) {
          this.fileIndex = Number(fileIndex);
        }
        return this.getFile(ft);
      }
      _getMatchingDistance(inEntry) {
        return SequencerFileRangeFind.ftToDistanceMap[inEntry] / this._gridSizeDiff;
      }
      getFileForDistance(inDistance) {
        if (!this._fileDistanceMap) {
          let distances = Object.keys(this.file).filter(
            (entry) => Object.keys(SequencerFileRangeFind.ftToDistanceMap).indexOf(entry) > -1
          ).map((ft) => {
            return {
              file: this.getFile(ft),
              minDistance: this._getMatchingDistance(ft)
            };
          });
          let uniqueDistances = [
            ...new Set(distances.map((item) => item.minDistance))
          ];
          uniqueDistances.sort((a, b) => a - b);
          let max = Math.max(...uniqueDistances);
          let min = Math.min(...uniqueDistances);
          this._fileDistanceMap = distances.map((entry) => {
            entry.distances = {
              min: entry.minDistance === min ? 0 : entry.minDistance,
              max: entry.minDistance === max ? Infinity : uniqueDistances[uniqueDistances.indexOf(entry.minDistance) + 1]
            };
            return entry;
          });
        }
        const possibleFiles = this._fileDistanceMap.filter((entry) => {
          const relativeDistance = inDistance / this._gridSizeDiff;
          return relativeDistance >= entry.distances.min && relativeDistance < entry.distances.max;
        }).map((entry) => entry.file).flat();
        return possibleFiles.length > 1 ? random_array_element(possibleFiles, { twister: this.twister }) : possibleFiles[0];
      }
    }
    class Database {
      #entriesStore = writable({});
      privateModules = [];
      flattenedEntries = [];
      flattenedEntriesAdvanced = [];
      inverseFlattenedEntries = /* @__PURE__ */ new Map();
      get entries() {
        return get_store_value(this.#entriesStore);
      }
      set entries(entries) {
        this.#entriesStore.set(entries);
      }
      get entriesStore() {
        return this.#entriesStore;
      }
      get publicModules() {
        return Object.keys(this.entries).filter(
          (module2) => !this.privateModules.includes(module2)
        );
      }
      get publicFlattenedEntries() {
        return this.flattenedEntries.filter((entry) => {
          return this.privateModules.indexOf(entry.split(".")[0]) === -1;
        });
      }
      get publicFlattenedSimpleEntries() {
        return make_array_unique(
          this.publicFlattenedEntries.map((entry) => {
            return entry.split(CONSTANTS.FEET_REGEX)[0];
          })
        );
      }
      get publicFlattenedEntriesAdvanced() {
        return this.flattenedEntriesAdvanced.filter((entry) => {
          return this.privateModules.indexOf(entry.path.split(".")[0]) === -1;
        });
      }
      /**
       *  Retrieves an object of every public entry
       *
       * @return {object}
       */
      get filePathDatabasePaths() {
        const fileDatabaseObject = {};
        Object.entries(this.entries).map((entry) => entry[1]).deepFlatten().forEach((sequencerFile) => {
          if (sequencerFile?.rangeFind) {
            Object.entries(sequencerFile.file).forEach((entry) => {
              fileDatabaseObject[entry[1]] = sequencerFile.dbPath + "." + entry[0];
            });
          } else {
            fileDatabaseObject[sequencerFile.file] = sequencerFile.dbPath;
          }
        });
        return fileDatabaseObject;
      }
      /**
       *  Registers a set of entries to the database on the given module name
       *
       * @param  {string}      inModuleName  The namespace to assign to the inserted entries
       * @param  {object}      inEntries     The entries to merge into the database
       * @param  {boolean}     isPrivate     Whether to mark these entries as private and not show in Effect Player or Database Viewer
       * @param  {boolean}     override      Whether to ignore existing entries and completely override the module's previous entries
       * @return {boolean}
       */
      registerEntries(inModuleName, inEntries, isPrivate = false, override = false) {
        if (inModuleName.includes("."))
          return this._throwError(
            "registerEntries",
            "module name must not contain periods"
          );
        if (this.entries[inModuleName] && !override)
          custom_warning(
            "Sequencer",
            `registerEntries | module "${inModuleName}" has already been registered to the database! Do you have two similar modules active?`,
            true
          );
        this._flatten(inEntries, inModuleName);
        const processedEntries = this._processEntries(inModuleName, inEntries);
        if (override) {
          if (isPrivate) {
            this.privateModules.push(inModuleName);
          } else {
            this.privateModules = this.privateModules.filter((mod) => module !== inModuleName);
          }
          this.entries[inModuleName] = processedEntries;
        } else {
          if (isPrivate) this.privateModules.push(inModuleName);
          this.entries = foundry.utils.mergeObject(this.entries, {
            [inModuleName]: processedEntries
          });
        }
        debug(
          `Sequencer | Database | Entries for "${inModuleName}" registered`
        );
        Hooks.callAll("registerSequencerDatabaseEntries", inModuleName);
        return true;
      }
      /**
       *  Validates the entries under a certain module name, checking whether paths to assets are correct or not
       *
       * @param  {string}     inModuleName    The namespace to assign to the inserted entries
       * @return {boolean}
       */
      async validateEntries(inModuleName) {
        let entries = this.getEntry(inModuleName);
        if (!Array.isArray(entries)) {
          entries = [entries];
        }
        ui.notifications.info(
          `Validating paths registered to "${inModuleName}"...`
        );
        let isValid = true;
        LoadingBar.init(
          `Validating paths registered to "${inModuleName}"...`,
          entries.length
        );
        for (let entry of entries) {
          const result = await entry.validate();
          LoadingBar.incrementProgress();
          isValid = !(!result || !isValid);
        }
        if (!isValid) {
          ui.notifications.error(
            `Validation of paths registered to "${inModuleName}" failed! Errors logged in console.`
          );
        } else {
          ui.notifications.info(
            `Validation of paths registered to "${inModuleName}" complete! No errors found!`
          );
        }
      }
      /**
       *  Quickly checks if the entry exists in the database
       *
       * @param  {string}      inString    The entry to find in the database
       * @return {boolean}                 If the entry exists in the database
       */
      entryExists(inString) {
        if (typeof inString !== "string")
          return this._throwError("entryExists", "inString must be of type string");
        inString = inString.trim();
        if (inString === "")
          return this._throwError("entryExists", "inString cannot be empty");
        inString = inString.replace(/\[[0-9]+]$/, "");
        return this.flattenedEntries.find((entry) => entry.startsWith(inString));
      }
      /**
       *  Gets the entry in the database by a dot-notated string
       *
       * @param  {string}                     inString        The entry to find in the database
       * @param  {boolean}                    softFail        Whether it should soft fail (no error) when no entry was found
       * @return {array|SequencerFile|boolean}                The found entry in the database, or false if not found (with warning)
       */
      getEntry(inString, { softFail = false } = {}) {
        if (typeof inString !== "string") {
          if (softFail) return false;
          return this._throwError("getEntry", "inString must be of type string");
        }
        inString = inString.trim();
        if (inString === "") {
          if (softFail) return false;
          return this._throwError("getEntry", "inString cannot be empty");
        }
        inString = inString.replace(/\[[0-9]+]$/, "");
        if (!this.entryExists(inString)) {
          if (softFail) return false;
          return this._throwError(
            "getEntry",
            `Could not find ${inString} in database`
          );
        }
        let ft = false;
        let index = false;
        if (CONSTANTS.FEET_REGEX.test(inString)) {
          ft = inString.match(CONSTANTS.FEET_REGEX)[0];
          const split = inString.split(ft).filter((str) => str !== "");
          if (split.length > 1) {
            index = split[1].split(".")[0];
          }
          inString = split[0];
        }
        const module2 = inString.split(".")[0];
        const exactEntries = this.entries[module2].filter((entry) => {
          return entry.dbPath === inString;
        });
        let filteredEntries = (exactEntries.length ? exactEntries : this.entries[module2].filter((entry) => {
          return entry.dbPath.startsWith(inString);
        })).map((entry) => {
          let foundFile = entry;
          if (ft) foundFile = entry.file?.[ft] ?? foundFile;
          if (index) foundFile = foundFile?.[index] ?? foundFile;
          return foundFile;
        });
        if (!filteredEntries.length)
          return this._throwError(
            "getEntry",
            `Could not find ${inString} in database`
          );
        const foundEntry = filteredEntries.length === 1 ? filteredEntries[0] : filteredEntries;
        if (index && filteredEntries.length === 1) {
          foundEntry.fileIndex = Number(index);
        }
        return foundEntry;
      }
      /**
       *  Gets all files under a database path
       *
       * @param  {string}         inDBPath    The module to get all files from
       * @return {array|boolean}                  The found entries in the database under the module's name, or false if not found (with warning)
       */
      getAllFileEntries(inDBPath) {
        if (typeof inDBPath !== "string")
          return this._throwError(
            "getAllFileEntries",
            "inDBPath must be of type string"
          );
        inDBPath = inDBPath.trim();
        if (inDBPath === "")
          return this._throwError("getAllFileEntries", "inDBPath cannot be empty");
        if (!this.entryExists(inDBPath))
          return this._throwError(
            "getAllFileEntries",
            `Could not find ${inDBPath} in database`
          );
        const entries = this._recurseGetFilePaths(inDBPath);
        return make_array_unique(entries.flat());
      }
      /**
       *  Get all valid entries under a certain path
       *
       * @param  {string}             inPath      The database path to get entries under
       * @return {array|boolean}                  An array containing the next layer of valid paths
       */
      getPathsUnder(inPath, {
        ranges = false,
        arrays = false,
        match = false,
        fullyQualified = false
      } = {}) {
        if (typeof inPath !== "string")
          return this._throwError("getPathsUnder", "inPath must be of type string");
        inPath = inPath.trim();
        if (inPath === "")
          return this._throwError("getPathsUnder", "inPath cannot be empty");
        inPath = inPath.replace(/\[[0-9]+]$/, "");
        if (!this.entryExists(inPath))
          return this._throwError(
            "getPathsUnder",
            `Could not find ${inPath} in database`
          );
        const entries = this.flattenedEntries.filter((e) => {
          return (e.startsWith(inPath + ".") || e === inPath) && (!match || match && e.match(match));
        });
        if (entries.length === 0) return [];
        return make_array_unique(
          entries.map((e) => !arrays ? e.split(CONSTANTS.ARRAY_REGEX)[0] : e).map((e) => !ranges ? e.split(CONSTANTS.FEET_REGEX)[0] : e).map((e) => !fullyQualified ? e.split(inPath)[1] : e).map((e) => !fullyQualified ? e ? e.split(".")[1] : "" : e).filter(Boolean)
        );
      }
      /**
       *  Get all valid entries under a certain path
       *
       * @param  {string}             inPath          The database path to search for
       * @param  {boolean}            publicOnly      Whether to only search for public modules
       * @return {array|boolean}                      An array containing potential database paths
       */
      searchFor(inPath, publicOnly = true) {
        const modules = publicOnly ? this.publicModules : Object.keys(this.entries);
        const originalEntries = publicOnly ? this.publicFlattenedEntries : this.flattenedEntries;
        if ((!inPath || inPath === "") && !modules.includes(inPath)) return modules;
        if (typeof inPath !== "string") {
          return this._throwError("searchFor", "inString must be of type string");
        }
        inPath = inPath.trim();
        if (inPath === "")
          return this._throwError("searchFor", "inString cannot be empty");
        inPath = inPath.replace(/\[[0-9]+]$/, "");
        inPath = inPath.trim();
        let entries = originalEntries.filter(
          (e) => e.startsWith(inPath) && e !== inPath
        );
        if (inPath.endsWith(".")) inPath = inPath.substring(0, inPath.length - 1);
        let length = inPath.split(".").length + 1;
        let foundEntries = entries.map((e) => {
          let path = e.split(CONSTANTS.FEET_REGEX)[0];
          return path.split(".").slice(0, length).join(".");
        });
        if (foundEntries.length === 0) {
          const regexString = str_to_search_regex_str(inPath).replace(/\s+/g, "|");
          const searchParts = regexString.split("|").length;
          const regexSearch = new RegExp(regexString, "gu");
          foundEntries = originalEntries.filter((e) => {
            return e.match(regexSearch)?.length >= searchParts;
          }).map((e) => {
            return e.split(CONSTANTS.FEET_REGEX)[0];
          });
        }
        return make_array_unique(foundEntries);
      }
      /**
       * Throws an error without THROWING one. Duh.
       *
       * @param inFunctionName
       * @param inError
       * @returns {boolean}
       * @private
       */
      _throwError(inFunctionName, inError) {
        let error = `Sequencer | Database | ${inFunctionName} - ${inError}`;
        ui.notifications.error(error);
        return false;
      }
      /**
       * Gets all file paths from the entirety of
       *
       * @param inDBPath
       * @returns {Array}
       * @private
       */
      _recurseGetFilePaths(inDBPath) {
        const module2 = inDBPath.split(".")[0];
        return this.entries[module2].filter((entry) => entry.dbPath.startsWith(inDBPath)).map((entry) => {
          return entry.getAllFiles();
        }).flat();
      }
      /**
       * Flattens a given object to just their db path and file path
       *
       * @param entries
       * @param inModule
       * @private
       */
      _flatten(entries, inModule) {
        let flattened = flatten_object(
          foundry.utils.duplicate({ [inModule]: entries })
        );
        this.flattenedEntries = make_array_unique(
          this.flattenedEntries.concat(
            Object.keys(flattened).map((file) => file.split(".file")[0])
          )
        );
        this.flattenedEntriesAdvanced = make_array_unique(
          this.flattenedEntriesAdvanced.concat(
            Object.entries(flattened).map(([path, file]) => ({
              path: path.split(".file")[0],
              file,
              isAudio: file.endsWith("ogg") || file.endsWith("mp3") || file.endsWith("wav")
            }))
          )
        );
        this.inverseFlattenedEntries = Object.keys(flattened).reduce(
          (acc, entry) => {
            return acc.set(flattened[entry], entry.split(".file")[0]);
          },
          this.inverseFlattenedEntries
        );
      }
      /**
       * Processes and recurse into a large object containing file paths at any given depth
       *
       * @param moduleName
       * @param entries
       * @returns {object}
       * @private
       */
      _processEntries(moduleName, entries) {
        const allPaths = new Set(
          this.flattenedEntries.filter((e) => e.split(".")[0] === moduleName).map((e) => e.split(CONSTANTS.FEET_REGEX)[0])
        );
        const allTemplates = foundry.utils.mergeObject(entries?._templates ?? {}, {
          default: [100, 0, 0]
        });
        if (entries?._templates) {
          delete entries?._templates;
        }
        const moduleEntries = [];
        const mediaFileExtensions = Object.keys(CONST.FILE_CATEGORIES.IMAGE).concat(Object.keys(CONST.FILE_CATEGORIES.VIDEO)).concat(Object.keys(CONST.FILE_CATEGORIES.AUDIO)).concat(["json"]);
        for (let wholeDBPath of allPaths) {
          let metadata = this._getCleanData(entries);
          let dbPath = wholeDBPath.split(".");
          dbPath.shift();
          let combinedPath = "";
          for (let part of dbPath) {
            combinedPath = combinedPath ? combinedPath + "." + part : part;
            const entry = foundry.utils.getProperty(entries, combinedPath);
            if (Array.isArray(entry) || typeof entry === "string" || entry?.file) {
              metadata = this._getCleanData(entry, { existingData: metadata });
              break;
            }
            metadata = this._getCleanData(entry, { existingData: metadata });
          }
          if (!metadata.template) metadata.template = "default";
          if (typeof metadata.template === "string") {
            metadata.template = allTemplates?.[metadata.template] ?? allTemplates?.["default"];
          }
          let data = foundry.utils.getProperty(entries, dbPath.join("."));
          if (!Array.isArray(data) && !(typeof data === "string")) {
            data = this._getCleanData(data, { metadata: false });
          }
          if (typeof data === "string") {
            const existingEntry = this.entryExists(data);
            const extension = data.split(".")[data.split(".").length - 1].toLowerCase();
            if (!existingEntry && extension && !mediaFileExtensions.includes(extension)) {
              console.warn(
                `Sequencer | Database | registerEntries - failed to register ${wholeDBPath} to ${data}!`
              );
              this.flattenedEntries.splice(
                this.flattenedEntries.indexOf(wholeDBPath),
                1
              );
              continue;
            } else if (existingEntry) {
              const sequencerFile = this.getEntry(data);
              const clone = sequencerFile.clone();
              clone.dbPath = wholeDBPath;
              clone.metadata = foundry.utils.mergeObject(
                clone.metadata ?? {},
                metadata ?? {}
              );
              moduleEntries.push(clone);
              continue;
            }
          }
          moduleEntries.push(SequencerFileBase.make(data, wholeDBPath, metadata));
        }
        return moduleEntries;
      }
      _getCleanData(data, { existingData = {}, metadata = true } = {}) {
        data = Object.entries(data).filter((entry) => {
          return metadata === entry[0].startsWith("_");
        });
        if (metadata) {
          data = data.map((entry) => [entry[0].slice(1), entry[1]]);
        }
        return foundry.utils.mergeObject(existingData, Object.fromEntries(data));
      }
    }
    const SequencerDatabase = new Database();
    function create_if_block_2$1(ctx) {
      let a;
      let i;
      let mounted;
      let dispose;
      return {
        c() {
          a = element("a");
          i = element("i");
          attr(i, "class", "fas svelte-seq-uyryhb");
          toggle_class(
            i,
            "fa-angle-down",
            /*data*/
            ctx[0].open
          );
          toggle_class(i, "fa-angle-right", !/*data*/
          ctx[0].open);
          attr(a, "class", "svelte-seq-uyryhb");
        },
        m(target, anchor) {
          insert(target, a, anchor);
          append(a, i);
          if (!mounted) {
            dispose = listen(
              a,
              "click",
              /*click_handler*/
              ctx[6]
            );
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (dirty & /*data*/
          1) {
            toggle_class(
              i,
              "fa-angle-down",
              /*data*/
              ctx2[0].open
            );
          }
          if (dirty & /*data*/
          1) {
            toggle_class(i, "fa-angle-right", !/*data*/
            ctx2[0].open);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(a);
          }
          mounted = false;
          dispose();
        }
      };
    }
    function create_if_block$7(ctx) {
      let t0;
      let a0;
      let i0;
      let t1;
      let a1;
      let mounted;
      let dispose;
      let if_block = !/*data*/
      ctx[0].hasChildren && create_if_block_1$4(ctx);
      return {
        c() {
          if (if_block) if_block.c();
          t0 = space();
          a0 = element("a");
          i0 = element("i");
          t1 = space();
          a1 = element("a");
          a1.innerHTML = `<i class="fas fa-play svelte-seq-uyryhb"></i>`;
          attr(i0, "class", "fas fa-database svelte-seq-uyryhb");
          toggle_class(
            i0,
            "flash-it",
            /*flashDBPath*/
            ctx[2]
          );
          attr(a0, "class", "database-entry-button svelte-seq-uyryhb");
          attr(a0, "title", localize("SEQUENCER.Database.CopyDatabasePath"));
          attr(a1, "class", "database-entry-button svelte-seq-uyryhb");
          attr(a1, "title", localize("SEQUENCER.Database.PlayPreview"));
        },
        m(target, anchor) {
          if (if_block) if_block.m(target, anchor);
          insert(target, t0, anchor);
          insert(target, a0, anchor);
          append(a0, i0);
          insert(target, t1, anchor);
          insert(target, a1, anchor);
          if (!mounted) {
            dispose = [
              listen(
                a0,
                "click",
                /*click_handler_2*/
                ctx[8]
              ),
              listen(
                a1,
                "click",
                /*click_handler_3*/
                ctx[9]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (!/*data*/
          ctx2[0].hasChildren) {
            if (if_block) {
              if_block.p(ctx2, dirty);
            } else {
              if_block = create_if_block_1$4(ctx2);
              if_block.c();
              if_block.m(t0.parentNode, t0);
            }
          } else if (if_block) {
            if_block.d(1);
            if_block = null;
          }
          if (dirty & /*flashDBPath*/
          4) {
            toggle_class(
              i0,
              "flash-it",
              /*flashDBPath*/
              ctx2[2]
            );
          }
        },
        d(detaching) {
          if (detaching) {
            detach(t0);
            detach(a0);
            detach(t1);
            detach(a1);
          }
          if (if_block) if_block.d(detaching);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_if_block_1$4(ctx) {
      let a;
      let i;
      let mounted;
      let dispose;
      return {
        c() {
          a = element("a");
          i = element("i");
          attr(i, "class", "fas fa-file svelte-seq-uyryhb");
          toggle_class(
            i,
            "flash-it",
            /*flashFilePath*/
            ctx[1]
          );
          attr(a, "class", "database-entry-button svelte-seq-uyryhb");
          attr(a, "title", localize("SEQUENCER.Database.CopyFilePath"));
        },
        m(target, anchor) {
          insert(target, a, anchor);
          append(a, i);
          if (!mounted) {
            dispose = listen(
              a,
              "click",
              /*click_handler_1*/
              ctx[7]
            );
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (dirty & /*flashFilePath*/
          2) {
            toggle_class(
              i,
              "flash-it",
              /*flashFilePath*/
              ctx2[1]
            );
          }
        },
        d(detaching) {
          if (detaching) {
            detach(a);
          }
          mounted = false;
          dispose();
        }
      };
    }
    function create_fragment$l(ctx) {
      let div3;
      let div2;
      let t0;
      let show_if = (
        /*data*/
        ctx[0].fullPath.includes(".")
      );
      let t1;
      let div1;
      let div0;
      let t2;
      let t3_value = (
        /*data*/
        ctx[0].path + ""
      );
      let t3;
      let div1_title_value;
      let if_block0 = (
        /*data*/
        ctx[0].hasChildren && create_if_block_2$1(ctx)
      );
      let if_block1 = show_if && create_if_block$7(ctx);
      return {
        c() {
          div3 = element("div");
          div2 = element("div");
          if (if_block0) if_block0.c();
          t0 = space();
          if (if_block1) if_block1.c();
          t1 = space();
          div1 = element("div");
          div0 = element("div");
          t2 = space();
          t3 = text$1(t3_value);
          attr(div0, "class", "database-entry-text-highlight svelte-seq-uyryhb");
          attr(div1, "class", "database-entry-text svelte-seq-uyryhb");
          attr(div1, "title", div1_title_value = /*data*/
          ctx[0].path);
          attr(div2, "class", "database-entry-text-container svelte-seq-uyryhb");
          attr(div3, "class", "database-entry svelte-seq-uyryhb");
          set_style(
            div3,
            "margin-left",
            /*data*/
            ctx[0].depth * 15 + "px"
          );
        },
        m(target, anchor) {
          insert(target, div3, anchor);
          append(div3, div2);
          if (if_block0) if_block0.m(div2, null);
          append(div2, t0);
          if (if_block1) if_block1.m(div2, null);
          append(div2, t1);
          append(div2, div1);
          append(div1, div0);
          div0.innerHTML = /*highlight*/
          ctx[3];
          append(div1, t2);
          append(div1, t3);
        },
        p(ctx2, [dirty]) {
          if (
            /*data*/
            ctx2[0].hasChildren
          ) {
            if (if_block0) {
              if_block0.p(ctx2, dirty);
            } else {
              if_block0 = create_if_block_2$1(ctx2);
              if_block0.c();
              if_block0.m(div2, t0);
            }
          } else if (if_block0) {
            if_block0.d(1);
            if_block0 = null;
          }
          if (dirty & /*data*/
          1) show_if = /*data*/
          ctx2[0].fullPath.includes(".");
          if (show_if) {
            if (if_block1) {
              if_block1.p(ctx2, dirty);
            } else {
              if_block1 = create_if_block$7(ctx2);
              if_block1.c();
              if_block1.m(div2, t1);
            }
          } else if (if_block1) {
            if_block1.d(1);
            if_block1 = null;
          }
          if (dirty & /*highlight*/
          8) div0.innerHTML = /*highlight*/
          ctx2[3];
          if (dirty & /*data*/
          1 && t3_value !== (t3_value = /*data*/
          ctx2[0].path + "")) set_data(t3, t3_value);
          if (dirty & /*data*/
          1 && div1_title_value !== (div1_title_value = /*data*/
          ctx2[0].path)) {
            attr(div1, "title", div1_title_value);
          }
          if (dirty & /*data*/
          1) {
            set_style(
              div3,
              "margin-left",
              /*data*/
              ctx2[0].depth * 15 + "px"
            );
          }
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div3);
          }
          if (if_block0) if_block0.d();
          if (if_block1) if_block1.d();
        }
      };
    }
    function instance$k($$self, $$props, $$invalidate) {
      let highlight;
      let $searchRegex;
      let { data } = $$props;
      const searchRegex = databaseStore.searchRegex;
      component_subscribe($$self, searchRegex, (value) => $$invalidate(5, $searchRegex = value));
      let flashFilePath = false;
      let flashDBPath = false;
      const click_handler = (e) => {
        databaseStore.openTreePath(data.fullPath, !data.open, e.ctrlKey);
      };
      const click_handler_1 = (e) => {
        databaseStore.copyPath(data.fullPath, true, e.ctrlKey);
        $$invalidate(1, flashFilePath = true);
        setTimeout(
          () => {
            $$invalidate(1, flashFilePath = false);
          },
          400
        );
      };
      const click_handler_2 = (e) => {
        databaseStore.copyPath(data.fullPath, false, e.ctrlKey);
        $$invalidate(2, flashDBPath = true);
        setTimeout(
          () => {
            $$invalidate(2, flashDBPath = false);
          },
          400
        );
      };
      const click_handler_3 = () => {
        databaseStore.playFile(data.fullPath);
      };
      $$self.$$set = ($$props2) => {
        if ("data" in $$props2) $$invalidate(0, data = $$props2.data);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*data, $searchRegex*/
        33) {
          $$invalidate(3, highlight = data.path.replace($searchRegex, "<mark>$&</mark>"));
        }
      };
      return [
        data,
        flashFilePath,
        flashDBPath,
        highlight,
        searchRegex,
        $searchRegex,
        click_handler,
        click_handler_1,
        click_handler_2,
        click_handler_3
      ];
    }
    class TreeViewEntry extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$k, create_fragment$l, safe_not_equal, { data: 0 });
      }
    }
    function create_fragment$k(ctx) {
      let div;
      return {
        c() {
          div = element("div");
          set_style(div, "margin-bottom", "0.3rem");
        },
        m(target, anchor) {
          insert(target, div, anchor);
        },
        p: noop,
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
        }
      };
    }
    function instance$j($$self, $$props, $$invalidate) {
      let { data } = $$props;
      $$self.$$set = ($$props2) => {
        if ("data" in $$props2) $$invalidate(0, data = $$props2.data);
      };
      return [data];
    }
    class TreeViewSeparator extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$j, create_fragment$k, safe_not_equal, { data: 0 });
      }
    }
    const viewSize = 320;
    let animatedSprite;
    let offscreenApp;
    let canvas$1;
    let offscreenCanvas;
    let oldImageSrcs = /* @__PURE__ */ new Map();
    function initOffscreenApp(databaseStore2) {
      if (offscreenApp) {
        return;
      }
      canvas$1 = document.createElement("canvas");
      canvas$1.style.display = "none";
      offscreenCanvas = canvas$1.transferControlToOffscreen();
      offscreenApp = new PIXI.Application({ autoStart: false, view: offscreenCanvas, backgroundColor: 10066329, sharedTicker: false });
      offscreenApp.ticker.stop();
      document.body.appendChild(canvas$1);
      offscreenCanvas.style = {};
      offscreenCanvas.width = viewSize;
      offscreenCanvas.height = viewSize;
    }
    async function playSpritesheet(file, databaseStore2) {
      initOffscreenApp();
      const sheet = await SequencerFileCache.loadFile(file);
      if (!sheet) {
        return;
      }
      SequencerFileCache.registerSpritesheet(file, sheet);
      const frames = Object.values(sheet.animations)?.[0];
      if (!frames) {
        return;
      }
      const framerate = sheet.data?.meta?.framerate ?? 30;
      const frametime = 1 / framerate * 1e3;
      databaseStore2.metadata.set({
        type: "Spritesheet",
        duration: Math.round(frametime * frames.length) + "ms"
      });
      if (!animatedSprite) {
        animatedSprite = new PIXI.AnimatedSprite(frames, true);
        animatedSprite.anchor.set(0.5);
        animatedSprite.x = viewSize / 2;
        animatedSprite.y = viewSize / 2;
        offscreenApp.stage.addChild(animatedSprite);
      }
      let queuedFrame;
      let renderedFrame;
      animatedSprite.onFrameChange = async (frame) => {
        if (queuedFrame !== renderedFrame) {
          return;
        }
        let curerntImageSrc = oldImageSrcs.get(frame);
        if (!curerntImageSrc) {
          queuedFrame = frame;
          offscreenApp.render();
          const imageBlob = await offscreenCanvas.convertToBlob();
          curerntImageSrc = URL.createObjectURL(imageBlob);
          oldImageSrcs.set(frame, curerntImageSrc);
          renderedFrame = frame;
        }
        databaseStore2.elements.image.src = curerntImageSrc;
      };
      animatedSprite.textures = frames;
      animatedSprite.scale.set(viewSize / Math.max(frames[0].width, frames[0].height));
      animatedSprite.file = file;
      animatedSprite.play();
    }
    async function cleanupSpritesheet(destroy = false) {
      if (!animatedSprite) {
        return;
      }
      animatedSprite.stop();
      animatedSprite.onFrameChange = null;
      if (animatedSprite.file) {
        await SequencerFileCache.unloadSpritesheet(animatedSprite.file);
        animatedSprite.file = null;
      }
      oldImageSrcs.values().forEach((objectUrl) => {
        URL.revokeObjectURL(objectUrl);
      });
      oldImageSrcs.clear();
      if (destroy) {
        animatedSprite.destroy();
        animatedSprite = null;
        offscreenApp.destroy();
        canvas$1.remove();
        offscreenCanvas = null;
        offscreenApp = void 0;
      }
    }
    let lastFile = false;
    function getFileData(entryText) {
      let entry = SequencerDatabase.getEntry(entryText);
      if (Array.isArray(entry)) {
        if (entry.includes(lastFile) && entry.length > 1) {
          entry.splice(entry.indexOf(lastFile), 1);
        }
        entry = random_array_element(entry);
        lastFile = entry;
      }
      let previewFile = entry?.file ?? entry;
      if (entry instanceof SequencerFileBase) {
        previewFile = entry.clone().getPreviewFile(entryText);
      }
      let lowerCaseEntry = previewFile ? previewFile.toLowerCase() : "unknown.jpg";
      const isAudio = lowerCaseEntry.endsWith("ogg") || lowerCaseEntry.endsWith("mp3") || lowerCaseEntry.endsWith("wav");
      const isSpritesheet = lowerCaseEntry.endsWith("json");
      const isImage = !lowerCaseEntry.endsWith("webm") && !isAudio && !isSpritesheet;
      const isVideo = !isAudio && !isImage && !isSpritesheet;
      const icon = previewFile ? isVideo || isSpritesheet ? "fa-film" : isAudio ? "fa-volume-high" : "fa-image" : "fa-question-mark";
      const title = previewFile ? isVideo ? "Animated WebM" : isSpritesheet ? "Spritesheet" : isAudio ? "Audio" : "Image" : "Unknown";
      return {
        file: previewFile ?? "unknown.jpg",
        dbEntry: entry,
        icon,
        title,
        isAudio,
        isImage,
        isSpritesheet,
        isVideo
      };
    }
    function copyPath(dbPath, getFilepath, quotes = false) {
      const tempInput = document.createElement("input");
      tempInput.value = `${dbPath}`;
      let entry;
      if (getFilepath) {
        entry = Sequencer.Database.getEntry(dbPath);
        if (Array.isArray(entry)) {
          entry = random_array_element(entry);
        }
        if (entry instanceof SequencerFileBase) {
          const specificFt = dbPath.match(CONSTANTS.FEET_REGEX);
          if (specificFt) {
            const ft = specificFt[0].replaceAll(".", "");
            entry = entry.getFile(ft);
          } else {
            const files2 = entry.getAllFiles();
            if (Array.isArray(files2)) {
              const index = Math.floor(interpolate(0, files2.length - 1, 0.5));
              entry = files2[index];
            }
          }
        }
        tempInput.value = `${entry?.file ?? entry}`;
      }
      if (quotes) {
        tempInput.value = `"${tempInput.value}"`;
      }
      document.body.appendChild(tempInput);
      tempInput.select();
      document.execCommand("copy");
      document.body.removeChild(tempInput);
      document.execCommand("copy");
    }
    async function playFile(entry) {
      await cleanupSpritesheet();
      const { file, isAudio, isImage, isVideo, isSpritesheet } = getFileData(entry);
      databaseStore.elements.audio.classList.toggle("hidden", !isAudio);
      databaseStore.elements.image.classList.toggle("hidden", !isImage && !isSpritesheet);
      databaseStore.elements.player.classList.toggle("hidden", !isVideo);
      if (isImage) {
        databaseStore.elements.image.src = file;
        databaseStore.metadata.set({
          type: "Image",
          duration: "n/a"
        });
        return;
      }
      if (isSpritesheet) {
        playSpritesheet(file, databaseStore);
        return;
      }
      const element2 = isAudio ? databaseStore.elements.audio : databaseStore.elements.player;
      element2.onerror = () => {
        const error = `Sequencer Database Viewer | Could not play file: ${file}`;
        ui.notifications.error(error);
        console.error(error);
      };
      element2.oncanplay = () => {
        element2.play();
      };
      element2.onloadedmetadata = () => {
        databaseStore.metadata.set({
          type: isVideo ? "Video" : isAudio ? "Audio" : "Image",
          duration: isImage ? "n/a" : element2.duration * 1e3 + "ms"
        });
      };
      element2.src = file;
    }
    const treeStore = writable({});
    const visibleTreeStore = writable([]);
    let flattenedEntries = [];
    const entriesStore = SequencerDatabase.entriesStore;
    const packStore = writable(SequencerDatabase.publicModules);
    const selectedPackStore = writable("all");
    const searchStore = writable("");
    const cleanSearchStore = writable("");
    const searchRegexStore = writable(new RegExp("", "gu"));
    SequencerDatabase.entriesStore.subscribe(() => {
      packStore.set(SequencerDatabase.publicModules);
    });
    const databaseStore = {
      metadata: writable(false),
      allRanges: writable(false),
      fileTypes: writable("all"),
      subLists: writable(false),
      listView: writable(false),
      packStore,
      selectedPackStore,
      visibleTreeStore,
      search: searchStore,
      cleanSearchStore,
      searchRegex: searchRegexStore,
      elements: {},
      cleanupSpritesheet() {
        cleanupSpritesheet(true);
      },
      copyPath,
      playFile,
      openTreePath
    };
    entriesStore.subscribe(() => {
      filterFlattenedEntries();
    });
    databaseStore.allRanges.subscribe(() => {
      filterFlattenedEntries();
    });
    databaseStore.subLists.subscribe(() => {
      filterFlattenedEntries();
    });
    databaseStore.selectedPackStore.subscribe(() => {
      filterFlattenedEntries();
    });
    searchStore.subscribe((val) => {
      const cleanSearch = str_to_search_regex_str(val).replace(/\s+/g, "|");
      cleanSearchStore.set(cleanSearch);
      searchRegexStore.set(new RegExp(cleanSearch, "gu"));
      updateVisualTree();
    });
    function filterFlattenedEntries() {
      const selectedPack = get_store_value(selectedPackStore);
      const search = get_store_value(searchStore);
      const searchRegex = get_store_value(searchRegexStore);
      const subLists = get_store_value(databaseStore.subLists);
      const allRanges = get_store_value(databaseStore.allRanges);
      flattenedEntries = make_array_unique(
        SequencerDatabase.publicFlattenedEntries.filter((e) => {
          return (selectedPack === "all" || e.startsWith(selectedPack + ".")) && (!search || e.match(searchRegex));
        }).map((e) => !subLists ? e.split(CONSTANTS.ARRAY_REGEX)[0] : e).map((e) => !allRanges ? e.split(CONSTANTS.FEET_REGEX)[0] : e)
      );
      treeStore.set(
        flattenedEntries.reduce((acc, entry) => {
          let path = "";
          for (const part of entry.split(".")) {
            const fullPath = path ? path + "." + part : part;
            path = path ? path + ".children." + part : part;
            if (!foundry.utils.getProperty(acc, path)) {
              foundry.utils.setProperty(
                acc,
                path,
                foundry.utils.mergeObject(
                  {
                    path: part,
                    fullPath,
                    open: false,
                    children: {}
                  },
                  foundry.utils.getProperty(acc, path)
                )
              );
            }
          }
          return acc;
        }, {})
      );
    }
    function openTreePath(fullPath, open, openAll = false) {
      treeStore.update((tree) => {
        const fullTreePath = fullPath.split(".").join(".children.");
        const node = foundry.utils.getProperty(tree, fullTreePath);
        foundry.utils.setProperty(tree, fullTreePath + ".open", open);
        if ((!open || openAll) && !foundry.utils.isEmpty(node.children)) {
          recurseOpenTree(node.children, open);
        }
        return tree;
      });
    }
    function recurseOpenTree(children2, open) {
      for (const node of Object.values(children2)) {
        node.open = open;
        if (!foundry.utils.isEmpty(node.children)) {
          recurseOpenTree(node.children, open);
        }
      }
    }
    treeStore.subscribe(() => {
      updateVisualTree();
    });
    function updateVisualTree() {
      const tree = get_store_value(treeStore);
      const visibleTree = recurseTree(tree).deepFlatten().filter((e) => e.visible);
      visibleTreeStore.set(visibleTree);
    }
    function recurseTree(tree, path = "", depth = 0) {
      const search = get_store_value(searchStore);
      const searchRegex = get_store_value(searchRegexStore);
      const searchParts = get_store_value(cleanSearchStore).split("|");
      return Object.entries(tree).map(([key, data]) => {
        const fullPath = path ? path + "." + key : key;
        const children2 = recurseTree(
          data.children,
          fullPath,
          depth + 1
        ).deepFlatten();
        const matchParts = make_array_unique(fullPath.match(searchRegex) || []);
        const open = data.open || search && (matchParts.length >= searchParts.length || children2.filter((e) => e.visible).length);
        let visible = !search || matchParts.length >= searchParts.length;
        if (visible) {
          children2.forEach((e) => e.visible = true);
        } else {
          visible = children2.filter((e) => e.visible).length;
        }
        const entry = {
          class: TreeViewEntry,
          path: key,
          fullPath,
          open,
          visible,
          hasChildren: !foundry.utils.isEmpty(data.children),
          depth
        };
        const leaf = [entry];
        if ((data.open || entry.open) && entry.hasChildren) {
          leaf.push(...children2, {
            fullPath: foundry.utils.randomID(),
            class: TreeViewSeparator
          });
        }
        return leaf;
      });
    }
    function create_fragment$j(ctx) {
      let div2;
      let button0;
      let t0;
      let button1;
      let i1;
      let t1;
      let button2;
      let i2;
      let t2;
      let div1;
      let div0;
      let t3;
      let t4;
      let mounted;
      let dispose;
      return {
        c() {
          div2 = element("div");
          button0 = element("button");
          button0.innerHTML = `<i class="fas fa-play svelte-seq-flzvpb"></i>`;
          t0 = space();
          button1 = element("button");
          i1 = element("i");
          t1 = space();
          button2 = element("button");
          i2 = element("i");
          t2 = space();
          div1 = element("div");
          div0 = element("div");
          t3 = space();
          t4 = text$1(
            /*entry*/
            ctx[0]
          );
          attr(button0, "type", "button");
          attr(button0, "class", "btn_play svelte-seq-flzvpb");
          attr(button0, "title", localize("SEQUENCER.Database.PlayPreview"));
          attr(i1, "class", "fas fa-file svelte-seq-flzvpb");
          toggle_class(
            i1,
            "flash-it",
            /*flashFilePath*/
            ctx[1]
          );
          attr(button1, "type", "button");
          attr(button1, "class", "btn_copy_filepath svelte-seq-flzvpb");
          attr(button1, "title", localize("SEQUENCER.Database.CopyFilePath"));
          attr(i2, "class", "fas fa-database svelte-seq-flzvpb");
          toggle_class(
            i2,
            "flash-it",
            /*flashDBPath*/
            ctx[2]
          );
          attr(button2, "type", "button");
          attr(button2, "class", "btn_copy_databasepath svelte-seq-flzvpb");
          attr(button2, "title", localize("SEQUENCER.Database.CopyDatabasePath"));
          attr(div0, "class", "database-entry-text-highlight svelte-seq-flzvpb");
          attr(div1, "class", "database-entry-text svelte-seq-flzvpb");
          attr(
            div1,
            "title",
            /*entry*/
            ctx[0]
          );
          attr(div2, "class", "database-entry svelte-seq-flzvpb");
          attr(
            div2,
            "data-id",
            /*entry*/
            ctx[0]
          );
        },
        m(target, anchor) {
          insert(target, div2, anchor);
          append(div2, button0);
          append(div2, t0);
          append(div2, button1);
          append(button1, i1);
          append(div2, t1);
          append(div2, button2);
          append(button2, i2);
          append(div2, t2);
          append(div2, div1);
          append(div1, div0);
          div0.innerHTML = /*highlight*/
          ctx[3];
          append(div1, t3);
          append(div1, t4);
          if (!mounted) {
            dispose = [
              listen(
                button0,
                "click",
                /*click_handler*/
                ctx[6]
              ),
              listen(
                button1,
                "click",
                /*click_handler_1*/
                ctx[7]
              ),
              listen(
                button2,
                "click",
                /*click_handler_2*/
                ctx[8]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*flashFilePath*/
          2) {
            toggle_class(
              i1,
              "flash-it",
              /*flashFilePath*/
              ctx2[1]
            );
          }
          if (dirty & /*flashDBPath*/
          4) {
            toggle_class(
              i2,
              "flash-it",
              /*flashDBPath*/
              ctx2[2]
            );
          }
          if (dirty & /*highlight*/
          8) div0.innerHTML = /*highlight*/
          ctx2[3];
          if (dirty & /*entry*/
          1) set_data(
            t4,
            /*entry*/
            ctx2[0]
          );
          if (dirty & /*entry*/
          1) {
            attr(
              div1,
              "title",
              /*entry*/
              ctx2[0]
            );
          }
          if (dirty & /*entry*/
          1) {
            attr(
              div2,
              "data-id",
              /*entry*/
              ctx2[0]
            );
          }
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div2);
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$i($$self, $$props, $$invalidate) {
      let highlight;
      let $searchRegex;
      createEventDispatcher();
      let { entry } = $$props;
      const searchRegex = databaseStore.searchRegex;
      component_subscribe($$self, searchRegex, (value) => $$invalidate(5, $searchRegex = value));
      let flashFilePath = false;
      let flashDBPath = false;
      const click_handler = () => {
        databaseStore.playFile(entry);
      };
      const click_handler_1 = (e) => {
        databaseStore.copyPath(entry, true, e.ctrlKey);
        $$invalidate(1, flashFilePath = true);
        setTimeout(
          () => {
            $$invalidate(1, flashFilePath = false);
          },
          400
        );
      };
      const click_handler_2 = (e) => {
        databaseStore.copyPath(entry, false, e.ctrlKey);
        $$invalidate(2, flashDBPath = true);
        setTimeout(
          () => {
            $$invalidate(2, flashDBPath = false);
          },
          400
        );
      };
      $$self.$$set = ($$props2) => {
        if ("entry" in $$props2) $$invalidate(0, entry = $$props2.entry);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*entry, $searchRegex*/
        33) {
          $$invalidate(3, highlight = entry.replace($searchRegex, "<mark>$&</mark>"));
        }
      };
      return [
        entry,
        flashFilePath,
        flashDBPath,
        highlight,
        searchRegex,
        $searchRegex,
        click_handler,
        click_handler_1,
        click_handler_2
      ];
    }
    class DatabaseEntry extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$i, create_fragment$j, safe_not_equal, { entry: 0 });
      }
    }
    const DIRECTION_TYPE = {
      FRONT: "FRONT",
      // scroll up or left
      BEHIND: "BEHIND"
      // scroll down or right
    };
    const CALC_TYPE = {
      INIT: "INIT",
      FIXED: "FIXED",
      DYNAMIC: "DYNAMIC"
    };
    const LEADING_BUFFER = 2;
    class Virtual {
      param;
      callUpdate;
      firstRangeTotalSize = 0;
      firstRangeAverageSize = 0;
      lastCalcIndex = 0;
      fixedSizeValue = 0;
      calcType = CALC_TYPE.INIT;
      offset = 0;
      direction = "";
      range;
      constructor(param, callUpdate) {
        this.init(param, callUpdate);
      }
      init(param, callUpdate) {
        this.param = param;
        this.callUpdate = callUpdate;
        this.sizes = /* @__PURE__ */ new Map();
        this.firstRangeTotalSize = 0;
        this.firstRangeAverageSize = 0;
        this.fixedSizeValue = 0;
        this.calcType = CALC_TYPE.INIT;
        this.offset = 0;
        this.direction = "";
        this.range = /* @__PURE__ */ Object.create(null);
        if (param) {
          this.checkRange(0, param.keeps - 1);
        }
      }
      destroy() {
        this.init(null, null);
      }
      // return current render range
      getRange() {
        const range = /* @__PURE__ */ Object.create(null);
        range.start = this.range.start;
        range.end = this.range.end;
        range.padFront = this.range.padFront;
        range.padBehind = this.range.padBehind;
        return range;
      }
      isBehind() {
        return this.direction === DIRECTION_TYPE.BEHIND;
      }
      isFront() {
        return this.direction === DIRECTION_TYPE.FRONT;
      }
      // return start index offset
      getOffset(start) {
        return (start < 1 ? 0 : this.getIndexOffset(start)) + this.param.slotHeaderSize;
      }
      updateParam(key, value) {
        if (this.param && key in this.param) {
          if (key === "uniqueIds") {
            this.sizes.forEach((v, key2) => {
              if (!value.includes(key2)) {
                this.sizes.delete(key2);
              }
            });
          }
          this.param[key] = value;
        }
      }
      // save each size map by id
      saveSize(id, size) {
        this.sizes.set(id, size);
        if (this.calcType === CALC_TYPE.INIT) {
          this.fixedSizeValue = size;
          this.calcType = CALC_TYPE.FIXED;
        } else if (this.calcType === CALC_TYPE.FIXED && this.fixedSizeValue !== size) {
          this.calcType = CALC_TYPE.DYNAMIC;
          delete this.fixedSizeValue;
        }
        if (this.calcType !== CALC_TYPE.FIXED && typeof this.firstRangeTotalSize !== "undefined") {
          if (this.sizes.size < Math.min(this.param.keeps, this.param.uniqueIds.length)) {
            this.firstRangeTotalSize = [...this.sizes.values()].reduce((acc, val) => acc + val, 0);
            this.firstRangeAverageSize = Math.round(this.firstRangeTotalSize / this.sizes.size);
          } else {
            delete this.firstRangeTotalSize;
          }
        }
      }
      // in some special situation (e.g. length change) we need to update in a row
      // try going to render next range by a leading buffer according to current direction
      handleDataSourcesChange() {
        let start = this.range.start;
        if (this.isFront()) {
          start = start - LEADING_BUFFER;
        } else if (this.isBehind()) {
          start = start + LEADING_BUFFER;
        }
        start = Math.max(start, 0);
        this.updateRange(this.range.start, this.getEndByStart(start));
      }
      // when slot size change, we also need force update
      handleSlotSizeChange() {
        this.handleDataSourcesChange();
      }
      // calculating range on scroll
      handleScroll(offset2) {
        this.direction = offset2 < this.offset ? DIRECTION_TYPE.FRONT : DIRECTION_TYPE.BEHIND;
        this.offset = offset2;
        if (!this.param) {
          return;
        }
        if (this.direction === DIRECTION_TYPE.FRONT) {
          this.handleFront();
        } else if (this.direction === DIRECTION_TYPE.BEHIND) {
          this.handleBehind();
        }
      }
      // ----------- public method end -----------
      handleFront() {
        const overs = this.getScrollOvers();
        if (overs > this.range.start) {
          return;
        }
        const start = Math.max(overs - this.param.buffer, 0);
        this.checkRange(start, this.getEndByStart(start));
      }
      handleBehind() {
        const overs = this.getScrollOvers();
        if (overs < this.range.start + this.param.buffer) {
          return;
        }
        this.checkRange(overs, this.getEndByStart(overs));
      }
      // return the pass overs according to current scroll offset
      getScrollOvers() {
        const offset2 = this.offset - this.param.slotHeaderSize;
        if (offset2 <= 0) {
          return 0;
        }
        if (this.isFixedType()) {
          return Math.floor(offset2 / this.fixedSizeValue);
        }
        let low = 0;
        let middle = 0;
        let middleOffset = 0;
        let high = this.param.uniqueIds.length;
        while (low <= high) {
          middle = low + Math.floor((high - low) / 2);
          middleOffset = this.getIndexOffset(middle);
          if (middleOffset === offset2) {
            return middle;
          } else if (middleOffset < offset2) {
            low = middle + 1;
          } else if (middleOffset > offset2) {
            high = middle - 1;
          }
        }
        return low > 0 ? --low : 0;
      }
      // return a scroll offset from given index, can efficiency be improved more here?
      // although the call frequency is very high, its only a superposition of numbers
      getIndexOffset(givenIndex) {
        if (!givenIndex) {
          return 0;
        }
        let offset2 = 0;
        let indexSize = 0;
        for (let index = 0; index < givenIndex; index++) {
          indexSize = this.sizes.get(this.param.uniqueIds[index]);
          offset2 = offset2 + (typeof indexSize === "number" ? indexSize : this.getEstimateSize());
        }
        this.lastCalcIndex = Math.max(this.lastCalcIndex, givenIndex - 1);
        this.lastCalcIndex = Math.min(this.lastCalcIndex, this.getLastIndex());
        return offset2;
      }
      // is fixed size type
      isFixedType() {
        return this.calcType === CALC_TYPE.FIXED;
      }
      // return the real last index
      getLastIndex() {
        return this.param.uniqueIds.length - 1;
      }
      // in some conditions range is broke, we need correct it
      // and then decide whether need update to next range
      checkRange(start, end) {
        const keeps = this.param.keeps;
        const total = this.param.uniqueIds.length;
        if (total <= keeps) {
          start = 0;
          end = this.getLastIndex();
        } else if (end - start < keeps - 1) {
          start = end - keeps + 1;
        }
        if (this.range.start !== start) {
          this.updateRange(start, end);
        }
      }
      // setting to a new range and rerender
      updateRange(start, end) {
        this.range.start = start;
        this.range.end = end;
        this.range.padFront = this.getPadFront();
        this.range.padBehind = this.getPadBehind();
        this.callUpdate(this.getRange());
      }
      // return end base on start
      getEndByStart(start) {
        const theoryEnd = start + this.param.keeps - 1;
        const truelyEnd = Math.min(theoryEnd, this.getLastIndex());
        return truelyEnd;
      }
      // return total front offset
      getPadFront() {
        if (this.isFixedType()) {
          return this.fixedSizeValue * this.range.start;
        } else {
          return this.getIndexOffset(this.range.start);
        }
      }
      // return total behind offset
      getPadBehind() {
        const end = this.range.end;
        const lastIndex = this.getLastIndex();
        if (this.isFixedType()) {
          return (lastIndex - end) * this.fixedSizeValue;
        }
        if (this.lastCalcIndex === lastIndex) {
          return this.getIndexOffset(lastIndex) - this.getIndexOffset(end);
        } else {
          return (lastIndex - end) * this.getEstimateSize();
        }
      }
      // get the item estimate size
      getEstimateSize() {
        return this.isFixedType() ? this.fixedSizeValue : this.firstRangeAverageSize || this.param.estimateSize;
      }
    }
    function isBrowser() {
      return typeof document !== "undefined";
    }
    function create_fragment$i(ctx) {
      let div;
      let current;
      const default_slot_template = (
        /*#slots*/
        ctx[5].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[4],
        null
      );
      return {
        c() {
          div = element("div");
          if (default_slot) default_slot.c();
          attr(div, "class", "virtual-scroll-item");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if (default_slot) {
            default_slot.m(div, null);
          }
          ctx[6](div);
          current = true;
        },
        p(ctx2, [dirty]) {
          if (default_slot) {
            if (default_slot.p && (!current || dirty & /*$$scope*/
            16)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx2,
                /*$$scope*/
                ctx2[4],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx2[4]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx2[4],
                  dirty,
                  null
                ),
                null
              );
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(default_slot, local);
          current = true;
        },
        o(local) {
          transition_out(default_slot, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if (default_slot) default_slot.d(detaching);
          ctx[6](null);
        }
      };
    }
    function instance$h($$self, $$props, $$invalidate) {
      let { $$slots: slots = {}, $$scope } = $$props;
      let { horizontal = false } = $$props;
      let { uniqueKey } = $$props;
      let { type = "item" } = $$props;
      let resizeObserver2;
      let itemDiv;
      let previousSize;
      const dispatch2 = createEventDispatcher();
      const shapeKey = horizontal ? "offsetWidth" : "offsetHeight";
      onMount(() => {
        if (typeof ResizeObserver !== "undefined") {
          resizeObserver2 = new ResizeObserver(dispatchSizeChange);
          resizeObserver2.observe(itemDiv);
        }
      });
      afterUpdate(dispatchSizeChange);
      onDestroy(() => {
        if (resizeObserver2) {
          resizeObserver2.disconnect();
          resizeObserver2 = null;
        }
      });
      function dispatchSizeChange() {
        const size = itemDiv ? itemDiv[shapeKey] : 0;
        if (size === previousSize) return;
        previousSize = size;
        dispatch2("resize", { id: uniqueKey, size, type });
      }
      function div_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          itemDiv = $$value;
          $$invalidate(0, itemDiv);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("horizontal" in $$props2) $$invalidate(1, horizontal = $$props2.horizontal);
        if ("uniqueKey" in $$props2) $$invalidate(2, uniqueKey = $$props2.uniqueKey);
        if ("type" in $$props2) $$invalidate(3, type = $$props2.type);
        if ("$$scope" in $$props2) $$invalidate(4, $$scope = $$props2.$$scope);
      };
      return [itemDiv, horizontal, uniqueKey, type, $$scope, slots, div_binding];
    }
    class Item extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$h, create_fragment$i, safe_not_equal, { horizontal: 1, uniqueKey: 2, type: 3 });
      }
    }
    const get_footer_slot_changes = (dirty) => ({});
    const get_footer_slot_context = (ctx) => ({});
    function get_each_context$6(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[39] = list[i];
      child_ctx[41] = i;
      return child_ctx;
    }
    const get_default_slot_changes = (dirty) => ({
      data: dirty[0] & /*displayItems*/
      4,
      index: dirty[0] & /*displayItems*/
      4
    });
    const get_default_slot_context = (ctx) => ({
      data: (
        /*dataItem*/
        ctx[39]
      ),
      index: (
        /*dataIndex*/
        ctx[41]
      )
    });
    const get_header_slot_changes = (dirty) => ({});
    const get_header_slot_context = (ctx) => ({});
    function create_if_block_1$3(ctx) {
      let item;
      let current;
      item = new Item({
        props: {
          type: "slot",
          uniqueKey: "header",
          $$slots: { default: [create_default_slot_2$1] },
          $$scope: { ctx }
        }
      });
      item.$on(
        "resize",
        /*onItemResized*/
        ctx[6]
      );
      return {
        c() {
          create_component(item.$$.fragment);
        },
        m(target, anchor) {
          mount_component(item, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const item_changes = {};
          if (dirty[0] & /*$$scope*/
          536870912) {
            item_changes.$$scope = { dirty, ctx: ctx2 };
          }
          item.$set(item_changes);
        },
        i(local) {
          if (current) return;
          transition_in(item.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(item.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(item, detaching);
        }
      };
    }
    function create_default_slot_2$1(ctx) {
      let current;
      const header_slot_template = (
        /*#slots*/
        ctx[26].header
      );
      const header_slot = create_slot(
        header_slot_template,
        ctx,
        /*$$scope*/
        ctx[29],
        get_header_slot_context
      );
      return {
        c() {
          if (header_slot) header_slot.c();
        },
        m(target, anchor) {
          if (header_slot) {
            header_slot.m(target, anchor);
          }
          current = true;
        },
        p(ctx2, dirty) {
          if (header_slot) {
            if (header_slot.p && (!current || dirty[0] & /*$$scope*/
            536870912)) {
              update_slot_base(
                header_slot,
                header_slot_template,
                ctx2,
                /*$$scope*/
                ctx2[29],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx2[29]
                ) : get_slot_changes(
                  header_slot_template,
                  /*$$scope*/
                  ctx2[29],
                  dirty,
                  get_header_slot_changes
                ),
                get_header_slot_context
              );
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(header_slot, local);
          current = true;
        },
        o(local) {
          transition_out(header_slot, local);
          current = false;
        },
        d(detaching) {
          if (header_slot) header_slot.d(detaching);
        }
      };
    }
    function create_default_slot_1$1(ctx) {
      let t;
      let current;
      const default_slot_template = (
        /*#slots*/
        ctx[26].default
      );
      const default_slot = create_slot(
        default_slot_template,
        ctx,
        /*$$scope*/
        ctx[29],
        get_default_slot_context
      );
      return {
        c() {
          if (default_slot) default_slot.c();
          t = space();
        },
        m(target, anchor) {
          if (default_slot) {
            default_slot.m(target, anchor);
          }
          insert(target, t, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (default_slot) {
            if (default_slot.p && (!current || dirty[0] & /*$$scope, displayItems*/
            536870916)) {
              update_slot_base(
                default_slot,
                default_slot_template,
                ctx2,
                /*$$scope*/
                ctx2[29],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx2[29]
                ) : get_slot_changes(
                  default_slot_template,
                  /*$$scope*/
                  ctx2[29],
                  dirty,
                  get_default_slot_changes
                ),
                get_default_slot_context
              );
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(default_slot, local);
          current = true;
        },
        o(local) {
          transition_out(default_slot, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(t);
          }
          if (default_slot) default_slot.d(detaching);
        }
      };
    }
    function create_each_block$6(key_2, ctx) {
      let first;
      let item;
      let current;
      item = new Item({
        props: {
          uniqueKey: (
            /*dataItem*/
            ctx[39][
              /*key*/
              ctx[0]
            ]
          ),
          horizontal: (
            /*isHorizontal*/
            ctx[1]
          ),
          type: "item",
          $$slots: { default: [create_default_slot_1$1] },
          $$scope: { ctx }
        }
      });
      item.$on(
        "resize",
        /*onItemResized*/
        ctx[6]
      );
      return {
        key: key_2,
        first: null,
        c() {
          first = empty();
          create_component(item.$$.fragment);
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          mount_component(item, target, anchor);
          current = true;
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const item_changes = {};
          if (dirty[0] & /*displayItems, key*/
          5) item_changes.uniqueKey = /*dataItem*/
          ctx[39][
            /*key*/
            ctx[0]
          ];
          if (dirty[0] & /*isHorizontal*/
          2) item_changes.horizontal = /*isHorizontal*/
          ctx[1];
          if (dirty[0] & /*$$scope, displayItems*/
          536870916) {
            item_changes.$$scope = { dirty, ctx };
          }
          item.$set(item_changes);
        },
        i(local) {
          if (current) return;
          transition_in(item.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(item.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(first);
          }
          destroy_component(item, detaching);
        }
      };
    }
    function create_if_block$6(ctx) {
      let item;
      let current;
      item = new Item({
        props: {
          type: "slot",
          uniqueKey: "footer",
          $$slots: { default: [create_default_slot$2] },
          $$scope: { ctx }
        }
      });
      item.$on(
        "resize",
        /*onItemResized*/
        ctx[6]
      );
      return {
        c() {
          create_component(item.$$.fragment);
        },
        m(target, anchor) {
          mount_component(item, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const item_changes = {};
          if (dirty[0] & /*$$scope*/
          536870912) {
            item_changes.$$scope = { dirty, ctx: ctx2 };
          }
          item.$set(item_changes);
        },
        i(local) {
          if (current) return;
          transition_in(item.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(item.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(item, detaching);
        }
      };
    }
    function create_default_slot$2(ctx) {
      let current;
      const footer_slot_template = (
        /*#slots*/
        ctx[26].footer
      );
      const footer_slot = create_slot(
        footer_slot_template,
        ctx,
        /*$$scope*/
        ctx[29],
        get_footer_slot_context
      );
      return {
        c() {
          if (footer_slot) footer_slot.c();
        },
        m(target, anchor) {
          if (footer_slot) {
            footer_slot.m(target, anchor);
          }
          current = true;
        },
        p(ctx2, dirty) {
          if (footer_slot) {
            if (footer_slot.p && (!current || dirty[0] & /*$$scope*/
            536870912)) {
              update_slot_base(
                footer_slot,
                footer_slot_template,
                ctx2,
                /*$$scope*/
                ctx2[29],
                !current ? get_all_dirty_from_scope(
                  /*$$scope*/
                  ctx2[29]
                ) : get_slot_changes(
                  footer_slot_template,
                  /*$$scope*/
                  ctx2[29],
                  dirty,
                  get_footer_slot_changes
                ),
                get_footer_slot_context
              );
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(footer_slot, local);
          current = true;
        },
        o(local) {
          transition_out(footer_slot, local);
          current = false;
        },
        d(detaching) {
          if (footer_slot) footer_slot.d(detaching);
        }
      };
    }
    function create_fragment$h(ctx) {
      let div2;
      let t0;
      let div0;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let t1;
      let t2;
      let div1;
      let current;
      let mounted;
      let dispose;
      let if_block0 = (
        /*$$slots*/
        ctx[8].header && create_if_block_1$3(ctx)
      );
      let each_value = ensure_array_like(
        /*displayItems*/
        ctx[2]
      );
      const get_key = (ctx2) => (
        /*dataItem*/
        ctx2[39][
          /*key*/
          ctx2[0]
        ]
      );
      for (let i = 0; i < each_value.length; i += 1) {
        let child_ctx = get_each_context$6(ctx, each_value, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block$6(key, child_ctx));
      }
      let if_block1 = (
        /*$$slots*/
        ctx[8].footer && create_if_block$6(ctx)
      );
      return {
        c() {
          div2 = element("div");
          if (if_block0) if_block0.c();
          t0 = space();
          div0 = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          t1 = space();
          if (if_block1) if_block1.c();
          t2 = space();
          div1 = element("div");
          set_style(
            div0,
            "padding",
            /*paddingStyle*/
            ctx[3]
          );
          attr(div0, "class", "virtual-scroll-wrapper");
          attr(div1, "class", "shepherd");
          set_style(
            div1,
            "width",
            /*isHorizontal*/
            ctx[1] ? "0px" : "100%"
          );
          set_style(
            div1,
            "height",
            /*isHorizontal*/
            ctx[1] ? "100%" : "0px"
          );
          set_style(div2, "overflow-y", "auto");
          set_style(div2, "height", "inherit");
          attr(div2, "class", "virtual-scroll-root");
        },
        m(target, anchor) {
          insert(target, div2, anchor);
          if (if_block0) if_block0.m(div2, null);
          append(div2, t0);
          append(div2, div0);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div0, null);
            }
          }
          append(div2, t1);
          if (if_block1) if_block1.m(div2, null);
          append(div2, t2);
          append(div2, div1);
          ctx[27](div1);
          ctx[28](div2);
          current = true;
          if (!mounted) {
            dispose = listen(
              div2,
              "scroll",
              /*onScroll*/
              ctx[7]
            );
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (
            /*$$slots*/
            ctx2[8].header
          ) {
            if (if_block0) {
              if_block0.p(ctx2, dirty);
              if (dirty[0] & /*$$slots*/
              256) {
                transition_in(if_block0, 1);
              }
            } else {
              if_block0 = create_if_block_1$3(ctx2);
              if_block0.c();
              transition_in(if_block0, 1);
              if_block0.m(div2, t0);
            }
          } else if (if_block0) {
            group_outros();
            transition_out(if_block0, 1, 1, () => {
              if_block0 = null;
            });
            check_outros();
          }
          if (dirty[0] & /*displayItems, key, isHorizontal, onItemResized, $$scope*/
          536870983) {
            each_value = ensure_array_like(
              /*displayItems*/
              ctx2[2]
            );
            group_outros();
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div0, outro_and_destroy_block, create_each_block$6, null, get_each_context$6);
            check_outros();
          }
          if (!current || dirty[0] & /*paddingStyle*/
          8) {
            set_style(
              div0,
              "padding",
              /*paddingStyle*/
              ctx2[3]
            );
          }
          if (
            /*$$slots*/
            ctx2[8].footer
          ) {
            if (if_block1) {
              if_block1.p(ctx2, dirty);
              if (dirty[0] & /*$$slots*/
              256) {
                transition_in(if_block1, 1);
              }
            } else {
              if_block1 = create_if_block$6(ctx2);
              if_block1.c();
              transition_in(if_block1, 1);
              if_block1.m(div2, t2);
            }
          } else if (if_block1) {
            group_outros();
            transition_out(if_block1, 1, 1, () => {
              if_block1 = null;
            });
            check_outros();
          }
          if (!current || dirty[0] & /*isHorizontal*/
          2) {
            set_style(
              div1,
              "width",
              /*isHorizontal*/
              ctx2[1] ? "0px" : "100%"
            );
          }
          if (!current || dirty[0] & /*isHorizontal*/
          2) {
            set_style(
              div1,
              "height",
              /*isHorizontal*/
              ctx2[1] ? "100%" : "0px"
            );
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block0);
          for (let i = 0; i < each_value.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          transition_in(if_block1);
          current = true;
        },
        o(local) {
          transition_out(if_block0);
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          transition_out(if_block1);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div2);
          }
          if (if_block0) if_block0.d();
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
          if (if_block1) if_block1.d();
          ctx[27](null);
          ctx[28](null);
          mounted = false;
          dispose();
        }
      };
    }
    function instance$g($$self, $$props, $$invalidate) {
      let { $$slots: slots = {}, $$scope } = $$props;
      const $$slots = compute_slots(slots);
      let { key = "id" } = $$props;
      let { data } = $$props;
      let { keeps = 30 } = $$props;
      let { estimateSize = 50 } = $$props;
      let { isHorizontal = false } = $$props;
      let { start = 0 } = $$props;
      let { offset: offset2 = 0 } = $$props;
      let { pageMode = false } = $$props;
      let { topThreshold = 0 } = $$props;
      let { bottomThreshold = 0 } = $$props;
      let displayItems = [];
      let paddingStyle;
      let directionKey = isHorizontal ? "scrollLeft" : "scrollTop";
      let range = null;
      let virtual = new Virtual(
        {
          slotHeaderSize: 0,
          slotFooterSize: 0,
          keeps,
          estimateSize,
          buffer: Math.round(keeps / 3),
          // recommend for a third of keeps
          uniqueIds: getUniqueIdFromDataSources()
        },
        onRangeChanged
      );
      let root;
      let shepherd;
      const dispatch2 = createEventDispatcher();
      function getSize(id) {
        return virtual.sizes.get(id);
      }
      function getSizes() {
        return virtual.sizes.size;
      }
      function getOffset() {
        if (pageMode && isBrowser()) {
          return document.documentElement[directionKey] || document.body[directionKey];
        } else {
          return root ? Math.ceil(root[directionKey]) : 0;
        }
      }
      function getClientSize() {
        const key2 = isHorizontal ? "clientWidth" : "clientHeight";
        if (pageMode && isBrowser()) {
          return document.documentElement[key2] || document.body[key2];
        } else {
          return root ? Math.ceil(root[key2]) : 0;
        }
      }
      function getScrollSize() {
        const key2 = isHorizontal ? "scrollWidth" : "scrollHeight";
        if (pageMode && isBrowser()) {
          return document.documentElement[key2] || document.body[key2];
        } else {
          return root ? Math.ceil(root[key2]) : 0;
        }
      }
      function updatePageModeFront() {
        if (root && isBrowser()) {
          const rect = root.getBoundingClientRect();
          const { defaultView } = root.ownerDocument;
          const offsetFront = isHorizontal ? rect.left + defaultView.pageXOffset : rect.top + defaultView.pageYOffset;
          virtual.updateParam("slotHeaderSize", offsetFront);
        }
      }
      function scrollToOffset(offset3) {
        if (!isBrowser()) return;
        if (pageMode) {
          document.body[directionKey] = offset3;
          document.documentElement[directionKey] = offset3;
        } else if (root) {
          $$invalidate(4, root[directionKey] = offset3, root);
        }
      }
      function scrollToIndex(index) {
        if (index >= data.length - 1) {
          scrollToBottom();
        } else {
          const offset3 = virtual.getOffset(index);
          scrollToOffset(offset3);
        }
      }
      function scrollToBottom() {
        if (shepherd) {
          const offset3 = shepherd[isHorizontal ? "offsetLeft" : "offsetTop"];
          scrollToOffset(offset3);
          setTimeout(
            () => {
              if (getOffset() + getClientSize() + 1 < getScrollSize()) {
                scrollToBottom();
              }
            },
            3
          );
        }
      }
      onMount(() => {
        if (start) {
          scrollToIndex(start);
        } else if (offset2) {
          scrollToOffset(offset2);
        }
        if (pageMode) {
          updatePageModeFront();
          document.addEventListener("scroll", onScroll, { passive: false });
        }
      });
      onDestroy(() => {
        virtual.destroy();
        if (pageMode && isBrowser()) {
          document.removeEventListener("scroll", onScroll);
        }
      });
      function getUniqueIdFromDataSources() {
        return data.map((dataSource) => dataSource[key]);
      }
      function onItemResized(event) {
        const { id, size, type } = event.detail;
        if (type === "item") virtual.saveSize(id, size);
        else if (type === "slot") {
          if (id === "header") virtual.updateParam("slotHeaderSize", size);
          else if (id === "footer") virtual.updateParam("slotFooterSize", size);
        }
      }
      function onRangeChanged(range_) {
        range = range_;
        $$invalidate(3, paddingStyle = $$invalidate(3, paddingStyle = isHorizontal ? `0px ${range.padBehind}px 0px ${range.padFront}px` : `${range.padFront}px 0px ${range.padBehind}px`));
        $$invalidate(2, displayItems = data.slice(range.start, range.end + 1));
      }
      function onScroll(event) {
        const offset3 = getOffset();
        const clientSize = getClientSize();
        const scrollSize = getScrollSize();
        if (offset3 < 0 || offset3 + clientSize > scrollSize || !scrollSize) {
          return;
        }
        virtual.handleScroll(offset3);
        emitEvent(offset3, clientSize, scrollSize, event);
      }
      function emitEvent(offset3, clientSize, scrollSize, event) {
        dispatch2("scroll", { event, range: virtual.getRange() });
        if (virtual.isFront() && !!data.length && offset3 - topThreshold <= 0) {
          dispatch2("top");
        } else if (virtual.isBehind() && offset3 + clientSize + bottomThreshold >= scrollSize) {
          dispatch2("bottom");
        }
      }
      function handleKeepsChange(keeps2) {
        virtual.updateParam("keeps", keeps2);
        virtual.handleSlotSizeChange();
      }
      async function handleDataSourcesChange(data2) {
        virtual.updateParam("uniqueIds", getUniqueIdFromDataSources());
        virtual.handleDataSourcesChange();
      }
      function div1_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          shepherd = $$value;
          $$invalidate(5, shepherd);
        });
      }
      function div2_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          root = $$value;
          $$invalidate(4, root);
        });
      }
      $$self.$$set = ($$props2) => {
        if ("key" in $$props2) $$invalidate(0, key = $$props2.key);
        if ("data" in $$props2) $$invalidate(9, data = $$props2.data);
        if ("keeps" in $$props2) $$invalidate(10, keeps = $$props2.keeps);
        if ("estimateSize" in $$props2) $$invalidate(11, estimateSize = $$props2.estimateSize);
        if ("isHorizontal" in $$props2) $$invalidate(1, isHorizontal = $$props2.isHorizontal);
        if ("start" in $$props2) $$invalidate(12, start = $$props2.start);
        if ("offset" in $$props2) $$invalidate(13, offset2 = $$props2.offset);
        if ("pageMode" in $$props2) $$invalidate(14, pageMode = $$props2.pageMode);
        if ("topThreshold" in $$props2) $$invalidate(15, topThreshold = $$props2.topThreshold);
        if ("bottomThreshold" in $$props2) $$invalidate(16, bottomThreshold = $$props2.bottomThreshold);
        if ("$$scope" in $$props2) $$invalidate(29, $$scope = $$props2.$$scope);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty[0] & /*offset*/
        8192) {
          scrollToOffset(offset2);
        }
        if ($$self.$$.dirty[0] & /*start*/
        4096) {
          scrollToIndex(start);
        }
        if ($$self.$$.dirty[0] & /*keeps*/
        1024) {
          handleKeepsChange(keeps);
        }
        if ($$self.$$.dirty[0] & /*data*/
        512) {
          handleDataSourcesChange();
        }
      };
      return [
        key,
        isHorizontal,
        displayItems,
        paddingStyle,
        root,
        shepherd,
        onItemResized,
        onScroll,
        $$slots,
        data,
        keeps,
        estimateSize,
        start,
        offset2,
        pageMode,
        topThreshold,
        bottomThreshold,
        getSize,
        getSizes,
        getOffset,
        getClientSize,
        getScrollSize,
        updatePageModeFront,
        scrollToOffset,
        scrollToIndex,
        scrollToBottom,
        slots,
        div1_binding,
        div2_binding,
        $$scope
      ];
    }
    class VirtualScroll extends SvelteComponent {
      constructor(options) {
        super();
        init(
          this,
          options,
          instance$g,
          create_fragment$h,
          safe_not_equal,
          {
            key: 0,
            data: 9,
            keeps: 10,
            estimateSize: 11,
            isHorizontal: 1,
            start: 12,
            offset: 13,
            pageMode: 14,
            topThreshold: 15,
            bottomThreshold: 16,
            getSize: 17,
            getSizes: 18,
            getOffset: 19,
            getClientSize: 20,
            getScrollSize: 21,
            updatePageModeFront: 22,
            scrollToOffset: 23,
            scrollToIndex: 24,
            scrollToBottom: 25
          },
          null,
          [-1, -1]
        );
      }
      get getSize() {
        return this.$$.ctx[17];
      }
      get getSizes() {
        return this.$$.ctx[18];
      }
      get getOffset() {
        return this.$$.ctx[19];
      }
      get getClientSize() {
        return this.$$.ctx[20];
      }
      get getScrollSize() {
        return this.$$.ctx[21];
      }
      get updatePageModeFront() {
        return this.$$.ctx[22];
      }
      get scrollToOffset() {
        return this.$$.ctx[23];
      }
      get scrollToIndex() {
        return this.$$.ctx[24];
      }
      get scrollToBottom() {
        return this.$$.ctx[25];
      }
    }
    function get_each_context$5(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[42] = list[i];
      child_ctx[44] = i;
      return child_ctx;
    }
    function create_each_block$5(ctx) {
      let option;
      let t_value = (
        /*pack*/
        ctx[42] + ""
      );
      let t;
      let option_value_value;
      return {
        c() {
          option = element("option");
          t = text$1(t_value);
          option.__value = option_value_value = /*pack*/
          ctx[42];
          set_input_value(option, option.__value);
        },
        m(target, anchor) {
          insert(target, option, anchor);
          append(option, t);
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*$packStore*/
          256 && t_value !== (t_value = /*pack*/
          ctx2[42] + "")) set_data(t, t_value);
          if (dirty[0] & /*$packStore*/
          256 && option_value_value !== (option_value_value = /*pack*/
          ctx2[42])) {
            option.__value = option_value_value;
            set_input_value(option, option.__value);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(option);
          }
        }
      };
    }
    function create_else_block_1(ctx) {
      let div;
      let virtualscroll;
      let current;
      virtualscroll = new VirtualScroll({
        props: {
          data: (
            /*$visibleTreeStore*/
            ctx[10]
          ),
          key: "fullPath",
          $$slots: {
            default: [
              create_default_slot_2,
              ({ data }) => ({ 41: data }),
              ({ data }) => [0, data ? 1024 : 0]
            ]
          },
          $$scope: { ctx }
        }
      });
      return {
        c() {
          div = element("div");
          create_component(virtualscroll.$$.fragment);
          attr(div, "class", "sequencer-database-entries-tree svelte-seq-r6s8zx");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          mount_component(virtualscroll, div, null);
          current = true;
        },
        p(ctx2, dirty) {
          const virtualscroll_changes = {};
          if (dirty[0] & /*$visibleTreeStore*/
          1024) virtualscroll_changes.data = /*$visibleTreeStore*/
          ctx2[10];
          if (dirty[1] & /*$$scope, data*/
          17408) {
            virtualscroll_changes.$$scope = { dirty, ctx: ctx2 };
          }
          virtualscroll.$set(virtualscroll_changes);
        },
        i(local) {
          if (current) return;
          transition_in(virtualscroll.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(virtualscroll.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          destroy_component(virtualscroll);
        }
      };
    }
    function create_if_block_1$2(ctx) {
      let div;
      let virtualscroll;
      let current;
      virtualscroll = new VirtualScroll({
        props: {
          data: (
            /*filteredEntries*/
            ctx[7]
          ),
          key: "entry",
          $$slots: {
            default: [
              create_default_slot_1,
              ({ data }) => ({ 41: data }),
              ({ data }) => [0, data ? 1024 : 0]
            ]
          },
          $$scope: { ctx }
        }
      });
      return {
        c() {
          div = element("div");
          create_component(virtualscroll.$$.fragment);
          attr(div, "class", "sequencer-database-entries svelte-seq-r6s8zx");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          mount_component(virtualscroll, div, null);
          current = true;
        },
        p(ctx2, dirty) {
          const virtualscroll_changes = {};
          if (dirty[0] & /*filteredEntries*/
          128) virtualscroll_changes.data = /*filteredEntries*/
          ctx2[7];
          if (dirty[1] & /*$$scope, data*/
          17408) {
            virtualscroll_changes.$$scope = { dirty, ctx: ctx2 };
          }
          virtualscroll.$set(virtualscroll_changes);
        },
        i(local) {
          if (current) return;
          transition_in(virtualscroll.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(virtualscroll.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          destroy_component(virtualscroll);
        }
      };
    }
    function create_default_slot_2(ctx) {
      let switch_instance;
      let switch_instance_anchor;
      let current;
      var switch_value = (
        /*data*/
        ctx[41].class
      );
      function switch_props(ctx2, dirty) {
        return { props: { data: (
          /*data*/
          ctx2[41]
        ) } };
      }
      if (switch_value) {
        switch_instance = construct_svelte_component(switch_value, switch_props(ctx));
      }
      return {
        c() {
          if (switch_instance) create_component(switch_instance.$$.fragment);
          switch_instance_anchor = empty();
        },
        m(target, anchor) {
          if (switch_instance) mount_component(switch_instance, target, anchor);
          insert(target, switch_instance_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty[1] & /*data*/
          1024 && switch_value !== (switch_value = /*data*/
          ctx2[41].class)) {
            if (switch_instance) {
              group_outros();
              const old_component = switch_instance;
              transition_out(old_component.$$.fragment, 1, 0, () => {
                destroy_component(old_component, 1);
              });
              check_outros();
            }
            if (switch_value) {
              switch_instance = construct_svelte_component(switch_value, switch_props(ctx2));
              create_component(switch_instance.$$.fragment);
              transition_in(switch_instance.$$.fragment, 1);
              mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
            } else {
              switch_instance = null;
            }
          } else if (switch_value) {
            const switch_instance_changes = {};
            if (dirty[1] & /*data*/
            1024) switch_instance_changes.data = /*data*/
            ctx2[41];
            switch_instance.$set(switch_instance_changes);
          }
        },
        i(local) {
          if (current) return;
          if (switch_instance) transition_in(switch_instance.$$.fragment, local);
          current = true;
        },
        o(local) {
          if (switch_instance) transition_out(switch_instance.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(switch_instance_anchor);
          }
          if (switch_instance) destroy_component(switch_instance, detaching);
        }
      };
    }
    function create_default_slot_1(ctx) {
      let databaseentry;
      let current;
      databaseentry = new DatabaseEntry({ props: { entry: (
        /*data*/
        ctx[41].entry
      ) } });
      return {
        c() {
          create_component(databaseentry.$$.fragment);
        },
        m(target, anchor) {
          mount_component(databaseentry, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const databaseentry_changes = {};
          if (dirty[1] & /*data*/
          1024) databaseentry_changes.entry = /*data*/
          ctx2[41].entry;
          databaseentry.$set(databaseentry_changes);
        },
        i(local) {
          if (current) return;
          transition_in(databaseentry.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(databaseentry.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(databaseentry, detaching);
        }
      };
    }
    function create_else_block$1(ctx) {
      let t;
      return {
        c() {
          t = text$1("No file loaded...");
        },
        m(target, anchor) {
          insert(target, t, anchor);
        },
        p: noop,
        d(detaching) {
          if (detaching) {
            detach(t);
          }
        }
      };
    }
    function create_if_block$5(ctx) {
      let t0;
      let t1_value = (
        /*$metadata*/
        ctx[11].type + ""
      );
      let t1;
      let t2;
      let t3_value = (
        /*$metadata*/
        ctx[11].duration + ""
      );
      let t3;
      return {
        c() {
          t0 = text$1("Type: ");
          t1 = text$1(t1_value);
          t2 = text$1(" | Duration: ");
          t3 = text$1(t3_value);
        },
        m(target, anchor) {
          insert(target, t0, anchor);
          insert(target, t1, anchor);
          insert(target, t2, anchor);
          insert(target, t3, anchor);
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*$metadata*/
          2048 && t1_value !== (t1_value = /*$metadata*/
          ctx2[11].type + "")) set_data(t1, t1_value);
          if (dirty[0] & /*$metadata*/
          2048 && t3_value !== (t3_value = /*$metadata*/
          ctx2[11].duration + "")) set_data(t3, t3_value);
        },
        d(detaching) {
          if (detaching) {
            detach(t0);
            detach(t1);
            detach(t2);
            detach(t3);
          }
        }
      };
    }
    function create_default_slot$1(ctx) {
      let div5;
      let div0;
      let select0;
      let option0;
      let t1;
      let select1;
      let option1;
      let option2;
      let option3;
      let select1_disabled_value;
      let select1_title_value;
      let t5;
      let input0;
      let t6;
      let input1;
      let t7;
      let label0;
      let t9;
      let input2;
      let t10;
      let label1;
      let t12;
      let input3;
      let t13;
      let label2;
      let t15;
      let div4;
      let current_block_type_index;
      let if_block0;
      let t16;
      let div3;
      let div1;
      let video;
      let t17;
      let img;
      let t18;
      let audio2;
      let t19;
      let div2;
      let current;
      let mounted;
      let dispose;
      let each_value = ensure_array_like(
        /*$packStore*/
        ctx[8]
      );
      let each_blocks = [];
      for (let i = 0; i < each_value.length; i += 1) {
        each_blocks[i] = create_each_block$5(get_each_context$5(ctx, each_value, i));
      }
      const if_block_creators = [create_if_block_1$2, create_else_block_1];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (
          /*$listView*/
          ctx2[5]
        ) return 0;
        return 1;
      }
      current_block_type_index = select_block_type(ctx);
      if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      function select_block_type_1(ctx2, dirty) {
        if (
          /*$metadata*/
          ctx2[11]
        ) return create_if_block$5;
        return create_else_block$1;
      }
      let current_block_type = select_block_type_1(ctx);
      let if_block1 = current_block_type(ctx);
      return {
        c() {
          div5 = element("div");
          div0 = element("div");
          select0 = element("select");
          option0 = element("option");
          option0.textContent = `${localize("SEQUENCER.Database.AllPacks")}`;
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          t1 = space();
          select1 = element("select");
          option1 = element("option");
          option1.textContent = `${localize("SEQUENCER.Database.All")}`;
          option2 = element("option");
          option2.textContent = `${localize("SEQUENCER.Database.Video")}`;
          option3 = element("option");
          option3.textContent = `${localize("SEQUENCER.Database.Sound")}`;
          t5 = space();
          input0 = element("input");
          t6 = space();
          input1 = element("input");
          t7 = space();
          label0 = element("label");
          label0.textContent = `${localize("SEQUENCER.Database.ShowAllRanges")}`;
          t9 = space();
          input2 = element("input");
          t10 = space();
          label1 = element("label");
          label1.textContent = `${localize("SEQUENCER.Database.ShowSubLists")}`;
          t12 = space();
          input3 = element("input");
          t13 = space();
          label2 = element("label");
          label2.textContent = `${localize("SEQUENCER.Database.ListView")}`;
          t15 = space();
          div4 = element("div");
          if_block0.c();
          t16 = space();
          div3 = element("div");
          div1 = element("div");
          video = element("video");
          video.innerHTML = ``;
          t17 = space();
          img = element("img");
          t18 = space();
          audio2 = element("audio");
          audio2.innerHTML = `<source type="audio"/>`;
          t19 = space();
          div2 = element("div");
          if_block1.c();
          option0.__value = "all";
          set_input_value(option0, option0.__value);
          attr(select0, "name", "pack-select");
          attr(select0, "class", "svelte-seq-r6s8zx");
          if (
            /*$selectedPackStore*/
            ctx[3] === void 0
          ) add_render_callback(() => (
            /*select0_change_handler*/
            ctx[28].call(select0)
          ));
          option1.__value = "all";
          set_input_value(option1, option1.__value);
          option2.__value = "video";
          set_input_value(option2, option2.__value);
          option3.__value = "sound";
          set_input_value(option3, option3.__value);
          attr(select1, "name", "file-select");
          select1.disabled = select1_disabled_value = !/*$allRanges*/
          ctx[4];
          attr(select1, "title", select1_title_value = /*$allRanges*/
          ctx[4] ? "" : localize("SEQUENCER.Database.FileTypePredicate"));
          attr(select1, "class", "svelte-seq-r6s8zx");
          if (
            /*$fileTypes*/
            ctx[1] === void 0
          ) add_render_callback(() => (
            /*select1_change_handler*/
            ctx[29].call(select1)
          ));
          attr(input0, "class", "ml-2 svelte-seq-r6s8zx");
          attr(input0, "placeholder", localize("SEQUENCER.Database.Search"));
          attr(input0, "type", "text");
          attr(input1, "class", "ml-2");
          attr(input1, "id", "database-all-ranges");
          attr(input1, "type", "checkbox");
          attr(label0, "class", "all-ranges-label svelte-seq-r6s8zx");
          attr(label0, "for", "database-all-ranges");
          attr(input2, "class", "ml-2");
          attr(input2, "id", "include-sub-lists");
          attr(input2, "type", "checkbox");
          attr(label1, "class", "all-ranges-label svelte-seq-r6s8zx");
          attr(label1, "for", "include-sub-lists");
          attr(input3, "class", "ml-2");
          attr(input3, "id", "treeview");
          attr(input3, "type", "checkbox");
          attr(label2, "class", "all-ranges-label svelte-seq-r6s8zx");
          attr(label2, "for", "treeview");
          attr(div0, "class", "sequencer-database-header svelte-seq-r6s8zx");
          video.autoplay = true;
          attr(video, "class", "database-player svelte-seq-r6s8zx");
          attr(video, "height", "335");
          video.loop = true;
          attr(video, "preload", "");
          attr(video, "width", "335");
          attr(img, "class", "database-image hidden svelte-seq-r6s8zx");
          audio2.controls = true;
          audio2.autoplay = true;
          attr(audio2, "class", "database-audio hidden svelte-seq-r6s8zx");
          attr(div1, "class", "sequencer-database-player-content svelte-seq-r6s8zx");
          attr(div2, "class", "sequencer-database-metadata-footer svelte-seq-r6s8zx");
          attr(div3, "class", "sequencer-database-player-container svelte-seq-r6s8zx");
          attr(div4, "class", "sequencer-database-entries-container svelte-seq-r6s8zx");
          attr(div5, "class", "sequencer-database-content svelte-seq-r6s8zx");
        },
        m(target, anchor) {
          insert(target, div5, anchor);
          append(div5, div0);
          append(div0, select0);
          append(select0, option0);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(select0, null);
            }
          }
          select_option(
            select0,
            /*$selectedPackStore*/
            ctx[3],
            true
          );
          append(div0, t1);
          append(div0, select1);
          append(select1, option1);
          append(select1, option2);
          append(select1, option3);
          select_option(
            select1,
            /*$fileTypes*/
            ctx[1],
            true
          );
          append(div0, t5);
          append(div0, input0);
          set_input_value(
            input0,
            /*$search*/
            ctx[2]
          );
          append(div0, t6);
          append(div0, input1);
          input1.checked = /*$allRanges*/
          ctx[4];
          append(div0, t7);
          append(div0, label0);
          append(div0, t9);
          append(div0, input2);
          input2.checked = /*$subLists*/
          ctx[9];
          append(div0, t10);
          append(div0, label1);
          append(div0, t12);
          append(div0, input3);
          input3.checked = /*$listView*/
          ctx[5];
          append(div0, t13);
          append(div0, label2);
          append(div5, t15);
          append(div5, div4);
          if_blocks[current_block_type_index].m(div4, null);
          append(div4, t16);
          append(div4, div3);
          append(div3, div1);
          append(div1, video);
          ctx[34](video);
          append(div1, t17);
          append(div1, img);
          ctx[37](img);
          append(div1, t18);
          append(div1, audio2);
          ctx[38](audio2);
          append(div3, t19);
          append(div3, div2);
          if_block1.m(div2, null);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                select0,
                "change",
                /*select0_change_handler*/
                ctx[28]
              ),
              listen(
                select1,
                "change",
                /*select1_change_handler*/
                ctx[29]
              ),
              listen(
                input0,
                "input",
                /*input0_input_handler*/
                ctx[30]
              ),
              listen(
                input1,
                "change",
                /*input1_change_handler*/
                ctx[31]
              ),
              listen(
                input2,
                "change",
                /*input2_change_handler*/
                ctx[32]
              ),
              listen(
                input3,
                "change",
                /*input3_change_handler*/
                ctx[33]
              ),
              listen(
                video,
                "mouseenter",
                /*mouseenter_handler*/
                ctx[35]
              ),
              listen(
                video,
                "mouseleave",
                /*mouseleave_handler*/
                ctx[36]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (dirty[0] & /*$packStore*/
          256) {
            each_value = ensure_array_like(
              /*$packStore*/
              ctx2[8]
            );
            let i;
            for (i = 0; i < each_value.length; i += 1) {
              const child_ctx = get_each_context$5(ctx2, each_value, i);
              if (each_blocks[i]) {
                each_blocks[i].p(child_ctx, dirty);
              } else {
                each_blocks[i] = create_each_block$5(child_ctx);
                each_blocks[i].c();
                each_blocks[i].m(select0, null);
              }
            }
            for (; i < each_blocks.length; i += 1) {
              each_blocks[i].d(1);
            }
            each_blocks.length = each_value.length;
          }
          if (dirty[0] & /*$selectedPackStore, $packStore*/
          264) {
            select_option(
              select0,
              /*$selectedPackStore*/
              ctx2[3]
            );
          }
          if (!current || dirty[0] & /*$allRanges*/
          16 && select1_disabled_value !== (select1_disabled_value = !/*$allRanges*/
          ctx2[4])) {
            select1.disabled = select1_disabled_value;
          }
          if (!current || dirty[0] & /*$allRanges*/
          16 && select1_title_value !== (select1_title_value = /*$allRanges*/
          ctx2[4] ? "" : localize("SEQUENCER.Database.FileTypePredicate"))) {
            attr(select1, "title", select1_title_value);
          }
          if (dirty[0] & /*$fileTypes*/
          2) {
            select_option(
              select1,
              /*$fileTypes*/
              ctx2[1]
            );
          }
          if (dirty[0] & /*$search*/
          4 && input0.value !== /*$search*/
          ctx2[2]) {
            set_input_value(
              input0,
              /*$search*/
              ctx2[2]
            );
          }
          if (dirty[0] & /*$allRanges*/
          16) {
            input1.checked = /*$allRanges*/
            ctx2[4];
          }
          if (dirty[0] & /*$subLists*/
          512) {
            input2.checked = /*$subLists*/
            ctx2[9];
          }
          if (dirty[0] & /*$listView*/
          32) {
            input3.checked = /*$listView*/
            ctx2[5];
          }
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if_blocks[current_block_type_index].p(ctx2, dirty);
          } else {
            group_outros();
            transition_out(if_blocks[previous_block_index], 1, 1, () => {
              if_blocks[previous_block_index] = null;
            });
            check_outros();
            if_block0 = if_blocks[current_block_type_index];
            if (!if_block0) {
              if_block0 = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
              if_block0.c();
            } else {
              if_block0.p(ctx2, dirty);
            }
            transition_in(if_block0, 1);
            if_block0.m(div4, t16);
          }
          if (current_block_type === (current_block_type = select_block_type_1(ctx2)) && if_block1) {
            if_block1.p(ctx2, dirty);
          } else {
            if_block1.d(1);
            if_block1 = current_block_type(ctx2);
            if (if_block1) {
              if_block1.c();
              if_block1.m(div2, null);
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block0);
          current = true;
        },
        o(local) {
          transition_out(if_block0);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div5);
          }
          destroy_each(each_blocks, detaching);
          if_blocks[current_block_type_index].d();
          ctx[34](null);
          ctx[37](null);
          ctx[38](null);
          if_block1.d();
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_fragment$g(ctx) {
      let applicationshell;
      let updating_elementRoot;
      let current;
      function applicationshell_elementRoot_binding(value) {
        ctx[39](value);
      }
      let applicationshell_props = {
        $$slots: { default: [create_default_slot$1] },
        $$scope: { ctx }
      };
      if (
        /*elementRoot*/
        ctx[0] !== void 0
      ) {
        applicationshell_props.elementRoot = /*elementRoot*/
        ctx[0];
      }
      applicationshell = new ApplicationShell({ props: applicationshell_props });
      binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding));
      return {
        c() {
          create_component(applicationshell.$$.fragment);
        },
        m(target, anchor) {
          mount_component(applicationshell, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const applicationshell_changes = {};
          if (dirty[0] & /*$metadata, databaseStore, filteredEntries, $listView, $visibleTreeStore, $subLists, $allRanges, $search, $fileTypes, $selectedPackStore, $packStore*/
          4094 | dirty[1] & /*$$scope*/
          16384) {
            applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
          }
          if (!updating_elementRoot && dirty[0] & /*elementRoot*/
          1) {
            updating_elementRoot = true;
            applicationshell_changes.elementRoot = /*elementRoot*/
            ctx2[0];
            add_flush_callback(() => updating_elementRoot = false);
          }
          applicationshell.$set(applicationshell_changes);
        },
        i(local) {
          if (current) return;
          transition_in(applicationshell.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(applicationshell.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(applicationshell, detaching);
        }
      };
    }
    function instance$f($$self, $$props, $$invalidate) {
      let $fileTypes;
      let $search;
      let $selectedPackStore;
      let $searchRegex;
      let $cleanSearchStore;
      let $allRanges;
      let $entriesStore;
      let $listView;
      let $packStore;
      let $subLists;
      let $visibleTreeStore;
      let $metadata;
      const { application } = getContext("#external");
      let { elementRoot } = $$props;
      let entries = [];
      let filteredEntries = [];
      const selectedPackStore2 = databaseStore.selectedPackStore;
      component_subscribe($$self, selectedPackStore2, (value) => $$invalidate(3, $selectedPackStore = value));
      const packStore2 = databaseStore.packStore;
      component_subscribe($$self, packStore2, (value) => $$invalidate(8, $packStore = value));
      const fileTypes = databaseStore.fileTypes;
      component_subscribe($$self, fileTypes, (value) => $$invalidate(1, $fileTypes = value));
      const metadata = databaseStore.metadata;
      component_subscribe($$self, metadata, (value) => $$invalidate(11, $metadata = value));
      const allRanges = databaseStore.allRanges;
      component_subscribe($$self, allRanges, (value) => $$invalidate(4, $allRanges = value));
      const subLists = databaseStore.subLists;
      component_subscribe($$self, subLists, (value) => $$invalidate(9, $subLists = value));
      const listView = databaseStore.listView;
      component_subscribe($$self, listView, (value) => $$invalidate(5, $listView = value));
      const visibleTreeStore2 = databaseStore.visibleTreeStore;
      component_subscribe($$self, visibleTreeStore2, (value) => $$invalidate(10, $visibleTreeStore = value));
      const search = databaseStore.search;
      component_subscribe($$self, search, (value) => $$invalidate(2, $search = value));
      const cleanSearchStore2 = databaseStore.cleanSearchStore;
      component_subscribe($$self, cleanSearchStore2, (value) => $$invalidate(26, $cleanSearchStore = value));
      const searchRegex = databaseStore.searchRegex;
      component_subscribe($$self, searchRegex, (value) => $$invalidate(25, $searchRegex = value));
      const entriesStore2 = SequencerDatabase.entriesStore;
      component_subscribe($$self, entriesStore2, (value) => $$invalidate(27, $entriesStore = value));
      listView.set(game.settings.get(CONSTANTS.MODULE_NAME, "db-list-view"));
      onDestroy(() => databaseStore.cleanupSpritesheet());
      function select0_change_handler() {
        $selectedPackStore = select_value(this);
        selectedPackStore2.set($selectedPackStore);
      }
      function select1_change_handler() {
        $fileTypes = select_value(this);
        fileTypes.set($fileTypes);
      }
      function input0_input_handler() {
        $search = this.value;
        search.set($search);
      }
      function input1_change_handler() {
        $allRanges = this.checked;
        allRanges.set($allRanges);
      }
      function input2_change_handler() {
        $subLists = this.checked;
        subLists.set($subLists);
      }
      function input3_change_handler() {
        $listView = this.checked;
        listView.set($listView);
      }
      function video_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          databaseStore.elements.player = $$value;
          $$invalidate(6, databaseStore);
        });
      }
      const mouseenter_handler = () => {
        $$invalidate(6, databaseStore.elements.player.controls = true, databaseStore);
      };
      const mouseleave_handler = () => {
        $$invalidate(6, databaseStore.elements.player.controls = false, databaseStore);
      };
      function img_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          databaseStore.elements.image = $$value;
          $$invalidate(6, databaseStore);
        });
      }
      function audio_binding($$value) {
        binding_callbacks[$$value ? "unshift" : "push"](() => {
          databaseStore.elements.audio = $$value;
          $$invalidate(6, databaseStore);
        });
      }
      function applicationshell_elementRoot_binding(value) {
        elementRoot = value;
        $$invalidate(0, elementRoot);
      }
      $$self.$$set = ($$props2) => {
        if ("elementRoot" in $$props2) $$invalidate(0, elementRoot = $$props2.elementRoot);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty[0] & /*$listView*/
        32) {
          game.settings.set(CONSTANTS.MODULE_NAME, "db-list-view", $listView);
        }
        if ($$self.$$.dirty[0] & /*$entriesStore, $allRanges*/
        134217744) {
          {
            const specificRanges = $allRanges ? Sequencer.Database.publicFlattenedEntriesAdvanced : Sequencer.Database.publicFlattenedSimpleEntries;
            $$invalidate(24, entries = specificRanges.map((entry) => {
              if (typeof entry === "string") {
                return { pack: entry.split(".")[0], entry };
              } else {
                return {
                  pack: entry.path.split(".")[0],
                  entry: entry.path,
                  isAudio: entry.isAudio
                };
              }
            }));
          }
        }
        if ($$self.$$.dirty[0] & /*$allRanges*/
        16) {
          {
            if (!$allRanges) set_store_value(fileTypes, $fileTypes = "all", $fileTypes);
          }
        }
        if ($$self.$$.dirty[0] & /*$cleanSearchStore, entries, $searchRegex, $selectedPackStore, $search, $fileTypes*/
        117440526) {
          {
            const searchParts = $cleanSearchStore.split("|");
            $$invalidate(7, filteredEntries = entries.filter((part) => {
              const matchParts = make_array_unique(part.entry.match($searchRegex) || []);
              return ($selectedPackStore === "all" || $selectedPackStore === part.pack) && ($search === "" || matchParts.length >= searchParts.length) && ($fileTypes === "all" || $fileTypes === "video" && !part.isAudio || $fileTypes === "sound" && part.isAudio);
            }));
          }
        }
      };
      return [
        elementRoot,
        $fileTypes,
        $search,
        $selectedPackStore,
        $allRanges,
        $listView,
        databaseStore,
        filteredEntries,
        $packStore,
        $subLists,
        $visibleTreeStore,
        $metadata,
        selectedPackStore2,
        packStore2,
        fileTypes,
        metadata,
        allRanges,
        subLists,
        listView,
        visibleTreeStore2,
        search,
        cleanSearchStore2,
        searchRegex,
        entriesStore2,
        entries,
        $searchRegex,
        $cleanSearchStore,
        $entriesStore,
        select0_change_handler,
        select1_change_handler,
        input0_input_handler,
        input1_change_handler,
        input2_change_handler,
        input3_change_handler,
        video_binding,
        mouseenter_handler,
        mouseleave_handler,
        img_binding,
        audio_binding,
        applicationshell_elementRoot_binding
      ];
    }
    class Database_shell extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$f, create_fragment$g, safe_not_equal, { elementRoot: 0 }, null, [-1, -1]);
      }
      get elementRoot() {
        return this.$$.ctx[0];
      }
      set elementRoot(elementRoot) {
        this.$$set({ elementRoot });
        flush();
      }
    }
    class DatabaseViewerApp extends SvelteApp {
      static get defaultOptions() {
        return foundry.utils.mergeObject(super.defaultOptions, {
          title: game.i18n.localize("SEQUENCER.Database.Title"),
          classes: ["dialog"],
          width: 900,
          height: 425,
          svelte: {
            class: Database_shell,
            target: document.body
          }
        });
      }
      static getActiveApp() {
        return Object.values(ui.windows).find((app) => {
          return app instanceof this && app._state > Application.RENDER_STATES.CLOSED;
        });
      }
      static async show(options = {}) {
        const existingApp = this.getActiveApp();
        if (existingApp) return existingApp.render(false, { focus: true });
        return new Promise((resolve) => {
          options.resolve = resolve;
          new this(options).render(true, { focus: true });
        });
      }
    }
    function create_if_block$4(ctx) {
      let p;
      let raw0_value = localize("SEQUENCER.HowTo.PermissionsExplanation") + "";
      let t0;
      let button;
      let i;
      let t1;
      let html_tag;
      let raw1_value = localize("SEQUENCER.HowTo.OpenModuleSettings") + "";
      let mounted;
      let dispose;
      return {
        c() {
          p = element("p");
          t0 = space();
          button = element("button");
          i = element("i");
          t1 = space();
          html_tag = new HtmlTag(false);
          attr(i, "class", "fas fa-plug");
          html_tag.a = null;
          attr(button, "type", "button");
          attr(button, "class", "w-100 open-module-settings");
        },
        m(target, anchor) {
          insert(target, p, anchor);
          p.innerHTML = raw0_value;
          insert(target, t0, anchor);
          insert(target, button, anchor);
          append(button, i);
          append(button, t1);
          html_tag.m(raw1_value, button);
          if (!mounted) {
            dispose = listen(
              button,
              "click",
              /*openSettings*/
              ctx[0]
            );
            mounted = true;
          }
        },
        p: noop,
        d(detaching) {
          if (detaching) {
            detach(p);
            detach(t0);
            detach(button);
          }
          mounted = false;
          dispose();
        }
      };
    }
    function create_fragment$f(ctx) {
      let div;
      let p0;
      let raw0_value = localize("SEQUENCER.HowTo.Welcome") + "";
      let t0;
      let p1;
      let raw1_value = localize("SEQUENCER.HowTo.Explanation") + "";
      let t1;
      let t2;
      let p2;
      let raw2_value = localize("SEQUENCER.HowTo.PlayerExplanation") + "";
      let t3;
      let p3;
      let raw3_value = localize("SEQUENCER.HowTo.LayerExplanation") + "";
      let t4;
      let ol;
      let li0;
      let strong0;
      let raw4_value = localize("SEQUENCER.HowTo.Click") + "";
      let br0;
      let t5;
      let html_tag;
      let raw5_value = localize("SEQUENCER.HowTo.ClickLabel") + "";
      let t6;
      let li1;
      let strong1;
      let raw6_value = localize("SEQUENCER.HowTo.ClickDrag") + "";
      let br1;
      let t7;
      let html_tag_1;
      let raw7_value = localize("SEQUENCER.HowTo.ClickDragLabel") + "";
      let t8;
      let li2;
      let strong2;
      let raw8_value = localize("SEQUENCER.HowTo.Shift") + "";
      let br2;
      let t9;
      let html_tag_2;
      let raw9_value = localize("SEQUENCER.HowTo.ShiftLabel") + "";
      let t10;
      let li3;
      let strong3;
      let raw10_value = localize("SEQUENCER.HowTo.ShiftControl") + "";
      let br3;
      let t11;
      let html_tag_3;
      let raw11_value = localize("SEQUENCER.HowTo.ShiftControlLabel") + "";
      let t12;
      let li4;
      let strong4;
      let raw12_value = localize("SEQUENCER.HowTo.MoreToCome") + "";
      let if_block = game.user.isGM && create_if_block$4(ctx);
      return {
        c() {
          div = element("div");
          p0 = element("p");
          t0 = space();
          p1 = element("p");
          t1 = space();
          if (if_block) if_block.c();
          t2 = space();
          p2 = element("p");
          t3 = space();
          p3 = element("p");
          t4 = space();
          ol = element("ol");
          li0 = element("li");
          strong0 = element("strong");
          br0 = element("br");
          t5 = space();
          html_tag = new HtmlTag(false);
          t6 = space();
          li1 = element("li");
          strong1 = element("strong");
          br1 = element("br");
          t7 = space();
          html_tag_1 = new HtmlTag(false);
          t8 = space();
          li2 = element("li");
          strong2 = element("strong");
          br2 = element("br");
          t9 = space();
          html_tag_2 = new HtmlTag(false);
          t10 = space();
          li3 = element("li");
          strong3 = element("strong");
          br3 = element("br");
          t11 = space();
          html_tag_3 = new HtmlTag(false);
          t12 = space();
          li4 = element("li");
          strong4 = element("strong");
          html_tag.a = null;
          attr(li0, "class", "svelte-seq-1gfsmnk");
          html_tag_1.a = null;
          attr(li1, "class", "svelte-seq-1gfsmnk");
          html_tag_2.a = null;
          attr(li2, "class", "svelte-seq-1gfsmnk");
          html_tag_3.a = null;
          attr(li3, "class", "svelte-seq-1gfsmnk");
          attr(li4, "class", "svelte-seq-1gfsmnk");
          attr(div, "class", "howto-container svelte-seq-1gfsmnk");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, p0);
          p0.innerHTML = raw0_value;
          append(div, t0);
          append(div, p1);
          p1.innerHTML = raw1_value;
          append(div, t1);
          if (if_block) if_block.m(div, null);
          append(div, t2);
          append(div, p2);
          p2.innerHTML = raw2_value;
          append(div, t3);
          append(div, p3);
          p3.innerHTML = raw3_value;
          append(div, t4);
          append(div, ol);
          append(ol, li0);
          append(li0, strong0);
          strong0.innerHTML = raw4_value;
          append(li0, br0);
          append(li0, t5);
          html_tag.m(raw5_value, li0);
          append(ol, t6);
          append(ol, li1);
          append(li1, strong1);
          strong1.innerHTML = raw6_value;
          append(li1, br1);
          append(li1, t7);
          html_tag_1.m(raw7_value, li1);
          append(ol, t8);
          append(ol, li2);
          append(li2, strong2);
          strong2.innerHTML = raw8_value;
          append(li2, br2);
          append(li2, t9);
          html_tag_2.m(raw9_value, li2);
          append(ol, t10);
          append(ol, li3);
          append(li3, strong3);
          strong3.innerHTML = raw10_value;
          append(li3, br3);
          append(li3, t11);
          html_tag_3.m(raw11_value, li3);
          append(ol, t12);
          append(ol, li4);
          append(li4, strong4);
          strong4.innerHTML = raw12_value;
        },
        p(ctx2, [dirty]) {
          if (game.user.isGM) if_block.p(ctx2, dirty);
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if (if_block) if_block.d();
        }
      };
    }
    function instance$e($$self) {
      async function openSettings() {
        const settings = new SettingsConfig();
        await settings.render(true);
        await wait$1(75);
        const focusElement = settings.element.find('select[name="sequencer.permissions-effect-create"]');
        settings.element.find("div.scrollable").scrollTop(focusElement.offset().top);
        await wait$1(250);
        focusElement.css("box-shadow", "rgba(200, 64, 67, 0.75) inset 0 0 10px");
        await wait$1(5e3);
        focusElement.css("box-shadow", "none");
      }
      return [openSettings];
    }
    class HowTo extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$e, create_fragment$f, safe_not_equal, {});
      }
    }
    function get_each_context$4(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[6] = list[i];
      child_ctx[8] = i;
      return child_ctx;
    }
    function create_if_block_1$1(ctx) {
      let div;
      return {
        c() {
          div = element("div");
          set_style(div, "border-right", "1px solid rgba(0,0,0,0.5)");
          set_style(div, "margin", "0 10px");
        },
        m(target, anchor) {
          insert(target, div, anchor);
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
        }
      };
    }
    function create_if_block$3(ctx) {
      let i;
      let i_class_value;
      return {
        c() {
          i = element("i");
          attr(i, "class", i_class_value = "icon " + /*tab*/
          ctx[6].icon + " svelte-seq-123fyp");
        },
        m(target, anchor) {
          insert(target, i, anchor);
        },
        p(ctx2, dirty) {
          if (dirty & /*tabs*/
          2 && i_class_value !== (i_class_value = "icon " + /*tab*/
          ctx2[6].icon + " svelte-seq-123fyp")) {
            attr(i, "class", i_class_value);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(i);
          }
        }
      };
    }
    function create_each_block$4(key_1, ctx) {
      let first;
      let t0;
      let div;
      let t1;
      let t2_value = localize(
        /*tab*/
        ctx[6].label
      ) + "";
      let t2;
      let t3;
      let mounted;
      let dispose;
      let if_block0 = (
        /*separateElements*/
        ctx[3] && /*index*/
        ctx[8] > 0 && create_if_block_1$1()
      );
      let if_block1 = (
        /*tab*/
        ctx[6].icon && create_if_block$3(ctx)
      );
      function click_handler() {
        return (
          /*click_handler*/
          ctx[5](
            /*tab*/
            ctx[6]
          )
        );
      }
      return {
        key: key_1,
        first: null,
        c() {
          first = empty();
          if (if_block0) if_block0.c();
          t0 = space();
          div = element("div");
          if (if_block1) if_block1.c();
          t1 = space();
          t2 = text$1(t2_value);
          t3 = space();
          attr(div, "class", "item item-piles-flexrow item-piles-clickable-link svelte-seq-123fyp");
          attr(div, "data-tab", "rest");
          toggle_class(
            div,
            "underscore",
            /*underscore*/
            ctx[2]
          );
          toggle_class(
            div,
            "active",
            /*activeTab*/
            ctx[0] === /*tab*/
            ctx[6].value
          );
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          if (if_block0) if_block0.m(target, anchor);
          insert(target, t0, anchor);
          insert(target, div, anchor);
          if (if_block1) if_block1.m(div, null);
          append(div, t1);
          append(div, t2);
          append(div, t3);
          if (!mounted) {
            dispose = listen(div, "click", click_handler);
            mounted = true;
          }
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          if (
            /*separateElements*/
            ctx[3] && /*index*/
            ctx[8] > 0
          ) {
            if (if_block0) ;
            else {
              if_block0 = create_if_block_1$1();
              if_block0.c();
              if_block0.m(t0.parentNode, t0);
            }
          } else if (if_block0) {
            if_block0.d(1);
            if_block0 = null;
          }
          if (
            /*tab*/
            ctx[6].icon
          ) {
            if (if_block1) {
              if_block1.p(ctx, dirty);
            } else {
              if_block1 = create_if_block$3(ctx);
              if_block1.c();
              if_block1.m(div, t1);
            }
          } else if (if_block1) {
            if_block1.d(1);
            if_block1 = null;
          }
          if (dirty & /*tabs*/
          2 && t2_value !== (t2_value = localize(
            /*tab*/
            ctx[6].label
          ) + "")) set_data(t2, t2_value);
          if (dirty & /*underscore*/
          4) {
            toggle_class(
              div,
              "underscore",
              /*underscore*/
              ctx[2]
            );
          }
          if (dirty & /*activeTab, tabs*/
          3) {
            toggle_class(
              div,
              "active",
              /*activeTab*/
              ctx[0] === /*tab*/
              ctx[6].value
            );
          }
        },
        d(detaching) {
          if (detaching) {
            detach(first);
            detach(t0);
            detach(div);
          }
          if (if_block0) if_block0.d(detaching);
          if (if_block1) if_block1.d();
          mounted = false;
          dispose();
        }
      };
    }
    function create_fragment$e(ctx) {
      let nav;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let nav_style_value;
      let each_value = ensure_array_like(
        /*tabs*/
        ctx[1].filter(func)
      );
      const get_key = (ctx2) => (
        /*tab*/
        ctx2[6].value
      );
      for (let i = 0; i < each_value.length; i += 1) {
        let child_ctx = get_each_context$4(ctx, each_value, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block$4(key, child_ctx));
      }
      return {
        c() {
          nav = element("nav");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          attr(nav, "class", "tabs svelte-seq-123fyp");
          attr(nav, "data-group", "primary");
          attr(nav, "style", nav_style_value = /*$$props*/
          ctx[4].style);
        },
        m(target, anchor) {
          insert(target, nav, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(nav, null);
            }
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*underscore, activeTab, tabs, separateElements*/
          15) {
            each_value = ensure_array_like(
              /*tabs*/
              ctx2[1].filter(func)
            );
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, nav, destroy_block, create_each_block$4, null, get_each_context$4);
          }
          if (dirty & /*$$props*/
          16 && nav_style_value !== (nav_style_value = /*$$props*/
          ctx2[4].style)) {
            attr(nav, "style", nav_style_value);
          }
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(nav);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
        }
      };
    }
    const func = (tab) => !tab.hidden;
    function instance$d($$self, $$props, $$invalidate) {
      let { activeTab } = $$props;
      let { tabs } = $$props;
      let { underscore = false } = $$props;
      let { separateElements = false } = $$props;
      const click_handler = (tab) => {
        $$invalidate(0, activeTab = tab.value);
      };
      $$self.$$set = ($$new_props) => {
        $$invalidate(4, $$props = assign(assign({}, $$props), exclude_internal_props($$new_props)));
        if ("activeTab" in $$new_props) $$invalidate(0, activeTab = $$new_props.activeTab);
        if ("tabs" in $$new_props) $$invalidate(1, tabs = $$new_props.tabs);
        if ("underscore" in $$new_props) $$invalidate(2, underscore = $$new_props.underscore);
        if ("separateElements" in $$new_props) $$invalidate(3, separateElements = $$new_props.separateElements);
      };
      $$props = exclude_internal_props($$props);
      return [activeTab, tabs, underscore, separateElements, $$props, click_handler];
    }
    class Tabs extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$d, create_fragment$e, safe_not_equal, {
          activeTab: 0,
          tabs: 1,
          underscore: 2,
          separateElements: 3
        });
      }
    }
    const SequenceManager = {
      VisibleEffects: writable({}),
      RunningSounds: writable({}),
      RunningSequences: writable({})
    };
    SequenceManager.VisibleEffects.get = (id) => {
      return get_store_value(SequenceManager.VisibleEffects)[id];
    };
    SequenceManager.VisibleEffects.add = (id, data) => {
      SequenceManager.VisibleEffects.update((effects) => {
        effects[id] = data;
        return effects;
      });
    };
    SequenceManager.VisibleEffects.delete = (id) => {
      SequenceManager.VisibleEffects.update((effects) => {
        delete effects[id];
        return effects;
      });
    };
    SequenceManager.VisibleEffects.values = () => {
      return Object.values(get_store_value(SequenceManager.VisibleEffects));
    };
    SequenceManager.RunningSounds.get = (id) => {
      return get_store_value(SequenceManager.RunningSounds)[id];
    };
    SequenceManager.RunningSounds.add = (id, data) => {
      SequenceManager.RunningSounds.update((sounds) => {
        sounds[id] = data;
        return sounds;
      });
    };
    SequenceManager.RunningSounds.delete = (id) => {
      SequenceManager.RunningSounds.update((sounds) => {
        delete sounds[id];
        return sounds;
      });
    };
    SequenceManager.RunningSounds.values = () => {
      return Object.values(get_store_value(SequenceManager.RunningSounds));
    };
    SequenceManager.RunningSounds.keys = () => {
      return Object.keys(get_store_value(SequenceManager.RunningSounds));
    };
    SequenceManager.RunningSequences.get = (id) => {
      return get_store_value(SequenceManager.RunningSequences)[id];
    };
    SequenceManager.RunningSequences.add = (id, sequence) => {
      SequenceManager.RunningSequences.update((sequences) => {
        sequences[id] = sequence;
        return sequences;
      });
    };
    SequenceManager.RunningSequences.delete = (id) => {
      SequenceManager.RunningSequences.update((sequences) => {
        delete sequences[id];
        return sequences;
      });
    };
    SequenceManager.RunningSequences.clearFinishedSequences = () => {
      SequenceManager.RunningSequences.update((sequences) => {
        for (const sequence of Object.values(sequences)) {
          if (sequence.status === CONSTANTS.STATUS.COMPLETE || sequence.status === CONSTANTS.STATUS.ABORTED) {
            delete sequences[sequence.id];
          }
        }
        return sequences;
      });
    };
    SequenceManager.RunningSequences.stopAll = () => {
      SequenceManager.RunningSequences.update((sequences) => {
        for (const sequence of Object.values(sequences)) {
          sequence._abort();
        }
        return sequences;
      });
    };
    SequenceManager.RunningSequences.values = () => {
      return Object.values(get_store_value(SequenceManager.RunningSequences));
    };
    class ColorMatrixFilter extends globalThis.PIXI.ColorMatrixFilter {
      /**
       * Properties & default values:
       *     - hue [false]
       *     - brightness [1]
       *     - contrast [1]
       *     - saturate [1]
       */
      constructor(inData) {
        super();
        this.isValid = true;
        this.values = /* @__PURE__ */ new Map();
        for (let [key, value] of Object.entries(inData)) {
          this.setValue(key, value);
          if (!this.isValid) break;
        }
      }
      setValue(key, value) {
        try {
          this.values[key] = value;
          super[key](value, true);
        } catch (err) {
          ui.notifications.warn(
            `Sequencer | ${this.constructor.name} | Could not set property ${key}`
          );
        }
      }
      get hue() {
        return this.values?.hue ?? 0;
      }
      set hue(value) {
        this.values.hue = value;
        super.hue(value);
        this.setOthers("hue");
      }
      get contrast() {
        return this.values?.contrast ?? 0;
      }
      set contrast(value) {
        this.values.contrast = value;
        super.contrast(value);
      }
      get brightness() {
        return this.values?.brightness ?? 0;
      }
      set brightness(value) {
        this.values.brightness = value;
        super.brightness(value);
      }
      get saturate() {
        return this.values?.saturate ?? 0;
      }
      set saturate(value) {
        this.values.saturate = value;
        super.saturate(value);
      }
      setOthers(ignoreKey) {
        for (let [key, value] of this.values.entries) {
          if (key === ignoreKey) continue;
          this.setValue(key, value);
        }
      }
    }
    class BlurFilter extends globalThis.PIXI.BlurFilter {
      /**
       * Properties & default values:
       *     - strength [8]
       *     - blur [2]
       *     - blurX [2]
       *     - blurY [2]
       *     - quality [4]
       *     - resolution [PIXI.settings.FILTER_RESOLUTION]
       *     - kernelSize [5]
       */
      constructor(inData = {}) {
        inData = foundry.utils.mergeObject(
          {
            strength: 1,
            quality: 4,
            resolution: PIXI.settings.FILTER_RESOLUTION,
            kernelSize: 5
          },
          inData
        );
        super(...Object.values(inData));
        this.isValid = true;
        for (let [key, value] of Object.entries(inData)) {
          try {
            this[key] = value;
          } catch (err) {
            ui.notifications.warn(
              `Sequencer | ${this.constructor.name} | Could not set property ${key}`
            );
            this.isValid = false;
          }
        }
      }
    }
    class NoiseFilter extends globalThis.PIXI.NoiseFilter {
      /**
       * Properties & default values:
       *     - noise [0.5]
       *     - seed [Math.random()]
       */
      constructor(inData = {}) {
        super();
        inData = foundry.utils.mergeObject(
          {
            noise: 0.5,
            seed: Math.random()
          },
          inData
        );
        this.isValid = true;
        for (let [key, value] of Object.entries(inData)) {
          try {
            this[key] = value;
          } catch (err) {
            ui.notifications.warn(
              `Sequencer | ${this.constructor.name} | Could not set property ${key}`
            );
            this.isValid = false;
          }
        }
      }
    }
    class GlowFilter extends globalThis.PIXI.Filter {
      static defaults = {
        distance: 10,
        outerStrength: 4,
        innerStrength: 0,
        color: 16777215,
        quality: 0.1,
        knockout: false,
        alpha: 1
      };
      constructor(options) {
        const opts = Object.assign({}, GlowFilter.defaults, options);
        const {
          outerStrength,
          innerStrength,
          color,
          knockout,
          quality,
          alpha
        } = opts;
        const distance = Math.round(opts.distance);
        super(vertex, frag.replace(/__ANGLE_STEP_SIZE__/gi, `${(1 / quality / distance).toFixed(7)}`).replace(/__DIST__/gi, `${distance.toFixed(0)}.0`));
        this.uniforms.glowColor = new Float32Array([0, 0, 0, 1]);
        this.uniforms.alpha = 1;
        Object.assign(this, {
          color,
          outerStrength,
          innerStrength,
          padding: distance,
          knockout,
          alpha
        });
        this.isValid = true;
      }
      /**
       * The color of the glow.
       * @default 0xFFFFFF
       */
      get color() {
        return PIXI.utils.rgb2hex(this.uniforms.glowColor);
      }
      set color(value) {
        PIXI.utils.hex2rgb(value, this.uniforms.glowColor);
      }
      /**
       * The strength of the glow outward from the edge of the sprite.
       * @default 4
       */
      get outerStrength() {
        return this.uniforms.outerStrength;
      }
      set outerStrength(value) {
        this.uniforms.outerStrength = value;
      }
      /**
       * The strength of the glow inward from the edge of the sprite.
       * @default 0
       */
      get innerStrength() {
        return this.uniforms.innerStrength;
      }
      set innerStrength(value) {
        this.uniforms.innerStrength = value;
      }
      /**
       * Only draw the glow, not the texture itself
       * @default false
       */
      get knockout() {
        return this.uniforms.knockout;
      }
      set knockout(value) {
        this.uniforms.knockout = value;
      }
      /**
       * The alpha value of the glow
       * @default 1
       */
      get alpha() {
        return this.uniforms.alpha;
      }
      set alpha(value) {
        this.uniforms.alpha = value;
      }
    }
    const frag = `varying vec2 vTextureCoord;
varying vec4 vColor;

uniform sampler2D uSampler;

uniform float outerStrength;
uniform float innerStrength;

uniform vec4 glowColor;

uniform vec4 filterArea;
uniform vec4 filterClamp;
uniform bool knockout;
uniform float alpha;

const float PI = 3.14159265358979323846264;

const float DIST = __DIST__;
const float ANGLE_STEP_SIZE = min(__ANGLE_STEP_SIZE__, PI * 2.0);
const float ANGLE_STEP_NUM = ceil(PI * 2.0 / ANGLE_STEP_SIZE);

const float MAX_TOTAL_ALPHA = ANGLE_STEP_NUM * DIST * (DIST + 1.0) / 2.0;

void main(void) {
    vec2 px = vec2(1.0 / filterArea.x, 1.0 / filterArea.y);

    float totalAlpha = 0.0;

    vec2 direction;
    vec2 displaced;
    vec4 curColor;

    for (float angle = 0.0; angle < PI * 2.0; angle += ANGLE_STEP_SIZE) {
       direction = vec2(cos(angle), sin(angle)) * px;

       for (float curDistance = 0.0; curDistance < DIST; curDistance++) {
           displaced = clamp(vTextureCoord + direction * 
                   (curDistance + 1.0), filterClamp.xy, filterClamp.zw);

           curColor = texture2D(uSampler, displaced);

           totalAlpha += (DIST - curDistance) * curColor.a;
       }
    }
    
    curColor = texture2D(uSampler, vTextureCoord);

    float alphaRatio = (totalAlpha / MAX_TOTAL_ALPHA);

    float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a;
    float innerGlowStrength = min(1.0, innerGlowAlpha);
    
    vec4 innerColor = mix(curColor, glowColor, innerGlowStrength);

    float outerGlowAlpha = alphaRatio * outerStrength * (1. - curColor.a);
    float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha);

    if (knockout) {
      float resultAlpha = (outerGlowAlpha + innerGlowAlpha) * alpha;
      gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);
    }
    else {
      vec4 outerGlowColor = outerGlowStrength * glowColor.rgba * alpha;
      gl_FragColor = innerColor + outerGlowColor;
    }
}`;
    const vertex = `attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;

uniform mat3 projectionMatrix;

varying vec2 vTextureCoord;

void main(void)
{
    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
    vTextureCoord = aTextureCoord;
}`;
    let shader = `
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
float alpha;

void main() {
    vec4 pixel = texture2D(uSampler, vTextureCoord);
    alpha = smoothstep(0.6,1.0,pixel.a);
    gl_FragColor = vec4(alpha, alpha, alpha, pixel.a);
}
`;
    class ClipFilter extends PIXI.Filter {
      constructor() {
        super(null, shader);
      }
    }
    const filters = {
      ColorMatrix: ColorMatrixFilter,
      Blur: BlurFilter,
      Noise: NoiseFilter,
      Glow: GlowFilter,
      Clip: ClipFilter
    };
    class MaskFilter extends FoundryShim.AbstractBaseFilter {
      /** @override */
      static fragmentShader = `        varying vec2 vTextureCoord;

        uniform sampler2D uSampler;
        uniform sampler2D uMaskSampler;

        void main(void) {
            gl_FragColor = texture2D(uSampler, vTextureCoord)
                * texture2D(uMaskSampler, vTextureCoord).a;
        }`;
      /** @override */
      static defaultUniforms = { uMaskSampler: null };
      /** @type {DisplayObject[]|null} */
      masks = [];
      /** @override */
      apply(filterManager, input, output, clearMode, currentState) {
        const maskFilterTexture = filterManager.getFilterTexture();
        const originalFilterTexture = this.#push(
          filterManager,
          currentState,
          maskFilterTexture
        );
        const renderer = filterManager.renderer;
        for (const mask of this.masks) {
          if (mask?.obj?.destroyed) continue;
          const renderable = mask.renderable;
          mask.renderable = true;
          mask.render(renderer);
          mask.renderable = renderable;
        }
        renderer.batch.flush();
        this.#pop(filterManager, currentState, originalFilterTexture);
        this.uniforms.uMaskSampler = maskFilterTexture;
        filterManager.applyFilter(this, input, output, clearMode);
        filterManager.returnFilterTexture(maskFilterTexture);
      }
      #push(filterManager, currentState, maskFilterTexture) {
        const originalFilterTexture = currentState.renderTexture;
        currentState.renderTexture = maskFilterTexture;
        filterManager.defaultFilterStack.push(currentState);
        filterManager.bindAndClear(maskFilterTexture);
        return originalFilterTexture;
      }
      #pop(filterManager, currentState, originalFilterTexture) {
        currentState.renderTexture = originalFilterTexture;
        filterManager.defaultFilterStack.pop();
        if (filterManager.activeState === currentState) {
          return;
        }
        filterManager.activeState = currentState;
        const globalUniforms = filterManager.globalUniforms.uniforms;
        globalUniforms.outputFrame = currentState.sourceFrame;
        globalUniforms.resolution = currentState.resolution;
        const inputSize = globalUniforms.inputSize;
        const inputPixel = globalUniforms.inputPixel;
        const inputClamp = globalUniforms.inputClamp;
        inputSize[0] = currentState.destinationFrame.width;
        inputSize[1] = currentState.destinationFrame.height;
        inputSize[2] = 1 / inputSize[0];
        inputSize[3] = 1 / inputSize[1];
        inputPixel[0] = Math.round(inputSize[0] * currentState.resolution);
        inputPixel[1] = Math.round(inputSize[1] * currentState.resolution);
        inputPixel[2] = 1 / inputPixel[0];
        inputPixel[3] = 1 / inputPixel[1];
        inputClamp[0] = 0.5 * inputPixel[2];
        inputClamp[1] = 0.5 * inputPixel[3];
        inputClamp[2] = currentState.sourceFrame.width * inputSize[2] - 0.5 * inputPixel[2];
        inputClamp[3] = currentState.sourceFrame.height * inputSize[3] - 0.5 * inputPixel[3];
        if (currentState.legacy) {
          const filterArea = globalUniforms.filterArea;
          filterArea[0] = currentState.destinationFrame.width;
          filterArea[1] = currentState.destinationFrame.height;
          filterArea[2] = currentState.sourceFrame.x;
          filterArea[3] = currentState.sourceFrame.y;
          globalUniforms.filterClamp = globalUniforms.inputClamp;
        }
        filterManager.globalUniforms.update();
      }
    }
    const SequencerAnimationEngine = {
      _animations: [],
      _debug: void 0,
      _deltas: [],
      ticker: false,
      dt: 0,
      isRunning: false,
      addAnimation(origin, attributes = [], timeDifference = 0) {
        if (!Array.isArray(attributes)) attributes = [attributes];
        return new Promise((resolve) => {
          this._animations.push({
            origin,
            attributes: attributes.map((attribute) => {
              attribute.targetId = get_object_identifier(attribute.target) + "-" + attribute.propertyName;
              attribute.id = foundry.utils.randomID();
              attribute.started = false;
              attribute.initialized = false;
              attribute.finishing = false;
              attribute.complete = false;
              attribute.previousValue = null;
              attribute.progress = 0;
              attribute.value = 0;
              attribute.coreValue = 0;
              attribute.isFunkyProperty = attribute.propertyName.startsWith("scale.");
              attribute.duration = attribute.duration ?? 0;
              attribute.durationDone = timeDifference ?? 0;
              if (attribute?.looping) {
                attribute.loopDuration = attribute.loopDuration ?? attribute.duration ?? 0;
                attribute.loopDurationDone = timeDifference % attribute.loopDuration;
                attribute.loops = attribute.loops ?? 0;
                attribute.loopsDone = Math.floor(
                  attribute.durationDone / attribute.duration
                );
                attribute.index = attribute.loopsDone % attribute.values.length;
                attribute.nextIndex = (attribute.loopsDone + 1) % attribute.values.length;
                if (!attribute.pingPong && attribute.nextIndex === 0) {
                  attribute.index = 0;
                  attribute.nextIndex = 1;
                }
              }
              return attribute;
            }),
            complete: false,
            totalDt: timeDifference,
            resolve
          });
          this._animations.sort((a, b) => {
            const aNumAbsolute = a.attributes.filter((attr2) => !attr2.complete && attr2.absolute).length;
            const bNumAbsolute = b.attributes.filter((attr2) => !attr2.complete && attr2.absolute).length;
            return bNumAbsolute - aNumAbsolute;
          });
          if (!this.ticker) {
            this.start();
          }
          debug(`Added animations to Animation Engine`);
        });
      },
      endAnimations(target) {
        this._animations = this._animations.filter(
          (animation2) => animation2.origin !== target
        );
      },
      updateStartValues(target, propertyName) {
        const targetId = get_object_identifier(target) + "-" + propertyName;
        if (targetId in this._coreValues) {
          this._coreValues[targetId].value = deep_get(target, propertyName);
        }
      },
      start() {
        if (!this.ticker) {
          debug(`Animation Engine Started`);
          this.ticker = FoundryShim.CanvasAnimation.ticker;
          this.ticker.add(this.nextFrame.bind(this));
        }
      },
      nextFrame() {
        if (this._animations.length === 0) {
          this._coreValues = {};
          return;
        }
        this._storedValues = {};
        this._animations.forEach((animation2) => this._animate(animation2));
        for (let delta of Object.values(this._storedValues)) {
          try {
            deep_set(delta.target, delta.propertyName, delta.value);
          } catch (err) {
          }
        }
        this._animations = this._animations.filter((animation2) => !animation2.complete);
      },
      _coreValues: {},
      _storedValues: {},
      _animate(animation2) {
        animation2.totalDt += this.ticker.elapsedMS;
        animation2.attributes.filter((attribute) => {
          return !attribute.complete && animation2.totalDt >= attribute.delay;
        }).forEach((attr2) => {
          this._animateAttribute(attr2);
          if (attr2.finishing) {
            attr2.complete = true;
            if (this._coreValues[attr2.targetId]) {
              delete this._coreValues[attr2.targetId];
            }
          }
        });
        animation2.complete = animation2.attributes.filter((attribute) => !attribute.complete).length === 0;
        if (animation2.complete) {
          animation2.resolve();
        }
      },
      _animateAttribute(attribute) {
        if (this._coreValues[attribute.targetId] === void 0) {
          this._coreValues[attribute.targetId] = {
            id: attribute.id,
            value: deep_get(attribute.target, attribute.propertyName)
          };
        }
        if (this._storedValues[attribute.targetId] === void 0) {
          this._storedValues[attribute.targetId] = {
            value: this._coreValues[attribute.targetId].value,
            target: attribute.target,
            propertyName: attribute.propertyName,
            targetId: attribute.targetId
          };
        }
        if (attribute?.looping && attribute?.indefinite) {
          this._handleIndefiniteLoop(attribute);
        } else if (attribute?.looping) {
          this._handleLoops(attribute);
        } else {
          this._handleDefault(attribute);
        }
        if (attribute.absolute) {
          this._coreValues[attribute.targetId].value = attribute.value;
          const delta = this._coreValues[attribute.targetId].value - this._storedValues[attribute.targetId].value;
          this._storedValues[attribute.targetId].value += delta;
        } else {
          if (attribute.isFunkyProperty) {
            const coreValue = this._coreValues[attribute.targetId].value;
            attribute.delta = coreValue * attribute.value - coreValue;
            this._storedValues[attribute.targetId].value += attribute.delta;
          } else {
            this._storedValues[attribute.targetId].value += attribute.value;
          }
        }
      },
      _handleBaseLoop(attribute) {
        if (!attribute.initialized) {
          if (attribute.values.length === 1) {
            attribute.values.unshift(this._coreValues[attribute.targetId].value);
          }
          attribute.initialized = true;
        }
        attribute.loopDurationDone += this.ticker.deltaMS;
        attribute.progress = attribute.loopDurationDone / attribute.loopDuration;
        attribute.value = interpolate(
          attribute.values[attribute.index],
          attribute.values[attribute.nextIndex],
          attribute.progress,
          attribute.ease
        );
        if (attribute.progress >= 1) {
          attribute.loopDurationDone -= attribute.loopDuration;
          attribute.index = (attribute.index + 1) % attribute.values.length;
          attribute.nextIndex = (attribute.nextIndex + 1) % attribute.values.length;
          if (!attribute.pingPong && attribute.nextIndex === 0) {
            attribute.index = 0;
            attribute.nextIndex = 1;
          }
          attribute.loopsDone++;
          attribute.value = interpolate(
            attribute.values[attribute.index],
            attribute.values[attribute.nextIndex],
            attribute.progress % 1,
            attribute.ease
          );
        }
      },
      _handleIndefiniteLoop(attribute) {
        return this._handleBaseLoop(attribute);
      },
      _handleLoops(attribute) {
        this._handleBaseLoop(attribute);
        attribute.durationDone += this.ticker.deltaMS;
        attribute.overallProgress = attribute.durationDone / attribute.duration;
        if (attribute.progress >= 1 && attribute.loopsDone === attribute.loops * 2) {
          attribute.finishing = true;
          attribute.value = attribute.values[attribute.index];
        }
        if (attribute.overallProgress >= 1) {
          attribute.finishing = true;
        }
      },
      _handleDefault(attribute) {
        if (!attribute.initialized) {
          if (attribute.from === void 0) {
            attribute.from = this._coreValues[attribute.targetId].value;
          }
          attribute.initialized = true;
        }
        attribute.durationDone += this.ticker.deltaMS;
        attribute.progress = attribute.durationDone / attribute.duration;
        attribute.value = interpolate(
          attribute.from,
          attribute.to,
          clamp$1(attribute.progress, 0, 1),
          attribute.ease
        );
        if (attribute.progress >= 1) {
          attribute.value = attribute.to;
          attribute.finishing = true;
        }
      }
    };
    const flagManager = {
      flagEffectAddBuffer: /* @__PURE__ */ new Map(),
      flagEffectRemoveBuffer: /* @__PURE__ */ new Map(),
      flagSoundAddBuffer: /* @__PURE__ */ new Map(),
      flagSoundRemoveBuffer: /* @__PURE__ */ new Map(),
      _latestFlagVersion: false,
      get latestFlagVersion() {
        if (!this._latestFlagVersion) {
          const versions = Object.keys(this.effectMigrations);
          versions.sort((a, b) => {
            return foundry.utils.isNewerVersion(a, b) ? -1 : 1;
          });
          this._latestFlagVersion = versions[0];
        }
        return this._latestFlagVersion;
      },
      /**
       * Sanitizes the effect data, accounting for changes to the structure in previous versions
       *
       * @param inDocument
       * @returns {array}
       */
      getEffectFlags(inDocument) {
        let effects = foundry.utils.getProperty(inDocument, CONSTANTS.EFFECTS_FLAG);
        if (!effects?.length) return [];
        effects = foundry.utils.deepClone(effects);
        const changes = [];
        for (let [effectId, effectData] of effects) {
          let effectVersion = effectData?.flagVersion ?? "1.0.0";
          let changesAdded = false;
          if (effectData._id !== effectId) {
            changesAdded = true;
            effectData._id = effectId;
            changes.push(effectData);
            debug(
              `Fixed effect with broken ID ${effectId}`
            );
          }
          if (effectData.flagVersion === this.latestFlagVersion) continue;
          for (let [version, migration] of Object.entries(this.effectMigrations)) {
            if (!foundry.utils.isNewerVersion(version, effectVersion)) continue;
            effectData = migration(inDocument, effectData);
          }
          debug(
            `Migrated effect with ID ${effectId} from version ${effectVersion} to version ${this.latestFlagVersion}`
          );
          effectData.flagVersion = this.latestFlagVersion;
          if (!changesAdded) changes.push(effectData);
        }
        if (changes.length) {
          flagManager.addEffectFlags(inDocument.uuid, changes);
        }
        return effects;
      },
      effectMigrations: {
        "2.0.0": (inDocument, effectData) => {
          effectData._id = effectData.id;
          effectData.creationTimestamp = effectData.timestamp;
          if (effectData.template) {
            effectData.template = {
              gridSize: effectData.template[0],
              startPoint: effectData.template[1],
              endPoint: effectData.template[2]
            };
          }
          if (effectData.attachTo) {
            effectData.attachTo = {
              active: true,
              align: "center",
              rotation: true,
              bindVisibility: true,
              bindAlpha: true
            };
            effectData.source = inDocument.uuid;
            const objectSize = get_object_dimensions(inDocument, true);
            effectData.offset = {
              x: effectData.position.x - objectSize.width,
              y: effectData.position.y - objectSize.height
            };
          } else if (effectData.position) {
            effectData.source = effectData.position;
          }
          if (effectData.reachTowards) {
            effectData.stretchTo = {
              attachTo: false,
              onlyX: false
            };
          }
          if (effectData.filters) {
            effectData.filters = Object.entries(effectData.filters).map((entry) => {
              return {
                className: entry[0],
                ...entry[1]
              };
            });
          }
          effectData.moveSpeed = effectData.speed;
          effectData.target = null;
          effectData.forcedIndex = null;
          effectData.flipX = false;
          effectData.flipY = false;
          effectData.nameOffsetMap = {};
          effectData.sequenceId = 0;
          delete effectData.id;
          delete effectData.timestamp;
          delete effectData.position;
          delete effectData.reachTowards;
          delete effectData.speed;
          delete effectData.audioVolume;
          delete effectData.gridSizeDifference;
          delete effectData.template;
          if (effectData.animatedProperties) {
            delete effectData.animatedProperties.fadeInAudio;
            delete effectData.animatedProperties.fadeOutAudio;
          }
          effectData = foundry.utils.mergeObject(
            effectData,
            effectData.animatedProperties
          );
          delete effectData.animatedProperties;
          return effectData;
        },
        "2.0.6": (inDocument, effectData) => {
          effectData.private = null;
          return effectData;
        },
        "2.0.8": (inDocument, effectData) => {
          if (effectData.stretchTo) {
            effectData.stretchTo.tiling = false;
          }
          return effectData;
        },
        "2.0.9": (inDocument, effectData) => {
          effectData.tilingTexture = false;
          if (effectData.stretchTo?.tiling !== void 0) {
            if (effectData.stretchTo.tiling) {
              effectData.tilingTexture = {
                scale: { x: 1, y: 1 },
                position: { x: 0, y: 0 }
              };
            }
            delete effectData.stretchTo.tiling;
          }
          return effectData;
        },
        "2.1.0": (inDocument, effectData) => {
          if (effectData.randomOffset) {
            effectData.randomOffset = {
              source: !effectData.target ? effectData.randomOffset : false,
              target: !!effectData.target ? effectData.randomOffset : false
            };
          }
          if (effectData.nameOffsetMap) {
            Object.values(effectData.nameOffsetMap).forEach((offsetMap) => {
              if (offsetMap.randomOffset) {
                offsetMap.randomOffset = {
                  source: !offsetMap.target ? offsetMap.randomOffset : false,
                  target: !!offsetMap.target ? offsetMap.randomOffset : false
                };
              }
            });
          }
          return effectData;
        },
        "3.2.0": (inDocument, effectData) => {
          if (effectData.attachTo?.followRotation !== void 0) {
            effectData.attachTo.bindRotation = effectData.attachTo.followRotation;
            delete effectData.attachTo.followRotation;
          }
          if (effectData.scaleToObject) {
            if (effectData.attachTo?.active) {
              effectData.attachTo.bindScale = true;
            } else if (!effectData.attachTo?.active && !effectData.attachTo?.bindScale) {
              effectData.scaleToObject = false;
              effectData.size = get_object_dimensions(inDocument);
            }
          }
          return effectData;
        },
        "3.2.1": (inDocument, effectData) => {
          if (effectData.noLoop !== void 0) {
            effectData.loopOptions = {
              loops: 1,
              loopDelay: 0,
              endOnLastLoop: false
            };
            delete effectData.noLoop;
          }
          return effectData;
        }
      },
      /**
       * Adds effects to a given document
       *
       * @param inObjectUUID
       * @param inEffects
       */
      addEffectFlags: (inObjectUUID, inEffects) => {
        if (!Array.isArray(inEffects)) inEffects = [inEffects];
        sequencerSocket.executeAsGM(
          SOCKET_HANDLERS.ADD_EFFECT_FLAGS,
          inObjectUUID,
          inEffects
        );
      },
      /**
       * Removes effects from a given document
       *
       * @param inObjectUUID
       * @param inEffects
       * @param removeAll
       */
      removeEffectFlags: (inObjectUUID, inEffects, removeAll = false) => {
        sequencerSocket.executeAsGM(
          SOCKET_HANDLERS.REMOVE_EFFECT_FLAGS,
          inObjectUUID,
          inEffects,
          removeAll
        );
      },
      _addEffectFlags: (inObjectUUID, inEffects) => {
        if (!Array.isArray(inEffects)) inEffects = [inEffects];
        let flagsToSet = flagManager.flagEffectAddBuffer.get(inObjectUUID) ?? {
          effects: []
        };
        flagsToSet.effects.push(...inEffects);
        flagManager.flagEffectAddBuffer.set(inObjectUUID, flagsToSet);
        flagManager.updateEffectFlags();
      },
      _removeEffectFlags: (inObjectUUID, inEffects, removeAll = false) => {
        if (inEffects && !Array.isArray(inEffects)) inEffects = [inEffects];
        let flagsToSet = flagManager.flagEffectRemoveBuffer.get(inObjectUUID) ?? {
          effects: [],
          removeAll
        };
        if (inEffects) flagsToSet.effects.push(...inEffects);
        flagManager.flagEffectRemoveBuffer.set(inObjectUUID, flagsToSet);
        flagManager.updateEffectFlags();
      },
      updateEffectFlags: foundry.utils.debounce(async () => {
        let flagsToAdd = Array.from(flagManager.flagEffectAddBuffer);
        let flagsToRemove = Array.from(flagManager.flagEffectRemoveBuffer);
        flagManager.flagEffectAddBuffer.clear();
        flagManager.flagEffectRemoveBuffer.clear();
        flagsToAdd.forEach((entry) => entry[1].original = true);
        flagsToRemove.forEach((entry) => entry[1].original = true);
        const objects = /* @__PURE__ */ new Set([
          ...flagsToAdd.map((effect) => effect[0]).filter(Boolean),
          ...flagsToRemove.map((effect) => effect[0]).filter(Boolean)
        ]);
        flagsToAdd = new Map(flagsToAdd);
        flagsToRemove = new Map(flagsToRemove);
        const actorUpdates = {};
        const sceneObjectsToUpdate = {};
        for (let objectUUID of objects) {
          let object = fromUuidSync(objectUUID);
          if (!object) {
            debug(
              `Failed to set flags on non-existent object with UUID: ${objectUUID}`
            );
            continue;
          }
          const isLinkedToken = object instanceof TokenDocument && object.actorLink;
          const isLinkedActor = object instanceof Actor && object.prototypeToken.actorLink;
          let toAdd = flagsToAdd.get(objectUUID) ?? { effects: [] };
          let toRemove = flagsToRemove.get(objectUUID) ?? {
            effects: [],
            removeAll: false
          };
          let origExistingFlags = foundry.utils.getProperty(object, CONSTANTS.EFFECTS_FLAG) ?? [];
          if (isLinkedToken) {
            origExistingFlags = origExistingFlags.concat(foundry.utils.getProperty(object.actor, CONSTANTS.EFFECTS_FLAG) ?? []);
          }
          const existingFlags = new Map(origExistingFlags);
          if (toRemove?.removeAll) {
            toRemove.effects = Array.from(existingFlags).map((entry) => entry[0]);
          }
          for (let effect of toAdd.effects) {
            if (typeof effect === "string") {
              effect = existingFlags.get(effect);
              if (!effect) continue;
            }
            existingFlags.set(effect._id, effect);
          }
          for (let effect of toRemove.effects) {
            if (typeof effect === "string") {
              effect = existingFlags.get(effect);
              if (!effect) continue;
            }
            existingFlags.delete(effect._id);
          }
          let flagsToSet = Array.from(existingFlags);
          const options = {};
          if ((isLinkedToken || isLinkedActor) && (toAdd.original || toRemove.original)) {
            const actor = object?.actor ?? object;
            actorUpdates[actor.id] = flagsToSet.filter(
              (effect) => is_UUID(effect[1]?.source) && effect[1]?.attachTo?.active && effect[1]?.persistOptions?.persistTokenPrototype
            );
            flagsToSet = flagsToSet.filter(
              (effect) => !effect[1]?.persistOptions?.persistTokenPrototype || !is_UUID(effect[1]?.source) || !effect[1]?.attachTo?.active
            );
            if (isLinkedToken && game.modules.get("multilevel-tokens")?.active && foundry.utils.getProperty(object, "flags.multilevel-tokens.stoken")) {
              options["mlt_bypass"] = true;
            }
          }
          if (object?.documentName === "Scene") {
            const sceneId = object.id;
            sceneObjectsToUpdate[sceneId] = sceneObjectsToUpdate[sceneId] ?? {
              updates: {},
              documents: {}
            };
            sceneObjectsToUpdate[sceneId].updates[CONSTANTS.EFFECTS_FLAG] = flagsToSet;
          } else if (!(object instanceof Actor) && origExistingFlags.length !== flagsToSet.length) {
            const sceneId = object.parent.id;
            const docName = object.documentName;
            sceneObjectsToUpdate[sceneId] = sceneObjectsToUpdate[sceneId] ?? {
              updates: {},
              documents: {}
            };
            sceneObjectsToUpdate[sceneId].documents[docName] = sceneObjectsToUpdate[sceneId].documents[docName] ?? {
              options: {},
              updates: []
            };
            sceneObjectsToUpdate[sceneId].documents[docName].options = options;
            sceneObjectsToUpdate[sceneId].documents[docName].updates.push({
              _id: object.id,
              [CONSTANTS.EFFECTS_FLAG]: flagsToSet
            });
          }
        }
        for (const [sceneId, sceneData] of Object.entries(sceneObjectsToUpdate)) {
          const scene = game.scenes.get(sceneId);
          if (!foundry.utils.isEmpty(sceneData.updates)) {
            await scene.update(sceneData.updates);
          }
          for (const [documentType, documentData] of Object.entries(
            sceneData.documents
          )) {
            await scene.updateEmbeddedDocuments(
              documentType,
              documentData.updates,
              documentData.options
            );
            debug(
              `Flags set for documents of type "${documentType}" in scene with ID "${sceneId}"`
            );
          }
        }
        await Actor.updateDocuments(
          Object.entries(actorUpdates).map(([actorId, effects]) => ({
            _id: actorId,
            [CONSTANTS.EFFECTS_FLAG]: effects
          }))
        );
      }, 250),
      /**
       * Sanitizes the effect data, accounting for changes to the structure in previous versions
       *
       * @param inDocument
       * @returns {array}
       */
      getSoundFlags(inDocument) {
        let sounds = foundry.utils.getProperty(inDocument, CONSTANTS.SOUNDS_FLAG);
        if (!sounds?.length) return [];
        sounds = foundry.utils.deepClone(sounds);
        const changes = [];
        for (let [soundId, soundData] of sounds) {
          let soundVersion = soundData?.flagVersion ?? "1.0.0";
          if (soundData.flagVersion === this.latestFlagVersion) continue;
          for (let [version, migration] of Object.entries(this.soundMigrations)) {
            if (!foundry.utils.isNewerVersion(version, soundVersion)) continue;
            soundData = migration(inDocument, soundData);
          }
          debug(
            `Migrated sound with ID ${soundId} from version ${soundVersion} to version ${this.latestFlagVersion}`
          );
          soundData.flagVersion = this.latestFlagVersion;
          changes.push(soundData);
        }
        if (changes.length) {
          flagManager.addSoundFlags(inDocument.uuid, changes);
        }
        return sounds;
      },
      soundMigrations: {},
      /**
       * Adds sounds to a given document
       *
       * @param inObjectUUID
       * @param inSounds
       */
      addSoundFlags: (inObjectUUID, inSounds) => {
        if (!Array.isArray(inSounds)) inSounds = [inSounds];
        sequencerSocket.executeAsGM(
          SOCKET_HANDLERS.ADD_EFFECT_FLAGS,
          inObjectUUID,
          inSounds
        );
      },
      /**
       * Removes sounds from a given document
       *
       * @param inObjectUUID
       * @param inSounds
       * @param removeAll
       */
      removeSoundFlags: (inObjectUUID, inSounds, removeAll = false) => {
        sequencerSocket.executeAsGM(
          SOCKET_HANDLERS.REMOVE_EFFECT_FLAGS,
          inObjectUUID,
          inSounds,
          removeAll
        );
      },
      _addSoundFlags: (sceneID, inSounds) => {
        if (!Array.isArray(inSounds)) inSounds = [inSounds];
        let flagsToSet = flagManager.flagAddBuffer.get(sceneID) ?? {
          effects: []
        };
        flagsToSet.effects.push(...inSounds);
        flagManager.flagSoundAddBuffer.set(sceneID, flagsToSet);
        flagManager.updateSoundFlags();
      },
      _removeSoundFlags: (sceneID, inSounds, removeAll = false) => {
        if (inSounds && !Array.isArray(inSounds)) inSounds = [inSounds];
        let flagsToSet = flagManager.flagRemoveBuffer.get(sceneID) ?? {
          effects: [],
          removeAll
        };
        if (inSounds) flagsToSet.effects.push(...inSounds);
        flagManager.flagSoundRemoveBuffer.set(sceneID, flagsToSet);
        flagManager.updateSoundFlags();
      },
      updateFlags: foundry.utils.debounce(async () => {
        let soundFlagsToAdd = Array.from(flagManager.flagSoundAddBuffer);
        let soundFlagsToRemove = Array.from(flagManager.flagSoundRemoveBuffer);
        flagManager.flagSoundAddBuffer.clear();
        flagManager.flagSoundRemoveBuffer.clear();
        soundFlagsToAdd.forEach((entry) => entry[1].original = true);
        soundFlagsToRemove.forEach((entry) => entry[1].original = true);
        const scenes = /* @__PURE__ */ new Set([
          ...soundFlagsToAdd.map((sound) => sound[0]).filter(Boolean),
          ...soundFlagsToRemove.map((sound) => sound[0]).filter(Boolean)
        ]);
        soundFlagsToAdd = new Map(soundFlagsToAdd);
        soundFlagsToRemove = new Map(soundFlagsToRemove);
        const scenesToUpdate = {};
        for (let sceneId of scenes) {
          let scene = game.scenes.get(sceneId);
          if (!scene) {
            debug(
              `Failed to set flags on non-existent scene with ID: ${sceneId}`
            );
            continue;
          }
          let soundsToAdd = soundFlagsToAdd.get(sceneId) ?? { sounds: [] };
          let soundsToRemove = soundFlagsToRemove.get(sceneId) ?? {
            sounds: [],
            removeAll: false
          };
          const existingFlags = new Map(
            foundry.utils.getProperty(scene, CONSTANTS.SOUNDS_FLAG) ?? []
          );
          if (soundsToRemove?.removeAll) {
            soundsToRemove.sounds = Array.from(existingFlags).map((entry) => entry[0]);
          }
          for (let sound of soundsToAdd.sounds) {
            if (typeof sound === "string") {
              sound = existingFlags.get(sound);
              if (!sound) continue;
            }
            existingFlags.set(sound.sound_id, sound);
          }
          for (let sound of soundsToRemove.sounds) {
            if (typeof sound === "string") {
              sound = existingFlags.get(sound);
              if (!sound) continue;
            }
            existingFlags.delete(sound.sound_id);
          }
          let flagsToSet = Array.from(existingFlags);
          scenesToUpdate[sceneId] = scenesToUpdate[sceneId] ?? {
            updates: {},
            documents: {}
          };
          scenesToUpdate[sceneId].updates[CONSTANTS.EFFECTS_FLAG] = flagsToSet;
        }
        for (const [sceneId, sceneData] of Object.entries(scenesToUpdate)) {
          const scene = game.scenes.get(sceneId);
          await scene.update(sceneData.updates);
        }
      }, 250)
    };
    class SequencerSoundManager {
      /**
       * Returns all the currently running sounds
       *
       * @returns {Array}
       */
      static get sounds() {
        return Array.from(SequenceManager.RunningSounds.values());
      }
      /**
       * Opens the Sequencer Manager with the sounds tab open
       */
      static show() {
        return EffectsUIApp.show({ tab: "manager" });
      }
      /**
       * Play an audio file.
       *
       * @param {Object} data The data that describes the audio to play.
       * @param {boolean} [push=false] A flag indicating whether to make other clients play the audio, too.
       * @returns {Number} A promise that resolves when the audio file has finished playing.
       */
      static async play(data, push = true) {
        if (push)
          sequencerSocket.executeForOthers(SOCKET_HANDLERS.PLAY_SOUND, data);
        return this._play(data);
      }
      /**
       * @param {Object} data
       * @returns {Number}
       * @private
       */
      static async _play(data) {
        if (data.delete) return false;
        Hooks.callAll("createSequencerSound", data);
        debug(`Playing sound:`, data);
        const playSound = game.settings.get("sequencer", "soundsEnabled") && game.user.viewedScene === data.sceneId && (!data?.users?.length || data?.users?.includes(game.userId));
        data.volume = playSound ? data.volume ?? 0.8 : 0;
        let sound;
        if (data.source) {
          let location2 = getPositionFromData(data);
          if (data.offset) {
            location2.x += (data.offset.source.x || 0) * (data.offset.gridUnits ? canvas.grid.size : 1);
            location2.y += (data.offset.source.y || 0) * (data.offset.gridUnits ? canvas.grid.size : 1);
          }
          if (data.randomOffset?.source) {
            const twister = createMersenneTwister(data.seed);
            location2 = get_random_offset(location2, data.randomOffset.source, twister);
          }
          sound = await canvas.sounds.playAtPosition(data.src, location2, data.locationOptions?.radius || 5, {
            gmAlways: false,
            walls: false,
            easing: true,
            muffledEffect: { type: "lowpass" },
            ...data.locationOptions,
            volume: data.volume,
            channel: data.channel || "interface"
          });
        } else {
          sound = await game.audio.play(data.src, {
            ...data.locationOptions,
            volume: data.fadeIn ? 0 : data.volume,
            loop: data.loop,
            offset: data.startTime,
            context: game.audio[data.channel || "interface"]
          });
        }
        if (!sound) return false;
        sound.sequencer_data = data;
        sound.sound_id = data.id;
        sound.sound_playing = playSound || game.user.isGM;
        SequenceManager.RunningSounds.add(data.id, sound);
        if (data.fadeIn && playSound) {
          SequencerAnimationEngine.addAnimation(data.id, {
            target: sound,
            propertyName: "volume",
            from: 0,
            to: data.volume,
            duration: Math.min(data.fadeIn.duration, data.duration),
            ease: data.fadeIn.ease,
            delay: Math.min(data.fadeIn.delay, data.duration),
            absolute: true
          });
        }
        if (data.fadeOut && playSound) {
          SequencerAnimationEngine.addAnimation(data.id, {
            target: sound,
            propertyName: "volume",
            from: data.volume,
            to: 0,
            duration: Math.min(data.fadeOut.duration, data.duration),
            ease: data.fadeOut.ease,
            delay: Math.max(
              data.duration - data.fadeOut.duration + data.fadeOut.delay,
              0
            ),
            absolute: true
          });
        }
        if (data.duration) {
          setTimeout(() => {
            sound.stop();
          }, data.duration);
        }
        new Promise((resolve) => {
          sound.addEventListener("stop", resolve);
          sound.addEventListener("end", resolve);
        }).then(() => {
          SequenceManager.RunningSounds.delete(data.id);
          Hooks.callAll("endedSequencerSound", data);
        });
        return data.duration;
      }
      static _validateFilters(inFilter) {
        if (inFilter?.sounds) {
          if (!Array.isArray(inFilter.sounds)) {
            inFilter.sounds = [inFilter.sounds];
          }
          inFilter.sounds = inFilter.sounds.map((sound) => {
            if (!(typeof sound === "string" || sound instanceof foundry?.audio?.Sound))
              throw custom_error(
                "Sequencer",
                "SoundManager | collections in inFilter.sounds must be of type string or Sound"
              );
            if (sound instanceof foundry?.audio?.Sound) return sound.sequencer_data.id;
            return sound;
          });
        }
        if (inFilter?.name && typeof inFilter?.name !== "string")
          throw custom_error(
            "Sequencer",
            "SoundManager | inFilter.name must be of type string"
          );
        if (inFilter?.sceneId) {
          if (typeof inFilter.sceneId !== "string")
            throw custom_error(
              "Sequencer",
              "SoundManager | inFilter.sceneId must be of type string"
            );
          if (!game.scenes.get(inFilter.sceneId))
            throw custom_error(
              "Sequencer",
              "SoundManager | inFilter.sceneId must be a valid scene id (could not find scene)"
            );
        } else {
          inFilter.sceneId = game.user.viewedScene;
        }
        if (inFilter?.origin && typeof inFilter?.origin !== "string")
          throw custom_error(
            "Sequencer",
            "SoundManager | inFilter.origin must be of type string"
          );
        if (!inFilter.sounds && !inFilter.name && !inFilter.sceneId && !inFilter.origin) {
          return false;
        }
        return foundry.utils.mergeObject(
          {
            sounds: null,
            name: null,
            sceneId: null,
            origin: null
          },
          inFilter
        );
      }
      static _filterSounds(inFilter) {
        if (inFilter.name) {
          inFilter.name = new RegExp(
            "^" + str_to_search_regex_str(safe_str(inFilter.name)) + "$",
            "gu"
          );
        }
        return this.sounds.filter((sound) => {
          return (inFilter.sounds === null || inFilter.sounds.includes(sound.sequencer_data.id)) && (inFilter.name === null || sound.sequencer_data.name && inFilter.name && sound.sequencer_data.name.match(inFilter.name)?.length) && (inFilter.sceneId === null || sound.sequencer_data.sceneId === inFilter.sceneId) && (inFilter.origin === null || inFilter.origin === sound.sequencer_data.origin);
        });
      }
      static getSounds(inFilter = {}) {
        const filters2 = this._validateFilters(inFilter);
        if (!inFilter)
          throw custom_error(
            "Sequencer",
            "SoundManager | getSounds | Incorrect or incomplete parameters provided"
          );
        return this._filterSounds(filters2);
      }
      static stop(ids) {
        custom_warning(
          "Sequencer",
          "SoundManager | stop | This method is becoming deprecated, please use Sequencer.SoundManager.endSounds instead",
          false
        );
        return this.endSounds({ sounds: ids });
      }
      static endSounds(inFilter, push = true) {
        const filters2 = this._validateFilters(inFilter);
        const sounds = this._filterSounds(filters2);
        if (!sounds?.length) return;
        const ids = sounds.map((sound) => sound.sequencer_data.id);
        if (push && game.user.isGM) {
          sequencerSocket.executeForOthers(SOCKET_HANDLERS.END_SOUNDS, ids);
        }
        return this._endSounds(ids);
      }
      /**
       * @param ids
       * @private
       */
      static _endSounds(ids) {
        for (const id of ids) {
          const sound = SequenceManager.RunningSounds.get(id);
          if (sound) {
            sound.stop();
          }
        }
      }
      static endAllSounds(push = true) {
        const ids = SequenceManager.RunningSounds.keys();
        if (push && game.user.isGM) {
          sequencerSocket.executeForOthers(SOCKET_HANDLERS.END_SOUNDS, ids);
        }
        return this._endSounds(ids);
      }
    }
    let lockedView = false;
    class SequencerFoundryReplicator {
      static registerHooks() {
        Hooks.on("canvasPan", () => {
          if (!lockedView) return;
          canvas.stage.pivot.set(lockedView.x, lockedView.y);
          canvas.stage.scale.set(lockedView.scale, lockedView.scale);
          canvas.updateBlur(lockedView.scale);
          canvas.controls._onCanvasPan();
          canvas.hud.align();
        });
      }
      static playScrollingText(data, push = true) {
        if (push) {
          sequencerSocket.executeForOthers(
            SOCKET_HANDLERS.CREATE_SCROLLING_TEXT,
            data
          );
        }
        return this._playScrollingText(data);
      }
      static _playScrollingText(data) {
        if (game.user.viewedScene !== data.sceneId) return;
        if (data.users.length && !data.users.includes(game.userId)) return;
        canvas.interface.createScrollingText(
          getPositionFromData(data),
          data.content,
          data.options
        );
        return data.options?.duration ?? 2e3;
      }
      static panCanvas(data, push = true) {
        if (push) {
          sequencerSocket.executeForOthers(SOCKET_HANDLERS.PAN_CANVAS, data);
        }
        return this._panCanvas(data);
      }
      static _panCanvas(data) {
        if (game.user.viewedScene !== data.sceneId) return;
        if (data.users.length && !data.users.includes(game.userId)) return;
        if (data.source) {
          const position = getPositionFromData(data);
          canvas.animatePan({
            x: position.x,
            y: position.y,
            scale: data.scale,
            duration: data.duration,
            speed: data.speed
          });
          if (data.speed) {
            let ray = new Ray(canvas.stage.pivot, {
              x: position.x,
              y: position.y
            });
            data.duration = Math.round(ray.distance * 1e3 / data.speed);
          }
          if (data.lockView > 0) {
            setTimeout(() => {
              lockedView = {
                x: position.x,
                y: position.y,
                scale: data.scale
              };
            }, data.duration);
            setTimeout(() => {
              lockedView = false;
            }, data.lockView + data.duration);
          }
        } else {
          data.duration = 0;
        }
        if (data.shake) {
          setTimeout(() => {
            this._shake(data.shake);
          }, data.duration);
        }
        return data.duration + Math.max(data.lockView ?? 0, data.shake?.duration ?? 0);
      }
      static _shake(shakeData) {
        if (!shakeData.duration || !shakeData.frequency) return;
        let x = random_float_between(-1, 1);
        let y = random_float_between(-1, 1);
        let rot = shakeData.rotation ? random_float_between(-1, 1) : 0;
        let positions = [{ x, y, rot }];
        for (let index = 0; index < Math.floor(shakeData.duration / shakeData.frequency); index++) {
          x = flip_negate(x, Math.random());
          y = flip_negate(y, Math.random());
          rot = shakeData.rotation ? flip_negate(rot, Math.random()) : 0;
          positions.push({ x, y, rot });
        }
        let currentDuration = 0;
        positions = positions.map((pos) => {
          let fadeStrength = 1;
          if (shakeData.fadeInDuration && currentDuration <= shakeData.fadeInDuration) {
            fadeStrength = Math.max(
              0,
              Math.min(1, currentDuration / shakeData.fadeInDuration)
            );
          }
          if (shakeData.fadeOutDuration && currentDuration >= shakeData.duration - shakeData.fadeOutDuration) {
            fadeStrength = Math.max(
              0,
              Math.min(
                1,
                (shakeData.duration - currentDuration) / shakeData.fadeOutDuration
              )
            );
          }
          pos.x *= shakeData.strength * fadeStrength;
          pos.y *= shakeData.strength * fadeStrength;
          if (shakeData.rotation) {
            pos.rot *= shakeData.strength / 7.5 * fadeStrength;
          } else {
            pos.rot = 0;
          }
          currentDuration += shakeData.frequency;
          return {
            transform: `translate(${pos.x}px, ${pos.y}px) rotate(${pos.rot}deg)`
          };
        });
        document.getElementById("board").animate(positions, {
          duration: shakeData.duration
        });
      }
    }
    const SequencerPreloader = {
      _usersToRespond: /* @__PURE__ */ new Set(),
      _clientsDone: [],
      _resolve: () => {
      },
      /**
       *  Caches provided file(s) locally, vastly improving loading speed of those files.
       *
       * @param {Array|String}        inSrcs
       * @param {Boolean}             showProgressBar
       * @returns {Promise<void>}
       */
      preload(inSrcs, showProgressBar = false) {
        if (Array.isArray(inSrcs)) {
          inSrcs.forEach((str) => {
            if (typeof str !== "string") {
              throw custom_error(
                "Sequencer",
                "preload | each entry in inSrcs must be of type string"
              );
            }
          });
        } else if (typeof inSrcs !== "string") {
          throw custom_error(
            "Sequencer",
            "preload | inSrcs must be of type string or array of strings"
          );
        }
        if (typeof showProgressBar !== "boolean") {
          throw custom_error(
            "Sequencer",
            "preload | showProgressBar must be of type of boolean"
          );
        }
        const srcs = this._cleanSrcs(inSrcs);
        if (srcs.length === 0) return;
        return this._preloadLocal(srcs, showProgressBar);
      },
      /**
       *  Causes each connected client (including the caller) to fetch and cache the provided file(s) locally, vastly
       *  improving loading speed of those files.
       *
       * @param {Array|String}        inSrcs
       * @param {Boolean}             showProgressBar
       * @returns {Promise<void>}
       */
      preloadForClients(inSrcs, showProgressBar = false) {
        if (Array.isArray(inSrcs)) {
          inSrcs.forEach((str) => {
            if (typeof str !== "string") {
              throw custom_error(
                "Sequencer",
                "preloadForClients | each entry in inSrcs must be of type string"
              );
            }
          });
        } else if (typeof inSrcs !== "string") {
          throw custom_error(
            "Sequencer",
            "preloadForClients | inSrcs must be of type string or array of strings"
          );
        }
        if (typeof showProgressBar !== "boolean") {
          throw custom_error(
            "Sequencer",
            "preloadForClients | showProgressBar must be of type of boolean"
          );
        }
        const srcs = this._cleanSrcs(inSrcs);
        if (srcs.length === 0) return;
        if (!user_can_do("permissions-preload")) {
          custom_warning(
            "Sequencer",
            "preloadForClients - You do not have permission to force other clients to preload. Preloading locally instead."
          );
          return this._preloadLocal(srcs, showProgressBar);
        }
        const promise2 = new Promise((resolve) => {
          this._resolve = resolve;
        });
        this._usersToRespond = new Set(
          game.users.filter((user) => user.active).map((user) => user.id)
        );
        sequencerSocket.executeForEveryone(
          SOCKET_HANDLERS.PRELOAD,
          game.user.id,
          srcs,
          showProgressBar
        );
        return promise2;
      },
      async respond(inSenderId, inSrcs, showProgressBar) {
        const numFilesFailedToLoad = await this._preloadLocal(
          inSrcs,
          showProgressBar
        );
        return sequencerSocket.executeAsUser(
          SOCKET_HANDLERS.PRELOAD_RESPONSE,
          inSenderId,
          game.user.id,
          numFilesFailedToLoad
        );
      },
      handleResponse(inUserId, numFilesFailedToLoad) {
        this._usersToRespond.delete(inUserId);
        this._clientsDone.push({
          userId: inUserId,
          numFilesFailedToLoad
        });
        if (this._usersToRespond.size > 0) return;
        this._clientsDone.forEach((user) => {
          if (user.numFilesFailedToLoad > 0) {
            debug(
              `${game.users.get(user.userId).name} preloaded files, failed to preload ${user.numFilesFailedToLoad} files`
            );
          } else {
            debug(
              `${game.users.get(user.userId).name} preloaded files successfully`
            );
          }
        });
        debug(`All clients responded to file preloads`);
        this._resolve();
        this._usersToRespond = /* @__PURE__ */ new Set();
        this._clientsDone = [];
        this._resolve = () => {
        };
      },
      /**
       * Filters and cleans up file paths given to the preload methods
       *
       * @private
       */
      _cleanSrcs(inSrcs) {
        if (!Array.isArray(inSrcs)) {
          inSrcs = [inSrcs];
        }
        if (inSrcs.length === 0) {
          custom_warning("Sequencer", "You need to provide files to preload");
          return [];
        }
        inSrcs = make_array_unique(
          inSrcs.filter(Boolean).map((src) => {
            if (Sequencer.Database.entryExists(src)) {
              return Sequencer.Database.getAllFileEntries(src);
            }
            return src;
          }).deepFlatten()
        );
        if (inSrcs.length >= 750) {
          custom_warning(
            "Sequencer",
            "You are preloading over 750 files, you are most likely preloading more files than the system can cache.",
            true
          );
        }
        return inSrcs;
      },
      /**
       * The method that actually preloads files locally, with an optional progress bar
       *
       * @private
       */
      _preloadLocal(inSrcs, showProgressBar) {
        let startTime = performance.now();
        let numFilesToLoad = inSrcs.length;
        debug(`Preloading ${numFilesToLoad} files...`);
        if (showProgressBar)
          LoadingBar.init(
            `Sequencer - Preloading ${numFilesToLoad} files`,
            numFilesToLoad
          );
        return new Promise(async (resolve) => {
          let numFilesFailedToLoad = 0;
          const loadingPromises = inSrcs.map(async (src) => {
            const blob = await SequencerFileCache.loadFile(src, true);
            if (showProgressBar) LoadingBar.incrementProgress();
            if (!blob) {
              numFilesFailedToLoad++;
            }
          });
          await Promise.allSettled(loadingPromises);
          const timeTaken = (performance.now() - startTime) / 1e3;
          let failedToLoad = ` (${numFilesFailedToLoad} failed to load)`;
          debug(
            `Preloading ${numFilesToLoad} files took ${timeTaken}s` + failedToLoad
          );
          resolve(numFilesFailedToLoad);
        });
      }
    };
    const SOCKET_HANDLERS = {
      PLAY_EFFECT: "playEffect",
      END_EFFECTS: "endEffects",
      UPDATE_EFFECT: "updateEffects",
      ADD_EFFECT_ANIMATIONS: "addEffectAnimations",
      PLAY_SOUND: "playSound",
      END_SOUNDS: "endSounds",
      PRELOAD: "preload",
      PRELOAD_RESPONSE: "preloadResponse",
      UPDATE_DOCUMENT: "updateDocument",
      ADD_EFFECT_FLAGS: "addEffectFlags",
      REMOVE_EFFECT_FLAGS: "removeEffectFlags",
      UPDATE_EFFECT_POSITION: "updateEffectPosition",
      ADD_SOUND_FLAGS: "addSoundFlags",
      REMOVE_SOUND_FLAGS: "removeSoundFlags",
      CREATE_SCROLLING_TEXT: "createScrollingText",
      PAN_CANVAS: "panCanvas",
      RUN_SEQUENCE_LOCALLY: "runSequenceLocally"
    };
    let sequencerSocket = false;
    function registerSocket() {
      if (sequencerSocket) return;
      if (!socketlib?.registerModule) return;
      sequencerSocket = socketlib.registerModule(CONSTANTS.MODULE_NAME);
      sequencerSocket.register(
        SOCKET_HANDLERS.PLAY_EFFECT,
        (...args) => SequencerEffectManager._playEffect(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.END_EFFECTS,
        (...args) => SequencerEffectManager._endManyEffects(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.UPDATE_EFFECT,
        (...args) => SequencerEffectManager._updateEffect(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
        (...args) => SequencerEffectManager._addEffectAnimations(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.PLAY_SOUND,
        (...args) => SequencerSoundManager._play(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.END_SOUNDS,
        (...args) => SequencerSoundManager._endSounds(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.PRELOAD,
        (...args) => SequencerPreloader.respond(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.PRELOAD_RESPONSE,
        (...args) => SequencerPreloader.handleResponse(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.UPDATE_DOCUMENT,
        (...args) => updateDocument(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.ADD_EFFECT_FLAGS,
        (...args) => flagManager._addEffectFlags(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.REMOVE_EFFECT_FLAGS,
        (...args) => flagManager._removeEffectFlags(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.UPDATE_EFFECT_POSITION,
        (...args) => SequencerEffectManager._updatePosition(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.ADD_SOUND_FLAGS,
        (...args) => flagManager._addSoundFlags(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.REMOVE_SOUND_FLAGS,
        (...args) => flagManager._removeSoundFlags(...args)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.CREATE_SCROLLING_TEXT,
        (data) => SequencerFoundryReplicator._playScrollingText(data)
      );
      sequencerSocket.register(
        SOCKET_HANDLERS.PAN_CANVAS,
        (data) => SequencerFoundryReplicator._panCanvas(data)
      );
      sequencerSocket.register(SOCKET_HANDLERS.RUN_SEQUENCE_LOCALLY, (data) => {
        debug("Playing remote Sequence");
        new Sequence().fromJSON(data).play();
      });
    }
    async function updateDocument(documentUuid, updates, animate) {
      const document2 = await fromUuid(documentUuid);
      return document2.update(updates, animate);
    }
    const PositionContainer = /* @__PURE__ */ new Map();
    const TemporaryPositionsContainer = /* @__PURE__ */ new Map();
    class SequencerEffectManager {
      /**
       * Returns all the currently running effects on the canvas
       *
       * @returns {Array}
       */
      static get effects() {
        return Array.from(SequenceManager.VisibleEffects.values());
      }
      static _updatePosition(uuid, position) {
        TemporaryPositionsContainer.set(uuid, position);
      }
      static getPositionForUUID(uuid) {
        return TemporaryPositionsContainer.get(uuid);
      }
      /**
       * Opens the Sequencer Manager UI with the effects tab open
       */
      static show() {
        return EffectsUIApp.show({ tab: "manager" });
      }
      /**
       * Play an effect on the canvas.
       *
       * @param {object} data The data that describes the audio to play
       * @param {boolean} [push=true] A flag indicating whether or not to make other clients play the effect
       * @returns {CanvasEffect} A CanvasEffect object
       */
      static async play(data, push = true) {
        if (!user_can_do("permissions-effect-create")) {
          custom_warning(
            "Sequencer",
            "EffectManager | play | Players do not have permissions to play effects. This can be configured in Sequencer's module settings."
          );
          return;
        }
        if (push) sequencerSocket.executeForOthers(SOCKET_HANDLERS.PLAY_EFFECT, data);
        return this._playEffect(data);
      }
      /**
       * Get effects that are playing on the canvas based on a set of filters
       *
       * @param {object} inFilter An object containing filters that determine which effects to return
       *                             - object: An ID or a PlaceableObject
       *                             - name: The name of the effect
       *                             - sceneId: the ID of the scene to search within
       * @returns {Array} An array containing effects that match the given filter
       */
      static getEffects(inFilter = {}) {
        const filters2 = this._validateFilters(inFilter);
        if (!inFilter)
          throw custom_error(
            "Sequencer",
            "EffectManager | getEffects | Incorrect or incomplete parameters provided"
          );
        return this._filterEffects(filters2);
      }
      /**
       * Updates effects based on a set of filters
       *
       * @param {object} inFilter An object containing filters that determine which effects to return
       *                             - object: An ID or a PlaceableObject
       *                             - name: The name of the effect
       *                             - sceneId: the ID of the scene to search within
       *                             - effects: a single CanvasEffect or its ID, or an array of such
       * @param {object} inUpdates
       * @returns {promise}
       */
      static updateEffects(inFilter, inUpdates) {
        inFilter = this._validateFilters(inFilter);
        if (!inFilter)
          throw custom_error(
            "Sequencer",
            "EffectManager | updateEffects | Incorrect or incomplete parameters provided"
          );
        CanvasEffect.validateUpdate(inUpdates);
        const effectsToUpdate = this._filterEffects(inFilter).filter(
          (effect) => effect.userCanUpdate
        );
        return Promise.allSettled(
          effectsToUpdate.map((effect) => effect.update(inUpdates))
        );
      }
      /**
       * End effects that are playing on the canvas based on a set of filters
       *
       * @param {object} inFilter An object containing filters that determine which effects to end
       *                             - object: An ID or a PlaceableObject
       *                             - name: The name of the effect
       *                             - sceneId: the ID of the scene to search within
       *                             - effects: a single CanvasEffect or its ID, or an array of such
       * @param {boolean} [push=true] A flag indicating whether or not to make other clients end the effects
       * @returns {promise} A promise that resolves when the effects have ended
       */
      static async endEffects(inFilter = {}, push = true) {
        inFilter = this._validateFilters(inFilter);
        if (!inFilter)
          throw custom_error(
            "Sequencer",
            "EffectManager | endEffects | Incorrect or incomplete parameters provided"
          );
        const effectsToEnd = this._getEffectsByFilter(inFilter);
        if (!effectsToEnd.length) return;
        if (push)
          sequencerSocket.executeForOthers(
            SOCKET_HANDLERS.END_EFFECTS,
            effectsToEnd
          );
        return this._endManyEffects(effectsToEnd);
      }
      /**
       * End all effects that are playing on the canvas
       *
       * @param {string} [inSceneId] A parameter which determines which scene to end all effects on, defaults to current viewed scene
       * @param {boolean} [push=true] A flag indicating whether or not to make other clients end all effects
       * @returns {promise} A promise that resolves when all of the effects have _ended
       */
      static async endAllEffects(inSceneId = game.user.viewedScene, push = true) {
        const inFilter = this._validateFilters({ sceneId: inSceneId });
        if (!inFilter)
          throw custom_error(
            "Sequencer",
            "EffectManager | endAllEffects | Incorrect or incomplete parameters provided"
          );
        const effectsToEnd = this._getEffectsByFilter(inFilter);
        if (!effectsToEnd.length) return;
        if (push)
          sequencerSocket.executeForOthers(
            SOCKET_HANDLERS.END_EFFECTS,
            effectsToEnd
          );
        return this._endManyEffects(effectsToEnd);
      }
      static _getEffectsByFilter(inFilter) {
        return make_array_unique(
          this._filterEffects(inFilter).filter((effect) => effect.userCanDelete).map((effect) => {
            return effect.data?.persistOptions?.persistTokenPrototype && is_UUID(effect?.data.source) && effect.data?.attachTo?.active ? effect.data?.persistOptions?.id ?? effect.id : effect.id;
          })
        );
      }
      /**
       * If an effect has been named its position will be cached, which can be retrieved with this method
       *
       * @param {string} inName
       * @returns {object|boolean}
       * @private
       */
      static getEffectPositionByName(inName) {
        if (!(typeof inName === "string"))
          throw custom_error(
            "Sequencer",
            "EffectManager | getEffectPositionByName | inName must be of type string"
          );
        return PositionContainer.get(inName) ?? false;
      }
      /**
       * Filters the existing effects based on the given filter
       *
       * @param inFilter
       * @returns {array}
       * @private
       */
      static _filterEffects(inFilter) {
        if (inFilter.name) {
          inFilter.name = new RegExp(
            "^" + str_to_search_regex_str(safe_str(inFilter.name)) + "$",
            "gu"
          );
        }
        let effects = this.effects;
        if (inFilter.sceneId && inFilter.sceneId !== canvas.scene.id) {
          effects = get_all_documents_from_scene(inFilter.sceneId).map((doc) => {
            return foundry.utils.getProperty(doc, CONSTANTS.EFFECTS_FLAG);
          }).filter((flags) => !!flags).map((flags) => {
            return flags.map((flag) => CanvasEffect.make(flag[1]));
          }).deepFlatten();
        }
        return effects.filter((effect) => {
          return (!inFilter.effects || inFilter.effects.includes(effect.id)) && (!inFilter.name || effect.data.name && effect.data.name.match(inFilter.name)?.length) && (!inFilter.source || inFilter.source === effect.data.source) && (!inFilter.target || inFilter.target === effect.data.target) && (!inFilter.origin || inFilter.origin === effect.data.origin);
        });
      }
      /**
       * Validates an object actually exists, and gets its UUID
       *
       * @param object
       * @param sceneId
       * @returns {string}
       * @private
       */
      static _validateObject(object, sceneId) {
        if (!(object instanceof foundry.abstract.Document || object instanceof FoundryShim.PlaceableObject || typeof object === "string")) {
          throw custom_error(
            "Sequencer",
            "EffectManager | object must be instance of PlaceableObject or of type string"
          );
        } else if (object instanceof FoundryShim.PlaceableObject || object instanceof foundry.abstract.Document) {
          object = get_object_identifier(object?.document ?? object);
        } else if (typeof object === "string") {
          const actualObject = get_object_from_scene(object, sceneId);
          if (!actualObject) {
            throw custom_error(
              "Sequencer",
              `EffectManager | could not find object with ID: ${object}`
            );
          }
          const uuid = get_object_identifier(actualObject);
          if (!uuid) {
            throw custom_error(
              "Sequencer",
              `EffectManager | could could not establish identifier of object with ID: ${object}`
            );
          }
          object = uuid;
        }
        return object;
      }
      /**
       * Validates the filter given to any of the above public methods
       *
       * @param inFilter
       * @returns {boolean}
       * @private
       */
      static _validateFilters(inFilter) {
        if (inFilter?.sceneId) {
          if (typeof inFilter.sceneId !== "string")
            throw custom_error(
              "Sequencer",
              "EffectManager | inFilter.sceneId must be of type string"
            );
          if (!game.scenes.get(inFilter.sceneId))
            throw custom_error(
              "Sequencer",
              "EffectManager | inFilter.sceneId must be a valid scene id (could not find scene)"
            );
        } else {
          inFilter.sceneId = game.user.viewedScene;
        }
        if (inFilter?.object) {
          inFilter.source = this._validateObject(inFilter.object, inFilter.sceneId);
          delete inFilter.object;
        }
        if (inFilter?.source) {
          inFilter.source = this._validateObject(inFilter.source, inFilter.sceneId);
        }
        if (inFilter?.target) {
          inFilter.target = this._validateObject(inFilter.target, inFilter.sceneId);
        }
        if (inFilter?.name && typeof inFilter?.name !== "string")
          throw custom_error(
            "Sequencer",
            "EffectManager | inFilter.name must be of type string"
          );
        if (inFilter?.origin && typeof inFilter?.origin !== "string")
          throw custom_error(
            "Sequencer",
            "EffectManager | inFilter.origin must be of type string"
          );
        if (inFilter?.effects) {
          if (!Array.isArray(inFilter.effects))
            inFilter.effects = [inFilter.effects];
          inFilter.effects = inFilter.effects.map((effect) => {
            if (!(typeof effect === "string" || effect instanceof CanvasEffect))
              throw custom_error(
                "Sequencer",
                "EffectManager | collections in inFilter.effects must be of type string or CanvasEffect"
              );
            if (effect instanceof CanvasEffect) return effect.id;
            return effect;
          });
        }
        if (!inFilter.name && !inFilter.origin && !inFilter.target && !inFilter.sceneId && !inFilter.effects && !inFilter.origin)
          return false;
        return foundry.utils.mergeObject(
          {
            effects: false,
            name: false,
            source: false,
            target: false,
            sceneId: false,
            origin: false
          },
          inFilter
        );
      }
      /**
       * Actually plays the effect on the canvas
       *
       * @param data
       * @param setFlags
       * @returns {Promise<{duration: Promise<number>, promise: Promise<void>}>}
       * @private
       */
      static async _playEffect(data, setFlags = true) {
        const effect = CanvasEffect.make(data);
        if (data.persist && setFlags && effect.context && effect.owner && !effect.isSourceTemporary && !data.temporary && !data.remote) {
          flagManager.addEffectFlags(effect.context.uuid, effect.data);
        }
        if (!effect.shouldPlay) return;
        const playData = effect.play();
        SequenceManager.VisibleEffects.add(effect.id, effect);
        if (effect.data.name) {
          effect._ticker.add(() => {
            if (effect.isDestroyed) return;
            PositionContainer.set(effect.data.name, {
              start: effect.sourcePosition,
              end: effect.targetPosition
            });
          });
        }
        if (data.temporary && effect.owner) {
          let lastSourcePosition = {};
          let lastTargetPosition = {};
          effect._addToTicker(() => {
            if (effect.source && !effect.isSourceDestroyed) {
              const sourceData = effect.getSourceData();
              if (JSON.stringify(sourceData) !== lastSourcePosition) {
                sequencerSocket.executeForOthers(
                  SOCKET_HANDLERS.UPDATE_EFFECT_POSITION,
                  data.source,
                  sourceData
                );
                lastSourcePosition = JSON.stringify(sourceData);
              }
            }
            if (effect.target && !effect.isTargetDestroyed) {
              const targetData = effect.getTargetData();
              if (JSON.stringify(targetData) !== lastTargetPosition) {
                sequencerSocket.executeForOthers(
                  SOCKET_HANDLERS.UPDATE_EFFECT_POSITION,
                  data.target,
                  targetData
                );
                lastTargetPosition = JSON.stringify(targetData);
              }
            }
          });
        }
        if (!data.persist) {
          playData.promise.then(() => this._removeEffect(effect));
        }
        return playData;
      }
      /**
       * Updates a single effect with the given data
       *
       * @param inEffectId
       * @param inUpdates
       * @returns {promise|boolean}
       * @private
       */
      static _updateEffect(inEffectId, inUpdates) {
        const effect = SequenceManager.VisibleEffects.get(inEffectId);
        if (!effect) return false;
        return effect._update(inUpdates);
      }
      /**
       * Updates a single effect with new animations
       *
       * @param inEffectId
       * @param inAnimations
       * @param inLoopingAnimations
       * @returns {promise|boolean}
       * @private
       */
      static _addEffectAnimations(inEffectId, inAnimations, inLoopingAnimations) {
        const effect = SequenceManager.VisibleEffects.get(inEffectId);
        if (!effect) return false;
        return effect._addAnimations(inAnimations, inLoopingAnimations);
      }
      /**
       * Sets up persisting effects when the scene is first loaded
       *
       * @returns {promise}
       */
      static async initializePersistentEffects() {
        await this.tearDownPersists();
        const allObjects = get_all_documents_from_scene();
        allObjects.push(canvas.scene);
        const docEffectsMap = allObjects.reduce((acc, doc) => {
          let effects = flagManager.getEffectFlags(doc);
          effects.forEach((e) => {
            if (is_UUID(e[1].source) && e[1].source !== doc.uuid) {
              e[1].delete = true;
            }
          });
          if (doc instanceof TokenDocument && doc?.actorLink) {
            const actorEffects = flagManager.getEffectFlags(doc?.actor);
            actorEffects.forEach((e) => {
              e[1]._id = foundry.utils.randomID();
              e[1].source = doc.uuid;
              e[1].sceneId = doc.parent.id;
            });
            effects = effects.concat(actorEffects);
          }
          if (effects.length) {
            acc[doc.uuid] = effects;
          }
          return acc;
        }, {});
        const promises = Object.entries(docEffectsMap).map(([uuid, effects]) => {
          return this._playEffectMap(effects, fromUuidSync(uuid));
        }).flat();
        return Promise.all(promises).then(() => {
          Hooks.callAll("sequencerEffectManagerReady");
        });
      }
      /**
       * Tears down persisting effects when the scene is unloaded
       */
      static tearDownPersists() {
        return Promise.allSettled(
          this.effects.map((effect) => {
            SequenceManager.VisibleEffects.delete(effect.id);
            return effect.destroy();
          })
        );
      }
      static setup() {
        Hooks.on("preCreateToken", this._patchCreationData.bind(this));
        Hooks.on("preCreateDrawing", this._patchCreationData.bind(this));
        Hooks.on("preCreateTile", this._patchCreationData.bind(this));
        Hooks.on("preCreateMeasuredTemplate", this._patchCreationData.bind(this));
        Hooks.on("createToken", this._documentCreated.bind(this));
        Hooks.on("createDrawing", this._documentCreated.bind(this));
        Hooks.on("createTile", this._documentCreated.bind(this));
        Hooks.on("createMeasuredTemplate", this._documentCreated.bind(this));
      }
      /**
       * Patches an object's creation data before it's created so that the effect plays on it correctly
       *
       * @param inDocument
       * @param data
       * @param options
       * @returns {*}
       */
      static async _patchCreationData(inDocument, data, options) {
        const effects = flagManager.getEffectFlags(inDocument);
        if (!effects?.length) return;
        const updates = {};
        let documentUuid;
        if (!inDocument._id) {
          const documentId = foundry.utils.randomID();
          documentUuid = inDocument.uuid + documentId;
          updates["_id"] = documentId;
          options.keepId = true;
        } else {
          documentUuid = inDocument.uuid;
        }
        updates[CONSTANTS.EFFECTS_FLAG] = this._patchEffectDataForDocument(
          documentUuid,
          effects
        );
        return inDocument.updateSource(updates);
      }
      static _patchEffectDataForDocument(inDocumentUuid, effects) {
        return effects.map((effect) => {
          effect[0] = foundry.utils.randomID();
          const effectData = effect[1];
          effectData._id = effect[0];
          if (is_UUID(effectData.source)) {
            if (effectData.masks.includes(effectData.source)) {
              const index = effectData.masks.indexOf(effectData.source);
              effectData.masks[index] = inDocumentUuid;
            }
            effectData.source = inDocumentUuid;
          }
          effectData.sceneId = inDocumentUuid.split(".")[1];
          return effect;
        });
      }
      /**
       * Plays the effects of a given document on creation
       *
       * @param inDocument
       * @returns {*}
       */
      static async _documentCreated(inDocument) {
        let effects = flagManager.getEffectFlags(inDocument);
        if (inDocument instanceof TokenDocument && inDocument?.actorLink) {
          let actorEffects = flagManager.getEffectFlags(inDocument?.actor);
          if (actorEffects.length) {
            actorEffects = this._patchEffectDataForDocument(
              inDocument.uuid,
              actorEffects
            );
          }
          effects = effects.concat(actorEffects);
        }
        if (!effects?.length) return;
        return this._playEffectMap(effects, inDocument);
      }
      /**
       * Plays multiple effects at the same time
       *
       * @param inEffects
       * @param inDocument
       * @returns {Promise<{duration: Promise<number>, promise: Promise<void>}[]>}
       * @private
       */
      static _playEffectMap(inEffects, inDocument) {
        if (inEffects instanceof Map) inEffects = Array.from(inEffects);
        return Promise.all(
          inEffects.map((effect) => {
            if (!CanvasEffect.checkValid(effect[1])) {
              if (!game.user.isGM) return;
              custom_warning(
                `Sequencer`,
                `Removed effect from ${inDocument.uuid} as it no longer had a valid source or target`
              );
              return flagManager.removeEffectFlags(inDocument.uuid, effect);
            }
            return this._playEffect(effect[1], false).then((result) => {
              if (!result) {
                debug("Error playing effect");
              }
            }).catch((err) => {
              debug("Error playing effect:", err);
            });
          })
        );
      }
      /**
       * Ends one or many effects at the same time, returning a promise that resolves once every effect has fully ended
       *
       * @param inEffectIds
       * @returns {Promise}
       * @private
       */
      static async _endManyEffects(inEffectIds = false) {
        const actorEffectsToEnd = this.effects.filter((effect) => {
          return effect.context?.actorLink && inEffectIds.includes(effect.data?.persistOptions?.id);
        });
        const effectsByActorUuid = Object.values(
          group_by(actorEffectsToEnd, "context.actor.uuid")
        );
        const regularEffectsToEnd = this.effects.filter((effect) => {
          return inEffectIds.includes(effect.id) || !effect.context?.actorLink && inEffectIds.includes(effect.data?.persistOptions?.id);
        });
        const effectsByContextUuid = Object.values(
          group_by(regularEffectsToEnd, "context.uuid")
        );
        effectsByContextUuid.forEach((effects) => {
          effects = effects.filter(
            (effect) => effect.data.persist && !effect.data.temporary
          );
          if (!effects.length) return;
          const effectData = effects.map((effect) => effect.data);
          flagManager.removeEffectFlags(
            effects[0].context.uuid,
            effectData,
            !inEffectIds
          );
        });
        effectsByActorUuid.forEach((effects) => {
          effects = effects.filter(
            (effect) => effect.data.persist && !effect.data.temporary
          );
          if (!effects.length) return;
          const effectContext = effects[0].context;
          const effectData = effects.map((effect) => effect.data);
          if (!(effectContext instanceof TokenDocument && effectContext.actorLink && effectContext.actor.prototypeToken.actorLink)) {
            return;
          }
          const persistentEffectData = effectData.filter(
            (data) => is_UUID(data?.source) && data?.persistOptions?.persistTokenPrototype
          );
          if (!persistentEffectData.length) return;
          const actorEffects = flagManager.getEffectFlags(effectContext.actor);
          const applicableActorEffects = actorEffects.filter((effect) => {
            return is_UUID(effect[1]?.source) && effect[1]?.persistOptions?.persistTokenPrototype && persistentEffectData.some(
              (persistentEffect) => persistentEffect.persistOptions.id === effect[1]?.persistOptions?.id
            );
          }).map((e) => e[0]);
          flagManager.removeEffectFlags(
            effectContext.actor.uuid,
            applicableActorEffects,
            !inEffectIds
          );
        });
        const effectsToEnd = effectsByContextUuid.concat(effectsByActorUuid).deepFlatten();
        return Promise.allSettled(
          effectsToEnd.map((effect) => this._removeEffect(effect))
        );
      }
      static _effectContextFilter(inUUID, effectData) {
        return effectData?.source === inUUID || effectData?.target === inUUID || (effectData?.tiedDocuments ?? []).indexOf(inUUID) > -1;
      }
      /**
       * Handles the deletion of objects that effects are attached to
       *
       * @param inUUID
       * @returns {Promise}
       */
      static objectDeleted(inUUID) {
        const documentsToCheck = game.scenes.filter((scene) => scene.id !== game.user.viewedScene).map((scene) => [scene, ...get_all_documents_from_scene(scene.id)]).deepFlatten();
        const documentEffectsToEnd = documentsToCheck.map((obj) => {
          const objEffects = flagManager.getEffectFlags(obj);
          const effectsToEnd = objEffects.filter(
            ([effectId, effectData]) => this._effectContextFilter(inUUID, effectData)
          );
          return {
            document: obj,
            effects: effectsToEnd.map((effect) => effect[0])
          };
        }).filter((obj) => obj.effects.length);
        const visibleEffectsToEnd = this.effects.filter((effect) => this._effectContextFilter(inUUID, effect.data)).map((e) => e.id);
        return Promise.allSettled([
          this._endManyEffects(visibleEffectsToEnd),
          ...documentEffectsToEnd.map((obj) => {
            return flagManager.removeEffectFlags(obj.document.uuid, obj.effects);
          })
        ]);
      }
      /**
       * Removes the effect from the manager and ends it, returning a promise that resolves once the effect has fully _ended
       *
       * @param effect
       * @returns {Promise}
       * @private
       */
      static _removeEffect(effect) {
        SequenceManager.VisibleEffects.delete(effect.id);
        TemporaryPositionsContainer.delete(effect.data.source);
        TemporaryPositionsContainer.delete(effect.data.target);
        return effect.endEffect();
      }
    }
    class BaseEffectsLayer extends FoundryShim.InteractionLayer {
      static get layerOptions() {
        return foundry.utils.mergeObject(super.layerOptions, {
          elevation: 1e8,
          name: CONSTANTS.EFFECTS_LAYER
        });
      }
    }
    class SequencerInterfaceLayer extends FoundryShim.InteractionLayer {
      constructor(...args) {
        super(...args);
      }
      isActive = false;
      static get layerOptions() {
        return foundry.utils.mergeObject(super.layerOptions, {
          elevation: 1e8,
          name: CONSTANTS.INTERFACE_LAYER
        });
      }
      activate(...args) {
        const result = super.activate(...args);
        this.isActive = true;
        return result;
      }
      deactivate() {
        super.deactivate();
        if (!this.isActive) return;
        this._clearChildren();
        this.isActive = false;
        InteractionManager.tearDown();
      }
      _setup() {
        if (!this.UIContainer || this.UIContainer._destroyed) {
          this.UIContainer = new PIXI.Container();
          this.UIContainer.sortableChildren = true;
          this.UIContainer.parentName = "sequencerUIContainer";
          this.UIContainer.zIndex = 1e13;
          this.addChild(this.UIContainer);
          this.linePoint = this.UIContainer.addChild(new PIXI.Graphics());
          this.line = this.UIContainer.addChild(new PIXI.Graphics());
          this.lineHead = this.UIContainer.addChild(new PIXI.Graphics());
          this.suggestionPoint = this.UIContainer.addChild(new PIXI.Graphics());
          this.effectHoverBoxes = this.UIContainer.addChild(new PIXI.Graphics());
          this.effectSelectionBorder = this.UIContainer.addChild(
            new PIXI.Graphics()
          );
          this.effectSourcePosition = this.UIContainer.addChild(
            new PIXI.Graphics()
          );
          this.effectTargetPosition = this.UIContainer.addChild(
            new PIXI.Graphics()
          );
          this.suggestionPoint.filters = [new PIXI.AlphaFilter(0.75)];
          this.effectSourcePosition.filters = [new PIXI.AlphaFilter(0.75)];
          this.effectTargetPosition.filters = [new PIXI.AlphaFilter(0.75)];
          this.effectSelectionBorder.zIndex = 1;
          this.effectSourcePosition.interactive = true;
          this.effectSourcePosition.on("mousedown", () => {
            SelectionManager.sourcePointSelected();
          });
          this.effectTargetPosition.interactive = true;
          this.effectTargetPosition.on("mousedown", () => {
            SelectionManager.targetPointSelected();
          });
        }
      }
      async _draw(...args) {
      }
      render(...args) {
        super.render(...args);
        this._setup();
        this._clearChildren();
        this._drawHoveredEffectElements();
        if (!this.isActive) return;
        this._drawLine();
        this._drawPoints();
        this._drawSelectedEffectElements();
        this._drawSuggestionPoint();
      }
      _clearChildren() {
        if (!this.UIContainer) return;
        this.UIContainer.children.forEach((child) => {
          child.clear();
        });
      }
      _drawLine() {
        if (!EffectPlayer.startPos || !EffectPlayer.endPos || game?.activeTool !== CONSTANTS.TOOLS.PLAY)
          return;
        this.line.lineStyle(3, CONSTANTS.COLOR.PRIMARY, 1);
        this.line.moveTo(EffectPlayer.startPos.x, EffectPlayer.startPos.y);
        this.line.lineTo(EffectPlayer.endPos.x, EffectPlayer.endPos.y);
      }
      _drawPoints() {
        if (game?.activeTool !== CONSTANTS.TOOLS.PLAY) return;
        const startPos = EffectPlayer.startPos || EffectPlayer.cursorPos;
        this.linePoint.beginFill(CONSTANTS.COLOR.PRIMARY);
        this.linePoint.drawCircle(startPos.x, startPos.y, 5);
        if (EffectPlayer.sourceAttachFound) {
          this._drawCrossAtLocation(this.linePoint, startPos);
        }
        if (!EffectPlayer.endPos) return;
        const angle = new Ray(startPos, EffectPlayer.endPos).angle;
        this.lineHead.beginFill(CONSTANTS.COLOR.PRIMARY);
        this.lineHead.moveTo(0, -5);
        this.lineHead.lineTo(-15, 30);
        this.lineHead.lineTo(15, 30);
        this.lineHead.endFill();
        this.lineHead.rotation = angle + Math.PI / 2;
        this.lineHead.position.set(EffectPlayer.endPos.x, EffectPlayer.endPos.y);
        if (EffectPlayer.targetAttachFound) {
          this.linePoint.beginFill(CONSTANTS.COLOR.SECONDARY);
          this._drawCrossAtLocation(this.linePoint, EffectPlayer.endPos);
        }
      }
      _drawHoveredEffectElements() {
        const effects = new Set(SelectionManager.hoveredEffects);
        if (SelectionManager.hoveredEffectUI)
          effects.add(SelectionManager.hoveredEffectUI);
        for (const effect of effects) {
          if (!effect || effect === SelectionManager.selectedEffect || effect.data.screenSpace || effect._isEnding)
            continue;
          this._drawBoxAroundEffect(this.effectHoverBoxes, effect);
        }
      }
      _drawSelectedEffectElements() {
        if (!SelectionManager.selectedEffect) return;
        this._drawBoxAroundEffect(
          this.effectSelectionBorder,
          SelectionManager.selectedEffect,
          true
        );
        this._drawEffectStartEndPoints(SelectionManager.selectedEffect);
      }
      _drawBoxAroundEffect(graphic, effect, selected = false) {
        if (!effect || effect._destroyed || !effect.spriteContainer || !effect.ready)
          return;
        graphic.lineStyle(3, selected ? CONSTANTS.COLOR.PRIMARY : 16777215, 0.9);
        let boundingBox = effect.sprite.getLocalBounds();
        let dimensions = {
          x: effect.position.x + boundingBox.x * effect.sprite.scale.x,
          y: effect.position.y + boundingBox.y * effect.sprite.scale.y,
          width: boundingBox.width * effect.sprite.scale.x,
          height: boundingBox.height * effect.sprite.scale.y
        };
        if (effect.data.shapes.length) {
          for (const shape of Object.values(effect.shapes)) {
            boundingBox = shape.getLocalBounds();
            dimensions = {
              x: Math.min(
                dimensions.x,
                effect.position.x + boundingBox.x * shape.scale.x
              ),
              y: Math.min(
                dimensions.y,
                effect.position.y + boundingBox.y * shape.scale.y
              ),
              width: Math.max(dimensions.width, boundingBox.width * shape.scale.x),
              height: Math.max(
                dimensions.height,
                boundingBox.height * shape.scale.y
              )
            };
          }
        }
        const rotation2 = Math.normalizeRadians(
          effect.rotationContainer.rotation + effect.spriteContainer.rotation + effect.sprite.rotation
        );
        this._drawRectangle(graphic, effect.position, rotation2, dimensions);
      }
      _drawRectangle(graphic, position, rotation2, dimensions) {
        graphic.moveTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x,
              y: dimensions.y
            },
            -rotation2
          )
        );
        graphic.lineTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x + dimensions.width,
              y: dimensions.y
            },
            -rotation2
          )
        );
        graphic.lineTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x + dimensions.width,
              y: dimensions.y + dimensions.height
            },
            -rotation2
          )
        );
        graphic.lineTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x,
              y: dimensions.y + dimensions.height
            },
            -rotation2
          )
        );
        graphic.lineTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x,
              y: dimensions.y
            },
            -rotation2
          )
        );
        graphic.lineTo(
          ...rotate_coordinate(
            position,
            {
              x: dimensions.x + dimensions.width,
              y: dimensions.y
            },
            -rotation2
          )
        );
      }
      /**
       * Draws the start/end point circles
       * @private
       */
      _drawEffectStartEndPoints(effect) {
        if (!effect || effect._destroyed || !effect.spriteContainer) return;
        if (!effect.data.stretchTo || !effect.sourcePosition || !effect.targetPosition)
          return;
        this.effectSourcePosition.beginFill(CONSTANTS.COLOR.PRIMARY);
        this.effectSourcePosition.drawCircle(
          effect.sourcePosition.x,
          effect.sourcePosition.y,
          canvas.grid.size * 0.25
        );
        if (typeof effect.data.source === "string") {
          this._drawCrossAtLocation(
            this.effectSourcePosition,
            effect.sourcePosition
          );
        }
        this.effectTargetPosition.beginFill(CONSTANTS.COLOR.SECONDARY);
        this.effectTargetPosition.drawCircle(
          effect.targetPosition.x,
          effect.targetPosition.y,
          canvas.grid.size * 0.25
        );
        this.effectTargetPosition.alpha = 0.75;
        if (typeof effect.data.target === "string") {
          this._drawCrossAtLocation(
            this.effectTargetPosition,
            effect.targetPosition
          );
        }
      }
      _drawSuggestionPoint() {
        if (!SelectionManager.suggestedProperties || !SelectionManager.selectedEffect)
          return;
        const effect = SelectionManager.selectedEffect;
        const suggestion = SelectionManager.suggestedProperties;
        this.suggestionPoint.position.set(0, 0);
        this.suggestionPoint.rotation = 0;
        if (effect.data.stretchTo) {
          this.suggestionPoint.beginFill(suggestion.color);
          this.suggestionPoint.drawCircle(
            suggestion.position.x,
            suggestion.position.y,
            canvas.grid.size * 0.25
          );
          if (suggestion.showCursor) {
            this._drawCrossAtLocation(this.suggestionPoint, suggestion.position);
          }
          return;
        }
        const boundingBox = effect.spriteContainer.getLocalBounds();
        const dimensions = {
          x: boundingBox.x * effect.scale.x,
          y: boundingBox.y * effect.scale.y,
          width: boundingBox.width * effect.scale.x,
          height: boundingBox.height * effect.scale.y
        };
        this.suggestionPoint.lineStyle(3, CONSTANTS.COLOR.PRIMARY, 0.9);
        this.suggestionPoint.position.set(
          suggestion.position.x,
          suggestion.position.y
        );
        this._drawRectangle(
          this.suggestionPoint,
          suggestion.position,
          effect.rotation,
          dimensions,
          true
        );
        if (suggestion.showCursor) {
          this.suggestionPoint.beginFill(CONSTANTS.COLOR.SECONDARY);
          this._drawCrossAtLocation(this.suggestionPoint);
        }
        if (suggestion.showPoint) {
          this.suggestionPoint.drawCircle(0, 0, canvas.grid.size * 0.2);
        }
      }
      _drawCrossAtLocation(inElement, inPosition = { x: 0, y: 0 }) {
        inElement.drawRect(
          inPosition.x + canvas.grid.size * -0.05,
          inPosition.y + canvas.grid.size * -0.5,
          canvas.grid.size * 0.1,
          canvas.grid.size
        );
        inElement.drawRect(
          inPosition.x + canvas.grid.size * -0.5,
          inPosition.y + canvas.grid.size * -0.05,
          canvas.grid.size,
          canvas.grid.size * 0.1
        );
      }
    }
    class UIEffectsLayer extends FoundryShim.InteractionLayer {
      static get layerOptions() {
        return foundry.utils.mergeObject(super.layerOptions, {
          zIndex: 999999999999999,
          name: "sequencerEffectsAboveEverything"
        });
      }
      updateTransform() {
        if (this.sortableChildren && this.sortDirty) {
          this.sortChildren();
        }
        this._boundsID++;
        this.transform.updateTransform(PIXI.Transform.IDENTITY);
        this.worldAlpha = this.alpha;
        for (let child of this.children) {
          if (child.visible) {
            child.updateTransform();
          }
        }
      }
    }
    let layer = false;
    class SequencerAboveUILayer {
      constructor(name2, zIndex = 0.1) {
        this.canvas = document.createElement("canvas");
        this.canvas.id = name2;
        this.canvas.style.cssText = `
            position:absolute;
            touch-action: none;
            pointer-events: none;
            width:100%;
            height:100%;
            z-index:${zIndex};
            padding: 0;
            margin: 0;
        `;
        document.body.appendChild(this.canvas);
        this.app = new PIXI.Application({
          width: window.innerWidth,
          height: window.innerHeight,
          view: this.canvas,
          antialias: true,
          backgroundAlpha: 0,
          sharedTicker: true
        });
        this.app.resizeTo = window;
        this.app.stage.renderable = false;
      }
      static setup() {
        if (!game.settings.get("sequencer", "enable-above-ui-screenspace")) return;
        layer = new this("sequencerUILayerAbove", 1e4);
      }
      static getLayer() {
        return layer ? layer.app.stage : canvas.sequencerEffectsUILayer;
      }
      static addChild(...args) {
        const layer2 = this.getLayer();
        const result = layer2.addChild(...args);
        layer2.renderable = layer2.children.length > 0;
        return result;
      }
      static sortChildren() {
        return this.getLayer().sortChildren();
      }
      static removeContainerByEffect(inEffect) {
        const layer2 = this.getLayer();
        if (!(layer2 instanceof SequencerAboveUILayer)) return;
        const child = layer2.children.find((child2) => child2 === inEffect);
        if (!child) return;
        layer2.removeChild(child);
        layer2.renderable = layer2.children.length > 0;
      }
      updateTransform() {
        if (this.app.stage.sortableChildren && this.app.stage.sortDirty) {
          this.app.stage.sortChildren();
        }
        this.app.stage._boundsID++;
        this.app.stage.transform.updateTransform(PIXI.Transform.IDENTITY);
        this.app.stage.worldAlpha = this.app.stage.alpha;
        for (let child of this.app.stage.children) {
          if (child.visible) {
            child.updateTransform();
          }
        }
      }
    }
    const tempMat = new PIXI.Matrix();
    const uvPoint = new PIXI.Point();
    class VisionSamplerShaderGenerator extends FoundryShim.BatchShaderGenerator {
      generateSampleSrc(maxTextures) {
        let src = "\n\n";
        for (let i = 0; i < maxTextures; i++) {
          if (i > 0) {
            src += "\nelse ";
          }
          if (i < maxTextures - 1) {
            src += `if(vTextureId < ${i}.5)`;
          }
          src += "\n{";
          src += `
	color = texture(uSamplers[${i}], coord, unclamped == coord ? 0.0f : -32.0f);`;
          src += "\n}";
        }
        src += "\n";
        src += "\n";
        return src;
      }
    }
    const emptyColorMatrix = new Uint8Array(20);
    class VisionSamplerShader extends FoundryShim.BaseSamplerShader {
      static classPluginName = "sequencerVisionBatch";
      static batchShaderGeneratorClass = VisionSamplerShaderGenerator;
      static batchGeometry = [
        { id: "aVertexPosition", size: 2, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aTextureCoord", size: 2, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aClampOffset", size: 2, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aClampFrame", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aMapCoord1", size: 3, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aMapCoord2", size: 3, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aMapCoord3", size: 3, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColor", size: 4, normalized: true, type: PIXI.TYPES.UNSIGNED_BYTE },
        { id: "aColorMatrixR", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColorMatrixG", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColorMatrixB", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColorMatrixA", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColorMatrixOffset", size: 4, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aColorMatrixAlpha", size: 1, normalized: false, type: PIXI.TYPES.FLOAT },
        { id: "aShaderFlags", size: 1, normalized: false, type: PIXI.TYPES.UNSIGNED_SHORT },
        { id: "aTextureId", size: 1, normalized: false, type: PIXI.TYPES.UNSIGNED_SHORT }
      ];
      static #SHADER_FLAGS = foundry.utils.BitMask.generateShaderBitMaskConstants([
        "IS_TILING",
        "IS_VISION_MASKING_ENABLED",
        "IS_COLOR_MATRIX_ENABLED"
      ]);
      /** @override */
      static batchVertexSize = 42;
      /** @override */
      static reservedTextureUnits = 1;
      // We need a texture unit for the occlusion texture
      /**
       * The batch vertex shader source.
       * @type {string}
       */
      static batchVertexShader = (
        /* glsl */
        `#version 300 es
	precision highp float;
	
	uniform vec2 screenDimensions;
	uniform mat3 projectionMatrix;
	uniform mat3 translationMatrix;
	uniform vec4 tint;
	
	in vec2 aVertexPosition;
	in vec2 aTextureCoord;
	in vec2 aClampOffset;
	in vec4 aClampFrame;
	in vec3 aMapCoord1;
	in vec3 aMapCoord2;
	in vec3 aMapCoord3;
	in vec4 aColor;
	in vec4 aColorMatrixR;
	in vec4 aColorMatrixG;
	in vec4 aColorMatrixB;
	in vec4 aColorMatrixA;
	in vec4 aColorMatrixOffset;
	in float aColorMatrixAlpha;
	in float aShaderFlags;
	in float aTextureId;
	
	out vec2 vTextureCoord;
	out vec2 vVisionCoord;
	flat out vec2 vClampOffset;
	flat out vec4 vClampFrame;
	flat out mat3 vMapCoord;
	flat out vec4 vColor;
	flat out mat4 vColorMatrix;
	flat out vec4 vColorMatrixOffset;
	flat out float vColorMatrixAlpha;
	flat out uint vShaderFlags;
	flat out float vTextureId;
	
	void main(void) {
		gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0f)).xy, 0.0f, 1.0f);
		vTextureCoord = aTextureCoord;
		vVisionCoord = aVertexPosition / screenDimensions;
		vColor = aColor * tint;
		vClampOffset = aClampOffset;
		vClampFrame = aClampFrame;
		vMapCoord = mat3(aMapCoord1, aMapCoord2, aMapCoord3);
		vColorMatrix = mat4(aColorMatrixR, aColorMatrixG, aColorMatrixB, aColorMatrixA);
		vColorMatrixOffset = aColorMatrixOffset;
		vColorMatrixAlpha = aColorMatrixAlpha;
		vShaderFlags = uint(aShaderFlags);
		vTextureId = aTextureId;
	}
	`
      );
      /**
       * The batch fragment shader source.
       * @type {string}
       */
      static batchFragmentShader = (
        /* glsl */
        `#version 300 es
	precision mediump float;

	in vec2 vTextureCoord;
	in vec2 vVisionCoord;
	flat in float vTextureId;
	flat in vec4 vColor;
	flat in mat3 vMapCoord;
	flat in uint vShaderFlags;
	flat in vec2 vClampOffset;
	flat in vec4 vClampFrame;
	flat in mat4 vColorMatrix;
	flat in vec4 vColorMatrixOffset;
	flat in float vColorMatrixAlpha;

	uniform bool enableVisionMasking;
	uniform sampler2D visionMaskTexture;
	uniform sampler2D uSamplers[%count%];
	out vec4 fragColor;

	${VisionSamplerShader.#SHADER_FLAGS}

	void main(void){
		bool isTilingEnabled = ((vShaderFlags & IS_TILING) == IS_TILING);
		bool isVisionMaskingEnabled = ((vShaderFlags & IS_VISION_MASKING_ENABLED) == IS_VISION_MASKING_ENABLED);
		bool isColorMatrixEnabled = ((vShaderFlags & IS_COLOR_MATRIX_ENABLED) == IS_COLOR_MATRIX_ENABLED);

		vec2 coord = vTextureCoord;
		vec2 unclamped;
		if (isTilingEnabled) {
			coord = coord + ceil(vClampOffset - coord);
			coord = (vMapCoord * vec3(coord, 1.0)).xy;
			unclamped = coord;
			coord = clamp(coord, vClampFrame.xy, vClampFrame.zw);
		} else {
			unclamped = coord;
	  }
	  float mask = isVisionMaskingEnabled && enableVisionMasking ? texture(visionMaskTexture, vVisionCoord).r : 1.0;

	  vec4 color;
	  %forloop%

		if (isColorMatrixEnabled && vColorMatrixAlpha > 0.0) {
			if (color.a > 0.0) {
	      color.rgb /= color.a;
	    }
			vec4 result = color * vColorMatrix + vColorMatrixOffset;

			vec3 rgb = mix(color.rgb, result.rgb, vColorMatrixAlpha);
			rgb *= result.a;
			color = vec4(rgb, result.a);
	  }
	  fragColor = color * mask * vColor;
	}	
	`
      );
      /** @override */
      static batchDefaultUniforms(maxTex) {
        return {
          screenDimensions: [1, 1],
          visionMaskTexture: maxTex
        };
      }
      /** @override */
      static _preRenderBatch(batchRenderer) {
        const uniforms = batchRenderer._shader.uniforms;
        uniforms.screenDimensions = canvas.screenDimensions;
        uniforms.enableVisionMasking = canvas?.visibility?.visible ?? canvas?.effects?.visibility?.visible ?? true;
        batchRenderer.renderer.texture.bind(canvas.masks.vision.renderTexture, uniforms.visionMaskTexture);
      }
      /** @override */
      static _packInterleavedGeometry(element2, attributeBuffer, indexBuffer, aIndex, iIndex) {
        const { float32View, uint32View, uint16View } = attributeBuffer;
        const mesh = element2.object;
        const packedVertices = aIndex / this.vertexSize;
        const indices = element2.indices;
        for (let i = 0; i < indices.length; i++) {
          indexBuffer[iIndex++] = packedVertices + indices[i];
        }
        const vertexData = element2.vertexData;
        let uvs = element2.uvs;
        const alpha = Math.min(element2.worldAlpha, 1);
        const baseTexture = element2._texture.baseTexture;
        const argb = PIXI.Color.shared.setValue(element2._tintRGB).toPremultiplied(alpha, baseTexture.alphaMode > 0);
        const textureId = element2._texture.baseTexture._batchLocation;
        const mapCoord = mesh.uvMatrix.mapCoord.toArray(true);
        let clampFrame = mesh.uvMatrix.uClampFrame;
        let clampOffset = mesh.uvMatrix.uClampOffset;
        if (mesh.tiling) {
          const tex = element2._texture;
          const w = tex.width;
          const h = tex.height;
          const W = mesh.width;
          const H = mesh.height;
          const lt = mesh.tileTransform.localTransform;
          tempMat.set(lt.a * w / W, lt.b * w / H, lt.c * h / W, lt.d * h / H, lt.tx / W, lt.ty / H);
          const anchorX = mesh.uvRespectAnchor ? mesh.anchor.x : 0;
          const anchorY = mesh.uvRespectAnchor ? mesh.anchor.y : 0;
          uvs[0] = uvs[6] = -anchorX;
          uvs[1] = uvs[3] = -anchorY;
          uvs[2] = uvs[4] = 1 - anchorX;
          uvs[5] = uvs[7] = 1 - anchorY;
        }
        const vertexSize = this.vertexSize;
        const colorMatrixArray = mesh.colorMatrixFilter?.matrix ?? emptyColorMatrix;
        const colorMatrixAlpha = mesh.colorMatrixFilter?.alpha ?? 1;
        for (let i = 0, j = 0; i < vertexData.length; i += 2, j += vertexSize) {
          uvPoint.set(uvs[i], uvs[i + 1]);
          if (mesh.tiling) {
            tempMat.applyInverse(uvPoint, uvPoint);
          }
          let k = aIndex + j;
          float32View[k++] = vertexData[i];
          float32View[k++] = vertexData[i + 1];
          float32View[k++] = uvPoint.x;
          float32View[k++] = uvPoint.y;
          float32View[k++] = clampOffset[0];
          float32View[k++] = clampOffset[1];
          float32View[k++] = clampFrame[0];
          float32View[k++] = clampFrame[1];
          float32View[k++] = clampFrame[2];
          float32View[k++] = clampFrame[3];
          float32View[k++] = mapCoord[0];
          float32View[k++] = mapCoord[1];
          float32View[k++] = mapCoord[2];
          float32View[k++] = mapCoord[3];
          float32View[k++] = mapCoord[4];
          float32View[k++] = mapCoord[5];
          float32View[k++] = mapCoord[6];
          float32View[k++] = mapCoord[7];
          float32View[k++] = mapCoord[8];
          uint32View[k++] = argb;
          float32View[k++] = colorMatrixArray[0];
          float32View[k++] = colorMatrixArray[1];
          float32View[k++] = colorMatrixArray[2];
          float32View[k++] = colorMatrixArray[3];
          float32View[k++] = colorMatrixArray[5];
          float32View[k++] = colorMatrixArray[6];
          float32View[k++] = colorMatrixArray[7];
          float32View[k++] = colorMatrixArray[8];
          float32View[k++] = colorMatrixArray[10];
          float32View[k++] = colorMatrixArray[11];
          float32View[k++] = colorMatrixArray[12];
          float32View[k++] = colorMatrixArray[13];
          float32View[k++] = colorMatrixArray[15];
          float32View[k++] = colorMatrixArray[16];
          float32View[k++] = colorMatrixArray[17];
          float32View[k++] = colorMatrixArray[18];
          float32View[k++] = colorMatrixArray[4];
          float32View[k++] = colorMatrixArray[9];
          float32View[k++] = colorMatrixArray[14];
          float32View[k++] = colorMatrixArray[19];
          float32View[k++] = colorMatrixAlpha;
          k <<= 1;
          uint16View[k++] = mesh.shaderFlags.valueOf();
          uint16View[k++] = textureId;
        }
      }
      // need to override createPlugin as canvas.performance is not defined in foundry when
      // we need it to be
      static createPlugin() {
        const shaderClass = this;
        const geometryClass = Array.isArray(shaderClass.batchGeometry) ? class BatchGeometry extends PIXI.Geometry {
          constructor(_static = false) {
            super();
            this._buffer = new PIXI.Buffer(null, _static, false);
            this._indexBuffer = new PIXI.Buffer(null, _static, true);
            for (const { id, size, normalized, type } of shaderClass.batchGeometry) {
              this.addAttribute(id, this._buffer, size, normalized, type);
            }
            this.addIndex(this._indexBuffer);
          }
        } : shaderClass.batchGeometry;
        return class BatchPlugin extends shaderClass.batchRendererClass {
          /** @override */
          static get shaderGeneratorClass() {
            return shaderClass.batchShaderGeneratorClass;
          }
          /* ---------------------------------------- */
          /** @override */
          static get defaultVertexSrc() {
            return shaderClass.batchVertexShader;
          }
          /* ---------------------------------------- */
          /** @override */
          static get defaultFragmentTemplate() {
            return shaderClass.batchFragmentShader;
          }
          /* ---------------------------------------- */
          /** @override */
          static get defaultUniforms() {
            return shaderClass.batchDefaultUniforms;
          }
          /* ---------------------------------------- */
          /**
           * The batch plugin constructor.
           * @param {PIXI.Renderer} renderer    The renderer
           */
          constructor(renderer) {
            super(renderer);
            this.geometryClass = geometryClass;
            this.vertexSize = shaderClass.batchVertexSize;
            this.reservedTextureUnits = shaderClass.reservedTextureUnits;
            this._packInterleavedGeometry = shaderClass._packInterleavedGeometry;
            this._preRenderBatch = shaderClass._preRenderBatch;
          }
          /* ---------------------------------------- */
          /** @inheritdoc */
          setShaderGenerator(options) {
            super.setShaderGenerator(options);
          }
          /* ---------------------------------------- */
          /** @inheritdoc */
          contextChange() {
            this.shaderGenerator = null;
            super.contextChange();
          }
        };
      }
    }
    class TilingSpriteMesh extends FoundryShim.SpriteMesh {
      /** @type {PIXI.Transform} */
      tileTransform;
      /** @type {PIXI.TextureMatrix} */
      uvMatrix;
      /** @type {PIXI.ColorMatrixFilter} */
      #colorMatrixFilter;
      shaderFlags = new foundry.utils.BitMask({
        isTiling: false,
        isVisionMaskingEnabled: true,
        isColorMatrixEnabled: false
      });
      /**
       * @param {PIXI.Texture} texture - The {@link PIXI.Texture} bound to this mesh
       * @param {object} [options = {}]
       * @property {typeof BaseSamplerShader} options.shaderClassader Shader class used by this sprite mesh.
       * @property {boolean} options.tiling Shader class used by this sprite mesh.
       * @property {boolean} options.isVisionMaskingEnabled Shader class used by this sprite mesh.
       */
      constructor(texture, { shaderClass = VisionSamplerShader, tiling = false, isVisionMaskingEnabled = true } = {}) {
        super(texture, shaderClass);
        this.tileTransform = new PIXI.Transform();
        this.tiling = tiling;
        this.isVisionMaskingEnabled = isVisionMaskingEnabled;
        this.uvMatrix = this.texture.uvMatrix || new PIXI.TextureMatrix(texture);
      }
      get tiling() {
        return this.shaderFlags.hasState("isTiling");
      }
      /**
       * @param {boolean} value
       */
      set tiling(value) {
        this.shaderFlags.toggleState("isTiling", value);
      }
      get isVisionMaskingEnabled() {
        return this.shaderFlags.hasState("isVisionMaskingEnabled");
      }
      /**
       * @param {boolean} value
       */
      set isVisionMaskingEnabled(value) {
        this.shaderFlags.toggleState("isVisionMaskingEnabled", value);
      }
      /**
       * @param {PIXI.ColorMatrixFilter | null} value
       */
      set colorMatrixFilter(value) {
        this.shaderFlags.toggleState("isColorMatrixEnabled", value != null);
        this.#colorMatrixFilter = value;
      }
      get colorMatrixFilter() {
        return this.#colorMatrixFilter;
      }
      /** The scaling of the image that is being tiled. */
      get tileScale() {
        return this.tileTransform.scale;
      }
      set tileScale(value) {
        this.tileTransform.scale.copyFrom(value);
      }
      /** The offset of the image that is being tiled. */
      get tilePosition() {
        return this.tileTransform.position;
      }
      set tilePosition(value) {
        this.tileTransform.position.copyFrom(value);
      }
      _onTextureUpdate() {
        super._onTextureUpdate();
        if (this.uvMatrix) {
          this.uvMatrix.texture = this._texture;
        }
      }
      /**
       * Renders the object using the WebGL renderer
       * @param renderer - The renderer
       */
      _render(renderer) {
        this.uvMatrix.update();
        this.tileTransform.updateLocalTransform();
        super._render(renderer);
      }
      destroy() {
        super.destroy();
        this.tileTransform = null;
        this.uvMatrix = null;
      }
    }
    class AnimatedSpriteMesh extends TilingSpriteMesh {
      /**
       * @param textures - An array of {@link PIXI.Texture} or frame
       *  objects that make up the animation.
       * @param {object} [options = {}]
       * @property {typeof BaseSamplerShader} options.shaderClassader Shader class used by this sprite mesh.
       * @property {boolean} options.tiling Shader class used by this sprite mesh.
       * @property {boolean} options.isVisionMaskingEnabled Shader class used by this sprite mesh.
       */
      constructor(textures, { autoUpdate = true, shaderClass = VisionSamplerShader, isVisionMaskingEnabled = true, tiling } = {}) {
        const texture = textures[0] instanceof PIXI.Texture ? textures[0] : textures[0].texture;
        super(texture, { shaderClass, tiling, isVisionMaskingEnabled });
        this._textures = [];
        this._durations = null;
        this._autoUpdate = autoUpdate;
        this._isConnectedToTicker = false;
        this.animationSpeed = 1;
        this.loop = true;
        this.updateAnchor = false;
        this.onComplete = null;
        this.onFrameChange = null;
        this.onLoop = null;
        this._currentTime = 0;
        this._playing = false;
        this._previousFrame = null;
        this.textures = textures;
      }
      /** Stops the AnimatedSprite. */
      stop() {
        if (!this._playing) {
          return;
        }
        this._playing = false;
        if (this._autoUpdate && this._isConnectedToTicker) {
          PIXI.Ticker.shared.remove(this.update, this);
          this._isConnectedToTicker = false;
        }
      }
      /** Plays the AnimatedSprite. */
      play() {
        if (this._playing) {
          return;
        }
        this._playing = true;
        if (this._autoUpdate && !this._isConnectedToTicker) {
          PIXI.Ticker.shared.add(this.update, this, PIXI.UPDATE_PRIORITY.HIGH);
          this._isConnectedToTicker = true;
        }
      }
      /**
       * Stops the AnimatedSprite and goes to a specific frame.
       * @param frameNumber - Frame index to stop at.
       */
      gotoAndStop(frameNumber) {
        this.stop();
        this.currentFrame = frameNumber;
      }
      /**
       * Goes to a specific frame and begins playing the AnimatedSprite.
       * @param frameNumber - Frame index to start at.
       */
      gotoAndPlay(frameNumber) {
        this.currentFrame = frameNumber;
        this.play();
      }
      /**
       * Updates the object transform for rendering.
       * @param deltaTime - Time since last tick.
       */
      update(deltaTime) {
        if (!this._playing) {
          return;
        }
        const elapsed = this.animationSpeed * deltaTime;
        const previousFrame = this.currentFrame;
        if (this._durations !== null) {
          let lag = this._currentTime % 1 * this._durations[this.currentFrame];
          lag += elapsed / 60 * 1e3;
          while (lag < 0) {
            this._currentTime--;
            lag += this._durations[this.currentFrame];
          }
          const sign = Math.sign(this.animationSpeed * deltaTime);
          this._currentTime = Math.floor(this._currentTime);
          while (lag >= this._durations[this.currentFrame]) {
            lag -= this._durations[this.currentFrame] * sign;
            this._currentTime += sign;
          }
          this._currentTime += lag / this._durations[this.currentFrame];
        } else {
          this._currentTime += elapsed;
        }
        if (this._currentTime < 0 && !this.loop) {
          this.gotoAndStop(0);
          if (this.onComplete) {
            this.onComplete();
          }
        } else if (this._currentTime >= this._textures.length && !this.loop) {
          this.gotoAndStop(this._textures.length - 1);
          if (this.onComplete) {
            this.onComplete();
          }
        } else if (previousFrame !== this.currentFrame) {
          if (this.loop && this.onLoop) {
            if (this.animationSpeed > 0 && this.currentFrame < previousFrame || this.animationSpeed < 0 && this.currentFrame > previousFrame) {
              this.onLoop();
            }
          }
          this.updateTexture();
        }
      }
      /** Updates the displayed texture to match the current frame index. */
      updateTexture() {
        const currentFrame = this.currentFrame;
        if (this._previousFrame === currentFrame) {
          return;
        }
        this._previousFrame = currentFrame;
        this._texture = this._textures[currentFrame];
        this._textureID = -1;
        this._textureTrimmedID = -1;
        this._cachedTint = [1, 1, 1, 1];
        this.uvs.set(this._texture._uvs.uvsFloat32);
        if (this.updateAnchor) {
          this._anchor.copyFrom(this._texture.defaultAnchor);
        }
        if (this.onFrameChange) {
          this.onFrameChange(this.currentFrame);
        }
        if (this.uvMatrix) {
          this.uvMatrix.texture = this._texture;
        }
      }
      destroy(options) {
        this.stop();
        super.destroy(options);
        this.onComplete = null;
        this.onFrameChange = null;
        this.onLoop = null;
      }
      /**
       * A short hand way of creating an AnimatedSprite from an array of frame ids.
       * @param frames - The array of frames ids the AnimatedSprite will use as its texture frames.
       * @returns - The new animated sprite with the specified frames.
       */
      static fromFrames(frames) {
        const textures = [];
        for (let i = 0; i < frames.length; ++i) {
          textures.push(PIXI.Texture.from(frames[i]));
        }
        return new AnimatedSprite(textures);
      }
      /**
       * A short hand way of creating an AnimatedSprite from an array of image ids.
       * @param images - The array of image urls the AnimatedSprite will use as its texture frames.
       * @returns The new animate sprite with the specified images as frames.
       */
      static fromImages(images) {
        const textures = [];
        for (let i = 0; i < images.length; ++i) {
          textures.push(PIXI.Texture.from(images[i]));
        }
        return new AnimatedSprite(textures);
      }
      /**
       * The total number of frames in the AnimatedSprite. This is the same as number of textures
       * assigned to the AnimatedSprite.
       * @readonly
       * @default
       */
      get totalFrames() {
        return this._textures.length;
      }
      /** The array of textures used for this AnimatedSprite. */
      get textures() {
        return this._textures;
      }
      set textures(value) {
        if (value[0] instanceof PIXI.Texture) {
          this._textures = value;
          this._durations = null;
        } else {
          this._textures = [];
          this._durations = [];
          for (let i = 0; i < value.length; i++) {
            this._textures.push(value[i].texture);
            this._durations.push(value[i].time);
          }
        }
        this._previousFrame = null;
        this.gotoAndStop(0);
        this.updateTexture();
      }
      /** The AnimatedSprite's current frame index. */
      get currentFrame() {
        let currentFrame = Math.floor(this._currentTime) % this._textures.length;
        if (currentFrame < 0) {
          currentFrame += this._textures.length;
        }
        return currentFrame;
      }
      set currentFrame(value) {
        if (value < 0 || value > this.totalFrames - 1) {
          throw new Error(
            `[AnimatedSprite]: Invalid frame index value ${value}, expected to be between 0 and totalFrames ${this.totalFrames}.`
          );
        }
        const previousFrame = this.currentFrame;
        this._currentTime = value;
        if (previousFrame !== this.currentFrame) {
          this.updateTexture();
        }
      }
      /**
       * Indicates if the AnimatedSprite is currently playing.
       * @readonly
       */
      get playing() {
        return this._playing;
      }
      /** Whether to use Ticker.shared to auto update animation time. */
      get autoUpdate() {
        return this._autoUpdate;
      }
      set autoUpdate(value) {
        if (value !== this._autoUpdate) {
          this._autoUpdate = value;
          if (!this._autoUpdate && this._isConnectedToTicker) {
            PIXI.Ticker.shared.remove(this.update, this);
            this._isConnectedToTicker = false;
          } else if (this._autoUpdate && !this._isConnectedToTicker && this._playing) {
            PIXI.Ticker.shared.add(this.update, this);
            this._isConnectedToTicker = true;
          }
        }
      }
    }
    class Asset {
      destroy() {
      }
    }
    class TextureAsset extends Asset {
      filepath;
      texture;
      constructor({ filepath, texture }) {
        super();
        this.filepath = filepath;
        this.texture = texture;
      }
    }
    class VideoAsset extends Asset {
      /** @type {string} */
      filepath;
      /** @type {PIXI.Texture} */
      texture;
      /** @type {HTMLVideoElement  } */
      video;
      /**
       *
       * @param {object} params
       * @param {string} params.filepath
       * @param {PIXI.Texture} params.texture
       * @param {HTMLVideoElement} params.video
       */
      constructor({ filepath, texture, video }) {
        super();
        this.filepath = filepath;
        this.texture = texture;
        this.video = video;
      }
      destroy() {
        try {
          this.video.pause();
          URL.revokeObjectURL(this.video.src);
          this.video.removeAttribute("src");
          this.video.onerror = null;
          this.video.oncanplay = null;
          this.video.load();
          this.video = null;
        } catch (err) {
        }
        this.texture.destroy(true);
      }
    }
    class VideoSpritesheetAsset extends Asset {
      /** @type {string} */
      filepath;
      /** @type {PIXI.Spritesheet} */
      spritesheet;
      /** @type {PIXI.FrameObject[]} */
      frameObjects;
      /** @type {number} */
      framerate;
      /**
       * @param {object} params
       * @param {string} params.filepath
       * @param {PIXI.Spritesheet} params.spritesheet
       */
      constructor({ filepath, spritesheet }) {
        super();
        this.filepath = filepath;
        this.spritesheet = spritesheet;
        this.framerate = this.spritesheet.data?.meta?.frameRate ?? 30;
        const frametime = 1 / this.framerate * 1e3;
        this.frameObjects = (Object.values(spritesheet.animations)[0] ?? []).map((texture) => ({
          texture,
          time: frametime
        }));
        this.#register();
      }
      destroy() {
        return SequencerFileCache.unloadSpritesheet(this.filepath);
      }
      #register() {
        SequencerFileCache.registerSpritesheet(this.filepath, this.spritesheet);
      }
    }
    class FlipbookAsset extends Asset {
      /** @type {string[]} */
      filepaths;
      /** @type {PIXI.FrameObject[]} */
      frameObjects;
      /** @type {number} */
      framerate;
      /**
       * @param {object} params
       * @param {string[]} params.filepaths
       * @param {PIXI.Texture[]} params.textures
       * @param {number} params.framerate
       */
      constructor({ filepaths, textures, framerate = 24 }) {
        super();
        this.filepaths = filepaths;
        this.framerate = framerate;
        const frametime = 1 / framerate * 1e3;
        this.frameObjects = textures.map((texture) => ({ texture, time: frametime }));
      }
      destroy() {
      }
    }
    class PlaybackControls {
      destroy() {
      }
    }
    class VideoPlaybackControls extends PlaybackControls {
      /** @type {HTMLVideoElement} */
      #video;
      /** @type {PIXI.Texture} */
      #texture;
      /**
       * @param {HTMLVideoElement} video
       * @param {PIXI.Texture} texture
       */
      constructor(video, texture) {
        super();
        this.#video = video;
        this.#texture = texture;
      }
      async play() {
        try {
          await this.#video.play();
          this.#texture.update();
        } catch (error) {
        }
      }
      stop() {
        this.#video.pause();
      }
      get duration() {
        return this.#video.duration;
      }
      get isPlaying() {
        return !this.#video.paused;
      }
      get loop() {
        return this.#video.loop;
      }
      set loop(value) {
        this.#video.loop = value;
      }
      get volume() {
        return this.#video.volume;
      }
      set volume(value) {
        this.#video.muted = !value;
        this.#video.volume = value;
      }
      get currentTime() {
        return this.#video.currentTime;
      }
      set currentTime(value) {
        this.#video.currentTime = value;
      }
      get playbackRate() {
        return this.#video.playbackRate;
      }
      set playbackRate(value) {
        this.#video.playbackRate = value;
      }
      destroy() {
        this.stop();
        this.#video = null;
        this.#texture = null;
      }
    }
    class SpritePlaybackControls extends PlaybackControls {
      /** @type {AnimatedSpriteMesh} */
      #sprite;
      /** @type {number} */
      #framerate;
      /** @type {number} */
      #framecount;
      /**
       * @param {AnimatedSpriteMesh} sprite
       * @param {number} framerate
       * @param {number} framecount
       */
      constructor(sprite, framerate, framecount) {
        super();
        this.#sprite = sprite;
        this.#framerate = framerate;
        this.#framecount = framecount;
      }
      async play() {
        this.#sprite.play();
      }
      stop() {
        this.#sprite.stop();
      }
      get duration() {
        return this.#framecount / this.#framerate;
      }
      get isPlaying() {
        return this.#sprite.playing;
      }
      get loop() {
        return this.#sprite.loop;
      }
      set loop(value) {
        this.#sprite.loop = value;
      }
      get volume() {
        return 0;
      }
      set volume(_value) {
      }
      get currentTime() {
        const accurateTime = (this.#sprite.currentFrame + 1) / this.#framerate;
        return Math.round(accurateTime * 1e3) / 1e3;
      }
      set currentTime(value) {
        const newFrame = Math.floor(value * this.#framerate);
        const newFrameIndex = Math.clamp(newFrame, 0, this.#framecount - 1);
        if (this.#sprite.playing) {
          this.#sprite.gotoAndPlay(newFrameIndex);
        } else {
          this.#sprite.gotoAndStop(newFrameIndex);
        }
      }
      get playbackRate() {
        return this.#sprite.animationSpeed;
      }
      set playbackRate(value) {
        this.#sprite.animationSpeed = value;
      }
      destroy() {
        this.stop();
        this.#sprite = null;
      }
    }
    class SequencerSpriteManager extends PIXI.Container {
      // @ts-ignore
      #id = foundry.utils.randomID();
      /** @type {import("../modules/sequencer-file.js").SequencerFile} */
      #file;
      /** @type {{ antialiasing: PIXI.SCALE_MODES; tiling?: boolean; xray?: boolean; isPersisted: boolean }} */
      #sharedSpriteConfig;
      /** @type {string | undefined} */
      #activeAssetPath;
      /** @type {Map<string | undefined, VideoAsset | VideoSpritesheetAsset | TextureAsset | FlipbookAsset>} */
      #relatedAssets = /* @__PURE__ */ new Map();
      /** @type {VideoPlaybackControls | SpritePlaybackControls | null} */
      #playbackControls;
      /** @type {Promise<void> | undefined} */
      #preloadingPromise;
      /** @type {TilingSpriteMesh | null} */
      #managedSprite;
      /** @type {PIXI.Text | null} */
      #textSprite;
      /** @type {{width: number, height: number, scaleX: number, scaleY: number}} */
      #defaultScaling = {
        width: 0,
        height: 0,
        scaleX: 1,
        scaleY: 1
      };
      get preloadingPromise() {
        if (this.#preloadingPromise) {
          return this.#preloadingPromise;
        }
        return Promise.resolve();
      }
      /**
       * @param {import("../modules/sequencer-file.js").SequencerFile} file
       * @param {{ antialiasing: PIXI.SCALE_MODES; tiling?: boolean; xray?: boolean; isPersisted: boolean }} options
       */
      constructor(file, options) {
        super();
        this.#sharedSpriteConfig = options ?? {
          antialiasing: PIXI.SCALE_MODES.LINEAR,
          tiling: false,
          xray: false,
          isPersisted: false
        };
        this.#file = file;
      }
      //#region public api
      get activePath() {
        return this.#activeAssetPath;
      }
      get activeAsset() {
        return this.#relatedAssets.get(this.activePath);
      }
      get texture() {
        return this.managedSprite?.texture;
      }
      get managedSprite() {
        return this.#managedSprite;
      }
      /** @return {PreciseText | null} */
      get textSprite() {
        return this.#textSprite;
      }
      /**
       * caches current scaling values to be used for spritesheet scaling if needed
       */
      updateDefaultScaling() {
        this.#defaultScaling = {
          scaleX: this.scale.x,
          scaleY: this.scale.y,
          width: this.width,
          height: this.height
        };
      }
      updateVideoTextures() {
        this.#managedSprite?.texture?.update();
      }
      /**
       * @param {string | undefined} filePath
       */
      async activate(filePath) {
        if (!filePath || this.#activeAssetPath === filePath) {
          return;
        }
        let nextAsset = this.#relatedAssets.get(filePath);
        if (this.#relatedAssets.has(filePath) && nextAsset == null) {
          return;
        }
        if (!nextAsset) {
          this.#relatedAssets[filePath] = void 0;
          nextAsset = await this.#loadAsset(filePath);
          if (this.destroyed) {
            return;
          }
          this.#relatedAssets.set(filePath, nextAsset);
        }
        if (this.#activateAsset(nextAsset)) {
          this.#activeAssetPath = filePath;
        }
        if (this.#sharedSpriteConfig.isPersisted && !this.#sharedSpriteConfig.tiling) {
          requestAnimationFrame(async () => {
            const minimumScale = this.#calculateMinimumSpritesheetScale();
            const spritesheet = await SequencerFileCache.requestCompiledSpritesheet(filePath, {
              minimumScale
            });
            if (!spritesheet) {
              return;
            }
            const previousAsset = this.activeAsset;
            const asset = new VideoSpritesheetAsset({ filepath: filePath, spritesheet });
            this.#relatedAssets.set(filePath, asset);
            if (this.destroyed || this.#activeAssetPath !== filePath) {
              return;
            }
            this.#activateAsset(asset);
            previousAsset?.destroy();
          });
        }
      }
      /**
       * @param {{ text: string | null; textStyle: Partial<PIXI.ITextStyle> | PIXI.TextStyle }} textData
       */
      addText(textData) {
        if (this.#textSprite) {
          this.#textSprite.text = textData.text ?? "";
          return this.#textSprite;
        }
        const textSprite = new PreciseText(textData.text ?? "", textData.textStyle);
        textSprite.resolution = 5;
        textSprite.zIndex = 1;
        textSprite.anchor.set(0.5, 0.5);
        this.#textSprite = textSprite;
        return this.addChild(textSprite);
      }
      removeText() {
        this.#textSprite?.destroy();
        this.#textSprite = null;
      }
      /**
       * @param {string | number} filepath
       */
      removeSprite(filepath) {
        this.#relatedAssets[filepath]?.destroy();
        delete this.#relatedAssets[filepath];
      }
      async preloadVariants() {
        if (!this.#preloadingPromise) {
          return this.#preloadingPromise = this.#preloadVariants();
        }
        return this.#preloadingPromise;
      }
      destroy() {
        this.#playbackControls?.destroy();
        for (const asset of this.#relatedAssets.values()) {
          asset?.destroy();
        }
        this.#relatedAssets.clear();
        this.managedSprite?.removeFromParent();
        this.managedSprite?.destroy();
        super.destroy({ children: true });
      }
      //#endregion
      //#region Managed Sprite proxies
      async play() {
        this.#playbackControls?.play();
      }
      stop() {
        this.#playbackControls?.stop();
      }
      get tileScale() {
        return this.managedSprite?.tileScale;
      }
      set tileScale(point) {
        if (point) {
          this.managedSprite?.tileScale.copyFrom(point);
        }
      }
      get tilePosition() {
        return this.managedSprite?.tilePosition;
      }
      set tilePosition(point) {
        if (point) {
          this.managedSprite?.tilePosition.copyFrom(point);
        }
      }
      get anchor() {
        return this.managedSprite?.anchor;
      }
      set anchor(point) {
        if (point) {
          this.managedSprite?.anchor.copyFrom(point);
        }
      }
      get tint() {
        return this.managedSprite?.tint ?? 16777215;
      }
      set tint(value) {
        if (this.managedSprite) {
          this.managedSprite.tint = typeof value === "number" ? Math.floor(value) : value;
        }
      }
      get scale() {
        return this.managedSprite?.scale || super.scale;
      }
      set scale(point) {
        this.managedSprite?.scale.copyFrom(point);
      }
      get width() {
        return this.managedSprite?.width ?? 0;
      }
      set width(value) {
        if (!this.managedSprite) {
          return;
        }
        this.managedSprite.width = value;
      }
      get height() {
        return this.managedSprite?.height ?? 0;
      }
      set height(value) {
        if (!this.managedSprite) {
          return;
        }
        this.managedSprite.height = value;
      }
      get resolution() {
        return this.#textSprite?.resolution;
      }
      set resolution(value) {
        if (!this.#textSprite) return;
        this.#textSprite.resolution = value ?? 5;
      }
      /** @type {} */
      get hasAnimatedMedia() {
        return this.activeAsset instanceof VideoAsset || this.activeAsset instanceof VideoSpritesheetAsset || this.activeAsset instanceof FlipbookAsset;
      }
      get playing() {
        return this.#playbackControls?.isPlaying ?? false;
      }
      get duration() {
        return this.#playbackControls?.duration ?? 0;
      }
      get volume() {
        return this.#playbackControls?.volume ?? 0;
      }
      set volume(value) {
        if (!this.#playbackControls) return;
        this.#playbackControls.volume = value;
      }
      get loop() {
        return this.#playbackControls?.loop ?? false;
      }
      set loop(value) {
        if (!this.#playbackControls) return;
        this.#playbackControls.loop = value;
      }
      get currentTime() {
        return this.#playbackControls?.currentTime ?? 0;
      }
      set currentTime(value) {
        if (!this.#playbackControls) return;
        this.#playbackControls.currentTime = value;
      }
      get playbackRate() {
        return this.#playbackControls?.playbackRate ?? 1;
      }
      set playbackRate(value) {
        if (!this.#playbackControls) return;
        this.#playbackControls.playbackRate = value;
      }
      /** @return {PIXI.ColorMatrixFilter | null} */
      get colorMatrixFilter() {
        return this.managedSprite?.colorMatrixFilter ?? null;
      }
      set colorMatrixFilter(value) {
        if (!this.managedSprite) return;
        this.managedSprite.colorMatrixFilter = value;
        if (this.#textSprite) {
          if (value) {
            this.#textSprite.filters?.push(value);
          } else if (this.#textSprite.filters) {
            this.#textSprite.filters = this.#textSprite.filters.filter(
              (filter2) => !(filter2 instanceof PIXI.ColorMatrixFilter)
            );
          }
        }
      }
      async #preloadVariants() {
        if (this.#activeAssetPath === "TEXT") {
          return;
        }
        if (!this.#file || this.#file.isFlipbook) {
          return;
        }
        const allFiles = this.#file.getAllFiles();
        for (const filePath of allFiles) {
          if (this.#relatedAssets[filePath]) {
            continue;
          }
          const asset = await this.#loadAsset(filePath);
          this.#relatedAssets.set(filePath, asset);
        }
      }
      /**
       * @param {string} filepath
       */
      async #loadAsset(filepath) {
        if (this.#file && this.#file.isFlipbook) {
          return this.#loadFlipbook(this.#file.getAllFiles(), this.#file.originalMetadata);
        }
        const texture = await SequencerFileCache.loadFile(filepath);
        if (texture?.baseTexture?.resource instanceof PIXI.CompressedTextureResource && texture?.baseTexture?.resource.levels === 1) {
          texture?.baseTexture?.setStyle(0, 0);
        } else if (this.#sharedSpriteConfig.antialiasing && this.#sharedSpriteConfig.antialiasing !== PIXI.SCALE_MODES.LINEAR) {
          texture?.baseTexture.setStyle(0, this.#sharedSpriteConfig.antialiasing);
        }
        if (texture instanceof PIXI.Spritesheet) {
          return new VideoSpritesheetAsset({ filepath, spritesheet: texture });
        }
        if (texture.baseTexture?.resource?.source instanceof HTMLVideoElement) {
          return new VideoAsset({ filepath, texture, video: texture.baseTexture.resource.source });
        }
        return new TextureAsset({ filepath, texture });
      }
      /**
       * @param {string[]} filepaths
       * @param {{ fps: number; }} metadata
       */
      async #loadFlipbook(filepaths, metadata) {
        const textures = (await Promise.all(filepaths.map(async (filepath) => FoundryShim.loadTexture(filepath)))).filter(
          (t) => t instanceof PIXI.Texture
        );
        return new FlipbookAsset({ filepaths, textures, framerate: metadata?.fps ?? 24 });
      }
      /**
       * @param {VideoAsset | VideoSpritesheetAsset | TextureAsset | FlipbookAsset} nextAsset
       * @returns
       */
      #activateAsset(nextAsset) {
        let view;
        let controls;
        const tiling = this.#sharedSpriteConfig.tiling;
        const isVisionMaskingEnabled = !this.#sharedSpriteConfig.xray;
        if (nextAsset instanceof VideoAsset) {
          view = new TilingSpriteMesh(nextAsset.texture, { isVisionMaskingEnabled, tiling });
          controls = new VideoPlaybackControls(nextAsset.video, nextAsset.texture);
        } else if (nextAsset instanceof VideoSpritesheetAsset || nextAsset instanceof FlipbookAsset) {
          view = new AnimatedSpriteMesh(nextAsset.frameObjects, {
            autoUpdate: true,
            isVisionMaskingEnabled,
            tiling: !!tiling
          });
          controls = new SpritePlaybackControls(view, nextAsset.framerate, nextAsset.frameObjects.length);
        } else if (nextAsset instanceof TextureAsset) {
          view = new TilingSpriteMesh(nextAsset.texture, { isVisionMaskingEnabled, tiling });
          controls = null;
        } else {
          return false;
        }
        this.#applyPreviousValues(view, controls);
        if (this.#playbackControls) {
          this.#playbackControls.destroy();
        } else {
          controls?.play();
        }
        this.#playbackControls = controls;
        if (this.managedSprite) {
          this.managedSprite.removeFromParent();
          this.managedSprite.destroy();
        }
        this.#managedSprite = view;
        this.addChildAt(view, 0);
        return true;
      }
      /**
       *
       * @param {TilingSpriteMesh} view
       * @param {VideoPlaybackControls | SpritePlaybackControls | null} controls
       */
      #applyPreviousValues(view, controls) {
        if (this.managedSprite) {
          const prev = this.managedSprite;
          view.tint = prev.tint;
          view.anchor.copyFrom(prev.anchor);
          view.scale.copyFrom(prev.scale);
          view.width = prev.width;
          view.height = prev.height;
          view.tileScale.copyFrom(prev.tileScale);
          view.tilePosition.copyFrom(prev.tilePosition);
          view.pivot.copyFrom(prev.pivot);
          view.skew.copyFrom(prev.skew);
          view.alpha = prev.alpha;
          view.colorMatrixFilter = prev.colorMatrixFilter;
          view.position.copyFrom(prev.position);
          view.alphaMode = prev.alphaMode;
          view.blendMode = prev.blendMode;
          view.cullable = prev.cullable;
          view.renderable = prev.renderable;
          view.visible = prev.visible;
          view.tiling = prev.tiling;
        }
        if (controls && this.#playbackControls) {
          const prev = this.#playbackControls;
          controls.volume = prev.volume;
          controls.loop = prev.loop;
          controls.playbackRate = prev.playbackRate;
          controls.currentTime = prev.currentTime;
          if (prev.isPlaying) {
            controls.play();
          } else {
            controls.stop();
          }
        }
      }
      /**
       * calculates the minimum scale required for generated spritesheets
       * @returns {number}
       */
      #calculateMinimumSpritesheetScale() {
        const defaultScale = this.#defaultScaling;
        const maxScale = Math.max(defaultScale.scaleX || 1, defaultScale.scaleY || 1);
        return Math.min(maxScale, 1);
      }
    }
    class CrosshairsPlaceable extends FoundryShim.MeasuredTemplate {
      constructor(...args) {
        super(...args);
        this.tag = "sequencer-crosshair-" + foundry.utils.randomID();
        this.cachedLocation = false;
      }
      #handlers = {
        mouseup: null,
        move: null,
        wheel: null
      };
      #promise = {
        resolve: null
      };
      #isDrag = false;
      #isPanning = false;
      #customText = false;
      #distanceText = false;
      #rangeHighlight = false;
      isValid = true;
      #lastPositions = false;
      get crosshair() {
        return this.document.crosshair;
      }
      get callbacks() {
        return this.document.callbacks;
      }
      get range() {
        const objLocation = this.crosshair.location.obj?.center ?? this.crosshair.location.obj;
        return canvas.grid.measurePath([objLocation, this.position]).distance;
      }
      updateCrosshair(data) {
        this.document.crosshair = foundry.utils.mergeObject(this.document.crosshair, data);
        if (this.#customText) {
          this.#customText.destroy();
          this.#customText = null;
        }
        if (this.#distanceText) {
          this.#distanceText.destroy();
          this.#distanceText = null;
        }
        if (this.#rangeHighlight) {
          this.#rangeHighlight.destroy();
          this.#rangeHighlight = null;
        }
        return this.draw();
      }
      async #refreshIcon() {
        this.controlIcon.renderable = !!this.crosshair.icon.texture;
        if (this.crosshair.icon.texture) {
          this.controlIcon.iconSrc = this.crosshair.icon.texture;
          this.controlIcon.texture = await FoundryShim.loadTexture(this.controlIcon.iconSrc);
          this.controlIcon.icon.texture = this.controlIcon.texture;
        }
        if (!this.crosshair.icon.borderVisible) {
          this.controlIcon.bg.clear();
        }
      }
      _refreshRulerText() {
        const shapeWidth = this.shape.width ?? 0;
        const shapeHeight = this.shape.height ?? 0;
        if (this.crosshair.location.showRange && this.crosshair.location.obj) {
          if (!this.#distanceText && this.crosshair.location.obj) {
            const style = CONFIG.canvasTextStyle.clone();
            style.align = "center";
            this.#distanceText = this.template.addChild(new PreciseText("", style));
          }
          const actualHeight = (this.shapeHeight || this.shape.radius) + canvas.grid.size / 2;
          this.#distanceText.anchor.set(0.5, 0.5);
          this.#distanceText.position.set(shapeWidth / 2, actualHeight);
          const { units } = this.document.parent.grid;
          this.#distanceText.text = this.range.toString() + " " + units;
        }
        this.ruler.renderable = !!this.crosshair.label?.text;
        if (!this.ruler.renderable) return;
        if (this.crosshair.label?.text) {
          if (!this.#customText) {
            const style = CONFIG.canvasTextStyle.clone();
            style.align = "center";
            this.#customText = this.template.addChild(new PreciseText("", style));
          }
          if (this.#customText.text !== this.crosshair.label.text) this.#customText.text = this.crosshair.label.text;
          this.#customText.anchor.set(0.5);
          this.#customText.position.set(
            shapeWidth / 2 + this.crosshair.label.dx,
            shapeHeight / 2 + this.crosshair.label.dy
          );
        } else {
          if (this.#customText) {
            this.#customText.text = "";
            this.#customText.destroy();
            this.#customText = null;
          }
          return super._refreshRulerText();
        }
      }
      _refreshTemplate() {
        const t = this.template.clear();
        t.lineStyle(this._borderThickness, this.document.borderColor, this.crosshair.borderAlpha).beginFill(0, 0);
        if (this.texture) {
          const d = canvas.dimensions;
          let { direction, distance } = this.document;
          distance *= d.size / d.distance;
          const textureAlpha = this.crosshair.textureAlpha || 0.5;
          let textureScale = this.crosshair.textureScale || 1;
          let textureSize = distance * textureScale;
          let xScale = 1;
          let yScale = 1;
          let xOffset = 0;
          let yOffset = 0;
          switch (this.document.t) {
            case "circle":
              xOffset = yOffset = textureSize;
              xScale = yScale = textureSize * 2 / this.texture.width;
              break;
            case "cone":
              textureSize /= 2;
              yOffset = -textureSize;
              xScale = yScale = textureSize * 2 / this.texture.width;
              break;
            case "rect":
              xScale = textureSize * Math.cos(Math.toRadians(direction)) / this.texture.width;
              yScale = textureSize * Math.sin(Math.toRadians(direction)) / this.texture.height;
              textureSize /= 2;
              direction = 0;
              break;
            case "ray":
              yOffset = this.document.width / d.distance * d.size / 2;
              xScale = textureSize / this.texture.width;
              yScale = textureSize / this.texture.height;
              yScale *= this.document.width / this.document.distance;
              break;
          }
          t.beginTextureFill({
            texture: this.texture,
            matrix: new PIXI.Matrix().scale(xScale, yScale).translate(xOffset, yOffset).rotate(Math.toRadians(direction)),
            alpha: textureAlpha
          });
        } else {
          t.beginFill(0, 0);
        }
        t.drawShape(this.shape);
        if (!this.crosshair.lockDrag) {
          t.lineStyle(this._borderThickness, 0).beginFill(0, 0.5).drawCircle(0, 0, 6).drawCircle(this.ray.dx, this.ray.dy, 6).endFill();
        }
      }
      #refreshRangeHighlight() {
        const loc = this.crosshair.location;
        if (!loc.displayRangePoly || !loc.obj || loc.limitMaxRange === null) return;
        if (this.#rangeHighlight) {
          this.#rangeHighlight.clear();
        } else {
          this.#rangeHighlight = new PIXI.Graphics();
          canvas.tokens.addChild(this.#rangeHighlight);
          this.#rangeHighlight.zIndex = -1;
          this.#rangeHighlight.interactive = false;
          canvas.tokens.sortChildren();
        }
        const object = loc.obj;
        const position = {
          x: object?.center?.x ?? object?.position?.x ?? object?.x,
          y: object?.center?.y ?? object?.position?.y ?? object?.y
        };
        const defaultSize = canvas.dimensions.distancePixels;
        const { w, h } = object;
        const distance = loc.limitMaxRange + Math.max(w ?? defaultSize, h ?? defaultSize) / 2 / canvas.dimensions.distancePixels;
        this.#rangeHighlight.beginFill(loc.rangePolyFillColor ?? 16777215, clamp$1(loc.rangePolyFillAlpha ?? 0.25, 0, 1)).lineStyle(2, loc.rangePolyLineColor ?? 16711680, clamp$1(loc.rangePolyLineAlpha ?? 0.5, 0, 1)).drawPolygon(canvas.grid.getCircle(position, distance));
      }
      async show() {
        await this.draw();
        this.layer.addChild(this);
        this.oldInteractiveChildren = this.layer.interactiveChildren;
        this.layer.interactiveChildren = false;
        this.#updateLocation();
        this.#refreshRangeHighlight();
        this.#runCallback(CONSTANTS.CALLBACKS.SHOW, this);
        return this.#activateShowListeners();
      }
      async #activateShowListeners() {
        return new Promise((resolve) => {
          this.#promise.resolve = resolve;
          this.#handlers.move = this.#onMove.bind(this);
          this.#handlers.mouseup = this.#onMouseUp.bind(this);
          this.#handlers.wheel = this.#onWheel.bind(this);
          canvas.stage.on("mousemove", this.#handlers.move);
          canvas.stage.on("pointerup", this.#handlers.mouseup);
          canvas.app.view.onwheel = this.#handlers.wheel;
        });
      }
      #getSnappedPoint(point, mode = this.crosshair.snap.position, resolution = this.crosshair.snap.resolution) {
        resolution = !resolution || resolution <= 0 ? canvas.grid.size : resolution;
        return canvas.grid.getSnappedPoint(point, { mode, resolution });
      }
      #onMove(evt) {
        const now2 = Date.now();
        const leftDown = (evt.buttons & 1) > 0;
        const rightDown = (evt.buttons & 2) > 0;
        this.#isDrag = !!(leftDown && canvas.mouseInteractionManager.isDragging);
        this.#isPanning = this.#isPanning || !!(rightDown && canvas.mouseInteractionManager.isDragging);
        if (this.#isPanning) return;
        if (this.#isDrag) {
          canvas.mouseInteractionManager.cancel(evt);
        }
        evt.preventDefault();
        if (now2 - this.moveTime <= 20) return;
        const moved = this.#updateLocation();
        this.#runCallback(CONSTANTS.CALLBACKS.MOUSE_MOVE, this);
        if (moved) this.#runCallback(CONSTANTS.CALLBACKS.MOVE, this);
        this.#updateLineOfSight();
        this.refresh();
        this.moveTime = now2;
      }
      #updateLineOfSight() {
        if (!this.crosshair.location?.obj || this.crosshair.location?.wallBehavior === CONSTANTS.PLACEMENT_RESTRICTIONS.ANYWHERE) return;
        const object = this.crosshair.location.obj;
        const objLocation = {
          x: object?.center?.x ?? object?.position?.x ?? object?.x,
          y: object?.center?.y ?? object?.position?.y ?? object?.y
        };
        const location2 = { x: this.document.x, y: this.document.y };
        const exitEarly = this.#lastPositions && (this.#lastPositions.obj.x === objLocation.x && this.#lastPositions.obj.y === objLocation.y && this.#lastPositions.tgt.x === location2.x && this.#lastPositions.tgt.y === location2.y);
        this.#lastPositions = {
          obj: objLocation,
          tgt: location2
        };
        if (exitEarly) return;
        const type = this.crosshair.location?.wallBehavior === CONSTANTS.PLACEMENT_RESTRICTIONS.LINE_OF_SIGHT ? "sight" : "move";
        const collisions = CONFIG.Canvas.polygonBackends.sight.testCollision(objLocation, location2, {
          type,
          useThreshold: true
        });
        const wasValid = this.isValid;
        this.isValid = !collisions.length;
        if (!this.isValid && wasValid) {
          this.#runCallback(CONSTANTS.CALLBACKS.COLLIDE, this, collisions);
        } else if (this.isValid && !wasValid) {
          this.#runCallback(CONSTANTS.CALLBACKS.STOP_COLLIDING, this);
        }
      }
      #handleLockedEdge(mouseLocation) {
        let snappedMouseLocation = this.#getSnappedPoint(mouseLocation, CONST.GRID_SNAPPING_MODES.CENTER);
        const { lockToEdgeDirection } = this.crosshair.location;
        const placeable = this.crosshair.location.obj;
        const shape = placeable.getShape();
        const { w, h } = this.crosshair.location.obj;
        const shapePoints = shape?.points ?? [0, 0, w, 0, w, h, 0, h];
        const points = shapePoints.map((point, i) => {
          const worldCoord = i % 2 === 0 ? placeable.document.x : placeable.document.y;
          return point + worldCoord;
        });
        const centerPoint = placeable.getCenterPoint();
        const ray = new Ray(centerPoint, mouseLocation);
        let intersection;
        for (let i = 0; i < points.length; i += 2) {
          intersection = ray.intersectSegment([points[i], points[i + 1], points[i + 2 >= points.length ? 0 : i + 2], points[i + 3 >= points.length ? 1 : i + 3]]);
          if (intersection) break;
        }
        if (!intersection) return {};
        let snappedIntersection = this.#getSnappedPoint(intersection, CONST.GRID_SNAPPING_MODES.EDGE_MIDPOINT);
        if (canvas.scene.grid.type === CONST.GRID_TYPES.SQUARE) {
          const size = this.document.parent.grid.size;
          const left = snappedMouseLocation.x < points[0];
          const above = snappedMouseLocation.y < points[1];
          const right = snappedMouseLocation.x > points[2];
          const below = snappedMouseLocation.y > points[5];
          if ((left || right) && (below || above)) {
            snappedIntersection.x = left ? points[0] - size : right ? points[2] + size : snappedIntersection.x;
            snappedIntersection.y = above ? points[1] - size : right ? points[5] + size : snappedIntersection.y;
            if (above && left) {
              snappedIntersection.x = points[0];
              snappedIntersection.y = points[1];
            } else if (above && right) {
              snappedIntersection.x = points[2];
              snappedIntersection.y = points[3];
            } else if (below && right) {
              snappedIntersection.x = points[4];
              snappedIntersection.y = points[5];
            } else if (below && left) {
              snappedIntersection.x = points[6];
              snappedIntersection.y = points[7];
            }
          }
        }
        if (lockToEdgeDirection) {
          const lockedRay = Ray.towardsPoint(snappedIntersection, snappedMouseLocation, 2);
          const snappedDirection = this.#getSnappedPoint(lockedRay.B, CONST.GRID_SNAPPING_MODES.CENTER);
          snappedMouseLocation.x = snappedDirection.x;
          snappedMouseLocation.y = snappedDirection.y;
        }
        const { direction, distance } = this.#getDraggedMatrix(snappedIntersection, snappedMouseLocation);
        return {
          ...snappedIntersection,
          direction,
          distance
        };
      }
      #handleLimit(mouseLocation, targetLocation) {
        const ray = new Ray(targetLocation, mouseLocation);
        const gridPath = canvas.grid.measurePath([targetLocation, mouseLocation]);
        const limitMinRange = is_real_number(this.crosshair.location.limitMinRange) ? this.crosshair.location.limitMinRange : 0;
        const limitMaxRange = is_real_number(this.crosshair.location.limitMaxRange) ? this.crosshair.location.limitMaxRange : Infinity;
        let finalLocation = mouseLocation;
        if (gridPath.cost < limitMinRange) {
          finalLocation = canvas.grid.getTranslatedPoint(targetLocation, Math.toDegrees(ray.angle), limitMinRange);
        } else if (gridPath.cost > limitMaxRange) {
          finalLocation = canvas.grid.getTranslatedPoint(targetLocation, Math.toDegrees(ray.angle), limitMaxRange);
        }
        const snappedPosition = this.#getSnappedPoint(finalLocation);
        const { direction, distance } = this.#getDraggedMatrix(targetLocation, snappedPosition);
        return {
          ...snappedPosition,
          direction,
          distance
        };
      }
      #updateLocation() {
        let mouseLocation = get_mouse_position();
        mouseLocation.x += this.crosshair.location.offset.x ?? 0;
        mouseLocation.y += this.crosshair.location.offset.y ?? 0;
        let update2;
        if (this.crosshair.location.obj && (this.crosshair.location.lockToEdge || this.crosshair.location.limitMinRange || this.crosshair.location.limitMaxRange)) {
          const location2 = this.crosshair.location.obj;
          const targetLocation = {
            x: location2?.center?.x ?? location2?.position?.x ?? location2?.x,
            y: location2?.center?.y ?? location2?.position?.y ?? location2?.y
          };
          if (this.crosshair.location.lockToEdge) {
            update2 = this.#handleLockedEdge(mouseLocation);
          } else if (this.crosshair.location.limitMinRange || this.crosshair.location.limitMaxRange) {
            update2 = this.#handleLimit(mouseLocation, targetLocation);
          }
        } else if (this.#isDrag) {
          const { direction, distance } = this.#getDraggedMatrix(this.document, mouseLocation);
          update2 = { distance, direction };
        } else {
          const snappedPosition = this.#getSnappedPoint(mouseLocation);
          update2 = {
            x: snappedPosition.x,
            y: snappedPosition.y
          };
        }
        const isChanged = update2?.x !== void 0 && this.document.x !== update2.x || update2?.y !== void 0 && this.document.y !== update2.y || update2?.direction !== void 0 && this.document.direction !== update2.direction || update2?.distance !== void 0 && this.document.distance !== update2.distance;
        this.document.updateSource(update2);
        return isChanged;
      }
      #getDistance(dragDistance) {
        if (this.crosshair.distanceMin === null && this.crosshair.distanceMax === null) {
          return this.document.distance;
        }
        const min = this.crosshair.distanceMin ?? this.document.originalConfig.distance;
        const max = this.crosshair.distanceMax ?? this.document.originalConfig.distance;
        return Math.min(Math.max(0.5, dragDistance, min), max);
      }
      #getDraggedMatrix(source, target) {
        const dragAngle = new Ray(source, target).angle;
        const dragDistance = canvas.grid.measurePath([source, target]);
        const direction = this.crosshair.snap.direction ? Math.round(Math.toDegrees(dragAngle) / this.crosshair.snap.direction) * this.crosshair.snap.direction : Math.toDegrees(dragAngle);
        return {
          direction: direction || 0,
          distance: this.#getDistance(dragDistance.distance)
        };
      }
      #onMouseUp(evt) {
        const event = evt?.nativeEvent ?? evt;
        if (!(event.which === 1 || event.which === 3)) return;
        if (this.#isDrag) {
          this.#isDrag = false;
          return;
        }
        if (this.#isPanning) {
          this.#isPanning = false;
          return;
        }
        return event.which === 1 ? this.#onConfirm() : this.#onCancel();
      }
      #onConfirm() {
        const position = this.document.getOrientation();
        if (!this.isValid) {
          this.#runCallback(CONSTANTS.CALLBACKS.INVALID_PLACEMENT, position);
          return;
        }
        const placedCallback = this.#runCallback(CONSTANTS.CALLBACKS.PLACED, position);
        if (placedCallback === false) {
          return;
        }
        this.cachedLocation = position;
        this.#promise.resolve(this.document);
        this.destroy();
      }
      #onCancel() {
        this.#runCallback(CONSTANTS.CALLBACKS.CANCEL);
        this.#promise.resolve(false);
        this.destroy();
      }
      #runCallback(name2, ...params) {
        if (!this.callbacks[name2]) return;
        return this.callbacks[name2](...params);
      }
      #clearHandlers() {
        this.layer.interactiveChildren = this.oldInteractiveChildren;
        canvas.stage.off("mousemove", this.#handlers.move);
        canvas.stage.off("pointerup", this.#handlers.mouseup);
        canvas.app.view.onwheel = null;
      }
      #onWheel(evt) {
        if (!evt.altKey && !evt.ctrlKey && !evt.shiftKey) return;
        evt.stopPropagation();
        if (evt.shiftKey) this.#updateDirection(evt);
        if (evt.altKey) this.#updateDistance(evt);
        if (evt.ctrlKey) ;
        this.refresh();
      }
      #updateDistance(evt) {
        const step = this.document.parent.grid.distance / 2;
        const delta = step * Math.sign(-evt.deltaY);
        let distance = this.document.distance + delta;
        distance = Math.max(0.5, distance.toNearest(step));
        distance = this.#getDistance(distance);
        this.document.updateSource({ distance });
      }
      #updateDirection(evt) {
        if (this.crosshair.lockManualRotation) return;
        const scrollDelta = Math.sign(evt.deltaY);
        let delta = this.crosshair.snap.direction ? this.crosshair.snap.direction * scrollDelta : scrollDelta * 5;
        if (delta < 0) delta += 360;
        if (delta > 360) delta -= 360;
        const direction = Math.max(1, this.document.direction + delta);
        this.document.updateSource({ direction });
      }
      /** @override */
      _getGridHighlightPositions() {
        if (!this.crosshair.gridHighlight) return [];
        return super._getGridHighlightPositions();
      }
      /** @override */
      _destroy(options = {}) {
        super._destroy(options);
        if (this.#rangeHighlight) this.#rangeHighlight.destroy();
        this.#clearHandlers();
      }
      /** @override */
      async draw() {
        await super.draw();
        this.#refreshIcon();
        return this;
      }
      /**
       * The only difference between here and `super` is that this passes along an alpha
       * @override
       */
      highlightGrid() {
        canvas.interface.grid.clearHighlightLayer(this.highlightId);
        const border = this.document.borderColor;
        const color = this.document.fillColor;
        const alpha = this.crosshair.fillAlpha;
        if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
          const shape = this._getGridHighlightShape();
          canvas.interface.grid.highlightPosition(this.highlightId, { border, color, alpha, shape });
        } else {
          const positions = this._getGridHighlightPositions();
          for (const { x, y } of positions) {
            canvas.interface.grid.highlightPosition(this.highlightId, { x, y, border, color, alpha });
          }
        }
      }
    }
    class Plugin {
      constructor(name2) {
        this.name = name2;
      }
      /**
       * The effect's source location, eg the target of `.atLocation()` or `.attachTo()`
       *
       * @param effect
       * @param position
       * @returns {*}
       */
      sourcePosition({ effect, position } = {}) {
        return position;
      }
      /**
       * The effect's source location, eg the target of `.stretchTo()` or `.rotateTowards()`
       *
       * @param effect
       * @param position
       * @returns {*}
       */
      targetPosition({ effect, position } = {}) {
        return position;
      }
      /**
       * The effect's rotation calculation
       *
       * @param effect
       */
      rotation({ effect } = {}) {
      }
      /**
       * The effect's elevation calculation
       *
       * @param effect
       * @param sort
       * @returns Number
       */
      elevation({ effect, sort } = {}) {
        return sort;
      }
      createSpriteContainers({ effect, container } = {}) {
        return container;
      }
      /**
       * makes changes to the effect upon creation
       *
       * @param effect
       */
      createSprite({ effect } = {}) {
      }
      /**
       * Allows you to make changes to the effect's mask, if used
       *
       * @param effect
       * @param doc
       * @param obj
       * @param shape
       * @returns {*}
       */
      masking({ effect, doc, obj, shape } = {}) {
        return shape;
      }
      /**
       * Which hooks should refresh the masking of the effect
       *
       * @returns {*[]}
       */
      get maskingHooks() {
        return [];
      }
    }
    class GrapeJuiceIsometrics extends Plugin {
      isIsometricActive(effect) {
        return !(effect.data.screenSpace || effect.data.screenSpaceAboveUI) && foundry.utils.getProperty(
          game.scenes.get(effect.data.sceneId),
          `flags.${this.name}.is_isometric`
        );
      }
      sourcePosition({ effect, position, height } = {}) {
        if (this.isIsometricActive(effect) && effect.source instanceof PlaceableObject) {
          const elevation = (effect.sourceDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
          position.x += elevation;
          position.y -= elevation;
          if (effect.data.isometric?.overlay || effect.target instanceof PlaceableObject) {
            position.x += height / 2;
            position.y -= height / 2;
          }
        }
        return position;
      }
      targetPosition({ effect, position, height } = {}) {
        if (this.isIsometricActive(effect) && effect.target instanceof PlaceableObject) {
          const targetHeight = height / 2;
          const elevation = (effect.targetDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
          position.x += elevation + targetHeight;
          position.y -= elevation + targetHeight;
        }
        return position;
      }
      rotation({ effect } = {}) {
        if (effect.data.stretchTo) {
          let skew = Math.normalizeRadians(
            effect.rotationContainer.rotation - Math.PI / 4
          );
          if (Math.abs(skew) >= Math.PI / 2 - 0.5 && Math.abs(skew) <= Math.PI / 2 + 0.5) {
            skew -= Math.PI / 2;
          }
          effect.isometricContainer.skew.set(Math.normalizeRadians(skew), 0);
          effect.isometricContainer.rotation = 0;
        } else if (effect.data?.isometric?.overlay) {
          effect.rotationContainer.rotation = 0;
          let skew = Math.PI / 4 + effect.rotationContainer.rotation;
          effect.isometricContainer.skew.set(
            Math.normalizeRadians(skew - Math.PI / 4),
            0
          );
          effect.isometricContainer.scale.set(
            1,
            window.scale ?? Math.sqrt(3)
          );
        }
      }
      elevation({ effect, sort } = {}) {
        if (this.isIsometricActive(effect)) {
          const sourceSort = effect.source ? (effect.sourceMesh?.sort ?? 0) + (effect.data.isometric?.overlay ? 1 : -1) : 0;
          const targetSort = effect.target ? (effect.targetMesh?.sort ?? 0) + (effect.data.isometric?.overlay ? 1 : -1) : 0;
          sort = Math.max(sourceSort, targetSort);
        }
        return sort;
      }
      createSpriteContainers({ effect, container } = {}) {
        effect.isometricContainer = container.addChild(
          new PIXI.Container()
        );
        effect.isometricContainer.id = effect.id + "-isometricContainer";
        return effect.isometricContainer;
      }
      createSprite({ effect } = {}) {
        if (this.isIsometricActive(effect)) {
          effect.isometricContainer.rotation = Math.PI / 4;
        }
      }
    }
    class IsometricPerspective extends GrapeJuiceIsometrics {
      isIsometricActive(effect) {
        return !(effect.data.screenSpace || effect.data.screenSpaceAboveUI) && foundry.utils.getProperty(
          game.scenes.get(effect.data.sceneId),
          `flags.${this.name}.isometricEnabled`
        );
      }
    }
    class WalledTemplates extends Plugin {
      masking({ effect, doc, obj, shape } = {}) {
        if (obj.walledtemplates?.walledTemplate) {
          let wt = obj.walledtemplates.walledTemplate;
          wt.options.padding = 3 * canvas.dimensions.distancePixels;
          shape = wt.computeShape();
          wt.options.padding = 0;
        }
        return shape;
      }
      get maskingHooks() {
        return ["createWall", "updateWall", "deleteWall"];
      }
    }
    class PluginsManager {
      static modules = {
        "grape_juice-isometrics": GrapeJuiceIsometrics,
        "isometric-perspective": IsometricPerspective,
        "walledtemplates": WalledTemplates
      };
      static plugins = [];
      static initialize() {
        for (const [module2, pluginClass] of Object.entries(this.modules)) {
          if (!game.modules.get(module2)?.active) continue;
          this.plugins.push(new pluginClass(module2));
        }
      }
      static sourcePosition({ effect, position, height } = {}) {
        for (const plugin of this.plugins) {
          position = plugin.sourcePosition({ effect, position, height });
        }
        return position;
      }
      static targetPosition({ effect, position, height } = {}) {
        for (const plugin of this.plugins) {
          position = plugin.targetPosition({ effect, position, height });
        }
        return position;
      }
      static rotation({ effect } = {}) {
        for (const plugin of this.plugins) {
          plugin.rotation({ effect });
        }
      }
      static elevation({ effect, sort } = {}) {
        for (const plugin of this.plugins) {
          sort = plugin.elevation({ effect, sort });
        }
        return sort;
      }
      static createSpriteContainers({ effect, container } = {}) {
        for (const plugin of this.plugins) {
          container = plugin.createSpriteContainers({ effect, container });
        }
        return container;
      }
      static createSprite({ effect } = {}) {
        for (const plugin of this.plugins) {
          plugin.createSprite({ effect });
        }
      }
      static masking({ effect, doc, obj, shape } = {}) {
        for (const plugin of this.plugins) {
          shape = plugin.masking({ effect, doc, obj, shape });
        }
        return shape;
      }
      static get maskingHooks() {
        let hooks = [];
        for (const plugin of this.plugins) {
          hooks = hooks.concat(plugin.maskingHooks);
        }
        return hooks;
      }
    }
    const hooksManager = {
      _hooks: /* @__PURE__ */ new Map(),
      _hooksRegistered: /* @__PURE__ */ new Set(),
      addHook(effectUuid, hookName, callable, callNow = false) {
        if (!this._hooksRegistered.has(hookName)) {
          debug("registering hook for: " + hookName);
          this._hooksRegistered.add(hookName);
          Hooks.on(hookName, (...args) => {
            this._hookCalled(hookName, ...args);
          });
        }
        const key = hookName + "-" + effectUuid;
        if (!this._hooks.has(key)) {
          this._hooks.set(key, []);
        }
        this._hooks.get(key).push(callable);
        if (callNow) {
          setTimeout(() => {
            callable();
          }, 20);
        }
      },
      _hookCalled(hookName, ...args) {
        Array.from(this._hooks).filter((entry) => entry[0].startsWith(hookName + "-")).map((hooks) => hooks[1]).deepFlatten().forEach((callback) => callback(...args));
      },
      removeHooks(effectUuid) {
        Array.from(this._hooks).filter((entry) => entry[0].endsWith("-" + effectUuid)).forEach((entry) => this._hooks.delete(entry[0]));
      }
    };
    const SyncGroups = {
      times: /* @__PURE__ */ new Map(),
      effectIds: /* @__PURE__ */ new Map(),
      get(effect) {
        const fullName = effect.data.sceneId + "-" + effect.data.syncGroup;
        const effectIds = new Set(this.effectIds.get(fullName));
        if (effectIds && !effectIds.has(effect.id)) {
          effectIds.add(effect.id);
          this.effectIds.set(fullName, Array.from(effectIds));
        }
        return this.times.get(fullName);
      },
      set(effect) {
        const fullName = effect.data.sceneId + "-" + effect.data.syncGroup;
        this.times.set(fullName, effect.data.creationTimestamp);
        this.effectIds.set(fullName, [effect.id]);
      },
      remove(effect) {
        const fullName = effect.data.sceneId + "-" + effect.data.syncGroup;
        const effectIds = new Set(this.effectIds.get(fullName));
        effectIds.delete(effect.id);
        if (effectIds.size) {
          this.effectIds.set(fullName, Array.from(effectIds));
        } else {
          this.effectIds.delete(fullName);
          this.times.delete(fullName);
        }
      }
    };
    class CanvasEffect extends PIXI.Container {
      #elevation = 0;
      #sort = 0;
      #sortLayer = 800;
      constructor(inData) {
        super();
        this.sortableChildren = true;
        this.interactiveChildren = false;
        this.actualCreationTime = +/* @__PURE__ */ new Date();
        this.data = inData;
        this._resolve = null;
        this._durationResolve = null;
        this.ready = false;
        this._ended = false;
        this._isEnding = false;
        this._cachedSourceData = {};
        this._cachedTargetData = {};
        this.sourceOffset = { x: 0, y: 0 };
        this.targetOffset = { x: 0, y: 0 };
        this.uuid = false;
      }
      static get protectedValues() {
        return [
          "_id",
          "sequenceId",
          "creationTimestamp",
          "creatorUserId",
          "moduleName",
          "index",
          "repetition",
          "moves",
          "fadeIn",
          "fadeOut",
          "scaleIn",
          "scaleOut",
          "rotateIn",
          "rotateOut",
          "fadeInAudio",
          "fadeOutAudio",
          "animations",
          "nameOffsetMap",
          "persist"
        ];
      }
      /** @type {number} */
      get elevation() {
        return this.#elevation;
      }
      set elevation(value) {
        this.#elevation = value;
      }
      /** @type {number} */
      get sort() {
        return this.#sort;
      }
      set sort(value) {
        this.#sort = value;
      }
      /** @type {number} */
      get sortLayer() {
        return this.#sortLayer;
      }
      set sortLayer(value) {
        this.#sortLayer = value;
      }
      get context() {
        return this.data.attachTo?.active && this.sourceDocument ? this.sourceDocument : game.scenes.get(this.data.sceneId);
      }
      get creationTimestamp() {
        if (this.data.syncGroup) {
          const time2 = SyncGroups.get(this);
          if (time2) return time2;
          SyncGroups.set(this);
        }
        return this.data.creationTimestamp;
      }
      /**
       * The ID of the effect
       *
       * @returns {string}
       */
      get id() {
        return this.data._id;
      }
      /**
       * Whether this effect is destroyed or is in the process of being destroyed
       */
      get isDestroyed() {
        return this.destroyed || this.source && this.isSourceDestroyed || this.target && this.isTargetDestroyed;
      }
      /**
       * Whether the source of this effect is temporary
       *
       * @returns {boolean}
       */
      get isSourceTemporary() {
        return this.data.attachTo?.active && this.sourceDocument && !is_UUID(this.sourceDocument?.uuid);
      }
      /**
       * Whether the source of this effect has been destroyed
       *
       * @returns {boolean}
       */
      get isSourceDestroyed() {
        return this.source && this.source?.destroyed && (!this.sourceDocument?.object || this.sourceDocument?.object?.destroyed || this.source.constructor.name === "Crosshairs");
      }
      /**
       * Whether the target of this effect is temporary
       *
       * @returns {boolean}
       */
      get isTargetTemporary() {
        return (this.data.stretchTo?.attachTo || this.data.rotateTowards?.attachTo) && this.targetDocument && !is_UUID(this.targetDocument.uuid);
      }
      /**
       * Whether the target of this effect has been destroyed
       *
       * @returns {boolean}
       */
      get isTargetDestroyed() {
        return this.target && this.target?.destroyed && (!this.targetDocument?.object || this.targetDocument?.object?.destroyed || this.target.constructor.name === "Crosshairs");
      }
      /**
       * The source object (or source location) of the effect
       *
       * @returns {boolean|object}
       */
      get source() {
        if (!this._source && this.data.source) {
          const getDifferentTarget = this.data.source === this.data.target;
          this._source = this._getObjectByID(this.data.source?.uuid ?? this.data.source, getDifferentTarget, true) ?? this.data.source;
          this._source = this._source?._object ?? this._source;
        }
        return this._source;
      }
      /**
       * Retrieves the source document
       *
       * @returns {Document|foundry.canvas.placeables.PlaceableObject}
       */
      get sourceDocument() {
        return this.source?.document ?? this.source;
      }
      /**
       * Retrieves the PIXI object for the source object
       *
       * @returns {*|PIXI.Sprite|TileHUD<Application.Options>}
       */
      get sourceMesh() {
        return this.source?.mesh ?? this.source?.template;
      }
      /**
       * The source position with the relevant offsets calculated
       *
       * @returns {{x: number, y: number}}
       */
      get sourcePosition() {
        let position = this.getSourceData().position;
        let offset2 = this._getOffset(this.data.source, true);
        if (this.data.attachTo?.active && this.data.attachTo?.align && this.data.attachTo?.align !== "center") {
          const additionalOffset = align({
            context: this.source,
            spriteWidth: this.sprite.width,
            spriteHeight: this.sprite.height,
            align: this.data.attachTo?.align,
            edge: this.data.attachTo?.edge
          });
          offset2.x += additionalOffset.x;
          offset2.y += additionalOffset.y;
        }
        return {
          x: position.x - offset2.x + this.sourceOffset.x,
          y: position.y - offset2.y + this.sourceOffset.y
        };
      }
      /**
       * The target object (or target location) of the effect
       *
       * @returns {boolean|object}
       */
      get target() {
        if (!this._target && this.data.target) {
          const getDifferentTarget = this.data.source === this.data.target;
          this._target = this._getObjectByID(this.data.target?.uuid ?? this.data.target, getDifferentTarget, false) ?? this.data.target;
          this._target = this._target?._object ?? this._target;
        }
        return this._target;
      }
      /**
       * Retrieves the document of the target
       *
       * @returns {Document|foundry.canvas.placeables.PlaceableObject}
       */
      get targetDocument() {
        return this.target?.document ?? this.target;
      }
      /**
       * Retrieves the PIXI object for the target object
       *
       * @returns {*|PIXI.Sprite|TileHUD<Application.Options>}
       */
      get targetMesh() {
        return this.target?.mesh ?? this.target?.template;
      }
      /**
       * The target position with the relevant offsets calculated
       *
       * @returns {{x: number, y: number}}
       */
      get targetPosition() {
        const position = this.getTargetData().position;
        const offset2 = this._getOffset(this.data.target);
        return {
          x: position.x - offset2.x + this.targetOffset.x,
          y: position.y - offset2.y + this.targetOffset.y
        };
      }
      /**
       * Returns this effect's world position
       *
       * @returns {{x: number, y: number}}
       */
      get worldPosition() {
        const t = canvas.stage.worldTransform;
        return {
          x: (this.sprite.worldTransform.tx - t.tx) / canvas.stage.scale.x,
          y: (this.sprite.worldTransform.ty - t.ty) / canvas.stage.scale.y
        };
      }
      /**
       * Whether the current user is the owner of this effect
       *
       * @returns {boolean}
       */
      get owner() {
        return this.data.creatorUserId === game.user.id;
      }
      get loopDelay() {
        return this.data.loopOptions?.loopDelay ?? 0;
      }
      get loops() {
        return this.data.loopOptions?.loops ?? 0;
      }
      /**
       * Whether the current user can update this effect
       *
       * @returns {boolean}
       */
      get userCanUpdate() {
        return game.user.isGM || this.owner || this.data.attachTo?.active && this.sourceDocument.canUserModify(game.user, "update");
      }
      /**
       * Whether the current user can delete this effect
       *
       * @returns {boolean}
       */
      get userCanDelete() {
        return this.userCanUpdate || user_can_do("permissions-effect-delete");
      }
      /**
       * Whether this effect is on the current scene
       *
       * @returns {boolean}
       */
      get onCurrentScene() {
        return this.data.sceneId === game.user.viewedScene;
      }
      /**
       * Whether this effect should be shown as faded or not - effects created by users for other users should be shown
       * for all
       *
       * @returns {boolean}
       */
      get shouldShowFadedVersion() {
        return this.data.users && this.data.users.length && !(this.data.users.length === 1 && this.data.users.includes(this.data.creatorUserId)) && !this.data.users.includes(game.userId);
      }
      set effectAlpha(value) {
        if (this.sprite) {
          this.sprite.alpha = value;
        }
        if (this.shapes) {
          Object.values(this.shapes).forEach((shape) => {
            shape.alpha = value;
          });
        }
      }
      get effectAlpha() {
        return this.sprite?.alpha;
      }
      async playMedia() {
        if (this.destroyed || this._ended || this._isEnding) {
          return;
        }
        await this.sprite.play();
        this._setupTimestampHook(this.mediaCurrentTime * 1e3);
      }
      updateTexture() {
        this.sprite.updateVideoTextures();
      }
      async pauseMedia() {
        this.sprite.stop();
      }
      get mediaLooping() {
        return this.sprite.loop;
      }
      set mediaLooping(looping) {
        return this.sprite.loop = looping;
      }
      get mediaIsPlaying() {
        return this.sprite.playing;
      }
      get mediaCurrentTime() {
        return this.sprite.currentTime;
      }
      get mediaPlaybackRate() {
        return this.sprite.playbackRate;
      }
      set mediaPlaybackRate(inPlaybackRate) {
        this.sprite.playbackRate = inPlaybackRate;
      }
      set mediaCurrentTime(newTime) {
        this.sprite.currentTime = newTime;
      }
      get mediaDuration() {
        return this.sprite.duration;
      }
      get mediaDurationMs() {
        return this.mediaDuration * 1e3;
      }
      get hasAnimatedMedia() {
        return this.sprite.hasAnimatedMedia;
      }
      /**
       * The template of the effect, determining the effect's internal grid size, and start/end padding
       *
       * @returns {object}
       */
      get template() {
        return this._template;
      }
      /**
       * The grid size difference between the internal effect's grid vs the grid on the canvas. If the effect is in screen space, we ignore this.
       *
       * @returns {number}
       */
      get gridSizeDifference() {
        return canvas.grid.size / (this.template?.gridSize ?? this.defaultGridSize);
      }
      get defaultGridSize() {
        return 100;
      }
      /**
       * Whether the effect should be flipped on any given axis
       *
       * @returns {number}
       */
      get flipX() {
        const offsetMap = this._nameOffsetMap?.[this.data.source];
        let flip = this.data.flipX ? -1 : 1;
        if (offsetMap && offsetMap.mirrorX !== void 0) {
          flip *= offsetMap.mirrorX ? -1 : 1;
        }
        return flip;
      }
      get flipY() {
        const offsetMap = this._nameOffsetMap?.[this.data.source];
        let flip = this.data.flipY ? -1 : 1;
        if (offsetMap && offsetMap.mirrorY !== void 0) {
          flip *= offsetMap.mirrorY ? -1 : 1;
        }
        return flip;
      }
      /**
       * Whether this effect should play at all, depending on a multitude of factors
       *
       * @returns {boolean}
       */
      get shouldPlay() {
        return (game.user.viewedScene === this.data.sceneId || this.data.creatorUserId === game.userId) && (game.user.isGM || !this.data.users || this.data.users.length === 0 || this.data.users.includes(game.userId));
      }
      get shouldPlayVisible() {
        let playVisible = this.shouldPlay && game.settings.get("sequencer", "effectsEnabled") && game.user.viewedScene === this.data.sceneId;
        if (game.settings.get("core", "photosensitiveMode")) {
          playVisible = false;
          throttled_custom_warning(
            this.data.moduleName,
            "Photosensitive Mode is turned on, so Sequencer's visual effects aren't being rendered"
          );
        }
        return playVisible;
      }
      static make(inData) {
        return !inData.persist ? new CanvasEffect(inData) : new PersistentCanvasEffect(inData);
      }
      static checkValid(effectData) {
        if (effectData.delete) {
          return false;
        }
        let sourceExists = true;
        let targetExists = true;
        if (effectData.source && is_UUID(effectData.source)) {
          sourceExists = fromUuidSync(effectData.source);
        }
        if (effectData.target && is_UUID(effectData.target)) {
          targetExists = fromUuidSync(effectData.target);
        }
        for (let tiedDocumentUuid of effectData?.tiedDocuments ?? []) {
          if (tiedDocumentUuid && is_UUID(tiedDocumentUuid)) {
            let tiedDocumentExists = fromUuidSync(tiedDocumentUuid);
            if (!tiedDocumentExists) return false;
          }
        }
        if (effectData.source && is_UUID(effectData.source) && effectData.target && is_UUID(effectData.target)) {
          const sourceScene = effectData.source.split(".")[1];
          const targetScene = effectData.target.split(".")[1];
          if (sourceScene !== targetScene || sourceScene !== effectData.sceneId)
            return false;
        }
        return sourceExists && targetExists;
      }
      /**
       * Validates that the update contains the appropriate data
       *
       * @param inUpdates
       */
      static validateUpdate(inUpdates) {
        const updateKeys = Object.keys(inUpdates);
        const protectedValues = updateKeys.filter(
          (key) => CanvasEffect.protectedValues.includes(key)
        );
        if (protectedValues.length) {
          throw custom_error(
            "Sequencer",
            `CanvasEffect | update | You cannot update the following keys of an effect's data: ${protectedValues.join(
              "\n - "
            )}`
          );
        }
        if (updateKeys.includes("source")) {
          if (!(is_UUID(inUpdates.source) || is_object_canvas_data(inUpdates.source))) {
            throw custom_error(
              "Sequencer",
              `CanvasEffect | update | source must be of type document UUID or object with X and Y coordinates`
            );
          }
        }
        if (updateKeys.includes("target")) {
          if (!(is_UUID(inUpdates.target) || is_object_canvas_data(inUpdates.target))) {
            throw custom_error(
              "Sequencer",
              `CanvasEffect | update | target must be of type document UUID or object with X and Y coordinates`
            );
          }
        }
      }
      getHook(type, uuid) {
        if (!is_UUID(uuid)) return false;
        const parts = uuid.split(".");
        return type + parts[parts.length - 2];
      }
      /**
       * Gets the source hook name
       *
       * @param {string} type
       * @returns {string|boolean}
       */
      getSourceHook(type = "") {
        return this.getHook(type, this.data.source);
      }
      /**
       * The source object's current position, or its current position
       *
       * @returns {boolean|object}
       */
      getSourceData() {
        if (this.data.temporary && !this.owner) {
          return SequencerEffectManager.getPositionForUUID(this.data.source);
        }
        if (this.source instanceof FoundryShim.PlaceableObject && this.isSourceDestroyed) {
          return {
            ...this._cachedSourceData
          };
        }
        let crosshairPos = this.source instanceof CrosshairsPlaceable ? this.sourceDocument.getOrientation() : false;
        crosshairPos = crosshairPos?.source;
        let position = this.source instanceof FoundryShim.PlaceableObject && !this.isSourceTemporary ? get_object_position(this.source) : crosshairPos || this.source?.worldPosition || this.source?.center || this.source;
        const { width: width2, height } = crosshairPos || get_object_dimensions(this.source);
        position = PluginsManager.sourcePosition({ effect: this, position, height });
        if (position !== void 0) {
          this._cachedSourceData.position = position;
        }
        if (width2 !== void 0 && height !== void 0) {
          this._cachedSourceData.width = width2;
          this._cachedSourceData.height = height;
        }
        let rotation2 = 0;
        if (this.source instanceof FoundryShim.MeasuredTemplate && this.sourceDocument?.t !== "rect") {
          rotation2 = Math.normalizeRadians(
            Math.toRadians(this.sourceDocument?.direction)
          );
        } else if (!(this.source instanceof FoundryShim.MeasuredTemplate)) {
          rotation2 = this.sourceDocument?.rotation ? Math.normalizeRadians(Math.toRadians(this.sourceDocument?.rotation)) : 0;
        }
        if (rotation2 !== void 0) {
          this._cachedSourceData.rotation = rotation2;
        }
        const alpha = this.sourceDocument instanceof TokenDocument || this.sourceDocument instanceof TileDocument ? this.sourceDocument?._source?.alpha ?? 1 : 1;
        if (alpha !== void 0) {
          this._cachedSourceData.alpha = alpha;
        }
        return {
          ...this._cachedSourceData
        };
      }
      /**
       * Gets the target hook name
       *
       * @param {string} type
       * @returns {string|boolean}
       */
      getTargetHook(type = "") {
        return this.getHook(type, this.data.target);
      }
      /**
       * The target object's current position, or its current position
       *
       * @returns {boolean|object}
       */
      getTargetData() {
        if (this.data.temporary && !this.owner) {
          return SequencerEffectManager.getPositionForUUID(this.data.target) ?? this.getSourceData();
        }
        if (this.target instanceof FoundryShim.PlaceableObject && this.isTargetDestroyed) {
          return {
            ...this._cachedTargetData
          };
        }
        let crosshairPos = this.target instanceof CrosshairsPlaceable ? this.targetDocument.getOrientation() : false;
        crosshairPos = crosshairPos?.target ?? crosshairPos?.source;
        let position = this.target instanceof FoundryShim.PlaceableObject && !this.isTargetTemporary && !this.isTargetDestroyed ? get_object_position(this.target, { measure: true }) : crosshairPos || this.target?.worldPosition || this.target?.center || this.target;
        const { width: width2, height } = crosshairPos || get_object_dimensions(this.target);
        position = PluginsManager.targetPosition({ effect: this, position, height });
        if (width2 !== void 0 && height !== void 0) {
          this._cachedTargetData.width = width2;
          this._cachedTargetData.height = height;
        }
        if (position !== void 0) {
          this._cachedTargetData.position = position;
        }
        let rotation2 = 0;
        if (this.target instanceof FoundryShim.MeasuredTemplate && this.targetDocument?.t !== "rect") {
          rotation2 = Math.normalizeRadians(
            Math.toRadians(this.targetDocument?.direction)
          );
        } else if (!(this.target instanceof FoundryShim.MeasuredTemplate)) {
          rotation2 = this.targetDocument?.rotation ? Math.normalizeRadians(Math.toRadians(this.targetDocument?.rotation)) : 0;
        }
        if (rotation2 !== void 0) {
          this._cachedTargetData.rotation = rotation2;
        }
        const alpha = this.targetDocument instanceof TokenDocument || this.targetDocument instanceof TileDocument ? this.targetDocument?.alpha ?? 1 : 1;
        if (alpha !== void 0) {
          this._cachedTargetData.alpha = alpha;
        }
        return {
          ...this._cachedTargetData
        };
      }
      /**
       * Calculates the offset for a given offset property and name mapping
       *
       * @param {string} offsetMapName
       * @param {boolean} source
       * @returns {{x: number, y: number}|*}
       * @private
       */
      _getOffset(offsetMapName, source = false) {
        const key = source ? "source" : "target";
        const offset2 = {
          x: 0,
          y: 0
        };
        let twister = this._twister;
        let nameOffsetMap = this._nameOffsetMap?.[this.data.name];
        if (nameOffsetMap) {
          twister = nameOffsetMap.twister;
        }
        if (this.data.missed && (!source || !this.data.target)) {
          let missedOffset = this._offsetCache[key]?.missedOffset || calculate_missed_position(this.source, this.target, twister);
          this._offsetCache[key].missedOffset = missedOffset;
          offset2.x -= missedOffset.x;
          offset2.y -= missedOffset.y;
        }
        const obj = source ? this.source : this.target;
        const multiplier = source ? this.data.randomOffset?.source : this.data.randomOffset?.target;
        if (obj && multiplier) {
          let randomOffset = this._offsetCache[key]?.randomOffset || get_random_offset(obj, multiplier, twister);
          this._offsetCache[key].randomOffset = randomOffset;
          offset2.x -= randomOffset.x;
          offset2.y -= randomOffset.y;
        }
        let extraOffset = this.data?.offset?.[key];
        if (extraOffset) {
          let newOffset = {
            x: extraOffset.x,
            y: extraOffset.y
          };
          if (extraOffset.gridUnits) {
            newOffset.x *= canvas.grid.size;
            newOffset.y *= canvas.grid.size;
          }
          if (extraOffset.local) {
            if (!this._cachedSourceData?.position || !this._cachedTargetData?.position) {
              this.getSourceData();
              this.getTargetData();
            }
            const startPos = this._cachedSourceData.position;
            const endPos = this._cachedTargetData.position;
            const angle = this.target ? new Ray(startPos, endPos).angle : Ray.fromAngle(
              startPos.x,
              startPos.y,
              this._cachedSourceData.rotation,
              1
            ).angle;
            newOffset = rotateAroundPoint(
              0,
              0,
              newOffset.x,
              newOffset.y,
              -angle
            );
          }
          offset2.x -= newOffset.x;
          offset2.y -= newOffset.y;
        }
        let offsetMap = this._nameOffsetMap?.[offsetMapName];
        if (!this._offsetCache[key]["nameCache"][offsetMapName]) {
          this._offsetCache[key]["nameCache"][offsetMapName] = {};
        }
        if (offsetMap) {
          if (offsetMap.missed) {
            const missedOffset = this._offsetCache[key]["nameCache"][offsetMapName]?.missedOffset || calculate_missed_position(
              offsetMap.sourceObj,
              offsetMap.targetObj,
              offsetMap.twister
            );
            this._offsetCache[key]["nameCache"][offsetMapName].missedOffset = missedOffset;
            offset2.x -= missedOffset.x;
            offset2.y -= missedOffset.y;
          }
          const obj2 = offsetMap.targetObj || offsetMap.sourceObj;
          const multiplier2 = offsetMap.randomOffset?.source || offsetMap.randomOffset?.target;
          if (obj2 && multiplier2) {
            let randomOffset = this._offsetCache[key]["nameCache"][offsetMapName]?.randomOffset || get_random_offset(obj2, multiplier2, offsetMap.twister);
            this._offsetCache[key]["nameCache"][offsetMapName].randomOffset = randomOffset;
            offset2.x -= randomOffset.x;
            offset2.y -= randomOffset.y;
          }
          if (offsetMap.offset) {
            offset2.x += offsetMap.offset.x;
            offset2.y += offsetMap.offset.y;
          }
        }
        return offset2;
      }
      /**
       * Initializes the name offset map by establishing targets
       *
       * @param inOffsetMap
       * @returns {{setup}|*}
       * @private
       */
      _setupOffsetMap(inOffsetMap) {
        if (!inOffsetMap.setup) {
          inOffsetMap.setup = true;
          inOffsetMap.sourceObj = inOffsetMap.source ? this._validateObject(inOffsetMap.source) : false;
          inOffsetMap.targetObj = inOffsetMap.target ? this._validateObject(inOffsetMap.target) : false;
          const repetition = this.data.repetition % inOffsetMap.repetitions;
          const seed = get_hash(`${inOffsetMap.seed}-${repetition}`);
          inOffsetMap.twister = createMersenneTwister(seed);
        }
        return inOffsetMap;
      }
      /**
       * Plays the effect, returning two promises; one that resolves once the duration has been established, and another
       * when the effect has finished playing
       *
       * @returns {Object}
       */
      play() {
        const durationPromise = new Promise((resolve, reject) => {
          this._durationResolve = resolve;
        });
        const finishPromise = new Promise(async (resolve, reject) => {
          this._resolve = resolve;
          Hooks.callAll("createSequencerEffect", this);
          debug(`Playing effect:`, this.data);
          this._initialize();
        });
        return {
          duration: durationPromise,
          promise: finishPromise
        };
      }
      /**
       *  Ends the effect
       */
      endEffect() {
        if (this._ended) return;
        Hooks.callAll("endedSequencerEffect", this);
        this.destroy();
      }
      destroy(...args) {
        this._destroyDependencies();
        return super.destroy(...args);
      }
      /**
       * Updates this effect with the given parameters
       * @param inUpdates
       * @returns {Promise}
       */
      async update(inUpdates) {
        if (!this.userCanUpdate)
          throw custom_error(
            "Sequencer",
            "CanvasEffect | Update | You do not have permission to update this effect"
          );
        CanvasEffect.validateUpdate(inUpdates);
        const newData = foundry.utils.deepClone(this.data);
        const updateKeys = Object.keys(inUpdates);
        updateKeys.forEach((key) => {
          foundry.utils.setProperty(newData, key, inUpdates[key]);
        });
        if (Object.keys(foundry.utils.diffObject(newData, this.data)).length === 0) {
          debug(
            `Skipped updating effect with ID ${this.id} - no changes needed`
          );
          return;
        }
        if (this.data.persist) {
          const originalSourceUUID = is_UUID(this.data.source) && this.data.attachTo ? this.data.source : "Scene." + this.data.sceneId;
          const newSourceUUID = is_UUID(newData.source) && newData.attachTo ? newData.source : "Scene." + newData.sceneId;
          if (originalSourceUUID !== newSourceUUID) {
            flagManager.removeEffectFlags(originalSourceUUID, newData);
          }
          flagManager.addEffectFlags(newSourceUUID, newData);
        }
        debug(`Updated effect with ID ${this.id}`);
        return sequencerSocket.executeForEveryone(
          SOCKET_HANDLERS.UPDATE_EFFECT,
          this.id,
          newData
        );
      }
      async addAnimatedProperties({ animations = [], loopingAnimation = [] } = {}) {
        const animationsToAdd = [];
        if (!Array.isArray(animations)) {
          throw custom_error(
            this.data.moduleName,
            `animations must be an array of arrays`
          );
        }
        for (const animationData of animations) {
          if (!Array.isArray(animationData)) {
            throw custom_error(
              this.data.moduleName,
              `each entry in animations must be an array, each with target, property name, and animation options`
            );
          }
          const result = validateAnimation(...animationData);
          if (typeof result === "string") {
            throw custom_error(this.data.moduleName, result);
          }
          result.creationTimestamp = +/* @__PURE__ */ new Date();
          animationsToAdd.push(result);
        }
        if (!Array.isArray(loopingAnimation)) {
          throw custom_error(
            this.data.moduleName,
            `loopingAnimation must be an array of arrays`
          );
        }
        for (const animationData of loopingAnimation) {
          if (!Array.isArray(animationData)) {
            throw custom_error(
              this.data.moduleName,
              `each entry in loopingAnimation must be an array, each with target, property name, and animation options`
            );
          }
          const result = validateLoopingAnimation(...animationData);
          if (typeof result === "string") {
            throw custom_error(this.data.moduleName, result);
          }
          result.creationTimestamp = +/* @__PURE__ */ new Date();
          animationsToAdd.push(result);
        }
        if (this.data.persist) {
          const originalSourceUUID = is_UUID(this.data.source) && this.data.attachTo ? this.data.source : "Scene." + this.data.sceneId;
          const newData = foundry.utils.deepClone(this.data);
          newData.animations = (newData.animations ?? []).concat(
            foundry.utils.deepClone(animationsToAdd)
          );
          flagManager.addEffectFlags(originalSourceUUID, newData);
        }
        return sequencerSocket.executeForEveryone(
          SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
          this.id,
          animationsToAdd
        );
      }
      async _addAnimations(inAnimations) {
        this._playAnimations(foundry.utils.deepClone(inAnimations));
        this.data.animations = (this.data.animations ?? []).concat(inAnimations);
      }
      /**
       * Updates the effect
       *
       * @param inUpdates
       * @returns {Promise}
       * @private
       */
      _update(inUpdates) {
        this.data = inUpdates;
        Hooks.callAll("updateSequencerEffect", this);
        this._destroyDependencies();
        return this._reinitialize();
      }
      /**
       * Determines whether a position is within the bounds of this effect
       *
       * @param inPosition
       * @returns {boolean}
       */
      isPositionWithinBounds(inPosition) {
        if (!this.spriteContainer) return false;
        return is_position_within_bounds(
          inPosition,
          this.spriteContainer,
          this.parent
        );
      }
      /**
       * Initializes the effect and places it on the canvas
       *
       * @returns {Promise}
       * @private
       */
      async _initialize() {
        this.ready = false;
        this._initializeVariables();
        this._addToContainer();
        this._createFile();
        this._updateCurrentFilePath(false, true);
        await this._createSprite();
        this._calculateDuration();
        this._createShapes();
        await this._setupMasks();
        await this._transformSprite();
        this._playPresetAnimations();
        this._playCustomAnimations();
        this._setEndTimeout();
        this._registerTickers();
        this._timeoutVisibility();
        await this._startEffect();
        this.ready = true;
      }
      /**
       * Reinitializes the effect after it has been updated
       *
       * @param play
       * @returns {Promise}
       * @private
       */
      async _reinitialize() {
        this.renderable = false;
        if (!this.shouldPlay) {
          return Sequencer.EffectManager._removeEffect(this);
        }
        this.actualCreationTime = +/* @__PURE__ */ new Date();
        return this._initialize();
      }
      /**
       * Initializes variables core to the function of the effect
       * This is run as a part of the construction of the effect
       *
       * @private
       */
      _initializeVariables() {
        this.rotationContainer = this.addChild(new PIXI.Container());
        this.rotationContainer.id = this.id + "-rotationContainer";
        this.pluginContainer = PluginsManager.createSpriteContainers({ effect: this, container: this.rotationContainer });
        this.spriteContainer = this.pluginContainer.addChild(
          new PIXI.Container()
        );
        this.spriteContainer.id = this.id + "-spriteContainer";
        this._template = this.data.template;
        this._ended = null;
        this._maskContainer = null;
        this._maskSprite = null;
        this._file = null;
        this._loopOffset = 0;
        this.effectFilters = {};
        this._animationDuration = 0;
        this._animationTimes = {};
        this._twister = createMersenneTwister(this.creationTimestamp);
        this._distanceCache = null;
        this._isRangeFind = false;
        this._customAngle = 0;
        this._currentFilePath = this.data.file;
        this._hooks = [];
        this._lastDimensions = {};
        this._lastScreenDimensions = {};
        if (this._resetTimeout) {
          clearTimeout(this._resetTimeout);
        }
        this._resetTimeout = null;
        this._source = false;
        this._target = false;
        this._offsetCache = {
          source: { nameCache: {} },
          target: { nameCache: {} }
        };
        this._nameOffsetMap = Object.fromEntries(
          Object.entries(
            foundry.utils.deepClone(this.data.nameOffsetMap ?? {})
          ).map((entry) => {
            return [entry[0], this._setupOffsetMap(entry[1])];
          })
        );
        this.uuid = !is_UUID(this.context.uuid) ? this.id : this.context.uuid + ".data.flags.sequencer.effects." + this.id;
        this._ticker = FoundryShim.CanvasAnimation.ticker;
        this._tickerMethods = [];
      }
      _addToTicker(func2) {
        this._tickerMethods.push(func2);
        this._ticker.add(func2, this);
      }
      /**
       * Destroys all dependencies to this element, such as tickers, animations, textures, and child elements
       *
       * @private
       */
      _destroyDependencies() {
        if (this._ended) return;
        this._ended = true;
        this.mask = null;
        hooksManager.removeHooks(this.uuid);
        this._tickerMethods.forEach((func2) => this._ticker.remove(func2, this));
        this._ticker = null;
        SequencerAnimationEngine.endAnimations(this.id);
        if (this._maskContainer) this._maskContainer.destroy({ children: true });
        if (this._maskSprite) {
          try {
            this._maskSprite.texture.destroy(true);
            this._maskSprite.destroy();
          } catch (err) {
          }
        }
        this.sprite.destroy();
        this.sprite = null;
        try {
          if (this.data.screenSpace) {
            SequencerAboveUILayer.removeContainerByEffect(this);
          }
        } catch (err) {
        }
        if (this.data.syncGroup) {
          SyncGroups.remove(this);
        }
        this.removeChildren().forEach((child) => child.destroy({ children: true }));
      }
      /**
       * Plays preset animations
       *
       * @private
       */
      _playPresetAnimations() {
        this._moveTowards();
        this._fadeOut();
        this._fadeIn();
        this._rotateOut();
        this._rotateIn();
        this._scaleOut();
        this._scaleIn();
        this._fadeOutAudio();
        this._fadeInAudio();
      }
      /**
       * Gets an object based on an identifier, checking if it exists within the named offset map, whether it's a
       * coordinate object, or if it's an UUID that needs to be fetched from the scene
       *
       * @param inIdentifier
       * @param specific
       * @param returnSource
       * @returns {*}
       * @private
       */
      _getObjectByID(inIdentifier, specific = false, returnSource = false) {
        let source = inIdentifier;
        let offsetMap = this._nameOffsetMap?.[inIdentifier];
        if (offsetMap) {
          if (specific) {
            source = (returnSource ? offsetMap?.sourceObj || offsetMap?.targetObj : offsetMap?.targetObj || offsetMap?.sourceObj) || source;
          } else {
            source = offsetMap?.targetObj || offsetMap?.sourceObj || source;
          }
        } else {
          source = this._validateObject(source);
        }
        return source;
      }
      /**
       * Validates the given parameter, whether it's a UUID or a coordinate object, and returns the proper one
       *
       * @param inObject
       * @returns {*}
       * @private
       */
      _validateObject(inObject) {
        if (is_UUID(inObject) || !is_object_canvas_data(inObject)) {
          inObject = get_object_from_scene(inObject, this.data.sceneId);
          inObject = inObject?._object ?? inObject;
        }
        return inObject;
      }
      /**
       * Adds this effect to the appropriate container on the right layer
       *
       * @private
       */
      _addToContainer() {
        let layer2;
        if (this.data.screenSpaceAboveUI) {
          layer2 = SequencerAboveUILayer;
        } else if (this.data.screenSpace) {
          layer2 = canvas.sequencerEffectsUILayer;
        } else if (this.data.aboveInterface) {
          layer2 = canvas.controls;
        } else if (this.data.aboveLighting) {
          layer2 = canvas.interface;
        } else {
          layer2 = canvas.primary;
        }
        layer2.addChild(this);
        layer2.sortChildren();
      }
      get startTimeMs() {
        return this._startTime * 1e3;
      }
      get endTimeMs() {
        return this._endTime * 1e3;
      }
      /**
       * Calculates the duration of this effect, based on animation durations, the video source duration, end/start times, etc
       *
       * @private
       */
      _calculateDuration() {
        let playbackRate = this.data.playbackRate || 1;
        this.mediaPlaybackRate = playbackRate;
        this._animationDuration = this.data.duration || this.mediaDurationMs;
        if (this.data.moveSpeed && this.data.moves) {
          let distance = distance_between(
            this.sourcePosition,
            this.targetPosition
          );
          let durationFromSpeed = distance / this.data.moveSpeed * 1e3;
          this._animationDuration = Math.max(durationFromSpeed, this.data.duration);
        } else if (!this.data.duration && !this.hasAnimatedMedia) {
          let fadeDuration = (this.data.fadeIn?.duration ?? 0) + (this.data.fadeOut?.duration ?? 0);
          let scaleDuration = (this.data.scaleIn?.duration ?? 0) + (this.data.scaleOut?.duration ?? 0);
          let rotateDuration = (this.data.rotateIn?.duration ?? 0) + (this.data.rotateOut?.duration ?? 0);
          let moveDuration = 0;
          if (this.data.moves) {
            let distance = distance_between(
              this.sourcePosition,
              this.targetPosition
            );
            moveDuration = (this.data.moveSpeed ? distance / this.data.moveSpeed * 1e3 : 1e3) + this.data.moves.delay;
          }
          let animationDurations = this.data.animations?.length ? Math.max(
            ...this.data.animations.map((animation2) => {
              if (animation2.looping) {
                if (animation2.loops === 0) return 0;
                return (animation2?.duration ?? 0) * (animation2?.loops ?? 0) + (animation2?.delay ?? 0);
              } else {
                return (animation2?.duration ?? 0) + (animation2?.delay ?? 0);
              }
            })
          ) : 0;
          this._animationDuration = Math.max(
            fadeDuration,
            scaleDuration,
            rotateDuration,
            moveDuration,
            animationDurations
          );
          this._animationDuration = this._animationDuration || 1e3;
        }
        this._startTime = 0;
        if (this.data.time?.start && this.mediaCurrentTime !== null) {
          let currentTime = !this.data.time.start.isPerc ? this.data.time.start.value ?? 0 : this._animationDuration * this.data.time.start.value;
          this.mediaCurrentTime = currentTime / 1e3;
          this._startTime = currentTime / 1e3;
        }
        this._endTime = this._animationDuration;
        if (this.data.time?.end) {
          if (this.data.time.end.isPerc) {
            this._endTime = this._animationDuration - this._animationDuration * this.data.time.end.value;
          } else {
            this._endTime = this.data.time.isRange ? this.data.time.end.value : this._animationDuration - this.data.time.end.value;
          }
        }
        this._endTime /= 1e3;
        this._animationDuration = clamp$1(this.endTimeMs - this.startTimeMs, 0, this._animationDuration);
        if (this._file?.markers && this._startTime === 0 && this._endTime === this.mediaDuration) {
          this._animationTimes.loopStart = this._file.markers.loop.start / playbackRate / 1e3;
          this._animationTimes.loopEnd = this._file.markers.loop.end / playbackRate / 1e3;
          this._animationTimes.forcedEnd = this._file.markers.forcedEnd / playbackRate / 1e3;
        }
        this._totalDuration = this.loops ? this._animationDuration * this.loops + this.loopDelay * (this.loops - 1) : this._animationDuration;
        this._totalDuration /= playbackRate;
        if (this.data.persist) {
          this.mediaLooping = (!this.data.time || this._startTime === 0 && this._endTime === this.mediaDuration) && this._animationTimes.loopStart === void 0 && this._animationTimes.loopEnd === void 0 && !this.loops && !this.loopDelay;
        } else {
          this.mediaLooping = this._startTime === 0 && this._endTime > this.mediaDuration && !(this.loops && this.loopDelay);
        }
        this._durationResolve(this._totalDuration);
      }
      /**
       * If this effect is animatable, hold off on rendering it for a bit so that the animations have time to initialize to
       * prevent it from spawning and then jumping to the right place
       *
       * @private
       */
      _timeoutVisibility() {
        if (!this.data.animations) {
          return this._setupHooks();
        }
        setTimeout(() => {
          this._setupHooks();
        }, 50);
      }
      /**
       * Add Ticker handler to check for updates to attached objects
       *
       * @private
       */
      _registerTickers() {
        if (this.data.stretchTo && this.data.stretchTo?.attachTo) {
          this._addToTicker(this._transformStretchToAttachedSprite);
        }
        if (this.data.attachTo?.active && !this.data.stretchTo?.attachTo) {
          this._addToTicker(this._transformAttachedNoStretchSprite);
        }
        if (this.data.rotateTowards && this.data.rotateTowards?.attachTo) {
          this._addToTicker(this._transformRotateTowardsAttachedSprite);
        }
        if (this.data.scaleToObject && this.data?.attachTo?.active && this.data?.attachTo?.bindScale) {
          const { heightWidthRatio, widthHeightRatio, baseScaleX, baseScaleY } = this._getBaseScale();
          this._addToTicker(() => {
            this._applyScaleToObject(heightWidthRatio, widthHeightRatio, baseScaleX, baseScaleY);
            this._setAnchors();
          });
        }
        if (this.isSourceTemporary) {
          this._addToTicker(this._checkSourceDestroyed);
        }
        if (this.isTargetTemporary) {
          this._addToTicker(this._checkTargetDestroyed);
        }
      }
      _checkSourceDestroyed() {
        if (this.isSourceDestroyed) {
          this._source = this.sourcePosition;
          SequencerEffectManager.endEffects({ effects: this });
        }
      }
      _checkTargetDestroyed() {
        if (this.isTargetDestroyed) {
          this._source = this.targetPosition;
          SequencerEffectManager.endEffects({ effects: this });
        }
      }
      _createFile() {
        if (this.data.file === "") {
          return;
        }
        let file;
        if (this.data.customRange) {
          const template = this.template ? [this.template.gridSize, this.template.startPoint, this.template.endPoint] : [100, 0, 0];
          file = SequencerFileBase.make(
            this.data.file,
            "temporary.range.file",
            { template }
          );
        } else if (Sequencer.Database.entryExists(this.data.file)) {
          file = Sequencer.Database.getEntry(this.data.file).clone();
        } else {
          file = SequencerFileBase.make(this.data.file);
          this._currentFilePath = this.data.file;
        }
        if (file.template) {
          this._template = foundry.utils.mergeObject(
            { gridSize: file.template[0], startPoint: file.template[1], endPoint: file.template[2] },
            this.data.template
          );
        }
        file.fileIndex = this.data.forcedIndex;
        file.twister = this._twister;
        this._file = file;
        this._isRangeFind = file?.rangeFind;
      }
      _updateCurrentFilePath(distance, showDistanceWarning = false) {
        if (!this._file) {
          return;
        }
        if (!this.data.stretchTo) {
          this._currentFilePath = this._file.getFile();
          return;
        }
        distance = distance || new Ray(this.sourcePosition, this.targetPosition).distance;
        if (distance === 0 && showDistanceWarning) {
          custom_error(
            "effect",
            `stretchTo - You are stretching over a distance of "0", you may be attempting to stretch between two of the same coordinates!`
          );
        }
        this._currentFilePath = this._file.getFileForDistance(distance);
      }
      /**
       * Creates the sprite, and the relevant containers that manage the position and offsets of the overall visual look of the sprite
       *
       * @private
       */
      async _createSprite() {
        this.renderable = false;
        const spriteData = {
          antialiasing: this.data?.fileOptions?.antialiasing,
          tiling: this.data.tilingTexture,
          xray: this.data.xray || this.data.screenSpace || this.data.screenSpaceAboveUI,
          isPersisted: this.data.persist && !this.data.loopOptions?.endOnLastLoop
        };
        this.sprite = new SequencerSpriteManager(this._file, spriteData);
        this.spriteContainer.addChild(this.sprite);
        this.sprite.id = this.id + "-sprite";
        this.sprite.loopDelay = this.loopDelay;
        this.sprite.currentTime = this._startTime;
        this.sprite.loop = this.loops;
        await this.sprite.activate(this._currentFilePath);
        this.sprite.volume = (this.data.volume ?? 0) * game.settings.get("core", "globalInterfaceVolume");
        if (this._isRangeFind && this.data.stretchTo && (this.data.attachTo?.active || this.data.stretchTo?.attachTo?.active)) {
          this.sprite.preloadVariants();
        }
        if (this.data.text) {
          const text2 = this.data.text.text;
          const fontSettings = foundry.utils.deepClone(this.data.text);
          fontSettings.fontSize = (fontSettings?.fontSize ?? 26) * (150 / canvas.grid.size);
          const textSprite = this.sprite.addText({ text: text2, textStyle: fontSettings });
          textSprite.zIndex = 1;
          const textAnchor = this.data.text.anchor;
          textSprite.anchor.set(textAnchor?.x ?? 0.5, textAnchor?.y ?? 0.5);
        }
        this.sprite.filters = [];
        if (this.data.filters) {
          for (let index = 0; index < this.data.filters.length; index++) {
            const filterData = this.data.filters[index];
            const filter2 = new filters[filterData.className](filterData.data);
            filter2.id = this.id + "-" + filterData.className + "-" + index.toString();
            if (filter2 instanceof PIXI.ColorMatrixFilter) {
              this.sprite.colorMatrixFilter = filter2;
            } else {
              this.sprite.filters.push(filter2);
            }
            const filterKeyName = filterData.name || filterData.className;
            this.effectFilters[filterKeyName] = filter2;
          }
        }
        this.effectAlpha = this.data.opacity;
        let spriteOffsetX = this.data.spriteOffset?.x ?? 0;
        let spriteOffsetY = this.data.spriteOffset?.y ?? 0;
        if (this.data.spriteOffset?.gridUnits) {
          spriteOffsetX *= canvas.grid.size;
          spriteOffsetY *= canvas.grid.size;
        }
        this.sprite.position.set(spriteOffsetX, spriteOffsetY);
        this.sprite.anchor?.set(
          this.data.spriteAnchor?.x ?? 0.5,
          this.data.spriteAnchor?.y ?? 0.5
        );
        let spriteRotation = this.data.spriteRotation ?? 0;
        if (this.data.randomSpriteRotation) {
          spriteRotation += random_float_between(-360, 360, this._twister);
        }
        this.sprite.rotation = Math.normalizeRadians(
          Math.toRadians(spriteRotation)
        );
        this._customAngle = this.data.angle ?? 0;
        if (this.data.randomRotation) {
          this._customAngle += random_float_between(-360, 360, this._twister);
        }
        const offsetMap = this._nameOffsetMap?.[this.data.source];
        if (offsetMap?.angle !== void 0) {
          this._customAngle += offsetMap?.angle;
        }
        if (offsetMap?.randomRotation) {
          this._customAngle += random_float_between(-360, 360, offsetMap.twister);
        }
        this.spriteContainer.rotation = -Math.normalizeRadians(
          Math.toRadians(this._customAngle)
        );
        PluginsManager.createSprite({ effect: this });
        if (this.data.tint) {
          this.sprite.tint = this.data.tint;
        }
        if (this.shouldShowFadedVersion) {
          this.alpha = game.settings.get(CONSTANTS.MODULE_NAME, "user-effect-opacity") / 100;
          this.filters = [
            new PIXI.ColorMatrixFilter({
              saturation: -1
            })
          ];
        }
        this.updateElevation();
      }
      _createShapes() {
        const nonMaskShapes = (this.data?.shapes ?? []).filter(
          (shape) => !shape.isMask
        );
        this.shapes = {};
        for (const shape of nonMaskShapes) {
          const graphic = createShape(shape);
          graphic.filters = this.sprite.filters;
          this.spriteContainer.addChild(graphic);
          this.shapes[shape?.name ?? "shape-" + foundry.utils.randomID()] = graphic;
        }
      }
      updateElevation() {
        let targetElevation = Math.max(
          get_object_elevation(this.source ?? {}),
          get_object_elevation(this.target ?? {})
        );
        let effectElevation = this.data.elevation?.elevation ?? 0;
        if (!this.data.elevation?.absolute) {
          effectElevation += targetElevation;
        }
        this.elevation = effectElevation;
        let sort = !is_real_number(this.data.zIndex) ? this?.parent?.children?.length ?? 0 : 1e5;
        sort = PluginsManager.elevation({ effect: this, sort });
        sort += 100 + (this.data.aboveLighting ? 300 : 0);
        this.zIndex = sort + (is_real_number(this.data.zIndex) ? this.data.zIndex : 0);
        this.sort = sort;
        this.sortLayer = this.data.sortLayer;
        if (this.parent) {
          this.parent.sortChildren();
        }
      }
      updateTransform() {
        super.updateTransform();
        if (this.data.screenSpace || this.data.screenSpaceAboveUI) {
          const [screenWidth, screenHeight] = canvas.screenDimensions;
          if (this._lastScreenDimensions?.screenWidth !== screenWidth && this._lastScreenDimensions?.screenHeight !== screenHeight) {
            this._lastScreenDimensions.screenWidth = screenWidth;
            this._lastScreenDimensions.screenHeight = screenHeight;
          }
          this.position.set(
            (this.data.screenSpacePosition?.x ?? 0) + screenWidth * (this.data.screenSpaceAnchor?.x ?? this.data.anchor?.x ?? 0.5),
            (this.data.screenSpacePosition?.y ?? 0) + screenHeight * (this.data.screenSpaceAnchor?.y ?? this.data.anchor?.y ?? 0.5)
          );
          if (this.data.screenSpaceScale) {
            const scaleData = this.data.screenSpaceScale ?? { x: 1, y: 1 };
            let scaleX = scaleData.x;
            let scaleY = scaleData.y;
            this._lastScreenDimensions.width = this.sprite.texture?.width || this._lastScreenDimensions.width || this.sprite.width || this.spriteContainer.children[this.spriteContainer.children.length - 1].width;
            this._lastScreenDimensions.height = this.sprite.texture?.height || this._lastScreenDimensions.height || this.sprite.height || this.spriteContainer.children[this.spriteContainer.children.length - 1].height;
            if (scaleData.fitX) {
              scaleX = scaleX * (screenWidth / this._lastScreenDimensions.width);
            }
            if (scaleData.fitY) {
              scaleY = scaleY * (screenHeight / this._lastScreenDimensions.height);
            }
            scaleX = scaleData.ratioX ? scaleY : scaleX;
            scaleY = scaleData.ratioY ? scaleX : scaleY;
            this.scale.set(scaleX, scaleY);
          }
        }
      }
      async _setupMasks() {
        const maskShapes = this.data.shapes.filter((shape) => shape.isMask);
        if (!this.data?.masks?.length && !maskShapes.length) return;
        const maskFilter = MaskFilter.create();
        for (const uuid of this.data.masks) {
          const documentObj = fromUuidSync(uuid);
          if (!documentObj || documentObj.parent.id !== this.data.sceneId) continue;
          const obj = documentObj.object;
          let shape = obj?.mesh;
          let shapeToAdd = shape;
          if (obj instanceof FoundryShim.MeasuredTemplate || obj instanceof FoundryShim.Drawing) {
            shape = obj?.shape?.geometry?.graphicsData?.[0]?.shape ?? obj?.shape;
            shape = PluginsManager.masking({
              effect: this,
              doc: documentObj,
              obj,
              shape
            });
            shapeToAdd = new PIXI.LegacyGraphics().beginFill().drawShape(shape).endFill();
            if (obj instanceof FoundryShim.MeasuredTemplate) {
              shapeToAdd.position.set(documentObj.x, documentObj.y);
            } else {
              const {
                x,
                y,
                shape: { width: width2, height },
                rotation: rotation2
              } = documentObj;
              shapeToAdd.pivot.set(width2 / 2, height / 2);
              shapeToAdd.position.set(x + width2 / 2, y + height / 2);
              shapeToAdd.angle = rotation2;
            }
            shapeToAdd.cullable = true;
            shapeToAdd.custom = true;
            shapeToAdd.renderable = false;
            shapeToAdd.uuid = uuid;
            canvas.stage.addChild(shapeToAdd);
          }
          shapeToAdd.obj = obj;
          const updateMethod = (doc) => {
            if (doc !== documentObj) return;
            const mask = maskFilter.masks.find((shape2) => shape2.uuid === uuid);
            if (!mask) return;
            if (!mask.custom) return;
            mask.clear();
            if (obj instanceof FoundryShim.MeasuredTemplate) {
              mask.position.set(documentObj.x, documentObj.y);
              let maskObj = documentObj.object;
              shape = obj?.shape?.geometry?.graphicsData?.[0]?.shape ?? obj?.shape;
              shape = PluginsManager.masking({
                effect: this,
                doc: documentObj,
                obj: maskObj,
                shape
              });
            } else {
              const {
                x,
                y,
                shape: { width: width2, height },
                rotation: rotation2
              } = documentObj;
              mask.pivot.set(width2 / 2, height / 2);
              mask.position.set(x + width2 / 2, y + height / 2);
              mask.angle = rotation2;
            }
            mask.beginFill().drawShape(shape).endFill();
          };
          PluginsManager.maskingHooks.forEach((hook) => {
            hooksManager.addHook(this.uuid, hook, (doc) => {
              setTimeout(() => {
                updateMethod(doc);
              }, 100);
            });
          });
          hooksManager.addHook(this.uuid, this.getHook("update", uuid), (doc) => {
            setTimeout(() => {
              updateMethod(doc);
            }, 100);
          });
          maskFilter.masks.push(shapeToAdd);
        }
        for (const shapeData of maskShapes) {
          const shape = createShape(shapeData);
          shape.cullable = true;
          shape.custom = true;
          shape.renderable = false;
          this.spriteContainer.addChild(shape);
          this.shapes[shapeData?.name ?? "shape-" + foundry.utils.randomID()] = shape;
          maskFilter.masks.push(shape);
        }
        this.sprite.filters.push(maskFilter);
      }
      /**
       * Sets up the hooks relating to this effect's source and target
       *
       * @private
       */
      _setupHooks() {
        const attachedToSource = this.data.attachTo?.active && is_UUID(this.data.source);
        const attachedToTarget = (this.data.stretchTo?.attachTo || this.data.rotateTowards?.attachTo) && is_UUID(this.data.target);
        const baseRenderable = this.shouldPlayVisible;
        let renderable = baseRenderable;
        let alpha = null;
        if (attachedToSource) {
          hooksManager.addHook(this.uuid, this.getSourceHook("delete"), (doc) => {
            const uuid = doc.uuid;
            if (doc !== this.sourceDocument) return;
            this._source = this._cachedSourceData.position;
            SequencerEffectManager.objectDeleted(uuid);
          });
          if (this.isSourceDestroyed) {
            SequencerEffectManager.objectDeleted(this.sourceDocument.uuid);
          }
          if (this.data.attachTo?.bindVisibility) {
            hooksManager.addHook(
              this.uuid,
              "sightRefresh",
              () => {
                const sourceVisible = this.source && !this.sourceMesh?.occluded;
                const sourceHidden = this.sourceDocument && (this.sourceDocument?.hidden ?? false);
                const targetVisible = this.target && (!attachedToTarget || (this.targetMesh?.occluded ?? true));
                this.renderable = baseRenderable && (!sourceHidden || game.user.isGM) && (sourceVisible || targetVisible) && this._checkWallCollisions();
                this.alpha = sourceVisible && sourceHidden ? 0.5 : 1;
                renderable = baseRenderable && this.renderable;
              },
              true
            );
          }
          if (this.data.attachTo?.bindAlpha || this.data.attachTo?.bindElevation) {
            hooksManager.addHook(this.uuid, this.getSourceHook("update"), (doc) => {
              if (doc !== this.sourceDocument) return;
              if (this.data.attachTo?.bindAlpha) {
                this.spriteContainer.alpha = this.getSourceData().alpha;
              }
              if (this.data.attachTo?.bindElevation) {
                this.updateElevation();
              }
            });
          }
          if (this.data.attachTo?.bindAlpha) {
            alpha = this.getSourceData().alpha;
          }
        }
        if (attachedToTarget) {
          hooksManager.addHook(this.uuid, this.getTargetHook("delete"), (doc) => {
            if (doc !== this.target) return;
            this._target = this._cachedTargetData.position;
            const uuid = doc.uuid;
            SequencerEffectManager.objectDeleted(uuid);
          });
          if (this.isTargetDestroyed) {
            SequencerEffectManager.objectDeleted(this.targetDocument.uuid);
          }
          hooksManager.addHook(this.uuid, this.getTargetHook("update"), (doc) => {
            if (doc !== this.target) return;
            this.updateElevation();
          });
        }
        for (let uuid of this.data?.tiedDocuments ?? []) {
          const tiedDocument = fromUuidSync(uuid);
          if (tiedDocument) {
            hooksManager.addHook(
              this.uuid,
              this.getHook("delete", tiedDocument.uuid),
              (doc) => {
                if (tiedDocument !== doc) return;
                SequencerEffectManager.objectDeleted(doc.uuid);
              }
            );
          }
        }
        setTimeout(() => {
          this.renderable = renderable;
          this.spriteContainer.alpha = alpha ?? 1;
        }, 25);
      }
      /**
       * Calculates the padding and scale to stretch an effect across the given distance
       *
       * If the file is a SequencerFileBase instance, it will also pick the appropriate file for the right distance
       *
       * @param {number} distance
       * @param {number} textureWidth
       * @returns {Object}
       * @private
       */
      async _getDistanceScaling(distance, textureWidth) {
        if (!this._distanceCache || this._distanceCache?.distance !== distance) {
          let scaleX = 1;
          let scaleY = 1;
          if (this._file instanceof SequencerFileBase) {
            const startPoint = this.template?.startPoint ?? 0;
            const endPoint = this.template?.endPoint ?? 0;
            const widthWithPadding = textureWidth - (startPoint + endPoint);
            const spriteScale = distance / widthWithPadding;
            scaleX = spriteScale;
            scaleY = this.data.stretchTo?.onlyX ? widthWithPadding / textureWidth : spriteScale;
          }
          this._distanceCache = {
            scaleX,
            scaleY,
            distance
          };
        }
        return this._distanceCache;
      }
      /**
       * Applies the distance scaling to the sprite based on the previous method
       *
       * @returns {Promise<void>}
       * @private
       */
      async _applyDistanceScaling() {
        const ray = new Ray(this.sourcePosition, this.targetPosition);
        this._rotateTowards(ray);
        const distance = ray.distance / (this.data.scale.x ?? 1);
        this._updateCurrentFilePath(distance);
        await this.sprite.activate(this._currentFilePath);
        const texture = this.sprite.texture;
        let { scaleX, scaleY } = await this._getDistanceScaling(distance, texture.width);
        if (this.data.attachTo?.active) {
          this.position.set(
            this.sourcePosition.x,
            this.sourcePosition.y
          );
        }
        if (this.data.tilingTexture) {
          const scaleX2 = this.data.scale.x ?? 1;
          const scaleY2 = this.data.scale.y ?? 1;
          this.sprite.scale.set(scaleX2 * this.flipX, scaleY2 * this.flipY);
          this.sprite.width = distance * scaleX2;
          this.sprite.height = texture.height * scaleY2;
          this.sprite.tileScale.x = this.data.tilingTexture.scale.x * scaleX2;
          this.sprite.tileScale.y = this.data.tilingTexture.scale.y * scaleY2;
          this.sprite.tilePosition = this.data.tilingTexture.position;
        } else {
          this.sprite.scale.set(
            scaleX * (this.data.scale.x ?? 1) * this.flipX,
            scaleY * (this.data.scale.y ?? 1) * this.flipY
          );
        }
      }
      _setAnchors() {
        let anchor = { x: 0.5, y: 0.5, ...this.data.spriteAnchor ?? null };
        if (this.data.rotateTowards && this.data.rotateTowards.template || this.data.stretchTo) {
          const textureWidth = this.sprite.texture?.width ?? this.sprite.width;
          const templateAnchorX = this.template ? this.template.startPoint / textureWidth : void 0;
          anchor = { x: templateAnchorX, y: 0.5 };
        }
        if (this.data.rotateTowards && !this.data.rotateTowards.template && !this.data.anchor) {
          this.spriteContainer.pivot.set(this.sprite.width * -0.5, 0);
        } else {
          this.spriteContainer.pivot.set(
            interpolate(
              this.sprite.width * -0.5,
              this.sprite.width * 0.5,
              this.data.anchor?.x ?? 0.5
            ),
            interpolate(
              this.sprite.height * -0.5,
              this.sprite.height * 0.5,
              this.data.anchor?.y ?? 0.5
            )
          );
        }
        this.sprite.anchor?.set(
          this.flipX === 1 ? anchor.x : 1 - anchor.x,
          anchor.y
        );
      }
      _checkWallCollisions() {
        if (!this.data.stretchTo?.attachTo || !this.data.stretchTo?.requiresLineOfSight)
          return true;
        const ray = new Ray(this.sourcePosition, this.targetPosition);
        const blockingObjects = canvas.walls.checkCollision(ray, { type: "sight" });
        if (!blockingObjects.length && !this.data.stretchTo?.hideLineOfSight) {
          SequencerEffectManager.endEffects({ effects: this });
        }
        return !blockingObjects.length;
      }
      /**
       * Rotates the effect towards the target
       *
       * @param ray
       * @private
       */
      _rotateTowards(ray) {
        if (!ray) {
          const sourcePosition = this.flipX === 1 ? this.sourcePosition : this.targetPosition;
          const targetPosition = this.flipX === 1 ? this.targetPosition : this.sourcePosition;
          ray = new Ray(sourcePosition, targetPosition);
        }
        this.rotationContainer.rotation = Math.normalizeRadians(
          ray.angle + Math.toRadians(this.data.rotateTowards?.rotationOffset ?? 0)
        );
        PluginsManager.rotation({ effect: this });
      }
      /**
       * Transforms the sprite, rotating it, stretching it, scaling it, sizing it according its data
       *
       * @private
       */
      async _transformSprite() {
        if (this.data.stretchTo) {
          await this._applyDistanceScaling();
        }
        if (!this.data.stretchTo) {
          this._transformNoStretchSprite();
        }
        if (!this.data.screenSpace && (!this.data.attachTo?.active || this.data.stretchTo?.attachTo)) {
          this.position.set(this.sourcePosition.x, this.sourcePosition.y);
        }
        if (this.data.rotateTowards) {
          this._rotateTowards();
        }
        this._setAnchors();
        PluginsManager.rotation({ effect: this });
        this.sprite.updateDefaultScaling();
      }
      async _transformStretchToAttachedSprite() {
        try {
          await this._applyDistanceScaling();
          this._setAnchors();
        } catch (err) {
        }
      }
      _transformNoStretchSprite() {
        if (this.data.tilingTexture) {
          this.sprite.tileScale = {
            x: this.data.tilingTexture.scale.x * this.gridSizeDifference,
            y: this.data.tilingTexture.scale.y * this.gridSizeDifference
          };
          this.sprite.tilePosition = this.data.tilingTexture.position;
        }
        const { heightWidthRatio, widthHeightRatio, baseScaleX, baseScaleY } = this._getBaseScale();
        if (this.data.scaleToObject) {
          this._applyScaleToObject(heightWidthRatio, widthHeightRatio, baseScaleX, baseScaleY);
        } else if (this.data.size) {
          let { height, width: width2 } = this.data.size;
          if (this.data.size.width === "auto" || this.data.size.height === "auto") {
            height = this.sprite.height;
            width2 = this.sprite.width;
            if (this.data.size.width === "auto") {
              height = this.data.size.height;
              if (this.data.size.gridUnits) {
                height *= canvas.grid.size;
              }
              width2 = height * widthHeightRatio;
            } else if (this.data.size.height === "auto") {
              width2 = this.data.size.width;
              if (this.data.size.gridUnits) {
                width2 *= canvas.grid.size;
              }
              height = width2 * heightWidthRatio;
            }
          } else if (this.data.size.gridUnits) {
            height *= canvas.grid.size;
            width2 *= canvas.grid.size;
          }
          this.sprite.width = width2 * baseScaleX;
          this.sprite.height = height * baseScaleY;
        } else if (this.data.screenSpace) {
          this.sprite.scale.set(
            baseScaleX,
            baseScaleY
          );
        } else {
          this.sprite.scale.set(
            baseScaleX * this.gridSizeDifference,
            baseScaleY * this.gridSizeDifference
          );
        }
      }
      /**
       * Calculate the base scale and aspect ratios of the sprite
       *
       * @returns {{heightWidthRatio: number, widthHeightRatio: number, baseScaleX: number, baseScaleY: number}}
       *
       * @private
       */
      _getBaseScale() {
        const heightWidthRatio = this.sprite.height / this.sprite.width;
        const widthHeightRatio = this.sprite.width / this.sprite.height;
        const baseScaleX = (this.data.scale?.x ?? 1) * (this.data.spriteScale?.x ?? 1) * this.flipX;
        const baseScaleY = (this.data.scale?.y ?? 1) * (this.data.spriteScale?.y ?? 1) * this.flipY;
        return {
          heightWidthRatio,
          widthHeightRatio,
          baseScaleX,
          baseScaleY
        };
      }
      _applyScaleToObject(heightWidthRatio, widthHeightRatio, baseScaleX, baseScaleY) {
        try {
          let { width: width2, height } = this.getSourceData();
          if (this.sourceDocument instanceof TokenDocument) {
            width2 *= this.data.scaleToObject?.considerTokenScale ? this.sourceDocument.texture.scaleX : 1;
            height *= this.data.scaleToObject?.considerTokenScale ? this.sourceDocument.texture.scaleY : 1;
          }
          if (width2 === this._lastDimensions.width && height === this._lastDimensions.height) return;
          this._lastDimensions = { width: width2, height };
          const ratioToUse = heightWidthRatio > widthHeightRatio;
          if (this.data.scaleToObject?.uniform) {
            let newWidth = Math.max(width2, height);
            height = Math.max(width2, height);
            width2 = newWidth;
          } else {
            width2 = width2 * (ratioToUse ? widthHeightRatio : 1);
            height = height * (!ratioToUse ? heightWidthRatio : 1);
          }
          this.sprite.width = width2 * (this.data.scaleToObject?.scale ?? 1) * baseScaleX;
          this.sprite.height = height * (this.data.scaleToObject?.scale ?? 1) * baseScaleY;
          SequencerAnimationEngine.updateStartValues(this.sprite, "width");
          SequencerAnimationEngine.updateStartValues(this.sprite, "height");
          SequencerAnimationEngine.updateStartValues(this.sprite, "scale.x");
          SequencerAnimationEngine.updateStartValues(this.sprite, "scale.y");
        } catch (err) {
        }
      }
      async _transformAttachedNoStretchSprite() {
        if (this.isDestroyed) return;
        const applyRotation = this.data.attachTo?.bindRotation && !(this.sourceDocument instanceof TokenDocument && this.sourceDocument.lockRotation) && (this.sourceDocument?.rotation !== void 0 || this.sourceDocument?.direction !== void 0) && !this.data.rotateTowards && !this.data.stretchTo;
        if (applyRotation) {
          this.rotationContainer.rotation = this.getSourceData().rotation;
        }
        PluginsManager.rotation({ effect: this });
        this.position.set(
          this.sourcePosition.x,
          this.sourcePosition.y
        );
      }
      async _transformRotateTowardsAttachedSprite() {
        if (this.isDestroyed) return;
        try {
          this._rotateTowards();
          this._setAnchors();
        } catch (err) {
          debug_error(err);
        }
      }
      /**
       * Provided an animation targeting the rotation of the sprite's primary container, this method will counter-rotate
       * the sprite in an equal fashion so that the sprite's rotation remains static relative to this animation
       *
       * @param animation
       * @returns {*[]}
       * @private
       */
      _counterAnimateRotation(animation2) {
        if (animation2.target === this.spriteContainer && this.data.zeroSpriteRotation) {
          delete animation2.target;
          let counterAnimation = foundry.utils.deepClone(animation2);
          animation2.target = this.spriteContainer;
          counterAnimation.target = this.sprite;
          if (counterAnimation.values) {
            counterAnimation.values = counterAnimation.values.map(
              (value) => value * -1
            );
          } else {
            counterAnimation.from *= -1;
            counterAnimation.to *= -1;
          }
          if (!Array.isArray(animation2)) {
            animation2 = [animation2, counterAnimation];
          } else {
            animation2.push(counterAnimation);
          }
        }
        return animation2;
      }
      /**
       * Plays the custom animations of this effect
       *
       * @returns {number}
       * @private
       */
      _playCustomAnimations() {
        if (!this.data.animations) return 0;
        this._playAnimations(
          foundry.utils.deepClone(this.data.animations) ?? [],
          this.actualCreationTime - this.creationTimestamp
        );
      }
      _playAnimations(animations, timeDifference = 0) {
        let animationsToSend = [];
        const oneShotAnimations = animations.filter(
          (animation2) => !animation2.looping && !animation2.fromEnd
        );
        for (let animation2 of oneShotAnimations) {
          if (animation2.target === "alphaFilter") {
            animation2.target = this;
            animation2.propertyName = "effectAlpha";
          } else if (animation2.target === "effect") {
            animation2.target = this;
          } else {
            animation2.target = foundry.utils.getProperty(this, animation2.target);
          }
          if (!animation2.target) continue;
          if (animation2.propertyName.indexOf("rotation") > -1) {
            animation2.from = animation2.from * (Math.PI / 180);
            animation2.to = animation2.to * (Math.PI / 180);
          }
          if (["position.x", "position.y", "height", "width"].includes(
            animation2.propertyName
          ) && animation2.gridUnits) {
            animation2.from *= canvas.grid.size;
            animation2.to *= canvas.grid.size;
          }
          if (["position.x", "position.y", "height", "width"].includes(
            animation2.propertyName
          ) && animation2.screenSpace) {
            const [screenWidth, screenHeight] = canvas.screenDimensions;
            const dimension = animation2.propertyName === "position.x" || animation2.propertyName === "width" ? screenWidth : screenHeight;
            animation2.from *= dimension;
            animation2.to *= dimension;
          }
          if (["hue"].includes(animation2.propertyName)) {
            animation2.getPropertyName = "values." + animation2.propertyName;
          }
          animationsToSend = animationsToSend.concat(
            this._counterAnimateRotation(animation2)
          );
        }
        const loopingAnimations = animations.filter(
          (animation2) => animation2.looping
        );
        for (let animation2 of loopingAnimations) {
          if (animation2.target === "alphaFilter") {
            animation2.target = this;
            animation2.propertyName = "effectAlpha";
          } else if (animation2.target === "effect") {
            animation2.target = this;
          } else {
            animation2.target = foundry.utils.getProperty(this, animation2.target);
          }
          if (!animation2.target) continue;
          if (animation2.propertyName.indexOf("rotation") > -1) {
            animation2.values = animation2.values.map((angle) => {
              return angle * (Math.PI / 180);
            });
          }
          if (["position.x", "position.y", "height", "width"].includes(
            animation2.propertyName
          ) && animation2.gridUnits) {
            animation2.values = animation2.values.map((value) => {
              return value * canvas.grid.size;
            });
          }
          if (["hue"].includes(animation2.propertyName)) {
            animation2.getPropertyName = "values." + animation2.propertyName;
          }
          animationsToSend = animationsToSend.concat(
            this._counterAnimateRotation(animation2)
          );
        }
        if (!(this instanceof PersistentCanvasEffect)) {
          animationsToSend = animationsToSend.concat(
            this._getFromEndCustomAnimations()
          );
        }
        setTimeout(() => {
          SequencerAnimationEngine.addAnimation(
            this.id,
            animationsToSend,
            timeDifference
          );
        }, 20);
      }
      _getFromEndCustomAnimations(immediate = false) {
        let fromEndAnimations = [];
        const animations = foundry.utils.deepClone(this.data.animations) ?? [];
        const oneShotEndingAnimations = animations.filter(
          (animation2) => !animation2.looping && animation2.fromEnd
        );
        for (let animation2 of oneShotEndingAnimations) {
          animation2.target = foundry.utils.getProperty(this, animation2.target);
          if (!animation2.target) continue;
          animation2.delay = is_real_number(immediate) ? Math.max(immediate - animation2.duration + animation2.delay, 0) : Math.max(
            this._totalDuration - animation2.duration + animation2.delay,
            0
          );
          if (animation2.propertyName.indexOf("rotation") > -1) {
            animation2.from = animation2.from * (Math.PI / 180);
            animation2.to = animation2.to * (Math.PI / 180);
          }
          if (["position.x", "position.y", "height", "width"].includes(
            animation2.propertyName
          ) && animation2.gridUnits) {
            animation2.from *= canvas.grid.size;
            animation2.to *= canvas.grid.size;
          }
          fromEndAnimations = fromEndAnimations.concat(
            this._counterAnimateRotation(animation2)
          );
        }
        return fromEndAnimations;
      }
      /**
       * Fades in the effect at the start of the effect
       *
       * @returns {number|*}
       * @private
       */
      _fadeIn() {
        if (!this.data.fadeIn || !this.sprite) return 0;
        let fadeIn = this.data.fadeIn;
        if (this.actualCreationTime - (this.creationTimestamp + fadeIn.duration + fadeIn.delay) > 0) {
          return;
        }
        this.effectAlpha = 0;
        SequencerAnimationEngine.addAnimation(this.id, {
          target: this,
          propertyName: "effectAlpha",
          to: this.data.opacity,
          duration: fadeIn.duration,
          ease: fadeIn.ease,
          delay: fadeIn.delay,
          absolute: true
        });
        return fadeIn.duration + fadeIn.delay;
      }
      /**
       * Fades in the effect's audio at the start of the effect
       *
       * @returns {number|*}
       * @private
       */
      _fadeInAudio() {
        if (!this.data.fadeInAudio || !this.sprite || !this.sprite.hasAnimatedMedia) return 0;
        let fadeInAudio = this.data.fadeInAudio;
        if (this.actualCreationTime - (this.creationTimestamp + fadeInAudio.duration + fadeInAudio.delay) > 0)
          return;
        this.sprite.volume = 0;
        SequencerAnimationEngine.addAnimation(this.id, {
          target: this.sprite,
          propertyName: "volume",
          to: (this.data.volume ?? 0) * game.settings.get("core", "globalInterfaceVolume"),
          duration: fadeInAudio.duration,
          ease: fadeInAudio.ease,
          delay: fadeInAudio.delay,
          absolute: true
        });
        return fadeInAudio.duration + fadeInAudio.delay;
      }
      /**
       * Fades out the effect at the end of the effect's duration
       *
       * @returns {number|*}
       * @private
       */
      _fadeOut(immediate = false) {
        if (!this.data.fadeOut || !this.sprite) return 0;
        let fadeOut = this.data.fadeOut;
        fadeOut.delay = is_real_number(immediate) ? Math.max(immediate - fadeOut.duration + fadeOut.delay, 0) : Math.max(this._totalDuration - fadeOut.duration + fadeOut.delay, 0);
        SequencerAnimationEngine.addAnimation(this.id, {
          target: this,
          propertyName: "effectAlpha",
          to: 0,
          duration: fadeOut.duration,
          ease: fadeOut.ease,
          delay: fadeOut.delay,
          absolute: true
        });
        return fadeOut.duration + fadeOut.delay;
      }
      /**
       * Fades out the effect at the end of the effect's duration
       *
       * @returns {number|*}
       * @private
       */
      _fadeOutAudio(immediate = false) {
        if (!this.data.fadeOutAudio || !this.sprite || !this.sprite.hasAnimatedMedia) return 0;
        let fadeOutAudio = this.data.fadeOutAudio;
        fadeOutAudio.delay = is_real_number(immediate) ? Math.max(immediate - fadeOutAudio.duration + fadeOutAudio.delay, 0) : Math.max(
          this._totalDuration - fadeOutAudio.duration + fadeOutAudio.delay,
          0
        );
        setTimeout(() => {
          SequencerAnimationEngine.addAnimation(this.id, {
            target: this.sprite,
            propertyName: "volume",
            to: 0,
            duration: fadeOutAudio.duration,
            ease: fadeOutAudio.ease,
            delay: fadeOutAudio.delay,
            absolute: true
          });
        });
        return fadeOutAudio.duration + fadeOutAudio.delay;
      }
      /**
       * Determines the scale to animate from or to
       * @param property
       * @returns {{x: number, y: number}}
       * @private
       */
      _determineScale(property) {
        let scale2 = {
          x: this.sprite.scale.x,
          y: this.sprite.scale.y
        };
        if (is_real_number(property.value)) {
          scale2.x *= property.value * this.gridSizeDifference * this.flipX;
          scale2.y *= property.value * this.gridSizeDifference * this.flipY;
        } else {
          scale2.x *= property.value.x * this.gridSizeDifference * this.flipX;
          scale2.y *= property.value.y * this.gridSizeDifference * this.flipY;
        }
        return scale2;
      }
      /**
       * Scales the effect in at the start of the effect
       *
       * @returns {number|*}
       * @private
       */
      _scaleIn() {
        if (!this.data.scaleIn || !this.sprite) return 0;
        let scaleIn = this.data.scaleIn;
        let fromScale = this._determineScale(scaleIn);
        if (this.actualCreationTime - (this.creationTimestamp + scaleIn.duration + scaleIn.delay) > 0)
          return;
        let toScale = {
          x: this.sprite.scale.x,
          y: this.sprite.scale.y
        };
        this.sprite.scale.set(fromScale.x, fromScale.y);
        SequencerAnimationEngine.addAnimation(this.id, [
          {
            target: this.sprite,
            propertyName: "scale.x",
            from: fromScale.x,
            to: toScale.x,
            duration: scaleIn.duration,
            ease: scaleIn.ease,
            delay: scaleIn.delay,
            absolute: true
          },
          {
            target: this.sprite,
            propertyName: "scale.y",
            from: fromScale.y,
            to: toScale.y,
            duration: scaleIn.duration,
            ease: scaleIn.ease,
            delay: scaleIn.delay,
            absolute: true
          }
        ]);
        return scaleIn.duration + scaleIn.delay;
      }
      /**
       * Scales the effect out at the end of the effect's duration
       *
       * @returns {number|*}
       * @private
       */
      _scaleOut(immediate = false) {
        if (!this.data.scaleOut || !this.sprite) return 0;
        let scaleOut = this.data.scaleOut;
        let scale2 = this._determineScale(scaleOut);
        scaleOut.delay = is_real_number(immediate) ? Math.max(immediate - scaleOut.duration + scaleOut.delay, 0) : Math.max(
          this._totalDuration - scaleOut.duration + scaleOut.delay,
          0
        );
        SequencerAnimationEngine.addAnimation(this.id, [
          {
            target: this.sprite,
            propertyName: "scale.x",
            to: scale2.x,
            duration: scaleOut.duration,
            ease: scaleOut.ease,
            delay: scaleOut.delay,
            absolute: true
          },
          {
            target: this.sprite,
            propertyName: "scale.y",
            to: scale2.y,
            duration: scaleOut.duration,
            ease: scaleOut.ease,
            delay: scaleOut.delay,
            absolute: true
          }
        ]);
        return scaleOut.duration + scaleOut.delay;
      }
      /**
       * Rotates the effect in at the start of the effect
       *
       * @returns {number|*}
       * @private
       */
      _rotateIn() {
        if (!this.data.rotateIn || !this.sprite) return 0;
        let rotateIn = this.data.rotateIn;
        if (this.actualCreationTime - (this.creationTimestamp + rotateIn.duration + rotateIn.delay) > 0)
          return;
        let original_radians = this.spriteContainer.rotation;
        this.spriteContainer.rotation = rotateIn.value * (Math.PI / 180);
        SequencerAnimationEngine.addAnimation(
          this.id,
          this._counterAnimateRotation({
            target: this.spriteContainer,
            propertyName: "rotation",
            to: original_radians,
            duration: rotateIn.duration,
            ease: rotateIn.ease,
            delay: rotateIn.delay,
            absolute: true
          })
        );
        return rotateIn.duration + rotateIn.delay;
      }
      /**
       * Rotates the effect out at the end of the effect's duration
       *
       * @returns {number|*}
       * @private
       */
      _rotateOut(immediate = false) {
        if (!this.data.rotateOut || !this.sprite) return 0;
        let rotateOut = this.data.rotateOut;
        rotateOut.delay = is_real_number(immediate) ? Math.max(immediate - rotateOut.duration + rotateOut.delay, 0) : Math.max(
          this._totalDuration - rotateOut.duration + rotateOut.delay,
          0
        );
        SequencerAnimationEngine.addAnimation(
          this.id,
          this._counterAnimateRotation({
            target: this.spriteContainer,
            propertyName: "rotation",
            to: rotateOut.value * (Math.PI / 180),
            duration: rotateOut.duration,
            ease: rotateOut.ease,
            delay: rotateOut.delay,
            absolute: true
          })
        );
        return rotateOut.duration + rotateOut.delay;
      }
      /**
       * Causes the effect to move towards the given location
       *
       * @returns {number|*}
       * @private
       */
      _moveTowards() {
        if (!this.data.moves || !this.sprite) return 0;
        let moves2 = this.data.moves;
        let movementDuration = this._totalDuration;
        if (this.data.moveSpeed) {
          const distance = distance_between(
            this.sourcePosition,
            this.targetPosition
          );
          movementDuration = distance / this.data.moveSpeed * 1e3;
        }
        if (this.data.moves.rotate) this._rotateTowards();
        const duration = movementDuration - moves2.delay;
        if (this.actualCreationTime - (this.creationTimestamp + duration + moves2.delay) > 0)
          return;
        SequencerAnimationEngine.addAnimation(this.id, [
          {
            target: this,
            propertyName: "position.x",
            to: this.targetPosition.x,
            duration,
            ease: moves2.ease,
            delay: moves2.delay,
            absolute: true
          },
          {
            target: this,
            propertyName: "position.y",
            to: this.targetPosition.y,
            duration,
            ease: moves2.ease,
            delay: moves2.delay,
            absolute: true
          }
        ]);
        return duration + moves2.delay;
      }
      /**
       * If this effect is temporary, this sets the timeout for when the effect should resolve and get removed;
       *
       * @private
       */
      _setEndTimeout() {
        setTimeout(() => {
          this._resolve(this.data);
          this.endEffect();
        }, this._totalDuration);
      }
      _setupTimestampHook(offset2) {
        if (!this._file?.originalMetadata?.timestamps || this._ended) return;
        const timestamps = this._file.getTimestamps();
        const timestampArray = Array.isArray(timestamps) ? timestamps : [timestamps];
        for (const timestamp of timestampArray) {
          if (!is_real_number(timestamp)) continue;
          let realTimestamp = timestamp - offset2 / this.mediaPlaybackRate;
          if (realTimestamp < 0) {
            realTimestamp += this._endTime;
          }
          setTimeout(() => {
            if (this._ended) return;
            Hooks.callAll("sequencerEffectTimestamp", this, this._file);
            if (this.mediaLooping) {
              const offsets = (this._endTime - this.mediaCurrentTime) * -1e3;
              this._setupTimestampHook(offsets);
            }
          }, realTimestamp);
        }
      }
      /**
       * Starts the loop of this effect, calculating the difference between the effect's creation time, and the actual
       * creation time on the client
       *
       * @returns {Promise<void>}
       * @private
       */
      async _startEffect() {
        if (!this.hasAnimatedMedia) return;
        let creationTimeDifference = this.data.persist ? this.actualCreationTime - this.creationTimestamp : 0;
        creationTimeDifference *= this.mediaPlaybackRate;
        this._currentLoops = Math.floor(creationTimeDifference / this._totalDuration) + 1;
        if (this.loops && this._currentLoops > this.loops) {
          if (this.data.loopOptions?.endOnLastLoop || !this.data.persist) {
            return this.endEffect();
          }
          await this.pauseMedia();
          this.mediaCurrentTime = this._endTime;
          if (this.sprite.texture) {
            const oldRenderable = this.renderable;
            this.renderable = false;
            setTimeout(() => {
              this.updateTexture();
              setTimeout(() => {
                this.renderable ||= oldRenderable;
              }, 150);
            }, 150);
          }
          return;
        }
        return this._startLoop(creationTimeDifference);
      }
      /**
       * Kicks off the loop, or just sets the video to loop
       *
       * @param creationTimeDifference
       * @returns {Promise<void>}
       * @private
       */
      async _startLoop(creationTimeDifference) {
        if (!this._animationTimes.loopStart) {
          this._loopOffset = creationTimeDifference % this._animationDuration / 1e3;
        } else if (creationTimeDifference / 1e3 > this._animationTimes.loopStart) {
          const loopDuration = this._animationTimes.loopEnd - this._animationTimes.loopStart;
          this._loopOffset = creationTimeDifference % (loopDuration * 1e3) / 1e3;
        }
        if (this._loopOffset) {
          this.mediaCurrentTime = this._loopOffset;
        }
        await this.playMedia();
        this._addToTicker(this.loopHandler);
      }
      async loopHandler() {
        if (this._ended || this._isEnding) {
          return;
        }
        const endTime = this.data.persist ? this._animationTimes.loopEnd ?? this._endTime : this._endTime;
        if (this.mediaCurrentTime < endTime) {
          return;
        }
        if (this.restartLoopHandler != null) {
          return;
        }
        this.pauseMedia();
        this.mediaCurrentTime = this._endTime;
        if ((this.loops || !this.data.persist) && this._currentLoops >= this.loops) {
          if (!this.data.persist || this.data.persist && this.data.loopOptions?.endOnLastLoop) {
            this.endEffect();
          }
          this._ticker?.remove(this.loopHandler, this);
          return;
        }
        const restartTime = this._startTime === 0 && this._animationTimes.loopStart ? this._animationTimes.loopStart : this._startTime;
        if (!this.loopDelay) {
          this._currentLoops++;
          this.mediaCurrentTime = restartTime;
          this.playMedia();
          return;
        }
        this._currentLoops++;
        this.restartLoopHandler = setTimeout(() => {
          this.restartLoopHandler = null;
          this.mediaCurrentTime = restartTime;
          this.playMedia();
        }, this.loopDelay);
      }
    }
    class PersistentCanvasEffect extends CanvasEffect {
      /** @OVERRIDE */
      _playPresetAnimations() {
        this._moveTowards();
        this._fadeIn();
        this._scaleIn();
        this._rotateIn();
      }
      /** @OVERRIDE */
      _timeoutVisibility() {
        let creationTimeDifference = this.actualCreationTime - this.creationTimestamp;
        let timeout = creationTimeDifference === 0 && !this.data.animations ? 0 : 50;
        setTimeout(() => {
          this._setupHooks();
        }, timeout);
      }
      /** @OVERRIDE */
      _setEndTimeout() {
        let creationTimeDifference = this.actualCreationTime - this.creationTimestamp;
        if (this.loops && creationTimeDifference >= this._totalDuration && this.hasAnimatedMedia) {
          setTimeout(() => {
            this.pauseMedia();
          }, this._totalDuration);
        }
      }
      /** @OVERRIDE */
      async endEffect() {
        if (this._isEnding) return;
        this._isEnding = true;
        let extraEndDuration = this.data.extraEndDuration ?? 0;
        this.mediaLooping = false;
        if (this._animationTimes?.forcedEnd) {
          this.mediaCurrentTime = this._animationTimes.forcedEnd;
          extraEndDuration += (this.mediaDuration - (this._animationTimes?.forcedEnd ?? 0)) * 1e3;
        } else if (this._animationTimes?.loopEnd) {
          extraEndDuration += (this.mediaDuration - this.mediaCurrentTime) * 1e3;
        }
        const fromEndCustomAnimations = this._getFromEndCustomAnimations(extraEndDuration);
        const durations = [
          this._fadeOut(extraEndDuration),
          this._fadeOutAudio(extraEndDuration),
          this._scaleOut(extraEndDuration),
          this._rotateOut(extraEndDuration),
          extraEndDuration,
          ...fromEndCustomAnimations.map(
            (animation2) => animation2.duration + animation2.delay
          )
        ].filter(Boolean);
        SequencerAnimationEngine.addAnimation(this.id, fromEndCustomAnimations);
        const waitDuration = Math.max(...durations, 0);
        this._resolve(waitDuration);
        return new Promise(
          (resolve) => setTimeout(() => {
            super.endEffect();
            resolve(this.data);
          }, waitDuration)
        );
      }
    }
    function createShape(shape) {
      const graphic = new PIXI.LegacyGraphics();
      graphic.id = "sequencer-graphics-" + foundry.utils.randomID();
      graphic.beginFill(
        shape?.isMask || !is_real_number(shape?.fillColor) ? 16777215 : shape?.fillColor,
        shape?.isMask ? 1 : shape?.fillAlpha ?? 0
      );
      graphic.lineStyle(
        shape.lineSize ?? (shape?.isMask ? 1 : 0),
        shape?.lineColor ?? 16777215
      );
      const offsetX = (shape.offset?.x ?? 0) * (shape.offset?.gridUnits ? canvas.grid.size : 1);
      const offsetY = (shape.offset?.y ?? 0) * (shape.offset?.gridUnits ? canvas.grid.size : 1);
      const sizeMultiplier = shape.gridUnits ? canvas.grid.size : 1;
      graphic.offset = {
        x: offsetX,
        y: offsetY
      };
      switch (shape.type) {
        case CONSTANTS.SHAPES.CIRC:
          graphic.drawCircle(
            graphic.offset.x,
            graphic.offset.y,
            shape.radius * sizeMultiplier
          );
          break;
        case CONSTANTS.SHAPES.RECT:
          graphic.drawRect(
            graphic.offset.x,
            graphic.offset.y,
            shape.width * sizeMultiplier,
            shape.height * sizeMultiplier
          );
          break;
        case CONSTANTS.SHAPES.ELIP:
          graphic.drawEllipse(
            graphic.offset.x,
            graphic.offset.y,
            shape.width * sizeMultiplier,
            shape.height * sizeMultiplier
          );
          break;
        case CONSTANTS.SHAPES.RREC:
          graphic.drawRoundedRect(
            graphic.offset.x,
            graphic.offset.y,
            shape.width * sizeMultiplier,
            shape.height * sizeMultiplier,
            shape.radius * sizeMultiplier
          );
          break;
        case CONSTANTS.SHAPES.POLY:
          graphic.drawPolygon(
            shape.points.map((point) => {
              return new PIXI.Point(
                point[0] * sizeMultiplier,
                point[1] * sizeMultiplier
              );
            })
          );
          break;
      }
      graphic.alpha = shape.alpha ?? 1;
      graphic.endFill();
      if (shape.anchor) {
        graphic.pivot.set(
          shape.width * (shape.anchor.x ?? 0),
          shape.height * (shape.anchor.y ?? 0)
        );
      }
      return graphic;
    }
    function calculate_missed_position(source, target, twister) {
      const sourcePosition = get_object_position(source);
      const sourceDimensions = get_object_dimensions(source, true);
      if (!target) {
        const angle2 = twister.random() * Math.PI * 2;
        let x2 = Math.cos(angle2) * sourceDimensions.width;
        let y2 = Math.sin(angle2) * sourceDimensions.height;
        return {
          x: random_float_between(x2 * 1.5, x2 * 2.5, twister),
          y: random_float_between(y2 * 1.5, y2 * 2.5, twister)
        };
      }
      const targetDimensions = get_object_dimensions(target, true);
      const targetPosition = get_object_position(target);
      const ray = new Ray(targetPosition, sourcePosition);
      let startRadians = ray.angle + Math.PI / 2;
      let endRadians = ray.angle - Math.PI / 2;
      const sizeCompensation = Math.max(
        1,
        Math.abs(sourceDimensions.width - targetDimensions.height)
      );
      let distance = ray.distance / canvas.grid.size - sizeCompensation;
      if (distance <= 1) {
        const angle2 = twister.random() > 0.5 ? ray.angle + Math.PI / 4 : ray.angle - Math.PI / 4;
        const x2 = Math.cos(angle2) * targetDimensions.width;
        const y2 = Math.sin(angle2) * targetDimensions.height;
        return { x: x2, y: y2 };
      }
      distance = Math.max(Math.abs(distance - 15), 6);
      endRadians -= Math.PI / distance;
      startRadians += Math.PI / distance;
      const angle = interpolate(startRadians, endRadians, twister.random());
      const x = Math.cos(angle) * targetDimensions.width;
      const y = Math.sin(angle) * targetDimensions.height;
      return {
        x: random_float_between(x * 1.5, x * 2.5, twister),
        y: random_float_between(y * 1.5, y * 2.5, twister)
      };
    }
    function get_object_position(obj, { measure = false, exact = false } = {}) {
      if (obj instanceof CanvasEffect) {
        return obj.worldPosition;
      }
      obj = obj?._object ?? obj.object ?? obj;
      let pos = {};
      if (obj instanceof FoundryShim.MeasuredTemplate) {
        if (measure) {
          if (obj.document.t === "cone" || obj.document.t === "ray") {
            pos.x = obj.ray.B.x;
            pos.y = obj.ray.B.y;
          }
        }
        if (obj.document.t === "rect") {
          pos.x = obj.x;
          pos.y = obj.y;
          if (!exact) {
            pos.x += Math.abs(obj.shape.width / 2) + obj.shape.x;
            pos.y += Math.abs(obj.shape.height / 2) + obj.shape.y;
          }
        }
      } else if (obj instanceof FoundryShim.Tile) {
        pos = {
          x: obj.document.x,
          y: obj.document.y
        };
        if (!exact) {
          pos.x += Math.abs(obj.document.width / 2);
          pos.y += Math.abs(obj.document.height / 2);
        }
      } else if (obj instanceof FoundryShim.Token) {
        const halfSize = get_object_dimensions(obj, true);
        pos = {
          x: obj.x + halfSize.width,
          y: obj.y + halfSize.height
        };
        if (exact) {
          pos.x -= halfSize.width;
          pos.y -= halfSize.height;
        }
      } else if (obj instanceof FoundryShim.Drawing) {
        pos = {
          x: obj.document.x,
          y: obj.document.y
        };
        if (!exact) {
          const halfSize = get_object_dimensions(obj, true);
          pos.x += halfSize.width;
          pos.y += halfSize.height;
        }
      }
      pos = {
        x: pos.x ?? obj?.x ?? obj?.position?.x ?? obj?.position?._x ?? obj?.document?.x ?? obj?.document?.position?.x ?? null,
        y: pos.y ?? obj?.y ?? obj?.position?.y ?? obj?.position?._y ?? obj?.document?.y ?? obj?.document?.position?.y ?? null,
        elevation: obj?.elevation ?? obj?.document?.elevation ?? null
      };
      if (pos.x === null) delete pos["x"];
      if (pos.y === null) delete pos["y"];
      if (pos.elevation === null) delete pos["elevation"];
      return pos;
    }
    function get_random_offset(target, randomOffset, twister = false) {
      let { width: width2, height } = get_object_dimensions(target, true);
      width2 *= randomOffset;
      height *= randomOffset;
      return {
        x: random_float_between(width2 * -1, width2, twister),
        y: random_float_between(height * -1, height, twister)
      };
    }
    function get_object_dimensions(inObj, half = false) {
      inObj = inObj?.object ?? inObj?._object ?? inObj;
      let width2 = inObj?.hitArea?.width ?? inObj?.w ?? inObj?.shape?.width ?? (inObj?.shape?.radius ? inObj?.shape?.radius * 2 : void 0) ?? inObj?.bounds?.width ?? inObj?.width ?? canvas.grid.size;
      let height = inObj?.hitArea?.height ?? inObj?.h ?? inObj?.shape?.height ?? (inObj?.shape?.radius ? inObj?.shape?.radius * 2 : void 0) ?? inObj?.bounds?.height ?? inObj?.height ?? canvas.grid.size;
      return {
        width: width2 / (half ? 2 : 1),
        height: height / (half ? 2 : 1)
      };
    }
    const alignments = {
      "top-left": { x: 0.5, y: 0.5 },
      top: { x: 0, y: 0.5 },
      "top-right": { x: -0.5, y: 0.5 },
      left: { x: 0.5, y: 0 },
      center: { x: 0, y: 0 },
      right: { x: -0.5, y: 0 },
      "bottom-left": { x: 0.5, y: -0.5 },
      bottom: { x: 0, y: -0.5 },
      "bottom-right": { x: -0.5, y: -0.5 }
    };
    function align({
      context,
      spriteWidth,
      spriteHeight,
      align: align2,
      edge
    } = {}) {
      let { width: width2, height } = get_object_dimensions(context);
      const alignRatio = alignments[align2];
      const offset2 = {
        x: interpolate(width2 * -0.5, width2 * 0.5, alignRatio.x + 0.5),
        y: interpolate(height * -0.5, height * 0.5, alignRatio.y + 0.5)
      };
      return {
        x: offset2.x + (edge && edge !== "on" ? spriteWidth * alignRatio.x * (edge === "outer" ? 1 : -1) : 0),
        y: offset2.y + (edge && edge !== "on" ? spriteHeight * alignRatio.y * (edge === "outer" ? 1 : -1) : 0)
      };
    }
    function is_object_canvas_data(inObj) {
      if (typeof inObj !== "object") return false;
      const keys = Object.keys(inObj);
      keys.sort();
      return keys.includes("x") && keys.includes("y") || keys.includes("height") && keys.includes("width") && keys.includes("x") && keys.includes("y");
    }
    function get_object_canvas_data(inObject, { measure = false, uuid = true } = {}) {
      inObject = inObject?.object ?? inObject;
      const data = {
        ...get_object_position(inObject, { measure }),
        ...get_object_dimensions(inObject?.mesh ?? inObject?.tile ?? inObject),
        elevation: get_object_elevation(inObject),
        cachedLocation: true
      };
      if (uuid) {
        data["uuid"] = inObject?.document?.uuid ?? inObject?.uuid;
      }
      return data;
    }
    function get_object_elevation(inObject) {
      return inObject?.document?.elevation ?? inObject?.elevation ?? 0;
    }
    function get_mouse_position(snapToGrid = false) {
      const pos = getCanvasMouse().getLocalPosition(canvas.app.stage);
      const snappingOptions = {
        mode: CONST.GRID_SNAPPING_MODES.CENTER | CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.EDGE_MIDPOINT
      };
      return !snapToGrid ? new PIXI.Point(pos.x, pos.y) : canvas.grid.getSnappedPoint({ x: pos.x, y: pos.y }, snappingOptions);
    }
    function distance_between(p1, p2) {
      return new Ray(p1, p2).distance;
    }
    function validateObject(inObject, sceneId) {
      if (is_UUID(inObject) || !is_object_canvas_data(inObject)) {
        inObject = get_object_from_scene(inObject, sceneId);
      }
      return inObject?._object ?? inObject;
    }
    function getPositionFromData(data, type = "source") {
      const source = data.nameOffsetMap[data[type]] ? data.nameOffsetMap[data[type]][type] : validateObject(data[type], data.sceneId);
      const position = source instanceof FoundryShim.PlaceableObject ? get_object_position(source) : source?.worldPosition || source?.center || source;
      const multiplier = data.randomOffset?.[type] ?? data.randomOffset;
      const twister = createMersenneTwister(data.seed);
      if (source && multiplier) {
        let randomOffset = get_random_offset(
          source,
          multiplier,
          twister
        );
        position.x -= randomOffset.x;
        position.y -= randomOffset.y;
      }
      let extraOffset = data.offset;
      if (extraOffset) {
        let newOffset = {
          x: extraOffset.x,
          y: extraOffset.y
        };
        if (extraOffset.gridUnits) {
          newOffset.x *= canvas.grid.size;
          newOffset.y *= canvas.grid.size;
        }
        if (extraOffset.local) {
          newOffset = rotateAroundPoint(
            0,
            0,
            newOffset.x,
            newOffset.y,
            source?.rotation ?? 0
          );
        }
        position.x -= newOffset.x;
        position.y -= newOffset.y;
      }
      return position;
    }
    function is_position_within_bounds(inPosition, inElement, relativeTo) {
      const localPosition = inElement.toLocal(inPosition, relativeTo);
      return inElement.getLocalBounds().contains(localPosition.x, localPosition.y);
    }
    function rotate_coordinate(p1, p2, radians) {
      let cos = Math.cos(radians);
      let sin = Math.sin(radians);
      let nx = cos * (p2.x - p1.x) + sin * (p2.y - p1.y) + p1.x;
      let ny = cos * (p2.y - p1.y) - sin * (p2.x - p1.x) + p1.y;
      return [nx, ny];
    }
    function get_closest_token(inPosition, { minimumDistance = false } = {}) {
      let tokens = Array.from(canvas.scene.tokens);
      if (minimumDistance) {
        tokens = tokens.filter(
          (token) => distance_between(get_object_position(token), inPosition) <= minimumDistance
        );
      }
      tokens.sort((a, b) => {
        return distance_between(get_object_position(a), inPosition) - distance_between(get_object_position(b), inPosition);
      });
      return tokens?.[0] ?? false;
    }
    function rotateAroundPoint(cx, cy, x, y, radians) {
      const cos = Math.cos(radians);
      const sin = Math.sin(radians);
      const nx = cos * (x - cx) + sin * (y - cy) + cx;
      const ny = cos * (y - cy) - sin * (x - cx) + cy;
      return { x: nx, y: ny };
    }
    function validateAnimation(inTarget, inPropertyName, inOptions) {
      if (typeof inPropertyName !== "string") {
        return `inPropertyName must be of type string`;
      }
      if (typeof inTarget !== "string") {
        return `inTarget must be of type string`;
      }
      if (!is_real_number(inOptions.from)) {
        return `inOptions.from must be of type number`;
      }
      if (!is_real_number(inOptions.to)) {
        return `inOptions.to must be of type number`;
      }
      if (!is_real_number(inOptions.duration)) {
        return `inOptions.duration must be of type number`;
      }
      if (inOptions?.delay !== void 0 && !is_real_number(inOptions.delay)) {
        return `inOptions.delay must be of type number`;
      }
      if (inOptions?.ease !== void 0 && typeof inOptions.ease !== "string") {
        return `inOptions.ease must be of type string`;
      }
      if (inOptions?.fromEnd !== void 0 && typeof inOptions.fromEnd !== "boolean") {
        return `inOptions.fromEnd must be of type boolean`;
      }
      if (inOptions?.screenSpace !== void 0 && typeof inOptions.screenSpace !== "boolean") {
        return `inOptions.screenSpace must be of type boolean`;
      }
      if (inOptions?.gridUnits !== void 0) {
        if (typeof inOptions.gridUnits !== "boolean") {
          return `inOptions.gridUnits must be of type boolean`;
        }
        if (inOptions.gridUnits && ![
          "position.x",
          "position.y",
          "scale.x",
          "scale.y",
          "height",
          "width"
        ].includes(inPropertyName)) {
          return `if inOptions.gridUnits is true, inPropertyName must be position.x, position.y, scale.x, scale.y, width, or height`;
        }
      }
      if (inOptions?.absolute !== void 0 && typeof inOptions.absolute !== "boolean") {
        return `inOptions.absolute must be of type boolean`;
      }
      return {
        target: inTarget,
        propertyName: inPropertyName,
        from: inOptions?.from,
        to: inOptions?.to,
        duration: inOptions?.duration ?? 0,
        delay: inOptions?.delay ?? 0,
        ease: inOptions?.ease ?? "linear",
        looping: false,
        fromEnd: inOptions?.fromEnd ?? false,
        gridUnits: inOptions?.gridUnits ?? false,
        absolute: inOptions?.absolute ?? false,
        screenSpace: inOptions?.screenSpace ?? false
      };
    }
    function validateLoopingAnimation(inTarget, inPropertyName, inOptions) {
      if (typeof inPropertyName !== "string") {
        return `inPropertyName must be of type string`;
      }
      if (typeof inTarget !== "string") {
        return `inTarget must be of type string`;
      }
      if (!inOptions?.values) {
        if (!inOptions?.from === void 0 || !inOptions?.to === void 0) {
          return `if inOptions.values is not set, you must provide inOptions.from and inOptions.to`;
        }
        if (!is_real_number(inOptions.from)) {
          return `inOptions.from must be of type number`;
        }
        if (!is_real_number(inOptions.to)) {
          return `inOptions.to must be of type number`;
        }
        inOptions.values = [inOptions?.from, inOptions?.to];
        delete inOptions.from;
        delete inOptions.to;
      } else {
        if (!Array.isArray(inOptions.values)) {
          return `inOptions.values must be of type array`;
        }
        inOptions.values.forEach((value) => {
          if (!is_real_number(value)) {
            return `values in inOptions.keys must be of type number`;
          }
        });
      }
      if (!is_real_number(inOptions.duration)) {
        return `inOptions.duration must be of type number`;
      }
      if (inOptions?.delay !== void 0 && !is_real_number(inOptions.delay)) {
        return `inOptions.delay must be of type number`;
      }
      if (inOptions?.ease !== void 0 && typeof inOptions.ease !== "string") {
        return `inOptions.ease must be of type string`;
      }
      if (inOptions?.loops !== void 0 && !is_real_number(inOptions.loops)) {
        return `inOptions.loops must be of type number`;
      }
      if (inOptions?.pingPong !== void 0 && typeof inOptions.pingPong !== "boolean") {
        return `inOptions.pingPong must be of type boolean`;
      }
      if (inOptions?.screenSpace !== void 0 && typeof inOptions.screenSpace !== "boolean") {
        return `inOptions.screenSpace must be of type boolean`;
      }
      if (inOptions?.gridUnits !== void 0) {
        if (typeof inOptions.gridUnits !== "boolean") {
          return `inOptions.gridUnits must be of type boolean`;
        }
        if (inOptions.gridUnits && ![
          "position.x",
          "position.y",
          "scale.x",
          "scale.y",
          "height",
          "width"
        ].includes(inPropertyName)) {
          return `if inOptions.gridUnits is true, inPropertyName must be position.x, position.y, scale.x, scale.y, width, or height`;
        }
      }
      return {
        target: inTarget,
        propertyName: inPropertyName,
        values: inOptions?.values,
        duration: inOptions?.duration ?? 0,
        delay: inOptions?.delay ?? 0,
        ease: inOptions?.ease ?? "linear",
        looping: true,
        loops: inOptions?.loops,
        indefinite: inOptions?.loops === void 0 || !is_real_number(inOptions?.loops),
        pingPong: inOptions?.pingPong ?? false,
        gridUnits: inOptions?.gridUnits ?? false,
        screenSpace: inOptions?.screenSpace ?? false
      };
    }
    const PlayerSettings = {
      file: {
        label: "SEQUENCER.Player.Option.File",
        store: writable(""),
        default: ""
      },
      scale: {
        label: "SEQUENCER.Player.Option.Scale",
        store: writable(1),
        default: 1
      },
      users: {
        label: "SEQUENCER.Player.Option.ForUsers",
        store: writable([]),
        default: []
      },
      belowTokens: {
        label: "SEQUENCER.Player.Option.BelowTokens",
        store: writable(false),
        default: false
      },
      snapToGrid: {
        label: "SEQUENCER.Player.Option.SnapToGrid",
        store: writable(false),
        default: false
      },
      rotation: {
        label: "SEQUENCER.Player.Option.Rotation",
        store: writable(0),
        default: 0
      },
      randomRotation: {
        label: "SEQUENCER.Player.Option.Randomize",
        store: writable(false),
        default: false
      },
      fadeIn: {
        label: "SEQUENCER.Player.Option.FadeIn",
        store: writable(0),
        default: 0
      },
      fadeOut: {
        label: "SEQUENCER.Player.Option.FadeOut",
        store: writable(0),
        default: 0
      },
      scaleIn: {
        label: "SEQUENCER.Player.Option.ScaleIn",
        store: writable(0),
        default: 0
      },
      scaleOut: {
        label: "SEQUENCER.Player.Option.ScaleOut",
        store: writable(0),
        default: 0
      },
      mirrorX: {
        label: "SEQUENCER.Player.Option.MirrorX",
        store: writable(false),
        default: false
      },
      mirrorY: {
        label: "SEQUENCER.Player.Option.MirrorY",
        store: writable(false),
        default: false
      },
      randomMirrorX: {
        label: "SEQUENCER.Player.Option.Randomize",
        store: writable(false),
        default: false
      },
      randomMirrorY: {
        label: "SEQUENCER.Player.Option.Randomize",
        store: writable(false),
        default: false
      },
      offsetX: {
        label: "SEQUENCER.Player.Option.OffsetX",
        store: writable(0),
        default: 0
      },
      offsetY: {
        label: "SEQUENCER.Player.Option.OffsetY",
        store: writable(0),
        default: 0
      },
      offsetGridUnits: {
        label: "SEQUENCER.Player.Option.GridUnits",
        store: writable(false),
        default: false
      },
      randomOffsetAmount: {
        label: "SEQUENCER.Player.Option.RandomOffset",
        store: writable(0),
        default: 0
      },
      randomOffset: {
        label: "SEQUENCER.Player.Option.Randomize",
        store: writable(false),
        default: false
      },
      preload: {
        label: "SEQUENCER.Player.Option.Preload",
        store: writable(false),
        default: false
      },
      moveTowards: {
        label: "SEQUENCER.Player.Option.DragBehavior",
        label_off: "SEQUENCER.Player.Option.DragStretch",
        label_on: "SEQUENCER.Player.Option.DragMove",
        store: writable(false),
        default: false
      },
      moveSpeed: {
        label: "SEQUENCER.Player.Option.MoveSpeed",
        store: writable(0),
        default: 0
      },
      attachTo: {
        label: "SEQUENCER.Player.Option.AttachTo",
        store: writable(false),
        default: false,
        callback: (e) => {
          EffectPlayer.sourceAttach = e.target.checked;
        }
      },
      stretchToAttach: {
        label: "SEQUENCER.Player.Option.StretchToAttach",
        store: writable(false),
        default: false,
        callback: (e) => {
          EffectPlayer.targetAttach = e.target.checked;
        }
      },
      persist: {
        label: "SEQUENCER.Player.Option.Persist",
        store: writable(false),
        default: false
      },
      repeat: {
        label: "SEQUENCER.Player.Option.Repeat",
        store: writable(false),
        default: false
      },
      repetitions: {
        label: "SEQUENCER.Player.Option.Repetitions",
        store: writable(1),
        default: 1
      },
      repeatDelayMin: {
        label: "SEQUENCER.Player.Option.DelayMin",
        store: writable(200),
        default: 200
      },
      repeatDelayMax: {
        label: "SEQUENCER.Player.Option.DelayMax",
        store: writable(400),
        default: 400
      }
    };
    PlayerSettings.export = () => {
      return Object.fromEntries(
        Object.entries(PlayerSettings).map((entry) => {
          return [entry[0], get_store_value(entry[1].store)];
        })
      );
    };
    PlayerSettings.import = (settings) => {
      Object.entries(PlayerSettings).forEach((entry) => {
        if (settings?.[entry[0]] !== void 0) {
          entry[1].store.set(settings?.[entry[0]]);
        } else if (entry[1]?.default !== void 0) {
          entry[1].store.set(entry[1].default);
        }
      });
    };
    PlayerSettings.getPresets = () => {
      return Object.keys(game.settings.get(CONSTANTS.MODULE_NAME, "effectPresets"));
    };
    PlayerSettings.loadPreset = (name2) => {
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      return PlayerSettings.import(effectPresets[name2]);
    };
    PlayerSettings.savePreset = async (name2) => {
      const newName = await promptNewPresetName(name2);
      if (!newName) return;
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      effectPresets[newName] = PlayerSettings.export();
      return game.settings.set(
        CONSTANTS.MODULE_NAME,
        "effectPresets",
        effectPresets
      );
    };
    PlayerSettings.copyPreset = async (name2) => {
      const newName = await promptNewPresetName(name2, true);
      if (!newName) return;
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      effectPresets[newName] = PlayerSettings.export();
      return game.settings.set(
        CONSTANTS.MODULE_NAME,
        "effectPresets",
        effectPresets
      );
    };
    PlayerSettings.deletePreset = (name2) => {
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      delete effectPresets[name2];
      return game.settings.set(
        CONSTANTS.MODULE_NAME,
        "effectPresets",
        effectPresets
      );
    };
    async function promptNewPresetName(inName, copy = false) {
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      let title = copy ? game.i18n.localize("SEQUENCER.Player.CopyPresetTitle") : game.i18n.localize("SEQUENCER.Player.CreateNewPresetTitle");
      let presetName = await new Promise((resolve) => {
        new Dialog({
          title,
          content: `<p><input type="text" placeholder="${game.i18n.localize(
            "SEQUENCER.Player.CreateNewPresetInputLabel"
          )}" id="newPresetName" style="width:100%;"></p>`,
          buttons: {
            okay: {
              icon: '<i class="fas fa-check"></i>',
              label: game.i18n.localize("SEQUENCER.OK"),
              callback: async (html) => {
                let name2 = html.find("#newPresetName").val();
                if (name2 === "" || !name2) {
                  name2 = false;
                }
                resolve(name2);
              }
            },
            cancel: {
              icon: '<i class="fas fa-times"></i>',
              label: game.i18n.localize("SEQUENCER.Cancel"),
              callback: () => {
                resolve(false);
              }
            }
          },
          close: () => {
          },
          render: (html) => {
            html.find("#newPresetName").val(inName).focus();
          }
        }).render(true);
      });
      if (presetName) {
        if (presetName.toLowerCase() === "default") {
          Dialog.prompt({
            title: game.i18n.localize("SEQUENCER.Player.DefaultErrorTitle"),
            content: `<p>${game.i18n.localize(
              "SEQUENCER.Player.DefaultErrorContent"
            )}</p>`,
            label: game.i18n.localize("SEQUENCER.OK"),
            callback: () => {
            }
          });
          return false;
        }
        if (effectPresets[presetName]) {
          const overwrite = await Dialog.confirm({
            title: game.i18n.localize("SEQUENCER.Player.OverwritePresetTitle"),
            content: `<p>${game.i18n.format(
              "SEQUENCER.Player.OverwritePresetContent",
              { preset_name: presetName }
            )}</p>`
          });
          if (!overwrite) {
            presetName = await promptPresetName(presetName);
          }
        }
      }
      return presetName;
    }
    PlayerSettings.migrateOldPresets = () => {
      if (!game.user.isGM) return;
      const effectPresets = game.settings.get(
        CONSTANTS.MODULE_NAME,
        "effectPresets"
      );
      const presetsToUpdate = Object.values(effectPresets).filter((preset) => {
        return !preset?.version;
      });
      if (!presetsToUpdate.length) return;
      const newEffectPresets = Object.fromEntries(
        Object.entries(effectPresets).map(([name2, preset]) => {
          if (preset?.version) return [name2, preset];
          preset.version = game.modules.get(CONSTANTS.MODULE_NAME).version;
          if (preset.repetitions > 1) {
            preset.repeat = true;
          }
          if (preset.randomMirrorY) {
            preset.mirrorY = true;
          }
          if (preset.randomOffset) {
            preset.randomOffsetAmount = 1;
            preset.offsetGridUnits = true;
          }
          return [name2, preset];
        })
      );
      return game.settings.set(
        CONSTANTS.MODULE_NAME,
        "effectPresets",
        newEffectPresets
      );
    };
    const InteractionManager = {
      startDragPosition: false,
      state: {
        LeftMouseDown: false,
        RightMouseDown: false,
        Dragging: false
      },
      get isLayerActive() {
        return canvas.sequencerInterfaceLayer.active;
      },
      initialize() {
        window.addEventListener("mousedown", (event) => {
          if (!canvas.ready) return;
          if (!this.isLayerActive) return;
          const hover = document.elementFromPoint(event.clientX, event.clientY);
          if (!hover || hover.id !== "board") return;
          const button = event.button;
          if (!(button === 0 || button === 2)) return;
          if (button === 0) {
            this.state.LeftMouseDown = true;
            this._propagateEvent("mouseLeftDown");
          }
          if (button === 2) {
            this.state.RightMouseDown = true;
            this._propagateEvent("mouseRightDown");
          }
        });
        window.addEventListener("mouseup", (event) => {
          if (!canvas.ready) return;
          if (!this.isLayerActive) return;
          const hover = document.elementFromPoint(event.clientX, event.clientY);
          if (!hover || hover.id !== "board") return;
          if (document.activeElement.tagName !== "BODY") return;
          const button = event.button;
          if (!(button === 0 || button === 2)) return;
          if (button === 0) {
            this.state.LeftMouseDown = false;
            this._propagateEvent("mouseLeftUp");
            this.state.Dragging = false;
            this.startDragPosition = false;
          }
          if (button === 2) {
            this.state.RightMouseDown = false;
            this._propagateEvent("mouseRightUp");
            this.state.Dragging = false;
            this.startDragPosition = false;
          }
        });
        window.addEventListener("mousemove", (event) => {
          if (!canvas.ready) return;
          if (!this.isLayerActive) return;
          const hover = document.elementFromPoint(event.clientX, event.clientY);
          if (!hover || hover.id !== "board") return;
          this._propagateEvent("mouseMove");
          if (this.state.LeftMouseDown && !this.startDragPosition) {
            this.startDragPosition = get_mouse_position();
          }
          if (this.state.LeftMouseDown && !this.state.Dragging) {
            const distance = distance_between(
              this.startDragPosition,
              get_mouse_position()
            );
            this.state.Dragging = distance > 20;
          }
        });
        EffectPlayer.initialize();
        SelectionManager.initialize();
      },
      tearDown() {
        EffectPlayer.tearDown();
        SelectionManager.tearDown();
      },
      _propagateEvent(eventName) {
        if (EffectPlayer.isActive && EffectPlayer[eventName]) {
          EffectPlayer[eventName]();
        }
        if (SelectionManager.isActive && SelectionManager[eventName]) {
          SelectionManager[eventName]();
        }
      }
    };
    const EffectPlayer = {
      sequenceBuffer: [],
      playMany: false,
      playManySequenced: false,
      cursorPos: false,
      startPos: false,
      endPos: false,
      get snapLocationToGrid() {
        return get_store_value(PlayerSettings.snapToGrid.store);
      },
      get sourceAttach() {
        return get_store_value(PlayerSettings.attachTo.store);
      },
      get targetAttach() {
        return get_store_value(PlayerSettings.stretchToAttach.store);
      },
      sourceAttachFound: false,
      targetAttachFound: false,
      get isActive() {
        return InteractionManager.isLayerActive && game?.activeTool === CONSTANTS.TOOLS.PLAY;
      },
      /**
       * Opens the Sequencer Effects UI with the player tab open
       */
      show() {
        return EffectsUIApp.show({ tab: "player" });
      },
      initialize() {
        this.layer = canvas.sequencerInterfaceLayer;
      },
      tearDown() {
        this._reset();
      },
      /**
       * Mouse events
       */
      mouseLeftDown() {
        this._evaluateStartPosition();
      },
      mouseLeftUp() {
        if (!this.startPos) return;
        this._playEffect();
        this.startPos = false;
        this.endPos = false;
        this.sourceAttachFound = false;
        this.targetAttachFound = false;
      },
      mouseRightUp() {
        this._reset();
      },
      mouseMove() {
        this._evaluateCursorPosition();
        if (InteractionManager.state.Dragging) {
          this._evaluateEndPosition();
        }
      },
      /**
       * Hotkeys
       */
      playManyUp() {
        this._playEffects();
        this._reset();
      },
      /**
       * Private methods
       */
      _evaluatePosition(attach = false) {
        let position = get_mouse_position(this.snapLocationToGrid);
        const attachToObject = attach ? get_closest_token(position, {
          minimumDistance: canvas.grid.size
        }) : false;
        let attachFound = false;
        if (attachToObject) {
          attachFound = true;
          position = get_object_position(attachToObject);
        }
        return [position, attachFound];
      },
      _evaluateCursorPosition() {
        const attach = InteractionManager.state.Dragging ? this.targetAttach : this.sourceAttach;
        [this.cursorPos] = this._evaluatePosition(attach);
      },
      _evaluateStartPosition() {
        if (this.startPos) return;
        [this.startPos, this.sourceAttachFound] = this._evaluatePosition(
          this.sourceAttach
        );
      },
      _evaluateEndPosition() {
        [this.endPos, this.targetAttachFound] = this._evaluatePosition(
          this.targetAttach
        );
      },
      _reset() {
        if (!this.layer) return;
        this.startPos = false;
        this.endPos = false;
        this.sourceAttachFound = false;
        this.targetAttachFound = false;
        this.sequenceBuffer = [];
        this._evaluateCursorPosition();
      },
      async _playEffect() {
        const settings = foundry.utils.mergeObject(PlayerSettings.export(), {
          ...InteractionManager.state,
          startPos: this.startPos,
          endPos: this.endPos
        });
        if (!settings.users.length || settings.users?.[0] === "all")
          settings.users = [];
        if (settings.file === "") return;
        if (!(Sequencer.Database.entryExists(settings.file) || await SequencerFileCache.srcExists(settings.file))) {
          throw custom_error(
            "Sequencer",
            `Sequencer Player | Could not find file or database entry: ${settings.file}`
          );
        }
        if (settings.preload) {
          await Sequencer.Preloader.preloadForClients(settings.file);
        }
        const sequence = this.sequenceBuffer.length > 0 && this.playManySequenced ? this.sequenceBuffer[this.sequenceBuffer.length - 1] : new Sequence();
        const effect = sequence.effect().file(settings.file).forUsers(settings.users).mirrorX(settings.mirrorX && !settings.randomMirrorX).mirrorY(settings.mirrorY && !settings.randomMirrorY).randomizeMirrorX(settings.randomMirrorX).randomizeMirrorY(settings.randomMirrorY).persist(settings.persist).belowTokens(settings.belowTokens);
        if (settings.repeat) {
          effect.repeats(
            settings.repetitions,
            settings.repeatDelayMin,
            settings.repeatDelayMax
          );
        }
        if (settings.fadeIn > 0) effect.fadeIn(settings.fadeIn);
        if (settings.fadeOut > 0) effect.fadeOut(settings.fadeOut);
        const offsetData = settings.randomOffset ? {
          offset: { x: settings.offsetX, y: settings.offsetY },
          gridUnits: settings.offsetGridUnits
        } : {};
        const offsetSource = !settings.Dragging ? offsetData : {};
        const attachToObject = settings.attachTo ? get_closest_token(settings.startPos, {
          minimumDistance: canvas.grid.size
        }) : false;
        if (attachToObject) {
          effect.attachTo(attachToObject, {
            randomOffset: settings.randomOffset && !settings.Dragging ? settings.randomOffsetAmount : false,
            ...offsetSource
          });
        } else {
          effect.atLocation(settings.startPos, {
            randomOffset: settings.randomOffset && !settings.Dragging ? settings.randomOffsetAmount : false,
            ...offsetSource
          });
        }
        if (settings.persist && settings.name && settings.name !== "" && settings.name !== "default" && settings.name !== "new") {
          effect.name("Preset: " + settings.name);
        }
        if (settings.Dragging) {
          if (settings.moveTowards) {
            effect.moveTowards(settings.endPos, {
              randomOffset: settings.randomOffset ? settings.randomOffsetAmount : false,
              ...offsetData
            });
            if (settings.moveSpeed) {
              effect.moveSpeed(settings.moveSpeed);
            }
          } else {
            let target = settings.stretchToAttach ? get_closest_token(settings.endPos, {
              minimumDistance: canvas.grid.size
            }) : settings.endPos;
            effect.stretchTo(target, {
              attachTo: settings.stretchToAttach,
              randomOffset: settings.randomOffset ? settings.randomOffsetAmount : false,
              ...offsetData
            });
          }
        }
        if (!settings.Dragging || settings.Dragging && settings.moveTowards) {
          effect.scale(settings.scale);
          if (settings.scaleIn > 0)
            effect.scaleIn(0, settings.scaleIn, { ease: "easeInOutSine" });
          if (settings.scaleOut > 0)
            effect.scaleOut(0, settings.scaleOut, { ease: "easeInOutSine" });
          effect.randomRotation(settings.randomRotation);
        }
        if (this.playManySequenced) {
          effect.waitUntilFinished();
        }
        if (!this.playManySequenced || this.sequenceBuffer.length === 0) {
          this.sequenceBuffer.push(sequence);
        }
        if (!this.playMany && !this.playManySequenced) this._playEffects();
      },
      _playEffects() {
        this.sequenceBuffer.forEach((sequence) => sequence.play());
        this.sequenceBuffer = [];
      }
    };
    const SelectionManager = {
      selectedEffect: false,
      hoveredEffects: /* @__PURE__ */ new Set(),
      suggestedProperties: false,
      sourceOrTarget: false,
      dragOffset: false,
      hoveredEffectUI: false,
      get snapToGrid() {
        return get_store_value(PlayerSettings.snapToGrid.store);
      },
      set snapToGrid(bool) {
        PlayerSettings.snapToGrid.store.set(bool);
      },
      set attachToTarget(bool) {
        PlayerSettings.stretchToAttach.store.set(bool);
      },
      get attachToTarget() {
        return get_store_value(PlayerSettings.stretchToAttach.store);
      },
      get isActive() {
        return InteractionManager.isLayerActive && game?.activeTool === CONSTANTS.TOOLS.SELECT;
      },
      get effects() {
        return SequencerEffectManager.effects.filter(
          (effect) => effect.userCanDelete
        );
      },
      initialize() {
        this.layer = canvas.sequencerInterfaceLayer;
      },
      tearDown() {
        this._reset();
        this.hoveredEffects = /* @__PURE__ */ new Set();
      },
      sourcePointSelected() {
        this.sourceOrTarget = "source";
      },
      targetPointSelected() {
        this.sourceOrTarget = "target";
      },
      /**
       * Mouse Events
       */
      mouseLeftDown() {
        if (!this.selectedEffect) {
          return this._selectEffects();
        }
        if (!this.hoveredEffects.size) {
          this._reset();
        }
      },
      mouseRightDown() {
      },
      mouseLeftUp() {
        if (!InteractionManager.state.Dragging) {
          return this._selectEffects();
        }
        if (!InteractionManager.state.Dragging || !this.selectedEffect || !this.suggestedProperties)
          return;
        this._updateEffect();
      },
      mouseRightUp() {
        InteractionManager.state.LeftMouseDown = false;
        this.suggestedProperties = false;
        this.sourceOrTarget = false;
        this.dragOffset = false;
      },
      mouseMove() {
        this._evaluateHoveredEffects();
        if (InteractionManager.state.LeftMouseDown && !InteractionManager.state.RightMouseDown) {
          this._evaluateEffectPositionUpdate();
        }
      },
      /**
       * Hotkeys
       */
      async delete() {
        if (!this.selectedEffect) return;
        await SequencerEffectManager.endEffects({ effects: this.selectedEffect });
        this.selectedEffect = false;
      },
      attachToTargetDown() {
        if (InteractionManager.state.LeftMouseDown && !InteractionManager.state.RightMouseDown) {
          this._evaluateEffectPositionUpdate();
        }
      },
      /**
       * Private methods
       */
      _selectEffects() {
        this._reset();
        if (!this.hoveredEffects.size) return;
        const firstElement = Array.from(this.hoveredEffects)[0];
        this.selectedEffect = !firstElement.selected ? firstElement : false;
      },
      _evaluateHoveredEffects() {
        const position = get_mouse_position();
        this.hoveredEffects = this.effects.filter(
          (effect) => effect.isPositionWithinBounds(position)
        );
        this.hoveredEffects.sort((a, b) => {
          return a.data.layer !== b.data.zIndex ? a.data.zIndex - b.data.zIndex : a.data.layer - b.data.zIndex;
        });
        this.hoveredEffects = new Set(this.hoveredEffects);
      },
      _evaluateEffectPositionUpdate() {
        if (!this.selectedEffect) return;
        if (this.selectedEffect.data.stretchTo && !this.sourceOrTarget) {
          return;
        }
        let showCursor = false;
        let showPoint = this.snapToGrid;
        let position = get_mouse_position(this.snapToGrid);
        if (!this.selectedEffect.data.stretchTo && !this.dragOffset) {
          this.dragOffset = {
            x: position.x - this.selectedEffect.position.x,
            y: position.y - this.selectedEffect.position.y
          };
        }
        if (this.attachToTarget) {
          const obj = get_closest_token(position, {
            minimumDistance: canvas.grid.size
          });
          if (obj) {
            position = get_object_position(obj);
            showCursor = true;
            showPoint = false;
          }
        }
        if (this.dragOffset && !showCursor && !this.snapToGrid) {
          position.x -= this.dragOffset.x;
          position.y -= this.dragOffset.y;
        }
        const color = (this.sourceOrTarget || "source") === "source" ? CONSTANTS.COLOR.PRIMARY : CONSTANTS.COLOR.SECONDARY;
        this.suggestedProperties = {
          position,
          showCursor,
          showPoint,
          color
        };
      },
      _updateEffect() {
        if (!this.selectedEffect) return;
        const updates = {
          attachTo: this.selectedEffect.data.attachTo,
          stretchTo: this.selectedEffect.data.stretchTo
        };
        const obj = this.attachToTarget ? get_closest_token(this.suggestedProperties.position, {
          minimumDistance: canvas.grid.size,
          type: TokenDocument
        }) : false;
        let objUuid = obj ? get_object_identifier(obj) : false;
        if (this.sourceOrTarget === "source") {
          if (!updates.attachTo) {
            updates.attachTo = {
              active: false,
              align: "center",
              rotation: true,
              bindVisibility: true,
              bindAlpha: true
            };
          }
          updates.attachTo = foundry.utils.mergeObject(updates.attachTo || {}, {
            active: this.attachToTarget && !!objUuid
          });
          if (this.attachToTarget && objUuid) {
            updates.source = objUuid;
          } else {
            updates["source"] = this.suggestedProperties.position;
          }
        } else if (this.sourceOrTarget === "target") {
          updates.stretchTo.attachTo = this.attachToTarget && !!objUuid;
          if (this.attachToTarget && objUuid) {
            updates.target = objUuid;
          } else {
            updates["target"] = this.suggestedProperties.position;
          }
        } else {
          updates["source"] = this.suggestedProperties.position;
        }
        this.selectedEffect.update(updates);
        this.suggestedProperties = false;
        this.sourceOrTarget = false;
        this.dragOffset = false;
      },
      _reset() {
        this.selectedEffect = false;
        this.suggestedProperties = false;
        this.sourceOrTarget = false;
        this.dragOffset = false;
      }
    };
    function create_fragment$d(ctx) {
      let div1;
      let button;
      let t0;
      let div0;
      let t1_value = (
        /*getEffectName*/
        ctx[1](
          /*effect*/
          ctx[0]
        ) + ""
      );
      let t1;
      let mounted;
      let dispose;
      return {
        c() {
          div1 = element("div");
          button = element("button");
          button.innerHTML = `<i class="fas fa-times"></i>`;
          t0 = space();
          div0 = element("div");
          t1 = text$1(t1_value);
          attr(button, "class", "btn_end svelte-seq-1fyjvdk");
          attr(button, "type", "button");
          attr(div0, "class", "effect-text hover-text svelte-seq-1fyjvdk");
          attr(div1, "class", "effect hover-highlight svelte-seq-1fyjvdk");
        },
        m(target, anchor) {
          insert(target, div1, anchor);
          append(div1, button);
          append(div1, t0);
          append(div1, div0);
          append(div0, t1);
          if (!mounted) {
            dispose = [
              listen(
                button,
                "click",
                /*endEffect*/
                ctx[4]
              ),
              listen(
                div1,
                "mouseleave",
                /*mouseLeave*/
                ctx[3]
              ),
              listen(
                div1,
                "mouseover",
                /*mouseOver*/
                ctx[2]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*effect*/
          1 && t1_value !== (t1_value = /*getEffectName*/
          ctx2[1](
            /*effect*/
            ctx2[0]
          ) + "")) set_data(t1, t1_value);
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div1);
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$c($$self, $$props, $$invalidate) {
      let { effect } = $$props;
      function getEffectName(effect2) {
        let effectName = "";
        if (effect2.data.file && typeof effect2.data.file === "string") {
          effectName = effect2.data.file.split("\\").pop().split("/").pop();
        } else if (effect2.data.file && typeof effect2.data.file === "object") {
          effectName = Object.values(effect2.data.file)[0].split("\\").pop().split("/").pop();
        } else if (effect2.data.text) {
          effectName = "Text: " + effect2.data.text.text;
        } else {
          effectName = effect2.data?.shapes?.[0]?.type ? "Shape: " + effect2.data.shapes[0]?.type : "Unknown effect";
        }
        effectName = effect2.data.name ? `${effect2.data.name} (${effectName})` : effectName;
        if (effect2.data.creatorUserId !== game.userId) {
          let user_name = game.users.get(effect2.data.creatorUserId)?.name;
          let formattedUsername = user_name ? localize("SEQUENCER.ManagerPlayersEffect", { user_name }) : localize("SEQUENCER.ManagerUnknownEffect");
          effectName += ` (${formattedUsername})`;
        }
        return effectName;
      }
      function mouseOver() {
        SelectionManager.hoveredEffectUI = effect;
      }
      function mouseLeave() {
        SelectionManager.hoveredEffectUI = false;
      }
      function endEffect() {
        SequencerEffectManager.endEffects({ effects: [effect] });
      }
      $$self.$$set = ($$props2) => {
        if ("effect" in $$props2) $$invalidate(0, effect = $$props2.effect);
      };
      return [effect, getEffectName, mouseOver, mouseLeave, endEffect];
    }
    class EffectEntry extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$c, create_fragment$d, safe_not_equal, { effect: 0 });
      }
    }
    function create_fragment$c(ctx) {
      let div1;
      let button;
      let t0;
      let div0;
      let t1_value = (
        /*sound*/
        ctx[0].src.split("/").slice(-1) + ""
      );
      let t1;
      let mounted;
      let dispose;
      return {
        c() {
          div1 = element("div");
          button = element("button");
          button.innerHTML = `<i class="fas fa-times"></i>`;
          t0 = space();
          div0 = element("div");
          t1 = text$1(t1_value);
          attr(button, "class", "btn_end svelte-seq-1fyjvdk");
          attr(button, "type", "button");
          attr(div0, "class", "effect-text hover-text svelte-seq-1fyjvdk");
          attr(div1, "class", "effect hover-highlight svelte-seq-1fyjvdk");
        },
        m(target, anchor) {
          insert(target, div1, anchor);
          append(div1, button);
          append(div1, t0);
          append(div1, div0);
          append(div0, t1);
          if (!mounted) {
            dispose = listen(
              button,
              "click",
              /*endSound*/
              ctx[1]
            );
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*sound*/
          1 && t1_value !== (t1_value = /*sound*/
          ctx2[0].src.split("/").slice(-1) + "")) set_data(t1, t1_value);
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div1);
          }
          mounted = false;
          dispose();
        }
      };
    }
    function instance$b($$self, $$props, $$invalidate) {
      let { id } = $$props;
      let { sound } = $$props;
      function endSound() {
        SequencerSoundManager.endSounds({ sounds: [id] }, true);
      }
      $$self.$$set = ($$props2) => {
        if ("id" in $$props2) $$invalidate(2, id = $$props2.id);
        if ("sound" in $$props2) $$invalidate(0, sound = $$props2.sound);
      };
      return [sound, endSound, id];
    }
    class SoundEntry extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$b, create_fragment$c, safe_not_equal, { id: 2, sound: 0 });
      }
    }
    function get_each_context$3(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[10] = list[i][0];
      child_ctx[11] = list[i][1];
      return child_ctx;
    }
    function get_each_context_1$1(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[14] = list[i];
      return child_ctx;
    }
    function get_each_context_2$1(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[14] = list[i];
      return child_ctx;
    }
    function create_if_block_5(ctx) {
      let div;
      let h2;
      return {
        c() {
          div = element("div");
          h2 = element("h2");
          h2.textContent = `${localize("SEQUENCER.Manager.NothingPlaying")}`;
          attr(div, "class", "no-effects");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, h2);
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
        }
      };
    }
    function create_if_block_1(ctx) {
      let button;
      let t1;
      let div;
      let t2;
      let t3;
      let current;
      let mounted;
      let dispose;
      let if_block0 = (
        /*persistentEffects*/
        ctx[2].length && create_if_block_4(ctx)
      );
      let if_block1 = (
        /*temporaryEffects*/
        ctx[1].length && /*persistentEffects*/
        ctx[2].length && create_if_block_3()
      );
      let if_block2 = (
        /*temporaryEffects*/
        ctx[1].length && create_if_block_2(ctx)
      );
      return {
        c() {
          button = element("button");
          button.textContent = `${localize("SEQUENCER.Manager.EndAllEffects")}`;
          t1 = space();
          div = element("div");
          if (if_block0) if_block0.c();
          t2 = space();
          if (if_block1) if_block1.c();
          t3 = space();
          if (if_block2) if_block2.c();
          attr(button, "class", "w-100 end-all-effects mb-2 svelte-seq-nc5j73");
          attr(button, "type", "button");
          attr(div, "class", "effects svelte-seq-nc5j73");
        },
        m(target, anchor) {
          insert(target, button, anchor);
          insert(target, t1, anchor);
          insert(target, div, anchor);
          if (if_block0) if_block0.m(div, null);
          append(div, t2);
          if (if_block1) if_block1.m(div, null);
          append(div, t3);
          if (if_block2) if_block2.m(div, null);
          current = true;
          if (!mounted) {
            dispose = listen(
              button,
              "click",
              /*endAllEffects*/
              ctx[6]
            );
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (
            /*persistentEffects*/
            ctx2[2].length
          ) {
            if (if_block0) {
              if_block0.p(ctx2, dirty);
              if (dirty & /*persistentEffects*/
              4) {
                transition_in(if_block0, 1);
              }
            } else {
              if_block0 = create_if_block_4(ctx2);
              if_block0.c();
              transition_in(if_block0, 1);
              if_block0.m(div, t2);
            }
          } else if (if_block0) {
            group_outros();
            transition_out(if_block0, 1, 1, () => {
              if_block0 = null;
            });
            check_outros();
          }
          if (
            /*temporaryEffects*/
            ctx2[1].length && /*persistentEffects*/
            ctx2[2].length
          ) {
            if (if_block1) ;
            else {
              if_block1 = create_if_block_3();
              if_block1.c();
              if_block1.m(div, t3);
            }
          } else if (if_block1) {
            if_block1.d(1);
            if_block1 = null;
          }
          if (
            /*temporaryEffects*/
            ctx2[1].length
          ) {
            if (if_block2) {
              if_block2.p(ctx2, dirty);
              if (dirty & /*temporaryEffects*/
              2) {
                transition_in(if_block2, 1);
              }
            } else {
              if_block2 = create_if_block_2(ctx2);
              if_block2.c();
              transition_in(if_block2, 1);
              if_block2.m(div, null);
            }
          } else if (if_block2) {
            group_outros();
            transition_out(if_block2, 1, 1, () => {
              if_block2 = null;
            });
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block0);
          transition_in(if_block2);
          current = true;
        },
        o(local) {
          transition_out(if_block0);
          transition_out(if_block2);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(button);
            detach(t1);
            detach(div);
          }
          if (if_block0) if_block0.d();
          if (if_block1) if_block1.d();
          if (if_block2) if_block2.d();
          mounted = false;
          dispose();
        }
      };
    }
    function create_if_block_4(ctx) {
      let h2;
      let t1;
      let div;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let current;
      let each_value_2 = ensure_array_like(
        /*persistentEffects*/
        ctx[2]
      );
      const get_key = (ctx2) => (
        /*effect*/
        ctx2[14].id
      );
      for (let i = 0; i < each_value_2.length; i += 1) {
        let child_ctx = get_each_context_2$1(ctx, each_value_2, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block_2$1(key, child_ctx));
      }
      return {
        c() {
          h2 = element("h2");
          h2.textContent = `${localize("SEQUENCER.Manager.PersistentEffects")}`;
          t1 = space();
          div = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
        },
        m(target, anchor) {
          insert(target, h2, anchor);
          insert(target, t1, anchor);
          insert(target, div, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div, null);
            }
          }
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty & /*persistentEffects*/
          4) {
            each_value_2 = ensure_array_like(
              /*persistentEffects*/
              ctx2[2]
            );
            group_outros();
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value_2, each_1_lookup, div, outro_and_destroy_block, create_each_block_2$1, null, get_each_context_2$1);
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          for (let i = 0; i < each_value_2.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(h2);
            detach(t1);
            detach(div);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
        }
      };
    }
    function create_each_block_2$1(key_1, ctx) {
      let first;
      let effectentry;
      let current;
      effectentry = new EffectEntry({ props: { effect: (
        /*effect*/
        ctx[14]
      ) } });
      return {
        key: key_1,
        first: null,
        c() {
          first = empty();
          create_component(effectentry.$$.fragment);
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          mount_component(effectentry, target, anchor);
          current = true;
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const effectentry_changes = {};
          if (dirty & /*persistentEffects*/
          4) effectentry_changes.effect = /*effect*/
          ctx[14];
          effectentry.$set(effectentry_changes);
        },
        i(local) {
          if (current) return;
          transition_in(effectentry.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(effectentry.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(first);
          }
          destroy_component(effectentry, detaching);
        }
      };
    }
    function create_if_block_3(ctx) {
      let hr;
      return {
        c() {
          hr = element("hr");
        },
        m(target, anchor) {
          insert(target, hr, anchor);
        },
        d(detaching) {
          if (detaching) {
            detach(hr);
          }
        }
      };
    }
    function create_if_block_2(ctx) {
      let h2;
      let t1;
      let div;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let current;
      let each_value_1 = ensure_array_like(
        /*temporaryEffects*/
        ctx[1]
      );
      const get_key = (ctx2) => (
        /*effect*/
        ctx2[14].id
      );
      for (let i = 0; i < each_value_1.length; i += 1) {
        let child_ctx = get_each_context_1$1(ctx, each_value_1, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block_1$1(key, child_ctx));
      }
      return {
        c() {
          h2 = element("h2");
          h2.textContent = `${localize("SEQUENCER.Manager.TemporaryEffects")}`;
          t1 = space();
          div = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
        },
        m(target, anchor) {
          insert(target, h2, anchor);
          insert(target, t1, anchor);
          insert(target, div, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div, null);
            }
          }
          current = true;
        },
        p(ctx2, dirty) {
          if (dirty & /*temporaryEffects*/
          2) {
            each_value_1 = ensure_array_like(
              /*temporaryEffects*/
              ctx2[1]
            );
            group_outros();
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value_1, each_1_lookup, div, outro_and_destroy_block, create_each_block_1$1, null, get_each_context_1$1);
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          for (let i = 0; i < each_value_1.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(h2);
            detach(t1);
            detach(div);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
        }
      };
    }
    function create_each_block_1$1(key_1, ctx) {
      let first;
      let effectentry;
      let current;
      effectentry = new EffectEntry({ props: { effect: (
        /*effect*/
        ctx[14]
      ) } });
      return {
        key: key_1,
        first: null,
        c() {
          first = empty();
          create_component(effectentry.$$.fragment);
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          mount_component(effectentry, target, anchor);
          current = true;
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const effectentry_changes = {};
          if (dirty & /*temporaryEffects*/
          2) effectentry_changes.effect = /*effect*/
          ctx[14];
          effectentry.$set(effectentry_changes);
        },
        i(local) {
          if (current) return;
          transition_in(effectentry.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(effectentry.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(first);
          }
          destroy_component(effectentry, detaching);
        }
      };
    }
    function create_if_block$2(ctx) {
      let button;
      let t1;
      let div1;
      let h2;
      let t3;
      let div0;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let current;
      let mounted;
      let dispose;
      let each_value = ensure_array_like(
        /*sounds*/
        ctx[3]
      );
      const get_key = (ctx2) => (
        /*id*/
        ctx2[10]
      );
      for (let i = 0; i < each_value.length; i += 1) {
        let child_ctx = get_each_context$3(ctx, each_value, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block$3(key, child_ctx));
      }
      return {
        c() {
          button = element("button");
          button.textContent = `${localize("SEQUENCER.Manager.EndAllSounds")}`;
          t1 = space();
          div1 = element("div");
          h2 = element("h2");
          h2.textContent = `${localize("SEQUENCER.Manager.Sounds")}`;
          t3 = space();
          div0 = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          attr(button, "class", "w-100 end-all-effects mb-2 svelte-seq-nc5j73");
          attr(button, "type", "button");
        },
        m(target, anchor) {
          insert(target, button, anchor);
          insert(target, t1, anchor);
          insert(target, div1, anchor);
          append(div1, h2);
          append(div1, t3);
          append(div1, div0);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div0, null);
            }
          }
          current = true;
          if (!mounted) {
            dispose = listen(
              button,
              "click",
              /*endAllSounds*/
              ctx[7]
            );
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (dirty & /*sounds*/
          8) {
            each_value = ensure_array_like(
              /*sounds*/
              ctx2[3]
            );
            group_outros();
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div0, outro_and_destroy_block, create_each_block$3, null, get_each_context$3);
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          for (let i = 0; i < each_value.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(button);
            detach(t1);
            detach(div1);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
          mounted = false;
          dispose();
        }
      };
    }
    function create_each_block$3(key_1, ctx) {
      let first;
      let soundentry;
      let current;
      soundentry = new SoundEntry({
        props: {
          id: (
            /*id*/
            ctx[10]
          ),
          sound: (
            /*sound*/
            ctx[11]
          )
        }
      });
      return {
        key: key_1,
        first: null,
        c() {
          first = empty();
          create_component(soundentry.$$.fragment);
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          mount_component(soundentry, target, anchor);
          current = true;
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const soundentry_changes = {};
          if (dirty & /*sounds*/
          8) soundentry_changes.id = /*id*/
          ctx[10];
          if (dirty & /*sounds*/
          8) soundentry_changes.sound = /*sound*/
          ctx[11];
          soundentry.$set(soundentry_changes);
        },
        i(local) {
          if (current) return;
          transition_in(soundentry.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(soundentry.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(first);
          }
          destroy_component(soundentry, detaching);
        }
      };
    }
    function create_fragment$b(ctx) {
      let div;
      let t0;
      let t1;
      let current;
      let if_block0 = !/*effects*/
      ctx[0].length && !/*sounds*/
      ctx[3].length && create_if_block_5();
      let if_block1 = (
        /*effects*/
        ctx[0].length && create_if_block_1(ctx)
      );
      let if_block2 = (
        /*sounds*/
        ctx[3].length && create_if_block$2(ctx)
      );
      return {
        c() {
          div = element("div");
          if (if_block0) if_block0.c();
          t0 = space();
          if (if_block1) if_block1.c();
          t1 = space();
          if (if_block2) if_block2.c();
          attr(div, "class", "effects-container svelte-seq-nc5j73");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if (if_block0) if_block0.m(div, null);
          append(div, t0);
          if (if_block1) if_block1.m(div, null);
          append(div, t1);
          if (if_block2) if_block2.m(div, null);
          current = true;
        },
        p(ctx2, [dirty]) {
          if (!/*effects*/
          ctx2[0].length && !/*sounds*/
          ctx2[3].length) {
            if (if_block0) ;
            else {
              if_block0 = create_if_block_5();
              if_block0.c();
              if_block0.m(div, t0);
            }
          } else if (if_block0) {
            if_block0.d(1);
            if_block0 = null;
          }
          if (
            /*effects*/
            ctx2[0].length
          ) {
            if (if_block1) {
              if_block1.p(ctx2, dirty);
              if (dirty & /*effects*/
              1) {
                transition_in(if_block1, 1);
              }
            } else {
              if_block1 = create_if_block_1(ctx2);
              if_block1.c();
              transition_in(if_block1, 1);
              if_block1.m(div, t1);
            }
          } else if (if_block1) {
            group_outros();
            transition_out(if_block1, 1, 1, () => {
              if_block1 = null;
            });
            check_outros();
          }
          if (
            /*sounds*/
            ctx2[3].length
          ) {
            if (if_block2) {
              if_block2.p(ctx2, dirty);
              if (dirty & /*sounds*/
              8) {
                transition_in(if_block2, 1);
              }
            } else {
              if_block2 = create_if_block$2(ctx2);
              if_block2.c();
              transition_in(if_block2, 1);
              if_block2.m(div, null);
            }
          } else if (if_block2) {
            group_outros();
            transition_out(if_block2, 1, 1, () => {
              if_block2 = null;
            });
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block1);
          transition_in(if_block2);
          current = true;
        },
        o(local) {
          transition_out(if_block1);
          transition_out(if_block2);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if (if_block0) if_block0.d();
          if (if_block1) if_block1.d();
          if (if_block2) if_block2.d();
        }
      };
    }
    function instance$a($$self, $$props, $$invalidate) {
      let effects;
      let sounds;
      let persistentEffects;
      let temporaryEffects;
      let $RunningSounds;
      let $VisibleEffects;
      const VisibleEffects = SequenceManager.VisibleEffects;
      component_subscribe($$self, VisibleEffects, (value) => $$invalidate(9, $VisibleEffects = value));
      const RunningSounds = SequenceManager.RunningSounds;
      component_subscribe($$self, RunningSounds, (value) => $$invalidate(8, $RunningSounds = value));
      function endAllEffects() {
        Sequencer.EffectManager.endEffects({
          effects: effects.filter((effect) => effect.userCanDelete && !effect.data.private)
        });
      }
      function endAllSounds() {
        SequencerSoundManager.endSounds({
          sounds: Object.entries($RunningSounds).filter((e) => e[1].sound_playing).map((e) => e[0])
        });
      }
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*$VisibleEffects*/
        512) {
          $$invalidate(0, effects = Object.values($VisibleEffects));
        }
        if ($$self.$$.dirty & /*$RunningSounds*/
        256) {
          $$invalidate(3, sounds = Object.entries($RunningSounds).filter((e) => e[1].sound_playing));
        }
        if ($$self.$$.dirty & /*effects*/
        1) {
          $$invalidate(2, persistentEffects = effects.filter((effect) => effect.data.persist));
        }
        if ($$self.$$.dirty & /*effects*/
        1) {
          $$invalidate(1, temporaryEffects = effects.filter((effect) => !effect.data.persist));
        }
      };
      return [
        effects,
        temporaryEffects,
        persistentEffects,
        sounds,
        VisibleEffects,
        RunningSounds,
        endAllEffects,
        endAllSounds,
        $RunningSounds,
        $VisibleEffects
      ];
    }
    class Manager extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$a, create_fragment$b, safe_not_equal, {});
      }
    }
    function create_fragment$a(ctx) {
      let div;
      let label;
      let t0_value = localize(
        /*setting*/
        ctx[0].label
      ) + "";
      let t0;
      let t1;
      let input0;
      let t2;
      let input1;
      let applyStyles_action;
      let mounted;
      let dispose;
      return {
        c() {
          div = element("div");
          label = element("label");
          t0 = text$1(t0_value);
          t1 = space();
          input0 = element("input");
          t2 = space();
          input1 = element("input");
          attr(label, "class", "svelte-seq-x3192w");
          input0.disabled = /*$isLocked*/
          ctx[6];
          attr(
            input0,
            "max",
            /*max*/
            ctx[2]
          );
          attr(
            input0,
            "min",
            /*min*/
            ctx[1]
          );
          attr(
            input0,
            "step",
            /*step*/
            ctx[4]
          );
          attr(input0, "type", "range");
          attr(input0, "class", "svelte-seq-x3192w");
          input1.disabled = /*$isLocked*/
          ctx[6];
          attr(
            input1,
            "max",
            /*maxInput*/
            ctx[3]
          );
          attr(
            input1,
            "min",
            /*min*/
            ctx[1]
          );
          input1.required = true;
          attr(
            input1,
            "step",
            /*step*/
            ctx[4]
          );
          attr(input1, "type", "number");
          attr(input1, "class", "svelte-seq-x3192w");
          set_style(div, "display", "flex");
          set_style(div, "align-items", "center");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, label);
          append(label, t0);
          append(div, t1);
          append(div, input0);
          set_input_value(
            input0,
            /*$store*/
            ctx[7]
          );
          append(div, t2);
          append(div, input1);
          set_input_value(
            input1,
            /*$store*/
            ctx[7]
          );
          if (!mounted) {
            dispose = [
              listen(
                input0,
                "change",
                /*input0_change_input_handler*/
                ctx[11]
              ),
              listen(
                input0,
                "input",
                /*input0_change_input_handler*/
                ctx[11]
              ),
              listen(
                input1,
                "input",
                /*input1_input_handler*/
                ctx[12]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                div,
                /*styles*/
                ctx[5]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*setting*/
          1 && t0_value !== (t0_value = localize(
            /*setting*/
            ctx2[0].label
          ) + "")) set_data(t0, t0_value);
          if (dirty & /*$isLocked*/
          64) {
            input0.disabled = /*$isLocked*/
            ctx2[6];
          }
          if (dirty & /*max*/
          4) {
            attr(
              input0,
              "max",
              /*max*/
              ctx2[2]
            );
          }
          if (dirty & /*min*/
          2) {
            attr(
              input0,
              "min",
              /*min*/
              ctx2[1]
            );
          }
          if (dirty & /*step*/
          16) {
            attr(
              input0,
              "step",
              /*step*/
              ctx2[4]
            );
          }
          if (dirty & /*$store*/
          128) {
            set_input_value(
              input0,
              /*$store*/
              ctx2[7]
            );
          }
          if (dirty & /*$isLocked*/
          64) {
            input1.disabled = /*$isLocked*/
            ctx2[6];
          }
          if (dirty & /*maxInput*/
          8) {
            attr(
              input1,
              "max",
              /*maxInput*/
              ctx2[3]
            );
          }
          if (dirty & /*min*/
          2) {
            attr(
              input1,
              "min",
              /*min*/
              ctx2[1]
            );
          }
          if (dirty & /*step*/
          16) {
            attr(
              input1,
              "step",
              /*step*/
              ctx2[4]
            );
          }
          if (dirty & /*$store*/
          128 && to_number(input1.value) !== /*$store*/
          ctx2[7]) {
            set_input_value(
              input1,
              /*$store*/
              ctx2[7]
            );
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          32) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx2[5]
          );
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$9($$self, $$props, $$invalidate) {
      let $isLocked;
      let $store;
      let { setting } = $$props;
      let { lock = false } = $$props;
      let { min = 0.1 } = $$props;
      let { max = 2 } = $$props;
      let { maxInput = Infinity } = $$props;
      let { step = 0.01 } = $$props;
      let { styles = {} } = $$props;
      const store = setting.store;
      component_subscribe($$self, store, (value) => $$invalidate(7, $store = value));
      const isLocked = lock ? lock.store : writable(false);
      component_subscribe($$self, isLocked, (value) => $$invalidate(6, $isLocked = value));
      function input0_change_input_handler() {
        $store = to_number(this.value);
        store.set($store);
      }
      function input1_input_handler() {
        $store = to_number(this.value);
        store.set($store);
      }
      $$self.$$set = ($$props2) => {
        if ("setting" in $$props2) $$invalidate(0, setting = $$props2.setting);
        if ("lock" in $$props2) $$invalidate(10, lock = $$props2.lock);
        if ("min" in $$props2) $$invalidate(1, min = $$props2.min);
        if ("max" in $$props2) $$invalidate(2, max = $$props2.max);
        if ("maxInput" in $$props2) $$invalidate(3, maxInput = $$props2.maxInput);
        if ("step" in $$props2) $$invalidate(4, step = $$props2.step);
        if ("styles" in $$props2) $$invalidate(5, styles = $$props2.styles);
      };
      return [
        setting,
        min,
        max,
        maxInput,
        step,
        styles,
        $isLocked,
        $store,
        store,
        isLocked,
        lock,
        input0_change_input_handler,
        input1_input_handler
      ];
    }
    class SliderInput extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$9, create_fragment$a, safe_not_equal, {
          setting: 0,
          lock: 10,
          min: 1,
          max: 2,
          maxInput: 3,
          step: 4,
          styles: 5
        });
      }
    }
    function create_fragment$9(ctx) {
      let div;
      let input;
      let input_disabled_value;
      let t0;
      let label_1;
      let t1_value = localize(
        /*setting*/
        ctx[0].label
      ) + "";
      let t1;
      let applyStyles_action;
      let mounted;
      let dispose;
      return {
        c() {
          div = element("div");
          input = element("input");
          t0 = space();
          label_1 = element("label");
          t1 = text$1(t1_value);
          attr(
            input,
            "id",
            /*id*/
            ctx[5]
          );
          input.disabled = input_disabled_value = /*$isLocked*/
          ctx[3] !== /*inverse*/
          ctx[1];
          set_style(input, "height", "15px");
          attr(input, "type", "checkbox");
          attr(
            label_1,
            "for",
            /*id*/
            ctx[5]
          );
          set_style(div, "display", "flex");
          set_style(div, "align-items", "center");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, input);
          input.checked = /*$store*/
          ctx[4];
          append(div, t0);
          append(div, label_1);
          append(label_1, t1);
          if (!mounted) {
            dispose = [
              listen(
                input,
                "change",
                /*input_change_handler*/
                ctx[10]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                div,
                /*styles*/
                ctx[2]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*$isLocked, inverse*/
          10 && input_disabled_value !== (input_disabled_value = /*$isLocked*/
          ctx2[3] !== /*inverse*/
          ctx2[1])) {
            input.disabled = input_disabled_value;
          }
          if (dirty & /*$store*/
          16) {
            input.checked = /*$store*/
            ctx2[4];
          }
          if (dirty & /*setting*/
          1 && t1_value !== (t1_value = localize(
            /*setting*/
            ctx2[0].label
          ) + "")) set_data(t1, t1_value);
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          4) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx2[2]
          );
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$8($$self, $$props, $$invalidate) {
      let $store;
      let $isLocked;
      let { setting } = $$props;
      let { label = false } = $$props;
      let { lock = false } = $$props;
      let { inverse = false } = $$props;
      let { styles = {} } = $$props;
      const id = "sequencer-input-" + foundry.utils.randomID();
      const store = setting.store;
      component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
      const isLocked = lock ? lock.store : writable(inverse);
      component_subscribe($$self, isLocked, (value) => $$invalidate(3, $isLocked = value));
      function input_change_handler() {
        $store = this.checked;
        store.set($store);
      }
      $$self.$$set = ($$props2) => {
        if ("setting" in $$props2) $$invalidate(0, setting = $$props2.setting);
        if ("label" in $$props2) $$invalidate(8, label = $$props2.label);
        if ("lock" in $$props2) $$invalidate(9, lock = $$props2.lock);
        if ("inverse" in $$props2) $$invalidate(1, inverse = $$props2.inverse);
        if ("styles" in $$props2) $$invalidate(2, styles = $$props2.styles);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*$isLocked, inverse*/
        10) {
          {
            if ($isLocked !== inverse) {
              set_store_value(store, $store = false, $store);
            }
          }
        }
      };
      return [
        setting,
        inverse,
        styles,
        $isLocked,
        $store,
        id,
        store,
        isLocked,
        label,
        lock,
        input_change_handler
      ];
    }
    class Checkbox extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$8, create_fragment$9, safe_not_equal, {
          setting: 0,
          label: 8,
          lock: 9,
          inverse: 1,
          styles: 2
        });
      }
    }
    function create_if_block$1(ctx) {
      let label;
      let t_value = localize(
        /*setting*/
        ctx[0].label
      ) + "";
      let t;
      return {
        c() {
          label = element("label");
          t = text$1(t_value);
          attr(
            label,
            "for",
            /*id*/
            ctx[5]
          );
          attr(label, "class", "svelte-seq-ywsxq0");
        },
        m(target, anchor) {
          insert(target, label, anchor);
          append(label, t);
        },
        p(ctx2, dirty) {
          if (dirty & /*setting*/
          1 && t_value !== (t_value = localize(
            /*setting*/
            ctx2[0].label
          ) + "")) set_data(t, t_value);
        },
        d(detaching) {
          if (detaching) {
            detach(label);
          }
        }
      };
    }
    function create_fragment$8(ctx) {
      let div;
      let show_if = localize(
        /*setting*/
        ctx[0].label
      );
      let t;
      let input;
      let input_disabled_value;
      let applyStyles_action;
      let mounted;
      let dispose;
      let if_block = show_if && create_if_block$1(ctx);
      return {
        c() {
          div = element("div");
          if (if_block) if_block.c();
          t = space();
          input = element("input");
          attr(
            input,
            "id",
            /*id*/
            ctx[5]
          );
          attr(input, "type", "number");
          input.disabled = input_disabled_value = /*$isLocked*/
          ctx[3] !== /*inverse*/
          ctx[1];
          attr(input, "class", "svelte-seq-ywsxq0");
          set_style(div, "display", "flex");
          set_style(div, "align-items", "center");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if (if_block) if_block.m(div, null);
          append(div, t);
          append(div, input);
          set_input_value(
            input,
            /*$store*/
            ctx[4]
          );
          if (!mounted) {
            dispose = [
              listen(
                input,
                "input",
                /*input_input_handler*/
                ctx[9]
              ),
              listen(
                input,
                "change",
                /*change_handler*/
                ctx[10]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                div,
                /*styles*/
                ctx[2]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*setting*/
          1) show_if = localize(
            /*setting*/
            ctx2[0].label
          );
          if (show_if) {
            if (if_block) {
              if_block.p(ctx2, dirty);
            } else {
              if_block = create_if_block$1(ctx2);
              if_block.c();
              if_block.m(div, t);
            }
          } else if (if_block) {
            if_block.d(1);
            if_block = null;
          }
          if (dirty & /*$isLocked, inverse*/
          10 && input_disabled_value !== (input_disabled_value = /*$isLocked*/
          ctx2[3] !== /*inverse*/
          ctx2[1])) {
            input.disabled = input_disabled_value;
          }
          if (dirty & /*$store*/
          16 && to_number(input.value) !== /*$store*/
          ctx2[4]) {
            set_input_value(
              input,
              /*$store*/
              ctx2[4]
            );
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*styles*/
          4) applyStyles_action.update.call(
            null,
            /*styles*/
            ctx2[2]
          );
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if (if_block) if_block.d();
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$7($$self, $$props, $$invalidate) {
      let $isLocked;
      let $store;
      let { setting } = $$props;
      let { lock = false } = $$props;
      let { inverse = false } = $$props;
      let { styles = {} } = $$props;
      const id = "sequencer-input-" + foundry.utils.randomID();
      const store = setting.store;
      component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
      const isLocked = lock ? lock.store : writable(inverse);
      component_subscribe($$self, isLocked, (value) => $$invalidate(3, $isLocked = value));
      function input_input_handler() {
        $store = to_number(this.value);
        store.set($store);
      }
      const change_handler = () => {
        if ($store === null) set_store_value(store, $store = 0, $store);
      };
      $$self.$$set = ($$props2) => {
        if ("setting" in $$props2) $$invalidate(0, setting = $$props2.setting);
        if ("lock" in $$props2) $$invalidate(8, lock = $$props2.lock);
        if ("inverse" in $$props2) $$invalidate(1, inverse = $$props2.inverse);
        if ("styles" in $$props2) $$invalidate(2, styles = $$props2.styles);
      };
      return [
        setting,
        inverse,
        styles,
        $isLocked,
        $store,
        id,
        store,
        isLocked,
        lock,
        input_input_handler,
        change_handler
      ];
    }
    class NumberInput extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$7, create_fragment$8, safe_not_equal, {
          setting: 0,
          lock: 8,
          inverse: 1,
          styles: 2
        });
      }
    }
    function create_fragment$7(ctx) {
      let div2;
      let div0;
      let span0;
      let t0_value = localize(
        /*setting*/
        ctx[0].label_off
      ) + "";
      let t0;
      let t1;
      let div1;
      let span1;
      let t2_value = localize(
        /*setting*/
        ctx[0].label_on
      ) + "";
      let t2;
      let applyStyles_action;
      let mounted;
      let dispose;
      return {
        c() {
          div2 = element("div");
          div0 = element("div");
          span0 = element("span");
          t0 = text$1(t0_value);
          t1 = space();
          div1 = element("div");
          span1 = element("span");
          t2 = text$1(t2_value);
          attr(div0, "class", "first svelte-seq-o0yoxs");
          toggle_class(div0, "active", !/*$store*/
          ctx[2]);
          attr(div1, "class", "second svelte-seq-o0yoxs");
          toggle_class(
            div1,
            "active",
            /*$store*/
            ctx[2]
          );
          set_style(div2, "display", "flex");
          set_style(div2, "align-items", "center");
          attr(div2, "class", "svelte-seq-o0yoxs");
        },
        m(target, anchor) {
          insert(target, div2, anchor);
          append(div2, div0);
          append(div0, span0);
          append(span0, t0);
          append(div2, t1);
          append(div2, div1);
          append(div1, span1);
          append(span1, t2);
          if (!mounted) {
            dispose = [
              listen(
                div0,
                "click",
                /*click_handler*/
                ctx[5]
              ),
              listen(
                div1,
                "click",
                /*click_handler_1*/
                ctx[6]
              ),
              action_destroyer(applyStyles_action = applyStyles.call(
                null,
                div2,
                /*finalStyles*/
                ctx[1]
              ))
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*setting*/
          1 && t0_value !== (t0_value = localize(
            /*setting*/
            ctx2[0].label_off
          ) + "")) set_data(t0, t0_value);
          if (dirty & /*$store*/
          4) {
            toggle_class(div0, "active", !/*$store*/
            ctx2[2]);
          }
          if (dirty & /*setting*/
          1 && t2_value !== (t2_value = localize(
            /*setting*/
            ctx2[0].label_on
          ) + "")) set_data(t2, t2_value);
          if (dirty & /*$store*/
          4) {
            toggle_class(
              div1,
              "active",
              /*$store*/
              ctx2[2]
            );
          }
          if (applyStyles_action && is_function(applyStyles_action.update) && dirty & /*finalStyles*/
          2) applyStyles_action.update.call(
            null,
            /*finalStyles*/
            ctx2[1]
          );
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div2);
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    const width = 5.75;
    function instance$6($$self, $$props, $$invalidate) {
      let finalStyles;
      let $store;
      let { setting } = $$props;
      let { styles = {} } = $$props;
      const store = setting.store;
      component_subscribe($$self, store, (value) => $$invalidate(2, $store = value));
      const click_handler = () => {
        set_store_value(store, $store = false, $store);
      };
      const click_handler_1 = () => {
        set_store_value(store, $store = true, $store);
      };
      $$self.$$set = ($$props2) => {
        if ("setting" in $$props2) $$invalidate(0, setting = $$props2.setting);
        if ("styles" in $$props2) $$invalidate(4, styles = $$props2.styles);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*styles*/
        16) {
          $$invalidate(1, finalStyles = {
            ...styles,
            "--switch-width": `${width}em`,
            "--half-switch-width": `${width - 1.5}em`,
            "--half-switch-width-on": `${width - 1.7}em`
          });
        }
      };
      return [setting, finalStyles, $store, store, styles, click_handler, click_handler_1];
    }
    class SwitchToggle extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$6, create_fragment$7, safe_not_equal, { setting: 0, styles: 4 });
      }
    }
    function get_each_context$2(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[21] = list[i];
      return child_ctx;
    }
    function get_each_context_1(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[24] = list[i];
      return child_ctx;
    }
    function get_each_context_2(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[27] = list[i];
      return child_ctx;
    }
    function create_each_block_2(ctx) {
      let option;
      let t_value = (
        /*suggestion*/
        ctx[27] + ""
      );
      let t;
      let option_value_value;
      return {
        c() {
          option = element("option");
          t = text$1(t_value);
          option.__value = option_value_value = /*suggestion*/
          ctx[27];
          set_input_value(option, option.__value);
        },
        m(target, anchor) {
          insert(target, option, anchor);
          append(option, t);
        },
        p(ctx2, dirty) {
          if (dirty & /*suggestions*/
          2 && t_value !== (t_value = /*suggestion*/
          ctx2[27] + "")) set_data(t, t_value);
          if (dirty & /*suggestions*/
          2 && option_value_value !== (option_value_value = /*suggestion*/
          ctx2[27])) {
            option.__value = option_value_value;
            set_input_value(option, option.__value);
          }
        },
        d(detaching) {
          if (detaching) {
            detach(option);
          }
        }
      };
    }
    function create_each_block_1(key_1, ctx) {
      let option;
      let t_value = (
        /*user*/
        ctx[24].name + ""
      );
      let t;
      return {
        key: key_1,
        first: null,
        c() {
          option = element("option");
          t = text$1(t_value);
          option.__value = /*user*/
          ctx[24].id;
          set_input_value(option, option.__value);
          this.first = option;
        },
        m(target, anchor) {
          insert(target, option, anchor);
          append(option, t);
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
        },
        d(detaching) {
          if (detaching) {
            detach(option);
          }
        }
      };
    }
    function create_each_block$2(ctx) {
      let option;
      let t_value = (
        /*preset*/
        ctx[21] + ""
      );
      let t;
      return {
        c() {
          option = element("option");
          t = text$1(t_value);
          option.__value = /*preset*/
          ctx[21];
          set_input_value(option, option.__value);
        },
        m(target, anchor) {
          insert(target, option, anchor);
          append(option, t);
        },
        p: noop,
        d(detaching) {
          if (detaching) {
            detach(option);
          }
        }
      };
    }
    function create_fragment$6(ctx) {
      let div16;
      let fieldset0;
      let legend0;
      let t1;
      let button0;
      let t3;
      let div0;
      let input;
      let t4;
      let button1;
      let t5;
      let datalist;
      let t6;
      let div1;
      let label;
      let t8;
      let select0;
      let option0;
      let each_blocks_1 = [];
      let each1_lookup = /* @__PURE__ */ new Map();
      let t10;
      let div4;
      let div2;
      let t12;
      let div3;
      let select1;
      let option1;
      let t14;
      let button2;
      let t15;
      let button3;
      let i2;
      let button3_disabled_value;
      let t16;
      let button4;
      let i3;
      let button4_disabled_value;
      let t17;
      let fieldset1;
      let legend1;
      let t19;
      let div11;
      let sliderinput0;
      let t20;
      let numberinput0;
      let t21;
      let numberinput1;
      let t22;
      let div5;
      let t23;
      let sliderinput1;
      let t24;
      let div6;
      let t25;
      let checkbox0;
      let t26;
      let div7;
      let t27;
      let div8;
      let t28;
      let checkbox1;
      let t29;
      let checkbox2;
      let t30;
      let checkbox3;
      let t31;
      let checkbox4;
      let t32;
      let div9;
      let t33;
      let numberinput2;
      let t34;
      let numberinput3;
      let t35;
      let checkbox5;
      let t36;
      let numberinput4;
      let t37;
      let checkbox6;
      let t38;
      let div10;
      let t39;
      let fieldset2;
      let legend2;
      let t41;
      let div15;
      let numberinput5;
      let t42;
      let numberinput6;
      let t43;
      let div12;
      let t44;
      let checkbox7;
      let t45;
      let numberinput7;
      let t46;
      let numberinput8;
      let t47;
      let numberinput9;
      let t48;
      let div13;
      let t49;
      let switchtoggle;
      let t50;
      let numberinput10;
      let t51;
      let div14;
      let t52;
      let checkbox8;
      let t53;
      let checkbox9;
      let t54;
      let checkbox10;
      let t55;
      let checkbox11;
      let t56;
      let checkbox12;
      let current;
      let mounted;
      let dispose;
      let each_value_2 = ensure_array_like(
        /*suggestions*/
        ctx[1]
      );
      let each_blocks_2 = [];
      for (let i = 0; i < each_value_2.length; i += 1) {
        each_blocks_2[i] = create_each_block_2(get_each_context_2(ctx, each_value_2, i));
      }
      let each_value_1 = ensure_array_like(
        /*users*/
        ctx[5]
      );
      const get_key = (ctx2) => (
        /*user*/
        ctx2[24].id
      );
      for (let i = 0; i < each_value_1.length; i += 1) {
        let child_ctx = get_each_context_1(ctx, each_value_1, i);
        let key = get_key(child_ctx);
        each1_lookup.set(key, each_blocks_1[i] = create_each_block_1(key, child_ctx));
      }
      let each_value = ensure_array_like(
        /*presets*/
        ctx[9]
      );
      let each_blocks = [];
      for (let i = 0; i < each_value.length; i += 1) {
        each_blocks[i] = create_each_block$2(get_each_context$2(ctx, each_value, i));
      }
      sliderinput0 = new SliderInput({
        props: {
          setting: PlayerSettings.scale,
          styles: { "grid-column": `1 / 5` }
        }
      });
      numberinput0 = new NumberInput({
        props: {
          setting: PlayerSettings.scaleIn,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput1 = new NumberInput({
        props: {
          setting: PlayerSettings.scaleOut,
          styles: { "grid-column": `3 / 5` }
        }
      });
      sliderinput1 = new SliderInput({
        props: {
          setting: PlayerSettings.rotation,
          lock: PlayerSettings.randomRotation,
          min: "-180",
          max: "180",
          styles: { "grid-column": `1 / 5` }
        }
      });
      checkbox0 = new Checkbox({
        props: {
          setting: PlayerSettings.randomRotation,
          styles: { "grid-column": `2 / 4` }
        }
      });
      checkbox1 = new Checkbox({
        props: {
          setting: PlayerSettings.mirrorX,
          styles: { "grid-column": `1 / 3` }
        }
      });
      checkbox2 = new Checkbox({
        props: {
          setting: PlayerSettings.mirrorY,
          styles: { "grid-column": `3 / 5` }
        }
      });
      checkbox3 = new Checkbox({
        props: {
          setting: PlayerSettings.randomMirrorX,
          styles: { "grid-column": `1 / 3` },
          lock: PlayerSettings.mirrorX,
          inverse: true
        }
      });
      checkbox4 = new Checkbox({
        props: {
          setting: PlayerSettings.randomMirrorY,
          styles: { "grid-column": `3 / 5` },
          lock: PlayerSettings.mirrorY,
          inverse: true
        }
      });
      numberinput2 = new NumberInput({
        props: {
          setting: PlayerSettings.offsetX,
          lock: PlayerSettings.randomOffset,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput3 = new NumberInput({
        props: {
          setting: PlayerSettings.offsetY,
          lock: PlayerSettings.randomOffset,
          styles: { "grid-column": `3 / 5` }
        }
      });
      checkbox5 = new Checkbox({
        props: {
          setting: PlayerSettings.randomOffset,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput4 = new NumberInput({
        props: {
          setting: PlayerSettings.randomOffsetAmount,
          lock: PlayerSettings.randomOffset,
          inverse: true,
          styles: { "grid-column": `3 / 5` }
        }
      });
      checkbox6 = new Checkbox({
        props: {
          setting: PlayerSettings.offsetGridUnits,
          styles: { "grid-column": `2 / 5` }
        }
      });
      numberinput5 = new NumberInput({
        props: {
          setting: PlayerSettings.fadeIn,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput6 = new NumberInput({
        props: {
          setting: PlayerSettings.fadeOut,
          styles: { "grid-column": `3 / 5` }
        }
      });
      checkbox7 = new Checkbox({
        props: {
          setting: PlayerSettings.repeat,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput7 = new NumberInput({
        props: {
          setting: PlayerSettings.repetitions,
          lock: PlayerSettings.repeat,
          inverse: true,
          styles: { "grid-column": `3 / 5` }
        }
      });
      numberinput8 = new NumberInput({
        props: {
          setting: PlayerSettings.repeatDelayMin,
          lock: PlayerSettings.repeat,
          inverse: true,
          styles: { "grid-column": `3 / 4` }
        }
      });
      numberinput9 = new NumberInput({
        props: {
          setting: PlayerSettings.repeatDelayMax,
          lock: PlayerSettings.repeat,
          inverse: true,
          styles: { "grid-column": `4 / 5` }
        }
      });
      switchtoggle = new SwitchToggle({
        props: {
          setting: PlayerSettings.moveTowards,
          styles: { "grid-column": `1 / 3` }
        }
      });
      numberinput10 = new NumberInput({
        props: {
          setting: PlayerSettings.moveSpeed,
          lock: PlayerSettings.moveTowards,
          inverse: true,
          styles: { "grid-column": `3 / 5` }
        }
      });
      checkbox8 = new Checkbox({
        props: {
          setting: PlayerSettings.attachTo,
          styles: { "grid-column": `1 / 5` }
        }
      });
      checkbox9 = new Checkbox({
        props: {
          setting: PlayerSettings.stretchToAttach,
          styles: { "grid-column": `1 / 5` }
        }
      });
      checkbox10 = new Checkbox({
        props: {
          setting: PlayerSettings.snapToGrid,
          styles: { "grid-column": `1 / 5` }
        }
      });
      checkbox11 = new Checkbox({
        props: {
          setting: PlayerSettings.persist,
          styles: { "grid-column": `1 / 5` }
        }
      });
      checkbox12 = new Checkbox({
        props: {
          setting: PlayerSettings.belowTokens,
          styles: { "grid-column": `1 / 5` }
        }
      });
      return {
        c() {
          div16 = element("div");
          fieldset0 = element("fieldset");
          legend0 = element("legend");
          legend0.textContent = "Effect";
          t1 = space();
          button0 = element("button");
          button0.textContent = `${localize("SEQUENCER.Player.SwitchToLayer")}`;
          t3 = space();
          div0 = element("div");
          input = element("input");
          t4 = space();
          button1 = element("button");
          button1.innerHTML = `<i class="fas fa-file-import svelte-seq-1ipnpu1"></i>`;
          t5 = space();
          datalist = element("datalist");
          for (let i = 0; i < each_blocks_2.length; i += 1) {
            each_blocks_2[i].c();
          }
          t6 = space();
          div1 = element("div");
          label = element("label");
          label.textContent = "Play for users:";
          t8 = space();
          select0 = element("select");
          option0 = element("option");
          option0.textContent = `${localize("SEQUENCER.Player.AllUsers")}`;
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            each_blocks_1[i].c();
          }
          t10 = space();
          div4 = element("div");
          div2 = element("div");
          div2.textContent = `${localize("SEQUENCER.Player.Presets")}`;
          t12 = space();
          div3 = element("div");
          select1 = element("select");
          option1 = element("option");
          option1.textContent = `${localize("SEQUENCER.Player.PresetsDefault")}`;
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          t14 = space();
          button2 = element("button");
          button2.innerHTML = `<i class="fas fa-download svelte-seq-1ipnpu1"></i>`;
          t15 = space();
          button3 = element("button");
          i2 = element("i");
          t16 = space();
          button4 = element("button");
          i3 = element("i");
          t17 = space();
          fieldset1 = element("fieldset");
          legend1 = element("legend");
          legend1.textContent = "Transform";
          t19 = space();
          div11 = element("div");
          create_component(sliderinput0.$$.fragment);
          t20 = space();
          create_component(numberinput0.$$.fragment);
          t21 = space();
          create_component(numberinput1.$$.fragment);
          t22 = space();
          div5 = element("div");
          t23 = space();
          create_component(sliderinput1.$$.fragment);
          t24 = space();
          div6 = element("div");
          t25 = space();
          create_component(checkbox0.$$.fragment);
          t26 = space();
          div7 = element("div");
          t27 = space();
          div8 = element("div");
          t28 = space();
          create_component(checkbox1.$$.fragment);
          t29 = space();
          create_component(checkbox2.$$.fragment);
          t30 = space();
          create_component(checkbox3.$$.fragment);
          t31 = space();
          create_component(checkbox4.$$.fragment);
          t32 = space();
          div9 = element("div");
          t33 = space();
          create_component(numberinput2.$$.fragment);
          t34 = space();
          create_component(numberinput3.$$.fragment);
          t35 = space();
          create_component(checkbox5.$$.fragment);
          t36 = space();
          create_component(numberinput4.$$.fragment);
          t37 = space();
          create_component(checkbox6.$$.fragment);
          t38 = space();
          div10 = element("div");
          t39 = space();
          fieldset2 = element("fieldset");
          legend2 = element("legend");
          legend2.textContent = "Behavior";
          t41 = space();
          div15 = element("div");
          create_component(numberinput5.$$.fragment);
          t42 = space();
          create_component(numberinput6.$$.fragment);
          t43 = space();
          div12 = element("div");
          t44 = space();
          create_component(checkbox7.$$.fragment);
          t45 = space();
          create_component(numberinput7.$$.fragment);
          t46 = space();
          create_component(numberinput8.$$.fragment);
          t47 = space();
          create_component(numberinput9.$$.fragment);
          t48 = space();
          div13 = element("div");
          t49 = space();
          create_component(switchtoggle.$$.fragment);
          t50 = space();
          create_component(numberinput10.$$.fragment);
          t51 = space();
          div14 = element("div");
          t52 = space();
          create_component(checkbox8.$$.fragment);
          t53 = space();
          create_component(checkbox9.$$.fragment);
          t54 = space();
          create_component(checkbox10.$$.fragment);
          t55 = space();
          create_component(checkbox11.$$.fragment);
          t56 = space();
          create_component(checkbox12.$$.fragment);
          attr(button0, "class", "activate-layer svelte-seq-1ipnpu1");
          attr(button0, "type", "button");
          attr(input, "class", "file-input flex3");
          attr(input, "list", "dblist");
          attr(input, "placeholder", localize("SEQUENCER.Player.PathInput"));
          attr(input, "type", "text");
          attr(button1, "class", "custom-file-picker small-button svelte-seq-1ipnpu1");
          attr(button1, "type", "button");
          attr(datalist, "id", "dblist");
          attr(div0, "class", "file-settings svelte-seq-1ipnpu1");
          attr(label, "for", "user-select");
          option0.selected = true;
          option0.__value = "all";
          set_input_value(option0, option0.__value);
          attr(select0, "class", "user-select");
          attr(select0, "id", "user-select");
          select0.multiple = true;
          if (
            /*$userStore*/
            ctx[3] === void 0
          ) add_render_callback(() => (
            /*select0_change_handler*/
            ctx[12].call(select0)
          ));
          attr(div1, "class", "user-settings flexcol svelte-seq-1ipnpu1");
          attr(div2, "class", "row w-100");
          option1.__value = "default";
          set_input_value(option1, option1.__value);
          attr(select1, "class", "preset-select svelte-seq-1ipnpu1");
          if (
            /*selectedPreset*/
            ctx[2] === void 0
          ) add_render_callback(() => (
            /*select1_change_handler*/
            ctx[13].call(select1)
          ));
          attr(button2, "class", "save-preset small-button svelte-seq-1ipnpu1");
          attr(button2, "data-tooltip", "Save Preset");
          attr(button2, "type", "button");
          attr(i2, "class", "fas fa-copy svelte-seq-1ipnpu1");
          attr(button3, "class", "copy-preset small-button svelte-seq-1ipnpu1");
          attr(button3, "data-tooltip", "Copy Preset");
          button3.disabled = button3_disabled_value = /*selectedPreset*/
          ctx[2] === "default";
          attr(button3, "type", "button");
          attr(i3, "class", "fas fa-times svelte-seq-1ipnpu1");
          attr(button4, "class", "delete-preset small-button svelte-seq-1ipnpu1");
          attr(button4, "data-tooltip", "Delete Preset");
          button4.disabled = button4_disabled_value = /*selectedPreset*/
          ctx[2] === "default";
          attr(button4, "type", "button");
          attr(div3, "class", "preset-container svelte-seq-1ipnpu1");
          attr(div4, "class", "flexcol");
          attr(div5, "class", "divider");
          attr(div8, "class", "divider");
          attr(div9, "class", "divider");
          attr(div11, "class", "effect-transform-container");
          attr(div12, "class", "divider");
          attr(div13, "class", "divider");
          attr(div14, "class", "divider");
          attr(div15, "class", "effect-transform-container");
          attr(div16, "class", "effect-player-container");
        },
        m(target, anchor) {
          insert(target, div16, anchor);
          append(div16, fieldset0);
          append(fieldset0, legend0);
          append(fieldset0, t1);
          append(fieldset0, button0);
          append(fieldset0, t3);
          append(fieldset0, div0);
          append(div0, input);
          set_input_value(
            input,
            /*$fileStore*/
            ctx[0]
          );
          append(div0, t4);
          append(div0, button1);
          append(div0, t5);
          append(div0, datalist);
          for (let i = 0; i < each_blocks_2.length; i += 1) {
            if (each_blocks_2[i]) {
              each_blocks_2[i].m(datalist, null);
            }
          }
          append(fieldset0, t6);
          append(fieldset0, div1);
          append(div1, label);
          append(div1, t8);
          append(div1, select0);
          append(select0, option0);
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            if (each_blocks_1[i]) {
              each_blocks_1[i].m(select0, null);
            }
          }
          select_options(
            select0,
            /*$userStore*/
            ctx[3]
          );
          append(fieldset0, t10);
          append(fieldset0, div4);
          append(div4, div2);
          append(div4, t12);
          append(div4, div3);
          append(div3, select1);
          append(select1, option1);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(select1, null);
            }
          }
          select_option(
            select1,
            /*selectedPreset*/
            ctx[2],
            true
          );
          append(div3, t14);
          append(div3, button2);
          append(div3, t15);
          append(div3, button3);
          append(button3, i2);
          append(div3, t16);
          append(div3, button4);
          append(button4, i3);
          append(div16, t17);
          append(div16, fieldset1);
          append(fieldset1, legend1);
          append(fieldset1, t19);
          append(fieldset1, div11);
          mount_component(sliderinput0, div11, null);
          append(div11, t20);
          mount_component(numberinput0, div11, null);
          append(div11, t21);
          mount_component(numberinput1, div11, null);
          append(div11, t22);
          append(div11, div5);
          append(div11, t23);
          mount_component(sliderinput1, div11, null);
          append(div11, t24);
          append(div11, div6);
          append(div11, t25);
          mount_component(checkbox0, div11, null);
          append(div11, t26);
          append(div11, div7);
          append(div11, t27);
          append(div11, div8);
          append(div11, t28);
          mount_component(checkbox1, div11, null);
          append(div11, t29);
          mount_component(checkbox2, div11, null);
          append(div11, t30);
          mount_component(checkbox3, div11, null);
          append(div11, t31);
          mount_component(checkbox4, div11, null);
          append(div11, t32);
          append(div11, div9);
          append(div11, t33);
          mount_component(numberinput2, div11, null);
          append(div11, t34);
          mount_component(numberinput3, div11, null);
          append(div11, t35);
          mount_component(checkbox5, div11, null);
          append(div11, t36);
          mount_component(numberinput4, div11, null);
          append(div11, t37);
          mount_component(checkbox6, div11, null);
          append(div11, t38);
          append(div11, div10);
          append(div16, t39);
          append(div16, fieldset2);
          append(fieldset2, legend2);
          append(fieldset2, t41);
          append(fieldset2, div15);
          mount_component(numberinput5, div15, null);
          append(div15, t42);
          mount_component(numberinput6, div15, null);
          append(div15, t43);
          append(div15, div12);
          append(div15, t44);
          mount_component(checkbox7, div15, null);
          append(div15, t45);
          mount_component(numberinput7, div15, null);
          append(div15, t46);
          mount_component(numberinput8, div15, null);
          append(div15, t47);
          mount_component(numberinput9, div15, null);
          append(div15, t48);
          append(div15, div13);
          append(div15, t49);
          mount_component(switchtoggle, div15, null);
          append(div15, t50);
          mount_component(numberinput10, div15, null);
          append(div15, t51);
          append(div15, div14);
          append(div15, t52);
          mount_component(checkbox8, div15, null);
          append(div15, t53);
          mount_component(checkbox9, div15, null);
          append(div15, t54);
          mount_component(checkbox10, div15, null);
          append(div15, t55);
          mount_component(checkbox11, div15, null);
          append(div15, t56);
          mount_component(checkbox12, div15, null);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                button0,
                "click",
                /*click_handler*/
                ctx[10]
              ),
              listen(
                input,
                "input",
                /*input_input_handler*/
                ctx[11]
              ),
              listen(
                button1,
                "click",
                /*handleClick*/
                ctx[8]
              ),
              listen(
                select0,
                "change",
                /*select0_change_handler*/
                ctx[12]
              ),
              listen(
                select1,
                "change",
                /*select1_change_handler*/
                ctx[13]
              ),
              listen(
                select1,
                "change",
                /*change_handler*/
                ctx[14]
              ),
              listen(
                button2,
                "click",
                /*click_handler_1*/
                ctx[15]
              ),
              listen(
                button3,
                "click",
                /*click_handler_2*/
                ctx[16]
              ),
              listen(
                button4,
                "click",
                /*click_handler_3*/
                ctx[17]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (dirty & /*$fileStore*/
          1 && input.value !== /*$fileStore*/
          ctx2[0]) {
            set_input_value(
              input,
              /*$fileStore*/
              ctx2[0]
            );
          }
          if (dirty & /*suggestions*/
          2) {
            each_value_2 = ensure_array_like(
              /*suggestions*/
              ctx2[1]
            );
            let i;
            for (i = 0; i < each_value_2.length; i += 1) {
              const child_ctx = get_each_context_2(ctx2, each_value_2, i);
              if (each_blocks_2[i]) {
                each_blocks_2[i].p(child_ctx, dirty);
              } else {
                each_blocks_2[i] = create_each_block_2(child_ctx);
                each_blocks_2[i].c();
                each_blocks_2[i].m(datalist, null);
              }
            }
            for (; i < each_blocks_2.length; i += 1) {
              each_blocks_2[i].d(1);
            }
            each_blocks_2.length = each_value_2.length;
          }
          if (dirty & /*users*/
          32) {
            each_value_1 = ensure_array_like(
              /*users*/
              ctx2[5]
            );
            each_blocks_1 = update_keyed_each(each_blocks_1, dirty, get_key, 1, ctx2, each_value_1, each1_lookup, select0, destroy_block, create_each_block_1, null, get_each_context_1);
          }
          if (dirty & /*$userStore, users*/
          40) {
            select_options(
              select0,
              /*$userStore*/
              ctx2[3]
            );
          }
          if (dirty & /*presets*/
          512) {
            each_value = ensure_array_like(
              /*presets*/
              ctx2[9]
            );
            let i;
            for (i = 0; i < each_value.length; i += 1) {
              const child_ctx = get_each_context$2(ctx2, each_value, i);
              if (each_blocks[i]) {
                each_blocks[i].p(child_ctx, dirty);
              } else {
                each_blocks[i] = create_each_block$2(child_ctx);
                each_blocks[i].c();
                each_blocks[i].m(select1, null);
              }
            }
            for (; i < each_blocks.length; i += 1) {
              each_blocks[i].d(1);
            }
            each_blocks.length = each_value.length;
          }
          if (dirty & /*selectedPreset, presets*/
          516) {
            select_option(
              select1,
              /*selectedPreset*/
              ctx2[2]
            );
          }
          if (!current || dirty & /*selectedPreset, presets*/
          516 && button3_disabled_value !== (button3_disabled_value = /*selectedPreset*/
          ctx2[2] === "default")) {
            button3.disabled = button3_disabled_value;
          }
          if (!current || dirty & /*selectedPreset, presets*/
          516 && button4_disabled_value !== (button4_disabled_value = /*selectedPreset*/
          ctx2[2] === "default")) {
            button4.disabled = button4_disabled_value;
          }
        },
        i(local) {
          if (current) return;
          transition_in(sliderinput0.$$.fragment, local);
          transition_in(numberinput0.$$.fragment, local);
          transition_in(numberinput1.$$.fragment, local);
          transition_in(sliderinput1.$$.fragment, local);
          transition_in(checkbox0.$$.fragment, local);
          transition_in(checkbox1.$$.fragment, local);
          transition_in(checkbox2.$$.fragment, local);
          transition_in(checkbox3.$$.fragment, local);
          transition_in(checkbox4.$$.fragment, local);
          transition_in(numberinput2.$$.fragment, local);
          transition_in(numberinput3.$$.fragment, local);
          transition_in(checkbox5.$$.fragment, local);
          transition_in(numberinput4.$$.fragment, local);
          transition_in(checkbox6.$$.fragment, local);
          transition_in(numberinput5.$$.fragment, local);
          transition_in(numberinput6.$$.fragment, local);
          transition_in(checkbox7.$$.fragment, local);
          transition_in(numberinput7.$$.fragment, local);
          transition_in(numberinput8.$$.fragment, local);
          transition_in(numberinput9.$$.fragment, local);
          transition_in(switchtoggle.$$.fragment, local);
          transition_in(numberinput10.$$.fragment, local);
          transition_in(checkbox8.$$.fragment, local);
          transition_in(checkbox9.$$.fragment, local);
          transition_in(checkbox10.$$.fragment, local);
          transition_in(checkbox11.$$.fragment, local);
          transition_in(checkbox12.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(sliderinput0.$$.fragment, local);
          transition_out(numberinput0.$$.fragment, local);
          transition_out(numberinput1.$$.fragment, local);
          transition_out(sliderinput1.$$.fragment, local);
          transition_out(checkbox0.$$.fragment, local);
          transition_out(checkbox1.$$.fragment, local);
          transition_out(checkbox2.$$.fragment, local);
          transition_out(checkbox3.$$.fragment, local);
          transition_out(checkbox4.$$.fragment, local);
          transition_out(numberinput2.$$.fragment, local);
          transition_out(numberinput3.$$.fragment, local);
          transition_out(checkbox5.$$.fragment, local);
          transition_out(numberinput4.$$.fragment, local);
          transition_out(checkbox6.$$.fragment, local);
          transition_out(numberinput5.$$.fragment, local);
          transition_out(numberinput6.$$.fragment, local);
          transition_out(checkbox7.$$.fragment, local);
          transition_out(numberinput7.$$.fragment, local);
          transition_out(numberinput8.$$.fragment, local);
          transition_out(numberinput9.$$.fragment, local);
          transition_out(switchtoggle.$$.fragment, local);
          transition_out(numberinput10.$$.fragment, local);
          transition_out(checkbox8.$$.fragment, local);
          transition_out(checkbox9.$$.fragment, local);
          transition_out(checkbox10.$$.fragment, local);
          transition_out(checkbox11.$$.fragment, local);
          transition_out(checkbox12.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div16);
          }
          destroy_each(each_blocks_2, detaching);
          for (let i = 0; i < each_blocks_1.length; i += 1) {
            each_blocks_1[i].d();
          }
          destroy_each(each_blocks, detaching);
          destroy_component(sliderinput0);
          destroy_component(numberinput0);
          destroy_component(numberinput1);
          destroy_component(sliderinput1);
          destroy_component(checkbox0);
          destroy_component(checkbox1);
          destroy_component(checkbox2);
          destroy_component(checkbox3);
          destroy_component(checkbox4);
          destroy_component(numberinput2);
          destroy_component(numberinput3);
          destroy_component(checkbox5);
          destroy_component(numberinput4);
          destroy_component(checkbox6);
          destroy_component(numberinput5);
          destroy_component(numberinput6);
          destroy_component(checkbox7);
          destroy_component(numberinput7);
          destroy_component(numberinput8);
          destroy_component(numberinput9);
          destroy_component(switchtoggle);
          destroy_component(numberinput10);
          destroy_component(checkbox8);
          destroy_component(checkbox9);
          destroy_component(checkbox10);
          destroy_component(checkbox11);
          destroy_component(checkbox12);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    let lastInput = "";
    function instance$5($$self, $$props, $$invalidate) {
      let $fileStore;
      let $userStore;
      const fileStore = PlayerSettings.file.store;
      component_subscribe($$self, fileStore, (value) => $$invalidate(0, $fileStore = value));
      const users2 = game.users.filter((user) => user.active);
      const userStore = PlayerSettings.users.store;
      component_subscribe($$self, userStore, (value) => $$invalidate(3, $userStore = value));
      let lastResults = [];
      let suggestions = [];
      const searchDebounce = foundry.utils.debounce(
        () => {
          const fileInput = get_store_value(fileStore).toLowerCase();
          if (!fileInput) {
            $$invalidate(1, suggestions = SequencerDatabase.publicModules);
            return;
          }
          if (lastInput === fileInput) return;
          let results = SequencerDatabase.searchFor(fileInput);
          if (lastResults.equals(results)) return;
          lastResults = foundry.utils.duplicate(results);
          if (results.length === 1 && results[0].startsWith(fileInput)) return;
          if (results.length > 100) {
            results = results.slice(0, 100);
          }
          $$invalidate(1, suggestions = foundry.utils.duplicate(results));
        },
        200
      );
      async function activateLayer() {
        if (CONSTANTS.IS_V13) {
          ui.controls.activate({
            control: "sequencer",
            tool: CONSTANTS.TOOLS.PLAY
          });
        } else {
          ui.controls.initialize({
            layer: "sequencer",
            tool: CONSTANTS.TOOLS.PLAY
          });
        }
        canvas.sequencerInterfaceLayer.activate({ tool: CONSTANTS.TOOLS.PLAY });
      }
      let filePicker = false;
      function handleClick() {
        if (!filePicker) {
          const file = get_store_value(fileStore);
          const current = SequencerDatabase.getEntry(file, { softFail: true }) ? file : "";
          filePicker = new FilePicker({
            type: "imageVideo",
            current,
            callback: (path) => {
              fileStore.set(path);
              filePicker = false;
            }
          });
        }
        filePicker.render(true, { focus: true });
      }
      const presets = PlayerSettings.getPresets();
      let selectedPreset = "default";
      const click_handler = () => activateLayer();
      function input_input_handler() {
        $fileStore = this.value;
        fileStore.set($fileStore);
      }
      function select0_change_handler() {
        $userStore = select_multiple_value(this);
        userStore.set($userStore);
        $$invalidate(5, users2);
      }
      function select1_change_handler() {
        selectedPreset = select_value(this);
        $$invalidate(2, selectedPreset);
        $$invalidate(9, presets);
      }
      const change_handler = () => PlayerSettings.loadPreset(selectedPreset);
      const click_handler_1 = () => PlayerSettings.savePreset(selectedPreset);
      const click_handler_2 = () => PlayerSettings.copyPreset(selectedPreset);
      const click_handler_3 = () => PlayerSettings.deletePreset(selectedPreset);
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*$fileStore*/
        1) {
          searchDebounce($fileStore);
        }
      };
      return [
        $fileStore,
        suggestions,
        selectedPreset,
        $userStore,
        fileStore,
        users2,
        userStore,
        activateLayer,
        handleClick,
        presets,
        click_handler,
        input_input_handler,
        select0_change_handler,
        select1_change_handler,
        change_handler,
        click_handler_1,
        click_handler_2,
        click_handler_3
      ];
    }
    class Player extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$5, create_fragment$6, safe_not_equal, {});
      }
    }
    function create_fragment$5(ctx) {
      let i0;
      let t;
      let i1;
      return {
        c() {
          i0 = element("i");
          i0.innerHTML = ``;
          t = space();
          i1 = element("i");
          attr(i0, "class", "fa-solid background-circle svelte-seq-1wkm0y3");
          toggle_class(
            i0,
            "invisible",
            /*$status*/
            ctx[1] === CONSTANTS.STATUS.READY
          );
          toggle_class(
            i0,
            "fa-arrow-right",
            /*$status*/
            ctx[1] === CONSTANTS.STATUS.RUNNING || /*$status*/
            ctx[1] === CONSTANTS.STATUS.READY
          );
          toggle_class(
            i0,
            "fa-check",
            /*$status*/
            ctx[1] === CONSTANTS.STATUS.COMPLETE
          );
          toggle_class(
            i0,
            "fa-arrow-down",
            /*$status*/
            ctx[1] === CONSTANTS.STATUS.SKIPPED
          );
          toggle_class(
            i0,
            "fa-times",
            /*$status*/
            ctx[1] === CONSTANTS.STATUS.ABORTED
          );
          attr(i1, "class", "fa-solid ");
        },
        m(target, anchor) {
          insert(target, i0, anchor);
          insert(target, t, anchor);
          insert(target, i1, anchor);
        },
        p(ctx2, [dirty]) {
          if (dirty & /*$status*/
          2) {
            toggle_class(
              i0,
              "invisible",
              /*$status*/
              ctx2[1] === CONSTANTS.STATUS.READY
            );
          }
          if (dirty & /*$status*/
          2) {
            toggle_class(
              i0,
              "fa-arrow-right",
              /*$status*/
              ctx2[1] === CONSTANTS.STATUS.RUNNING || /*$status*/
              ctx2[1] === CONSTANTS.STATUS.READY
            );
          }
          if (dirty & /*$status*/
          2) {
            toggle_class(
              i0,
              "fa-check",
              /*$status*/
              ctx2[1] === CONSTANTS.STATUS.COMPLETE
            );
          }
          if (dirty & /*$status*/
          2) {
            toggle_class(
              i0,
              "fa-arrow-down",
              /*$status*/
              ctx2[1] === CONSTANTS.STATUS.SKIPPED
            );
          }
          if (dirty & /*$status*/
          2) {
            toggle_class(
              i0,
              "fa-times",
              /*$status*/
              ctx2[1] === CONSTANTS.STATUS.ABORTED
            );
          }
        },
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(i0);
            detach(t);
            detach(i1);
          }
        }
      };
    }
    function instance$4($$self, $$props, $$invalidate) {
      let $status, $$unsubscribe_status = noop, $$subscribe_status = () => ($$unsubscribe_status(), $$unsubscribe_status = subscribe(status, ($$value) => $$invalidate(1, $status = $$value)), status);
      $$self.$$.on_destroy.push(() => $$unsubscribe_status());
      let { status } = $$props;
      $$subscribe_status();
      $$self.$$set = ($$props2) => {
        if ("status" in $$props2) $$subscribe_status($$invalidate(0, status = $$props2.status));
      };
      return [status, $status];
    }
    class SequenceStatus extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$4, create_fragment$5, safe_not_equal, { status: 0 });
      }
    }
    function create_fragment$4(ctx) {
      let div;
      let span0;
      let sequencestatus;
      let t0;
      let span1;
      let t2;
      let span2;
      let a;
      let current;
      let mounted;
      let dispose;
      sequencestatus = new SequenceStatus({ props: { status: (
        /*status*/
        ctx[2]
      ) } });
      return {
        c() {
          div = element("div");
          span0 = element("span");
          create_component(sequencestatus.$$.fragment);
          t0 = space();
          span1 = element("span");
          span1.textContent = `${/*sectionName*/
          ctx[3]}`;
          t2 = space();
          span2 = element("span");
          a = element("a");
          a.innerHTML = `<i class="fas fa-stop"></i>`;
          attr(span1, "class", "section-name svelte-seq-1ee9h3");
          attr(a, "class", "svelte-seq-1ee9h3");
          toggle_class(
            a,
            "section-done",
            /*$status*/
            ctx[1] > CONSTANTS.STATUS.READY
          );
          attr(span2, "class", "sequence-actions svelte-seq-1ee9h3");
          attr(span2, "data-tooltip", localize("SEQUENCER.Sequences.AbortSection"));
          attr(div, "class", "svelte-seq-1ee9h3");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, span0);
          mount_component(sequencestatus, span0, null);
          append(div, t0);
          append(div, span1);
          append(div, t2);
          append(div, span2);
          append(span2, a);
          current = true;
          if (!mounted) {
            dispose = listen(
              a,
              "click",
              /*click_handler*/
              ctx[4]
            );
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (!current || dirty & /*$status*/
          2) {
            toggle_class(
              a,
              "section-done",
              /*$status*/
              ctx2[1] > CONSTANTS.STATUS.READY
            );
          }
        },
        i(local) {
          if (current) return;
          transition_in(sequencestatus.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(sequencestatus.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          destroy_component(sequencestatus);
          mounted = false;
          dispose();
        }
      };
    }
    function instance$3($$self, $$props, $$invalidate) {
      let $status;
      let { section } = $$props;
      const status = section.sectionStatus;
      component_subscribe($$self, status, (value) => $$invalidate(1, $status = value));
      const sectionName = (section?.constructor?.niceName ? section?.constructor?.niceName : section.constructor.name) + (section?._name ? " - " + section._name : "");
      const click_handler = () => {
        section._abortSection();
      };
      $$self.$$set = ($$props2) => {
        if ("section" in $$props2) $$invalidate(0, section = $$props2.section);
      };
      return [section, $status, status, sectionName, click_handler];
    }
    class SequenceSection extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$3, create_fragment$4, safe_not_equal, { section: 0 });
      }
    }
    function get_each_context$1(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[6] = list[i];
      return child_ctx;
    }
    function create_each_block$1(ctx) {
      let sequencesection;
      let current;
      sequencesection = new SequenceSection({ props: { section: (
        /*section*/
        ctx[6]
      ) } });
      return {
        c() {
          create_component(sequencesection.$$.fragment);
        },
        m(target, anchor) {
          mount_component(sequencesection, target, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const sequencesection_changes = {};
          if (dirty & /*sequence*/
          1) sequencesection_changes.section = /*section*/
          ctx2[6];
          sequencesection.$set(sequencesection_changes);
        },
        i(local) {
          if (current) return;
          transition_in(sequencesection.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(sequencesection.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(sequencesection, detaching);
        }
      };
    }
    function create_fragment$3(ctx) {
      let div;
      let span0;
      let sequencestatus;
      let t0;
      let span1;
      let t1;
      let t2;
      let t3_value = (
        /*sequence*/
        ctx[0].moduleName ? ` (${/*sequence*/
        ctx[0].moduleName})` : ""
      );
      let t3;
      let t4;
      let span2;
      let a0;
      let t5;
      let a1;
      let t6;
      let each_1_anchor;
      let current;
      let mounted;
      let dispose;
      sequencestatus = new SequenceStatus({ props: { status: (
        /*status*/
        ctx[3]
      ) } });
      let each_value = ensure_array_like(
        /*sequence*/
        ctx[0].sections
      );
      let each_blocks = [];
      for (let i = 0; i < each_value.length; i += 1) {
        each_blocks[i] = create_each_block$1(get_each_context$1(ctx, each_value, i));
      }
      const out = (i) => transition_out(each_blocks[i], 1, 1, () => {
        each_blocks[i] = null;
      });
      return {
        c() {
          div = element("div");
          span0 = element("span");
          create_component(sequencestatus.$$.fragment);
          t0 = space();
          span1 = element("span");
          t1 = text$1("Sequence ");
          t2 = text$1(
            /*index*/
            ctx[1]
          );
          t3 = text$1(t3_value);
          t4 = space();
          span2 = element("span");
          a0 = element("a");
          a0.innerHTML = `<i class="fas fa-trash-can"></i>`;
          t5 = space();
          a1 = element("a");
          a1.innerHTML = `<i class="fas fa-stop"></i>`;
          t6 = space();
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          each_1_anchor = empty();
          attr(span1, "class", "sequence-name svelte-seq-1dcwqos");
          attr(a0, "class", "clear-sequence svelte-seq-1dcwqos");
          attr(a0, "data-tooltip", localize("SEQUENCER.Sequences.Clear"));
          toggle_class(
            a0,
            "sequence-done-show",
            /*$status*/
            ctx[2] > CONSTANTS.STATUS.RUNNING
          );
          attr(a1, "data-tooltip", localize("SEQUENCER.Sequences.AbortSequence"));
          attr(a1, "class", "svelte-seq-1dcwqos");
          toggle_class(
            a1,
            "sequence-done-hide",
            /*$status*/
            ctx[2] > CONSTANTS.STATUS.RUNNING
          );
          attr(span2, "class", "sequence-actions svelte-seq-1dcwqos");
          attr(div, "class", "sequence-name-container svelte-seq-1dcwqos");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, span0);
          mount_component(sequencestatus, span0, null);
          append(div, t0);
          append(div, span1);
          append(span1, t1);
          append(span1, t2);
          append(span1, t3);
          append(div, t4);
          append(div, span2);
          append(span2, a0);
          append(span2, t5);
          append(span2, a1);
          insert(target, t6, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(target, anchor);
            }
          }
          insert(target, each_1_anchor, anchor);
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                a0,
                "click",
                /*click_handler*/
                ctx[4]
              ),
              listen(
                a1,
                "click",
                /*click_handler_1*/
                ctx[5]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, [dirty]) {
          if (!current || dirty & /*index*/
          2) set_data(
            t2,
            /*index*/
            ctx2[1]
          );
          if ((!current || dirty & /*sequence*/
          1) && t3_value !== (t3_value = /*sequence*/
          ctx2[0].moduleName ? ` (${/*sequence*/
          ctx2[0].moduleName})` : "")) set_data(t3, t3_value);
          if (!current || dirty & /*$status*/
          4) {
            toggle_class(
              a0,
              "sequence-done-show",
              /*$status*/
              ctx2[2] > CONSTANTS.STATUS.RUNNING
            );
          }
          if (!current || dirty & /*$status*/
          4) {
            toggle_class(
              a1,
              "sequence-done-hide",
              /*$status*/
              ctx2[2] > CONSTANTS.STATUS.RUNNING
            );
          }
          if (dirty & /*sequence*/
          1) {
            each_value = ensure_array_like(
              /*sequence*/
              ctx2[0].sections
            );
            let i;
            for (i = 0; i < each_value.length; i += 1) {
              const child_ctx = get_each_context$1(ctx2, each_value, i);
              if (each_blocks[i]) {
                each_blocks[i].p(child_ctx, dirty);
                transition_in(each_blocks[i], 1);
              } else {
                each_blocks[i] = create_each_block$1(child_ctx);
                each_blocks[i].c();
                transition_in(each_blocks[i], 1);
                each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor);
              }
            }
            group_outros();
            for (i = each_value.length; i < each_blocks.length; i += 1) {
              out(i);
            }
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          transition_in(sequencestatus.$$.fragment, local);
          for (let i = 0; i < each_value.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          transition_out(sequencestatus.$$.fragment, local);
          each_blocks = each_blocks.filter(Boolean);
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
            detach(t6);
            detach(each_1_anchor);
          }
          destroy_component(sequencestatus);
          destroy_each(each_blocks, detaching);
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function instance$2($$self, $$props, $$invalidate) {
      let $status;
      let { sequence } = $$props;
      let { index } = $$props;
      const status = sequence.statusStore;
      component_subscribe($$self, status, (value) => $$invalidate(2, $status = value));
      const click_handler = () => {
        SequenceManager.RunningSequences.delete(sequence.id);
      };
      const click_handler_1 = () => {
        sequence._abort();
      };
      $$self.$$set = ($$props2) => {
        if ("sequence" in $$props2) $$invalidate(0, sequence = $$props2.sequence);
        if ("index" in $$props2) $$invalidate(1, index = $$props2.index);
      };
      return [sequence, index, $status, status, click_handler, click_handler_1];
    }
    let Sequence$2 = class Sequence extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$2, create_fragment$3, safe_not_equal, { sequence: 0, index: 1 });
      }
    };
    function get_each_context(ctx, list, i) {
      const child_ctx = ctx.slice();
      child_ctx[6] = list[i][0];
      child_ctx[7] = list[i][1];
      child_ctx[9] = i;
      return child_ctx;
    }
    function create_else_block(ctx) {
      let div0;
      let button0;
      let t1;
      let button1;
      let t3;
      let div1;
      let each_blocks = [];
      let each_1_lookup = /* @__PURE__ */ new Map();
      let current;
      let mounted;
      let dispose;
      let each_value = ensure_array_like(
        /*runningSequences*/
        ctx[0]
      );
      const get_key = (ctx2) => (
        /*id*/
        ctx2[6]
      );
      for (let i = 0; i < each_value.length; i += 1) {
        let child_ctx = get_each_context(ctx, each_value, i);
        let key = get_key(child_ctx);
        each_1_lookup.set(key, each_blocks[i] = create_each_block(key, child_ctx));
      }
      return {
        c() {
          div0 = element("div");
          button0 = element("button");
          button0.textContent = `${localize("SEQUENCER.Sequences.ClearFinished")}`;
          t1 = space();
          button1 = element("button");
          button1.textContent = `${localize("SEQUENCER.Sequences.StopAll")}`;
          t3 = space();
          div1 = element("div");
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].c();
          }
          attr(button0, "type", "button");
          attr(button0, "class", "svelte-seq-1ismzan");
          attr(button1, "type", "button");
          attr(button1, "class", "svelte-seq-1ismzan");
          attr(div0, "class", "sequence-button-header svelte-seq-1ismzan");
          attr(div1, "class", "running-sequences svelte-seq-1ismzan");
        },
        m(target, anchor) {
          insert(target, div0, anchor);
          append(div0, button0);
          append(div0, t1);
          append(div0, button1);
          insert(target, t3, anchor);
          insert(target, div1, anchor);
          for (let i = 0; i < each_blocks.length; i += 1) {
            if (each_blocks[i]) {
              each_blocks[i].m(div1, null);
            }
          }
          current = true;
          if (!mounted) {
            dispose = [
              listen(
                button0,
                "click",
                /*click_handler*/
                ctx[3]
              ),
              listen(
                button1,
                "click",
                /*click_handler_1*/
                ctx[4]
              )
            ];
            mounted = true;
          }
        },
        p(ctx2, dirty) {
          if (dirty & /*runningSequences*/
          1) {
            each_value = ensure_array_like(
              /*runningSequences*/
              ctx2[0]
            );
            group_outros();
            each_blocks = update_keyed_each(each_blocks, dirty, get_key, 1, ctx2, each_value, each_1_lookup, div1, outro_and_destroy_block, create_each_block, null, get_each_context);
            check_outros();
          }
        },
        i(local) {
          if (current) return;
          for (let i = 0; i < each_value.length; i += 1) {
            transition_in(each_blocks[i]);
          }
          current = true;
        },
        o(local) {
          for (let i = 0; i < each_blocks.length; i += 1) {
            transition_out(each_blocks[i]);
          }
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div0);
            detach(t3);
            detach(div1);
          }
          for (let i = 0; i < each_blocks.length; i += 1) {
            each_blocks[i].d();
          }
          mounted = false;
          run_all(dispose);
        }
      };
    }
    function create_if_block(ctx) {
      let div;
      let h2;
      return {
        c() {
          div = element("div");
          h2 = element("h2");
          h2.textContent = `${localize("SEQUENCER.Sequences.NoSequences")}`;
          attr(div, "class", "no-sequences");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          append(div, h2);
        },
        p: noop,
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div);
          }
        }
      };
    }
    function create_each_block(key_1, ctx) {
      let first;
      let sequence_1;
      let current;
      sequence_1 = new Sequence$2({
        props: {
          sequence: (
            /*sequence*/
            ctx[7]
          ),
          index: (
            /*index*/
            ctx[9] + 1
          )
        }
      });
      return {
        key: key_1,
        first: null,
        c() {
          first = empty();
          create_component(sequence_1.$$.fragment);
          this.first = first;
        },
        m(target, anchor) {
          insert(target, first, anchor);
          mount_component(sequence_1, target, anchor);
          current = true;
        },
        p(new_ctx, dirty) {
          ctx = new_ctx;
          const sequence_1_changes = {};
          if (dirty & /*runningSequences*/
          1) sequence_1_changes.sequence = /*sequence*/
          ctx[7];
          if (dirty & /*runningSequences*/
          1) sequence_1_changes.index = /*index*/
          ctx[9] + 1;
          sequence_1.$set(sequence_1_changes);
        },
        i(local) {
          if (current) return;
          transition_in(sequence_1.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(sequence_1.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(first);
          }
          destroy_component(sequence_1, detaching);
        }
      };
    }
    function create_fragment$2(ctx) {
      let div;
      let current_block_type_index;
      let if_block;
      let current;
      const if_block_creators = [create_if_block, create_else_block];
      const if_blocks = [];
      function select_block_type(ctx2, dirty) {
        if (!/*runningSequences*/
        ctx2[0].length) return 0;
        return 1;
      }
      current_block_type_index = select_block_type(ctx);
      if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx);
      return {
        c() {
          div = element("div");
          if_block.c();
          attr(div, "class", "sequence-container svelte-seq-1ismzan");
        },
        m(target, anchor) {
          insert(target, div, anchor);
          if_blocks[current_block_type_index].m(div, null);
          current = true;
        },
        p(ctx2, [dirty]) {
          let previous_block_index = current_block_type_index;
          current_block_type_index = select_block_type(ctx2);
          if (current_block_type_index === previous_block_index) {
            if_blocks[current_block_type_index].p(ctx2, dirty);
          } else {
            group_outros();
            transition_out(if_blocks[previous_block_index], 1, 1, () => {
              if_blocks[previous_block_index] = null;
            });
            check_outros();
            if_block = if_blocks[current_block_type_index];
            if (!if_block) {
              if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx2);
              if_block.c();
            } else {
              if_block.p(ctx2, dirty);
            }
            transition_in(if_block, 1);
            if_block.m(div, null);
          }
        },
        i(local) {
          if (current) return;
          transition_in(if_block);
          current = true;
        },
        o(local) {
          transition_out(if_block);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(div);
          }
          if_blocks[current_block_type_index].d();
        }
      };
    }
    function instance$1($$self, $$props, $$invalidate) {
      let runningSequences;
      let $RunningSequences;
      const RunningSequences = SequenceManager.RunningSequences;
      component_subscribe($$self, RunningSequences, (value) => $$invalidate(2, $RunningSequences = value));
      onMount(() => {
        SequenceManager.RunningSequences.clearFinishedSequences();
      });
      onDestroy(() => {
        SequenceManager.RunningSequences.clearFinishedSequences();
      });
      const click_handler = () => {
        SequenceManager.RunningSequences.clearFinishedSequences();
      };
      const click_handler_1 = () => {
        SequenceManager.RunningSequences.stopAll();
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*$RunningSequences*/
        4) {
          $$invalidate(0, runningSequences = Object.entries($RunningSequences));
        }
      };
      return [
        runningSequences,
        RunningSequences,
        $RunningSequences,
        click_handler,
        click_handler_1
      ];
    }
    class Sequences extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance$1, create_fragment$2, safe_not_equal, {});
      }
    }
    function create_default_slot(ctx) {
      let tabs_1;
      let updating_activeTab;
      let t;
      let switch_instance;
      let switch_instance_anchor;
      let current;
      function tabs_1_activeTab_binding(value) {
        ctx[4](value);
      }
      let tabs_1_props = { tabs: (
        /*tabs*/
        ctx[3]
      ) };
      if (
        /*activeTab*/
        ctx[1] !== void 0
      ) {
        tabs_1_props.activeTab = /*activeTab*/
        ctx[1];
      }
      tabs_1 = new Tabs({ props: tabs_1_props });
      binding_callbacks.push(() => bind(tabs_1, "activeTab", tabs_1_activeTab_binding));
      var switch_value = (
        /*component*/
        ctx[2]
      );
      function switch_props(ctx2, dirty) {
        return {};
      }
      if (switch_value) {
        switch_instance = construct_svelte_component(switch_value, switch_props());
      }
      return {
        c() {
          create_component(tabs_1.$$.fragment);
          t = space();
          if (switch_instance) create_component(switch_instance.$$.fragment);
          switch_instance_anchor = empty();
        },
        m(target, anchor) {
          mount_component(tabs_1, target, anchor);
          insert(target, t, anchor);
          if (switch_instance) mount_component(switch_instance, target, anchor);
          insert(target, switch_instance_anchor, anchor);
          current = true;
        },
        p(ctx2, dirty) {
          const tabs_1_changes = {};
          if (!updating_activeTab && dirty & /*activeTab*/
          2) {
            updating_activeTab = true;
            tabs_1_changes.activeTab = /*activeTab*/
            ctx2[1];
            add_flush_callback(() => updating_activeTab = false);
          }
          tabs_1.$set(tabs_1_changes);
          if (dirty & /*component*/
          4 && switch_value !== (switch_value = /*component*/
          ctx2[2])) {
            if (switch_instance) {
              group_outros();
              const old_component = switch_instance;
              transition_out(old_component.$$.fragment, 1, 0, () => {
                destroy_component(old_component, 1);
              });
              check_outros();
            }
            if (switch_value) {
              switch_instance = construct_svelte_component(switch_value, switch_props());
              create_component(switch_instance.$$.fragment);
              transition_in(switch_instance.$$.fragment, 1);
              mount_component(switch_instance, switch_instance_anchor.parentNode, switch_instance_anchor);
            } else {
              switch_instance = null;
            }
          }
        },
        i(local) {
          if (current) return;
          transition_in(tabs_1.$$.fragment, local);
          if (switch_instance) transition_in(switch_instance.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(tabs_1.$$.fragment, local);
          if (switch_instance) transition_out(switch_instance.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          if (detaching) {
            detach(t);
            detach(switch_instance_anchor);
          }
          destroy_component(tabs_1, detaching);
          if (switch_instance) destroy_component(switch_instance, detaching);
        }
      };
    }
    function create_fragment$1(ctx) {
      let applicationshell;
      let updating_elementRoot;
      let current;
      function applicationshell_elementRoot_binding(value) {
        ctx[5](value);
      }
      let applicationshell_props = {
        $$slots: { default: [create_default_slot] },
        $$scope: { ctx }
      };
      if (
        /*elementRoot*/
        ctx[0] !== void 0
      ) {
        applicationshell_props.elementRoot = /*elementRoot*/
        ctx[0];
      }
      applicationshell = new ApplicationShell({ props: applicationshell_props });
      binding_callbacks.push(() => bind(applicationshell, "elementRoot", applicationshell_elementRoot_binding));
      return {
        c() {
          create_component(applicationshell.$$.fragment);
        },
        m(target, anchor) {
          mount_component(applicationshell, target, anchor);
          current = true;
        },
        p(ctx2, [dirty]) {
          const applicationshell_changes = {};
          if (dirty & /*$$scope, component, activeTab*/
          134) {
            applicationshell_changes.$$scope = { dirty, ctx: ctx2 };
          }
          if (!updating_elementRoot && dirty & /*elementRoot*/
          1) {
            updating_elementRoot = true;
            applicationshell_changes.elementRoot = /*elementRoot*/
            ctx2[0];
            add_flush_callback(() => updating_elementRoot = false);
          }
          applicationshell.$set(applicationshell_changes);
        },
        i(local) {
          if (current) return;
          transition_in(applicationshell.$$.fragment, local);
          current = true;
        },
        o(local) {
          transition_out(applicationshell.$$.fragment, local);
          current = false;
        },
        d(detaching) {
          destroy_component(applicationshell, detaching);
        }
      };
    }
    function instance($$self, $$props, $$invalidate) {
      let component;
      const { application } = getContext("#external");
      let { elementRoot } = $$props;
      let tabs = [
        {
          value: "player",
          label: localize("SEQUENCER.Player.Title"),
          icon: "fas fa-play-circle",
          component: Player
        },
        {
          value: "manager",
          label: localize("SEQUENCER.Manager.Title"),
          icon: "fas fa-film",
          component: Manager
        },
        {
          value: "sequences",
          label: localize("SEQUENCER.Sequences.Title"),
          icon: "fas fa-play",
          component: Sequences
        },
        {
          value: "howto",
          label: localize("SEQUENCER.HowTo.Title"),
          icon: "fas fa-chalkboard-teacher",
          component: HowTo
        }
      ];
      let activeTab = application.options.tab ?? "manager";
      function tabs_1_activeTab_binding(value) {
        activeTab = value;
        $$invalidate(1, activeTab);
      }
      function applicationshell_elementRoot_binding(value) {
        elementRoot = value;
        $$invalidate(0, elementRoot);
      }
      $$self.$$set = ($$props2) => {
        if ("elementRoot" in $$props2) $$invalidate(0, elementRoot = $$props2.elementRoot);
      };
      $$self.$$.update = () => {
        if ($$self.$$.dirty & /*activeTab*/
        2) {
          $$invalidate(2, component = tabs.find((tab) => tab.value === activeTab).component);
        }
      };
      return [
        elementRoot,
        activeTab,
        component,
        tabs,
        tabs_1_activeTab_binding,
        applicationshell_elementRoot_binding
      ];
    }
    class Effects_ui_shell extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance, create_fragment$1, safe_not_equal, { elementRoot: 0 });
      }
      get elementRoot() {
        return this.$$.ctx[0];
      }
      set elementRoot(elementRoot) {
        this.$$set({ elementRoot });
        flush();
      }
    }
    class EffectsUIApp extends SvelteApp {
      static get defaultOptions() {
        return foundry.utils.mergeObject(super.defaultOptions, {
          title: game.i18n.localize("SEQUENCER.ManagerUI"),
          classes: ["dialog"],
          width: "auto",
          height: "auto",
          top: 65,
          left: 120,
          resizable: false,
          svelte: {
            class: Effects_ui_shell,
            target: document.body
          }
        });
      }
      static getActiveApp() {
        return Object.values(ui.windows).find((app) => {
          return app instanceof this && app._state > Application.RENDER_STATES.CLOSED;
        });
      }
      static async show(options = {}) {
        const existingApp = this.getActiveApp();
        if (existingApp) return existingApp.render(false, { focus: true });
        return new Promise((resolve) => {
          options.resolve = resolve;
          new this(options).render(true, { focus: true });
        });
      }
    }
    function registerSettings() {
      game.settings.register(CONSTANTS.MODULE_NAME, "enable-fix-pixi", {
        name: "SEQUENCER.Setting.EnablePixiFix.Title",
        hint: "SEQUENCER.Setting.EnablePixiFix.Label",
        scope: "client",
        config: true,
        default: false,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "enable-global-fix-pixi", {
        name: "SEQUENCER.Setting.EnableGlobalPixiFix.Title",
        hint: "SEQUENCER.Setting.EnableGlobalPixiFix.Label",
        scope: "client",
        config: true,
        default: false,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "enable-above-ui-screenspace", {
        name: "SEQUENCER.Setting.EnableAboveUIScreenspace.Title",
        hint: "SEQUENCER.Setting.EnableAboveUIScreenspace.Label",
        scope: "client",
        config: true,
        default: true,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "debug", {
        name: "SEQUENCER.Setting.Debug.Title",
        hint: "SEQUENCER.Setting.Debug.Label",
        scope: "client",
        config: true,
        default: false,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "showSidebarTools", {
        name: "SEQUENCER.Setting.ShowTools.Title",
        hint: "SEQUENCER.Setting.ShowTools.Label",
        scope: "client",
        config: true,
        default: true,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "showTokenSidebarTools", {
        name: "SEQUENCER.Setting.ShowTokenTools.Title",
        hint: "SEQUENCER.Setting.ShowTokenTools.Label",
        scope: "client",
        config: true,
        default: true,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "effectsEnabled", {
        name: "SEQUENCER.Setting.EnableEffects.Title",
        hint: "SEQUENCER.Setting.EnableEffects.Label",
        scope: "client",
        config: true,
        default: true,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "soundsEnabled", {
        name: "SEQUENCER.Setting.EnableSounds.Title",
        hint: "SEQUENCER.Setting.EnableSounds.Label",
        scope: "client",
        config: true,
        default: true,
        requiresReload: true,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "user-effect-opacity", {
        name: "SEQUENCER.Setting.ExternalEffectOpacity.Title",
        hint: "SEQUENCER.Setting.ExternalEffectOpacity.Label",
        scope: "client",
        config: true,
        default: 50,
        type: Number,
        range: {
          min: 0,
          max: 100,
          step: 1
        }
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "db-list-view", {
        scope: "client",
        config: false,
        default: false,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "support-dialog-shown", {
        scope: "world",
        config: false,
        default: false,
        type: Boolean
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "welcome-shown-version", {
        scope: "world",
        config: false,
        default: "0.0.0",
        type: String
      });
      const permissionLevels = [
        game.i18n.localize("SEQUENCER.Permission.Player"),
        game.i18n.localize("SEQUENCER.Permission.Trusted"),
        game.i18n.localize("SEQUENCER.Permission.Assistant"),
        game.i18n.localize("SEQUENCER.Permission.GM")
      ];
      game.settings.register(CONSTANTS.MODULE_NAME, "permissions-effect-create", {
        name: "SEQUENCER.Setting.Permission.EffectCreate.Title",
        hint: "SEQUENCER.Setting.Permission.EffectCreate.Label",
        scope: "world",
        config: true,
        default: 0,
        type: Number,
        choices: permissionLevels,
        requiresReload: true
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "permissions-effect-delete", {
        name: "SEQUENCER.Setting.Permission.EffectDelete.Title",
        hint: "SEQUENCER.Setting.Permission.EffectDelete.Label",
        scope: "world",
        config: true,
        default: 2,
        type: Number,
        choices: permissionLevels,
        requiresReload: true
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "permissions-sound-create", {
        name: "SEQUENCER.Setting.Permission.SoundCreate.Title",
        hint: "SEQUENCER.Setting.Permission.SoundCreate.Label",
        scope: "world",
        config: true,
        default: 0,
        type: Number,
        choices: permissionLevels,
        requiresReload: true
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "permissions-preload", {
        name: "SEQUENCER.Setting.Permission.PreloadClients.Title",
        hint: "SEQUENCER.Setting.Permission.PreloadClients.Label",
        scope: "world",
        config: true,
        default: 1,
        type: Number,
        choices: permissionLevels,
        requiresReload: true
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "permissions-sidebar-tools", {
        name: "SEQUENCER.Setting.Permission.UseSidebarTools.Title",
        hint: "SEQUENCER.Setting.Permission.UseSidebarTools.Label",
        scope: "world",
        config: true,
        default: 0,
        type: Number,
        choices: permissionLevels,
        requiresReload: true
      });
      game.settings.register(CONSTANTS.MODULE_NAME, "effectPresets", {
        scope: "client",
        default: {},
        type: Object
      });
      Hooks.on("getSceneControlButtons", (controls) => {
        if (!game.settings.get(CONSTANTS.MODULE_NAME, "showSidebarTools")) return;
        const sidebarTools = {
          [CONSTANTS.TOOLS.SELECT]: {
            name: CONSTANTS.TOOLS.SELECT,
            title: "SEQUENCER.SidebarButtons.Select",
            icon: "fas fa-expand",
            visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
            onChange: () => {
            }
          },
          [CONSTANTS.TOOLS.PLAY]: {
            name: CONSTANTS.TOOLS.PLAY,
            title: "SEQUENCER.SidebarButtons.Play",
            icon: "fas fa-play",
            visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
            onChange: (event, active2) => {
              if (active2 || !CONSTANTS.IS_V13) {
                EffectsUIApp.show({ inFocus: true, tab: "player" });
              }
            }
          },
          [CONSTANTS.TOOLS.VIEWER]: {
            name: CONSTANTS.TOOLS.VIEWER,
            title: "SEQUENCER.SidebarButtons.Manager",
            icon: "fas fa-film",
            button: true,
            visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
            onChange: (event, active2) => {
              if (active2 || !CONSTANTS.IS_V13) {
                EffectsUIApp.show({ inFocus: true, tab: "manager" });
              }
            }
          },
          [CONSTANTS.TOOLS.DATABASE]: {
            name: CONSTANTS.TOOLS.DATABASE,
            title: "SEQUENCER.SidebarButtons.Database",
            icon: "fas fa-database",
            button: true,
            visible: user_can_do("permissions-sidebar-tools"),
            onChange: (event, active2) => {
              if (active2 || !CONSTANTS.IS_V13) {
                DatabaseViewerApp.show();
              }
            }
          }
        };
        if (CONSTANTS.IS_V13) {
          return setupSidebarToolsV13(controls, sidebarTools);
        }
        Object.values(sidebarTools).forEach((button) => {
          button.onClick = button.onChange;
        });
        return setupSidebarToolsV12(controls, sidebarTools);
      });
      debug("Sequencer | Registered settings");
    }
    function setupSidebarToolsV13(controls, sidebarTools) {
      controls[CONSTANTS.MODULE_NAME] = {
        name: CONSTANTS.MODULE_NAME,
        title: "Sequencer Layer",
        icon: "fas fa-list-ol",
        layer: CONSTANTS.INTERFACE_LAYER,
        visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
        activeTool: CONSTANTS.TOOLS.PLAY,
        onChange: (event, active2) => {
          if (active2) canvas.sequencerInterfaceLayer.activate({ tool: CONSTANTS.TOOLS.PLAY });
        },
        tools: sidebarTools
      };
      if (!game.settings.get(CONSTANTS.MODULE_NAME, "showTokenSidebarTools")) {
        return;
      }
      controls["tokens"].tools[CONSTANTS.TOOLS.DATABASE] = sidebarTools[CONSTANTS.TOOLS.DATABASE];
      controls["tokens"].tools[CONSTANTS.TOOLS.VIEWER] = sidebarTools[CONSTANTS.TOOLS.VIEWER];
    }
    function setupSidebarToolsV12(controls, sidebarTools) {
      controls.push({
        name: CONSTANTS.MODULE_NAME,
        title: "Sequencer Layer",
        icon: "fas fa-list-ol",
        layer: CONSTANTS.INTERFACE_LAYER,
        visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
        activeTool: CONSTANTS.TOOLS.SELECT,
        tools: Object.values(sidebarTools)
      });
      if (!game.settings.get(CONSTANTS.MODULE_NAME, "showTokenSidebarTools")) {
        return;
      }
      const bar = controls.find((c) => c.name === "token");
      bar.tools.push(sidebarTools[CONSTANTS.TOOLS.DATABASE]);
      bar.tools.push(sidebarTools[CONSTANTS.TOOLS.VIEWER]);
    }
    async function migrateSettings() {
      const oldScreenspaceSetting = game.settings.storage.get("client").getItem("sequencer.disable-above-ui-screenspace");
      if (oldScreenspaceSetting) {
        const value = oldScreenspaceSetting === "true";
        game.settings.storage.get("client").removeItem("sequencer.disable-above-ui-screenspace");
        await game.settings.set(
          CONSTANTS.MODULE_NAME,
          "enable-above-ui-screenspace",
          !value
        );
      }
    }
    function registerLayers() {
      CONFIG.Canvas.layers = foundry.utils.mergeObject(FoundryShim.Canvas.layers, {
        sequencerEffects: {
          layerClass: BaseEffectsLayer,
          group: "primary"
        },
        sequencerInterfaceLayer: {
          layerClass: SequencerInterfaceLayer,
          group: "interface"
        },
        sequencerEffectsUILayer: {
          layerClass: UIEffectsLayer,
          group: "interface"
        }
      });
      if (!Object.is(FoundryShim.Canvas.layers, CONFIG.Canvas.layers)) {
        const layers = FoundryShim.Canvas.layers;
        Object.defineProperty(FoundryShim.Canvas, "layers", {
          get: function() {
            return foundry.utils.mergeObject(layers, CONFIG.Canvas.layers);
          }
        });
      }
      debug("Registered Layers");
    }
    function registerBatchShader() {
      VisionSamplerShader.registerPlugin();
      debug("Registered VisionBatchShader");
    }
    const hotkeys = {
      get _ready() {
        return canvas.ready && canvas.sequencerInterfaceLayer.active;
      },
      playTool: {
        playManySequencedDown: () => {
          if (!hotkeys._ready) return;
          EffectPlayer.playManySequenced = true;
        },
        playManySequencedUp: () => {
          if (!hotkeys._ready) return;
          EffectPlayer.playManySequenced = false;
          if (!EffectPlayer.isActive) return;
          EffectPlayer.playManyUp();
        },
        playManyDown: () => {
          if (!hotkeys._ready) return;
          EffectPlayer.playMany = true;
        },
        playManyUp: () => {
          if (!hotkeys._ready) return;
          EffectPlayer.playMany = false;
          if (!EffectPlayer.isActive) return;
          EffectPlayer.playManyUp();
        },
        attachToDown: () => {
          if (!hotkeys._ready) return;
          PlayerSettings.attachTo.store.set(true);
          PlayerSettings.stretchToAttach.store.set(true);
        }
      },
      selectTool: {
        snapToGridDown: () => {
          if (!hotkeys._ready) return;
          SelectionManager.snapToGrid = true;
        },
        snapToGridUp: () => {
          if (!hotkeys._ready) return;
          SelectionManager.snapToGrid = false;
        },
        attachToTargetDown: () => {
          if (!hotkeys._ready) return;
          if (!SelectionManager.isActive) return;
          PlayerSettings.attachTo.store.set(true);
          PlayerSettings.stretchToAttach.store.set(true);
        },
        attachToTargetUp: () => {
          if (!hotkeys._ready) return;
          PlayerSettings.attachTo.store.set(false);
          PlayerSettings.stretchToAttach.store.set(false);
        },
        deleteDown: () => {
          if (!hotkeys._ready) return;
          SelectionManager.delete();
        }
      }
    };
    function registerHotkeys() {
      game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-control", {
        name: "SEQUENCER.Hotkeys.PlayTool.Control",
        editable: [{ key: "ControlLeft" }],
        onDown: hotkeys.playTool.playManySequencedDown,
        onUp: hotkeys.playTool.playManySequencedUp
      });
      game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-shift", {
        name: "SEQUENCER.Hotkeys.PlayTool.Shift",
        editable: [{ key: "ShiftLeft" }],
        onDown: hotkeys.playTool.playManyDown,
        onUp: hotkeys.playTool.playManyUp
      });
      game.keybindings.register(CONSTANTS.MODULE_NAME, "play-tool-hotkey-alt", {
        name: "SEQUENCER.Hotkeys.PlayTool.Alt",
        editable: [{ key: "AltLeft" }],
        onDown: hotkeys.playTool.attachToDown,
        onUp: hotkeys.playTool.attachToDown
      });
      game.keybindings.register(
        CONSTANTS.MODULE_NAME,
        "select-tool-hotkey-control",
        {
          name: "SEQUENCER.Hotkeys.SelectTool.Control",
          editable: [{ key: "ControlLeft" }],
          onDown: hotkeys.selectTool.snapToGridDown,
          onUp: hotkeys.selectTool.snapToGridUp
        }
      );
      game.keybindings.register(CONSTANTS.MODULE_NAME, "select-tool-hotkey-alt", {
        name: "SEQUENCER.Hotkeys.SelectTool.Alt",
        editable: [{ key: "AltLeft" }],
        onDown: hotkeys.selectTool.attachToTargetDown,
        onUp: hotkeys.selectTool.attachToTargetUp
      });
      game.keybindings.register(
        CONSTANTS.MODULE_NAME,
        "select-tool-hotkey-delete",
        {
          name: "SEQUENCER.Hotkeys.SelectTool.Delete",
          editable: [{ key: "Delete" }],
          onDown: hotkeys.selectTool.deleteDown
        }
      );
    }
    async function registerTypes(register) {
      fetch("modules/sequencer/typings/types.d.ts").then((response) => response.text()).then((content) => register("sequencer/types.d.ts", content));
    }
    const presetMap = /* @__PURE__ */ new Map();
    class SequencerPresets {
      /**
       * Adds a preset that can then be used in sequences
       *
       * @param {string} inName
       * @param {Function} inFunction
       * @param {boolean} [overwrite=false] overwrite
       * @returns {Map<string, Function>}
       */
      static add(inName, inFunction, overwrite = false) {
        if (typeof inName !== "string") {
          throw custom_error(
            "Sequencer",
            `SequencerPresets | inName must be of type string`
          );
        }
        if (!is_function$1(inFunction)) {
          throw custom_error(
            "Sequencer",
            `SequencerPresets | inFunction must be of type function`
          );
        }
        if (presetMap.get(inName) && !overwrite) {
          throw custom_error(
            "Sequencer",
            `SequencerPresets | Preset "${inName}" already exists`
          );
        }
        presetMap.set(inName, inFunction);
        debug(`Sequencer | Presets | Added "${inName}" preset`);
        return presetMap;
      }
      /**
       * Retrieves all presets
       *
       * @returns {Map<string, Function>}
       */
      static getAll() {
        return presetMap;
      }
      /**
       * Retrieves preset based on its name
       *
       * @param {string} name
       * @param {boolean} exact
       * @returns {Function}
       */
      static get(name2, exact = false) {
        if (presetMap.has(name2) || exact) {
          return presetMap.get(name2);
        }
        const parts = name2.split(".");
        parts.pop();
        while (parts.length) {
          const newName = parts.join(".");
          if (presetMap.has(newName)) {
            return presetMap.get(newName);
          }
        }
        return false;
      }
    }
    class Section {
      constructor(inSequence) {
        this.sequence = inSequence;
        this._applyTraits();
        this._sectionStatus = writable(CONSTANTS.STATUS.READY);
        this._playIf = true;
        this._waitUntilFinished = false;
        this._async = false;
        this._waitUntilFinishedDelay = [0, 0];
        this._repetitions = 1;
        this._currentRepetition = 0;
        this._repeatDelayMin = 0;
        this._repeatDelayMax = 0;
        this._repeatDelay = 0;
        this._delayMin = 0;
        this._delayMax = 0;
        this._basicDelay = 0;
        this._duration = false;
      }
      static niceName = "Section";
      /**
       * @protected
       */
      get _shouldAsync() {
        return this._async || this._waitAnyway;
      }
      /**
       * @protected
       */
      get shouldWaitUntilFinished() {
        return this._waitUntilFinished || this._waitAnyway;
      }
      /**
       * @protected
       */
      get _waitAnyway() {
        return (this._async || this._waitUntilFinished) && this._isLastRepetition || this._isLastRepetition && this._isLastSection;
      }
      /**
       * @protected
       */
      get _isLastSection() {
        return this.sequence.sections.length - 1 === this.sequence.sections.indexOf(this);
      }
      /** ------------------------------------------------------------------------------------------------------------------------------ *
       * Methods below this point should NOT be overridden by child instances of the class, they are integral to the sequence functioning
       * ------------------------------------------------------------------------------------------------------------------------------- */
      /**
       * @protected
       */
      get _isLastRepetition() {
        return this._repetitions === 1 || this._repetitions === this._currentRepetition + 1;
      }
      /**
       * @protected
       */
      get _currentWaitTime() {
        let waitUntilFinishedDelay = this._waitAnyway ? random_int_between(...this._waitUntilFinishedDelay) : 0;
        return waitUntilFinishedDelay + this._repeatDelay;
      }
      /**
       * Method overwritten by inheriting classes, which is called just before the "run" method is called (see below)
       *
       * @returns {Promise<void>}
       * @protected
       */
      async preRun() {
      }
      /**
       * Method overwritten by inheriting classes, which is called when this section is executed by the Sequence
       *
       * @returns {Promise<void>}
       * @protected
       */
      async run() {
      }
      /**
       * Method overwritten by inheriting classes, which is called when this section is serialized by the Sequence
       *
       * @returns {object}
       * @private
       */
      async _serialize() {
        return {
          async: this._async,
          delay: [this._delayMin, this._delayMax],
          waitUntilFinished: this._waitUntilFinished,
          waitUntilFinishedDelay: this._waitUntilFinishedDelay,
          repetitions: this._repetitions,
          repetitionsDelay: [this._repeatDelayMin, this._repeatDelayMax]
        };
      }
      _deserialize(data) {
        this._async = data.async;
        this._waitUntilFinished = data.waitUntilFinished;
        this._waitUntilFinishedDelay = data.waitUntilFinishedDelay;
        this._repetitions = data.repetitions;
        this._repeatDelayMin = data.repetitionsDelay[0];
        this._repeatDelayMax = data.repetitionsDelay[1];
        return this;
      }
      /**
       * Method overwritten by inheriting classes, which stores data or prepares data before the Sequence executes it (see EffectsSection)
       *
       * @protected
       */
      async _initialize() {
      }
      /**
       * Method overwritten by inheriting classes. Inheriting classes uses the following to apply traits to themselves:
       * - Object.assign(this.constructor.prototype, trait)
       *
       * @protected
       */
      _applyTraits() {
      }
      /**
       * Causes the section to be repeated n amount of times, with an optional delay. If given inRepeatDelayMin
       * and inRepeatDelayMax, a random repetition delay will be picked for every repetition
       *
       * @param {number} inRepetitions
       * @param {number} inRepeatDelayMin
       * @param {number} inRepeatDelayMax
       * @returns {Section} this
       */
      repeats(inRepetitions, inRepeatDelayMin = 0, inRepeatDelayMax) {
        if (!is_real_number(inRepetitions))
          throw this.sequence._customError(
            this,
            "repeats",
            "inRepetitions must be of type number"
          );
        if (!is_real_number(inRepeatDelayMin))
          throw this.sequence._customError(
            this,
            "repeats",
            "repeatDelayMin must be of type number"
          );
        if (inRepeatDelayMax && !is_real_number(inRepeatDelayMax)) {
          throw this.sequence._customError(
            this,
            "repeats",
            "repeatDelayMax must be of type number"
          );
        }
        this._repetitions = inRepetitions;
        this._repeatDelayMin = Math.min(
          inRepeatDelayMin,
          inRepeatDelayMax ?? inRepeatDelayMin
        );
        this._repeatDelayMax = Math.max(
          inRepeatDelayMin,
          inRepeatDelayMax ?? inRepeatDelayMin
        );
        return this;
      }
      /**
       * Causes the effect or sound to not play, and skip all delays, repetitions, waits, etc. If you pass a function,
       * the function should return something false-y if you do not want the effect or sound to play.
       *
       * @param {boolean|function} inCondition
       * @returns {Section} this
       */
      playIf(inCondition) {
        this._playIf = inCondition;
        return this;
      }
      /**
       * Causes the section to finish running before starting the next section.
       *
       * @param {number|boolean} [minDelay=0] minDelay
       * @param {number/null} [maxDelay=null] maxDelay
       * @returns {Section} this
       */
      waitUntilFinished(minDelay = 0, maxDelay = null) {
        if (minDelay === false) return this;
        if (!is_real_number(minDelay))
          throw this.sequence._customError(
            this,
            "waitUntilFinished",
            "minDelay must be of type number"
          );
        if (maxDelay !== null && !is_real_number(maxDelay))
          throw this.sequence._customError(
            this,
            "waitUntilFinished",
            "maxDelay must be of type number"
          );
        this._waitUntilFinished = true;
        this._waitUntilFinishedDelay = [
          Math.min(minDelay, maxDelay ?? minDelay),
          Math.max(minDelay, maxDelay ?? minDelay)
        ];
        return this;
      }
      /**
       * Causes each effect or sound to finish playing before the next one starts playing. This differs from
       * .waitUntilFinished() in the sense that this is for each repetition, whilst .waitUntilFinished() is
       * for the entire section.
       *
       * @returns {Section} this
       */
      async() {
        this._async = true;
        return this;
      }
      /**
       * Delays the effect or sound from being played for a set amount of milliseconds. If given a second number, a
       * random delay between the two numbers will be generated.
       *
       * @param {number} [msMin=1] minMs
       * @param {number} [msMax=1] maxMs
       * @returns {Section} this
       */
      delay(msMin, msMax) {
        if (!is_real_number(msMin))
          throw this.sequence._customError(
            this,
            "delay",
            "msMin must be of type number"
          );
        if (msMax && !is_real_number(msMax))
          throw this.sequence._customError(
            this,
            "delay",
            "msMax must be of type number"
          );
        this._delayMin = Math.min(msMin, msMax ?? msMin);
        this._delayMax = Math.max(msMin, msMax ?? msMin);
        return this;
      }
      /**
       * Overrides the duration of this section
       *
       * @param {number} inDuration
       * @returns {Section} this
       */
      duration(inDuration) {
        if (!is_real_number(inDuration))
          throw this.sequence._customError(
            this,
            "duration",
            "inDuration must be of type number"
          );
        this._duration = inDuration;
        return this;
      }
      /**
       * Applies a preset to the current section
       *
       * @param {string} presetName
       * @param {*} args
       * @returns {Section|FunctionSection|EffectSection|AnimationSection|SoundSection}
       */
      preset(presetName, ...args) {
        if (typeof presetName !== "string") {
          throw this.sequence._customError(
            this,
            "name",
            `inName must be of type string`
          );
        }
        const preset = SequencerPresets.get(presetName);
        if (!preset) {
          custom_warning(
            "Sequencer",
            `preset | Could not find preset with name "${presetName}"`
          );
          return this;
        }
        return preset(this, ...args);
      }
      /**
       * @protected
       */
      async _shouldPlay() {
        return is_function$1(this._playIf) ? await this._playIf() : this._playIf;
      }
      /**
       * @protected
       */
      _validateLocation(inLocation) {
        inLocation = validate_document(inLocation);
        if (typeof inLocation === "string") {
          inLocation = get_object_from_scene(inLocation) ?? inLocation;
        }
        if (typeof inLocation === "string") {
          inLocation = safe_str(inLocation);
        }
        return inLocation;
      }
      /**
       * @protected
       */
      async _execute() {
        if (!await this._shouldPlay()) {
          this.sectionStatus = CONSTANTS.STATUS.SKIPPED;
          return;
        }
        this._basicDelay = random_float_between(this._delayMin, this._delayMax);
        return new Promise(async (resolve) => {
          setTimeout(async () => {
            this.sectionStatus = CONSTANTS.STATUS.RUNNING;
            for (let i = 0; i < this._repetitions; i++) {
              if (get_store_value(this.sectionStatus) === CONSTANTS.STATUS.ABORTED) {
                resolve();
                return;
              }
              this._currentRepetition = i;
              this._repeatDelay = i !== this._repetitions - 1 ? random_float_between(
                this._repeatDelayMin,
                this._repeatDelayMax
              ) : 0;
              await this.preRun();
              if (this._shouldAsync) {
                await this.run();
              } else {
                this.run();
              }
              if (this._repetitions > 1 && i !== this._repetitions - 1) {
                await this._delayBetweenRepetitions();
              }
            }
            resolve();
          }, this._basicDelay);
        }).then(() => {
          this.sectionStatus = CONSTANTS.STATUS.COMPLETE;
        });
      }
      set sectionStatus(inStatus) {
        this._sectionStatus.update((currentStatus) => {
          if (currentStatus === CONSTANTS.STATUS.READY || currentStatus === CONSTANTS.STATUS.RUNNING && inStatus !== CONSTANTS.STATUS.ABORTED) {
            return inStatus;
          }
          return currentStatus;
        });
      }
      get sectionStatus() {
        return this._sectionStatus;
      }
      _abortSection() {
        this.sectionStatus = CONSTANTS.STATUS.ABORTED;
      }
      /**
       * @protected
       */
      async _delayBetweenRepetitions() {
        let self = this;
        return new Promise((resolve) => {
          setTimeout(resolve, self._repeatDelay);
        });
      }
    }
    class FunctionSection extends Section {
      constructor(inSequence, inFunc) {
        super(inSequence);
        if (!is_function$1(inFunc))
          this._customError(
            "create",
            "The given function needs to be an actual function"
          );
        this._func = inFunc;
        this._waitUntilFinished = inFunc.constructor.name === "AsyncFunction";
      }
      static niceName = "Function";
      /**
       * @returns {Promise<void>}
       */
      async run() {
        debug("Running function");
        await this._func();
      }
      /**
       * @returns {Promise}
       * @private
       */
      async _execute() {
        await this.run();
      }
    }
    const animation = {
      /**
       * Base properties
       */
      _animations: null,
      /**
       * Animates a property on the target of the animation.
       *
       * @param {string} inTarget
       * @param {string} inPropertyName
       * @param {object} inOptions
       *      @param {Number} inOptions.from       - a single number from which to animate
       *      @param {Number} inOptions.to         - a single number to which to animate
       *      @param {Number} inOptions.duration   - how long in ms the animation should take
       *      @param {Number} inOptions.delay      - inserts a delay in ms before the animation starts
       *      @param {String} inOptions.ease       - what type of easing the animation should use
       *      @param {Boolean} inOptions.gridUnits - if animating width or height, this will set it to work in the scene's grid units
       *      @param {Boolean} inOptions.screenSpace - if animating position, width, or height, this will set it to work in the screen's dimensions
       *      @param {Boolean} inOptions.fromEnd   - makes this animation play from the end, like fadeOut, scaleOut, etc
       *      @param {Boolean} inOptions.absolute  - makes this animation's values override the current value
       *
       * @returns this
       */
      animateProperty(inTarget, inPropertyName, inOptions = {}) {
        if (!this._animations) this._animations = [];
        const result = validateAnimation(
          inTarget,
          inPropertyName,
          inOptions
        );
        if (typeof result === "string") {
          throw this.sequence._customError(this, "animateProperty", result);
        }
        this._animations.push(result);
        return this;
      },
      /**
       * Loops a property between a set of values on the target
       *
       * @param {string} inTarget
       * @param {string} inPropertyName
       * @param {object} inOptions
       *      @param {Number} inOptions.from         - a single number from which to loop
       *      @param {Number} inOptions.to           - a single number to which to loop
       *      @param {Number} inOptions.values       - an array of values to loop between
       *      @param {Number} inOptions.duration     - how long in ms the loop should take
       *      @param {Number} inOptions.loops        - how many loops in total this animation should go through - if none are specified, the loop is indefinite
       *      @param {Number} inOptions.delay        - inserts a delay in ms before the animation starts
       *      @param {String} inOptions.ease         - what type of easing the animation should use
       *      @param {Boolean} inOptions.pingPong    - sets whether loop should interpolate to the first value after it reaches the first value, or simply set it to the first value
       *      @param {Boolean} inOptions.gridUnits   - if animating width or height, this will set it to work in the scene's grid units
       *      @param {Boolean} inOptions.screenSpace - if animating position, width, or height, this will set it to work in the screen's dimensions
       *      @param {Boolean} inOptions.absolute    - makes this animation's values override the current value
       *
       * @returns this
       */
      loopProperty(inTarget, inPropertyName, inOptions = {}) {
        if (!this._animations) this._animations = [];
        const result = validateLoopingAnimation(
          inTarget,
          inPropertyName,
          inOptions
        );
        if (typeof result === "string") {
          throw this.sequence._customError(this, "loopProperty", result);
        }
        this._animations.push(result);
        return this;
      }
    };
    const audio = {
      /**
       * Base properties
       */
      _volume: null,
      _channel: "interface",
      _fadeInAudio: null,
      _fadeOutAudio: null,
      /**
       * Sets the volume of the sound.
       *
       * @param {number} inVolume
       * @returns this
       */
      volume(inVolume) {
        if (!is_real_number(inVolume))
          throw this.sequence._customError(
            this,
            "volume",
            "inVolume must be of type number"
          );
        this._volume = Math.max(0, Math.min(1, inVolume));
        return this;
      },
      /**
       * Causes the animated section to fade in its audio (if any) when played
       *
       * @param {number} duration     How long the fade should be
       * @param {object} [options]    Additional options, such as easing and delay
       * @returns this
       */
      fadeInAudio(duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "fadeInAudio",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "fadeInAudio",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "fadeInAudio",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "fadeInAudio",
            "options.delay must be of type number"
          );
        this._fadeInAudio = {
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      },
      /**
       * Causes the audio to fade out at the end of the animated section's duration
       *
       * @param {number} duration     How long the fade should be
       * @param {object} [options]    Additional options, such as easing and delay
       * @returns this
       */
      fadeOutAudio(duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "fadeOutAudio",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "fadeOutAudio",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "fadeOutAudio",
            "ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "fadeOutAudio",
            "delay must be of type number"
          );
        this._fadeOutAudio = {
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      }
    };
    const files = {
      /**
       * Base properties
       */
      _file: "",
      _fileOptions: false,
      _baseFolder: "",
      _mustache: null,
      /**
       * Defines the base folder that will prepend to the file path. This is mainly just useful to make the file
       * path easier to manage.
       *
       * @param {string} inBaseFolder
       * @returns this
       */
      baseFolder(inBaseFolder) {
        if (typeof inBaseFolder !== "string")
          throw this.sequence._customError(
            this,
            "baseFolder",
            "inBaseFolder must be of type string"
          );
        this._baseFolder = inBaseFolder + (inBaseFolder.endsWith("/") ? "" : "/");
        return this;
      },
      /**
       * Sets the Mustache of the filepath. This is applied after the randomization of the filepath, if available.
       *
       * @param {object} inMustache
       * @returns this
       */
      setMustache(inMustache) {
        if (typeof inMustache !== "object")
          throw this.sequence._customError(
            this,
            "setMustache",
            "inMustache must be of type object"
          );
        this._mustache = inMustache;
        return this;
      },
      async _determineFile(inFile) {
        if (!Array.isArray(inFile) && typeof inFile === "object") {
          return this._validateCustomRange(inFile);
        }
        if (Array.isArray(inFile))
          inFile = random_array_element(inFile, { recurse: true });
        inFile = this._applyMustache(inFile);
        if (Sequencer.Database.entryExists(inFile)) {
          return this._determineDatabaseFile(inFile);
        }
        const determinedFile = await this._processFile(inFile);
        return { file: determinedFile, forcedIndex: false, customRange: false };
      },
      async _processFile(inFile) {
        inFile = this._applyMustache(inFile);
        inFile = this._applyBaseFolder(inFile);
        inFile = await this._applyWildcard(inFile);
        if (Array.isArray(inFile))
          inFile = random_array_element(inFile, { recurse: true });
        return inFile;
      },
      async _validateCustomRange(inFile) {
        const finalFiles = {};
        const validRanges = Object.keys(SequencerFileRangeFind.ftToDistanceMap);
        for (const [range, rangeFile] of Object.entries(inFile)) {
          if (!validRanges.includes(range)) {
            throw this.sequence._customError(
              this,
              "file",
              `a file-distance key map must only contain the following keys: ${validRanges.join(
                ", "
              )}`
            );
          }
          finalFiles[range] = await this._processFile(rangeFile);
        }
        return { file: finalFiles, forcedIndex: false, customRange: true };
      },
      _determineDatabaseFile(inFile) {
        const entries = Sequencer.Database.getEntry(inFile);
        const entry = Array.isArray(entries) ? random_array_element(entries) : entries;
        const match = inFile.match(/(\d)+$/);
        return {
          file: entry,
          forcedIndex: match ? Number(match[1]) : false,
          customRange: false
        };
      },
      _applyBaseFolder(inFile) {
        if (Array.isArray(inFile))
          return inFile.map((file) => this._applyBaseFolder(file));
        return inFile.startsWith(this._baseFolder) ? inFile : this._baseFolder + inFile;
      },
      _applyMustache(inFile) {
        if (!this._mustache) return inFile;
        let template = Handlebars.compile(inFile);
        return template(this._mustache);
      },
      async _applyWildcard(inFile) {
        if (!inFile.includes("*")) return inFile;
        if (Array.isArray(inFile))
          return inFile.map(async (file) => await this._applyWildcard(file));
        inFile = this._applyBaseFolder(inFile);
        return getFiles(inFile, {
          applyWildCard: true,
          softFail: this.sequence.softFail
        });
      }
    };
    const moves = {
      /**
       * Base properties
       */
      _moveTowards: null,
      _moveSpeed: null,
      /**
       * Sets the location to move the target object to
       *
       * @param {object|string} inTarget
       * @param {object} options
       * @returns this
       */
      moveTowards(inTarget, options = {}) {
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0,
            rotate: true,
            cacheLocation: false
          },
          options
        );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "moveTowards",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "moveTowards",
            "options.delay must be of type number"
          );
        if (typeof options.rotate !== "boolean")
          throw this.sequence._customError(
            this,
            "moveTowards",
            "options.rotate must be of type boolean"
          );
        if (typeof options.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "moveTowards",
            "options.cacheLocation must be of type boolean"
          );
        options.target = this._validateLocation(inTarget);
        if (!options.target)
          throw this.sequence._customError(
            this,
            "moveTowards",
            "could not find position of given object"
          );
        options.target = options.cacheLocation ? get_object_position(options.cacheLocation, { measure: true }) : options.target;
        this._moveTowards = options;
        return this;
      },
      /**
       * Sets the speed (pixels per frame) to move the target object
       *
       * @param {number} inSpeed
       * @returns this
       */
      moveSpeed(inSpeed) {
        if (!is_real_number(inSpeed))
          throw this.sequence._customError(
            this,
            "moveSpeed",
            "inSpeed must be of type number"
          );
        this._moveSpeed = inSpeed;
        return this;
      }
    };
    const opacity = {
      /**
       * Base properties
       */
      _opacity: null,
      _fadeIn: null,
      _fadeOut: null,
      /**
       * Sets the opacity of the effect. If used with ._fadeIn() and/or ._fadeOut(), this defines what the effect will fade to/from
       *
       * @param {number} inOpacity
       * @returns this
       */
      opacity(inOpacity) {
        if (!is_real_number(inOpacity))
          throw this.sequence._customError(
            this,
            "opacity",
            "inOpacity must be of type number"
          );
        this._opacity = inOpacity;
        return this;
      },
      /**
       * Causes the effect to fade in when played
       *
       * @param {number} duration     How long the fade should be
       * @param {object} [options]    Additional options, such as easing and delay
       * @returns this
       */
      fadeIn(duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "fadeIn",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "fadeIn",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "fadeIn",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "fadeIn",
            "options.delay must be of type number"
          );
        this._fadeIn = {
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      },
      /**
       * Causes the effect to fade out at the end of the effect's duration
       *
       * @param {number} duration     How long the fade should be
       * @param {object} [options]    Additional options, such as easing and delay
       * @returns this
       */
      fadeOut(duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "fadeOut",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "fadeOut",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "fadeOut",
            "ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "fadeOut",
            "delay must be of type number"
          );
        this._fadeOut = {
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      }
    };
    const rotation = {
      /**
       * Base properties
       */
      _angle: null,
      _rotateIn: null,
      _rotateOut: null,
      _randomRotation: null,
      _rotateTowards: null,
      /**
       * The object gets a random rotation, which means it should not be used with .stretchTo()
       *
       * @param {boolean} [inBool=true] inBool
       * @returns this
       */
      randomRotation(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "randomRotation",
            "inBool must be of type boolean"
          );
        this._randomRotation = inBool;
        return this;
      },
      /**
       * Sets the rotation of the object, which is added on top of the calculated rotation after .rotateTowards() or .randomRotation()
       *
       * @param {number} inRotation
       * @returns this
       */
      rotate(inRotation) {
        if (!is_real_number(inRotation))
          throw this.sequence._customError(
            this,
            "opacity",
            "inRotation must be of type number"
          );
        this._angle = inRotation;
        return this;
      },
      /**
       *  Causes the object to rotate when it starts playing
       *
       * @param {number} degrees
       * @param {number} duration
       * @param {object} [options] options
       * @returns this
       */
      rotateIn(degrees, duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "rotateIn",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(degrees))
          throw this.sequence._customError(
            this,
            "rotateOut",
            "degrees must be of type number"
          );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "rotateOut",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "rotateIn",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "rotateIn",
            "options.delay must be of type number"
          );
        this._rotateIn = {
          value: degrees,
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      },
      /**
       *  Causes the object to rotate at the end of the effect's duration
       *
       * @param {number} degrees
       * @param {number} duration
       * @param {object} [options] options
       * @returns this
       */
      rotateOut(degrees, duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "rotateOut",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(degrees))
          throw this.sequence._customError(
            this,
            "rotateOut",
            "degrees must be of type number"
          );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "rotateOut",
            "duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "rotateOut",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "rotateOut",
            "options.delay must be of type number"
          );
        this._rotateOut = {
          value: degrees,
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      }
    };
    const scale = {
      _scaleMin: null,
      _scaleMax: null,
      _scaleIn: null,
      _scaleOut: null,
      /**
       *  A method that can take the following:
       *  - A number to set the scale uniformly
       *  - An object with x and y for non-uniform scaling
       *  - Two numbers which the Sequencer will randomly pick a uniform scale between
       *
       * @param {number|object} inScaleMin
       * @param {number} [inScaleMax] inScaleMax
       * @returns this
       */
      scale(inScaleMin, inScaleMax) {
        if (!is_real_number(inScaleMin) && typeof inScaleMin !== "object")
          throw this.sequence._customError(
            this,
            "scale",
            "inScale must be of type number or object"
          );
        if (is_real_number(inScaleMin)) {
          if (inScaleMax && !is_real_number(inScaleMax)) {
            throw this.sequence._customError(
              this,
              "scale",
              "if inScaleMin is a number, inScaleMax must also be of type number"
            );
          }
        }
        this._scaleMin = inScaleMin;
        this._scaleMax = inScaleMax ?? false;
        return this;
      },
      /**
       *  Causes the effect to scale when it starts playing
       *
       * @param {number|object} scale
       * @param {number} duration
       * @param {object} [options] options
       * @returns this
       */
      scaleIn(scale2, duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "scaleIn",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "scaleIn",
            "duration must be of type number"
          );
        if (!is_real_number(scale2) && typeof scale2 !== "object")
          throw this.sequence._customError(
            this,
            "scaleIn",
            "scale must be of type number or object"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "scaleIn",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "scaleIn",
            "options.delay must be of type number"
          );
        this._scaleIn = {
          value: scale2,
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      },
      /**
       *  Causes the effect to scale at the end of the effect's duration
       *
       * @param {number|object} scale
       * @param {number} duration
       * @param {object} [options] options
       * @returns this
       */
      scaleOut(scale2, duration, options = {}) {
        if (typeof options !== "object")
          throw this.sequence._customError(
            this,
            "scaleOut",
            "options must be of type object"
          );
        options = foundry.utils.mergeObject(
          {
            ease: "linear",
            delay: 0
          },
          options
        );
        if (!is_real_number(duration))
          throw this.sequence._customError(
            this,
            "scaleOut",
            "duration must be of type number"
          );
        if (!is_real_number(scale2) && typeof scale2 !== "object")
          throw this.sequence._customError(
            this,
            "scaleOut",
            "scale must be of type number or object"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "scaleOut",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "scaleOut",
            "options.delay must be of type number"
          );
        this._scaleOut = {
          value: scale2,
          duration,
          ease: options.ease,
          delay: options.delay
        };
        return this;
      }
    };
    const time = {
      _hasTime: true,
      _isRange: false,
      _startTime: null,
      _startPerc: null,
      _endTime: null,
      _endPerc: null,
      /**
       * Sets the start and end time of the section, playing only that range
       *
       * @param {number} inMsStart
       * @param {number} inMsEnd
       * @returns this
       */
      timeRange(inMsStart, inMsEnd) {
        if (!is_real_number(inMsStart))
          throw this.sequence._customError(
            this,
            "timeRange",
            "inMsStart must be of type number"
          );
        if (!is_real_number(inMsEnd))
          throw this.sequence._customError(
            this,
            "timeRange",
            "inMsEnd must be of type number"
          );
        this._startTime = inMsStart;
        this._endTime = inMsEnd;
        this._isRange = true;
        return this;
      },
      /**
       * Sets the start time of the section.
       *
       * @param {number} inMs
       * @returns this
       */
      startTime(inMs) {
        if (!is_real_number(inMs))
          throw this.sequence._customError(
            this,
            "startTime",
            "inMs must be of type number"
          );
        this._startTime = inMs;
        this._startPerc = false;
        this._isRange = false;
        return this;
      },
      /**
       * Sets the start time of the section based on a percentage from its total duration.
       *
       * @param {number} inPercentage
       * @returns this
       */
      startTimePerc(inPercentage) {
        if (!is_real_number(inPercentage))
          throw this.sequence._customError(
            this,
            "startTimePerc",
            "inPercentage must be of type number"
          );
        this._startTime = inPercentage;
        this._startPerc = true;
        this._isRange = false;
        return this;
      },
      /**
       * Sets the ending time of the section (from the end).
       *
       * @param {number} inMs
       * @returns this
       */
      endTime(inMs) {
        if (!is_real_number(inMs))
          throw this.sequence._customError(
            this,
            "endTime",
            "inMs must be of type number"
          );
        this._endTime = inMs;
        this._endPerc = false;
        this._isRange = false;
        return this;
      },
      /**
       * Sets the ending time of the section based on a percentage from the total duration.
       *
       * @param {number} inPercentage
       * @returns this
       */
      endTimePerc(inPercentage) {
        if (!is_real_number(inPercentage))
          throw this.sequence._customError(
            this,
            "endTimePerc",
            "inPercentage must be of type number"
          );
        this._endTime = inPercentage;
        this._endPerc = true;
        this._isRange = false;
        return this;
      }
    };
    const users = {
      _users: null,
      _addUser(inUser) {
        if (!this._users) this._users = [];
        if (typeof inUser !== "string")
          throw this.sequence._customError(
            this,
            "_addUser",
            "inUser must be of type string"
          );
        if (!game.users.has(inUser)) {
          if (game.users.getName(inUser)) {
            inUser = game.users.getName(inUser).id;
          } else {
            throw this.sequence._customError(
              this,
              "_addUser",
              `user with id or name "${inUser}" does not exist!`
            );
          }
        }
        if (!this._users.includes(inUser)) this._users.push(inUser);
      },
      _deleteUser(inUser) {
        if (!this._users) this._users = [];
        if (this._users.includes(inUser)) {
          let index = this._users.indexOf(inUser);
          this._users.splice(index, 1);
        }
      },
      /**
       * Causes section to be executed only locally, and not push to other connected clients.
       *
       * @param {boolean} inLocally
       * @returns this
       */
      locally(inLocally = true) {
        if (inLocally) this._addUser(game.userId);
        else this._deleteUser(game.userId);
        return this;
      },
      /**
       * Causes the section to be executed for only a set of users.
       *
       * @param {string|User|array<string|User>} inUsers
       * @returns this
       */
      forUsers(inUsers) {
        if (!Array.isArray(inUsers)) {
          if (typeof inUsers !== "string")
            throw this.sequence._customError(
              this,
              "forUsers",
              "inUser must be of type string"
            );
          inUsers = [inUsers];
        }
        inUsers.forEach((u) => this._addUser(u));
        return this;
      }
    };
    const filter = {
      _filters: null,
      _addFilter(inFilterName, inData, inName = false) {
        if (!this._filters) this._filters = [];
        this._filters.push({
          className: inFilterName,
          name: inName,
          data: inData
        });
      },
      _testFilter(inFilterName, inData) {
        let filter2 = new filters[inFilterName](inData);
        if (!filter2.isValid)
          throw this.sequence._customError(
            this,
            "filter",
            `Could not create ${inFilterName} filter - data is malformed!`
          );
      },
      filter(inFilterName, inData = {}, inName = "") {
        if (typeof inFilterName !== "string")
          throw this.sequence._customError(
            this,
            "filter",
            `inFilterName must be of type string`
          );
        if (!Object.keys(filters).includes(inFilterName))
          throw this.sequence._customError(
            this,
            "filter",
            `"${inFilterName}" does not exist`
          );
        this._testFilter(inFilterName, inData);
        this._addFilter(inFilterName, inData, inName);
        return this;
      }
    };
    const tint = {
      _tint: null,
      /**
       * Tints the target of this section by the color given to the
       *
       * @param {number|string} inColor
       * @returns this
       */
      tint(inColor) {
        if (!is_real_number(inColor) && typeof inColor !== "string")
          throw this.sequence._customError(
            this,
            "tint",
            `inColor must be of type string (hexadecimal) or number (decimal)!`
          );
        this._tint = parseColor(inColor);
        return this;
      }
    };
    const location = {
      /**
       * Base properties
       */
      _source: null,
      _offset: null,
      _randomOffset: null,
      /**
       *  A smart method that can take a reference to an object, or a direct on the canvas to play the effect at,
       *  or a string reference (see .name())
       *
       * @param {Object|String} inLocation
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      atLocation(inLocation, inOptions = {}) {
        if (!inLocation || !(typeof inLocation === "object" || typeof inLocation === "string")) {
          throw this.sequence._customError(
            this,
            "atLocation",
            `inLocation is invalid, and must be of type of object, string, placeable object, or document`
          );
        }
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "atLocation",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            cacheLocation: false,
            offset: false,
            randomOffset: false,
            gridUnits: false,
            local: false
          },
          inOptions
        );
        inLocation = this._validateLocation(inLocation);
        if (inLocation === void 0)
          throw this.sequence._customError(
            this,
            "atLocation",
            "could not find position of given object"
          );
        if (typeof inOptions.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "atLocation",
            "inOptions.cacheLocation must be of type boolean"
          );
        if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
          throw this.sequence._customError(
            this,
            "atLocation",
            "inOptions.randomOffset must be of type boolean or number"
          );
        if (inOptions.offset) {
          const offsetData = this._validateOffset(
            "atLocation",
            inOptions.offset,
            inOptions
          );
          this._offset = {
            source: offsetData,
            target: this._offset?.target ?? false
          };
        }
        this._randomOffset = {
          source: inOptions.randomOffset,
          target: this._randomOffset?.target ?? false
        };
        this._source = inOptions.cacheLocation && typeof inLocation !== "string" ? get_object_canvas_data(inLocation, { uuid: false }) : inLocation;
        return this;
      }
    };
    const offset = {
      _offset: null,
      _randomOffset: null,
      _validateOffset(functionName, inOffset, inOptions = {}) {
        inOffset = foundry.utils.mergeObject(
          {
            x: 0,
            y: 0
          },
          inOffset
        );
        inOptions = foundry.utils.mergeObject(
          {
            gridUnits: false,
            local: false
          },
          inOptions
        );
        if (typeof inOptions.gridUnits !== "boolean")
          throw this.sequence._customError(
            this,
            functionName,
            "inOptions.gridUnits must be of type boolean"
          );
        if (typeof inOptions.local !== "boolean")
          throw this.sequence._customError(
            this,
            functionName,
            "inOptions.local must be of type boolean"
          );
        if (!is_real_number(inOffset.x))
          throw this.sequence._customError(
            this,
            functionName,
            `inOffset.x must be of type number!`
          );
        if (!is_real_number(inOffset.y))
          throw this.sequence._customError(
            this,
            functionName,
            `inOffset.y must be of type number!`
          );
        return {
          ...inOffset,
          ...inOptions
        };
      }
    };
    const text = {
      _text: null,
      /**
       *  Creates a text element, attached to the sprite. The options for the text are available here:
       *  https://pixijs.io/pixi-text-style/
       *
       * @param {String} inText
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      text(inText, inOptions = {}) {
        if (typeof inText !== "string")
          throw this.sequence._customError(
            this,
            "text",
            "inText must be of type string"
          );
        this._text = foundry.utils.mergeObject(
          {
            text: inText
          },
          inOptions
        );
        return this;
      }
    };
    const name = {
      _name: null,
      _origin: null,
      /**
       * Causes the effect or sound to be named, which affects them differently. In the case of effects, names can be used
       * in the place of 
       *
       * @param {String} inName
       * @returns {EffectSection}
       */
      name(inName) {
        if (typeof inName !== "string")
          throw this.sequence._customError(
            this,
            "name",
            "inName must be of type string"
          );
        this._name = safe_str(inName);
        return this;
      },
      /**
       *  This is for adding extra information to an sound, like the origin of the sound in the form of the item's uuid.
       *  The method accepts a string or a Document that has an UUID.
       *
       * @param {string|document} inOrigin
       * @returns {Section}
       */
      origin(inOrigin) {
        inOrigin = validate_document(inOrigin);
        if (inOrigin instanceof foundry.abstract.Document) {
          inOrigin = inOrigin?.uuid;
          if (!inOrigin)
            throw this.sequence._customError(
              this,
              "origin",
              "could not find the UUID for the given Document"
            );
        }
        if (typeof inOrigin !== "string")
          throw this.sequence._customError(
            this,
            "origin",
            "inOrigin must be of type string"
          );
        this._origin = inOrigin;
        return this;
      }
    };
    const traits = {
      animation,
      audio,
      files,
      moves,
      opacity,
      rotation,
      scale,
      time,
      users,
      filter,
      tint,
      location,
      offset,
      text,
      name
    };
    class CrosshairsDocument extends MeasuredTemplateDocument {
      constructor(config = {}, context = {}, crosshair = {}, callbacks = {}) {
        if (config.t === CONST.MEASURED_TEMPLATE_TYPES.RECTANGLE && !(config.direction % 90)) {
          config.direction = 45;
        }
        super(config, context);
        this.crosshair = foundry.utils.mergeObject(CrosshairsDocument.defaultConfig, crosshair);
        this.callbacks = callbacks;
        this.originalConfig = foundry.utils.deepClone(config);
      }
      crosshair = {};
      #layer = null;
      cachedPosition = null;
      originalConfig = {};
      static get placeableClass() {
        return CrosshairsPlaceable;
      }
      static get defaultConfig() {
        return {
          borderAlpha: 0.75,
          fillAlpha: 0.25,
          textureAlpha: 0.5,
          textureScale: 1,
          gridHighlight: true,
          icon: {
            texture: "",
            borderVisible: false
          },
          snap: {
            position: CONST.GRID_SNAPPING_MODES.CENTER,
            size: CONST.GRID_SNAPPING_MODES.CENTER,
            resolution: 1,
            direction: 0
          },
          lockDrag: true,
          distanceMin: null,
          distanceMax: null,
          label: {
            text: "",
            dx: 0,
            dy: 0
          },
          location: {
            obj: null,
            limitMinRange: null,
            limitMaxRange: null,
            showRange: false,
            displayRangePoly: false,
            rangePolyFillColor: null,
            rangePolyLineColor: null,
            rangePolyFillAlpha: null,
            rangePolyLineAlpha: null,
            lockToEdge: false,
            lockToEdgeDirection: false,
            offset: { x: 0, y: 0 },
            wallBehavior: CONSTANTS.PLACEMENT_RESTRICTIONS.ANYWHERE
          },
          lockManualRotation: false
        };
      }
      getOrientation() {
        this.cachedPosition = !this.object || this.object?.destroyed ? this.cachedPosition : {
          source: get_object_canvas_data(this.object, { uuid: false }),
          target: this.t === CONST.MEASURED_TEMPLATE_TYPES.CONE || this.t === CONST.MEASURED_TEMPLATE_TYPES.RAY ? get_object_canvas_data(this.object, { measure: true, uuid: false }) : null
        };
        return this.cachedPosition;
      }
      get documentName() {
        return "CrosshairsDocument";
      }
      get layer() {
        if (this.#layer) return this.#layer;
        const create = (doc) => new this.constructor.placeableClass(doc);
        const sink = {
          get(target, prop) {
            switch (prop) {
              case "createObject":
                return create;
              default:
                return target[prop];
            }
          }
        };
        this.#layer = new Proxy(canvas.activeLayer, sink);
        return this.#layer;
      }
      get isEmbedded() {
        return !!this.parent;
      }
      getCrosshairShape() {
        const { t, distance, direction, angle, width: width2 } = this;
        switch (t) {
          case "circle":
            return FoundryShim.MeasuredTemplate.getCircleShape(distance);
          case "cone":
            return FoundryShim.MeasuredTemplate.getConeShape(distance, direction, angle);
          case "rect":
            return FoundryShim.MeasuredTemplate.getRectShape(distance, direction);
          case "ray":
            return FoundryShim.MeasuredTemplate.getRayShape(distance, direction, width2);
        }
      }
      token = {};
      prepareDerivedData() {
        super.prepareDerivedData();
        const gridUnits = this.distance / this.parent.grid.distance;
        this.radius = gridUnits * this.parent.grid.size;
        this.token = {};
        this.token.width = gridUnits * 2;
        this.token.height = gridUnits * 2;
        switch (this.t) {
          case "rect":
            this.token.x = this.x;
            this.token.y = this.y;
            break;
          case "circle":
          default:
            this.token.x = this.x - this.radius;
            this.token.y = this.y - this.radius;
        }
      }
      show() {
        this._destroyed = false;
        this.#layer = null;
        return this.object.show();
      }
    }
    class EffectSection extends Section {
      constructor(inSequence, inFile = "") {
        super(inSequence);
        this._deserializedData = null;
        this._file = inFile;
        this._text = null;
        this._source = null;
        this._stretchTo = null;
        this._attachTo = null;
        this._copySprite = null;
        this._anchor = null;
        this._spriteAnchor = null;
        this._randomOffset = null;
        this._missed = null;
        this._private = null;
        this._randomMirrorX = null;
        this._randomMirrorY = null;
        this._mirrorX = null;
        this._mirrorY = null;
        this._playbackRate = null;
        this._template = null;
        this._overrides = [];
        this._zIndex = null;
        this._offset = null;
        this._spriteOffset = null;
        this._size = null;
        this._syncGroup = null;
        this._persist = null;
        this._persistOptions = null;
        this._zeroSpriteRotation = null;
        this._extraEndDuration = null;
        this._loopOptions = null;
        this._tilingTexture = null;
        this._snapToGrid = null;
        this._scaleToObject = null;
        this._screenSpace = null;
        this._screenSpaceAboveUI = null;
        this._screenSpaceAnchor = null;
        this._screenSpacePosition = null;
        this._screenSpaceScale = null;
        this._elevation = null;
        this._sortLayer = 800;
        this._masks = [];
        this._tiedDocuments = [];
        this._selfMask = false;
        this._temporaryEffect = false;
        this._spriteRotation = 0;
        this._randomSpriteRotation = false;
        this._isRangedEffect = null;
        this._offsetLegacy = null;
        this._randomOffsetLegacy = null;
        this._aboveLighting = null;
        this._aboveInterface = null;
        this._spriteScaleMin = 1;
        this._spriteScaleMax = null;
        this._isometric = null;
        this._shapes = [];
        this._xray = null;
        this._playEffect = true;
      }
      static niceName = "Effect";
      /**
       * @private
       */
      get _target() {
        return this._stretchTo || this._rotateTowards || this._moveTowards || false;
      }
      static debounceWarning() {
        custom_warning(
          "Sequencer",
          "Effect | This user does not have permissions to play effects. This can be configured in Sequencer's module settings."
        );
      }
      /**
       * Causes the effect to persist indefinitely on the canvas until _ended via SequencerEffectManager.endAllEffects() or
       * name the effect with .name() and then end it through SequencerEffectManager.endEffect()
       *
       * @param {Boolean} [inBool=true] inBool
       * @param {Object} [inOptions={}] inOptions
       * @returns {EffectSection}
       */
      persist(inBool = true, inOptions = {}) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "persist",
            "inBool must be of type boolean"
          );
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "persist",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            id: foundry.utils.randomID(),
            persistTokenPrototype: false
          },
          inOptions
        );
        if (typeof inOptions.persistTokenPrototype !== "boolean")
          throw this.sequence._customError(
            this,
            "persist",
            "inOptions.persistTokenPrototype must be of type boolean"
          );
        this._persist = inBool;
        this._persistOptions = inOptions;
        return this;
      }
      syncGroup(inString) {
        if (typeof inString !== "string")
          throw this.sequence._customError(
            this,
            "syncGroup",
            "inString must be of type string"
          );
        this._syncGroup = inString;
        return this;
      }
      /**
       * Causes the effect to become temporary, which means it will not be stored in the flags of any object,
       * even if it .persist() is called
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      temporary(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "temporary",
            "inBool must be of type boolean"
          );
        this._temporaryEffect = inBool || this._temporaryEffect;
        return this;
      }
      /**
       * Sets the effect's playback rate. A playback rate of 2.0 would make it play 2x as fast, 0.5 would make
       * it play half as fast.
       *
       * @param {Number} inNumber
       * @returns {EffectSection}
       */
      playbackRate(inNumber = 1) {
        if (!is_real_number(inNumber))
          throw this.sequence._customError(
            this,
            "playbackRate",
            "inNumber must be of type number"
          );
        this._playbackRate = inNumber;
        return this;
      }
      /**
       * Causes the effect to target a location close to the .stretchTowards() location, but not on it.
       *
       * @param {Boolean} [inBool=true] inBool
       * @returns {EffectSection}
       */
      missed(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "missed",
            "inBool must be of type boolean"
          );
        this._missed = inBool;
        return this;
      }
      /**
       * Adds a function that will run at the end of the effect serialization step, but before it is played. Allows direct
       * modifications of effect's data. For example, it could be manipulated to change which file will be used based
       * on the distance to the target.
       *
       * @param {Function} inFunc
       * @returns {EffectSection}
       */
      addOverride(inFunc) {
        if (!is_function$1(inFunc))
          throw this.sequence._customError(
            this,
            "addOverride",
            "The given function needs to be an actual function."
          );
        this._overrides.push(inFunc);
        return this;
      }
      /**
       *  A smart method that can take a reference to an object, or a direct on the canvas to attach an effect to,
       *  or a string reference (see .name())
       *
       * @param {Object|String} inObject
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      attachTo(inObject, inOptions = {}) {
        if (!inObject || !(typeof inObject === "object" || typeof inObject === "string")) {
          throw this.sequence._customError(
            this,
            "attachTo",
            `inObject is invalid, and must be of type of object, string, placeable object, or document`
          );
        }
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "attachTo",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            align: "center",
            edge: "on",
            bindVisibility: true,
            bindAlpha: true,
            bindElevation: true,
            bindScale: true,
            bindRotation: true,
            offset: false,
            randomOffset: false,
            gridUnits: false,
            local: false
          },
          inOptions
        );
        const validatedObject = this._validateLocation(inObject);
        if (validatedObject === void 0)
          throw this.sequence._customError(
            this,
            "attachTo",
            "could not find given object"
          );
        const aligns = Object.keys(alignments);
        if (typeof inOptions.align !== "string" || !aligns.includes(inOptions.align)) {
          throw this.sequence._customError(
            this,
            "attachTo",
            `inOptions.align must be of type string, one of: ${aligns.join(", ")}`
          );
        }
        if (typeof inOptions.edge !== "string" || !(inOptions.edge === "on" || inOptions.edge === "inner" || inOptions.edge === "outer")) {
          throw this.sequence._customError(
            this,
            "attachTo",
            `inOptions.edge must of type string with the value of either "on", "inner", or "outer"`
          );
        }
        if (typeof inOptions.bindVisibility !== "boolean")
          throw this.sequence._customError(
            this,
            "attachTo",
            `inOptions.bindVisibility must be of type boolean`
          );
        if (inOptions.followRotation !== void 0) {
          inOptions.bindRotation = inOptions.followRotation;
          this.sequence._showWarning(
            this,
            "attachTo",
            "inOptions.followRotation is deprecated, please use inOptions.bindRotation instead",
            true
          );
        }
        if (typeof inOptions.bindRotation !== "boolean")
          throw this.sequence._customError(
            this,
            "attachTo",
            `inOptions.bindRotation must be of type boolean`
          );
        if (typeof inOptions.bindAlpha !== "boolean")
          throw this.sequence._customError(
            this,
            "attachTo",
            "inOptions.bindAlpha must be of type boolean"
          );
        if (typeof inOptions.bindElevation !== "boolean")
          throw this.sequence._customError(
            this,
            "attachTo",
            "inOptions.bindElevation must be of type boolean"
          );
        if (typeof inOptions.bindScale !== "boolean")
          throw this.sequence._customError(
            this,
            "attachTo",
            "inOptions.bindScale must be of type boolean"
          );
        if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
          throw this.sequence._customError(
            this,
            "attachTo",
            "inOptions.randomOffset must be of type boolean or number"
          );
        this._source = validatedObject;
        if (inOptions.offset) {
          const offsetData = this._validateOffset(
            "attachTo",
            inOptions.offset,
            inOptions
          );
          this._offset = {
            source: offsetData,
            target: this._offset?.target ?? false
          };
        }
        this._randomOffset = {
          source: inOptions.randomOffset,
          target: this._randomOffset?.target ?? false
        };
        this._attachTo = {
          active: !!validatedObject,
          align: inOptions.align,
          edge: inOptions.edge,
          bindVisibility: inOptions.bindVisibility,
          bindAlpha: inOptions.bindAlpha,
          bindScale: inOptions.bindScale,
          bindElevation: inOptions.bindElevation,
          bindRotation: inOptions.bindRotation
        };
        return this;
      }
      /**
       *  Causes the effect to be rotated and stretched towards an object, or a direct on the canvas to play the effect at, or a string reference (see .name())
       *  This effectively calculates the proper X scale for the effect to reach the target
       *
       * @param {Object|String} inLocation
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      stretchTo(inLocation, inOptions = {}) {
        if (!inLocation || !(typeof inLocation === "object" || typeof inLocation === "string")) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            `inLocation is invalid, and must be of type of object, string, placeable object, or document`
          );
        }
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "stretchTo",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            cacheLocation: false,
            attachTo: false,
            onlyX: false,
            tiling: false,
            offset: false,
            randomOffset: false,
            gridUnits: false,
            local: false,
            requiresLineOfSight: false,
            hideLineOfSight: false
          },
          inOptions
        );
        const validatedObject = this._validateLocation(inLocation);
        if (validatedObject === void 0)
          throw this.sequence._customError(
            this,
            "stretchTo",
            "could not find position of given object"
          );
        if (typeof inOptions.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "stretchTo",
            "inOptions.cacheLocation must be of type boolean"
          );
        if (typeof inOptions.attachTo !== "boolean")
          throw this.sequence._customError(
            this,
            "stretchTo",
            "inOptions.attachTo must be of type boolean"
          );
        if (typeof inOptions.onlyX !== "boolean")
          throw this.sequence._customError(
            this,
            "stretchTo",
            "inOptions.onlyX must be of type boolean"
          );
        if (typeof inOptions.tiling !== "boolean")
          throw this.sequence._customError(
            this,
            "stretchTo",
            "inOptions.tiling must be of type boolean"
          );
        if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
          throw this.sequence._customError(
            this,
            "stretchTo",
            "inOptions.randomOffset must be of type boolean or number"
          );
        if (inOptions.cacheLocation && inOptions.attachTo) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "cacheLocation and attachTo cannot both be true - pick one or the other"
          );
        }
        if (typeof inOptions.requiresLineOfSight !== "boolean") {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "requiresLineOfSight must be of type boolean"
          );
        }
        if (!inOptions.attachTo && inOptions.requiresLineOfSight) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "requiresLineOfSight requires that attachTo is true"
          );
        }
        if (typeof inOptions.hideLineOfSight !== "boolean") {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "hideLineOfSight must be of type boolean"
          );
        }
        if (!inOptions.requiresLineOfSight && inOptions.hideLineOfSight) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "hideLineOfSight requires that requiresLineOfSight is true"
          );
        }
        if (inOptions.tiling) this.tilingTexture();
        if (inOptions.offset) {
          const offsetData = this._validateOffset(
            "stretchTo",
            inOptions.offset,
            inOptions
          );
          this._offset = {
            source: this._offset?.source ?? false,
            target: offsetData
          };
        }
        this._randomOffset = {
          source: this._randomOffset?.source ?? false,
          target: inOptions.randomOffset
        };
        this._stretchTo = {
          target: inOptions.cacheLocation ? get_object_canvas_data(validatedObject, { measure: true, uuid: false }) : validatedObject,
          attachTo: inOptions.attachTo,
          onlyX: inOptions.onlyX,
          requiresLineOfSight: inOptions.requiresLineOfSight,
          hideLineOfSight: inOptions.hideLineOfSight
        };
        return this;
      }
      /**
       * Sets the location to rotate the object to
       *
       * @param {object|string} inLocation
       * @param {object} inOptions
       * @returns this
       */
      rotateTowards(inLocation, inOptions = {}) {
        if (!inLocation || !(typeof inLocation === "object" || typeof inLocation === "string")) {
          throw this.sequence._customError(
            this,
            "inLocation",
            `inLocation is invalid, and must be of type of object, string, placeable object, or document`
          );
        }
        inOptions = foundry.utils.mergeObject(
          {
            rotationOffset: 0,
            cacheLocation: false,
            attachTo: false,
            offset: false,
            randomOffset: false,
            local: false,
            gridUnits: false,
            template: false
          },
          inOptions
        );
        if (!is_real_number(inOptions.rotationOffset))
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "inOptions.rotationOffset must be of type number"
          );
        if (typeof inOptions.attachTo !== "boolean")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "inOptions.attachTo must be of type boolean"
          );
        if (typeof inOptions.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "inOptions.cacheLocation must be of type boolean"
          );
        const validatedObject = this._validateLocation(inLocation);
        if (!validatedObject)
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "could not find position of given object"
          );
        if (inOptions.offset) {
          const offsetData = this._validateOffset(
            "attachTo",
            inOptions.offset,
            inOptions
          );
          this._offset = {
            target: offsetData ?? this._offset?.target ?? false
          };
        }
        if (typeof inOptions.template !== "boolean")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "inOptions.template must be of type boolean"
          );
        this._randomOffset = {
          target: inOptions.randomOffset ?? this._randomOffset?.target ?? false
        };
        this._rotateTowards = {
          target: inOptions.cacheLocation ? get_object_canvas_data(validatedObject, { measure: true, uuid: false }) : validatedObject,
          rotationOffset: inOptions.rotationOffset,
          cacheLocation: inOptions.cacheLocation,
          attachTo: inOptions.attachTo,
          template: inOptions.template
        };
        return this;
      }
      /**
       *  Create an effect based on the given object, effectively copying the object as an effect. Useful when you want to do some effect magic on tokens or tiles.
       *  @deprecated
       */
      from(...args) {
        this.sequence._showWarning(
          this,
          "from",
          ".from() is deprecated, please use .copySprite() instead",
          true
        );
        return this.copySprite(...args);
      }
      /**
       *  Create an effect based on the given object, effectively copying the object as an effect. Useful when you want to do some effect magic on tokens or tiles.
       *
       * @param {Object} inObject
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      copySprite(inObject, inOptions = {}) {
        if (!(inObject instanceof FoundryShim.Token || inObject instanceof FoundryShim.Tile || inObject instanceof TokenDocument || inObject instanceof TileDocument)) {
          throw this.sequence._customError(
            this,
            "copySprite",
            "inObject must be of type Token, Tile, TokenDocument, or TileDocument"
          );
        }
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "copySprite",
            `inOptions must be of type object`
          );
        inObject = inObject.document ?? inObject;
        if (!inObject?.texture?.src)
          throw this.sequence._customError(
            this,
            "copySprite",
            "could not find the image for the given object"
          );
        inOptions = foundry.utils.mergeObject(
          {
            cacheLocation: false,
            offset: false,
            randomOffset: false,
            local: false,
            gridUnits: false
          },
          inOptions
        );
        if (typeof inOptions.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "copySprite",
            "inOptions.cacheLocation must be of type boolean"
          );
        if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
          throw this.sequence._customError(
            this,
            "copySprite",
            "inOptions.randomOffset must be of type boolean or number"
          );
        if (inOptions.offset) {
          const offsetData = this._validateOffset(
            "attachTo",
            inOptions.offset,
            inOptions
          );
          this._offset = {
            source: offsetData,
            target: this._offset?.target ?? false
          };
        }
        this._randomOffset = {
          source: inOptions.randomOffset,
          target: this._randomOffset?.target ?? false
        };
        this._copySprite = {
          object: inObject,
          options: inOptions
        };
        return this;
      }
      shape(inType, inOptions = {}) {
        if (typeof inType !== "string")
          throw this.sequence._customError(
            this,
            "shape",
            "type must be of type string"
          );
        if (!Object.values(CONSTANTS.SHAPES).includes(inType)) {
          throw this.sequence._customError(
            this,
            "shape",
            "type must be one of: " + Object.values(CONSTANTS.SHAPES).join(", ")
          );
        }
        if (inType === CONSTANTS.SHAPES.POLY) {
          if (!Array.isArray(inOptions.points)) {
            throw this.sequence._customError(
              this,
              "shape",
              "if creating polygon, inOptions.points must be of type array"
            );
          }
          inOptions.points = inOptions.points.map((point) => {
            if (Array.isArray(point)) {
              if (!is_real_number(point[0]) || !is_real_number(point[1])) {
                throw this.sequence._customError(
                  this,
                  "shape",
                  "inOptions.points must be an array, containing an array of two numbers or objects with x and y number properties"
                );
              }
              return point;
            }
            if (typeof point === "object") {
              if (!is_real_number(point?.x) || !is_real_number(point?.y)) {
                throw this.sequence._customError(
                  this,
                  "shape",
                  "inOptions.points must be an array, containing an array of two numbers or objects with x and y number properties"
                );
              }
              return [point.x, point.y];
            }
          });
        } else if (inType === CONSTANTS.SHAPES.CIRC) {
          if (typeof inOptions.radius !== "number") {
            throw this.sequence._customError(
              this,
              "shape",
              "if creating circle, inOptions.radius must be of type number"
            );
          }
        } else if (inType === CONSTANTS.SHAPES.RECT || inType === CONSTANTS.SHAPES.RREC || inType === CONSTANTS.SHAPES.ELIP) {
          if (inOptions.width ^ inOptions.height) {
            inOptions.width = inOptions.width ?? inOptions.height;
            inOptions.height = inOptions.height ?? inOptions.width;
          }
          if (typeof inOptions.width !== "number") {
            throw this.sequence._customError(
              this,
              "shape",
              `if creating rectangle, rounded rectangle, or an ellipse, inOptions.width must be of type number`
            );
          }
          if (typeof inOptions.height !== "number") {
            throw this.sequence._customError(
              this,
              "shape",
              "if creating rectangle, rounded rectangle, or an ellipse, inOptions.height must be of type number"
            );
          }
          if (inType === CONSTANTS.SHAPES.RREC && typeof inOptions.radius !== "number") {
            throw this.sequence._customError(
              this,
              "shape",
              "if creating rounded border rectangle, inOptions.radius must be of type number"
            );
          }
        }
        if (inOptions.gridUnits !== void 0 && typeof inOptions.gridUnits !== "boolean") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.gridUnits must be of type boolean"
          );
        }
        if (inOptions.name && typeof inOptions.name !== "string") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.name must be of type string"
          );
        }
        if (inOptions.fillColor && !is_real_number(inOptions.fillColor) && typeof inOptions.fillColor !== "string") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.fillColor must be of type string (hexadecimal) or number (decimal)"
          );
        } else {
          inOptions.fillColor = parseColor(inOptions.fillColor).decimal;
        }
        if (inOptions.fillAlpha && !is_real_number(inOptions.fillAlpha)) {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.fillAlpha must be of type number"
          );
        }
        if (inOptions.alpha && !is_real_number(inOptions.alpha)) {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.alpha must be of type number"
          );
        }
        if (inOptions.lineSize && !is_real_number(inOptions.lineSize)) {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.lineSize must be of type number"
          );
        }
        if (inOptions.lineColor && !is_real_number(inOptions.lineColor) && typeof inOptions.lineColor !== "string") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.lineColor must be of type string (hexadecimal) or number (decimal)"
          );
        } else {
          inOptions.lineColor = parseColor(inOptions.lineColor).decimal;
        }
        if (inOptions.offset) {
          inOptions.offset = this._validateOffset(
            "shape",
            inOptions.offset,
            inOptions.offset
          );
        }
        if (inOptions.texture !== void 0 && typeof inOptions.texture !== "string") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.texture must be of type string"
          );
        }
        if (inOptions.isMask !== void 0 && typeof inOptions.isMask !== "boolean") {
          throw this.sequence._customError(
            this,
            "shape",
            "inOptions.isMask must be of type boolean"
          );
        }
        this._shapes.push({
          ...inOptions,
          type: inType
        });
        return this;
      }
      /**
       *  Causes the effect's sprite to be offset relative to its location based on a given vector
       *
       * @param {Object} inOffset
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      spriteOffset(inOffset, inOptions = {}) {
        if (inOffset === void 0)
          throw this.sequence._customError(
            this,
            "spriteOffset",
            "inOffset must not be undefined"
          );
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "spriteOffset",
            "options must be of type object"
          );
        this._spriteOffset = this._validateOffset(
          "spriteOffset",
          inOffset,
          inOptions
        );
        return this;
      }
      /**
       * Causes the final effect location to be snapped to the grid
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      snapToGrid(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "snapToGrid",
            "inBool must be of type boolean"
          );
        this._snapToGrid = inBool;
        return this;
      }
      /**
       * Causes the effect to be scaled to the target object's width
       *
       * @param {Number} inScale
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      scaleToObject(inScale = 1, inOptions = {}) {
        if (!is_real_number(inScale))
          throw this.sequence._customError(
            this,
            "scaleToObject",
            `inScale must be of type number!`
          );
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "scaleToObject",
            "inOptions must be of type object"
          );
        inOptions = foundry.utils.mergeObject(
          {
            scale: inScale,
            considerTokenScale: false,
            uniform: false
          },
          inOptions
        );
        if (typeof inOptions.considerTokenScale !== "boolean")
          throw this.sequence._customError(
            this,
            "scaleToObject",
            "inOptions.considerTokenScale must be of type boolean"
          );
        if (typeof inOptions.uniform !== "boolean")
          throw this.sequence._customError(
            this,
            "scaleToObject",
            "inOptions.uniform must be of type boolean"
          );
        this._scaleToObject = inOptions;
        return this;
      }
      /**
       * Sets the width and the height of the effect in pixels, this size is set before any scaling
       *
       * @param {Number|Object<{width: {Number}, height: {Number}}>} inSize
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      size(inSize, inOptions = {}) {
        if (!is_real_number(inSize) && typeof inSize !== "object")
          throw this.sequence._customError(
            this,
            "size",
            "inSize must be of type number or object"
          );
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "size",
            "inOptions must be of type object"
          );
        if (is_real_number(inSize)) {
          inSize = {
            width: inSize,
            height: inSize
          };
        }
        if (inSize.width === void 0 ^ inSize.height === void 0) {
          if (inSize.width) {
            if (!is_real_number(inSize.width))
              throw this.sequence._customError(
                this,
                "size",
                "inSize.width must be of type number or string 'auto'"
              );
            inSize["height"] = "auto";
          } else {
            if (!is_real_number(inSize.height))
              throw this.sequence._customError(
                this,
                "size",
                "inSize.height must be of type number or string 'auto'"
              );
            inSize["width"] = "auto";
          }
        }
        inOptions = foundry.utils.mergeObject(
          {
            gridUnits: false
          },
          inOptions
        );
        if (!is_real_number(inSize.width) && inSize.width !== "auto")
          throw this.sequence._customError(
            this,
            "size",
            "inSize.width must be of type number or string 'auto'"
          );
        if (!is_real_number(inSize.height) && inSize.height !== "auto")
          throw this.sequence._customError(
            this,
            "size",
            "inSize.height must be of type number or string 'auto'"
          );
        if (typeof inOptions.gridUnits !== "boolean")
          throw this.sequence._customError(
            this,
            "size",
            "inOptions.gridUnits must be of type boolean"
          );
        this._size = {
          width: inSize.width ?? canvas.grid.size,
          height: inSize.height ?? canvas.grid.size,
          ...inOptions
        };
        return this;
      }
      /**
       *  This scales the sprite of the effect, and this method can take the following:
       *  - A number to set the scale uniformly
       *  - An object with x and y for non-uniform scaling
       *  - Two numbers which the Sequencer will randomly pick a uniform scale between
       *
       * @param {number|object} inScaleMin
       * @param {number} [inScaleMax] inScaleMax
       * @returns this
       */
      spriteScale(inScaleMin, inScaleMax) {
        if (!is_real_number(inScaleMin) && typeof inScaleMin !== "object")
          throw this.sequence._customError(
            this,
            "spriteScale",
            "inScale must be of type number or object"
          );
        if (is_real_number(inScaleMin)) {
          if (inScaleMax && !is_real_number(inScaleMax)) {
            throw this.sequence._customError(
              this,
              "spriteScale",
              "if inScaleMin is a number, inScaleMax must also be of type number"
            );
          }
        }
        this._spriteScaleMin = inScaleMin;
        this._spriteScaleMax = inScaleMax ?? false;
        return this;
      }
      /**
       * This defines the internal padding of this effect. Gridsize determines the internal grid size of this effect which will determine how big it is on the canvas
       * relative to the canvas's grid size. Start and end point defines padding at the left and right of the effect
       *
       * @param {Number} gridSize
       * @param {Number} startPoint
       * @param {Number} endPoint
       * @returns {EffectSection}
       */
      template({ gridSize, startPoint, endPoint } = {}) {
        if (gridSize && !is_real_number(gridSize))
          throw this.sequence._customError(
            this,
            "template",
            "gridSize must be of type number"
          );
        if (startPoint && !is_real_number(startPoint))
          throw this.sequence._customError(
            this,
            "template",
            "startPoint must be of type number"
          );
        if (endPoint && !is_real_number(endPoint))
          throw this.sequence._customError(
            this,
            "template",
            "endPoint must be of type number"
          );
        if (!gridSize && !startPoint && !endPoint)
          throw this.sequence._customError(
            this,
            "template",
            "You need to define at least one parameter!"
          );
        if (!this._template) this._template = {};
        if (gridSize) this._template["gridSize"] = gridSize;
        if (startPoint) this._template["startPoint"] = startPoint;
        if (endPoint) this._template["endPoint"] = endPoint;
        return this;
      }
      /**
       * This makes the texture of the effect tile, effectively repeat itself within the sprite's dimensions
       *
       * @param {Object|Number} scale
       * @param {Object} position
       * @returns {EffectSection}
       */
      tilingTexture(scale2 = { x: 1, y: 1 }, position = { x: 0, y: 0 }) {
        if (is_real_number(scale2)) {
          scale2 = { x: scale2, y: scale2 };
        }
        scale2 = { x: scale2?.x ?? 1, y: scale2?.y ?? 1 };
        if (!is_real_number(scale2.x))
          throw this.sequence._customError(
            this,
            "tilingTexture",
            `scale.x must be of type number!`
          );
        if (!is_real_number(scale2.y))
          throw this.sequence._customError(
            this,
            "tilingTexture",
            `scale.y must be of type number!`
          );
        position = { x: position?.x ?? 0, y: position?.y ?? 0 };
        if (!is_real_number(position.x))
          throw this.sequence._customError(
            this,
            "tilingTexture",
            `position.x must be of type number!`
          );
        if (!is_real_number(position.y))
          throw this.sequence._customError(
            this,
            "tilingTexture",
            `position.y must be of type number!`
          );
        this._tilingTexture = {
          scale: scale2,
          position
        };
        return this;
      }
      /**
       *  Anchors the sprite's container according to the given x and y coordinates, or uniformly based on a single number
       *
       * @param {Number|Object} inAnchor
       * @returns {EffectSection}
       */
      anchor(inAnchor) {
        if (is_real_number(inAnchor)) {
          inAnchor = {
            x: inAnchor,
            y: inAnchor
          };
        }
        inAnchor = {
          x: inAnchor?.x ?? 0.5,
          y: inAnchor?.y ?? 0.5
        };
        if (!is_real_number(inAnchor.x))
          throw this.sequence._customError(
            this,
            "anchor",
            `inAnchor.x must be of type number!`
          );
        if (!is_real_number(inAnchor.y))
          throw this.sequence._customError(
            this,
            "anchor",
            `inAnchor.y must be of type number!`
          );
        this._anchor = inAnchor;
        return this;
      }
      /**
       *  Anchors the sprite according to the given x and y coordinates, or uniformly based on a single number
       *
       * @param {Number|Object} inAnchor
       * @returns {EffectSection}
       */
      spriteAnchor(inAnchor) {
        if (is_real_number(inAnchor)) {
          inAnchor = {
            x: inAnchor,
            y: inAnchor
          };
        }
        inAnchor = {
          x: inAnchor?.x ?? 0.5,
          y: inAnchor?.y ?? 0.5
        };
        if (!is_real_number(inAnchor.x))
          throw this.sequence._customError(
            this,
            "anchor",
            `inAnchor.x must be of type number!`
          );
        if (!is_real_number(inAnchor.y))
          throw this.sequence._customError(
            this,
            "anchor",
            `inAnchor.y must be of type number!`
          );
        this._spriteAnchor = inAnchor;
        return this;
      }
      /**
       *  Centers the sprite, effectively giving it an anchor of {x: 0.5, y: 0.5}
       *
       *  Note: If this is used, it will override the anchor set by Aim Towards, which sets the sprite's anchor to the
       *  outermost edge of the location the sprite is played at
       *
       * @returns {EffectSection}
       */
      center() {
        this.anchor(0.5);
        return this;
      }
      /**
       * The sprite gets a randomized flipped X scale. If the scale on that axis was 1, it can
       * become 1 or -1, effectively mirroring the sprite on its horizontal axis
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      randomizeMirrorX(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "randomizeMirrorX",
            "inBool must be of type boolean"
          );
        this._randomMirrorX = inBool;
        return this;
      }
      /**
       * The sprite gets a randomized flipped Y scale. If the scale on that axis was 1, it can
       * become 1 or -1, effectively mirroring the sprite on its vertical axis
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      randomizeMirrorY(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "randomizeMirrorY",
            "inBool must be of type boolean"
          );
        this._randomMirrorY = inBool;
        return this;
      }
      /**
       * The sprite gets a flipped X scale. If the scale on that axis was 1, it will become 1 or -1, effectively
       * mirroring the sprite on its horizontal axis
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      mirrorX(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "mirrorX",
            "inBool must be of type boolean"
          );
        this._mirrorX = inBool;
        return this;
      }
      /**
       * The sprite gets a flipped Y scale. If the scale on that axis was 1, it will become 1 or -1, effectively
       * mirroring the sprite on its vertical axis
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      mirrorY(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "mirrorY",
            "inBool must be of type boolean"
          );
        this._mirrorY = inBool;
        return this;
      }
      /**
       * Causes the effect to play beneath most tokens
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      belowTokens(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "belowTokens",
            "inBool must be of type boolean"
          );
        if (game.release.generation >= 12) {
          return this.sortLayer(inBool ? 600 : 800);
        } else {
          if (!inBool) return this;
          return this.elevation(0, { absolute: true });
        }
      }
      /**
       * Causes the effect to play beneath most tiles
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      belowTiles(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "belowTokens",
            "inBool must be of type boolean"
          );
        if (game.release.generation >= 12) {
          return this.sortLayer(inBool ? 300 : 500);
        } else {
          if (!inBool) return this;
          return this.elevation(-1, { absolute: true });
        }
      }
      /**
       * Causes the effect to be played on top of the vision mask
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      aboveLighting(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "aboveLighting",
            "inBool must be of type boolean"
          );
        this._aboveLighting = inBool;
        if (game.release.generation >= 12) {
          return this.sortLayer(inBool ? 1200 : 800);
        } else {
          if (!inBool) return this;
        }
        return this;
      }
      /**
       * Causes the effect to be played on top of interface
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      aboveInterface(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "aboveInterface",
            "inBool must be of type boolean"
          );
        this._aboveInterface = inBool;
        return this;
      }
      /**
       * Changes the effect's elevation
       *
       * @param {Number} inElevation
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      elevation(inElevation, inOptions = {}) {
        if (typeof inElevation !== "number")
          throw this.sequence._customError(
            this,
            "elevation",
            "inElevation must be of type number"
          );
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "elevation",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            elevation: 1,
            absolute: false
          },
          inOptions
        );
        if (typeof inOptions.absolute !== "boolean")
          throw this.sequence._customError(
            this,
            "elevation",
            "inOptions.absolute must be of type boolean"
          );
        this._elevation = {
          elevation: inElevation,
          absolute: inOptions.absolute
        };
        return this;
      }
      /**
       * Changes the effect's sortLayer, potentially displaying effects below tiles, above tokens or even weather effects
       * in case of identical elevations
       *
       * @param {Number} inSortLayer
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      sortLayer(inSortLayer, inOptions = {}) {
        if (!is_real_number(inSortLayer))
          throw this.sequence._customError(
            this,
            "sortLayer",
            "inSortLayer must be of type number"
          );
        this._sortLayer = inSortLayer;
        return this;
      }
      /**
       * Sets the zIndex of the effect, potentially displaying it on top of other effects the same elevation and sort
       *
       * @param {Number} inZIndex
       * @returns {EffectSection}
       */
      zIndex(inZIndex) {
        if (!is_real_number(inZIndex))
          throw this.sequence._customError(
            this,
            "zIndex",
            "inZIndex must be of type number"
          );
        this._zIndex = inZIndex;
        return this;
      }
      /**
       * This method only modifies .persist()ed effects and causes them to not immediately end, but stick around for the given duration passed to this method.
       *
       * @param {Number} inExtraDuration
       * @returns {EffectSection}
       */
      extraEndDuration(inExtraDuration) {
        if (!is_real_number(inExtraDuration))
          throw this.sequence._customError(
            this,
            "extraEndDuration",
            "inExtraDuration must be of type number"
          );
        this._extraEndDuration = inExtraDuration;
        return this;
      }
      /**
       * Rotates the sprite
       *
       * @param {Number} inAngle
       * @returns {EffectSection}
       */
      spriteRotation(inAngle) {
        if (!is_real_number(inAngle))
          throw this.sequence._customError(
            this,
            "spriteRotation",
            "inAngle must be of type number"
          );
        this._spriteRotation = inAngle;
        return this;
      }
      /**
       * Rotates the sprite
       *
       * @param {Boolean} inBool
       * @returns {EffectSection}
       */
      randomSpriteRotation(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "randomSpriteRotation",
            "inBool must be of type boolean"
          );
        this._randomSpriteRotation = inBool;
        return this;
      }
      /**
       * Causes the effect to not rotate should its container rotate
       *
       * @param {Boolean} [inBool=true] inBool
       * @returns {EffectSection}
       */
      zeroSpriteRotation(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "zeroSpriteRotation",
            "inBool must be of type boolean"
          );
        this._zeroSpriteRotation = inBool;
        return this;
      }
      /**
       * @deprecated
       */
      noLoop(inBool = true) {
        this.sequence._showWarning(
          this,
          "noLoop",
          ".noLoop() is deprecated, please use .loopOptions({ loops: 1 }) instead",
          true
        );
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "noLoop",
            "inBool must be of type boolean"
          );
        this._loopOptions = foundry.utils.mergeObject(
          this._loopOptions ?? {
            loopDelay: 0,
            loops: 0
          },
          {
            loops: 1
          }
        );
        return this;
      }
      /**
       * Allows you to control the number of loops and the delays between each loop
       *
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      loopOptions(inOptions = {}) {
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "loopOptions",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            loopDelay: 0,
            loops: 0,
            endOnLastLoop: false
          },
          inOptions
        );
        if (typeof inOptions.endOnLastLoop !== "boolean")
          throw this.sequence._customError(
            this,
            "loopOptions",
            "inOptions.endOnLastLoop must be of type boolean"
          );
        if (typeof inOptions.loopDelay !== "number" || inOptions.loopDelay < 0)
          throw this.sequence._customError(
            this,
            "loopOptions",
            "inOptions.loopDelay must be of type number that is not below 0"
          );
        if (typeof inOptions.loops !== "number" || inOptions.loops < 0)
          throw this.sequence._customError(
            this,
            "loopOptions",
            "inOptions.loops must be of type number that is not below 0"
          );
        this._loopOptions = inOptions;
        return this;
      }
      /**
       * Causes the effect to not show up in the Effect Manager UI - DO NOT USE UNLESS YOU KNOW WHAT YOU ARE DOING
       *
       * @param inBool
       * @returns {EffectSection}
       */
      private(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "private",
            "inBool must be of type boolean"
          );
        this._private = inBool;
        return this;
      }
      /**
       * Causes the effect to be played in screen space instead of world space (where tokens are)
       *
       * @param {Boolean} [inBool=true] inBool
       * @returns {EffectSection}
       */
      screenSpace(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpace",
            "inBool must be of type boolean"
          );
        this._screenSpace = inBool;
        this._screenSpaceAnchor = this._screenSpaceAnchor ?? { x: 0.5, y: 0.5 };
        return this;
      }
      /**
       * Causes the effect to be played above all of the UI elements
       *
       * @param {Boolean} [inBool=true] inBool
       * @returns {EffectSection}
       */
      screenSpaceAboveUI(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpaceAboveUI",
            "inBool must be of type boolean"
          );
        this._screenSpaceAboveUI = inBool;
        return this;
      }
      /**
       *  Positions the effect in a screen space position, offset from its .screenSpaceAnchor()
       *
       * @param {Object} inPosition
       * @returns {EffectSection}
       */
      screenSpacePosition(inPosition) {
        inPosition = {
          x: inPosition?.x ?? 0,
          y: inPosition?.y ?? 0
        };
        if (!is_real_number(inPosition.x))
          throw this.sequence._customError(
            this,
            "screenSpacePosition",
            `inPosition.x must be of type number!`
          );
        if (!is_real_number(inPosition.y))
          throw this.sequence._customError(
            this,
            "screenSpacePosition",
            `inPosition.y must be of type number!`
          );
        this._screenSpacePosition = inPosition;
        return this;
      }
      /**
       *  Anchors the sprite according to the given x and y coordinates, or uniformly based on a single number in screen space
       *
       * @param {Number|Object} inAnchor
       * @returns {EffectSection}
       */
      screenSpaceAnchor(inAnchor) {
        if (is_real_number(inAnchor)) {
          inAnchor = {
            x: inAnchor,
            y: inAnchor
          };
        }
        inAnchor = {
          x: inAnchor?.x ?? 0.5,
          y: inAnchor?.y ?? 0.5
        };
        if (!is_real_number(inAnchor.x))
          throw this.sequence._customError(
            this,
            "screenSpaceAnchor",
            `inAnchor.x must be of type number!`
          );
        if (!is_real_number(inAnchor.y))
          throw this.sequence._customError(
            this,
            "screenSpaceAnchor",
            `inAnchor.y must be of type number!`
          );
        this._screenSpaceAnchor = inAnchor;
        return this;
      }
      /**
       *  Sets up various properties relating to scale of the effect on the screen
       *
       * @param {Object} inOptions
       * @returns {EffectSection}
       */
      screenSpaceScale(inOptions) {
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            x: 1,
            y: 1,
            fitX: false,
            fitY: false,
            ratioX: false,
            ratioY: false
          },
          inOptions
        );
        if (!is_real_number(inOptions.x))
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            `inOptions.x must be of type number!`
          );
        if (!is_real_number(inOptions.y))
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            `inOptions.y must be of type number!`
          );
        if (typeof inOptions.fitX !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            "inOptions.fitX must be of type boolean"
          );
        if (typeof inOptions.fitY !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            "inOptions.fitY must be of type boolean"
          );
        if (typeof inOptions.ratioX !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            "inOptions.ratioX must be of type boolean"
          );
        if (typeof inOptions.ratioY !== "boolean")
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            "inOptions.ratioY must be of type boolean"
          );
        if (inOptions.ratioX && inOptions.ratioY)
          throw this.sequence._customError(
            this,
            "screenSpaceScale",
            "both ratioX and ratioY cannot be true, one axis must fit or be set directly"
          );
        this._screenSpaceScale = inOptions;
        return this;
      }
      /**
       * Ties the effect to any number of documents in Foundry - if those get deleted, the effect is ended.
       *
       * @param {String|PlaceableObject|foundry.abstract.Document|Array<String|PlaceableObject|foundry.abstract.Document>} inDocuments
       * @returns {EffectSection}
       */
      tieToDocuments(inDocuments) {
        if (!Array.isArray(inDocuments)) {
          inDocuments = [inDocuments];
        }
        for (let doc of inDocuments) {
          if (typeof doc !== "string" && !(doc instanceof FoundryShim.PlaceableObject) && !(doc instanceof foundry.abstract.Document)) {
            throw this.sequence._customError(
              this,
              "tieToDocument",
              "inOrigin must be of type string, PlaceableObject, or Document, or an array thereof"
            );
          }
          if (typeof doc === "string") {
            const obj = fromUuidSync(doc);
            if (!obj)
              throw this.sequence._customError(
                this,
                "tieToDocument",
                `could not find document with UUID "${doc}"`
              );
          } else {
            doc = validate_document(doc);
            if (doc instanceof foundry.abstract.Document) {
              doc = doc?.uuid;
              if (!doc)
                throw this.sequence._customError(
                  this,
                  "tieToDocument",
                  "could not find the UUID for the given object"
                );
            }
          }
          this._tiedDocuments.push(doc);
        }
        return this;
      }
      /**
       *  Masks the effect to the given object or objects. If no object is given, the effect will be masked to the source
       *  of the effect.
       *
       * @param {Token/TokenDocument/Tile/TileDocument/Drawing/DrawingDocument/MeasuredTemplate/MeasuredTemplateDocument/Array} inObject
       * @returns {Section}
       */
      mask(inObject) {
        if (!inObject) {
          this._selfMask = true;
          return this;
        }
        if (Array.isArray(inObject)) {
          for (let obj of inObject) {
            this.mask(obj);
          }
          return this;
        }
        const validatedObject = this._validateLocation(inObject);
        const isValidObject = validatedObject instanceof TokenDocument || validatedObject instanceof TileDocument || validatedObject instanceof DrawingDocument || validatedObject instanceof MeasuredTemplateDocument;
        if (!isValidObject) {
          throw this.sequence._customError(
            this,
            "mask",
            "A foundry object was provided, but only Tokens, Tiles, Drawings, and MeasuredTemplates may be used to create effect masks"
          );
        }
        this._masks.push(get_object_identifier(validatedObject));
        return this;
      }
      /**
       * Causes the effect to be visible through walls
       *
       * @param inBool
       * @returns {EffectSection}
       */
      xray(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "xray",
            "inBool must be of type boolean"
          );
        this._xray = inBool;
        return this;
      }
      /**
       * Declares which file to be played. This may also be an array of paths, which will be randomly picked from each
       * time the section is played.
       *
       * @param {string|array} inFile
       * @param {object} inOptions
       * @returns this
       */
      file(inFile, inOptions = {}) {
        if (typeof inOptions === "boolean") {
          inOptions = {};
          this.sequence._showWarning(
            this,
            "file",
            "passing a boolean as a second argument to .file() is deprecated, please softFail: true on the sequence itself instead",
            true
          );
        }
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "file",
            "inOptions must be of type object"
          );
        inOptions = foundry.utils.mergeObject({
          antialiasing: PIXI.SCALE_MODES.LINEAR
        }, inOptions);
        if (typeof inOptions.antialiasing !== "number" || !(inOptions.antialiasing >= 0 && inOptions.antialiasing <= 1)) {
          throw this.sequence._customError(
            this,
            "file",
            "inOptions.antialiasing must be of type number of 0 or 1 (see PIXI.SCALE_MODES)"
          );
        }
        this._file = inFile;
        this._fileOptions = inOptions;
        return this;
      }
      /**
       * Configures the isometric configuration of this effect
       *
       * @param inOptions
       * @returns {EffectSection}
       */
      isometric(inOptions = {}) {
        if (typeof inOptions !== "object")
          throw this.sequence._customError(
            this,
            "isometric",
            `inOptions must be of type object`
          );
        inOptions = foundry.utils.mergeObject(
          {
            overlay: false
          },
          inOptions
        );
        if (typeof inOptions?.overlay !== "boolean")
          throw this.sequence._customError(
            this,
            "isometric",
            "inOptions.overlay must be of type boolean"
          );
        this._isometric = inOptions;
        return this;
      }
      /**
       * @private
       */
      _expressWarnings() {
        if (this._stretchTo && this._anchor?.x) {
          this.sequence._showWarning(
            this,
            "stretchTo",
            "you have called .stretchTo() and .anchor() - stretchTo will manually set the X axis of the anchor and may not behave like you expect.",
            true
          );
        }
        if (this._stretchTo && this._scaleToObject) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "You're trying to stretch towards an object, while scaling to fit another??? Make up your mind!"
          );
        }
        if (this._stretchTo && this._randomRotation) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "You're trying to stretch towards an object, while trying to randomly rotate the effect? What?"
          );
        }
        if (this._stretchTo && this._moveTowards) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "You're trying to stretch towards an object, while moving towards it? You're insane."
          );
        }
        if (this._attachTo && this._stretchTo?.attachTo && (this._startTime || this._endTime) && this._isRangedEffect) {
          throw this.sequence._customError(
            this,
            "stretchTo",
            "Dual-attached range-finding effects combined while using any of the time methods is stable - modern web browsers cannot handle it and it may crash them, so this feature has been disabled."
          );
        }
        const source = this._getSourceObject();
        const target = this._getTargetObject();
        if (!this._screenSpace && this._persistOptions?.persistTokenPrototype && this._masks.filter((uuid) => uuid !== source).length > 0) {
          this.sequence._showWarning(
            this,
            "persist",
            "You have applied persistTokenPrototype with multiple masks from objects in the scene - these will not be persisted across scenes!",
            true
          );
        }
        if (!source && !target && !this._screenSpace) {
          throw this.sequence._customError(
            this,
            "play",
            "Could not determine where to play the effect!"
          );
        }
      }
      /**
       * @OVERRIDE
       */
      async preRun() {
        const oldSource = this._source;
        const crosshairSource = this.sequence?.crosshairs?.[this._source];
        if (typeof this._source === "string" && crosshairSource) {
          this._source = crosshairSource.uuid;
        }
        const oldTarget = this._target?.target;
        const crosshairTarget = this.sequence?.crosshairs?.[this._target?.target];
        if (typeof this._target?.target === "string" && crosshairTarget) {
          this._target.target = crosshairTarget.uuid;
        }
        if (this._attachTo && !this._attachTo.active && typeof this._source === "string" && crosshairSource) {
          this._attachTo.active = !!crosshairSource;
        }
        if (this._name && (oldSource !== this._source || oldTarget !== this._target?.target)) {
          this.sequence.nameOffsetMap[this._name].source = this._getSourceObject();
          this.sequence.nameOffsetMap[this._name].target = this._getTargetObject();
        }
        const source = this._getSourceObject();
        if (this._persistOptions?.persistTokenPrototype && !(this._attachTo?.active || is_UUID(source))) {
          this._persistOptions.persistTokenPrototype = false;
        }
      }
      /**
       * @OVERRIDE
       * @returns {Promise<void>}
       */
      async run() {
        if (!user_can_do("permissions-effect-create") || !this._playEffect) {
          if (!user_can_do("permissions-effect-create")) {
            foundry.utils.debounce(EffectSection.debounceWarning, 1e3);
          }
          return new Promise((resolve) => {
            resolve();
          });
        }
        if (!this._deserializedData) this._expressWarnings();
        const data = await this._sanitizeEffectData();
        if (Hooks.call("preCreateSequencerEffect", data) === false) return;
        let push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
        let canvasEffectData = await Sequencer.EffectManager.play(data, push);
        let totalDuration = this._currentWaitTime;
        if (this._persist) {
          totalDuration += await canvasEffectData.promise;
        } else {
          totalDuration += await canvasEffectData.duration;
        }
        await new Promise((resolve) => setTimeout(resolve, totalDuration));
      }
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.files);
        Object.assign(this.constructor.prototype, traits.audio);
        Object.assign(this.constructor.prototype, traits.moves);
        Object.assign(this.constructor.prototype, traits.opacity);
        Object.assign(this.constructor.prototype, traits.rotation);
        Object.assign(this.constructor.prototype, traits.scale);
        Object.assign(this.constructor.prototype, traits.time);
        Object.assign(this.constructor.prototype, traits.users);
        Object.assign(this.constructor.prototype, traits.animation);
        Object.assign(this.constructor.prototype, traits.filter);
        Object.assign(this.constructor.prototype, traits.tint);
        Object.assign(this.constructor.prototype, traits.location);
        Object.assign(this.constructor.prototype, traits.offset);
        Object.assign(this.constructor.prototype, traits.text);
        Object.assign(this.constructor.prototype, traits.name);
      }
      /**
       * @private
       */
      async _initialize() {
        this._mirrorX = this._mirrorX || this._randomMirrorX && Math.random() < 0.5;
        this._mirrorY = this._mirrorY || this._randomMirrorY && Math.random() < 0.5;
        if (this._copySprite && !this._file) {
          this._file = this._copySprite.object?.ring?.enabled ? this._copySprite.object?.ring?.subject?.texture || this._copySprite.object?.texture?.src : this._copySprite.object?.texture?.src;
          if (this._source === null) {
            this._source = this._validateLocation(this._copySprite.object);
          }
          if (this._size === null) {
            const size = get_object_dimensions(this._copySprite.object);
            this._size = {
              width: size?.width ?? canvas.grid.size,
              height: size?.height ?? canvas.grid.size,
              gridUnits: false
            };
          }
          if (this._mirrorX === null && (this._copySprite.object.mirrorX || this._copySprite.object?.tile && this._copySprite.object?.tile.scale.x < 0)) {
            this._mirrorX = true;
          }
          if (this._mirrorY === null && (this._copySprite.object.mirrorY || this._copySprite.object?.tile && this._copySprite.object?.tile.scale.y < 0)) {
            this._mirrorY = true;
          }
          if (this._angle === null && this._copySprite.object?.rotation) {
            this._angle = -this._copySprite.object.rotation;
          }
          this._randomOffset = {
            source: this._randomOffset?.source ?? this._copySprite.options.randomOffset,
            target: this._randomOffset?.target ?? false
          };
        }
        if (this._name) {
          this.sequence.nameOffsetMap ||= {};
          if (!this.sequence.nameOffsetMap[this._name]) {
            const source = this._getSourceObject();
            const target = this._getTargetObject();
            if (this._offsetLegacy && !this._offset) {
              this._offset = {
                source: !target ? this._offsetLegacy : false,
                target: !!target ? this._offsetLegacy : false
              };
            }
            if (this._randomOffsetLegacy && !this._randomOffset) {
              this._randomOffset = {
                source: !target ? this._randomOffsetLegacy : false,
                target: !!target ? this._randomOffsetLegacy : false
              };
            }
            this.sequence.nameOffsetMap[this._name] = {
              seed: `${this._name}-${foundry.utils.randomID()}`,
              source,
              target,
              randomOffset: this._randomOffset,
              angle: this._angle,
              randomRotation: this._randomRotation,
              mirrorX: this._mirrorX,
              mirrorY: this._mirrorY,
              missed: this._missed,
              offset: this._offset,
              repetitions: this._repetitions,
              twister: {}
            };
          }
        }
        if (!this._file && !this._copySprite && !this._text && !this._shapes.length && this.sequence.softFail) {
          this._playEffect = false;
          return;
        }
        let fileData = this._file ? await this._determineFile(this._file) : {
          file: this._file,
          forcedIndex: false,
          customRange: false
        };
        this._isRangedEffect = fileData?.file?.rangeFind;
        if (fileData.customRange || fileData.file?.dbPath) return;
        let exists = false;
        try {
          exists = await SequencerFileCache.srcExists(fileData.file);
        } catch (err) {
        }
        if (!exists) {
          if (this.sequence.softFail) {
            this._playEffect = false;
            return;
          }
          throw this.sequence._customError(
            this,
            "Play",
            `Could not find file:<br>${fileData.file}`
          );
        }
      }
      /**
       * @private
       */
      _getSourceObject() {
        if (!this._source || typeof this._source !== "object") {
          return this._source;
        }
        if (this._source instanceof CrosshairsPlaceable || this._source instanceof CrosshairsDocument) {
          const doc = this._source?.document ?? this._source;
          if (this._attachTo) {
            return get_object_identifier(doc.object);
          }
          return doc.getOrientation().source;
        }
        if (this._source?.cachedLocation || !this._attachTo) {
          return get_object_canvas_data(this._source, { uuid: true });
        }
        return get_object_identifier(this._source) ?? get_object_canvas_data(this._source, { uuid: true });
      }
      /**
       * @private
       */
      _getTargetObject() {
        if (!this._target) return this._target;
        if (typeof this._target.target !== "object") {
          return this._target.target;
        }
        if (this._target?.target instanceof CrosshairsPlaceable || this._target?.target instanceof CrosshairsDocument) {
          const doc = this._target?.target?.document ?? this._target?.target;
          if (this._stretchTo?.attachTo || this._rotateTowards?.attachTo) {
            return get_object_identifier(doc.object);
          }
          const orientation = doc.getOrientation();
          return orientation.target ?? orientation.source;
        }
        if (this._target?.target?.cachedLocation || !(this._stretchTo?.attachTo || this._rotateTowards?.attachTo)) {
          return get_object_canvas_data(this._target.target, { measure: true, uuid: true });
        }
        return get_object_identifier(this._target.target) ?? get_object_canvas_data(this._target.target, { measure: true, uuid: true });
      }
      /**
       * @private
       */
      async _sanitizeEffectData() {
        if (this._deserializedData) {
          this._deserializedData.creationTimestamp = +/* @__PURE__ */ new Date();
          this._deserializedData.remote = true;
          return this._deserializedData;
        }
        const { file, forcedIndex, customRange } = this._file && this._playEffect ? await this._determineFile(this._file) : {
          file: this._file,
          forcedIndex: false,
          customRange: false
        };
        let source = this._getSourceObject();
        let target = this._getTargetObject();
        this._temporaryEffect = this._temporaryEffect || (source instanceof foundry.abstract.Document || source instanceof FoundryShim.MeasuredTemplate ? !is_UUID(source?.uuid) : this._temporaryEffect || false);
        if (this._offsetLegacy) {
          this._offset = {
            source: !target && this._offset?.source ? this._offsetLegacy : this._offset?.source,
            target: !!target && this._offset?.target ? this._offsetLegacy : this._offset?.target
          };
        }
        if (this._randomOffsetLegacy) {
          this._randomOffset = {
            source: !target && this._randomOffset?.source ? this._randomOffsetLegacy : this._randomOffset?.source,
            target: !!target && this._randomOffset?.target ? this._randomOffsetLegacy : this._randomOffset?.target
          };
        }
        if (this._selfMask) {
          this._masks.push(
            get_object_identifier(this._source) ?? get_object_canvas_data(this._source, { uuid: false })
          );
        }
        let sceneId = game.user.viewedScene;
        if (is_UUID(source)) {
          const potentialSceneId = source.split(".")[1];
          if (game.scenes.get(potentialSceneId)) {
            sceneId = potentialSceneId;
          }
        } else if (is_UUID(target)) {
          const potentialSceneId = target.split(".")[1];
          if (game.scenes.get(potentialSceneId)) {
            sceneId = potentialSceneId;
          }
        }
        let data = foundry.utils.duplicate({
          /**
           * Core properties
           */
          _id: foundry.utils.randomID(),
          flagVersion: flagManager.latestFlagVersion,
          sequenceId: this.sequence.id,
          creationTimestamp: +/* @__PURE__ */ new Date(),
          sceneId,
          creatorUserId: game.userId,
          moduleName: this.sequence.moduleName,
          users: this._users ? Array.from(this._users) : false,
          name: this._name,
          origin: this._origin,
          index: this.sequence.effectIndex,
          repetition: this._currentRepetition,
          private: this._private,
          temporary: this._temporaryEffect,
          tiedDocuments: Array.from(new Set(this._tiedDocuments)),
          /**
           * Source/target properties
           */
          source,
          target,
          rotateTowards: this._rotateTowards,
          stretchTo: this._stretchTo ? {
            attachTo: this._stretchTo.attachTo,
            onlyX: this._stretchTo.onlyX,
            requiresLineOfSight: this._stretchTo.requiresLineOfSight,
            hideLineOfSight: this._stretchTo.hideLineOfSight
          } : false,
          moveTowards: this._moveTowards ? {
            ease: this._moveTowards.ease,
            rotate: this._moveTowards.rotate
          } : false,
          attachTo: this._attachTo,
          missed: this._missed,
          /**
           * Sprite properties
           */
          file: file?.dbPath ?? file,
          customRange,
          forcedIndex,
          fileOptions: this._fileOptions,
          text: this._text,
          tilingTexture: this._tilingTexture,
          masks: Array.from(new Set(this._masks)),
          shapes: this._shapes,
          volume: this._volume,
          isometric: this._isometric,
          syncGroup: this._syncGroup,
          // Transforms
          scale: this._getCalculatedScale("scale"),
          spriteScale: this._getCalculatedScale("spriteScale"),
          angle: this._angle,
          size: this._size,
          offset: this._offset,
          anchor: this._anchor,
          spriteOffset: this._spriteOffset,
          spriteAnchor: this._spriteAnchor,
          template: this._template,
          zeroSpriteRotation: this._zeroSpriteRotation,
          randomOffset: this._randomOffset,
          randomRotation: this._randomRotation,
          scaleToObject: this._scaleToObject,
          elevation: this._elevation,
          sortLayer: this._sortLayer,
          aboveLighting: this._aboveLighting,
          aboveInterface: this._aboveInterface,
          xray: this._xray,
          // Appearance
          zIndex: this._zIndex,
          opacity: is_real_number(this._opacity) ? this._opacity : 1,
          filters: this._filters,
          loopOptions: this._loopOptions,
          spriteRotation: this._spriteRotation,
          randomSpriteRotation: this._randomSpriteRotation,
          tint: this._tint?.decimal,
          flipX: this._mirrorX,
          flipY: this._mirrorY,
          /**
           * Time properties
           */
          duration: this._duration,
          persist: this._persist,
          persistOptions: this._persistOptions,
          playbackRate: this._playbackRate,
          extraEndDuration: this._extraEndDuration,
          time: this._startTime || this._endTime ? {
            start: is_real_number(this._startTime) ? {
              value: this._startTime,
              isPerc: this._startPerc
            } : false,
            end: is_real_number(this._endTime) ? {
              value: this._endTime,
              isPerc: this._endPerc
            } : false,
            isRange: this._isRange
          } : false,
          /**
           * Animation properties
           */
          moves: this._moveTowards,
          moveSpeed: this._moveSpeed,
          fadeIn: this._fadeIn,
          fadeOut: this._fadeOut,
          scaleIn: this._scaleIn,
          scaleOut: this._scaleOut,
          rotateIn: this._rotateIn,
          rotateOut: this._rotateOut,
          fadeInAudio: this._fadeInAudio,
          fadeOutAudio: this._fadeOutAudio,
          animations: this._animations,
          /**
           * Screenspace properties
           */
          screenSpace: this._screenSpace,
          screenSpaceAboveUI: this._screenSpaceAboveUI,
          screenSpaceAnchor: this._screenSpaceAnchor,
          screenSpacePosition: this._screenSpacePosition,
          screenSpaceScale: this._screenSpaceScale,
          nameOffsetMap: this.sequence.nameOffsetMap
        });
        for (let override of this._overrides) {
          data = await override(this, data);
        }
        if ((typeof data.file !== "string" || data.file === "") && !data.text && !data.shapes && !data.customRange) {
          throw this.sequence._customError(
            this,
            "file",
            "an effect must have a file, text, or have a shape!"
          );
        }
        return data;
      }
      async _serialize() {
        const data = await super._serialize();
        await this.preRun();
        const sectionData = await this._sanitizeEffectData();
        return {
          ...data,
          type: "effect",
          sectionData
        };
      }
      async _deserialize(data) {
        this._deserializedData = data.sectionData;
        return super._deserialize(data);
      }
      /**
       * @private
       */
      _getCalculatedScale(type) {
        const min = this["_" + type + "Min"];
        const max = this["_" + type + "Max"];
        let scale2 = min;
        if (is_real_number(min)) {
          if (max && is_real_number(max)) {
            scale2 = random_float_between(min, max);
          }
          scale2 = {
            x: scale2,
            y: scale2
          };
        }
        return {
          x: scale2?.x ?? 1,
          y: scale2?.y ?? 1
        };
      }
    }
    class SoundSection extends Section {
      constructor(inSequence, inFile = "") {
        super(inSequence);
        this._file = inFile;
        this._volume = 0.8;
        this._channel = "interface";
        this._overrides = [];
        this._locationOptions = {};
      }
      static niceName = "Sound";
      /**
       * Declares which file to be played. This may also be an array of paths, which will be randomly picked from each
       * time the section is played.
       *
       * @param {string|array} inFile
       * @returns this
       */
      file(inFile) {
        this._file = inFile;
        return this;
      }
      /**
       * Adds a function that will run at the end of the sound serialization step, but before it is played. Allows direct
       * modifications of sound's data.
       *
       * @param {function} inFunc
       * @returns {SoundSection}
       */
      addOverride(inFunc) {
        if (!is_function$1(inFunc))
          throw this.sequence._customError(
            this,
            "addOverride",
            "The given function needs to be an actual function."
          );
        this._overrides.push(inFunc);
        return this;
      }
      radius(inNumber) {
        if (!is_real_number(inNumber))
          throw this.sequence._customError(
            this,
            "radius",
            "inNumber must be of type number"
          );
        this._locationOptions["radius"] = inNumber;
        return this;
      }
      constrainedByWalls(inBool) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "constrainedByWalls",
            `inBool must be of type boolean`
          );
        this._locationOptions["walls"] = inBool;
        return this;
      }
      distanceEasing(inBool) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "distanceEasing",
            `inBool must be of type boolean`
          );
        this._locationOptions["easing"] = inBool;
        return this;
      }
      audioChannel(inString) {
        if (typeof inString !== "string")
          throw this.sequence._customError(
            this,
            "audioChannel",
            `inString must be of type string`
          );
        if (!(game.audio?.[inString] instanceof AudioContext)) {
          const validChannels = Object.entries(game.audio).filter((e) => e[1] instanceof AudioContext).map((e) => e[0]);
          throw this.sequence._customError(
            this,
            "audioChannel",
            `inString must be of type ${validChannels.slice(0, -1).join(", ")}, or ${validChannels.slice(-1)}`
          );
        }
        this._channel = inString;
        return this;
      }
      alwaysForGMs(inBool) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "alwaysForGMs",
            `inBool must be of type boolean`
          );
        this._locationOptions["gmAlways"] = inBool;
        return this;
      }
      baseEffect(options = {}) {
        options = foundry.utils.mergeObject({
          type: "",
          intensity: 0
        }, options);
        if (typeof options.type !== "string" || !CONFIG.soundEffects[options.type])
          throw this.sequence._customError(
            this,
            "baseEffect",
            `options.type must be of type string, and one of ${Object.keys(CONFIG.soundEffects).join(", ")}`
          );
        if (!is_real_number(options.intensity))
          throw this.sequence._customError(
            this,
            "baseEffect",
            "options.intensity must be of type number"
          );
        this._locationOptions["baseEffect"] = {
          type: options.type,
          intensity: options.intensity
        };
        return this;
      }
      muffledEffect(options = {}) {
        options = foundry.utils.mergeObject({
          type: "",
          intensity: 0
        }, options);
        if (typeof options.type !== "string" || !CONFIG.soundEffects[options.type])
          throw this.sequence._customError(
            this,
            "baseEffect",
            `options.type must be of type string, and one of ${Object.keys(CONFIG.soundEffects).join(", ")}`
          );
        if (!is_real_number(options.intensity))
          throw this.sequence._customError(
            this,
            "baseEffect",
            "options.intensity must be of type number"
          );
        this._locationOptions["muffledEffect"] = {
          type: options.type,
          intensity: options.intensity
        };
        return this;
      }
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.files);
        Object.assign(this.constructor.prototype, traits.audio);
        Object.assign(this.constructor.prototype, traits.time);
        Object.assign(this.constructor.prototype, traits.users);
        Object.assign(this.constructor.prototype, traits.name);
        Object.assign(this.constructor.prototype, traits.location);
        Object.assign(this.constructor.prototype, traits.offset);
      }
      /**
       * @OVERRIDE
       * @returns {Promise}
       */
      async run() {
        const playData = await this._sanitizeSoundData();
        if (typeof playData.src !== "string" || playData.src === "") {
          if (this.sequence.softFail) {
            playData.play = false;
          } else {
            throw this.sequence._customError(
              this,
              "file",
              "a sound must have a src of type string!"
            );
          }
        }
        if (!playData.play && this.sequence.softFail) {
          return new Promise((reject) => {
            reject();
          });
        }
        if (!playData?.play) {
          this.sequence._customError(
            this,
            "Play",
            `File not found: ${playData.src}`
          );
          return new Promise((reject) => reject());
        }
        if (Hooks.call("preCreateSequencerSound", playData) === false) return;
        let push = !(playData?.users?.length === 1 && playData?.users?.includes(game.userId)) && !this.sequence.localOnly;
        SequencerSoundManager.play(playData, push);
        await new Promise(
          (resolve) => setTimeout(resolve, this._currentWaitTime + playData.duration)
        );
      }
      _getSourceObject() {
        if (!this._source || typeof this._source !== "object") {
          return this._source;
        }
        if (this._source instanceof CrosshairsPlaceable || this._source instanceof CrosshairsDocument) {
          const doc = this._source?.document ?? this._source;
          if (this._attachTo) {
            return get_object_identifier(doc.object);
          }
          return doc.getOrientation().source;
        }
        if (this._source?.cachedLocation || !this._attachTo) {
          return get_object_canvas_data(this._source, { uuid: true });
        }
        return get_object_identifier(this._source) ?? get_object_canvas_data(this._source, { uuid: true });
      }
      /**
       * @returns {Promise}
       * @private
       */
      async _sanitizeSoundData() {
        if (this._deserializedData) {
          return this._deserializedData;
        }
        if (!this._file) {
          return {
            play: false,
            src: false
          };
        }
        let { file, forcedIndex } = await this._determineFile(this._file);
        if (!file) {
          return {
            play: false,
            src: false
          };
        }
        if (file instanceof SequencerFileBase) {
          file.forcedIndex = forcedIndex;
          if (file.timeRange) {
            [this._startTime, this._endTime] = file.timeRange;
            this._isRange = true;
          }
          file = file.getFile();
        }
        let soundFile = await foundry.audio.AudioHelper.preloadSound(file);
        if (!soundFile || soundFile.failed) {
          return {
            play: false,
            src: this._file
          };
        }
        let duration = soundFile.duration * 1e3;
        let startTime = (this._startTime ? !this._startPerc ? this._startTime : this._startTime * duration : 0) / 1e3;
        if (this._endTime) {
          duration = !this._endPerc ? Number(
            this._isRange ? this._endTime - this._startTime : duration - this._endTime
          ) : this._endTime * duration;
        }
        let data = {
          id: foundry.utils.randomID(),
          play: true,
          src: file,
          source: this._getSourceObject(),
          offset: this._offset,
          randomOffset: this._randomOffset,
          locationOptions: this._locationOptions,
          loop: this._duration > duration,
          volume: this._volume,
          channel: this._channel,
          fadeIn: this._fadeInAudio,
          fadeOut: this._fadeOutAudio,
          startTime,
          duration: this._duration || duration,
          sceneId: this._source?.parent?.id || game.user.viewedScene,
          users: this._users ? Array.from(this._users) : null,
          name: this._name,
          origin: this._origin,
          seed: `${this._name}-${foundry.utils.randomID()}-${this._currentRepetition}`,
          nameOffsetMap: this.sequence.nameOffsetMap
        };
        for (let override of this._overrides) {
          data = await override(this, data);
        }
        return data;
      }
      async _serialize() {
        const data = await super._serialize();
        const sectionData = await this._sanitizeSoundData();
        return {
          ...data,
          type: "sound",
          sectionData
        };
      }
      async _deserialize(data) {
        this._deserializedData = data.sectionData;
        return super._deserialize(data);
      }
    }
    class AnimationSection extends Section {
      static niceName = "Animation";
      constructor(inSequence, inTarget) {
        super(inSequence);
        this._teleportTo = false;
        this._originObject = false;
        this._moveSpeed = 23;
        this._offset = { x: 0, y: 0 };
        this._closestSquare = false;
        this._snapToGrid = false;
        this._hide = void 0;
        if (inTarget) this.on(inTarget);
      }
      /**
       * Sets the target object to be animated
       *
       * @param {object|string} inTarget
       * @returns {AnimationSection}
       */
      on(inTarget) {
        inTarget = this._validateLocation(inTarget);
        if (!inTarget)
          throw this.sequence._customError(
            this,
            "on",
            "could not find position of given object"
          );
        this._originObject = this._validateLocation(inTarget);
        return this;
      }
      /**
       * Sets the location to teleport the target object to
       *
       * @param {object|string} inTarget
       * @param {object} options
       * @returns {AnimationSection}
       */
      teleportTo(inTarget, options = {}) {
        options = foundry.utils.mergeObject(
          {
            delay: 0,
            relativeToCenter: false
          },
          options
        );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "teleportTo",
            "options.delay must be of type number"
          );
        inTarget = this._validateLocation(inTarget);
        if (!inTarget)
          throw this.sequence._customError(
            this,
            "teleportTo",
            "could not find position of given object"
          );
        options.target = this._validateLocation(inTarget);
        this._teleportTo = options;
        return this;
      }
      /**
       * Sets the location to rotate the object to
       *
       * @param {object|string} inLocation
       * @param {object} options
       * @returns this
       */
      rotateTowards(inLocation, options = {}) {
        options = foundry.utils.mergeObject(
          {
            duration: 0,
            ease: "linear",
            delay: 0,
            rotationOffset: 0,
            towardsCenter: true,
            cacheLocation: false
          },
          options
        );
        if (!is_real_number(options.duration))
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.duration must be of type number"
          );
        if (typeof options.ease !== "string")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.ease must be of type string"
          );
        if (!is_real_number(options.delay))
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.delay must be of type number"
          );
        if (!is_real_number(options.rotationOffset))
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.rotationOffset must be of type number"
          );
        if (typeof options.towardsCenter !== "boolean")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.towardsCenter must be of type boolean"
          );
        if (typeof options.cacheLocation !== "boolean")
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "options.cacheLocation must be of type boolean"
          );
        options.target = this._validateLocation(inLocation);
        if (!options.target)
          throw this.sequence._customError(
            this,
            "rotateTowards",
            "could not find position of given object"
          );
        options.target = options.cacheLocation ? get_object_position(options.target, { measure: true }) : options.target;
        this._rotateTowards = options;
        return this;
      }
      /**
       * Causes the movement or teleportation to be offset in the X and/or Y axis
       *
       * @param {object} inOffset
       * @returns {AnimationSection}
       */
      offset(inOffset) {
        inOffset = foundry.utils.mergeObject({ x: 0, y: 0 }, inOffset);
        this._offset = this._validateLocation(inOffset);
        return this;
      }
      /**
       * Causes the movement or teleportation to pick the closest non-intersecting square, if the target is a token or tile
       *
       * @param {boolean} inBool
       * @returns {AnimationSection}
       */
      closestSquare(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "closestSquare",
            "inBool must be of type boolean"
          );
        this._closestSquare = inBool;
        return this;
      }
      /**
       * Causes the final location to be snapped to the grid
       *
       * @param {boolean} inBool
       * @returns {AnimationSection}
       */
      snapToGrid(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "snapToGrid",
            "inBool must be of type boolean"
          );
        this._snapToGrid = inBool;
        return this;
      }
      /**
       * Causes the object to become hidden
       *
       * @param {boolean} inBool
       * @returns {AnimationSection}
       */
      hide(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "hide",
            "inBool must be of type boolean"
          );
        this._hide = inBool;
        return this;
      }
      /**
       * Causes the object to become visible
       *
       * @param {boolean} inBool
       * @returns {AnimationSection}
       */
      show(inBool = true) {
        if (typeof inBool !== "boolean")
          throw this.sequence._customError(
            this,
            "show",
            "inBool must be of type boolean"
          );
        this._hide = !inBool;
        return this;
      }
      /**
       * @private
       */
      async run() {
        return this._runAnimate();
      }
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.moves);
        Object.assign(this.constructor.prototype, traits.opacity);
        Object.assign(this.constructor.prototype, traits.rotation);
        Object.assign(this.constructor.prototype, traits.audio);
        Object.assign(this.constructor.prototype, traits.tint);
      }
      /**
       * @private
       */
      async _updateObject(obj, updates, animate = false, animation2 = {}) {
        const uuid = obj?.uuid ?? obj?.document?.uuid;
        await sequencerSocket.executeAsGM(
          SOCKET_HANDLERS.UPDATE_DOCUMENT,
          uuid,
          updates,
          { animate, animation: animation2, teleport: !!this._teleportTo }
        );
      }
      /**
       * @private
       */
      async _waitForTokenRefresh(obj) {
        let token;
        if (obj instanceof FoundryShim.Token) {
          token = obj;
        }
        if (obj instanceof TokenDocument) {
          token = obj.object;
        }
        if (token == null || token.mesh != null) {
          return;
        }
        let refreshTokenID;
        return await new Promise((resolve) => {
          refreshTokenID = Hooks.on("refreshToken", async (tokenDoc) => {
            if (tokenDoc.document.actorId !== token.document.actorId || !token.mesh)
              return;
            Hooks.off("refreshToken", refreshTokenID);
            resolve();
          });
        });
      }
      /**
       * @private
       */
      async _execute() {
        if (!await this._shouldPlay()) return;
        let self = this;
        this._basicDelay = random_float_between(this._delayMin, this._delayMax);
        return new Promise(async (resolve) => {
          setTimeout(async () => {
            await this._waitForTokenRefresh(this._originObject);
            if (this._shouldAsync) {
              await self.run();
            } else {
              self.run();
            }
            resolve();
          }, this._basicDelay);
        });
      }
      /**
       * @private
       */
      _getClosestSquare(origin, target) {
        let originLoc = get_object_position(origin, { exact: true });
        let targetLoc = get_object_position(target, { exact: true });
        let originDimensions = get_object_dimensions(origin);
        let targetDimensions = get_object_dimensions(target);
        let originBottom = Math.max(
          originDimensions.width - canvas.grid.size,
          canvas.grid.size
        );
        let originRight = Math.max(
          originDimensions.height - canvas.grid.size,
          canvas.grid.size
        );
        let ray = new Ray(originLoc, targetLoc);
        let dx = ray.dx;
        let dy = ray.dy;
        if (dx > 0 && Math.abs(dx) > originRight) {
          dx -= originDimensions.width;
        } else if (dx < 0 && Math.abs(dx) > targetDimensions.width) {
          dx += targetDimensions.height;
        } else {
          dx = 0;
        }
        if (dy > 0 && Math.abs(dy) > originBottom) {
          dy -= originDimensions.height;
        } else if (dy < 0 && Math.abs(dy) > targetDimensions.height) {
          dy += targetDimensions.height;
        } else {
          dy = 0;
        }
        const pos = {
          x: originLoc.x + dx,
          y: originLoc.y + dy,
          elevation: targetLoc?.elevation
        };
        if (!pos.elevation) {
          delete pos["elevation"];
        }
        return pos;
      }
      /**
       * This needs a rewrite, jeesus.
       */
      async _runAnimate() {
        let animData = {
          attributes: [],
          maxFPS: 1e3 / game.settings.get("core", "maxFPS"),
          lastTimespan: performance.now(),
          totalDt: 0
        };
        if (typeof this._moveTowards?.target === "string" && this.sequence.nameOffsetMap[this._moveTowards?.target]) {
          this._moveTowards.target = this.sequence.nameOffsetMap[this._moveTowards?.target].target ?? this.sequence.nameOffsetMap[this._moveTowards?.target].source;
        }
        if (typeof this._teleportTo?.target === "string" && this.sequence.nameOffsetMap[this._teleportTo?.target]) {
          this._teleportTo.target = this.sequence.nameOffsetMap[this._teleportTo?.target].target ?? this.sequence.nameOffsetMap[this._teleportTo?.target].source;
        }
        if (typeof this._rotateTowards?.target === "string" && this.sequence.nameOffsetMap[this._rotateTowards?.target]) {
          this._rotateTowards.target = this.sequence.nameOffsetMap[this._rotateTowards?.target].target ?? this.sequence.nameOffsetMap[this._rotateTowards?.target].source;
        }
        let overallDuration = this._duration ? this._duration : 0;
        const originLocation = get_object_position(this._originObject, {
          exact: true
        });
        if (this._rotateTowards) {
          let offset2 = (this._angle ? this._angle : 0) + this._rotateTowards.rotationOffset;
          let targetLoc = this._moveTowards?.target || this._teleportTo?.target || this._originObject;
          targetLoc = this._closestSquare ? this._getClosestSquare(this._originObject, targetLoc) : get_object_position(targetLoc, { exact: true });
          targetLoc.x += this._offset.x;
          targetLoc.y += this._offset.y;
          if (this._snapToGrid) {
            targetLoc = canvas.grid.getSnappedPoint(targetLoc, { mode: CONST.GRID_SNAPPING_MODES.CENTER, resolution: 1 });
          }
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              let startLocation = this._originObject.object?.center ?? targetLoc;
              let targetLocation = this._rotateTowards.target?.object ?? this._rotateTowards.target;
              if (this._rotateTowards.towardsCenter) {
                targetLocation = targetLocation?.center ?? targetLocation;
              }
              let ray = new Ray(startLocation, targetLocation);
              let angle = Math.normalizeDegrees(ray.angle * 180 / Math.PI - 90);
              angle += offset2;
              await this._updateObject(
                this._originObject,
                { rotation: angle },
                this._rotateTowards.duration > 0,
                {
                  duration: this._rotateTowards.duration
                }
              );
            }, this._rotateTowards.delay ?? 0);
          } else {
            animData.attributes.push({
              name: "rotationTowards",
              offset: offset2,
              origin: this._originObject,
              originLocation: targetLoc,
              target: this._rotateTowards.target?.object ?? this._rotateTowards.target,
              towardsCenter: this._rotateTowards.towardsCenter,
              from: false,
              to: false,
              progress: 0,
              done: false,
              duration: this._rotateTowards.duration,
              durationDone: 0,
              delay: this._rotateTowards.delay,
              ease: this._rotateTowards.ease
            });
          }
          let rotateDuration = this._rotateTowards.duration + this._rotateTowards.delay;
          overallDuration = overallDuration > rotateDuration ? overallDuration : rotateDuration;
        }
        if (this._fadeIn) {
          let to = is_real_number(this._opacity) ? this._opacity : 1;
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              await this._updateObject(this._originObject, { alpha: to }, true, {
                duration: this._fadeIn.duration,
                easing: this._fadeIn.ease
              });
            }, this._fadeIn.delay ?? 0);
          } else {
            animData.attributes.push({
              name: "alpha",
              from: 0,
              to,
              progress: 0,
              done: false,
              duration: this._fadeIn.duration,
              durationDone: 0,
              delay: this._fadeIn.delay,
              ease: this._fadeIn.ease
            });
          }
          let fadeDuration = this._fadeIn.duration + this._fadeIn.delay;
          overallDuration = overallDuration > fadeDuration ? overallDuration : fadeDuration;
        }
        if (this._fadeInAudio && this._originObject?.video?.volume !== void 0) {
          let to = is_real_number(this._volume) ? this._volume : 1;
          animData.attributes.push({
            name: "video.volume",
            from: 0,
            to,
            progress: 0,
            done: false,
            duration: this._fadeInAudio.duration,
            durationDone: 0,
            delay: this._fadeInAudio.delay,
            ease: this._fadeInAudio.ease
          });
          let fadeDuration = this._fadeInAudio.duration + this._fadeInAudio.delay;
          overallDuration = overallDuration > fadeDuration ? overallDuration : fadeDuration;
        }
        if (this._rotateIn) {
          let from = this._angle ? this._angle : this._originObject.rotation;
          let to = this._rotateIn.value;
          if (Math.abs(from - to) > 180) {
            if (to < 0) {
              to += 360;
            } else if (from > to) {
              from -= 360;
            }
          }
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              if (this._originObject.rotation !== from) {
                await this._updateObject(
                  this._originObject,
                  { rotation: from },
                  false
                );
              }
              await this._updateObject(this._originObject, { rotation: to }, true, {
                duration: this._rotateIn.duration
              });
            }, this._rotateIn.delay ?? 0);
          } else {
            animData.attributes.push({
              name: "rotation",
              from,
              to,
              progress: 0,
              done: false,
              duration: this._rotateIn.duration,
              durationDone: 0,
              delay: this._rotateIn.delay,
              ease: this._rotateIn.ease
            });
          }
          let rotateDuration = this._rotateIn.duration + this._rotateIn.delay;
          overallDuration = overallDuration > rotateDuration ? overallDuration : rotateDuration;
        }
        if (this._moveTowards) {
          let originLocation2 = get_object_position(this._originObject, {
            exact: true
          });
          let targetLocation = this._closestSquare ? this._getClosestSquare(this._originObject, this._moveTowards.target) : get_object_position(this._moveTowards.target, {
            exact: true
          });
          targetLocation.x += this._offset.x;
          targetLocation.y += this._offset.y;
          targetLocation.elevation = targetLocation?.elevation ?? this._originObject?.elevation;
          if (this._moveTowards.relativeToCenter) {
            const dimensions = get_object_dimensions(this._originObject);
            targetLocation.x -= dimensions.width / 2;
            targetLocation.y -= dimensions.height / 2;
            if (this._snapToGrid) {
              targetLocation.x -= 0.01;
              targetLocation.y -= 0.01;
            }
          }
          if (this._snapToGrid) {
            targetLocation = canvas.grid.getSnappedPoint(targetLocation, {
              mode: CONST.GRID_SNAPPING_MODES.VERTEX,
              resolution: 1
            });
          }
          let originalDx = targetLocation.x - originLocation2.x;
          let originalDy = targetLocation.y - originLocation2.y;
          let originalDistance = Math.sqrt(
            originalDx * originalDx + originalDy * originalDy
          );
          let duration = this._duration ? this._duration : originalDistance / this._moveSpeed * animData.maxFPS;
          let moveDuration = duration + this._moveTowards.delay;
          overallDuration = overallDuration > moveDuration ? overallDuration : moveDuration;
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              await this._updateObject(this._originObject, targetLocation, true, {
                movementSpeed: this._moveSpeed,
                duration
              });
            }, this._moveTowards.delay ?? 0);
          } else {
            if (!(duration === 0 || originalDistance === 0)) {
              animData.attributes.push({
                name: "position",
                origin: originLocation2,
                target: targetLocation,
                originalDistance,
                currentDistance: 0,
                progress: 0,
                speed: 0,
                duration,
                done: false,
                ease: this._moveTowards.ease,
                delay: this._moveTowards.delay
              });
            }
          }
        }
        if (this._fadeOut) {
          let from = is_real_number(this._opacity) ? this._opacity : this._originObject.alpha ?? 1;
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              await this._updateObject(this._originObject, { alpha: 0 }, true, {
                duration: this._fadeOut.duration
              });
            }, this._fadeOut.delay ?? 0);
          } else {
            animData.attributes.push({
              name: "alpha",
              from,
              to: 0,
              progress: 0,
              done: false,
              duration: this._fadeOut.duration,
              durationDone: 0,
              delay: overallDuration - this._fadeOut.duration,
              ease: this._fadeOut.ease
            });
          }
          let fadeOutDuration = this._fadeOut.duration + this._fadeOut.delay;
          overallDuration = overallDuration > fadeOutDuration ? overallDuration : fadeOutDuration;
        }
        if (this._fadeOutAudio && this._originObject?.video?.volume !== void 0) {
          let from = is_real_number(this._volume) ? this._volume : this._originObject.video.volume;
          animData.attributes.push({
            name: "video.volume",
            from,
            to: 0,
            progress: 0,
            done: false,
            duration: this._fadeOutAudio.duration,
            durationDone: 0,
            delay: overallDuration - this._fadeOutAudio.duration,
            ease: this._fadeOutAudio.ease
          });
          let fadeOutAudioDuration = this._fadeOutAudio.duration + this._fadeOutAudio.delay;
          overallDuration = overallDuration > fadeOutAudioDuration ? overallDuration : fadeOutAudioDuration;
        }
        if (this._rotateOut) {
          let from = this._rotateOut.value;
          let to = this._angle ? this._angle : this._originObject.rotation;
          if (this._rotateIn) from += this._rotateIn.value;
          if (Math.abs(from - to) > 180) {
            if (to < 0) {
              to += 360;
            } else if (from > to) {
              from -= 360;
            }
          }
          if (this._originObject instanceof TokenDocument) {
            setTimeout(async () => {
              if (this._originObject.rotation !== from) {
                await this._updateObject(
                  this._originObject,
                  { rotation: from },
                  false
                );
              }
              await this._updateObject(this._originObject, { rotation: to }, true, {
                duration: this._rotateOut.duration
              });
            }, this._rotateOut.delay ?? 0);
          } else {
            animData.attributes.push({
              name: "rotation",
              from,
              to,
              progress: 0,
              done: false,
              duration: this._rotateOut.duration,
              durationDone: 0,
              delay: overallDuration - this._rotateOut.duration,
              ease: this._rotateOut.ease
            });
          }
          let rotateOutDuration = this._rotateOut.duration + this._rotateOut.delay;
          overallDuration = overallDuration > rotateOutDuration ? overallDuration : rotateOutDuration;
        }
        if (this._teleportTo) {
          setTimeout(async () => {
            let targetLocation = this._closestSquare ? this._getClosestSquare(this._originObject, this._teleportTo.target) : get_object_position(this._teleportTo.target, {
              exact: true
            });
            if (targetLocation.x === void 0) targetLocation.x = originLocation.x;
            if (targetLocation.y === void 0) targetLocation.y = originLocation.y;
            if (targetLocation.elevation === void 0)
              targetLocation.elevation = originLocation.elevation;
            targetLocation.x += this._offset.x;
            targetLocation.y += this._offset.y;
            targetLocation.elevation = targetLocation?.elevation ?? this._originObject?.elevation;
            const dimensions = get_object_dimensions(this._originObject);
            if (this._teleportTo.relativeToCenter) {
              targetLocation.x -= dimensions.width / 2;
              targetLocation.y -= dimensions.height / 2;
              if (this._snapToGrid) {
                targetLocation.x -= 0.01;
                targetLocation.y -= 0.01;
              }
            }
            if (this._snapToGrid) {
              targetLocation.x -= dimensions.width / 2;
              targetLocation.y -= dimensions.height / 2;
              targetLocation = canvas.grid.getSnappedPoint(targetLocation, {
                mode: CONST.GRID_SNAPPING_MODES.VERTEX,
                resolution: 1
              });
            }
            await this._updateObject(this._originObject, targetLocation, false);
          }, this._teleportTo.delay);
          if (overallDuration <= this._teleportTo.delay) {
            this._waitUntilFinished = true;
          }
          overallDuration = overallDuration > this._teleportTo.delay ? overallDuration : this._teleportTo.delay;
        }
        let updateAttributes = {};
        if (is_real_number(this._angle) && !this._rotateIn && !this._rotateOut) {
          updateAttributes["rotation"] = this._angle;
        }
        if (is_real_number(this._opacity) && !this._fadeIn && !this._fadeOut) {
          updateAttributes["alpha"] = this._opacity;
        }
        if (is_real_number(this._volume) && !this._fadeInAudio && !this._fadeOutAudio && this._originObject?.video?.volume !== void 0) {
          updateAttributes["video.volume"] = this._volume;
        }
        if (this._tint) {
          updateAttributes["texture.tint"] = this._tint.hexadecimal;
        }
        if (this._hide !== void 0) {
          updateAttributes["hidden"] = this._hide;
        }
        if (Object.keys(updateAttributes).length) {
          await wait$1(1);
          await this._updateObject(this._originObject, updateAttributes);
          await wait$1(1);
        }
        return new Promise(async (resolve) => {
          this._animate(animData, resolve);
          setTimeout(
            resolve,
            Math.max(0, overallDuration + this._currentWaitTime + animData.maxFPS)
          );
        });
      }
      /**
       * @private
       */
      async _animate(animData, resolve, timespan) {
        if (timespan) {
          let animatedAttributes = {};
          let dt = timespan - animData.lastTimespan;
          if (dt >= animData.maxFPS) {
            animData.totalDt += dt;
            for (let attribute of animData.attributes) {
              if (attribute.done) continue;
              if (animData.totalDt < attribute.delay) continue;
              if (attribute.name === "position") {
                attribute.speed = attribute.originalDistance / (attribute.duration / dt);
                attribute.currentDistance += attribute.speed;
                attribute.progress = attribute.currentDistance / attribute.originalDistance;
                let x = interpolate(
                  attribute.origin.x,
                  attribute.target.x,
                  attribute.progress,
                  attribute.ease
                );
                let y = interpolate(
                  attribute.origin.y,
                  attribute.target.y,
                  attribute.progress,
                  attribute.ease
                );
                if (attribute.currentDistance >= attribute.originalDistance) {
                  x = attribute.target.x;
                  y = attribute.target.y;
                  attribute.done = true;
                }
                animatedAttributes["x"] = x;
                animatedAttributes["y"] = y;
              } else {
                if (attribute.name === "rotationTowards" && !attribute.from && !attribute.to) {
                  let target = attribute.target;
                  if (this._rotateTowards.towardsCenter)
                    target = target?.center ?? target;
                  let ray = new Ray(attribute.originLocation, target);
                  let angle = ray.angle * 180 / Math.PI - 90;
                  angle += attribute.offset;
                  attribute.from = attribute.origin.rotation;
                  attribute.to = angle;
                  if (Math.abs(attribute.from - attribute.to) > 180) {
                    if (attribute.to < 0) {
                      attribute.to += 360;
                    } else if (attribute.from > attribute.to) {
                      attribute.from -= 360;
                    }
                  }
                  attribute.name = "rotation";
                }
                attribute.durationDone += dt;
                attribute.progress = attribute.durationDone / attribute.duration;
                let val = interpolate(
                  attribute.from,
                  attribute.to,
                  attribute.progress,
                  attribute.ease
                );
                if (attribute.progress >= 1) {
                  val = attribute.to;
                  attribute.done = true;
                }
                animatedAttributes[attribute.name] = val;
              }
            }
            if (Object.keys(animatedAttributes).length > 0) {
              await this._updateObject(this._originObject, animatedAttributes);
            }
            animData.attributes = animData.attributes.filter((a) => !a.done);
            if (animData.attributes.length === 0) return;
            animData.lastTimespan = timespan;
          }
        }
        let self = this;
        requestAnimationFrame(function(timespan2) {
          self._animate(animData, resolve, timespan2);
        });
      }
    }
    class ScrollingTextSection extends Section {
      constructor(inSequence, target, text2, textOptions) {
        super(inSequence);
        this._deserializedData = null;
        this._source = null;
        this._text = "";
        this._duration = 2e3;
        this._distance = null;
        this._jitter = 0;
        this._anchor = null;
        this._direction = null;
        this._seed = get_hash(foundry.utils.randomID());
        if (target) {
          this.atLocation(target);
        }
        if (text2) {
          this.text(text2, textOptions);
        }
      }
      static niceName = "Scrolling Text";
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.users);
        Object.assign(this.constructor.prototype, traits.location);
        Object.assign(this.constructor.prototype, traits.offset);
        Object.assign(this.constructor.prototype, traits.text);
      }
      direction(inDirection) {
        if (!(typeof inDirection === "string" || is_real_number(inDirection))) {
          throw this.sequence._customError(
            this,
            "direction",
            "inDirection must be of type string (CONST.TEXT_ANCHOR_POINTS) or number"
          );
        }
        if (typeof inDirection === "string" && !CONST.TEXT_ANCHOR_POINTS[inDirection]) {
          throw this.sequence._customError(
            this,
            "direction",
            `${inDirection} does not exist in CONST.TEXT_ANCHOR_POINTS!`
          );
        } else if (typeof inDirection === "string") {
          this._direction = CONST.TEXT_ANCHOR_POINTS[inDirection];
        } else {
          this._direction = inDirection;
        }
        return this;
      }
      anchor(inAnchor) {
        if (!(typeof inAnchor === "string" || is_real_number(inAnchor))) {
          throw this.sequence._customError(
            this,
            "direction",
            "inAnchor must be of type string (CONST.TEXT_ANCHOR_POINTS) or number"
          );
        }
        if (typeof inAnchor === "string" && CONST.TEXT_ANCHOR_POINTS[inAnchor] === void 0 || is_real_number(inAnchor) && !Object.values(CONST.TEXT_ANCHOR_POINTS).includes(inAnchor)) {
          throw this.sequence._customError(
            this,
            "direction",
            `${inAnchor} does not exist in CONST.TEXT_ANCHOR_POINTS!`
          );
        } else if (typeof inAnchor === "string") {
          this._anchor = CONST.TEXT_ANCHOR_POINTS[inAnchor];
        } else {
          this._anchor = inAnchor;
        }
        return this;
      }
      jitter(inJitter) {
        if (!(is_real_number(inJitter) && inJitter >= 0 && inJitter <= 1)) {
          throw this.sequence._customError(
            this,
            "jitter",
            "inJitter must be of type number between 0 and 1"
          );
        }
        this._jitter = inJitter;
        return this;
      }
      async preRun() {
        const oldSource = this._source;
        const crosshairSource = this.sequence?.crosshairs?.[this._source];
        if (typeof this._source === "string" && crosshairSource) {
          this._source = crosshairSource.uuid;
        }
        if (this._name && oldSource !== this._source) {
          this.sequence.nameOffsetMap[this._name].source = this._getSourceObject();
        }
      }
      async run() {
        const data = await this._sanitizeTextData();
        if (Hooks.call("preCreateScrollingText", data) === false) return;
        const push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
        const duration = SequencerFoundryReplicator.playScrollingText(data, push);
        await new Promise(
          (resolve) => setTimeout(resolve, this._currentWaitTime + duration)
        );
      }
      _getSourceObject() {
        if (!this._source || typeof this._source !== "object") return this._source;
        if (this._source instanceof CrosshairsPlaceable || this._source instanceof CrosshairsDocument) {
          const doc = this._source?.document ?? this._source;
          return doc.getOrientation().source;
        }
        return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
      }
      async _sanitizeTextData() {
        if (this._deserializedData) {
          return this._deserializedData;
        }
        return {
          sceneId: game.user.viewedScene,
          seed: this._seed,
          sequenceId: this.sequence.id,
          creatorUserId: game.userId,
          users: this._users ? Array.from(this._users) : false,
          moduleName: this.sequence.moduleName,
          source: this._getSourceObject(),
          offset: this._offset?.source ?? false,
          randomOffset: this._randomOffset?.source ?? false,
          content: this._text?.text ?? "",
          nameOffsetMap: this.sequence.nameOffsetMap,
          options: {
            anchor: this._anchor,
            direction: this._direction,
            duration: this._duration,
            distance: this._distance,
            jitter: this._jitter,
            ...this._text
          }
        };
      }
      async _serialize() {
        const data = await super._serialize();
        const sectionData = await this._sanitizeTextData();
        return {
          ...data,
          type: "scrollingText",
          sectionData
        };
      }
      async _deserialize(data) {
        this._deserializedData = data.sectionData;
        return super._deserialize(data);
      }
    }
    class CanvasPanSection extends Section {
      constructor(inSequence, target, duration, scale2) {
        super(inSequence);
        this._deserializedData = null;
        this._source = null;
        this._duration = duration ?? 250;
        this._speed = null;
        this._scale = scale2 ?? 1;
        this._lockView = null;
        this._shake = null;
        this._seed = get_hash(foundry.utils.randomID());
        if (target) {
          this.atLocation(target);
        }
      }
      static niceName = "Canvas Pan";
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.users);
        Object.assign(this.constructor.prototype, traits.location);
        Object.assign(this.constructor.prototype, traits.offset);
      }
      /**
       * Sets the speed (pixels per frame) of the canvas pan
       *
       * @param {number} inSpeed
       * @returns this
       */
      speed(inSpeed) {
        if (!is_real_number(inSpeed))
          throw this.sequence._customError(
            this,
            "speed",
            "inSpeed must be of type number"
          );
        if (inSpeed < 0) {
          throw this.sequence._customError(
            this,
            "speed",
            "inSpeed must be greater or equal to 0"
          );
        }
        this._speed = inSpeed;
        return this;
      }
      /**
       * Sets the zoom level of the canvas pan
       *
       * @param {number} inScale
       * @returns this
       */
      scale(inScale) {
        if (!is_real_number(inScale))
          throw this.sequence._customError(
            this,
            "scale",
            "inScale must be of type number"
          );
        if (inScale <= 0) {
          throw this.sequence._customError(
            this,
            "scale",
            "inScale must be greater than 0"
          );
        }
        this._scale = inScale;
        return this;
      }
      /**
       * Locks the canvas at the given location for the given duration
       *
       * @param {number} inDuration
       * @returns this
       */
      lockView(inDuration) {
        if (!is_real_number(inDuration))
          throw this.sequence._customError(
            this,
            "lockView",
            "inDuration must be of type number"
          );
        if (inDuration < 0) {
          throw this.sequence._customError(
            this,
            "lockView",
            "inDuration must be greater or equal to 0"
          );
        }
        this._lockView = inDuration;
        return this;
      }
      /**
       * Shakes the canvas
       *
       * @param {number} duration
       * @param {number} strength
       * @param {number} frequency
       * @param {number} fadeInDuration
       * @param {number} fadeOutDuration
       * @param {boolean} rotation
       * @returns this
       */
      shake({
        duration = 250,
        strength = 20,
        frequency = 10,
        fadeInDuration = 0,
        fadeOutDuration = 200,
        rotation: rotation2 = true
      } = {}) {
        if (!is_real_number(duration)) {
          throw this.sequence._customError(
            this,
            "shake",
            "duration must be of type number"
          );
        }
        if (!is_real_number(strength)) {
          throw this.sequence._customError(
            this,
            "shake",
            "strength must be of type number"
          );
        }
        if (!is_real_number(strength)) {
          throw this.sequence._customError(
            this,
            "shake",
            "frequency must be of type number"
          );
        }
        if (!is_real_number(fadeInDuration)) {
          throw this.sequence._customError(
            this,
            "shake",
            "fadeInDuration must be of type number"
          );
        }
        if (!is_real_number(fadeOutDuration)) {
          throw this.sequence._customError(
            this,
            "shake",
            "fadeOutDuration must be of type number"
          );
        }
        if (typeof rotation2 !== "boolean") {
          throw this.sequence._customError(
            this,
            "shake",
            "rotation must be of type boolean"
          );
        }
        this._shake = {
          duration,
          strength,
          frequency,
          fadeInDuration,
          fadeOutDuration,
          rotation: rotation2
        };
        return this;
      }
      async preRun() {
        const oldSource = this._source;
        const crosshairSource = this.sequence?.crosshairs?.[this._source];
        if (typeof this._source === "string" && crosshairSource) {
          this._source = crosshairSource.uuid;
        }
        if (this._name && oldSource !== this._source) {
          this.sequence.nameOffsetMap[this._name].source = this._getSourceObject();
        }
      }
      async run() {
        const data = await this._sanitizeData();
        if (Hooks.call("preCanvasPan", data) === false) return;
        const push = !(data?.users?.length === 1 && data?.users?.includes(game.userId)) && !this.sequence.localOnly;
        const duration = SequencerFoundryReplicator.panCanvas(data, push);
        await new Promise(
          (resolve) => setTimeout(resolve, this._currentWaitTime + duration)
        );
      }
      _getSourceObject() {
        if (!this._source || typeof this._source !== "object") return this._source;
        if (this._source instanceof CrosshairsPlaceable || this._source instanceof CrosshairsDocument) {
          const doc = this._source?.document ?? this._source;
          return doc.getOrientation().source;
        }
        return get_object_identifier(this._source) ?? get_object_canvas_data(this._source, { uuid: false });
      }
      async _sanitizeData() {
        if (this._deserializedData) {
          return this._deserializedData;
        }
        return {
          sceneId: game.user.viewedScene,
          seed: this._seed,
          sequenceId: this.sequence.id,
          creatorUserId: game.userId,
          users: this._users ? Array.from(this._users) : false,
          moduleName: this.sequence.moduleName,
          source: this._getSourceObject(),
          offset: this._offset?.source ?? false,
          randomOffset: this._randomOffset?.source ?? false,
          duration: this._duration,
          speed: this._speed,
          scale: this._scale,
          lockView: this._lockView,
          shake: this._shake,
          nameOffsetMap: this.sequence.nameOffsetMap
        };
      }
      async _serialize() {
        const data = await super._serialize();
        const sectionData = await this._sanitizeData();
        return {
          ...data,
          type: "canvasPan",
          sectionData
        };
      }
      async _deserialize(data) {
        this._deserializedData = data.sectionData;
        return super._deserialize(data);
      }
    }
    class WaitSection extends Section {
      constructor(inSequence, msMin, msMax) {
        super(inSequence);
        this._waitUntilFinished = true;
        this._waitDuration = random_int_between(msMin, Math.max(msMin, msMax));
      }
      static niceName = "Wait";
      /**
       * @returns {Promise<void>}
       */
      async run() {
        debug("Running wait");
        await new Promise(async (resolve) => {
          setTimeout(resolve, this._waitDuration);
        });
      }
      /**
       * @returns {Promise}
       * @private
       */
      async _execute() {
        await this.run();
      }
      async _serialize() {
        const data = await super._serialize();
        return {
          ...data,
          type: "wait",
          sectionData: {
            waitDuration: this._waitDuration
          }
        };
      }
      async _deserialize(data) {
        this._waitDuration = data.sectionData.waitDuration;
        return super._deserialize(data);
      }
    }
    class CrosshairSection extends Section {
      constructor(inSequence, inName = "") {
        super(inSequence);
        this._name = inName;
        this._type = CONST.MEASURED_TEMPLATE_TYPES.CIRCLE;
        this._distance = canvas.grid.distance / 2;
        this._angle = 53.13;
        this._width = canvas.grid.distance;
        this._direction = 0;
        this._borderColor = null;
        this._fillColor = null;
        this._persist = false;
        this._config = CrosshairsDocument.defaultConfig;
        this._waitUntilFinished = true;
        this._callbacks = {};
      }
      static niceName = "Crosshair";
      /**
       * Sets the type of MeasurableTemplate to create, see CONST.MEASURED_TEMPLATE_TYPES
       */
      type(inType = "") {
        if (typeof inType !== "string") {
          throw this.sequence._customError(this, "type", "inType must be of type string");
        }
        if (!Object.values(CONST.MEASURED_TEMPLATE_TYPES).includes(inType)) {
          throw this.sequence._customError(this, "type", `inType must be one of valid types: ${Object.values(CONST.MEASURED_TEMPLATE_TYPES).join(" ")} (see CONST.MEASURED_TEMPLATE_TYPES)`);
        }
        this._type = inType;
        return this;
      }
      /**
       * Sets a custom label to be set as a part of this crosshair
       */
      label(inText, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "label", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({
          dx: CrosshairsDocument.defaultConfig.label.dx,
          dy: CrosshairsDocument.defaultConfig.label.dy
        }, inOptions);
        if (typeof inText !== "string") {
          throw this.sequence._customError(this, "label", "inText must be of type string");
        }
        if (!is_real_number(inOptions.dx)) {
          throw this.sequence._customError(this, "label", "inOptions.dx must be of type number");
        }
        if (!is_real_number(inOptions.dy)) {
          throw this.sequence._customError(this, "label", "inOptions.dy must be of type number");
        }
        this._config["label"]["text"] = inText;
        this._config["label"]["dx"] = inOptions.dx;
        this._config["label"]["dy"] = inOptions.dy;
        return this;
      }
      /**
       * Sets how the position of the crosshair should snap on the grid
       */
      snapPosition(inSnap) {
        if (!is_real_number(inSnap)) {
          throw this.sequence._customError(this, "snapPosition", "inSnap must be of type number, see CONST.GRID_SNAPPING_MODES");
        }
        this._config["snap"]["position"] = inSnap;
        return this;
      }
      /**
       * Sets the distance for the crosshair - or radius for a circular crosshair
       */
      distance(inDistance, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "distance", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({
          min: CrosshairsDocument.defaultConfig.distanceMin,
          max: CrosshairsDocument.defaultConfig.distanceMax
        }, inOptions);
        if (!is_real_number(inDistance)) {
          throw this.sequence._customError(this, "distance", "inDistance must be of type number");
        }
        if (inOptions.min !== null) {
          if (!is_real_number(inOptions.min)) {
            throw this.sequence._customError(this, "distance", "inOptions.min must be of type number");
          }
          if (inOptions.min <= 0) {
            throw this.sequence._customError(this, "distance", "inOptions.min must be a non-zero number");
          }
        } else {
          inOptions.min = inDistance;
        }
        if (inOptions.max !== null) {
          if (!is_real_number(inOptions.max)) {
            throw this.sequence._customError(this, "distance", "inOptions.max must be of type number");
          }
          if (inOptions.max <= 0) {
            throw this.sequence._customError(this, "distance", "inOptions.max must be a non-zero number");
          }
        } else {
          inOptions.max = inDistance;
        }
        if (inOptions.min > inOptions.max) {
          throw this.sequence._customError(this, "distance", "inOptions.min cannot be larger than inOptions.max");
        }
        this._distance = inDistance;
        this._config["distanceMin"] = inOptions.min;
        this._config["distanceMax"] = inOptions.max;
        return this;
      }
      /**
       * Configures the angle of the crosshair - mostly used for the width of cone crosshairs
       */
      angle(inAngle) {
        if (!is_real_number(inAngle)) {
          throw this.sequence._customError(this, "angle", "inAngle must be of type number");
        }
        this._angle = inAngle;
        return this;
      }
      /**
       * Configures the width for the crosshair - used for ray crosshairs
       */
      width(inWidth) {
        if (!is_real_number(inWidth)) {
          throw this.sequence._customError(this, "width", "inWidth must be of type number");
        }
        this._width = inWidth;
        return this;
      }
      /**
       * Configures the width for the crosshair - used for ray crosshairs
       */
      direction(inDirection) {
        if (!is_real_number(inDirection)) {
          throw this.sequence._customError(this, "direction", "inDirection must be of type number");
        }
        this._direction = inDirection;
        return this;
      }
      /**
       * Configures the  increments the direction should snap along
       */
      snapDirection(inSnapDirection) {
        if (!is_real_number(inSnapDirection)) {
          throw this.sequence._customError(this, "snapDirection", "inDirectionSnap must be of type number");
        }
        this._config["snap"]["direction"] = inSnapDirection;
        return this;
      }
      /**
       * Toggles whether the crosshair can be manually rotated
       */
      lockManualRotation(inBool = true) {
        if (typeof inBool !== "boolean") {
          throw this.sequence._customError(this, "preventUserRotation", "inBool must be of type number");
        }
        this._config["lockManualRotation"] = inBool;
        return this;
      }
      /**
       * Toggles whether the crosshair's end position can be dragged
       * @param inBool
       */
      lockDrag(inBool = true) {
        if (typeof inBool !== "boolean") {
          throw this.sequence._customError(this, "lockDrag", "inBool must be of type number");
        }
        this._config["lockDrag"] = inBool;
        return this;
      }
      /**
       * Configures the custom icon to be used on the crosshair
       */
      icon(inTexture, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "icon", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({ borderVisible: CrosshairsDocument.defaultConfig.icon.borderVisible }, inOptions);
        if (typeof inTexture !== "string") {
          throw this.sequence._customError(this, "icon", "inTexture must be of type string");
        }
        if (typeof inOptions.borderVisible !== "boolean") {
          throw this.sequence._customError(this, "icon", "inOptions.borderVisible must be of type boolean");
        }
        this._config["icon"]["texture"] = inTexture;
        this._config["icon"]["borderVisible"] = inOptions.borderVisible;
        return this;
      }
      /**
       * Sets the border color of the crosshair
       */
      borderColor(inColor, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "borderColor", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({ borderVisible: CrosshairsDocument.defaultConfig.borderAlpha }, inOptions);
        const { alpha } = inOptions;
        if (!is_real_number(alpha)) {
          throw this.sequence._customError(this, "borderAlpha", "inOptions.alpha must be of type number");
        }
        this._borderColor = parseColor(inColor).hexadecimal;
        this._config["borderAlpha"] = normalize_alpha_number(alpha);
        return this;
      }
      /**
       * Sets the fill color of the crosshair
       */
      fillColor(inColor, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "fillColor", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({ alpha: CrosshairsDocument.defaultConfig.fillAlpha }, inOptions);
        const { alpha } = inOptions;
        if (!is_real_number(alpha)) {
          throw this.sequence._customError(this, "fillColor", "inOptions.alpha must be of type number");
        }
        this._config["fillAlpha"] = normalize_alpha_number(alpha);
        this._fillColor = parseColor(inColor).hexadecimal;
        return this;
      }
      /**
       * Sets the texture used by the crosshair
       */
      texture(inTexture, inOptions = {}) {
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "texture", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject(
          {
            alpha: CrosshairsDocument.defaultConfig.textureAlpha,
            scale: CrosshairsDocument.defaultConfig.textureScale
          },
          inOptions
        );
        const { alpha, scale: scale2 } = inOptions;
        if (!is_real_number(alpha)) {
          throw this.sequence._customError(this, "texture", "inOptions.alpha must be of type number");
        }
        if (!is_real_number(scale2)) {
          throw this.sequence._customError(this, "texture", "inOptions.scale must be of type number");
        }
        if (typeof inTexture !== "string") {
          throw this.sequence._customError(this, "texture", "inTexture must be of type string");
        }
        this._texture = inTexture;
        this._config["textureAlpha"] = normalize_alpha_number(alpha);
        this._config["textureScale"] = scale2;
        return this;
      }
      /**
       * Configures the source location of the crosshair, usually to limit it around the target placeable object, or to
       * cause it to be limited within a certain range of the placeable object
       */
      location(inLocation, inOptions = {}) {
        if (!inLocation || typeof inLocation !== "object") {
          throw this.sequence._customError(this, "location", "inLocation is invalid, and must be of type of placeable object, or document");
        }
        if (typeof inOptions !== "object") {
          throw this.sequence._customError(this, "location", "inOptions must be of type object");
        }
        inOptions = foundry.utils.mergeObject({
          limitMinRange: CrosshairsDocument.defaultConfig.location.limitMinRange,
          limitMaxRange: CrosshairsDocument.defaultConfig.location.limitMaxRange,
          showRange: CrosshairsDocument.defaultConfig.location.showRange,
          lockToEdge: CrosshairsDocument.defaultConfig.location.lockToEdge,
          lockToEdgeDirection: CrosshairsDocument.defaultConfig.location.lockToEdgeDirection,
          offset: CrosshairsDocument.defaultConfig.location.offset,
          wallBehavior: CrosshairsDocument.defaultConfig.location.wallBehavior,
          displayRangePoly: CrosshairsDocument.defaultConfig.location.displayRangePoly,
          rangePolyFillColor: CrosshairsDocument.defaultConfig.location.rangePolyFillColor,
          rangePolyLineColor: CrosshairsDocument.defaultConfig.location.rangePolyLineColor,
          rangePolyFillAlpha: CrosshairsDocument.defaultConfig.location.rangePolyFillAlpha,
          rangePolyLineAlpha: CrosshairsDocument.defaultConfig.location.rangePolyLineAlpha
        }, inOptions);
        inLocation = this._validateLocation(inLocation);
        if (typeof inOptions.wallBehavior !== "string") {
          throw this.sequence._customError(this, "location", "inOptions.wallBehavior must be of type string");
        }
        if (inLocation === void 0) {
          throw this.sequence._customError(this, "location", "could not find position of given object");
        }
        if (inOptions.limitMinRange && !is_real_number(inOptions.limitMinRange)) {
          throw this.sequence._customError(this, "location", "inOptions.limitMinRange must be of type number");
        }
        if (inOptions.limitMaxRange && !is_real_number(inOptions.limitMaxRange)) {
          throw this.sequence._customError(this, "location", "inOptions.limitMaxRange must be of type number");
        }
        if (typeof inOptions.lockToEdge !== "boolean") {
          throw this.sequence._customError(this, "location", "inOptions.lockToEdge must be of type boolean");
        }
        if (typeof inOptions.showRange !== "boolean") {
          throw this.sequence._customError(this, "location", "inOptions.showRange must be of type boolean");
        }
        if (typeof inOptions.lockToEdgeDirection !== "boolean") {
          throw this.sequence._customError(this, "location", "inOptions.lockToEdgeDirection must be of type boolean");
        }
        if (typeof inOptions.offset !== "object") {
          throw this.sequence._customError(this, "location", "inOptions.offset must be of type of object");
        }
        if (!is_real_number(inOptions.offset.x)) {
          throw this.sequence._customError(this, "location", "inOptions.offset.x must be of type of number");
        }
        if (!is_real_number(inOptions.offset.y)) {
          throw this.sequence._customError(this, "location", "inOptions.offset.y must be of type of number");
        }
        if (typeof inOptions.displayRangePoly !== "boolean") {
          throw this.sequence._customError(this, "location", "inOptions.displayRangePoly must be of type boolean");
        }
        if (inOptions.rangePolyFillColor && !is_real_number(inOptions.rangePolyFillColor)) {
          throw this.sequence._customError(this, "location", "inOptions.rangePolyFillColor must be of type number (color, eg 0xFF0000)");
        }
        if (inOptions.rangePolyLineColor && !is_real_number(inOptions.rangePolyLineColor)) {
          throw this.sequence._customError(this, "location", "inOptions.rangePolyLineColor must be of type number (color, eg 0xFF0000)");
        }
        if (inOptions.rangePolyFillAlpha && !is_real_number(inOptions.rangePolyFillAlpha)) {
          throw this.sequence._customError(this, "location", "inOptions.rangePolyFillAlpha must be of type number");
        }
        if (inOptions.rangePolyLineAlpha && !is_real_number(inOptions.rangePolyLineAlpha)) {
          throw this.sequence._customError(this, "location", "inOptions.rangePolyLineAlpha must be of type number");
        }
        this._config["location"] = {
          obj: inLocation?.object ?? inLocation,
          limitMinRange: inOptions.limitMinRange,
          limitMaxRange: inOptions.limitMaxRange,
          lockToEdge: inOptions.lockToEdge,
          lockToEdgeDirection: inOptions.lockToEdgeDirection,
          showRange: inOptions.showRange,
          offset: inOptions.offset,
          wallBehavior: inOptions.wallBehavior,
          displayRangePoly: inOptions.displayRangePoly,
          rangePolyFillColor: inOptions.rangePolyFillColor,
          rangePolyLineColor: inOptions.rangePolyLineColor,
          rangePolyFillAlpha: inOptions.rangePolyFillAlpha,
          rangePolyLineAlpha: inOptions.rangePolyLineAlpha
        };
        return this;
      }
      /**
       * Causes the crosshair to spawn a measurable template identical to the crosshair
       */
      persist(inBool = true) {
        if (typeof inBool !== "boolean") {
          throw this.sequence._customError(this, "persist", "inBool must be of type boolean");
        }
        this._persist = inBool;
        return this;
      }
      /**
       * Toggles whether this crosshair should highlight the grid
       */
      gridHighlight(inBool = true) {
        if (typeof inBool !== "boolean") {
          throw this.sequence._customError(this, "gridHighlight", "inBool must be of type boolean");
        }
        this._config["gridHighlight"] = inBool;
        return this;
      }
      /**
       * Adds a callback function for certain crosshair events
       */
      callback(inString, inCallback) {
        if (typeof inString !== "string" || !Object.values(CONSTANTS.CALLBACKS).some((str) => str === inString)) {
          throw this.sequence._customError(this, "callback", "inString must be of type string and one of Sequencer.Crosshair.CALLBACKS");
        }
        if (!is_function$1(inCallback)) {
          throw this.sequence._customError(this, "callback", "inCallback must be of type Function");
        }
        this._callbacks[inString] = inCallback;
        return this;
      }
      async run() {
        const reticle = new CrosshairsDocument({
          t: this._type,
          distance: this._distance,
          width: this._width,
          direction: this._direction,
          angle: this._angle,
          borderColor: this._borderColor,
          texture: this._texture,
          fillColor: this._fillColor
        }, {
          parent: canvas.scene
        }, this._config, this._callbacks);
        return reticle.show().then(async () => {
          if (this._persist) {
            const [template] = await canvas.scene.createEmbeddedDocuments("MeasuredTemplate", [
              reticle.toObject()
            ]);
            this.sequence.crosshairs[this._name] = template;
          }
          if (this._name) {
            this.sequence.nameOffsetMap ||= {};
            this.sequence.nameOffsetMap[this._name] = {
              seed: `${this._name}-${foundry.utils.randomID()}`,
              twister: {},
              source: this.sequence.crosshairs[this._name]?.uuid ?? reticle.getOrientation().source,
              target: this.sequence.crosshairs[this._name]?.uuid ?? reticle.getOrientation().target
            };
          }
        }).catch((err) => {
          console.log(err);
          this.sequence._abort();
        });
      }
      async _execute() {
        await this.run();
      }
      /**
       * @private
       */
      _applyTraits() {
        Object.assign(this.constructor.prototype, traits.name);
      }
    }
    let Sequence$1 = class Sequence2 {
      constructor(options = {
        moduleName: "Sequencer",
        softFail: false
      }, softFail = false) {
        this.id = foundry.utils.randomID();
        this.moduleName = typeof options === "string" ? options : options?.moduleName ?? "Sequencer";
        this.softFail = options?.softFail ?? softFail;
        this.sections = [];
        this.nameOffsetMap = false;
        this.crosshairs = {};
        this.effectIndex = 0;
        this.sectionToCreate = void 0;
        this.localOnly = false;
        this._status = writable(CONSTANTS.STATUS.READY);
        return sequence_proxy_wrap(this);
      }
      /**
       * Plays all of this sequence's sections
       *
       * @returns {Promise}
       */
      async play({ remote = false, preload = false, local = false } = {}) {
        this.localOnly = local || remote;
        if (remote) {
          const data = await this.toJSON();
          sequencerSocket.executeForOthers(
            SOCKET_HANDLERS.RUN_SEQUENCE_LOCALLY,
            data
          );
          return new Sequence2().fromJSON(data).play({ local: true });
        }
        Hooks.callAll("createSequencerSequence", this);
        debug("Initializing sections");
        const initializationPromises = this.sections.map((section) => section._initialize());
        await Promise.allSettled(initializationPromises);
        if (preload) {
          const preloadFiles = this.sections.filter((section) => !!section._file).map((section) => section._file);
          if (local) {
            await Sequencer.Preloader.preload(preloadFiles);
          } else {
            await Sequencer.Preloader.preloadForClients(preloadFiles);
          }
        }
        SequenceManager.RunningSequences.add(this.id, this);
        this.effectIndex = 0;
        debug("Playing sections");
        this.status = CONSTANTS.STATUS.RUNNING;
        const promises = [];
        for (let section of this.sections) {
          if (section instanceof EffectSection) this.effectIndex++;
          if (section.shouldWaitUntilFinished) {
            promises.push(await section._execute());
          } else {
            promises.push(section._execute());
          }
          if (this.status === CONSTANTS.STATUS.ABORTED) {
            continue;
          }
          if (!section._isLastSection) {
            await new Promise((resolve) => setTimeout(resolve, 3));
          }
        }
        return Promise.allSettled(promises).then(() => {
          Hooks.callAll("endedSequencerSequence");
          debug("Finished playing sections");
          this.status = CONSTANTS.STATUS.COMPLETE;
        });
      }
      /**
       * Creates a section that will run a function.
       *
       * @param {function} inFunc
       * @returns {Sequence} this
       */
      thenDo(inFunc) {
        const func2 = section_proxy_wrap(new FunctionSection(this, inFunc));
        this.sections.push(func2);
        return func2;
      }
      /**
       * Creates a section that will run a macro based on a name or a direct reference to a macro.
       *
       * @param {string|Macro} inMacro
       * @param {object} args
       * @returns {Sequence} this
       */
      macro(inMacro, ...args) {
        let macro;
        let compendium = false;
        if (typeof inMacro === "string") {
          if (inMacro.startsWith("Compendium")) {
            let packArray = inMacro.split(".");
            let pack = game.packs.get(`${packArray[1]}.${packArray[2]}`);
            if (!pack) {
              if (this.softFail) {
                return this;
              }
              throw custom_error(
                this.moduleName,
                `macro - Compendium '${packArray[1]}.${packArray[2]}' was not found`
              );
            }
            macro = packArray;
            compendium = pack;
          } else {
            macro = game.macros.getName(inMacro);
            if (!macro) {
              if (this.softFail) {
                return this;
              }
              throw custom_error(
                this.moduleName,
                `macro - Macro '${inMacro}' was not found`
              );
            }
          }
        } else if (inMacro instanceof Macro) {
          macro = inMacro;
        } else {
          throw custom_error(
            this.moduleName,
            `macro - inMacro must be of instance string or Macro`
          );
        }
        args = args.length ? args?.[0] : {};
        if (typeof args !== "object") {
          throw custom_error(
            this.moduleName,
            `macro - Secondary argument must be an object`
          );
        }
        const func2 = section_proxy_wrap(
          new FunctionSection(
            this,
            async () => {
              if (compendium) {
                const macroIndex = (await compendium.getIndex()).find((i) => {
                  if (macro[3] === "Macro") {
                    return macro[4] === i._id;
                  }
                  return i.name === macro[3];
                });
                const macroData = macroIndex ? await compendium.getDocument(macroIndex?._id) : false;
                if (!macroData) {
                  if (this.softFail) {
                    return;
                  }
                  throw custom_error(
                    this.moduleName,
                    `macro - Macro '${macro[3]}' was not found in compendium '${macro[1]}.${macro[2]}'`
                  );
                }
                macro = new Macro(macroData);
                macro.ownership.default = CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER;
              }
              await macro.execute(args);
            },
            true
          )
        );
        this.sections.push(func2);
        return this;
      }
      /**
       * Creates an effect section. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Effect section.
       *
       * @param {string} [inFile] inFile
       * @returns {Section}
       */
      effect(inFile = "") {
        const effect = section_proxy_wrap(new EffectSection(this, inFile));
        this.sections.push(effect);
        return effect;
      }
      /**
       * Creates a sound section. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Sound section.
       *
       * @param {string} [inFile] inFile
       * @returns {Section}
       */
      sound(inFile = "") {
        const sound = section_proxy_wrap(new SoundSection(this, inFile));
        this.sections.push(sound);
        return sound;
      }
      /**
       * Creates an animation. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Animation section.
       *
       * @param {Token|Tile} [inTarget=false] inTarget
       * @returns {AnimationSection}
       */
      animation(inTarget) {
        const animation2 = section_proxy_wrap(
          new AnimationSection(this, inTarget)
        );
        this.sections.push(animation2);
        return animation2;
      }
      /**
       * Creates a scrolling text. Until you call .then(), .effect(), .sound(), or .wait(), you'll be working on the Scrolling Text section.
       *
       * @param {Object|String|Boolean} [inTarget=false] inTarget
       * @param {String|Boolean} [inText=false] inText
       * @param {Object} [inTextOptions={}] inTextOptions
       * @returns {AnimationSection}
       */
      scrollingText(inTarget = false, inText = false, inTextOptions = {}) {
        const scrolling = section_proxy_wrap(
          new ScrollingTextSection(this, inTarget, inText, inTextOptions)
        );
        this.sections.push(scrolling);
        return scrolling;
      }
      /**
       * Pans the canvas text. Until you call any other sections you'll be working on the Canvas Pan section.
       *
       * @param {Object|String|Boolean} [inTarget=false] inTarget
       * @param {Boolean|Number} inDuration
       * @param {Boolean|Number} inSpeed
       * @returns {AnimationSection}
       */
      canvasPan(inTarget = false, inDuration = null, inSpeed = null) {
        const panning = section_proxy_wrap(
          new CanvasPanSection(this, inTarget)
        );
        this.sections.push(panning);
        return panning;
      }
      /**
       * Creates a crosshair section. Until you call other Sequence methods, you will be working on the Crosshair section.
       *
       * @param {string} [inName] inName
       * @returns {Section}
       */
      crosshair(inName = "") {
        const crosshair = section_proxy_wrap(new CrosshairSection(this, inName));
        this.sections.push(crosshair);
        return crosshair;
      }
      /**
       * Adds a location to the sequence and ties it to a string so that it may be used later
       * @param {string} inName
       * @param {object/PlaceableObject/Document} inLocation
       * @returns {Sequence} this
       */
      addNamedLocation(inName, inLocation) {
        if (typeof inName !== "string")
          throw custom_error(this.moduleName, `addNamedLocation - inName must be of type string`);
        if (!(typeof inLocation === "object" || inLocation instanceof FoundryShim.PlaceableObject || inLocation instanceof foundry.abstract.Document))
          throw custom_error(this.moduleName, `addNamedLocation - inLocation must be of type object, PlaceableObject, or Document`);
        if (inLocation instanceof CrosshairsPlaceable) inLocation = inLocation.document;
        this.nameOffsetMap ||= {};
        const sourceLocation = inLocation?.source ?? inLocation?.cachedPosition?.source ?? (inLocation instanceof CrosshairsDocument ? inLocation.getOrientation().source : get_object_canvas_data(inLocation, { uuid: false }));
        const targetLocation = inLocation?.target ?? inLocation?.cachedPosition?.target ?? (inLocation instanceof CrosshairsDocument ? inLocation.getOrientation().target ?? sourceLocation : get_object_canvas_data(inLocation, { measure: true, uuid: false }));
        this.nameOffsetMap[inName] = {
          seed: `${inName}-${foundry.utils.randomID()}`,
          source: sourceLocation,
          target: targetLocation
        };
        return this;
      }
      /**
       * Causes the sequence to wait after the last section for as many milliseconds as you pass to this method. If given
       * a second number, a random wait time between the two given numbers will be generated.
       *
       * @param {number} [msMin=1] minMs
       * @param {number} [msMax=1] maxMs
       * @returns {Sequence} this
       */
      wait(msMin = 1, msMax = 1) {
        if (msMin < 1)
          throw custom_error(
            this.moduleName,
            `wait - Wait ms cannot be less than 1`
          );
        if (msMax < 1)
          throw custom_error(
            this.moduleName,
            `wait - Max wait ms cannot be less than 1`
          );
        const section = section_proxy_wrap(new WaitSection(this, msMin, msMax));
        this.sections.push(section);
        return this;
      }
      /**
       * Applies a preset to the sequence
       *
       * @param {string} presetName
       * @param {*} args
       * @returns {Sequence|FunctionSection|EffectSection|AnimationSection|SoundSection}
       */
      preset(presetName, ...args) {
        if (typeof presetName !== "string") {
          throw this._customError(this, "name", `inName must be of type string`);
        }
        const preset = SequencerPresets.get(presetName);
        if (!preset) {
          custom_warning(
            "Sequencer",
            `preset | Could not find preset with name "${presetName}"`
          );
          return this;
        }
        const lastSection = this.sections[this.sections.length - 1] || this;
        return preset(lastSection, ...args);
      }
      /**
       * Adds the sections from a given Sequence to this Sequence
       *
       * @param {Sequence|FunctionSection|EffectSection|AnimationSection|SoundSection} inSequence
       * @returns {Sequence} this
       */
      addSequence(inSequence) {
        if (inSequence instanceof Section) inSequence = inSequence.sequence;
        if (!(inSequence instanceof Sequence2)) {
          throw custom_error(
            this.moduleName,
            `addSequence - could not find the sequence from the given parameter`
          );
        }
        const newSections = inSequence.sections.map((section) => {
          const newSection = Object.assign(
            Object.create(Object.getPrototypeOf(section)),
            section
          );
          newSection.sequence = this;
          return newSection;
        });
        this.sections = this.sections.concat(newSections);
        return this;
      }
      async toJSON() {
        const data = {
          options: { moduleName: this.moduleName, softFail: this.softFail },
          sections: []
        };
        for (const section of this.sections) {
          const sectionData = await section._serialize();
          if (!sectionData.type) {
            throw new Error(
              `Sequencer | toJson | ${section.constructor.name} does not support serialization!`
            );
          }
          data.sections.push(sectionData);
        }
        return data;
      }
      fromJSON(data) {
        this.moduleName = data.options.moduleName;
        this.softFail = data.options.softFail;
        this.localOnly = true;
        for (const section of data.sections) {
          this[section.type]()._deserialize(section);
        }
        return this;
      }
      _createCustomSection(...args) {
        const func2 = section_proxy_wrap(
          new this.sectionToCreate(this, ...args)
        );
        this.sectionToCreate = void 0;
        this.sections.push(func2);
        return func2;
      }
      _showWarning(self, func2, warning, notify = false) {
        custom_warning(
          this.moduleName,
          `${self.constructor.name.replace("Section", "")} | ${func2} - ${warning}`,
          notify
        );
      }
      _customError(self, func2, error) {
        return custom_error(
          this.moduleName,
          `${self.constructor.name.replace("Section", "")} | ${func2} - ${error}`
        );
      }
      set status(inStatus) {
        this._status.update((currentStatus) => {
          if (currentStatus === CONSTANTS.STATUS.READY || currentStatus === CONSTANTS.STATUS.RUNNING) {
            return inStatus;
          }
          return currentStatus;
        });
      }
      get status() {
        return get_store_value(this._status);
      }
      get statusStore() {
        return this._status;
      }
      _abort() {
        this.status = CONSTANTS.STATUS.ABORTED;
        for (const section of this.sections) {
          section._abortSection();
        }
      }
    };
    class SequencerSectionManager {
      #sections = {};
      get externalSections() {
        return this.#sections;
      }
      /**
       * Registers a class by a name that will then be available through the Sequencer
       *
       * @param {String}      inModuleName
       * @param {String}      inMethodName
       * @param {Class}       inClass
       * @param {Boolean}     overwrite
       * @returns {Boolean}               Whether the registration succeeded
       */
      registerSection(inModuleName, inMethodName, inClass, overwrite = false) {
        if (!(inClass.prototype instanceof Section)) {
          throw custom_error(
            inModuleName,
            `inClass must be instance of Sequencer.BaseSection`
          );
        }
        let coreMethods = Object.getOwnPropertyNames(Sequence.prototype).filter(
          (method) => {
            return !method.startsWith("_") && method !== "constructor";
          }
        );
        if (coreMethods.includes(inMethodName)) {
          throw custom_error(
            inModuleName,
            `${inMethodName} is an existing protected method of the Sequence class - please register with another method name!`
          );
        }
        if (this.#sections[inMethodName] && !overwrite) {
          throw custom_error(
            inModuleName,
            `${inMethodName} is already a registered Section with the class ${this.#sections[inMethodName].constructor.name}`
          );
        }
        coreMethods = coreMethods.concat(Object.keys(this.#sections));
        const clashingMethods = Object.getOwnPropertyNames(
          inClass.prototype
        ).filter((method) => coreMethods.includes(method));
        if (clashingMethods.length) {
          let errors = clashingMethods.join(", ");
          throw custom_error(
            inModuleName,
            `${inMethodName} cannot contain the following methods: ${errors}<br>These methods are existing methods on the Sequence or from already registered Sections. Please rename these methods to avoid conflicts.`
          );
        }
        debug(
          `SectionManager | Successfully registered ${inMethodName} with Sequencer!`
        );
        this.#sections[inMethodName] = inClass;
        return true;
      }
    }
    const sectionManager = new SequencerSectionManager();
    let libWrapper = void 0;
    const TGT_SPLIT_RE = new RegExp(
      `([^.[]+|\\[('([^'\\\\]|\\\\.)+?'|"([^"\\\\]|\\\\.)+?")\\])`,
      "g"
    );
    const TGT_CLEANUP_RE = new RegExp(`(^\\['|'\\]$|^\\["|"\\]$)`, "g");
    Hooks.once("init", () => {
      if (globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
        libWrapper = globalThis.libWrapper;
        return;
      }
      libWrapper = class {
        static get is_fallback() {
          return true;
        }
        static get WRAPPER() {
          return "WRAPPER";
        }
        static get MIXED() {
          return "MIXED";
        }
        static get OVERRIDE() {
          return "OVERRIDE";
        }
        static register(package_id, target, fn, type = "MIXED", { chain = void 0, bind: bind2 = [] } = {}) {
          const is_setter = target.endsWith("#set");
          target = !is_setter ? target : target.slice(0, -4);
          const split = target.match(TGT_SPLIT_RE).map((x) => x.replace(/\\(.)/g, "$1").replace(TGT_CLEANUP_RE, ""));
          const root_nm = split.splice(0, 1)[0];
          let obj, fn_name;
          if (split.length == 0) {
            obj = globalThis;
            fn_name = root_nm;
          } else {
            const _eval = eval;
            fn_name = split.pop();
            obj = split.reduce(
              (x, y) => x[y],
              globalThis[root_nm] ?? _eval(root_nm)
            );
          }
          let iObj = obj;
          let descriptor = null;
          while (iObj) {
            descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
            if (descriptor) break;
            iObj = Object.getPrototypeOf(iObj);
          }
          if (!descriptor || descriptor?.configurable === false)
            throw new Error(
              `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`
            );
          let original = null;
          const wrapper = chain ?? (type.toUpperCase?.() != "OVERRIDE" && type != 3) ? function(...args) {
            return fn.call(this, original.bind(this), ...bind2, ...args);
          } : function(...args) {
            return fn.call(this, ...bind2, ...args);
          };
          if (!is_setter) {
            if (descriptor.value) {
              original = descriptor.value;
              descriptor.value = wrapper;
            } else {
              original = descriptor.get;
              descriptor.get = wrapper;
            }
          } else {
            if (!descriptor.set)
              throw new Error(
                `libWrapper Shim: '${target}' does not have a setter`
              );
            original = descriptor.set;
            descriptor.set = wrapper;
          }
          descriptor.configurable = true;
          Object.defineProperty(obj, fn_name, descriptor);
        }
      };
    });
    function registerLibwrappers() {
      libWrapper.register(CONSTANTS.MODULE_NAME, "PIXI.BaseImageResource.prototype.upload", PIXIUPLOAD);
    }
    function PIXIUPLOAD(wrapped, ...args) {
      let baseTexture = args[1];
      if (baseTexture.sequencer_patched || !game.settings.get(CONSTANTS.MODULE_NAME, "enable-global-fix-pixi")) {
        return wrapped(...args);
      }
      let source = args[3];
      source = source || this.source;
      const isVideo = !!source.videoWidth;
      if (isVideo) {
        baseTexture.alphaMode = PIXI.ALPHA_MODES.PREMULTIPLIED_ALPHA;
        baseTexture.sequencer_patched = true;
      }
      return wrapped(...args);
    }
    async function runMigrations() {
      const sortedMigrations = Object.entries(migrations).sort((a, b) => {
        return foundry.utils.isNewerVersion(b[0], a[0]) ? -1 : 1;
      });
      for (const [version, migration] of sortedMigrations) {
        try {
          await migration(version);
        } catch (err) {
          custom_warning(
            "Sequencer",
            `Something went wrong when migrating to version ${version}. Please check the console for the error!`,
            true
          );
          console.error(err);
        }
      }
    }
    function getSequencerEffectTokens(version, tokenFilter = false) {
      return Array.from(game.scenes).map((scene) => [
        scene,
        Array.from(scene.tokens).filter((token) => token.isOwner).filter((token, index) => {
          if (tokenFilter) {
            return tokenFilter(token, index);
          }
          const effects = foundry.utils.getProperty(token, CONSTANTS.EFFECTS_FLAG) ?? [];
          const effectsOutOfDate = effects.filter(
            (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
          );
          return effectsOutOfDate.length;
        })
      ]).filter(([_, tokens]) => tokens.length);
    }
    function getSequencerEffectActors(version, actorFilter = false) {
      return Array.from(game.actors).filter((actor) => actor.isOwner).filter((actor, index) => {
        if (actorFilter) {
          return actorFilter(actor, index);
        }
        const effects = foundry.utils.getProperty(actor, CONSTANTS.EFFECTS_FLAG) ?? [];
        const effectsOutOfDate = effects.filter(
          (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
        );
        return effectsOutOfDate.length;
      });
    }
    const migrations = {
      "3.0.0": async (version) => {
        const actorsToUpdate = getSequencerEffectActors(version, (actor) => {
          const effects = foundry.utils.getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
          const effectsOutOfDate = effects.filter(
            (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
          );
          return effectsOutOfDate.length;
        });
        const actorUpdateArray = actorsToUpdate.map((actor) => {
          const effectsToMoveFromTokenPrototype = foundry.utils.getProperty(
            actor.prototypeToken,
            CONSTANTS.EFFECTS_FLAG
          ).filter(([_, effect]) => {
            return effect.persistOptions?.persistTokenPrototype;
          }).map(([id, effect]) => {
            effect.flagVersion = version;
            return [id, effect];
          });
          const effectsToKeepOnTokenPrototype = foundry.utils.getProperty(
            actor.prototypeToken,
            CONSTANTS.EFFECTS_FLAG
          ).filter(([_, effect]) => {
            return !effect.persistOptions?.persistTokenPrototype;
          }).map(([id, effect]) => {
            effect.flagVersion = version;
            return [id, effect];
          });
          return {
            _id: actor.id,
            [CONSTANTS.EFFECTS_FLAG]: effectsToMoveFromTokenPrototype,
            ["prototypeToken." + CONSTANTS.EFFECTS_FLAG]: effectsToKeepOnTokenPrototype
          };
        });
        const tokensOnScenes = getSequencerEffectTokens(version, (t) => {
          let actor;
          try {
            actor = t.actor;
          } catch (err) {
            return false;
          }
          const effects = foundry.utils.getProperty(t, CONSTANTS.EFFECTS_FLAG) ?? [];
          const prototypeTokenEffects = foundry.utils.getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
          const effectsOutOfDate = effects.filter(
            (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
          );
          const prototypeEffectsOutOfDate = prototypeTokenEffects.filter(
            (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
          );
          return t.actorLink && (effectsOutOfDate.length || prototypeEffectsOutOfDate.length);
        });
        for (const [scene, tokens] of tokensOnScenes) {
          const updates = [];
          for (const token of tokens) {
            const effectsToKeepOnToken = foundry.utils.getProperty(token, CONSTANTS.EFFECTS_FLAG).filter(([_, effect]) => {
              return !effect.persistOptions?.persistTokenPrototype;
            }).map(([id, effect]) => {
              effect.flagVersion = version;
              return [id, effect];
            });
            updates.push({
              _id: token.id,
              [CONSTANTS.EFFECTS_FLAG]: effectsToKeepOnToken
            });
          }
          if (updates.length) {
            debug(
              `Sequencer | Updated ${updates.length} tokens' effects on scene ${scene.id} to version ${version}`
            );
            await scene.updateEmbeddedDocuments("Token", updates);
          }
        }
        if (actorUpdateArray.length) {
          debug(
            `Sequencer | Updated ${actorUpdateArray.length} actors' effects to version ${version}`
          );
          await Actor.updateDocuments(actorUpdateArray);
        }
      },
      "3.4.4": async (version) => {
        const actorsToUpdate = getSequencerEffectActors(version, (actor) => {
          const effects = foundry.utils.getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
          const effectsOutOfDate = effects.filter(
            (e) => foundry.utils.isNewerVersion(version, e[1].flagVersion)
          );
          return effectsOutOfDate.length;
        });
        const actorUpdateArray = actorsToUpdate.map((actor) => {
          const actorEffects = foundry.utils.getProperty(actor, CONSTANTS.EFFECTS_FLAG) ?? [];
          const prototypeTokenEffects = foundry.utils.getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
          return {
            "_id": actor.id,
            ["prototypeToken." + CONSTANTS.REMOVE_EFFECTS_FLAG]: null,
            [CONSTANTS.EFFECTS_FLAG]: actorEffects.concat(prototypeTokenEffects)
          };
        });
        if (actorUpdateArray.length) {
          debug(
            `Sequencer | Updated ${actorUpdateArray.length} actors' effects to version ${version}`
          );
          await Actor.updateDocuments(actorUpdateArray);
        }
      }
    };
    class TokenCrosshairsDocument extends CrosshairsDocument {
      /**
       * @inheritdoc
       */
      constructor(tokenPlaceable, context = {}, crosshair = {}, callbacks = {}) {
        const tokenDoc = tokenPlaceable.document;
        const { distance, size } = context.parent.grid;
        const rayBounds = new Ray(
          { x: 0, y: 0 },
          { x: tokenDoc.width * distance, y: tokenDoc.height * distance }
        );
        const initial = {
          t: "rect",
          "icon.display": false,
          direction: Math.toDegrees(rayBounds.angle),
          distance: rayBounds.distance
        };
        const defaultCrosshair = foundry.utils.mergeObject(
          TokenCrosshairsDocument.defaultConfig,
          {
            distanceMinMax: {
              min: rayBounds.distance,
              max: rayBounds.distance
            },
            location: {
              offset: {
                x: tokenDoc.width * size / -2,
                y: tokenDoc.height * size / -2
              }
            },
            token: tokenPlaceable
          }
        );
        super(initial, context, foundry.utils.mergeObject(defaultCrosshair, crosshair), callbacks);
      }
      static get defaultConfig() {
        return foundry.utils.mergeObject(super.defaultConfig, {
          gridHighlight: false,
          snap: {
            position: CONST.GRID_SNAPPING_MODES.VERTEX
          },
          label: {
            display: false
          },
          lockDrag: true,
          alpha: 0.5
        });
      }
      static get placeableClass() {
        return TokenCrosshair;
      }
    }
    class TokenCrosshair extends CrosshairsPlaceable {
      #clonedToken = false;
      #tokenRotation = 0;
      /**
       * @override
       */
      _refreshTemplate() {
        this.template.clear();
        this.#clonedToken.document.x = this.x;
        this.#clonedToken.document.y = this.y;
        this.#clonedToken.document.rotation = this.#tokenRotation;
        this.#clonedToken.document.alpha = this.crosshair.alpha;
        this.#clonedToken.renderFlags.set({ refreshPosition: true, refreshRotation: true, refreshMesh: true });
        this.#clonedToken.initializeSources();
      }
      /**
       * @override
       */
      async draw() {
        this.#clonedToken = this.crosshair.token.clone();
        this.#tokenRotation = this.#clonedToken.document.rotation;
        this.#clonedToken.visible = false;
        this.layer.preview.addChild(this.#clonedToken);
        await this.#clonedToken.draw().then((c) => c.visible = true);
        return super.draw();
      }
      _destroy(options = {}) {
        super._destroy(options);
        this.#clonedToken?.destroy();
      }
      updateDirection(evt) {
        if (this.crosshair.lockManualRotation) return;
        const scrollDelta = Math.sign(evt.deltaY);
        let delta = this.crosshair.snap.direction ? this.crosshair.snap.direction * scrollDelta : scrollDelta * 10;
        if (delta < 0) delta += 360;
        if (delta > 360) delta -= 360;
        this.#tokenRotation += delta;
      }
      _onConfirm(evt) {
        evt.preventDefault();
        canvas.mouseInteractionManager.cancel(evt);
        if (this.isDrag) {
          this.isDrag = false;
          canvas.mouseInteractionManager.reset({
            interactionData: true,
            state: false
          });
          return;
        }
        this.document.updateSource({
          direction: this.#tokenRotation
        });
        return super._onConfirm(evt);
      }
    }
    class Crosshair {
      static PLACEMENT_RESTRICTIONS = CONSTANTS.PLACEMENT_RESTRICTIONS;
      static CALLBACKS = CONSTANTS.CALLBACKS;
      /**
       * Show a configurable crosshair
       *
       * @param {CrosshairData/Object} config
       * @param {CrosshairCallbackData/Object} callbacks
       * @returns {Promise}
       */
      static show(config = {}, callbacks = {}) {
        const reticle = new CrosshairsDocument({
          t: config.t ?? CONST.MEASURED_TEMPLATE_TYPES.CIRCLE,
          distance: config?.distance ?? canvas.grid.distance / 2,
          width: config?.width ?? canvas.grid.distance,
          borderColor: config.borderColor ?? "#000000",
          fillColor: config.fillColor ?? game.user.color,
          texture: config.texture,
          angle: config.angle ?? 53.13,
          // Default for Foundry, it seems?
          direction: config.direction ?? 0
        }, {
          parent: canvas.scene
        }, foundry.utils.mergeObject(CrosshairsDocument.defaultConfig, config), callbacks);
        return reticle.show();
      }
      /**
       * Show a configurable crosshair based a PlaceableObject
       *
       * @param {PlaceableObject} obj
       * @param {CrosshairData/Object} config
       * @param {CrosshairCallbackData/Object} callbacks
       * @returns {Promise}
       */
      static showToken(obj, config = {}, callbacks = {}) {
        const placeable = obj instanceof FoundryShim.PlaceableObject ? obj : obj.object;
        const controlled = placeable.controlled;
        placeable.release();
        const reticle = new TokenCrosshairsDocument(placeable, {
          parent: canvas.scene
        }, config, callbacks);
        return reticle.show().finally(() => {
          if (controlled) placeable.control();
        });
      }
      /**
       * @param {CrosshairsDocument} crosshair
       * @param {String/Array<string>} types
       * @param {(object: PlaceableObject, crosshair: CrosshairsDocument, shape: PIXI.Graphics) => boolean} filterMethod
       * @returns {Array<Document>/Record<String, Array<Document>>}
       */
      static collect(crosshair, types = "Token", filterMethod = this.containsCenter) {
        const typesArray = Array.isArray(types) ? types : [types];
        const crosshairDoc = crosshair instanceof CrosshairsPlaceable ? crosshair.document : crosshair;
        const shape = crosshairDoc.getCrosshairShape();
        shape.x = crosshair.x;
        shape.y = crosshair.y;
        const result = typesArray.reduce((acc, embeddedName) => {
          const collection = crosshairDoc.parent.getEmbeddedCollection(embeddedName);
          acc[embeddedName] = collection.filter((document2) => {
            return filterMethod(document2.object, crosshairDoc, shape);
          });
          return acc;
        }, {});
        return Array.isArray(types) ? result : result[types];
      }
      static containsCenter(placeable, crosshair, shape) {
        return shape.contains(placeable.center.x, placeable.center.y);
      }
    }
    function create_fragment(ctx) {
      let div1;
      return {
        c() {
          div1 = element("div");
          div1.innerHTML = `<p class="header svelte-seq-cwk6bd"><strong>Sequencer is entering a new phase of development</strong></p> <p class="svelte-seq-cwk6bd">Foundry VTT continues to change, and keeping Sequencer working well across new major versions takes ongoing
		effort. To properly support Foundry v14 and future releases, Sequencer will have to be re-written and undergo
		a long-overdue user interface update.</p> <p class="svelte-seq-cwk6bd">Planned improvements include:</p> <ul><li>Improvements to the renderer &amp; effects</li> <li>Support for copying tokens with token rings</li> <li>Dark mode and light mode support</li> <li>Cleanup of older UI and systems for better stability</li></ul> <p class="svelte-seq-cwk6bd">Sequencer will remain <strong>free and fully functional</strong>. Critical fixes and Foundry compatibility updates
		will always be
		available to everyone.</p> <p class="svelte-seq-cwk6bd">However, if Sequencer is useful to you and you would like to support this next phase of development, you can do so
		here:</p> <div class="sequencer-support svelte-seq-cwk6bd"><span><a class="sequencer-clickable-link svelte-seq-cwk6bd" href="https://www.patreon.com/cw/fantasycomputerworks"><i class="fa-brands fa-patreon"></i> <span>Support us on Patreon</span></a></span></div> <p class="svelte-seq-cwk6bd">Your support helps fund maintenance, UI improvements, and long-term sustainability for Sequencer and our other
		free tools.</p> <p class="svelte-seq-cwk6bd">Thank you for using Sequencer and for supporting the Foundry community.</p> <p class="svelte-seq-cwk6bd">- Fantasy Computerworks</p>`;
          attr(div1, "class", "svelte-seq-cwk6bd");
        },
        m(target, anchor) {
          insert(target, div1, anchor);
        },
        p: noop,
        i: noop,
        o: noop,
        d(detaching) {
          if (detaching) {
            detach(div1);
          }
        }
      };
    }
    class Support_dialog extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, null, create_fragment, safe_not_equal, {});
      }
    }
    let moduleValid = false;
    let moduleReady = false;
    let canvasReady = false;
    Hooks.once("init", async function() {
      if (!game.modules.get("socketlib")?.active) return;
      moduleValid = true;
      CONSTANTS.IS_V13 = foundry.utils.isNewerVersion(game.version, "13");
      if (!CONSTANTS.IS_V13) {
        CONFIG.Canvas.transcoders.basis = true;
      }
      initializeModule();
      registerSocket();
      if (CONSTANTS.IS_V13) {
        Object.defineProperty(SvelteApp, "defaultOptions", {
          get: () => {
            return foundry.utils.mergeObject(Application.defaultOptions, {
              // Copied directly from TRL except for minWidth and minHeight
              defaultCloseAnimation: true,
              draggable: true,
              focusAuto: true,
              focusKeep: false,
              focusSource: void 0,
              focusTrap: true,
              headerButtonNoClose: false,
              headerButtonNoLabel: false,
              headerIcon: void 0,
              headerNoTitleMinimized: false,
              minHeight: 50,
              // MIN_WINDOW_HEIGHT
              minWidth: 200,
              // MIN_WINDOW_WIDTH
              positionable: true,
              positionInitial: TJSPosition.Initial.browserCentered,
              positionOrtho: true,
              positionValidator: TJSPosition.Validators.transformWindow,
              sessionStorage: void 0,
              svelte: void 0,
              transformOrigin: "top left"
            }, { inPlace: false });
          }
        });
      }
    });
    Hooks.once("socketlib.ready", registerSocket);
    Hooks.once("ready", async function() {
      if (!game.modules.get("socketlib")?.active) {
        moduleValid = false;
        ui.notifications.error(
          "Sequencer - Sequencer requires the SocketLib module to be active and will not work without it!",
          { console: true }
        );
        return;
      }
      if (!sequencerSocket) {
        moduleValid = false;
        ui.notifications.error(
          "Sequencer - Failed to set up network socket with socketlib, ensure it is installed correctly!",
          { console: true }
        );
        return;
      }
      for (const [name2, func2] of Object.entries(easeFunctions)) {
        if (!FoundryShim.CanvasAnimation[name2]) {
          FoundryShim.CanvasAnimation[name2] = func2;
        }
      }
      if (game.user.isGM) {
        await runMigrations();
        await migrateSettings();
        await PlayerSettings.migrateOldPresets();
      }
      SequencerFoundryReplicator.registerHooks();
      InteractionManager.initialize();
    });
    Hooks.on("canvasTearDown", () => {
      canvasReady = false;
      SequencerEffectManager.tearDownPersists();
    });
    const setupModule = foundry.utils.debounce(() => {
      if (!moduleValid) return;
      if (!moduleReady) {
        moduleReady = true;
        debug("Ready to go!");
        Hooks.callAll("sequencer.ready");
        Hooks.callAll("sequencerReady");
      }
      if (!canvasReady && game.canvas?.ready) {
        canvasReady = true;
        SequencerEffectManager.initializePersistentEffects();
      }
    }, 25);
    Hooks.on("canvasReady", () => {
      setTimeout(() => {
        setupModule();
      }, 450);
    });
    Hooks.on("refreshToken", setupModule);
    Hooks.on("refreshDrawing", setupModule);
    Hooks.on("refreshTile", setupModule);
    Hooks.on("refreshMeasuredTemplate", setupModule);
    function initializeModule() {
      window.Sequence = Sequence$1;
      window.Sequencer = {
        Player: EffectPlayer,
        Presets: SequencerPresets,
        Database: SequencerDatabase,
        DatabaseViewer: DatabaseViewerApp,
        Preloader: SequencerPreloader,
        EffectManager: SequencerEffectManager,
        SoundManager: SequencerSoundManager,
        SectionManager: sectionManager,
        registerEase,
        BaseSection: Section,
        CONSTANTS: {
          EASE
        },
        Helpers: {
          wait: wait$1,
          clamp: clamp$1,
          interpolate,
          random_float_between,
          random_int_between,
          shuffle_array,
          random_array_element,
          random_object_element,
          make_array_unique
        },
        Crosshair
      };
      registerSettings();
      registerLayers();
      registerHotkeys();
      registerLibwrappers();
      registerBatchShader();
      SequencerEffectManager.setup();
      SequencerAboveUILayer.setup();
      PluginsManager.initialize();
    }
    Hooks.once("ready", async () => {
      displaySupportDialog();
      displaySequencerWelcome();
    });
    async function displaySupportDialog() {
      const shown = game.settings.get(CONSTANTS.MODULE_NAME, "support-dialog-shown");
      if (!game.user.isGM || shown) return;
      await game.settings.set(CONSTANTS.MODULE_NAME, "support-dialog-shown", true);
      return TJSDialog.prompt({
        title: "Sequencer",
        label: "Okay",
        content: {
          class: Support_dialog
        }
      }, {
        height: "auto",
        width: 500
      });
    }
    async function displaySequencerWelcome() {
      const version = game.settings.get(CONSTANTS.MODULE_NAME, "welcome-shown-version");
      if (!game.user.isGM || !foundry.utils.isNewerVersion(version, game.version)) return;
      await game.settings.set(CONSTANTS.MODULE_NAME, "welcome-shown-version", game.version);
      const chatMessages = game.messages.filter((message) => {
        return message.content.includes("sequencer-welcome");
      }).map((message) => message.id);
      if (chatMessages.length) {
        await ChatMessage.deleteDocuments(chatMessages.slice(0, -1));
      }
      await ChatMessage.create({
        content: `
<div class="sequencer-welcome">
<img src="modules/sequencer/images/sequencer.png"/>
<div class="sequencer-divider"></div>
<p>Sequencer can only remain open, free, and regularly updated with the support of the Foundry community.</p>
<p>Please consider supporting us if you enjoy Foundry & visual effects!</p>
<div class="sequencer-divider"></div>
<p><a target="_blank" href="https://fantasycomputer.works/">Website</a> | <a target="_blank" href="https://fantasycomputer.works/FoundryVTT-Sequencer/#/">Docs</a> | <a target="_blank" href="https://discord.gg/qFHQUwBZAz">Discord</a> | <a target="_blank" href="https://ko-fi.com/fantasycomputerworks">Donate</a></p>
</div>`
      });
    }
    Hooks.once("monaco-editor.ready", registerTypes);
  }
});
export default require_sequencer();
//# sourceMappingURL=sequencer.js.map
