const module = "";
const CONSTANTS = {
  MODULE_NAME: "sequencer",
  FLAG_NAME: "effects",
  COLOR: {
    PRIMARY: 15615023,
    SECONDARY: 6298186,
    TERTIARY: 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
  }
};
CONSTANTS.INTEGRATIONS = {};
CONSTANTS.INTEGRATIONS.ISOMETRIC = {};
CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE = false;
CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME = "grape_juice-isometrics";
CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED = `flags.${CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME}.is_isometric`;
CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_FLAG = `flags.${CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME}.original_image_projection_type`;
CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_TYPES = {
  TOPDOWN: "topdown",
  TRUE: "true_isometric",
  DIAMETRIC: "diametric"
};
CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION = Math.sqrt(3);
CONSTANTS.INTEGRATIONS.ISOMETRIC.DIMETRIC_CONVERSION = 2 / CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION;
CONSTANTS.INTEGRATIONS.ISOMETRIC.DUNGEON_BUILDER_CONVERSION = 278 / 154 / CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION;
CONSTANTS.EFFECTS_FLAG = `flags.${CONSTANTS.MODULE_NAME}.${CONSTANTS.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 } = FilePicker.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 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 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(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 = from_uuid_fast(inObjectId);
    if (obj)
      return obj;
    tryUUID = false;
  }
  return get_all_documents_from_scene(inSceneId).find((obj) => {
    return get_object_identifier(obj, tryUUID) === inObjectId;
  });
}
function from_uuid_fast(uuid) {
  let parts = uuid.split(".");
  let doc;
  const [docName, docId] = parts.slice(0, 2);
  parts = parts.slice(2);
  const collection = CONFIG[docName].collection.instance;
  doc = collection.get(docId);
  while (doc && parts.length > 1) {
    const [embeddedName, embeddedId] = parts.slice(0, 2);
    if (embeddedName === "SequencerEffect") {
      if (game.user.viewedScene !== docId) {
        let effects = doc.getFlag(CONSTANTS.MODULE_NAME, CONSTANTS.FLAG_NAME);
        doc = new Map(effects).get(embeddedId);
      } else {
        doc = Sequencer.EffectManager.getEffects({ effect: docId })?.[0];
      }
    } else {
      doc = doc.getEmbeddedDocument(embeddedName, embeddedId);
    }
    parts = parts.slice(2);
  }
  return doc || null;
}
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.templates?.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);
}
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 = 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(/[^A-Za-z0-9 .*_-]/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 noop() {
}
const identity = (x) => x;
function assign(tar, src) {
  for (const k in src)
    tar[k] = src[k];
  return 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 (!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) {
    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 && root.host) {
    return root;
  }
  return node.ownerDocument;
}
function append_empty_stylesheet(node) {
  const style_element = element("style");
  append_stylesheet(get_root_for_style(node), style_element);
  return style_element.sheet;
}
function append_stylesheet(node, style) {
  append(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(name) {
  return document.createElement(name);
}
function svg_element(name) {
  return document.createElementNS("http://www.w3.org/2000/svg", name);
}
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.wholeText !== data)
    text2.data = 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, important ? "important" : "");
  }
}
function select_option(select, value) {
  for (let i = 0; i < select.options.length; i += 1) {
    const option = select.options[i];
    if (option.__value === value) {
      option.selected = true;
      return;
    }
  }
  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") || select.options[0];
  return selected_option && selected_option.__value;
}
function select_multiple_value(select) {
  return [].map.call(select.querySelectorAll(":checked"), (option) => option.__value);
}
function toggle_class(element2, name, toggle) {
  element2.classList[toggle ? "add" : "remove"](name);
}
function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) {
  const e = document.createEvent("CustomEvent");
  e.initCustomEvent(type, bubbles, cancelable, detail);
  return e;
}
class HtmlTag {
  constructor(is_svg = false) {
    this.is_svg = false;
    this.is_svg = is_svg;
    this.e = this.n = null;
  }
  c(html) {
    this.h(html);
  }
  m(html, target, anchor = null) {
    if (!this.e) {
      if (this.is_svg)
        this.e = svg_element(target.nodeName);
      else
        this.e = element(target.nodeName);
      this.t = target;
      this.c(html);
    }
    this.i(anchor);
  }
  h(html) {
    this.e.innerHTML = html;
    this.n = Array.from(this.e.childNodes);
  }
  i(anchor) {
    for (let i = 0; i < this.n.length; i += 1) {
      insert(this.t, this.n[i], anchor);
    }
  }
  p(html) {
    this.d();
    this.h(html);
    this.i(this.a);
  }
  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 name = `__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[name]) {
    rules[name] = true;
    stylesheet.insertRule(`@keyframes ${name} ${rule}`, stylesheet.cssRules.length);
  }
  const animation2 = node.style.animation || "";
  node.style.animation = `${animation2 ? `${animation2}, ` : ""}${name} ${duration}ms linear ${delay}ms 1 both`;
  active += 1;
  return name;
}
function delete_rule(node, name) {
  const previous = (node.style.animation || "").split(", ");
  const next = previous.filter(
    name ? (anim) => anim.indexOf(name) < 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, 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);
}
const dirty_components = [];
const binding_callbacks = [];
const render_callbacks = [];
const flush_callbacks = [];
const resolved_promise = 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);
  }
}
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;
  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"));
    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 && config.tick) {
        config.tick(1, 0);
      }
      if (running) {
        if (animation_name)
          delete_rule(node, animation_name);
        running = false;
      }
    }
  };
}
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();
  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 if (dynamic) {
      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]);
  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, name, callback) {
  const index = component.$$.props[name];
  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, customElement) {
  const { fragment, after_update } = component.$$;
  fragment && fragment.m(target, anchor);
  if (!customElement) {
    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) {
    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, 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, options.customElement);
    flush();
  }
  set_current_component(parent_component);
}
class SvelteComponent {
  $destroy() {
    destroy_component(this, 1);
    this.$destroy = noop;
  }
  $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);
    };
  }
  $set($$props) {
    if (this.$$set && !is_empty($$props)) {
      this.$$.skip_bound = true;
      this.$$set($$props);
      this.$$.skip_bound = false;
    }
  }
}
const s_TAG_OBJECT = "[object Object]";
function deepMerge(target = {}, ...sourceObj) {
  if (Object.prototype.toString.call(target) !== s_TAG_OBJECT) {
    throw new TypeError(`deepMerge error: 'target' is not an 'object'.`);
  }
  for (let cntr = 0; cntr < sourceObj.length; cntr++) {
    if (Object.prototype.toString.call(sourceObj[cntr]) !== s_TAG_OBJECT) {
      throw new TypeError(`deepMerge error: 'sourceObj[${cntr}]' is not an 'object'.`);
    }
  }
  return _deepMerge(target, ...sourceObj);
}
function isIterable(value) {
  if (value === null || value === void 0 || typeof value !== "object") {
    return false;
  }
  return typeof value[Symbol.iterator] === "function";
}
function isObject(value) {
  return value !== null && typeof value === "object";
}
function isPlainObject(value) {
  if (Object.prototype.toString.call(value) !== s_TAG_OBJECT) {
    return false;
  }
  const prototype = Object.getPrototypeOf(value);
  return prototype === null || prototype === Object.prototype;
}
function safeAccess(data, accessor, defaultValue = void 0) {
  if (typeof data !== "object") {
    return defaultValue;
  }
  if (typeof accessor !== "string") {
    return defaultValue;
  }
  const access = accessor.split(".");
  for (let cntr = 0; cntr < access.length; cntr++) {
    if (typeof data[access[cntr]] === "undefined" || data[access[cntr]] === null) {
      return defaultValue;
    }
    data = data[access[cntr]];
  }
  return data;
}
function safeSet(data, accessor, value, operation = "set", createMissing = true) {
  if (typeof data !== "object") {
    throw new TypeError(`safeSet Error: 'data' is not an 'object'.`);
  }
  if (typeof accessor !== "string") {
    throw new TypeError(`safeSet Error: 'accessor' is not a 'string'.`);
  }
  const access = accessor.split(".");
  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;
          break;
        case "div":
          data[access[cntr]] /= value;
          break;
        case "mult":
          data[access[cntr]] *= value;
          break;
        case "set":
          data[access[cntr]] = value;
          break;
        case "set-undefined":
          if (typeof data[access[cntr]] === "undefined") {
            data[access[cntr]] = value;
          }
          break;
        case "sub":
          data[access[cntr]] -= value;
          break;
      }
    } else {
      if (createMissing && typeof data[access[cntr]] === "undefined") {
        data[access[cntr]] = {};
      }
      if (data[access[cntr]] === null || typeof data[access[cntr]] !== "object") {
        return false;
      }
      data = data[access[cntr]];
    }
  }
  return true;
}
function _deepMerge(target = {}, ...sourceObj) {
  for (let cntr = 0; cntr < sourceObj.length; cntr++) {
    const obj = sourceObj[cntr];
    for (const prop in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        if (prop.startsWith("-=")) {
          delete target[prop.slice(2)];
          continue;
        }
        target[prop] = Object.prototype.hasOwnProperty.call(target, prop) && target[prop]?.constructor === Object && obj[prop]?.constructor === Object ? _deepMerge({}, target[prop], obj[prop]) : obj[prop];
      }
    }
  }
  return target;
}
class A11yHelper {
  /**
   * Apply focus to the HTMLElement targets in a given A11yFocusSource data object. An iterable list `options.focusEl`
   * can contain HTMLElements 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" ? focusOpts.debug : false;
      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 instanceof HTMLElement && 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 instanceof HTMLElement && 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 {HTMLElement|Document} [element=document] - Optional element to start query.
   *
   * @param {object} [options] - Optional parameters.
   *
   * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
   *
   * @param {Set<HTMLElement>} [options.ignoreElements] - Set of elements to ignore.
   *
   * @returns {HTMLElement} 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 {HTMLElement|Document} [element=document] Optional element to start query.
   *
   * @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.
   *
   * @param {Set<HTMLElement>}  [options.ignoreElements] - Set of elements to ignore.
   *
   * @param {string}            [options.selectors] - Custom list of focusable selectors for `querySelectorAll`.
   *
   * @returns {Array<HTMLElement>} Child keyboard focusable
   */
  static getFocusableElements(element2 = document, { anchorHref = true, ignoreClasses, ignoreElements, selectors } = {}) {
    if (!(element2 instanceof HTMLElement) && !(element2 instanceof Document)) {
      throw new TypeError(`'element' is not a HTMLElement 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 && !(ignoreElements instanceof Set)) {
      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);
    const allElements = [...element2.querySelectorAll(selectorQuery)];
    if (ignoreElements && ignoreClasses) {
      return 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) {
      return 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) {
      return 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 {
      return allElements.filter((el) => {
        return el.style.display !== "none" && el.style.visibility !== "hidden" && !el.hasAttribute("disabled") && !el.hasAttribute("inert") && el.getAttribute("aria-hidden") !== "true";
      });
    }
  }
  /**
   * 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 {HTMLElement|string} [options.focusEl] - A specific HTMLElement 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
   *
   * TODO: Evaluate / test against touch input devices.
   */
  static getFocusSource({ event, x, y, focusEl, debug: debug2 = false }) {
    if (focusEl !== void 0 && !(focusEl instanceof HTMLElement) && typeof focusEl !== "string") {
      throw new TypeError(
        `A11yHelper.getFocusSource error: 'focusEl' is not a HTMLElement or string.`
      );
    }
    if (debug2 !== void 0 && typeof debug2 !== "boolean") {
      throw new TypeError(`A11yHelper.getFocusSource error: 'debug' is not a boolean.`);
    }
    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.`);
      }
      return {
        debug: debug2,
        focusEl: focusEl !== void 0 ? [focusEl] : void 0,
        x,
        y
      };
    }
    if (!(event instanceof KeyboardEvent) && !(event instanceof MouseEvent)) {
      throw new TypeError(`A11yHelper.getFocusSource error: 'event' is not a KeyboardEvent or MouseEvent.`);
    }
    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.`);
    }
    const targetEl = event.target;
    if (!(targetEl instanceof HTMLElement)) {
      throw new TypeError(`A11yHelper.getFocusSource error: 'event.target' is not an HTMLElement.`);
    }
    const result = { debug: debug2 };
    if (event instanceof MouseEvent) {
      if (event?.button !== 2 && event.type === "contextmenu") {
        const rect = targetEl.getBoundingClientRect();
        result.x = x ?? rect.left + rect.width / 2;
        result.y = y ?? rect.top + rect.height / 2;
        result.focusEl = focusEl !== void 0 ? [targetEl, focusEl] : [targetEl];
        result.source = "keyboard";
      } else {
        result.x = x ?? event.pageX;
        result.y = y ?? event.pageY;
        result.focusEl = focusEl !== void 0 ? [focusEl] : void 0;
      }
    } else {
      const rect = targetEl.getBoundingClientRect();
      result.x = x ?? rect.left + rect.width / 2;
      result.y = y ?? rect.top + rect.height / 2;
      result.focusEl = focusEl !== void 0 ? [targetEl, focusEl] : [targetEl];
      result.source = "keyboard";
    }
    return result;
  }
  /**
   * Returns first focusable element within a specified element.
   *
   * @param {HTMLElement|Document} [element=document] - Optional element to start query.
   *
   * @param {object} [options] - Optional parameters.
   *
   * @param {Iterable<string>} [options.ignoreClasses] - Iterable list of classes to ignore elements.
   *
   * @param {Set<HTMLElement>} [options.ignoreElements] - Set of elements to ignore.
   *
   * @returns {HTMLElement} First 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 {HTMLElement} [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 instanceof HTMLElement) || el?.hidden || !el?.isConnected) {
      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 = el.getAttribute("tabindex");
    const tabindexFocusable = typeof tabindexAttr === "string" && tabindexAttr !== "-1";
    const isAnchor = el instanceof HTMLAnchorElement;
    if (contenteditableFocusable || tabindexFocusable || isAnchor || el instanceof HTMLButtonElement || el instanceof HTMLDetailsElement || el instanceof HTMLEmbedElement || el instanceof HTMLIFrameElement || el instanceof HTMLInputElement || el instanceof HTMLObjectElement || el instanceof HTMLSelectElement || el instanceof HTMLTextAreaElement) {
      if (isAnchor && anchorHref && 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 {HTMLElement|string}   data - Either an HTMLElement or selector string.
   *
   * @returns {boolean} Is valid focus source.
   */
  static isFocusSource(data) {
    return data instanceof HTMLElement || typeof data === "string";
  }
}
class StyleManager {
  /** @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 (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 StyleManager instance into a new document.
   *
   * Note: This is used to support the `PopOut` module.
   *
   * @param {Document} [document] Target browser document to clone into.
   *
   * @returns {StyleManager} New style manager instance.
   */
  clone(document2 = globalThis.document) {
    const newStyleManager = new StyleManager({
      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 {Object<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);
  }
}
const s_REGEX = /(\d+)\s*px/;
function styleParsePixels(value) {
  if (typeof value !== "string") {
    return void 0;
  }
  const isPixels = s_REGEX.test(value);
  const number = parseInt(value);
  return isPixels && Number.isFinite(number) ? number : void 0;
}
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 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");
}
function isSvelteComponent(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 !== void 0 ? typeof comp.prototype.$destroy === "function" && typeof comp.prototype.$on === "function" : (
    // client-side
    typeof comp.render === "function"
  );
}
async function outroAndDestroy(instance2) {
  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();
    }
  });
}
function parseSvelteConfig(config, thisArg = void 0) {
  if (typeof config !== "object") {
    throw new TypeError(`parseSvelteConfig - 'config' is not an object:
${JSON.stringify(config)}.`);
  }
  if (!isSvelteComponent(config.class)) {
    throw new TypeError(
      `parseSvelteConfig - 'class' is not a Svelte component constructor for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.hydrate !== void 0 && typeof config.hydrate !== "boolean") {
    throw new TypeError(
      `parseSvelteConfig - 'hydrate' is not a boolean for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.intro !== void 0 && typeof config.intro !== "boolean") {
    throw new TypeError(
      `parseSvelteConfig - 'intro' is not a boolean for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.target !== void 0 && typeof config.target !== "string" && !(config.target instanceof HTMLElement) && !(config.target instanceof ShadowRoot) && !(config.target instanceof DocumentFragment)) {
    throw new TypeError(
      `parseSvelteConfig - 'target' is not a string, HTMLElement, ShadowRoot, or DocumentFragment for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.anchor !== void 0 && typeof config.anchor !== "string" && !(config.anchor instanceof HTMLElement) && !(config.anchor instanceof ShadowRoot) && !(config.anchor instanceof DocumentFragment)) {
    throw new TypeError(
      `parseSvelteConfig - 'anchor' is not a string, HTMLElement, ShadowRoot, or DocumentFragment for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.context !== void 0 && typeof config.context !== "function" && !(config.context instanceof Map) && typeof config.context !== "object") {
    throw new TypeError(
      `parseSvelteConfig - 'context' is not a Map, function or object for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.selectorTarget !== void 0 && typeof config.selectorTarget !== "string") {
    throw new TypeError(
      `parseSvelteConfig - 'selectorTarget' is not a string for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.options !== void 0 && typeof config.options !== "object") {
    throw new TypeError(
      `parseSvelteConfig - 'options' is not an object for config:
${JSON.stringify(config)}.`
    );
  }
  if (config.options !== void 0) {
    if (config.options.injectApp !== void 0 && typeof config.options.injectApp !== "boolean") {
      throw new TypeError(
        `parseSvelteConfig - 'options.injectApp' is not a boolean for config:
${JSON.stringify(config)}.`
      );
    }
    if (config.options.injectEventbus !== void 0 && typeof config.options.injectEventbus !== "boolean") {
      throw new TypeError(
        `parseSvelteConfig - 'options.injectEventbus' is not a boolean for config:
${JSON.stringify(config)}.`
      );
    }
    if (config.options.selectorElement !== void 0 && typeof config.options.selectorElement !== "string") {
      throw new TypeError(
        `parseSvelteConfig - 'selectorElement' is not a string for config:
${JSON.stringify(config)}.`
      );
    }
  }
  const svelteConfig = { ...config };
  delete svelteConfig.options;
  let externalContext = {};
  if (typeof svelteConfig.context === "function") {
    const contextFunc = svelteConfig.context;
    delete svelteConfig.context;
    const result = contextFunc.call(thisArg);
    if (isObject(result)) {
      externalContext = { ...result };
    } else {
      throw new Error(`parseSvelteConfig - 'context' is a function that did not return an object for config:
${JSON.stringify(config)}`);
    }
  } else if (svelteConfig.context instanceof Map) {
    externalContext = Object.fromEntries(svelteConfig.context);
    delete svelteConfig.context;
  } else if (isObject(svelteConfig.context)) {
    externalContext = svelteConfig.context;
    delete svelteConfig.context;
  }
  svelteConfig.props = s_PROCESS_PROPS(svelteConfig.props, thisArg, config);
  if (Array.isArray(svelteConfig.children)) {
    const children2 = [];
    for (let cntr = 0; cntr < svelteConfig.children.length; cntr++) {
      const child = svelteConfig.children[cntr];
      if (!isSvelteComponent(child.class)) {
        throw new Error(`parseSvelteConfig - 'class' is not a Svelte component for child[${cntr}] for config:
${JSON.stringify(config)}`);
      }
      child.props = s_PROCESS_PROPS(child.props, thisArg, config);
      children2.push(child);
    }
    if (children2.length > 0) {
      externalContext.children = children2;
    }
    delete svelteConfig.children;
  } else if (isObject(svelteConfig.children)) {
    if (!isSvelteComponent(svelteConfig.children.class)) {
      throw new Error(`parseSvelteConfig - 'class' is not a Svelte component for children object for config:
${JSON.stringify(config)}`);
    }
    svelteConfig.children.props = s_PROCESS_PROPS(svelteConfig.children.props, thisArg, config);
    externalContext.children = [svelteConfig.children];
    delete svelteConfig.children;
  }
  if (!(svelteConfig.context instanceof Map)) {
    svelteConfig.context = /* @__PURE__ */ new Map();
  }
  svelteConfig.context.set("#external", externalContext);
  return svelteConfig;
}
function s_PROCESS_PROPS(props, thisArg, config) {
  if (typeof props === "function") {
    const result = props.call(thisArg);
    if (isObject(result)) {
      return result;
    } else {
      throw new Error(`parseSvelteConfig - '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(
      `parseSvelteConfig - 'props' is not a function or an object for config:
${JSON.stringify(config)}`
    );
  }
  return {};
}
function hasGetter(object, accessor) {
  if (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;
}
const subscriber_queue = [];
function readable(value, start) {
  return {
    subscribe: writable$1(value, start).subscribe
  };
}
function writable$1(value, start = noop) {
  let stop;
  const subscribers = /* @__PURE__ */ new Set();
  function set(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) {
    set(fn(value));
  }
  function subscribe2(run2, invalidate = noop) {
    const subscriber = [run2, invalidate];
    subscribers.add(subscriber);
    if (subscribers.size === 1) {
      stop = start(set) || noop;
    }
    run2(value);
    return () => {
      subscribers.delete(subscriber);
      if (subscribers.size === 0) {
        stop();
        stop = null;
      }
    };
  }
  return { set, update: update2, subscribe: subscribe2 };
}
function derived(stores, fn, initial_value) {
  const single = !Array.isArray(stores);
  const stores_array = single ? [stores] : stores;
  const auto = fn.length < 2;
  return readable(initial_value, (set) => {
    let inited = false;
    const values = [];
    let pending = 0;
    let cleanup = noop;
    const sync = () => {
      if (pending) {
        return;
      }
      cleanup();
      const result = fn(single ? values[0] : values, set);
      if (auto) {
        set(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 (inited) {
        sync();
      }
    }, () => {
      pending |= 1 << i;
    }));
    inited = true;
    sync();
    return function stop() {
      run_all(unsubscribers);
      cleanup();
    };
  });
}
function isSimpleDeriver(deriver) {
  return deriver.length < 2;
}
function generator(storage2) {
  function readable2(key, value, start) {
    return {
      subscribe: writable2(key, value, start).subscribe
    };
  }
  function writable2(key, value, start = noop) {
    function wrap_start(ogSet) {
      return start(function wrap_set(new_value) {
        if (storage2) {
          storage2.setItem(key, JSON.stringify(new_value));
        }
        return ogSet(new_value);
      });
    }
    if (storage2) {
      const storageValue = storage2.getItem(key);
      try {
        if (storageValue) {
          value = JSON.parse(storageValue);
        }
      } catch (err) {
      }
      storage2.setItem(key, JSON.stringify(value));
    }
    const ogStore = writable$1(value, start ? wrap_start : void 0);
    function set(new_value) {
      if (storage2) {
        storage2.setItem(key, JSON.stringify(new_value));
      }
      ogStore.set(new_value);
    }
    function update2(fn) {
      set(fn(get_store_value(ogStore)));
    }
    function subscribe2(run2, invalidate = noop) {
      return ogStore.subscribe(run2, invalidate);
    }
    return { set, update: update2, subscribe: subscribe2 };
  }
  function derived2(key, stores, fn, initial_value) {
    const single = !Array.isArray(stores);
    const stores_array = single ? [stores] : stores;
    if (storage2 && storage2.getItem(key)) {
      try {
        initial_value = JSON.parse(storage2.getItem(key));
      } catch (err) {
      }
    }
    return readable2(key, initial_value, (set) => {
      let inited = false;
      const values = [];
      let pending = 0;
      let cleanup = noop;
      const sync = () => {
        if (pending) {
          return;
        }
        cleanup();
        const input = single ? values[0] : values;
        if (isSimpleDeriver(fn)) {
          set(fn(input));
        } else {
          const result = fn(input, set);
          cleanup = is_function(result) ? result : noop;
        }
      };
      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() {
        run_all(unsubscribers);
        cleanup();
      };
    });
  }
  return {
    readable: readable2,
    writable: writable2,
    derived: derived2,
    get: get_store_value
  };
}
var storage = typeof window !== "undefined" ? window.sessionStorage : void 0;
var g = generator(storage);
var writable = g.writable;
class TJSSessionStorage {
  /**
   * @type {Map<string, import('svelte/store').Writable>}
   */
  #stores = /* @__PURE__ */ new Map();
  /**
   * Creates a new store for the given key.
   *
   * @param {string}   key - Key to lookup in stores map.
   *
   * @param {boolean}  [defaultValue] - A default value to set for the store.
   *
   * @returns {import('svelte/store').Writable} The new store.
   */
  static #createStore(key, defaultValue = void 0) {
    try {
      const value = sessionStorage.getItem(key);
      if (value !== null) {
        defaultValue = value === "undefined" ? void 0 : JSON.parse(value);
      }
    } catch (err) {
    }
    return writable(key, defaultValue);
  }
  /**
   * Gets a store from the `stores` Map or creates a new store for the key and a given default value.
   *
   * @param {string}               key - Key to lookup in stores map.
   *
   * @param {boolean}              [defaultValue] - A default value to set for the store.
   *
   * @returns {import('svelte/store').Writable} The store for the given key.
   */
  #getStore(key, defaultValue = void 0) {
    let store = this.#stores.get(key);
    if (store === void 0) {
      store = TJSSessionStorage.#createStore(key, defaultValue);
      this.#stores.set(key, store);
    }
    return store;
  }
  /**
   * Get value from the sessionStorage.
   *
   * @param {string}   key - Key to lookup in sessionStorage.
   *
   * @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 = sessionStorage.getItem(key);
    if (storageValue !== null) {
      try {
        value = storageValue === "undefined" ? void 0 : JSON.parse(storageValue);
      } catch (err) {
        value = defaultValue;
      }
    } else if (defaultValue !== void 0) {
      try {
        const newValue = JSON.stringify(defaultValue);
        sessionStorage.setItem(key, newValue === "undefined" ? void 0 : 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.
   *
   * @param {string}   key - Key to lookup in sessionStorage.
   *
   * @param {*}        [defaultValue] - A default value to return if key not present in session storage.
   *
   * @returns {import('svelte/store').Writable} The Svelte store for this key.
   */
  getStore(key, defaultValue) {
    return this.#getStore(key, defaultValue);
  }
  /**
   * Sets the value for the given key in sessionStorage.
   *
   * @param {string}   key - Key to lookup in sessionStorage.
   *
   * @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 session storage.
   *
   * @param {string}   key - Key to lookup in sessionStorage.
   *
   * @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 = !!JSON.parse(sessionStorage.getItem(key));
    } catch (err) {
    }
    const newValue = typeof currentValue === "boolean" ? !currentValue : false;
    store.set(newValue);
    return newValue;
  }
}
function isUpdatableStore(store) {
  if (store === null || store === void 0) {
    return false;
  }
  switch (typeof store) {
    case "function":
    case "object":
      return typeof store.subscribe === "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);
    }
  });
}
function writableDerived(origins, derive, reflect, initial) {
  var childDerivedSetter, originValues, blockNextDerive = false;
  var reflectOldValues = reflect.length >= 2;
  var wrappedDerive = (got, set) => {
    childDerivedSetter = set;
    if (reflectOldValues) {
      originValues = got;
    }
    if (!blockNextDerive) {
      let returned = derive(got, set);
      if (derive.length < 2) {
        set(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;
      }
    );
  }
}
const storeState = writable$1(void 0);
({
  subscribe: storeState.subscribe,
  get: () => game
});
Hooks.once("ready", () => storeState.set(game));
function cubicOut(t) {
  const f = t - 1;
  return f * f * f + 1;
}
function lerp$5(start, end, amount) {
  return (1 - amount) * start + amount * end;
}
function degToRad(deg) {
  return deg * (Math.PI / 180);
}
var EPSILON = 1e-6;
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
var RANDOM = Math.random;
if (!Math.hypot)
  Math.hypot = function() {
    var y = 0, i = arguments.length;
    while (i--) {
      y += arguments[i] * arguments[i];
    }
    return Math.sqrt(y);
  };
function create$6() {
  var out = new ARRAY_TYPE(9);
  if (ARRAY_TYPE != Float32Array) {
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[5] = 0;
    out[6] = 0;
    out[7] = 0;
  }
  out[0] = 1;
  out[4] = 1;
  out[8] = 1;
  return out;
}
function create$5() {
  var out = new ARRAY_TYPE(16);
  if (ARRAY_TYPE != Float32Array) {
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[11] = 0;
    out[12] = 0;
    out[13] = 0;
    out[14] = 0;
  }
  out[0] = 1;
  out[5] = 1;
  out[10] = 1;
  out[15] = 1;
  return out;
}
function clone$5(a) {
  var out = new ARRAY_TYPE(16);
  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;
}
function copy$5(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;
}
function fromValues$5(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
  var out = new ARRAY_TYPE(16);
  out[0] = m00;
  out[1] = m01;
  out[2] = m02;
  out[3] = m03;
  out[4] = m10;
  out[5] = m11;
  out[6] = m12;
  out[7] = m13;
  out[8] = m20;
  out[9] = m21;
  out[10] = m22;
  out[11] = m23;
  out[12] = m30;
  out[13] = m31;
  out[14] = m32;
  out[15] = m33;
  return out;
}
function set$5(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) {
  out[0] = m00;
  out[1] = m01;
  out[2] = m02;
  out[3] = m03;
  out[4] = m10;
  out[5] = m11;
  out[6] = m12;
  out[7] = m13;
  out[8] = m20;
  out[9] = m21;
  out[10] = m22;
  out[11] = m23;
  out[12] = m30;
  out[13] = m31;
  out[14] = m32;
  out[15] = m33;
  return out;
}
function identity$2(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;
}
function transpose(out, a) {
  if (out === a) {
    var a01 = a[1], a02 = a[2], a03 = a[3];
    var a12 = a[6], a13 = a[7];
    var 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;
}
function invert$2(out, a) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
  var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
  var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
  var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  var b00 = a00 * a11 - a01 * a10;
  var b01 = a00 * a12 - a02 * a10;
  var b02 = a00 * a13 - a03 * a10;
  var b03 = a01 * a12 - a02 * a11;
  var b04 = a01 * a13 - a03 * a11;
  var b05 = a02 * a13 - a03 * a12;
  var b06 = a20 * a31 - a21 * a30;
  var b07 = a20 * a32 - a22 * a30;
  var b08 = a20 * a33 - a23 * a30;
  var b09 = a21 * a32 - a22 * a31;
  var b10 = a21 * a33 - a23 * a31;
  var b11 = a22 * a33 - a23 * a32;
  var 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;
}
function adjoint(out, a) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
  var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
  var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
  var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22);
  out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
  out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12);
  out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
  out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
  out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22);
  out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
  out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12);
  out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21);
  out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
  out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11);
  out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
  out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
  out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21);
  out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
  out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11);
  return out;
}
function determinant(a) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
  var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
  var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
  var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  var b00 = a00 * a11 - a01 * a10;
  var b01 = a00 * a12 - a02 * a10;
  var b02 = a00 * a13 - a03 * a10;
  var b03 = a01 * a12 - a02 * a11;
  var b04 = a01 * a13 - a03 * a11;
  var b05 = a02 * a13 - a03 * a12;
  var b06 = a20 * a31 - a21 * a30;
  var b07 = a20 * a32 - a22 * a30;
  var b08 = a20 * a33 - a23 * a30;
  var b09 = a21 * a32 - a22 * a31;
  var b10 = a21 * a33 - a23 * a31;
  var b11 = a22 * a33 - a23 * a32;
  return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
}
function multiply$5(out, a, b) {
  var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
  var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
  var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
  var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
  var b0 = b[0], b1 = b[1], b2 = b[2], 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;
}
function translate$1(out, a, v) {
  var x = v[0], y = v[1], z = v[2];
  var a00, a01, a02, a03;
  var a10, a11, a12, a13;
  var a20, a21, a22, a23;
  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 {
    a00 = a[0];
    a01 = a[1];
    a02 = a[2];
    a03 = a[3];
    a10 = a[4];
    a11 = a[5];
    a12 = a[6];
    a13 = a[7];
    a20 = a[8];
    a21 = a[9];
    a22 = a[10];
    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;
}
function scale$5(out, a, v) {
  var x = v[0], y = v[1], 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;
}
function rotate$1(out, a, rad, axis) {
  var x = axis[0], y = axis[1], z = axis[2];
  var len = Math.hypot(x, y, z);
  var s, c, t;
  var a00, a01, a02, a03;
  var a10, a11, a12, a13;
  var a20, a21, a22, a23;
  var b00, b01, b02;
  var b10, b11, b12;
  var b20, b21, b22;
  if (len < EPSILON) {
    return null;
  }
  len = 1 / len;
  x *= len;
  y *= len;
  z *= len;
  s = Math.sin(rad);
  c = Math.cos(rad);
  t = 1 - c;
  a00 = a[0];
  a01 = a[1];
  a02 = a[2];
  a03 = a[3];
  a10 = a[4];
  a11 = a[5];
  a12 = a[6];
  a13 = a[7];
  a20 = a[8];
  a21 = a[9];
  a22 = a[10];
  a23 = a[11];
  b00 = x * x * t + c;
  b01 = y * x * t + z * s;
  b02 = z * x * t - y * s;
  b10 = x * y * t - z * s;
  b11 = y * y * t + c;
  b12 = z * y * t + x * s;
  b20 = x * z * t + y * s;
  b21 = y * z * t - x * s;
  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;
}
function rotateX$3(out, a, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  var a10 = a[4];
  var a11 = a[5];
  var a12 = a[6];
  var a13 = a[7];
  var a20 = a[8];
  var a21 = a[9];
  var a22 = a[10];
  var 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;
}
function rotateY$3(out, a, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a03 = a[3];
  var a20 = a[8];
  var a21 = a[9];
  var a22 = a[10];
  var 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;
}
function rotateZ$3(out, a, rad) {
  var s = Math.sin(rad);
  var c = Math.cos(rad);
  var a00 = a[0];
  var a01 = a[1];
  var a02 = a[2];
  var a03 = a[3];
  var a10 = a[4];
  var a11 = a[5];
  var a12 = a[6];
  var 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;
}
function fromTranslation$1(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;
}
function 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;
}
function fromRotation$1(out, rad, axis) {
  var x = axis[0], y = axis[1], z = axis[2];
  var len = Math.hypot(x, y, z);
  var s, c, t;
  if (len < EPSILON) {
    return null;
  }
  len = 1 / len;
  x *= len;
  y *= len;
  z *= len;
  s = Math.sin(rad);
  c = Math.cos(rad);
  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;
}
function fromXRotation(out, rad) {
  var s = Math.sin(rad);
  var 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;
}
function fromYRotation(out, rad) {
  var s = Math.sin(rad);
  var 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;
}
function fromZRotation(out, rad) {
  var s = Math.sin(rad);
  var 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;
}
function fromRotationTranslation$1(out, q, v) {
  var x = q[0], y = q[1], z = q[2], w = q[3];
  var x2 = x + x;
  var y2 = y + y;
  var z2 = z + z;
  var xx = x * x2;
  var xy = x * y2;
  var xz = x * z2;
  var yy = y * y2;
  var yz = y * z2;
  var zz = z * z2;
  var wx = w * x2;
  var wy = w * y2;
  var 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;
}
function fromQuat2(out, a) {
  var translation = new ARRAY_TYPE(3);
  var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7];
  var magnitude = bx * bx + by * by + bz * bz + bw * bw;
  if (magnitude > 0) {
    translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude;
    translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude;
    translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude;
  } else {
    translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2;
    translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2;
    translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2;
  }
  fromRotationTranslation$1(out, a, translation);
  return out;
}
function getTranslation$1(out, mat) {
  out[0] = mat[12];
  out[1] = mat[13];
  out[2] = mat[14];
  return out;
}
function getScaling(out, mat) {
  var m11 = mat[0];
  var m12 = mat[1];
  var m13 = mat[2];
  var m21 = mat[4];
  var m22 = mat[5];
  var m23 = mat[6];
  var m31 = mat[8];
  var m32 = mat[9];
  var m33 = mat[10];
  out[0] = Math.hypot(m11, m12, m13);
  out[1] = Math.hypot(m21, m22, m23);
  out[2] = Math.hypot(m31, m32, m33);
  return out;
}
function getRotation(out, mat) {
  var scaling = new ARRAY_TYPE(3);
  getScaling(scaling, mat);
  var is1 = 1 / scaling[0];
  var is2 = 1 / scaling[1];
  var is3 = 1 / scaling[2];
  var sm11 = mat[0] * is1;
  var sm12 = mat[1] * is2;
  var sm13 = mat[2] * is3;
  var sm21 = mat[4] * is1;
  var sm22 = mat[5] * is2;
  var sm23 = mat[6] * is3;
  var sm31 = mat[8] * is1;
  var sm32 = mat[9] * is2;
  var sm33 = mat[10] * is3;
  var trace = sm11 + sm22 + sm33;
  var 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;
}
function fromRotationTranslationScale(out, q, v, s) {
  var x = q[0], y = q[1], z = q[2], w = q[3];
  var x2 = x + x;
  var y2 = y + y;
  var z2 = z + z;
  var xx = x * x2;
  var xy = x * y2;
  var xz = x * z2;
  var yy = y * y2;
  var yz = y * z2;
  var zz = z * z2;
  var wx = w * x2;
  var wy = w * y2;
  var wz = w * z2;
  var sx = s[0];
  var sy = s[1];
  var 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;
}
function fromRotationTranslationScaleOrigin(out, q, v, s, o) {
  var x = q[0], y = q[1], z = q[2], w = q[3];
  var x2 = x + x;
  var y2 = y + y;
  var z2 = z + z;
  var xx = x * x2;
  var xy = x * y2;
  var xz = x * z2;
  var yy = y * y2;
  var yz = y * z2;
  var zz = z * z2;
  var wx = w * x2;
  var wy = w * y2;
  var wz = w * z2;
  var sx = s[0];
  var sy = s[1];
  var sz = s[2];
  var ox = o[0];
  var oy = o[1];
  var oz = o[2];
  var out0 = (1 - (yy + zz)) * sx;
  var out1 = (xy + wz) * sx;
  var out2 = (xz - wy) * sx;
  var out4 = (xy - wz) * sy;
  var out5 = (1 - (xx + zz)) * sy;
  var out6 = (yz + wx) * sy;
  var out8 = (xz + wy) * sz;
  var out9 = (yz - wx) * sz;
  var 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;
}
function fromQuat(out, q) {
  var x = q[0], y = q[1], z = q[2], w = q[3];
  var x2 = x + x;
  var y2 = y + y;
  var z2 = z + z;
  var xx = x * x2;
  var yx = y * x2;
  var yy = y * y2;
  var zx = z * x2;
  var zy = z * y2;
  var zz = z * z2;
  var wx = w * x2;
  var wy = w * y2;
  var 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;
}
function frustum(out, left, right, bottom, top, near, far) {
  var rl = 1 / (right - left);
  var tb = 1 / (top - bottom);
  var nf = 1 / (near - far);
  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[10] = (far + near) * nf;
  out[11] = -1;
  out[12] = 0;
  out[13] = 0;
  out[14] = far * near * 2 * nf;
  out[15] = 0;
  return out;
}
function perspectiveNO(out, fovy, aspect, near, far) {
  var f = 1 / Math.tan(fovy / 2), nf;
  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) {
    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;
}
var perspective = perspectiveNO;
function perspectiveZO(out, fovy, aspect, near, far) {
  var f = 1 / Math.tan(fovy / 2), nf;
  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) {
    nf = 1 / (near - far);
    out[10] = far * nf;
    out[14] = far * near * nf;
  } else {
    out[10] = -1;
    out[14] = -near;
  }
  return out;
}
function perspectiveFromFieldOfView(out, fov, near, far) {
  var upTan = Math.tan(fov.upDegrees * Math.PI / 180);
  var downTan = Math.tan(fov.downDegrees * Math.PI / 180);
  var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180);
  var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180);
  var xScale = 2 / (leftTan + rightTan);
  var 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;
}
function orthoNO(out, left, right, bottom, top, near, far) {
  var lr = 1 / (left - right);
  var bt = 1 / (bottom - top);
  var 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;
}
var ortho = orthoNO;
function orthoZO(out, left, right, bottom, top, near, far) {
  var lr = 1 / (left - right);
  var bt = 1 / (bottom - top);
  var 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;
}
function lookAt(out, eye, center, up) {
  var x0, x1, x2, y0, y1, y2, z0, z1, z2, len;
  var eyex = eye[0];
  var eyey = eye[1];
  var eyez = eye[2];
  var upx = up[0];
  var upy = up[1];
  var upz = up[2];
  var centerx = center[0];
  var centery = center[1];
  var centerz = center[2];
  if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) {
    return identity$2(out);
  }
  z0 = eyex - centerx;
  z1 = eyey - centery;
  z2 = eyez - centerz;
  len = 1 / Math.hypot(z0, z1, z2);
  z0 *= len;
  z1 *= len;
  z2 *= len;
  x0 = upy * z2 - upz * z1;
  x1 = upz * z0 - upx * z2;
  x2 = upx * z1 - upy * z0;
  len = Math.hypot(x0, x1, x2);
  if (!len) {
    x0 = 0;
    x1 = 0;
    x2 = 0;
  } else {
    len = 1 / len;
    x0 *= len;
    x1 *= len;
    x2 *= len;
  }
  y0 = z1 * x2 - z2 * x1;
  y1 = z2 * x0 - z0 * x2;
  y2 = z0 * x1 - z1 * x0;
  len = Math.hypot(y0, y1, 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;
}
function targetTo(out, eye, target, up) {
  var eyex = eye[0], eyey = eye[1], eyez = eye[2], upx = up[0], upy = up[1], upz = up[2];
  var z0 = eyex - target[0], z1 = eyey - target[1], z2 = eyez - target[2];
  var len = z0 * z0 + z1 * z1 + z2 * z2;
  if (len > 0) {
    len = 1 / Math.sqrt(len);
    z0 *= len;
    z1 *= len;
    z2 *= len;
  }
  var x0 = upy * z2 - upz * z1, x1 = upz * z0 - upx * z2, 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;
}
function str$5(a) {
  return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")";
}
function frob(a) {
  return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]);
}
function add$5(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;
}
function subtract$3(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;
}
function 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;
}
function 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;
}
function exactEquals$5(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];
}
function equals$5(a, b) {
  var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
  var a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7];
  var a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11];
  var a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15];
  var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
  var b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7];
  var b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11];
  var b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
  return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1, Math.abs(a15), Math.abs(b15));
}
var mul$5 = multiply$5;
var sub$3 = subtract$3;
const mat4 = /* @__PURE__ */ Object.freeze({
  __proto__: null,
  add: add$5,
  adjoint,
  clone: clone$5,
  copy: copy$5,
  create: create$5,
  determinant,
  equals: equals$5,
  exactEquals: exactEquals$5,
  frob,
  fromQuat,
  fromQuat2,
  fromRotation: fromRotation$1,
  fromRotationTranslation: fromRotationTranslation$1,
  fromRotationTranslationScale,
  fromRotationTranslationScaleOrigin,
  fromScaling,
  fromTranslation: fromTranslation$1,
  fromValues: fromValues$5,
  fromXRotation,
  fromYRotation,
  fromZRotation,
  frustum,
  getRotation,
  getScaling,
  getTranslation: getTranslation$1,
  identity: identity$2,
  invert: invert$2,
  lookAt,
  mul: mul$5,
  multiply: multiply$5,
  multiplyScalar,
  multiplyScalarAndAdd,
  ortho,
  orthoNO,
  orthoZO,
  perspective,
  perspectiveFromFieldOfView,
  perspectiveNO,
  perspectiveZO,
  rotate: rotate$1,
  rotateX: rotateX$3,
  rotateY: rotateY$3,
  rotateZ: rotateZ$3,
  scale: scale$5,
  set: set$5,
  str: str$5,
  sub: sub$3,
  subtract: subtract$3,
  targetTo,
  translate: translate$1,
  transpose
});
function create$4() {
  var out = new ARRAY_TYPE(3);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
  }
  return out;
}
function clone$4(a) {
  var out = new ARRAY_TYPE(3);
  out[0] = a[0];
  out[1] = a[1];
  out[2] = a[2];
  return out;
}
function length$4(a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  return Math.hypot(x, y, z);
}
function fromValues$4(x, y, z) {
  var out = new ARRAY_TYPE(3);
  out[0] = x;
  out[1] = y;
  out[2] = z;
  return out;
}
function copy$4(out, a) {
  out[0] = a[0];
  out[1] = a[1];
  out[2] = a[2];
  return out;
}
function set$4(out, x, y, z) {
  out[0] = x;
  out[1] = y;
  out[2] = z;
  return out;
}
function add$4(out, a, b) {
  out[0] = a[0] + b[0];
  out[1] = a[1] + b[1];
  out[2] = a[2] + b[2];
  return out;
}
function subtract$2(out, a, b) {
  out[0] = a[0] - b[0];
  out[1] = a[1] - b[1];
  out[2] = a[2] - b[2];
  return out;
}
function multiply$4(out, a, b) {
  out[0] = a[0] * b[0];
  out[1] = a[1] * b[1];
  out[2] = a[2] * b[2];
  return out;
}
function divide$2(out, a, b) {
  out[0] = a[0] / b[0];
  out[1] = a[1] / b[1];
  out[2] = a[2] / b[2];
  return out;
}
function ceil$2(out, a) {
  out[0] = Math.ceil(a[0]);
  out[1] = Math.ceil(a[1]);
  out[2] = Math.ceil(a[2]);
  return out;
}
function floor$2(out, a) {
  out[0] = Math.floor(a[0]);
  out[1] = Math.floor(a[1]);
  out[2] = Math.floor(a[2]);
  return out;
}
function min$2(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;
}
function max$2(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;
}
function round$2(out, a) {
  out[0] = Math.round(a[0]);
  out[1] = Math.round(a[1]);
  out[2] = Math.round(a[2]);
  return out;
}
function scale$4(out, a, b) {
  out[0] = a[0] * b;
  out[1] = a[1] * b;
  out[2] = a[2] * b;
  return out;
}
function scaleAndAdd$2(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;
}
function distance$2(a, b) {
  var x = b[0] - a[0];
  var y = b[1] - a[1];
  var z = b[2] - a[2];
  return Math.hypot(x, y, z);
}
function squaredDistance$2(a, b) {
  var x = b[0] - a[0];
  var y = b[1] - a[1];
  var z = b[2] - a[2];
  return x * x + y * y + z * z;
}
function squaredLength$4(a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  return x * x + y * y + z * z;
}
function negate$2(out, a) {
  out[0] = -a[0];
  out[1] = -a[1];
  out[2] = -a[2];
  return out;
}
function inverse$2(out, a) {
  out[0] = 1 / a[0];
  out[1] = 1 / a[1];
  out[2] = 1 / a[2];
  return out;
}
function normalize$4(out, a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  var 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;
}
function dot$4(a, b) {
  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function cross$2(out, a, b) {
  var ax = a[0], ay = a[1], az = a[2];
  var 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;
}
function lerp$4(out, a, b, t) {
  var ax = a[0];
  var ay = a[1];
  var 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;
}
function hermite(out, a, b, c, d, t) {
  var factorTimes2 = t * t;
  var factor1 = factorTimes2 * (2 * t - 3) + 1;
  var factor2 = factorTimes2 * (t - 2) + t;
  var factor3 = factorTimes2 * (t - 1);
  var 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;
}
function bezier(out, a, b, c, d, t) {
  var inverseFactor = 1 - t;
  var inverseFactorTimesTwo = inverseFactor * inverseFactor;
  var factorTimes2 = t * t;
  var factor1 = inverseFactorTimesTwo * inverseFactor;
  var factor2 = 3 * t * inverseFactorTimesTwo;
  var factor3 = 3 * factorTimes2 * inverseFactor;
  var 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;
}
function random$3(out, scale2) {
  scale2 = scale2 || 1;
  var r = RANDOM() * 2 * Math.PI;
  var z = RANDOM() * 2 - 1;
  var zScale = Math.sqrt(1 - z * z) * scale2;
  out[0] = Math.cos(r) * zScale;
  out[1] = Math.sin(r) * zScale;
  out[2] = z * scale2;
  return out;
}
function transformMat4$2(out, a, m) {
  var x = a[0], y = a[1], z = a[2];
  var w = m[3] * x + m[7] * y + m[11] * z + m[15];
  w = w || 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;
}
function transformMat3$1(out, a, m) {
  var 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;
}
function transformQuat$1(out, a, q) {
  var qx = q[0], qy = q[1], qz = q[2], qw = q[3];
  var x = a[0], y = a[1], z = a[2];
  var uvx = qy * z - qz * y, uvy = qz * x - qx * z, uvz = qx * y - qy * x;
  var uuvx = qy * uvz - qz * uvy, uuvy = qz * uvx - qx * uvz, uuvz = qx * uvy - qy * uvx;
  var w2 = qw * 2;
  uvx *= w2;
  uvy *= w2;
  uvz *= w2;
  uuvx *= 2;
  uuvy *= 2;
  uuvz *= 2;
  out[0] = x + uvx + uuvx;
  out[1] = y + uvy + uuvy;
  out[2] = z + uvz + uuvz;
  return out;
}
function rotateX$2(out, a, b, rad) {
  var p = [], r = [];
  p[0] = a[0] - b[0];
  p[1] = a[1] - b[1];
  p[2] = a[2] - b[2];
  r[0] = p[0];
  r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
  r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad);
  out[0] = r[0] + b[0];
  out[1] = r[1] + b[1];
  out[2] = r[2] + b[2];
  return out;
}
function rotateY$2(out, a, b, rad) {
  var p = [], r = [];
  p[0] = a[0] - b[0];
  p[1] = a[1] - b[1];
  p[2] = a[2] - b[2];
  r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
  r[1] = p[1];
  r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad);
  out[0] = r[0] + b[0];
  out[1] = r[1] + b[1];
  out[2] = r[2] + b[2];
  return out;
}
function rotateZ$2(out, a, b, rad) {
  var p = [], r = [];
  p[0] = a[0] - b[0];
  p[1] = a[1] - b[1];
  p[2] = a[2] - b[2];
  r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
  r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
  r[2] = p[2];
  out[0] = r[0] + b[0];
  out[1] = r[1] + b[1];
  out[2] = r[2] + b[2];
  return out;
}
function angle$1(a, b) {
  var ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2], mag1 = Math.sqrt(ax * ax + ay * ay + az * az), mag2 = Math.sqrt(bx * bx + by * by + bz * bz), mag = mag1 * mag2, cosine = mag && dot$4(a, b) / mag;
  return Math.acos(Math.min(Math.max(cosine, -1), 1));
}
function zero$2(out) {
  out[0] = 0;
  out[1] = 0;
  out[2] = 0;
  return out;
}
function str$4(a) {
  return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")";
}
function exactEquals$4(a, b) {
  return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
}
function equals$4(a, b) {
  var a0 = a[0], a1 = a[1], a2 = a[2];
  var b0 = b[0], b1 = b[1], b2 = b[2];
  return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2));
}
var sub$2 = subtract$2;
var mul$4 = multiply$4;
var div$2 = divide$2;
var dist$2 = distance$2;
var sqrDist$2 = squaredDistance$2;
var len$4 = length$4;
var sqrLen$4 = squaredLength$4;
var forEach$2 = function() {
  var vec = create$4();
  return function(a, stride, offset2, count, fn, arg) {
    var i, l;
    if (!stride) {
      stride = 3;
    }
    if (!offset2) {
      offset2 = 0;
    }
    if (count) {
      l = Math.min(count * stride + offset2, a.length);
    } else {
      l = a.length;
    }
    for (i = offset2; i < l; i += stride) {
      vec[0] = a[i];
      vec[1] = a[i + 1];
      vec[2] = a[i + 2];
      fn(vec, vec, arg);
      a[i] = vec[0];
      a[i + 1] = vec[1];
      a[i + 2] = vec[2];
    }
    return a;
  };
}();
const vec3 = /* @__PURE__ */ Object.freeze({
  __proto__: null,
  add: add$4,
  angle: angle$1,
  bezier,
  ceil: ceil$2,
  clone: clone$4,
  copy: copy$4,
  create: create$4,
  cross: cross$2,
  dist: dist$2,
  distance: distance$2,
  div: div$2,
  divide: divide$2,
  dot: dot$4,
  equals: equals$4,
  exactEquals: exactEquals$4,
  floor: floor$2,
  forEach: forEach$2,
  fromValues: fromValues$4,
  hermite,
  inverse: inverse$2,
  len: len$4,
  length: length$4,
  lerp: lerp$4,
  max: max$2,
  min: min$2,
  mul: mul$4,
  multiply: multiply$4,
  negate: negate$2,
  normalize: normalize$4,
  random: random$3,
  rotateX: rotateX$2,
  rotateY: rotateY$2,
  rotateZ: rotateZ$2,
  round: round$2,
  scale: scale$4,
  scaleAndAdd: scaleAndAdd$2,
  set: set$4,
  sqrDist: sqrDist$2,
  sqrLen: sqrLen$4,
  squaredDistance: squaredDistance$2,
  squaredLength: squaredLength$4,
  str: str$4,
  sub: sub$2,
  subtract: subtract$2,
  transformMat3: transformMat3$1,
  transformMat4: transformMat4$2,
  transformQuat: transformQuat$1,
  zero: zero$2
});
function create$3() {
  var out = new ARRAY_TYPE(4);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
  }
  return out;
}
function normalize$3(out, a) {
  var x = a[0];
  var y = a[1];
  var z = a[2];
  var w = a[3];
  var len = x * x + y * y + z * z + w * w;
  if (len > 0) {
    len = 1 / Math.sqrt(len);
  }
  out[0] = x * len;
  out[1] = y * len;
  out[2] = z * len;
  out[3] = w * len;
  return out;
}
(function() {
  var vec = create$3();
  return function(a, stride, offset2, count, fn, arg) {
    var i, l;
    if (!stride) {
      stride = 4;
    }
    if (!offset2) {
      offset2 = 0;
    }
    if (count) {
      l = Math.min(count * stride + offset2, a.length);
    } else {
      l = a.length;
    }
    for (i = offset2; i < l; i += stride) {
      vec[0] = a[i];
      vec[1] = a[i + 1];
      vec[2] = a[i + 2];
      vec[3] = a[i + 3];
      fn(vec, vec, arg);
      a[i] = vec[0];
      a[i + 1] = vec[1];
      a[i + 2] = vec[2];
      a[i + 3] = vec[3];
    }
    return a;
  };
})();
function create$2() {
  var out = new ARRAY_TYPE(4);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
  }
  out[3] = 1;
  return out;
}
function setAxisAngle(out, axis, rad) {
  rad = rad * 0.5;
  var s = Math.sin(rad);
  out[0] = s * axis[0];
  out[1] = s * axis[1];
  out[2] = s * axis[2];
  out[3] = Math.cos(rad);
  return out;
}
function slerp(out, a, b, t) {
  var ax = a[0], ay = a[1], az = a[2], aw = a[3];
  var bx = b[0], by = b[1], bz = b[2], bw = b[3];
  var omega, cosom, sinom, scale0, scale1;
  cosom = ax * bx + ay * by + az * bz + aw * bw;
  if (cosom < 0) {
    cosom = -cosom;
    bx = -bx;
    by = -by;
    bz = -bz;
    bw = -bw;
  }
  if (1 - cosom > EPSILON) {
    omega = Math.acos(cosom);
    sinom = Math.sin(omega);
    scale0 = Math.sin((1 - t) * omega) / sinom;
    scale1 = Math.sin(t * omega) / sinom;
  } else {
    scale0 = 1 - t;
    scale1 = t;
  }
  out[0] = scale0 * ax + scale1 * bx;
  out[1] = scale0 * ay + scale1 * by;
  out[2] = scale0 * az + scale1 * bz;
  out[3] = scale0 * aw + scale1 * bw;
  return out;
}
function fromMat3(out, m) {
  var fTrace = m[0] + m[4] + m[8];
  var fRoot;
  if (fTrace > 0) {
    fRoot = Math.sqrt(fTrace + 1);
    out[3] = 0.5 * fRoot;
    fRoot = 0.5 / fRoot;
    out[0] = (m[5] - m[7]) * fRoot;
    out[1] = (m[6] - m[2]) * fRoot;
    out[2] = (m[1] - m[3]) * fRoot;
  } else {
    var i = 0;
    if (m[4] > m[0])
      i = 1;
    if (m[8] > m[i * 3 + i])
      i = 2;
    var j = (i + 1) % 3;
    var k = (i + 2) % 3;
    fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1);
    out[i] = 0.5 * fRoot;
    fRoot = 0.5 / fRoot;
    out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
    out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
    out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
  }
  return out;
}
var normalize$2 = normalize$3;
(function() {
  var tmpvec3 = create$4();
  var xUnitVec3 = fromValues$4(1, 0, 0);
  var yUnitVec3 = fromValues$4(0, 1, 0);
  return function(out, a, b) {
    var dot = dot$4(a, b);
    if (dot < -0.999999) {
      cross$2(tmpvec3, xUnitVec3, a);
      if (len$4(tmpvec3) < 1e-6)
        cross$2(tmpvec3, yUnitVec3, a);
      normalize$4(tmpvec3, tmpvec3);
      setAxisAngle(out, tmpvec3, Math.PI);
      return out;
    } else if (dot > 0.999999) {
      out[0] = 0;
      out[1] = 0;
      out[2] = 0;
      out[3] = 1;
      return out;
    } else {
      cross$2(tmpvec3, a, b);
      out[0] = tmpvec3[0];
      out[1] = tmpvec3[1];
      out[2] = tmpvec3[2];
      out[3] = 1 + dot;
      return normalize$2(out, out);
    }
  };
})();
(function() {
  var temp1 = create$2();
  var temp2 = create$2();
  return function(out, a, b, c, d, t) {
    slerp(temp1, a, d, t);
    slerp(temp2, b, c, t);
    slerp(out, temp1, temp2, 2 * t * (1 - t));
    return out;
  };
})();
(function() {
  var matr = create$6();
  return function(out, view, right, up) {
    matr[0] = right[0];
    matr[3] = right[1];
    matr[6] = right[2];
    matr[1] = up[0];
    matr[4] = up[1];
    matr[7] = up[2];
    matr[2] = -view[0];
    matr[5] = -view[1];
    matr[8] = -view[2];
    return normalize$2(out, fromMat3(out, matr));
  };
})();
function create() {
  var out = new ARRAY_TYPE(2);
  if (ARRAY_TYPE != Float32Array) {
    out[0] = 0;
    out[1] = 0;
  }
  return out;
}
(function() {
  var vec = create();
  return function(a, stride, offset2, count, fn, arg) {
    var i, l;
    if (!stride) {
      stride = 2;
    }
    if (!offset2) {
      offset2 = 0;
    }
    if (count) {
      l = Math.min(count * stride + offset2, a.length);
    } else {
      l = a.length;
    }
    for (i = offset2; i < l; i += stride) {
      vec[0] = a[i];
      vec[1] = a[i + 1];
      fn(vec, vec, arg);
      a[i] = vec[0];
      a[i + 1] = vec[1];
    }
    return a;
  };
})();
class AnimationControl {
  /** @type {object} */
  #animationData;
  /** @type {Promise<void>} */
  #finishedPromise;
  #willFinish;
  /**
   * Defines a static empty / void animation control.
   *
   * @type {AnimationControl}
   */
  static #voidControl = new AnimationControl(null);
  /**
   * Provides a static void / undefined AnimationControl that is automatically resolved.
   *
   * @returns {AnimationControl} Void AnimationControl
   */
  static get voidControl() {
    return this.#voidControl;
  }
  /**
   * @param {object|null} [animationData] - Animation data from {@link AnimationAPI}.
   *
   * @param {boolean}     [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 {Promise<void>}
   */
  get finished() {
    if (!(this.#finishedPromise instanceof Promise)) {
      this.#finishedPromise = this.#willFinish ? new Promise((resolve) => this.#animationData.resolve = resolve) : Promise.resolve();
    }
    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 {boolean} Animation active state.
   */
  get isActive() {
    return this.#animationData.active;
  }
  /**
   * Returns whether this animation is completely finished.
   *
   * @returns {boolean} Animation finished state.
   */
  get isFinished() {
    return this.#animationData.finished;
  }
  /**
   * Cancels the animation.
   */
  cancel() {
    const animationData = this.#animationData;
    if (animationData === null || animationData === void 0) {
      return;
    }
    animationData.cancelled = true;
  }
}
class AnimationManager {
  /**
   * @type {object[]}
   */
  static activeList = [];
  /**
   * @type {object[]}
   */
  static newList = [];
  /**
   * @type {number}
   */
  static current;
  /**
   * Add animation data.
   *
   * @param {object}   data -
   */
  static add(data) {
    const now2 = performance.now();
    data.start = now2 + (AnimationManager.current - now2);
    AnimationManager.newList.push(data);
  }
  /**
   * Manage all animation
   */
  static animate() {
    const current = AnimationManager.current = performance.now();
    if (AnimationManager.activeList.length === 0 && AnimationManager.newList.length === 0) {
      globalThis.requestAnimationFrame(AnimationManager.animate);
      return;
    }
    if (AnimationManager.newList.length) {
      for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
        const data = AnimationManager.newList[cntr];
        if (data.cancelled) {
          AnimationManager.newList.splice(cntr, 1);
          data.cleanup(data);
        }
        if (data.active) {
          AnimationManager.newList.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);
        data.cleanup(data);
        continue;
      }
      data.current = current - 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.activeList.splice(cntr, 1);
        data.cleanup(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);
    }
    globalThis.requestAnimationFrame(AnimationManager.animate);
  }
  /**
   * Cancels all animations for given Position instance.
   *
   * @param {Position} position - Position instance.
   */
  static cancel(position) {
    for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
      const data = AnimationManager.activeList[cntr];
      if (data.position === position) {
        AnimationManager.activeList.splice(cntr, 1);
        data.cancelled = true;
        data.cleanup(data);
      }
    }
    for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
      const data = AnimationManager.newList[cntr];
      if (data.position === position) {
        AnimationManager.newList.splice(cntr, 1);
        data.cancelled = true;
        data.cleanup(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;
      data.cleanup(data);
    }
    for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
      const data = AnimationManager.newList[cntr];
      data.cancelled = true;
      data.cleanup(data);
    }
    AnimationManager.activeList.length = 0;
    AnimationManager.newList.length = 0;
  }
  /**
   * Gets all {@link AnimationControl} instances for a given Position instance.
   *
   * @param {Position} position - Position instance.
   *
   * @returns {AnimationControl[]} All scheduled AnimationControl instances for the given Position instance.
   */
  static getScheduled(position) {
    const results = [];
    for (let cntr = AnimationManager.activeList.length; --cntr >= 0; ) {
      const data = AnimationManager.activeList[cntr];
      if (data.position === position) {
        results.push(data.control);
      }
    }
    for (let cntr = AnimationManager.newList.length; --cntr >= 0; ) {
      const data = AnimationManager.newList[cntr];
      if (data.position === position) {
        results.push(data.control);
      }
    }
    return results;
  }
}
AnimationManager.animate();
const animateKeys = /* @__PURE__ */ new Set([
  // Main keys
  "left",
  "top",
  "maxWidth",
  "maxHeight",
  "minWidth",
  "minHeight",
  "width",
  "height",
  "rotateX",
  "rotateY",
  "rotateZ",
  "scale",
  "translateX",
  "translateY",
  "translateZ",
  "zIndex",
  // Aliases
  "rotation"
]);
const transformKeys = ["rotateX", "rotateY", "rotateZ", "scale", "translateX", "translateY", "translateZ"];
Object.freeze(transformKeys);
const relativeRegex = /^([-+*])=(-?[\d]*\.?[\d]+)$/;
const numericDefaults = {
  // 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,
  rotation: 0
};
Object.freeze(numericDefaults);
function 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;
  }
  if (data.rotation === null) {
    data.rotation = 0;
  }
}
const transformKeysBitwise = {
  rotateX: 1,
  rotateY: 2,
  rotateZ: 4,
  scale: 8,
  translateX: 16,
  translateY: 32,
  translateZ: 64
};
Object.freeze(transformKeysBitwise);
const transformOriginDefault = "top left";
const transformOrigins = [
  "top left",
  "top center",
  "top right",
  "center left",
  "center",
  "center right",
  "bottom left",
  "bottom center",
  "bottom right"
];
Object.freeze(transformOrigins);
function convertRelative(positionData, position) {
  for (const key in positionData) {
    if (animateKeys.has(key)) {
      const value = positionData[key];
      if (typeof value !== "string") {
        continue;
      }
      if (value === "auto" || value === "inherit") {
        continue;
      }
      const regexResults = relativeRegex.exec(value);
      if (!regexResults) {
        throw new Error(
          `convertRelative error: malformed relative key (${key}) with value (${value})`
        );
      }
      const current = position[key];
      switch (regexResults[1]) {
        case "-":
          positionData[key] = current - parseFloat(regexResults[2]);
          break;
        case "+":
          positionData[key] = current + parseFloat(regexResults[2]);
          break;
        case "*":
          positionData[key] = current * parseFloat(regexResults[2]);
          break;
      }
    }
  }
}
class AnimationAPI {
  /** @type {PositionData} */
  #data;
  /** @type {Position} */
  #position;
  /**
   * Tracks the number of animation control instances that are active.
   *
   * @type {number}
   */
  #instanceCount = 0;
  /**
   * Provides a bound function to pass as data to AnimationManager to invoke
   *
   * @type {Function}
   * @see {AnimationAPI.#cleanupInstance}
   */
  #cleanup;
  constructor(position, data) {
    this.#position = position;
    this.#data = data;
    this.#cleanup = this.#cleanupInstance.bind(this);
  }
  /**
   * Returns whether there are scheduled animations whether active or delayed for this Position.
   *
   * @returns {boolean} Are there active animation instances.
   */
  get isScheduled() {
    return this.#instanceCount > 0;
  }
  /**
   * Adds / schedules an animation w/ the AnimationManager. This contains the final steps common to all tweens.
   *
   * @param {object}      initial -
   *
   * @param {object}      destination -
   *
   * @param {number}      duration -
   *
   * @param {HTMLElement} el -
   *
   * @param {number}      delay -
   *
   * @param {Function}    ease -
   *
   * @param {Function}    interpolate -
   *
   * @returns {AnimationControl} The associated animation control.
   */
  #addAnimation(initial, destination, duration, el, delay, ease, interpolate2) {
    setNumericDefaults(initial);
    setNumericDefaults(destination);
    for (const key in initial) {
      if (!Number.isFinite(initial[key])) {
        delete initial[key];
      }
    }
    const keys = Object.keys(initial);
    const newData = Object.assign({ immediateElementUpdate: true }, initial);
    if (keys.length === 0) {
      return AnimationControl.voidControl;
    }
    const animationData = {
      active: true,
      cleanup: this.#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: this.#position,
      resolve: void 0,
      start: void 0
    };
    if (delay > 0) {
      animationData.active = false;
      setTimeout(() => {
        if (!animationData.cancelled) {
          animationData.active = true;
          const now2 = performance.now();
          animationData.start = now2 + (AnimationManager.current - now2);
        }
      }, delay * 1e3);
    }
    this.#instanceCount++;
    AnimationManager.add(animationData);
    return new AnimationControl(animationData, true);
  }
  /**
   * Cancels all animation instances for this Position instance.
   */
  cancel() {
    AnimationManager.cancel(this.#position);
  }
  /**
   * Cleans up an animation instance.
   *
   * @param {object}   data - Animation data for an animation instance.
   */
  #cleanupInstance(data) {
    this.#instanceCount--;
    data.active = false;
    data.finished = true;
    if (typeof data.resolve === "function") {
      data.resolve(data.cancelled);
    }
  }
  /**
   * Returns all currently scheduled AnimationControl instances for this Position instance.
   *
   * @returns {AnimationControl[]} All currently scheduled animation controls for this Position instance.
   */
  getScheduled() {
    return AnimationManager.getScheduled(this.#position);
  }
  /**
   * Provides a tween from given position data to the current position.
   *
   * @param {PositionDataExtended} fromData - The starting position.
   *
   * @param {object}         [opts] - Optional parameters.
   *
   * @param {number}         [opts.delay=0] - Delay in seconds before animation starts.
   *
   * @param {number}         [opts.duration=1] - Duration in seconds.
   *
   * @param {Function}       [opts.ease=cubicOut] - Easing function.
   *
   * @param {Function}       [opts.interpolate=lerp] - Interpolation function.
   *
   * @returns {AnimationControl}  A control object that can cancel animation and provides a `finished` Promise.
   */
  from(fromData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
    if (!isObject(fromData)) {
      throw new TypeError(`AnimationAPI.from error: 'fromData' is not an object.`);
    }
    const position = this.#position;
    const parent = position.parent;
    if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
      return AnimationControl.voidControl;
    }
    const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
    const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
    if (!Number.isFinite(delay) || delay < 0) {
      throw new TypeError(`AnimationAPI.from error: 'delay' is not a positive number.`);
    }
    if (!Number.isFinite(duration) || duration < 0) {
      throw new TypeError(`AnimationAPI.from error: 'duration' is not a positive number.`);
    }
    if (typeof ease !== "function") {
      throw new TypeError(`AnimationAPI.from error: 'ease' is not a function.`);
    }
    if (typeof interpolate2 !== "function") {
      throw new TypeError(`AnimationAPI.from error: 'interpolate' is not a function.`);
    }
    const initial = {};
    const destination = {};
    const data = this.#data;
    for (const key in fromData) {
      if (data[key] !== void 0 && fromData[key] !== data[key]) {
        initial[key] = fromData[key];
        destination[key] = data[key];
      }
    }
    convertRelative(initial, data);
    return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
  }
  /**
   * Provides a tween from given position data to the current position.
   *
   * @param {PositionDataExtended} fromData - The starting position.
   *
   * @param {PositionDataExtended} toData - The ending position.
   *
   * @param {object}         [opts] - Optional parameters.
   *
   * @param {number}         [opts.delay=0] - Delay in seconds before animation starts.
   *
   * @param {number}         [opts.duration=1] - Duration in seconds.
   *
   * @param {Function}       [opts.ease=cubicOut] - Easing function.
   *
   * @param {Function}       [opts.interpolate=lerp] - Interpolation function.
   *
   * @returns {AnimationControl}  A control object that can cancel animation and provides a `finished` Promise.
   */
  fromTo(fromData, toData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
    if (!isObject(fromData)) {
      throw new TypeError(`AnimationAPI.fromTo error: 'fromData' is not an object.`);
    }
    if (!isObject(toData)) {
      throw new TypeError(`AnimationAPI.fromTo error: 'toData' is not an object.`);
    }
    const parent = this.#position.parent;
    if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
      return AnimationControl.voidControl;
    }
    const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
    const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
    if (!Number.isFinite(delay) || delay < 0) {
      throw new TypeError(`AnimationAPI.fromTo error: 'delay' is not a positive number.`);
    }
    if (!Number.isFinite(duration) || duration < 0) {
      throw new TypeError(`AnimationAPI.fromTo error: 'duration' is not a positive number.`);
    }
    if (typeof ease !== "function") {
      throw new TypeError(`AnimationAPI.fromTo error: 'ease' is not a function.`);
    }
    if (typeof interpolate2 !== "function") {
      throw new TypeError(`AnimationAPI.fromTo error: 'interpolate' is not a function.`);
    }
    const initial = {};
    const destination = {};
    const data = this.#data;
    for (const key in fromData) {
      if (toData[key] === void 0) {
        console.warn(
          `AnimationAPI.fromTo warning: key ('${key}') from 'fromData' missing in 'toData'; skipping this key.`
        );
        continue;
      }
      if (data[key] !== void 0) {
        initial[key] = fromData[key];
        destination[key] = toData[key];
      }
    }
    convertRelative(initial, data);
    convertRelative(destination, data);
    return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
  }
  /**
   * Provides a tween to given position data from the current position.
   *
   * @param {PositionDataExtended} toData - The destination position.
   *
   * @param {object}         [opts] - Optional parameters.
   *
   * @param {number}         [opts.delay=0] - Delay in seconds before animation starts.
   *
   * @param {number}         [opts.duration=1] - Duration in seconds.
   *
   * @param {Function}       [opts.ease=cubicOut] - Easing function.
   *
   * @param {Function}       [opts.interpolate=lerp] - Interpolation function.
   *
   * @returns {AnimationControl}  A control object that can cancel animation and provides a `finished` Promise.
   */
  to(toData, { delay = 0, duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
    if (!isObject(toData)) {
      throw new TypeError(`AnimationAPI.to error: 'toData' is not an object.`);
    }
    const parent = this.#position.parent;
    if (parent !== void 0 && typeof parent?.options?.positionable === "boolean" && !parent?.options?.positionable) {
      return AnimationControl.voidControl;
    }
    const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
    const el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
    if (!Number.isFinite(delay) || delay < 0) {
      throw new TypeError(`AnimationAPI.to error: 'delay' is not a positive number.`);
    }
    if (!Number.isFinite(duration) || duration < 0) {
      throw new TypeError(`AnimationAPI.to error: 'duration' is not a positive number.`);
    }
    if (typeof ease !== "function") {
      throw new TypeError(`AnimationAPI.to error: 'ease' is not a function.`);
    }
    if (typeof interpolate2 !== "function") {
      throw new TypeError(`AnimationAPI.to error: 'interpolate' is not a function.`);
    }
    const initial = {};
    const destination = {};
    const data = this.#data;
    for (const key in toData) {
      if (data[key] !== void 0 && toData[key] !== data[key]) {
        destination[key] = toData[key];
        initial[key] = data[key];
      }
    }
    convertRelative(destination, data);
    return this.#addAnimation(initial, destination, duration, el, delay, ease, interpolate2);
  }
  /**
   * Returns a function that provides an optimized way to constantly update a to-tween.
   *
   * @param {Iterable<string>}  keys - The keys for quickTo.
   *
   * @param {object}            [opts] - Optional parameters.
   *
   * @param {number}            [opts.duration=1] - Duration in seconds.
   *
   * @param {Function}          [opts.ease=cubicOut] - Easing function.
   *
   * @param {Function}          [opts.interpolate=lerp] - Interpolation function.
   *
   * @returns {quickToCallback} quick-to tween function.
   */
  quickTo(keys, { duration = 1, ease = cubicOut, interpolate: interpolate2 = lerp$5 } = {}) {
    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.`);
    }
    if (!Number.isFinite(duration) || duration < 0) {
      throw new TypeError(`AnimationAPI.quickTo error: 'duration' is not a positive number.`);
    }
    if (typeof ease !== "function") {
      throw new TypeError(`AnimationAPI.quickTo error: 'ease' is not a function.`);
    }
    if (typeof interpolate2 !== "function") {
      throw new TypeError(`AnimationAPI.quickTo error: 'interpolate' is not a function.`);
    }
    const initial = {};
    const destination = {};
    const data = this.#data;
    for (const key of keys) {
      if (typeof key !== "string") {
        throw new TypeError(`AnimationAPI.quickTo error: key is not a string.`);
      }
      if (!animateKeys.has(key)) {
        throw new Error(`AnimationAPI.quickTo error: key ('${key}') is not animatable.`);
      }
      if (data[key] !== void 0) {
        destination[key] = data[key];
        initial[key] = data[key];
      }
    }
    const keysArray = [...keys];
    Object.freeze(keysArray);
    const newData = Object.assign({ immediateElementUpdate: true }, initial);
    const animationData = {
      active: true,
      cleanup: this.#cleanup,
      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: interpolate2,
      keys,
      newData,
      position: this.#position,
      resolve: void 0,
      start: void 0
    };
    const quickToCB = (...args) => {
      const argsLength = args.length;
      if (argsLength === 0) {
        return;
      }
      for (let cntr = keysArray.length; --cntr >= 0; ) {
        const key = keysArray[cntr];
        if (data[key] !== void 0) {
          initial[key] = data[key];
        }
      }
      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];
          }
        }
      }
      convertRelative(destination, data);
      setNumericDefaults(initial);
      setNumericDefaults(destination);
      const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
      animationData.el = targetEl instanceof HTMLElement && targetEl.isConnected ? targetEl : void 0;
      if (animationData.finished) {
        animationData.finished = false;
        animationData.active = true;
        animationData.current = 0;
        this.#instanceCount++;
        AnimationManager.add(animationData);
      } else {
        const now2 = performance.now();
        animationData.start = now2 + (AnimationManager.current - now2);
        animationData.current = 0;
      }
    };
    quickToCB.keys = keysArray;
    quickToCB.options = ({ duration: duration2, ease: ease2, interpolate: interpolate3 } = {}) => {
      if (duration2 !== void 0 && (!Number.isFinite(duration2) || duration2 < 0)) {
        throw new TypeError(`AnimationAPI.quickTo.options error: 'duration' is not a positive number.`);
      }
      if (ease2 !== void 0 && typeof ease2 !== "function") {
        throw new TypeError(`AnimationAPI.quickTo.options error: 'ease' is not a function.`);
      }
      if (interpolate3 !== void 0 && typeof interpolate3 !== "function") {
        throw new TypeError(`AnimationAPI.quickTo.options error: 'interpolate' is not a function.`);
      }
      if (duration2 >= 0) {
        animationData.duration = duration2 * 1e3;
      }
      if (ease2) {
        animationData.ease = ease2;
      }
      if (interpolate3) {
        animationData.interpolate = interpolate3;
      }
      return quickToCB;
    };
    return quickToCB;
  }
}
class AnimationGroupControl {
  /** @type {AnimationControl[]} */
  #animationControls;
  /** @type {Promise<Awaited<unknown>[]>} */
  #finishedPromise;
  /**
   * Defines a static empty / void animation control.
   *
   * @type {AnimationGroupControl}
   */
  static #voidControl = new AnimationGroupControl(null);
  /**
   * Provides a static void / undefined AnimationGroupControl that is automatically resolved.
   *
   * @returns {AnimationGroupControl} Void AnimationGroupControl
   */
  static get voidControl() {
    return this.#voidControl;
  }
  /**
   * @param {AnimationControl[]} animationControls - An array of AnimationControl instances.
   */
  constructor(animationControls) {
    this.#animationControls = animationControls;
  }
  /**
   * Get a promise that resolves when all animations are finished.
   *
   * @returns {Promise<Awaited<unknown>[]>|Promise<void>} Finished Promise for all animations.
   */
  get finished() {
    const animationControls = this.#animationControls;
    if (animationControls === null || animationControls === void 0) {
      return Promise.resolve();
    }
    if (!(this.#finishedPromise instanceof Promise)) {
      const promises = [];
      for (let cntr = animationControls.length; --cntr >= 0; ) {
        promises.push(animationControls[cntr].finished);
      }
      this.#finishedPromise = Promise.all(promises);
    }
    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 {boolean} Are there active animation instances.
   */
  get isActive() {
    const animationControls = this.#animationControls;
    if (animationControls === null || animationControls === void 0) {
      return false;
    }
    for (let cntr = animationControls.length; --cntr >= 0; ) {
      if (animationControls[cntr].isActive) {
        return true;
      }
    }
    return false;
  }
  /**
   * Returns whether all animations in the group are finished.
   *
   * @returns {boolean} Are all animation instances finished.
   */
  get isFinished() {
    const animationControls = this.#animationControls;
    if (animationControls === null || animationControls === void 0) {
      return true;
    }
    for (let cntr = animationControls.length; --cntr >= 0; ) {
      if (!animationControls[cntr].isFinished) {
        return false;
      }
    }
    return false;
  }
  /**
   * Cancels the all animations.
   */
  cancel() {
    const animationControls = this.#animationControls;
    if (animationControls === null || animationControls === void 0) {
      return;
    }
    for (let cntr = this.#animationControls.length; --cntr >= 0; ) {
      this.#animationControls[cntr].cancel();
    }
  }
}
class AnimationGroupAPI {
  /**
   * Checks of the given object is a Position instance by checking for AnimationAPI.
   *
   * @param {*}  object - Any data.
   *
   * @returns {boolean} Is Position.
   */
  static #isPosition(object) {
    return isObject(object) && object.animate instanceof AnimationAPI;
  }
  /**
   * Cancels any animation for given Position data.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   */
  static cancel(position) {
    if (isIterable(position)) {
      let index = -1;
      for (const entry of position) {
        index++;
        const actualPosition = this.#isPosition(entry) ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.cancel warning: No Position instance found at index: ${index}.`);
          continue;
        }
        AnimationManager.cancel(actualPosition);
      }
    } else {
      const actualPosition = this.#isPosition(position) ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.cancel warning: No Position instance found.`);
        return;
      }
      AnimationManager.cancel(actualPosition);
    }
  }
  /**
   * Cancels all Position animation.
   */
  static cancelAll() {
    AnimationManager.cancelAll();
  }
  /**
   * Gets all animation controls for the given position data.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   *
   * @returns {{position: Position, data: object|void, controls: AnimationControl[]}[]} Results array.
   */
  static getScheduled(position) {
    const results = [];
    if (isIterable(position)) {
      let index = -1;
      for (const entry of position) {
        index++;
        const isPosition = this.#isPosition(entry);
        const actualPosition = isPosition ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.getScheduled warning: No Position instance found at index: ${index}.`);
          continue;
        }
        const controls = AnimationManager.getScheduled(actualPosition);
        results.push({ position: actualPosition, data: isPosition ? void 0 : entry, controls });
      }
    } else {
      const isPosition = this.#isPosition(position);
      const actualPosition = isPosition ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.getScheduled warning: No Position instance found.`);
        return results;
      }
      const controls = AnimationManager.getScheduled(actualPosition);
      results.push({ position: actualPosition, data: isPosition ? void 0 : position, controls });
    }
    return results;
  }
  /**
   * Provides the `from` animation tween for one or more Position instances as a group.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   *
   * @param {object|Function}   fromData -
   *
   * @param {object|Function}   options -
   *
   * @returns {TJSBasicAnimation} Basic animation control.
   */
  static from(position, 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 = [];
    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, data: void 0 };
    }
    let actualFromData = fromData;
    let actualOptions = options;
    if (isIterable(position)) {
      for (const entry of position) {
        index++;
        const isPosition = this.#isPosition(entry);
        const actualPosition = isPosition ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.from warning: No Position instance found at index: ${index}.`);
          continue;
        }
        if (hasCallback) {
          callbackOptions.index = index;
          callbackOptions.position = position;
          callbackOptions.data = isPosition ? void 0 : entry;
        }
        if (hasDataCallback) {
          actualFromData = fromData(callbackOptions);
          if (actualFromData === null || actualFromData === void 0) {
            continue;
          }
          if (typeof actualFromData !== "object") {
            throw new TypeError(`AnimationGroupAPI.from error: fromData callback function iteration(${index}) failed to return an object.`);
          }
        }
        if (hasOptionCallback) {
          actualOptions = options(callbackOptions);
          if (actualOptions === null || actualOptions === void 0) {
            continue;
          }
          if (typeof actualOptions !== "object") {
            throw new TypeError(`AnimationGroupAPI.from error: options callback function iteration(${index}) failed to return an object.`);
          }
        }
        animationControls.push(actualPosition.animate.from(actualFromData, actualOptions));
      }
    } else {
      const isPosition = this.#isPosition(position);
      const actualPosition = isPosition ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.from warning: No Position instance found.`);
        return AnimationGroupControl.voidControl;
      }
      if (hasCallback) {
        callbackOptions.index = 0;
        callbackOptions.position = position;
        callbackOptions.data = isPosition ? void 0 : position;
      }
      if (hasDataCallback) {
        actualFromData = fromData(callbackOptions);
        if (typeof actualFromData !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.from error: fromData callback function failed to return an object.`
          );
        }
      }
      if (hasOptionCallback) {
        actualOptions = options(callbackOptions);
        if (typeof actualOptions !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.from error: options callback function failed to return an object.`
          );
        }
      }
      animationControls.push(actualPosition.animate.from(actualFromData, actualOptions));
    }
    return new AnimationGroupControl(animationControls);
  }
  /**
   * Provides the `fromTo` animation tween for one or more Position instances as a group.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   *
   * @param {object|Function}   fromData -
   *
   * @param {object|Function}   toData -
   *
   * @param {object|Function}   options -
   *
   * @returns {TJSBasicAnimation} Basic animation control.
   */
  static fromTo(position, 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 = [];
    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, data: void 0 };
    }
    let actualFromData = fromData;
    let actualToData = toData;
    let actualOptions = options;
    if (isIterable(position)) {
      for (const entry of position) {
        index++;
        const isPosition = this.#isPosition(entry);
        const actualPosition = isPosition ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.fromTo warning: No Position instance found at index: ${index}.`);
          continue;
        }
        if (hasCallback) {
          callbackOptions.index = index;
          callbackOptions.position = position;
          callbackOptions.data = isPosition ? void 0 : entry;
        }
        if (hasFromCallback) {
          actualFromData = fromData(callbackOptions);
          if (actualFromData === null || actualFromData === void 0) {
            continue;
          }
          if (typeof actualFromData !== "object") {
            throw new TypeError(`AnimationGroupAPI.fromTo error: fromData callback function iteration(${index}) failed to return an object.`);
          }
        }
        if (hasToCallback) {
          actualToData = toData(callbackOptions);
          if (actualToData === null || actualToData === void 0) {
            continue;
          }
          if (typeof actualToData !== "object") {
            throw new TypeError(`AnimationGroupAPI.fromTo error: toData callback function iteration(${index}) failed to return an object.`);
          }
        }
        if (hasOptionCallback) {
          actualOptions = options(callbackOptions);
          if (actualOptions === null || actualOptions === void 0) {
            continue;
          }
          if (typeof actualOptions !== "object") {
            throw new TypeError(`AnimationGroupAPI.fromTo error: options callback function iteration(${index}) failed to return an object.`);
          }
        }
        animationControls.push(actualPosition.animate.fromTo(actualFromData, actualToData, actualOptions));
      }
    } else {
      const isPosition = this.#isPosition(position);
      const actualPosition = isPosition ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.fromTo warning: No Position instance found.`);
        return AnimationGroupControl.voidControl;
      }
      if (hasCallback) {
        callbackOptions.index = 0;
        callbackOptions.position = position;
        callbackOptions.data = isPosition ? void 0 : position;
      }
      if (hasFromCallback) {
        actualFromData = fromData(callbackOptions);
        if (typeof actualFromData !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.fromTo error: fromData callback function failed to return an object.`
          );
        }
      }
      if (hasToCallback) {
        actualToData = toData(callbackOptions);
        if (typeof actualToData !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.fromTo error: toData callback function failed to return an object.`
          );
        }
      }
      if (hasOptionCallback) {
        actualOptions = options(callbackOptions);
        if (typeof actualOptions !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.fromTo error: options callback function failed to return an object.`
          );
        }
      }
      animationControls.push(actualPosition.animate.fromTo(actualFromData, actualToData, actualOptions));
    }
    return new AnimationGroupControl(animationControls);
  }
  /**
   * Provides the `to` animation tween for one or more Position instances as a group.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   *
   * @param {object|Function}   toData -
   *
   * @param {object|Function}   options -
   *
   * @returns {TJSBasicAnimation} Basic animation control.
   */
  static to(position, 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 = [];
    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, data: void 0 };
    }
    let actualToData = toData;
    let actualOptions = options;
    if (isIterable(position)) {
      for (const entry of position) {
        index++;
        const isPosition = this.#isPosition(entry);
        const actualPosition = isPosition ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.to warning: No Position instance found at index: ${index}.`);
          continue;
        }
        if (hasCallback) {
          callbackOptions.index = index;
          callbackOptions.position = position;
          callbackOptions.data = isPosition ? void 0 : entry;
        }
        if (hasDataCallback) {
          actualToData = toData(callbackOptions);
          if (actualToData === null || actualToData === void 0) {
            continue;
          }
          if (typeof actualToData !== "object") {
            throw new TypeError(`AnimationGroupAPI.to error: toData callback function iteration(${index}) failed to return an object.`);
          }
        }
        if (hasOptionCallback) {
          actualOptions = options(callbackOptions);
          if (actualOptions === null || actualOptions === void 0) {
            continue;
          }
          if (typeof actualOptions !== "object") {
            throw new TypeError(`AnimationGroupAPI.to error: options callback function iteration(${index}) failed to return an object.`);
          }
        }
        animationControls.push(actualPosition.animate.to(actualToData, actualOptions));
      }
    } else {
      const isPosition = this.#isPosition(position);
      const actualPosition = isPosition ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.to warning: No Position instance found.`);
        return AnimationGroupControl.voidControl;
      }
      if (hasCallback) {
        callbackOptions.index = 0;
        callbackOptions.position = position;
        callbackOptions.data = isPosition ? void 0 : position;
      }
      if (hasDataCallback) {
        actualToData = toData(callbackOptions);
        if (typeof actualToData !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.to error: toData callback function failed to return an object.`
          );
        }
      }
      if (hasOptionCallback) {
        actualOptions = options(callbackOptions);
        if (typeof actualOptions !== "object") {
          throw new TypeError(
            `AnimationGroupAPI.to error: options callback function failed to return an object.`
          );
        }
      }
      animationControls.push(actualPosition.animate.to(actualToData, actualOptions));
    }
    return new AnimationGroupControl(animationControls);
  }
  /**
   * Provides the `to` animation tween for one or more Position instances as a group.
   *
   * @param {Position|{position: Position}|Iterable<Position>|Iterable<{position: Position}>} position -
   *
   * @param {Iterable<string>}  keys -
   *
   * @param {object|Function}   options -
   *
   * @returns {quickToCallback} Basic animation control.
   */
  static quickTo(position, 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, data: void 0 };
    let actualOptions = options;
    if (isIterable(position)) {
      for (const entry of position) {
        index++;
        const isPosition = this.#isPosition(entry);
        const actualPosition = isPosition ? entry : entry.position;
        if (!this.#isPosition(actualPosition)) {
          console.warn(`AnimationGroupAPI.quickTo warning: No Position instance found at index: ${index}.`);
          continue;
        }
        callbackOptions.index = index;
        callbackOptions.position = position;
        callbackOptions.data = isPosition ? void 0 : entry;
        if (hasOptionCallback) {
          actualOptions = options(callbackOptions);
          if (actualOptions === null || actualOptions === void 0) {
            continue;
          }
          if (typeof actualOptions !== "object") {
            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 isPosition = this.#isPosition(position);
      const actualPosition = isPosition ? position : position.position;
      if (!this.#isPosition(actualPosition)) {
        console.warn(`AnimationGroupAPI.quickTo warning: No Position instance found.`);
        return () => null;
      }
      callbackOptions.index = 0;
      callbackOptions.position = position;
      callbackOptions.data = isPosition ? void 0 : position;
      if (hasOptionCallback) {
        actualOptions = options(callbackOptions);
        if (typeof actualOptions !== "object") {
          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(position)) {
          for (const entry of position) {
            index++;
            const isPosition = this.#isPosition(entry);
            const actualPosition = isPosition ? entry : entry.position;
            if (!this.#isPosition(actualPosition)) {
              continue;
            }
            callbackOptions.index = index;
            callbackOptions.position = position;
            callbackOptions.data = isPosition ? void 0 : entry;
            const toData = dataCallback(callbackOptions);
            if (toData === null || toData === void 0) {
              continue;
            }
            const toDataIterable = isIterable(toData);
            if (!Number.isFinite(toData) && !toDataIterable && typeof toData !== "object") {
              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 isPosition = this.#isPosition(position);
          const actualPosition = isPosition ? position : position.position;
          if (!this.#isPosition(actualPosition)) {
            return;
          }
          callbackOptions.index = 0;
          callbackOptions.position = position;
          callbackOptions.data = isPosition ? void 0 : position;
          const toData = dataCallback(callbackOptions);
          if (toData === null || toData === void 0) {
            return;
          }
          const toDataIterable = isIterable(toData);
          if (!Number.isFinite(toData) && !toDataIterable && typeof toData !== "object") {
            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);
        }
      }
    };
    quickToCB.keys = keysArray;
    quickToCB.options = (options2) => {
      if (options2 !== void 0 && !isObject(options2) && typeof options2 !== "function") {
        throw new TypeError(`AnimationGroupAPI.quickTo error: 'options' is not an object or function.`);
      }
      if (isObject(options2)) {
        for (let cntr = quickToCallbacks.length; --cntr >= 0; ) {
          quickToCallbacks[cntr].options(options2);
        }
      } else if (typeof options2 === "function") {
        if (isIterable(position)) {
          index = -1;
          let cntr = 0;
          for (const entry of position) {
            index++;
            const isPosition = this.#isPosition(entry);
            const actualPosition = isPosition ? entry : entry.position;
            if (!this.#isPosition(actualPosition)) {
              console.warn(
                `AnimationGroupAPI.quickTo.options warning: No Position instance found at index: ${index}.`
              );
              continue;
            }
            callbackOptions.index = index;
            callbackOptions.position = position;
            callbackOptions.data = isPosition ? void 0 : entry;
            actualOptions = options2(callbackOptions);
            if (actualOptions === null || actualOptions === void 0) {
              continue;
            }
            if (typeof actualOptions !== "object") {
              throw new TypeError(
                `AnimationGroupAPI.quickTo.options error: options callback function iteration(${index}) failed to return an object.`
              );
            }
            quickToCallbacks[cntr++].options(actualOptions);
          }
        } else {
          const isPosition = this.#isPosition(position);
          const actualPosition = isPosition ? position : position.position;
          if (!this.#isPosition(actualPosition)) {
            console.warn(`AnimationGroupAPI.quickTo.options warning: No Position instance found.`);
            return quickToCB;
          }
          callbackOptions.index = 0;
          callbackOptions.position = position;
          callbackOptions.data = isPosition ? void 0 : position;
          actualOptions = options2(callbackOptions);
          if (typeof actualOptions !== "object") {
            throw new TypeError(
              `AnimationGroupAPI.quickTo error: options callback function failed to return an object.`
            );
          }
          quickToCallbacks[0].options(actualOptions);
        }
      }
      return quickToCB;
    };
    return quickToCB;
  }
}
class Centered {
  /**
   * @type {HTMLElement}
   */
  #element;
  /**
   * 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`.
   *
   * @type {number}
   */
  #height;
  /**
   * Set from an optional value in the constructor to lock accessors preventing modification.
   */
  #lock;
  /**
   * 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`.
   *
   * @type {number}
   */
  #width;
  constructor({ element: element2, lock = false, width: width2, height } = {}) {
    this.element = element2;
    this.width = width2;
    this.height = height;
    this.#lock = typeof lock === "boolean" ? lock : false;
  }
  get element() {
    return this.#element;
  }
  get height() {
    return this.#height;
  }
  get width() {
    return this.#width;
  }
  set element(element2) {
    if (this.#lock) {
      return;
    }
    if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
      this.#element = element2;
    } else {
      throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
    }
  }
  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.`);
    }
  }
  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.`);
    }
  }
  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.`);
    }
  }
  getLeft(width2) {
    const boundsWidth = this.#width ?? this.#element?.offsetWidth ?? globalThis.innerWidth;
    return (boundsWidth - width2) / 2;
  }
  getTop(height) {
    const boundsHeight = this.#height ?? this.#element?.offsetHeight ?? globalThis.innerHeight;
    return (boundsHeight - height) / 2;
  }
}
const browserCentered = new Centered();
const positionInitial = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  Centered,
  browserCentered
}, Symbol.toStringTag, { value: "Module" }));
class PositionChangeSet {
  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 PositionData {
  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;
    Object.seal(this);
  }
  /**
   * Copies given data to this instance.
   *
   * @param {PositionData}   data - Copy from this instance.
   *
   * @returns {PositionData} This instance.
   */
  copy(data) {
    this.height = data.height;
    this.left = data.left;
    this.maxHeight = data.maxHeight;
    this.maxWidth = data.maxWidth;
    this.minHeight = data.minHeight;
    this.minWidth = data.minWidth;
    this.rotateX = data.rotateX;
    this.rotateY = data.rotateY;
    this.rotateZ = data.rotateZ;
    this.scale = data.scale;
    this.top = data.top;
    this.transformOrigin = data.transformOrigin;
    this.translateX = data.translateX;
    this.translateY = data.translateY;
    this.translateZ = data.translateZ;
    this.width = data.width;
    this.zIndex = data.zIndex;
    return this;
  }
}
class PositionStateAPI {
  /** @type {PositionData} */
  #data;
  /**
   * @type {Map<string, PositionDataExtended>}
   */
  #dataSaved = /* @__PURE__ */ new Map();
  /** @type {Position} */
  #position;
  /** @type {Transforms} */
  #transforms;
  constructor(position, data, transforms) {
    this.#position = position;
    this.#data = data;
    this.#transforms = transforms;
  }
  /**
   * Returns any stored save state by name.
   *
   * @param {string}   name - Saved data set name.
   *
   * @returns {PositionDataExtended} The saved data set.
   */
  get({ name }) {
    if (typeof name !== "string") {
      throw new TypeError(`Position - getSave error: 'name' is not a string.`);
    }
    return this.#dataSaved.get(name);
  }
  /**
   * Returns any associated default data.
   *
   * @returns {PositionDataExtended} Associated default data.
   */
  getDefault() {
    return this.#dataSaved.get("#defaultData");
  }
  /**
   * Removes and returns any position state by name.
   *
   * @param {object}   options - Options.
   *
   * @param {string}   options.name - Name to remove and retrieve.
   *
   * @returns {PositionDataExtended} Saved position data.
   */
  remove({ name }) {
    if (typeof name !== "string") {
      throw new TypeError(`Position - remove: 'name' is not a string.`);
    }
    const data = this.#dataSaved.get(name);
    this.#dataSaved.delete(name);
    return data;
  }
  /**
   * Resets data to default values and invokes set.
   *
   * @param {object}   [opts] - Optional parameters.
   *
   * @param {boolean}  [opts.keepZIndex=false] - When true keeps current z-index.
   *
   * @param {boolean}  [opts.invokeSet=true] - When true invokes set method.
   *
   * @returns {boolean} Operation successful.
   */
  reset({ keepZIndex = false, invokeSet = true } = {}) {
    const defaultData = this.#dataSaved.get("#defaultData");
    if (typeof defaultData !== "object") {
      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);
    if (this.#position.parent?.reactive?.minimized) {
      this.#position.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, easing, and interpolate functions along with configuring a Promise to be
   * returned if awaiting the end of the animation.
   *
   * @param {object}            params - Parameters
   *
   * @param {string}            params.name - Saved data set name.
   *
   * @param {boolean}           [params.remove=false] - Remove data set.
   *
   * @param {Iterable<string>}  [params.properties] - Specific properties to set / animate.
   *
   * @param {boolean}           [params.silent] - Set position data directly; no store or style updates.
   *
   * @param {boolean}           [params.async=false] - If animating return a Promise that resolves with any saved data.
   *
   * @param {boolean}           [params.animateTo=false] - Animate to restore data.
   *
   * @param {number}            [params.duration=0.1] - Duration in seconds.
   *
   * @param {Function}          [params.ease=linear] - Easing function.
   *
   * @param {Function}          [params.interpolate=lerp] - Interpolation function.
   *
   * @returns {PositionDataExtended|Promise<PositionDataExtended>} Saved position data.
   */
  restore({
    name,
    remove = false,
    properties,
    silent = false,
    async = false,
    animateTo = false,
    duration = 0.1,
    ease = identity,
    interpolate: interpolate2 = lerp$5
  }) {
    if (typeof name !== "string") {
      throw new TypeError(`Position - restore error: 'name' is not a string.`);
    }
    const dataSaved = this.#dataSaved.get(name);
    if (dataSaved) {
      if (remove) {
        this.#dataSaved.delete(name);
      }
      let data = dataSaved;
      if (isIterable(properties)) {
        data = {};
        for (const property of properties) {
          data[property] = dataSaved[property];
        }
      }
      if (silent) {
        for (const property in 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, interpolate: interpolate2 }).finished.then(() => dataSaved);
        } else {
          this.#position.animate.to(data, { duration, ease, interpolate: interpolate2 });
        }
      } else {
        this.#position.set(data);
      }
    }
    return dataSaved;
  }
  /**
   * Saves current position state with the opportunity to add extra data to the saved state.
   *
   * @param {object}   opts - Options.
   *
   * @param {string}   opts.name - name to index this saved data.
   *
   * @param {...*}     [opts.extra] - Extra data to add to saved data.
   *
   * @returns {PositionData} Current position data
   */
  save({ name, ...extra }) {
    if (typeof name !== "string") {
      throw new TypeError(`Position - save error: 'name' is not a string.`);
    }
    const data = this.#position.get(extra);
    this.#dataSaved.set(name, data);
    return data;
  }
  /**
   * Directly sets a position state.
   *
   * @param {object}   opts - Options.
   *
   * @param {string}   opts.name - name to index this saved data.
   *
   * @param {...*}     [opts.data] - Position data to set.
   */
  set({ name, ...data }) {
    if (typeof name !== "string") {
      throw new TypeError(`Position - set error: 'name' is not a string.`);
    }
    this.#dataSaved.set(name, data);
  }
}
class StyleCache {
  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 = {
      contentHeight: void 0,
      contentWidth: void 0,
      offsetHeight: void 0,
      offsetWidth: void 0
    };
    const storeResizeObserved = writable$1(this.resizeObserved);
    this.stores = {
      element: writable$1(this.el),
      resizeContentHeight: propertyStore(storeResizeObserved, "contentHeight"),
      resizeContentWidth: propertyStore(storeResizeObserved, "contentWidth"),
      resizeObserved: storeResizeObserved,
      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 {number} The element offsetHeight.
   */
  get offsetHeight() {
    if (this.el instanceof HTMLElement) {
      return this.resizeObserved.offsetHeight !== void 0 ? this.resizeObserved.offsetHeight : this.el.offsetHeight;
    }
    throw new Error(`StyleCache - 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 {number} The element offsetHeight.
   */
  get offsetWidth() {
    if (this.el instanceof HTMLElement) {
      return this.resizeObserved.offsetWidth !== void 0 ? this.resizeObserved.offsetWidth : this.el.offsetWidth;
    }
    throw new Error(`StyleCache - get offsetWidth error: no element assigned.`);
  }
  /**
   * @param {HTMLElement} el -
   *
   * @returns {boolean} Does element match cached element.
   */
  hasData(el) {
    return this.el === el;
  }
  /**
   * Resets the style cache.
   */
  reset() {
    if (this.el instanceof HTMLElement && this.el.isConnected && !this.hasWillChange) {
      this.el.style.willChange = null;
    }
    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 {HTMLElement} el - An HTML element.
   */
  update(el) {
    this.el = el;
    this.computed = globalThis.getComputedStyle(el);
    this.marginLeft = styleParsePixels(el.style.marginLeft) ?? styleParsePixels(this.computed.marginLeft);
    this.marginTop = styleParsePixels(el.style.marginTop) ?? styleParsePixels(this.computed.marginTop);
    this.maxHeight = styleParsePixels(el.style.maxHeight) ?? styleParsePixels(this.computed.maxHeight);
    this.maxWidth = styleParsePixels(el.style.maxWidth) ?? styleParsePixels(this.computed.maxWidth);
    this.minHeight = styleParsePixels(el.style.minHeight) ?? styleParsePixels(this.computed.minHeight);
    this.minWidth = styleParsePixels(el.style.minWidth) ?? styleParsePixels(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 TransformData {
  constructor() {
    Object.seal(this);
  }
  /**
   * Stores the calculated bounding rectangle.
   *
   * @type {DOMRect}
   */
  #boundingRect = new DOMRect();
  /**
   * Stores the individual transformed corner points of the window in screenspace clockwise from:
   * top left -> top right -> bottom right -> bottom left.
   *
   * @type {Vector3[]}
   */
  #corners = [vec3.create(), vec3.create(), vec3.create(), vec3.create()];
  /**
   * Stores the current gl-matrix mat4 data.
   *
   * @type {Matrix4}
   */
  #mat4 = mat4.create();
  /**
   * Stores the pre & post origin translations to apply to matrix transforms.
   *
   * @type {Matrix4[]}
   */
  #originTranslations = [mat4.create(), mat4.create()];
  /**
   * @returns {DOMRect} The bounding rectangle.
   */
  get boundingRect() {
    return this.#boundingRect;
  }
  /**
   * @returns {Vector3[]} The transformed corner points as vec3 in screen space.
   */
  get corners() {
    return this.#corners;
  }
  /**
   * @returns {string} Returns the CSS style string for the transform matrix.
   */
  get css() {
    return `matrix3d(${this.mat4.join(",")})`;
  }
  /**
   * @returns {Matrix4} The transform matrix.
   */
  get mat4() {
    return this.#mat4;
  }
  /**
   * @returns {Matrix4[]} The pre / post translation matrices for origin translation.
   */
  get originTranslations() {
    return this.#originTranslations;
  }
}
class AdapterValidators {
  /** @type {boolean} */
  #enabled = true;
  /**
   * @type {ValidatorData[]}
   */
  #validatorData;
  #mapUnsubscribe = /* @__PURE__ */ new Map();
  /**
   * @returns {[AdapterValidators, ValidatorData[]]} Returns this and internal storage for validator adapter.
   */
  constructor() {
    this.#validatorData = [];
    Object.seal(this);
    return [this, this.#validatorData];
  }
  /**
   * @returns {boolean} Returns the enabled state.s
   */
  get enabled() {
    return this.#enabled;
  }
  /**
   * @returns {number} Returns the length of the validators array.
   */
  get length() {
    return this.#validatorData.length;
  }
  /**
   * @param {boolean}  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 {Generator<ValidatorData|undefined>} Generator / iterator of validators.
   * @yields {ValidatorData}
   */
  *[Symbol.iterator]() {
    if (this.#validatorData.length === 0) {
      return;
    }
    for (const entry of this.#validatorData) {
      yield { ...entry };
    }
  }
  /**
   * @param {...(ValidatorFn|ValidatorData)}   validators -
   */
  add(...validators) {
    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,
            validator,
            weight: 1
          };
          subscribeFn = validator.subscribe;
          break;
        case "object":
          if (typeof validator.validator !== "function") {
            throw new TypeError(`AdapterValidator error: 'validator' 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,
            validator: validator.validator.bind(validator),
            weight: validator.weight || 1,
            instance: validator
          };
          subscribeFn = validator.validator.subscribe ?? validator.subscribe;
          break;
      }
      const index = this.#validatorData.findIndex((value) => {
        return 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();
        if (typeof unsubscribe !== "function") {
          throw new TypeError(
            "AdapterValidator error: Filter has subscribe function, but no unsubscribe function is returned."
          );
        }
        if (this.#mapUnsubscribe.has(data.validator)) {
          throw new Error(
            "AdapterValidator error: Filter added already has an unsubscribe function registered."
          );
        }
        this.#mapUnsubscribe.set(data.validator, unsubscribe);
      }
    }
  }
  clear() {
    this.#validatorData.length = 0;
    for (const unsubscribe of this.#mapUnsubscribe.values()) {
      unsubscribe();
    }
    this.#mapUnsubscribe.clear();
  }
  /**
   * @param {...(ValidatorFn|ValidatorData)}   validators -
   */
  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.validator : void 0;
      if (!actualValidator) {
        continue;
      }
      for (let cntr = this.#validatorData.length; --cntr >= 0; ) {
        if (this.#validatorData[cntr].validator === actualValidator) {
          this.#validatorData.splice(cntr, 1);
          let unsubscribe = void 0;
          if (typeof (unsubscribe = this.#mapUnsubscribe.get(actualValidator)) === "function") {
            unsubscribe();
            this.#mapUnsubscribe.delete(actualValidator);
          }
        }
      }
    }
  }
  /**
   * Remove validators by the provided callback. The callback takes 3 parameters: `id`, `validator`, and `weight`.
   * Any truthy value returned will remove that validator.
   *
   * @param {function(*, ValidatorFn, number): boolean} 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.validator)) === "function") {
          unsubscribe();
          this.#mapUnsubscribe.delete(data.validator);
        }
      }
      return !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.validator)) === "function") {
          unsubscribe();
          this.#mapUnsubscribe.delete(data.validator);
        }
      }
      return !remove;
    });
  }
}
class BasicBounds {
  /**
   * When true constrains the min / max width or height to element.
   *
   * @type {boolean}
   */
  #constrain;
  /**
   * @type {HTMLElement}
   */
  #element;
  /**
   * When true the validator is active.
   *
   * @type {boolean}
   */
  #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`.
   *
   * @type {number}
   */
  #height;
  /**
   * Set from an optional value in the constructor to lock accessors preventing modification.
   */
  #lock;
  /**
   * 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`.
   *
   * @type {number}
   */
  #width;
  constructor({ constrain = true, element: element2, enabled = true, lock = false, width: width2, height } = {}) {
    this.element = element2;
    this.constrain = constrain;
    this.enabled = enabled;
    this.width = width2;
    this.height = height;
    this.#lock = typeof lock === "boolean" ? lock : false;
  }
  get constrain() {
    return this.#constrain;
  }
  get element() {
    return this.#element;
  }
  get enabled() {
    return this.#enabled;
  }
  get height() {
    return this.#height;
  }
  get width() {
    return this.#width;
  }
  set constrain(constrain) {
    if (this.#lock) {
      return;
    }
    if (typeof constrain !== "boolean") {
      throw new TypeError(`'constrain' is not a boolean.`);
    }
    this.#constrain = constrain;
  }
  set element(element2) {
    if (this.#lock) {
      return;
    }
    if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
      this.#element = element2;
    } else {
      throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
    }
  }
  set enabled(enabled) {
    if (this.#lock) {
      return;
    }
    if (typeof enabled !== "boolean") {
      throw new TypeError(`'enabled' is not a boolean.`);
    }
    this.#enabled = enabled;
  }
  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.`);
    }
  }
  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.`);
    }
  }
  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.`);
    }
  }
  /**
   * Provides a validator that respects transforms in positional data constraining the position to within the target
   * elements bounds.
   *
   * @param {ValidationData}   valData - The associated validation data for position updates.
   *
   * @returns {PositionData} Potentially adjusted position data.
   */
  validator(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 = valData.width = Math.clamped(valData.position.width, valData.minWidth, maxW);
      if (valData.width + valData.position.left + valData.marginLeft > boundsWidth) {
        valData.position.left = boundsWidth - valData.width - valData.marginLeft;
      }
    }
    if (typeof valData.position.height === "number") {
      const maxH = valData.maxHeight ?? (this.#constrain ? boundsHeight : Number.MAX_SAFE_INTEGER);
      valData.position.height = valData.height = Math.clamped(valData.position.height, valData.minHeight, maxH);
      if (valData.height + valData.position.top + valData.marginTop > boundsHeight) {
        valData.position.top = boundsHeight - valData.height - valData.marginTop;
      }
    }
    const maxL = Math.max(boundsWidth - valData.width - valData.marginLeft, 0);
    valData.position.left = Math.round(Math.clamped(valData.position.left, 0, maxL));
    const maxT = Math.max(boundsHeight - valData.height - valData.marginTop, 0);
    valData.position.top = Math.round(Math.clamped(valData.position.top, 0, maxT));
    return valData.position;
  }
}
const s_TRANSFORM_DATA = new TransformData();
class TransformBounds {
  /**
   * When true constrains the min / max width or height to element.
   *
   * @type {boolean}
   */
  #constrain;
  /**
   * @type {HTMLElement}
   */
  #element;
  /**
   * When true the validator is active.
   *
   * @type {boolean}
   */
  #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`.
   *
   * @type {number}
   */
  #height;
  /**
   * Set from an optional value in the constructor to lock accessors preventing modification.
   */
  #lock;
  /**
   * 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`.
   *
   * @type {number}
   */
  #width;
  constructor({ constrain = true, element: element2, enabled = true, lock = false, width: width2, height } = {}) {
    this.element = element2;
    this.constrain = constrain;
    this.enabled = enabled;
    this.width = width2;
    this.height = height;
    this.#lock = typeof lock === "boolean" ? lock : false;
  }
  get constrain() {
    return this.#constrain;
  }
  get element() {
    return this.#element;
  }
  get enabled() {
    return this.#enabled;
  }
  get height() {
    return this.#height;
  }
  get width() {
    return this.#width;
  }
  set constrain(constrain) {
    if (this.#lock) {
      return;
    }
    if (typeof constrain !== "boolean") {
      throw new TypeError(`'constrain' is not a boolean.`);
    }
    this.#constrain = constrain;
  }
  set element(element2) {
    if (this.#lock) {
      return;
    }
    if (element2 === void 0 || element2 === null || element2 instanceof HTMLElement) {
      this.#element = element2;
    } else {
      throw new TypeError(`'element' is not a HTMLElement, undefined, or null.`);
    }
  }
  set enabled(enabled) {
    if (this.#lock) {
      return;
    }
    if (typeof enabled !== "boolean") {
      throw new TypeError(`'enabled' is not a boolean.`);
    }
    this.#enabled = enabled;
  }
  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.`);
    }
  }
  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.`);
    }
  }
  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.`);
    }
  }
  /**
   * Provides a validator that respects transforms in positional data constraining the position to within the target
   * elements bounds.
   *
   * @param {ValidationData}   valData - The associated validation data for position updates.
   *
   * @returns {PositionData} Potentially adjusted position data.
   */
  validator(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 = Math.clamped(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 = Math.clamped(valData.height, valData.minHeight, maxH);
    }
    const data = valData.transforms.getData(valData.position, s_TRANSFORM_DATA, valData);
    const initialX = data.boundingRect.x;
    const initialY = data.boundingRect.y;
    if (data.boundingRect.bottom + valData.marginTop > boundsHeight) {
      data.boundingRect.y += boundsHeight - data.boundingRect.bottom - valData.marginTop;
    }
    if (data.boundingRect.right + valData.marginLeft > boundsWidth) {
      data.boundingRect.x += boundsWidth - data.boundingRect.right - valData.marginLeft;
    }
    if (data.boundingRect.top - valData.marginTop < 0) {
      data.boundingRect.y += Math.abs(data.boundingRect.top - valData.marginTop);
    }
    if (data.boundingRect.left - valData.marginLeft < 0) {
      data.boundingRect.x += Math.abs(data.boundingRect.left - valData.marginLeft);
    }
    valData.position.left -= initialX - data.boundingRect.x;
    valData.position.top -= initialY - data.boundingRect.y;
    return valData.position;
  }
}
const basicWindow = new BasicBounds({ lock: true });
const transformWindow = new TransformBounds({ lock: true });
const positionValidators = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
  __proto__: null,
  BasicBounds,
  TransformBounds,
  basicWindow,
  transformWindow
}, Symbol.toStringTag, { value: "Module" }));
const s_SCALE_VECTOR = [1, 1, 1];
const s_TRANSLATE_VECTOR = [0, 0, 0];
const s_MAT4_RESULT = mat4.create();
const s_MAT4_TEMP = mat4.create();
const s_VEC3_TEMP = vec3.create();
class Transforms {
  /**
   * Stores the transform keys in the order added.
   *
   * @type {string[]}
   */
  #orderList = [];
  constructor() {
    this._data = {};
  }
  /**
   * @returns {boolean} Whether there are active transforms in local data.
   */
  get isActive() {
    return this.#orderList.length > 0;
  }
  /**
   * @returns {number|undefined} Any local rotateX data.
   */
  get rotateX() {
    return this._data.rotateX;
  }
  /**
   * @returns {number|undefined} Any local rotateY data.
   */
  get rotateY() {
    return this._data.rotateY;
  }
  /**
   * @returns {number|undefined} Any local rotateZ data.
   */
  get rotateZ() {
    return this._data.rotateZ;
  }
  /**
   * @returns {number|undefined} Any local rotateZ scale.
   */
  get scale() {
    return this._data.scale;
  }
  /**
   * @returns {number|undefined} Any local translateZ data.
   */
  get translateX() {
    return this._data.translateX;
  }
  /**
   * @returns {number|undefined} Any local translateZ data.
   */
  get translateY() {
    return this._data.translateY;
  }
  /**
   * @returns {number|undefined} 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 {number|null|undefined}   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 {number|null|undefined}   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 {number|null|undefined}   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 {number|null|undefined}   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 {number|null|undefined}   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 {number|null|undefined}   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 {number|null|undefined}   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 {object} [data] - Optional position data otherwise use local stored transform data.
   *
   * @returns {string} The CSS matrix3d string.
   */
  getCSS(data = this._data) {
    return `matrix3d(${this.getMat4(data, s_MAT4_RESULT).join(",")})`;
  }
  /**
   * Returns the matrix3d CSS transform for the given position / transform data.
   *
   * @param {object} [data] - Optional position data otherwise use local stored transform data.
   *
   * @returns {string} The CSS matrix3d string.
   */
  getCSSOrtho(data = this._data) {
    return `matrix3d(${this.getMat4Ortho(data, s_MAT4_RESULT).join(",")})`;
  }
  /**
   * Collects all data including a bounding rect, transform matrix, and points array of the given {@link PositionData}
   * instance with the applied local transform data.
   *
   * @param {PositionData} position - The position data to process.
   *
   * @param {TransformData} [output] - Optional TransformData output instance.
   *
   * @param {object} [validationData] - Optional validation data for adjustment parameters.
   *
   * @returns {TransformData} The output TransformData instance.
   */
  getData(position, output = new TransformData(), validationData = {}) {
    const valWidth = validationData.width ?? 0;
    const valHeight = validationData.height ?? 0;
    const valOffsetTop = validationData.offsetTop ?? validationData.marginTop ?? 0;
    const valOffsetLeft = validationData.offsetLeft ?? validationData.offsetLeft ?? 0;
    position.top += valOffsetTop;
    position.left += valOffsetLeft;
    const width2 = Number.isFinite(position.width) ? position.width : valWidth;
    const height = Number.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 = s_GET_ORIGIN_TRANSLATION(position.transformOrigin, width2, height, output.originTranslations);
      if (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 {object}   [data] - PositionData instance or local transform data.
   *
   * @param {Matrix4}  [output] - The output mat4 instance.
   *
   * @returns {Matrix4} Transform matrix.
   */
  getMat4(data = this._data, output = mat4.create()) {
    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 |= transformKeysBitwise.rotateX;
          mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
        case "rotateY":
          seenKeys |= transformKeysBitwise.rotateY;
          mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
        case "rotateZ":
          seenKeys |= transformKeysBitwise.rotateZ;
          mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
        case "scale":
          seenKeys |= transformKeysBitwise.scale;
          s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data[key];
          mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
          break;
        case "translateX":
          seenKeys |= transformKeysBitwise.translateX;
          s_TRANSLATE_VECTOR[0] = data.translateX;
          s_TRANSLATE_VECTOR[1] = 0;
          s_TRANSLATE_VECTOR[2] = 0;
          mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
          break;
        case "translateY":
          seenKeys |= transformKeysBitwise.translateY;
          s_TRANSLATE_VECTOR[0] = 0;
          s_TRANSLATE_VECTOR[1] = data.translateY;
          s_TRANSLATE_VECTOR[2] = 0;
          mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
          break;
        case "translateZ":
          seenKeys |= transformKeysBitwise.translateZ;
          s_TRANSLATE_VECTOR[0] = 0;
          s_TRANSLATE_VECTOR[1] = 0;
          s_TRANSLATE_VECTOR[2] = data.translateZ;
          mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
          break;
      }
    }
    if (data !== this._data) {
      for (let cntr = 0; cntr < transformKeys.length; cntr++) {
        const key = transformKeys[cntr];
        if (data[key] === null || (seenKeys & transformKeysBitwise[key]) > 0) {
          continue;
        }
        switch (key) {
          case "rotateX":
            mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
          case "rotateY":
            mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
          case "rotateZ":
            mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
          case "scale":
            s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data[key];
            mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
            break;
          case "translateX":
            s_TRANSLATE_VECTOR[0] = data[key];
            s_TRANSLATE_VECTOR[1] = 0;
            s_TRANSLATE_VECTOR[2] = 0;
            mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
            break;
          case "translateY":
            s_TRANSLATE_VECTOR[0] = 0;
            s_TRANSLATE_VECTOR[1] = data[key];
            s_TRANSLATE_VECTOR[2] = 0;
            mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
            break;
          case "translateZ":
            s_TRANSLATE_VECTOR[0] = 0;
            s_TRANSLATE_VECTOR[1] = 0;
            s_TRANSLATE_VECTOR[2] = data[key];
            mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
            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 {object}   [data] - PositionData instance or local transform data.
   *
   * @param {Matrix4}  [output] - The output mat4 instance.
   *
   * @returns {Matrix4} Transform matrix.
   */
  getMat4Ortho(data = this._data, output = mat4.create()) {
    const matrix = mat4.identity(output);
    s_TRANSLATE_VECTOR[0] = (data.left ?? 0) + (data.translateX ?? 0);
    s_TRANSLATE_VECTOR[1] = (data.top ?? 0) + (data.translateY ?? 0);
    s_TRANSLATE_VECTOR[2] = data.translateZ ?? 0;
    mat4.multiply(matrix, matrix, mat4.fromTranslation(s_MAT4_TEMP, s_TRANSLATE_VECTOR));
    if (data.scale !== null) {
      s_SCALE_VECTOR[0] = s_SCALE_VECTOR[1] = data.scale;
      mat4.multiply(matrix, matrix, mat4.fromScaling(s_MAT4_TEMP, s_SCALE_VECTOR));
    }
    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 |= transformKeysBitwise.rotateX;
          mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
        case "rotateY":
          seenKeys |= transformKeysBitwise.rotateY;
          mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
        case "rotateZ":
          seenKeys |= transformKeysBitwise.rotateZ;
          mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
          break;
      }
    }
    if (data !== this._data) {
      for (let cntr = 0; cntr < transformKeys.length; cntr++) {
        const key = transformKeys[cntr];
        if (data[key] === null || (seenKeys & transformKeysBitwise[key]) > 0) {
          continue;
        }
        switch (key) {
          case "rotateX":
            mat4.multiply(matrix, matrix, mat4.fromXRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
          case "rotateY":
            mat4.multiply(matrix, matrix, mat4.fromYRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
          case "rotateZ":
            mat4.multiply(matrix, matrix, mat4.fromZRotation(s_MAT4_TEMP, degToRad(data[key])));
            break;
        }
      }
    }
    return matrix;
  }
  /**
   * Tests an object if it contains transform keys and the values are finite numbers.
   *
   * @param {object} data - An object to test for transform data.
   *
   * @returns {boolean} Whether the given PositionData has transforms.
   */
  hasTransform(data) {
    for (const key of transformKeys) {
      if (Number.isFinite(data[key])) {
        return true;
      }
    }
    return false;
  }
  /**
   * Resets internal data from the given object containing valid transform keys.
   *
   * @param {object}   data - An object with transform data.
   */
  reset(data) {
    for (const key in data) {
      if (transformKeys.includes(key)) {
        if (Number.isFinite(data[key])) {
          this._data[key] = data[key];
        } else {
          const index = this.#orderList.findIndex((entry) => entry === key);
          if (index >= 0) {
            this.#orderList.splice(index, 1);
          }
          delete this._data[key];
        }
      }
    }
  }
}
function s_GET_ORIGIN_TRANSLATION(transformOrigin, width2, height, output) {
  const vector = s_VEC3_TEMP;
  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 UpdateElementData {
  constructor() {
    this.data = void 0;
    this.dataSubscribers = new PositionData();
    this.dimensionData = { width: 0, height: 0 };
    this.changeSet = void 0;
    this.options = void 0;
    this.queued = false;
    this.styleCache = void 0;
    this.transforms = void 0;
    this.transformData = new TransformData();
    this.subscriptions = void 0;
    this.storeDimension = writable$1(this.dimensionData);
    this.storeTransform = writable$1(this.transformData, () => {
      this.options.transformSubscribed = true;
      return () => this.options.transformSubscribed = false;
    });
    this.queued = false;
    Object.seal(this.dimensionData);
  }
}
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 = performance.now();
  for (; --cntr >= 0; ) {
    currentTime = await new Promise((resolve) => requestAnimationFrame(resolve));
  }
  return currentTime;
}
class UpdateElementManager {
  static list = [];
  static listCntr = 0;
  static updatePromise;
  static get promise() {
    return this.updatePromise;
  }
  /**
   * Potentially adds the given element and internal updateData instance to the list.
   *
   * @param {HTMLElement}       el - An HTMLElement instance.
   *
   * @param {UpdateElementData} updateData - An UpdateElementData instance.
   *
   * @returns {Promise<number>} 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 {Promise<number>} 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) {
        s_UPDATE_ELEMENT_ORTHO(el, updateData);
      } else {
        s_UPDATE_ELEMENT(el, updateData);
      }
      if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
        s_UPDATE_TRANSFORM(el, updateData);
      }
      this.updateSubscribers(updateData);
    }
    this.listCntr = 0;
    return currentTime;
  }
  /**
   * Potentially immediately updates the given element.
   *
   * @param {HTMLElement}       el - An HTMLElement instance.
   *
   * @param {UpdateElementData} updateData - An UpdateElementData instance.
   */
  static immediate(el, updateData) {
    if (!el.isConnected) {
      return;
    }
    if (updateData.options.ortho) {
      s_UPDATE_ELEMENT_ORTHO(el, updateData);
    } else {
      s_UPDATE_ELEMENT(el, updateData);
    }
    if (updateData.options.calculateTransform || updateData.options.transformSubscribed) {
      s_UPDATE_TRANSFORM(el, updateData);
    }
    this.updateSubscribers(updateData);
  }
  /**
   * @param {UpdateElementData} updateData - Data change set.
   */
  static updateSubscribers(updateData) {
    const data = updateData.data;
    const changeSet = updateData.changeSet;
    if (!changeSet.hasChange()) {
      return;
    }
    const output = updateData.dataSubscribers.copy(data);
    const subscriptions = updateData.subscriptions;
    if (subscriptions.length > 0) {
      for (let cntr = 0; cntr < subscriptions.length; cntr++) {
        subscriptions[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);
  }
}
function s_UPDATE_ELEMENT(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}` : null;
  }
  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 === "center" ? null : data.transformOrigin;
  }
  if (changeSet.transform) {
    el.style.transform = updateData.transforms.isActive ? updateData.transforms.getCSS() : null;
  }
}
function s_UPDATE_ELEMENT_ORTHO(el, updateData) {
  const changeSet = updateData.changeSet;
  const data = updateData.data;
  if (changeSet.zIndex) {
    el.style.zIndex = typeof data.zIndex === "number" ? `${data.zIndex}` : null;
  }
  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 === "center" ? null : data.transformOrigin;
  }
  if (changeSet.left || changeSet.top || changeSet.transform) {
    el.style.transform = updateData.transforms.getCSSOrtho(data);
  }
}
function s_UPDATE_TRANSFORM(el, updateData) {
  s_VALIDATION_DATA$1.height = updateData.data.height !== "auto" ? updateData.data.height : updateData.styleCache.offsetHeight;
  s_VALIDATION_DATA$1.width = updateData.data.width !== "auto" ? updateData.data.width : updateData.styleCache.offsetWidth;
  s_VALIDATION_DATA$1.marginLeft = updateData.styleCache.marginLeft;
  s_VALIDATION_DATA$1.marginTop = updateData.styleCache.marginTop;
  updateData.transforms.getData(updateData.data, updateData.transformData, s_VALIDATION_DATA$1);
  updateData.storeTransform.set(updateData.transformData);
}
const s_VALIDATION_DATA$1 = {
  height: void 0,
  width: void 0,
  marginLeft: void 0,
  marginTop: void 0
};
class Position {
  /**
   * @type {PositionData}
   */
  #data = new PositionData();
  /**
   * Provides the animation API.
   *
   * @type {AnimationAPI}
   */
  #animate = new AnimationAPI(this, this.#data);
  /**
   * Provides a way to turn on / off the position handling.
   *
   * @type {boolean}
   */
  #enabled = true;
  /**
   * Stores the style attributes that changed on update.
   *
   * @type {PositionChangeSet}
   */
  #positionChangeSet = new PositionChangeSet();
  /**
   * Stores ongoing options that are set in the constructor or by transform store subscription.
   *
   * @type {PositionOptions}
   */
  #options = {
    calculateTransform: false,
    initialHelper: void 0,
    ortho: true,
    transformSubscribed: false
  };
  /**
   * The associated parent for positional data tracking. Used in validators.
   *
   * @type {PositionParent}
   */
  #parent;
  /**
   * @type {StorePosition}
   */
  #stores;
  /**
   * Stores an instance of the computer styles for the target element.
   *
   * @type {StyleCache}
   */
  #styleCache;
  /**
   * Stores the subscribers.
   *
   * @type {(function(PositionData): void)[]}
   */
  #subscriptions = [];
  /**
   * @type {Transforms}
   */
  #transforms = new Transforms();
  /**
   * @type {UpdateElementData}
   */
  #updateElementData;
  /**
   * Stores the UpdateElementManager wait promise.
   *
   * @type {Promise}
   */
  #updateElementPromise;
  /**
   * @type {AdapterValidators}
   */
  #validators;
  /**
   * @type {ValidatorData[]}
   */
  #validatorData;
  /**
   * @type {PositionStateAPI}
   */
  #state = new PositionStateAPI(this, this.#data, this.#transforms);
  /**
   * @returns {AnimationGroupAPI} Public Animation API.
   */
  static get Animate() {
    return AnimationGroupAPI;
  }
  /**
   * @returns {{browserCentered?: Centered, Centered?: *}} Initial position helpers.
   */
  static get Initial() {
    return positionInitial;
  }
  /**
   * Returns TransformData class / constructor.
   *
   * @returns {TransformData} TransformData class / constructor.
   */
  static get TransformData() {
    return TransformData;
  }
  /**
   * Returns default validators.
   *
   * Note: `basicWindow` and `BasicBounds` will eventually be removed.
   *
   * @returns {{basicWindow?: BasicBounds, transformWindow?: TransformBounds, TransformBounds?: *, BasicBounds?: *}}
   *  Available validators.
   */
  static get Validators() {
    return positionValidators;
  }
  /**
   * Returns a duplicate of a given position instance copying any options and validators.
   *
   * // TODO: Consider more safety over options processing.
   *
   * @param {Position}          position - A position instance.
   *
   * @param {PositionOptions}   options - Position options.
   *
   * @returns {Position} A duplicate position instance.
   */
  static duplicate(position, options) {
    if (!(position instanceof Position)) {
      throw new TypeError(`'position' is not an instance of Position.`);
    }
    const newPosition = new Position(options);
    newPosition.#options = Object.assign({}, position.#options, options);
    newPosition.#validators.add(...position.#validators);
    newPosition.set(position.#data);
    return newPosition;
  }
  /**
   * @param {PositionParent|PositionOptionsAll}   [parent] - A potential parent element or object w/ `elementTarget`
   *                                                      getter. May also be the PositionOptions object w/ 1 argument.
   *
   * @param {PositionOptionsAll}   [options] - Default values.
   */
  constructor(parent, options) {
    if (isPlainObject(parent)) {
      options = parent;
    } else {
      this.#parent = parent;
    }
    const data = this.#data;
    const transforms = this.#transforms;
    this.#styleCache = new StyleCache();
    const updateData = new UpdateElementData();
    updateData.changeSet = this.#positionChangeSet;
    updateData.data = this.#data;
    updateData.options = this.#options;
    updateData.styleCache = this.#styleCache;
    updateData.subscriptions = this.#subscriptions;
    updateData.transforms = this.#transforms;
    this.#updateElementData = updateData;
    if (isObject(options)) {
      if (typeof options.calculateTransform === "boolean") {
        this.#options.calculateTransform = options.calculateTransform;
      }
      if (typeof options.ortho === "boolean") {
        this.#options.ortho = options.ortho;
      }
      if (Number.isFinite(options.height) || options.height === "auto" || options.height === "inherit" || options.height === null) {
        data.height = updateData.dimensionData.height = typeof options.height === "number" ? Math.round(options.height) : options.height;
      }
      if (Number.isFinite(options.left) || options.left === null) {
        data.left = typeof options.left === "number" ? Math.round(options.left) : options.left;
      }
      if (Number.isFinite(options.maxHeight) || options.maxHeight === null) {
        data.maxHeight = typeof options.maxHeight === "number" ? Math.round(options.maxHeight) : options.maxHeight;
      }
      if (Number.isFinite(options.maxWidth) || options.maxWidth === null) {
        data.maxWidth = typeof options.maxWidth === "number" ? Math.round(options.maxWidth) : options.maxWidth;
      }
      if (Number.isFinite(options.minHeight) || options.minHeight === null) {
        data.minHeight = typeof options.minHeight === "number" ? Math.round(options.minHeight) : options.minHeight;
      }
      if (Number.isFinite(options.minWidth) || options.minWidth === null) {
        data.minWidth = typeof options.minWidth === "number" ? Math.round(options.minWidth) : options.minWidth;
      }
      if (Number.isFinite(options.rotateX) || options.rotateX === null) {
        transforms.rotateX = data.rotateX = options.rotateX;
      }
      if (Number.isFinite(options.rotateY) || options.rotateY === null) {
        transforms.rotateY = data.rotateY = options.rotateY;
      }
      if (Number.isFinite(options.rotateZ) || options.rotateZ === null) {
        transforms.rotateZ = data.rotateZ = options.rotateZ;
      }
      if (Number.isFinite(options.scale) || options.scale === null) {
        transforms.scale = data.scale = options.scale;
      }
      if (Number.isFinite(options.top) || options.top === null) {
        data.top = typeof options.top === "number" ? Math.round(options.top) : options.top;
      }
      if (typeof options.transformOrigin === "string" || options.transformOrigin === null) {
        data.transformOrigin = transformOrigins.includes(options.transformOrigin) ? options.transformOrigin : null;
      }
      if (Number.isFinite(options.translateX) || options.translateX === null) {
        transforms.translateX = data.translateX = options.translateX;
      }
      if (Number.isFinite(options.translateY) || options.translateY === null) {
        transforms.translateY = data.translateY = options.translateY;
      }
      if (Number.isFinite(options.translateZ) || options.translateZ === null) {
        transforms.translateZ = data.translateZ = options.translateZ;
      }
      if (Number.isFinite(options.width) || options.width === "auto" || options.width === "inherit" || options.width === null) {
        data.width = updateData.dimensionData.width = typeof options.width === "number" ? Math.round(options.width) : options.width;
      }
      if (Number.isFinite(options.zIndex) || options.zIndex === null) {
        data.zIndex = typeof options.zIndex === "number" ? Math.round(options.zIndex) : options.zIndex;
      }
    }
    this.#stores = {
      // The main properties for manipulating Position.
      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 },
      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
    };
    subscribeIgnoreFirst(this.#stores.resizeObserved, (resizeData) => {
      const parent2 = this.#parent;
      const el = parent2 instanceof HTMLElement ? parent2 : parent2?.elementTarget;
      if (el instanceof HTMLElement && Number.isFinite(resizeData?.offsetWidth) && Number.isFinite(resizeData?.offsetHeight)) {
        this.set(data);
      }
    });
    this.#stores.transformOrigin.values = transformOrigins;
    [this.#validators, this.#validatorData] = new AdapterValidators();
    if (options?.initial || options?.positionInitial) {
      const initialHelper = options.initial ?? options.positionInitial;
      if (typeof initialHelper?.getLeft !== "function" || typeof initialHelper?.getTop !== "function") {
        throw new Error(
          `'options.initial' position helper does not contain 'getLeft' and / or 'getTop' functions.`
        );
      }
      this.#options.initialHelper = options.initial;
    }
    if (options?.validator) {
      if (isIterable(options?.validator)) {
        this.validators.add(...options.validator);
      } else {
        this.validators.add(options.validator);
      }
    }
  }
  /**
   * Returns the animation API.
   *
   * @returns {AnimationAPI} Animation API.
   */
  get animate() {
    return this.#animate;
  }
  /**
   * Returns the dimension data for the readable store.
   *
   * @returns {{width: number | 'auto', height: number | 'auto'}} Dimension data.
   */
  get dimension() {
    return this.#updateElementData.dimensionData;
  }
  /**
   * Returns the enabled state.
   *
   * @returns {boolean} Enabled state.
   */
  get enabled() {
    return this.#enabled;
  }
  /**
   * Returns the current HTMLElement being positioned.
   *
   * @returns {HTMLElement|undefined} 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<number>} Promise resolved on element update.
   */
  get elementUpdated() {
    return this.#updateElementPromise;
  }
  /**
   * Returns the associated {@link PositionParent} instance.
   *
   * @returns {PositionParent} The PositionParent instance.
   */
  get parent() {
    return this.#parent;
  }
  /**
   * Returns the state API.
   *
   * @returns {PositionStateAPI} Position state API.
   */
  get state() {
    return this.#state;
  }
  /**
   * Returns the derived writable stores for individual data variables.
   *
   * @returns {StorePosition} Derived / writable stores.
   */
  get stores() {
    return this.#stores;
  }
  /**
   * Returns the transform data for the readable store.
   *
   * @returns {TransformData} Transform Data.
   */
  get transform() {
    return this.#updateElementData.transformData;
  }
  /**
   * Returns the validators.
   *
   * @returns {AdapterValidators} validators.
   */
  get validators() {
    return this.#validators;
  }
  /**
   * Sets the enabled state.
   *
   * @param {boolean}  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 PositionParent} instance. Resets the style cache and default data.
   *
   * @param {PositionParent|void} parent - A PositionParent instance.
   */
  set parent(parent) {
    if (parent !== void 0 && !(parent instanceof HTMLElement) && !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 {number|'auto'|'inherit'|null} height
   */
  get height() {
    return this.#data.height;
  }
  /**
   * @returns {number|null} left
   */
  get left() {
    return this.#data.left;
  }
  /**
   * @returns {number|null} maxHeight
   */
  get maxHeight() {
    return this.#data.maxHeight;
  }
  /**
   * @returns {number|null} maxWidth
   */
  get maxWidth() {
    return this.#data.maxWidth;
  }
  /**
   * @returns {number|null} minHeight
   */
  get minHeight() {
    return this.#data.minHeight;
  }
  /**
   * @returns {number|null} minWidth
   */
  get minWidth() {
    return this.#data.minWidth;
  }
  /**
   * @returns {number|null} rotateX
   */
  get rotateX() {
    return this.#data.rotateX;
  }
  /**
   * @returns {number|null} rotateY
   */
  get rotateY() {
    return this.#data.rotateY;
  }
  /**
   * @returns {number|null} rotateZ
   */
  get rotateZ() {
    return this.#data.rotateZ;
  }
  /**
   * @returns {number|null} alias for rotateZ
   */
  get rotation() {
    return this.#data.rotateZ;
  }
  /**
   * @returns {number|null} scale
   */
  get scale() {
    return this.#data.scale;
  }
  /**
   * @returns {number|null} top
   */
  get top() {
    return this.#data.top;
  }
  /**
   * @returns {string} transformOrigin
   */
  get transformOrigin() {
    return this.#data.transformOrigin;
  }
  /**
   * @returns {number|null} translateX
   */
  get translateX() {
    return this.#data.translateX;
  }
  /**
   * @returns {number|null} translateY
   */
  get translateY() {
    return this.#data.translateY;
  }
  /**
   * @returns {number|null} translateZ
   */
  get translateZ() {
    return this.#data.translateZ;
  }
  /**
   * @returns {number|'auto'|'inherit'|null} width
   */
  get width() {
    return this.#data.width;
  }
  /**
   * @returns {number|null} z-index
   */
  get zIndex() {
    return this.#data.zIndex;
  }
  /**
   * @param {number|string|null} height -
   */
  set height(height) {
    this.#stores.height.set(height);
  }
  /**
   * @param {number|string|null} left -
   */
  set left(left) {
    this.#stores.left.set(left);
  }
  /**
   * @param {number|string|null} maxHeight -
   */
  set maxHeight(maxHeight) {
    this.#stores.maxHeight.set(maxHeight);
  }
  /**
   * @param {number|string|null} maxWidth -
   */
  set maxWidth(maxWidth) {
    this.#stores.maxWidth.set(maxWidth);
  }
  /**
   * @param {number|string|null} minHeight -
   */
  set minHeight(minHeight) {
    this.#stores.minHeight.set(minHeight);
  }
  /**
   * @param {number|string|null} minWidth -
   */
  set minWidth(minWidth) {
    this.#stores.minWidth.set(minWidth);
  }
  /**
   * @param {number|string|null} rotateX -
   */
  set rotateX(rotateX) {
    this.#stores.rotateX.set(rotateX);
  }
  /**
   * @param {number|string|null} rotateY -
   */
  set rotateY(rotateY) {
    this.#stores.rotateY.set(rotateY);
  }
  /**
   * @param {number|string|null} rotateZ -
   */
  set rotateZ(rotateZ) {
    this.#stores.rotateZ.set(rotateZ);
  }
  /**
   * @param {number|string|null} rotateZ - alias for rotateZ
   */
  set rotation(rotateZ) {
    this.#stores.rotateZ.set(rotateZ);
  }
  /**
   * @param {number|string|null} scale -
   */
  set scale(scale2) {
    this.#stores.scale.set(scale2);
  }
  /**
   * @param {number|string|null} top -
   */
  set top(top) {
    this.#stores.top.set(top);
  }
  /**
   * @param {string} transformOrigin -
   */
  set transformOrigin(transformOrigin) {
    if (transformOrigins.includes(transformOrigin)) {
      this.#stores.transformOrigin.set(transformOrigin);
    }
  }
  /**
   * @param {number|string|null} translateX -
   */
  set translateX(translateX) {
    this.#stores.translateX.set(translateX);
  }
  /**
   * @param {number|string|null} translateY -
   */
  set translateY(translateY) {
    this.#stores.translateY.set(translateY);
  }
  /**
   * @param {number|string|null} translateZ -
   */
  set translateZ(translateZ) {
    this.#stores.translateZ.set(translateZ);
  }
  /**
   * @param {number|string|null} width -
   */
  set width(width2) {
    this.#stores.width.set(width2);
  }
  /**
   * @param {number|string|null} zIndex -
   */
  set zIndex(zIndex) {
    this.#stores.zIndex.set(zIndex);
  }
  /**
   * Assigns current position to object passed into method.
   *
   * @param {object|PositionData}  [position] - Target to assign current position data.
   *
   * @param {PositionGetOptions}   [options] - Defines options for specific keys and substituting null for numeric
   *                                           default values.
   *
   * @returns {PositionData} Passed in object with current position data.
   */
  get(position = {}, options) {
    const keys = options?.keys;
    const excludeKeys = options?.exclude;
    const numeric = options?.numeric ?? false;
    if (isIterable(keys)) {
      if (numeric) {
        for (const key of keys) {
          position[key] = this[key] ?? numericDefaults[key];
        }
      } else {
        for (const key of keys) {
          position[key] = this[key];
        }
      }
      if (isIterable(excludeKeys)) {
        for (const key of excludeKeys) {
          delete position[key];
        }
      }
      return position;
    } else {
      const data = Object.assign(position, this.#data);
      if (isIterable(excludeKeys)) {
        for (const key of excludeKeys) {
          delete data[key];
        }
      }
      if (numeric) {
        setNumericDefaults(data);
      }
      return data;
    }
  }
  /**
   * @returns {PositionData} Current position data.
   */
  toJSON() {
    return Object.assign({}, this.#data);
  }
  /**
   * All calculation and updates of position are implemented in {@link Position}. This allows position to be fully
   * reactive and in control of updating inline styles for the application.
   *
   * Note: the logic for updating position is improved and changes a few aspects from the default
   * {@link Application.setPosition}. The gate on `popOut` is removed, so to ensure no positional application occurs
   * popOut applications can set `this.options.positionable` to false ensuring no positional inline styles are
   * applied.
   *
   * The initial set call on an application 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 from the application via
   * `this.position.validators.add(<Function>)`.
   *
   * Updates to any target element are decoupled from the underlying Position data. This method returns this instance
   * that you can then await on the target element inline style update by using {@link Position.elementUpdated}.
   *
   * @param {PositionDataExtended} [position] - Position data to set.
   *
   * @returns {Position} This Position instance.
   */
  set(position = {}) {
    if (typeof position !== "object") {
      throw new TypeError(`Position - 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 = position.immediateElementUpdate === true;
    const data = this.#data;
    const transforms = this.#transforms;
    const targetEl = parent instanceof HTMLElement ? parent : parent?.elementTarget;
    const el = targetEl instanceof HTMLElement && 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;
      }
      convertRelative(position, this);
      position = this.#updatePosition(position, parent, el, styleCache);
      if (position === null) {
        return this;
      }
    }
    if (Number.isFinite(position.left)) {
      position.left = Math.round(position.left);
      if (data.left !== position.left) {
        data.left = position.left;
        changeSet.left = true;
      }
    }
    if (Number.isFinite(position.top)) {
      position.top = Math.round(position.top);
      if (data.top !== position.top) {
        data.top = position.top;
        changeSet.top = true;
      }
    }
    if (Number.isFinite(position.maxHeight) || position.maxHeight === null) {
      position.maxHeight = typeof position.maxHeight === "number" ? Math.round(position.maxHeight) : null;
      if (data.maxHeight !== position.maxHeight) {
        data.maxHeight = position.maxHeight;
        changeSet.maxHeight = true;
      }
    }
    if (Number.isFinite(position.maxWidth) || position.maxWidth === null) {
      position.maxWidth = typeof position.maxWidth === "number" ? Math.round(position.maxWidth) : null;
      if (data.maxWidth !== position.maxWidth) {
        data.maxWidth = position.maxWidth;
        changeSet.maxWidth = true;
      }
    }
    if (Number.isFinite(position.minHeight) || position.minHeight === null) {
      position.minHeight = typeof position.minHeight === "number" ? Math.round(position.minHeight) : null;
      if (data.minHeight !== position.minHeight) {
        data.minHeight = position.minHeight;
        changeSet.minHeight = true;
      }
    }
    if (Number.isFinite(position.minWidth) || position.minWidth === null) {
      position.minWidth = typeof position.minWidth === "number" ? Math.round(position.minWidth) : null;
      if (data.minWidth !== position.minWidth) {
        data.minWidth = position.minWidth;
        changeSet.minWidth = true;
      }
    }
    if (Number.isFinite(position.rotateX) || position.rotateX === null) {
      if (data.rotateX !== position.rotateX) {
        data.rotateX = transforms.rotateX = position.rotateX;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.rotateY) || position.rotateY === null) {
      if (data.rotateY !== position.rotateY) {
        data.rotateY = transforms.rotateY = position.rotateY;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.rotateZ) || position.rotateZ === null) {
      if (data.rotateZ !== position.rotateZ) {
        data.rotateZ = transforms.rotateZ = position.rotateZ;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.scale) || position.scale === null) {
      position.scale = typeof position.scale === "number" ? Math.max(0, Math.min(position.scale, 1e3)) : null;
      if (data.scale !== position.scale) {
        data.scale = transforms.scale = position.scale;
        changeSet.transform = true;
      }
    }
    if (typeof position.transformOrigin === "string" && transformOrigins.includes(
      position.transformOrigin
    ) || position.transformOrigin === null) {
      if (data.transformOrigin !== position.transformOrigin) {
        data.transformOrigin = position.transformOrigin;
        changeSet.transformOrigin = true;
      }
    }
    if (Number.isFinite(position.translateX) || position.translateX === null) {
      if (data.translateX !== position.translateX) {
        data.translateX = transforms.translateX = position.translateX;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.translateY) || position.translateY === null) {
      if (data.translateY !== position.translateY) {
        data.translateY = transforms.translateY = position.translateY;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.translateZ) || position.translateZ === null) {
      if (data.translateZ !== position.translateZ) {
        data.translateZ = transforms.translateZ = position.translateZ;
        changeSet.transform = true;
      }
    }
    if (Number.isFinite(position.zIndex)) {
      position.zIndex = Math.round(position.zIndex);
      if (data.zIndex !== position.zIndex) {
        data.zIndex = position.zIndex;
        changeSet.zIndex = true;
      }
    }
    if (Number.isFinite(position.width) || position.width === "auto" || position.width === "inherit" || position.width === null) {
      position.width = typeof position.width === "number" ? Math.round(position.width) : position.width;
      if (data.width !== position.width) {
        data.width = position.width;
        changeSet.width = true;
      }
    }
    if (Number.isFinite(position.height) || position.height === "auto" || position.height === "inherit" || position.height === null) {
      position.height = typeof position.height === "number" ? Math.round(position.height) : position.height;
      if (data.height !== position.height) {
        data.height = position.height;
        changeSet.height = true;
      }
    }
    if (el) {
      const defaultData = this.#state.getDefault();
      if (typeof defaultData !== "object") {
        this.#state.save({ name: "#defaultData", ...Object.assign({}, data) });
      }
      if (immediateElementUpdate) {
        UpdateElementManager.immediate(el, this.#updateElementData);
        this.#updateElementPromise = Promise.resolve(performance.now());
      } else if (!this.#updateElementData.queued) {
        this.#updateElementPromise = UpdateElementManager.add(el, this.#updateElementData);
      }
    } else {
      UpdateElementManager.updateSubscribers(this.#updateElementData);
    }
    return this;
  }
  /**
   *
   * @param {function(PositionData): void} handler - Callback function that is invoked on update / changes. Receives
   *                                                 a copy of the PositionData.
   *
   * @returns {(function(): void)} Unsubscribe function.
   */
  subscribe(handler) {
    this.#subscriptions.push(handler);
    handler(Object.assign({}, this.#data));
    return () => {
      const index = this.#subscriptions.findIndex((sub) => sub === handler);
      if (index >= 0) {
        this.#subscriptions.splice(index, 1);
      }
    };
  }
  /**
   * @param {PositionDataExtended} opts -
   *
   * @param {number|null} opts.left -
   *
   * @param {number|null} opts.top -
   *
   * @param {number|null} opts.maxHeight -
   *
   * @param {number|null} opts.maxWidth -
   *
   * @param {number|null} opts.minHeight -
   *
   * @param {number|null} opts.minWidth -
   *
   * @param {number|'auto'|null} opts.width -
   *
   * @param {number|'auto'|null} opts.height -
   *
   * @param {number|null} opts.rotateX -
   *
   * @param {number|null} opts.rotateY -
   *
   * @param {number|null} opts.rotateZ -
   *
   * @param {number|null} opts.scale -
   *
   * @param {string} opts.transformOrigin -
   *
   * @param {number|null} opts.translateX -
   *
   * @param {number|null} opts.translateY -
   *
   * @param {number|null} opts.translateZ -
   *
   * @param {number|null} opts.zIndex -
   *
   * @param {number|null} opts.rotation - alias for rotateZ
   *
   * @param {*} opts.rest -
   *
   * @param {object} parent -
   *
   * @param {HTMLElement} el -
   *
   * @param {StyleCache} styleCache -
   *
   * @returns {null|PositionData} 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 = s_DATA_UPDATE.copy(this.#data);
    if (el.style.width === "" || width2 !== void 0) {
      if (width2 === "auto" || currentPosition.width === "auto" && width2 !== null) {
        currentPosition.width = "auto";
        width2 = styleCache.offsetWidth;
      } else if (width2 === "inherit" || currentPosition.width === "inherit" && width2 !== null) {
        currentPosition.width = "inherit";
        width2 = styleCache.offsetWidth;
      } else {
        const newWidth = Number.isFinite(width2) ? width2 : currentPosition.width;
        currentPosition.width = width2 = Number.isFinite(newWidth) ? Math.round(newWidth) : styleCache.offsetWidth;
      }
    } else {
      width2 = Number.isFinite(currentPosition.width) ? currentPosition.width : styleCache.offsetWidth;
    }
    if (el.style.height === "" || height !== void 0) {
      if (height === "auto" || currentPosition.height === "auto" && height !== null) {
        currentPosition.height = "auto";
        height = styleCache.offsetHeight;
      } else if (height === "inherit" || currentPosition.height === "inherit" && height !== null) {
        currentPosition.height = "inherit";
        height = styleCache.offsetHeight;
      } else {
        const newHeight = Number.isFinite(height) ? height : currentPosition.height;
        currentPosition.height = height = Number.isFinite(newHeight) ? Math.round(newHeight) : styleCache.offsetHeight;
      }
    } else {
      height = Number.isFinite(currentPosition.height) ? currentPosition.height : styleCache.offsetHeight;
    }
    if (Number.isFinite(left)) {
      currentPosition.left = left;
    } else if (!Number.isFinite(currentPosition.left)) {
      currentPosition.left = typeof this.#options.initialHelper?.getLeft === "function" ? this.#options.initialHelper.getLeft(width2) : 0;
    }
    if (Number.isFinite(top)) {
      currentPosition.top = top;
    } else if (!Number.isFinite(currentPosition.top)) {
      currentPosition.top = typeof this.#options.initialHelper?.getTop === "function" ? this.#options.initialHelper.getTop(height) : 0;
    }
    if (Number.isFinite(maxHeight) || maxHeight === null) {
      currentPosition.maxHeight = Number.isFinite(maxHeight) ? Math.round(maxHeight) : null;
    }
    if (Number.isFinite(maxWidth) || maxWidth === null) {
      currentPosition.maxWidth = Number.isFinite(maxWidth) ? Math.round(maxWidth) : null;
    }
    if (Number.isFinite(minHeight) || minHeight === null) {
      currentPosition.minHeight = Number.isFinite(minHeight) ? Math.round(minHeight) : null;
    }
    if (Number.isFinite(minWidth) || minWidth === null) {
      currentPosition.minWidth = Number.isFinite(minWidth) ? Math.round(minWidth) : null;
    }
    if (Number.isFinite(rotateX) || rotateX === null) {
      currentPosition.rotateX = rotateX;
    }
    if (Number.isFinite(rotateY) || rotateY === null) {
      currentPosition.rotateY = rotateY;
    }
    if (rotateZ !== currentPosition.rotateZ && (Number.isFinite(rotateZ) || rotateZ === null)) {
      currentPosition.rotateZ = rotateZ;
    } else if (rotation2 !== currentPosition.rotateZ && (Number.isFinite(rotation2) || rotation2 === null)) {
      currentPosition.rotateZ = rotation2;
    }
    if (Number.isFinite(translateX) || translateX === null) {
      currentPosition.translateX = translateX;
    }
    if (Number.isFinite(translateY) || translateY === null) {
      currentPosition.translateY = translateY;
    }
    if (Number.isFinite(translateZ) || translateZ === null) {
      currentPosition.translateZ = translateZ;
    }
    if (Number.isFinite(scale2) || scale2 === null) {
      currentPosition.scale = typeof scale2 === "number" ? Math.max(0, Math.min(scale2, 1e3)) : null;
    }
    if (typeof transformOrigin === "string" || transformOrigin === null) {
      currentPosition.transformOrigin = transformOrigins.includes(transformOrigin) ? transformOrigin : null;
    }
    if (Number.isFinite(zIndex) || zIndex === null) {
      currentPosition.zIndex = typeof zIndex === "number" ? Math.round(zIndex) : zIndex;
    }
    const validatorData = this.#validatorData;
    if (this.#validators.enabled && validatorData.length) {
      s_VALIDATION_DATA.parent = parent;
      s_VALIDATION_DATA.el = el;
      s_VALIDATION_DATA.computed = styleCache.computed;
      s_VALIDATION_DATA.transforms = this.#transforms;
      s_VALIDATION_DATA.height = height;
      s_VALIDATION_DATA.width = width2;
      s_VALIDATION_DATA.marginLeft = styleCache.marginLeft;
      s_VALIDATION_DATA.marginTop = styleCache.marginTop;
      s_VALIDATION_DATA.maxHeight = styleCache.maxHeight ?? currentPosition.maxHeight;
      s_VALIDATION_DATA.maxWidth = styleCache.maxWidth ?? currentPosition.maxWidth;
      const isMinimized = parent?.reactive?.minimized ?? false;
      s_VALIDATION_DATA.minHeight = isMinimized ? currentPosition.minHeight ?? 0 : styleCache.minHeight || (currentPosition.minHeight ?? 0);
      s_VALIDATION_DATA.minWidth = isMinimized ? currentPosition.minWidth ?? 0 : styleCache.minWidth || (currentPosition.minWidth ?? 0);
      for (let cntr = 0; cntr < validatorData.length; cntr++) {
        s_VALIDATION_DATA.position = currentPosition;
        s_VALIDATION_DATA.rest = rest;
        currentPosition = validatorData[cntr].validator(s_VALIDATION_DATA);
        if (currentPosition === null) {
          return null;
        }
      }
    }
    return currentPosition;
  }
}
const s_DATA_UPDATE = new PositionData();
const s_VALIDATION_DATA = {
  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
};
Object.seal(s_VALIDATION_DATA);
class ApplicationState {
  /** @type {ApplicationShellExt} */
  #application;
  /** @type {Map<string, ApplicationStateData>} */
  #dataSaved = /* @__PURE__ */ new Map();
  /**
   * @param {ApplicationShellExt}   application - The application.
   */
  constructor(application) {
    this.#application = application;
    Object.seal(this);
  }
  /**
   * Returns current application state along with any extra data passed into method.
   *
   * @param {object} [extra] - Extra data to add to application state.
   *
   * @returns {ApplicationStateData} Passed in object with current application state.
   */
  get(extra = {}) {
    return Object.assign(extra, {
      position: this.#application?.position?.get(),
      beforeMinimized: this.#application?.position?.state.get({ name: "#beforeMinimized" }),
      options: Object.assign({}, this.#application?.options),
      ui: { minimized: this.#application?.reactive?.minimized }
    });
  }
  /**
   * Returns any stored save state by name.
   *
   * @param {string}   name - Saved data set name.
   *
   * @returns {ApplicationStateData} The saved data set.
   */
  getSave({ name }) {
    if (typeof name !== "string") {
      throw new TypeError(`ApplicationState - getSave error: 'name' is not a string.`);
    }
    return this.#dataSaved.get(name);
  }
  /**
   * Removes and returns any application state by name.
   *
   * @param {object}   options - Options.
   *
   * @param {string}   options.name - Name to remove and retrieve.
   *
   * @returns {ApplicationStateData} Saved application data.
   */
  remove({ name }) {
    if (typeof name !== "string") {
      throw new TypeError(`ApplicationState - remove: 'name' is not a string.`);
    }
    const data = this.#dataSaved.get(name);
    this.#dataSaved.delete(name);
    return data;
  }
  /**
   * Restores a saved application 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, easing, and interpolate functions along with configuring a Promise to be
   * returned if awaiting the end of the animation.
   *
   * @param {object}            params - Parameters
   *
   * @param {string}            params.name - Saved data set name.
   *
   * @param {boolean}           [params.remove=false] - Remove data set.
   *
   * @param {boolean}           [params.async=false] - If animating return a Promise that resolves with any saved data.
   *
   * @param {boolean}           [params.animateTo=false] - Animate to restore data.
   *
   * @param {number}            [params.duration=0.1] - Duration in seconds.
   *
   * @param {Function}          [params.ease=linear] - Easing function.
   *
   * @param {Function}          [params.interpolate=lerp] - Interpolation function.
   *
   * @returns {ApplicationStateData|Promise<ApplicationStateData>} Saved application data.
   */
  restore({
    name,
    remove = false,
    async = false,
    animateTo = false,
    duration = 0.1,
    ease = identity,
    interpolate: interpolate2 = lerp$5
  }) {
    if (typeof name !== "string") {
      throw new TypeError(`ApplicationState - restore error: 'name' is not a string.`);
    }
    const dataSaved = this.#dataSaved.get(name);
    if (dataSaved) {
      if (remove) {
        this.#dataSaved.delete(name);
      }
      if (async) {
        return this.set(dataSaved, { async, animateTo, duration, ease, interpolate: interpolate2 }).then(() => dataSaved);
      } else {
        this.set(dataSaved, { async, animateTo, duration, ease, interpolate: interpolate2 });
      }
    }
    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 data.
   *
   * @param {...*}     [options.extra] - Extra data to add to saved data.
   *
   * @returns {ApplicationStateData} Current application data
   */
  save({ name, ...extra }) {
    if (typeof name !== "string") {
      throw new TypeError(`ApplicationState - save error: 'name' is not a string.`);
    }
    const data = this.get(extra);
    this.#dataSaved.set(name, data);
    return data;
  }
  /**
   * Restores a saved application 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, easing, and interpolate functions along with configuring a Promise to be
   * returned if awaiting the end of the animation.
   *
   * 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.
   *
   * TODO: THIS METHOD NEEDS TO BE REFACTORED WHEN TRL IS MADE INTO A STANDALONE FRAMEWORK.
   *
   * @param {ApplicationStateData}   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 {Function}          [opts.ease=linear] - Easing function.
   *
   * @param {Function}          [opts.interpolate=lerp] - Interpolation function.
   *
   * @returns {ApplicationShellExt|Promise<ApplicationShellExt>} When synchronous the application or Promise when
   *                                                             animating resolving with application.
   */
  set(data, { async = false, animateTo = false, duration = 0.1, ease = identity, interpolate: interpolate2 = lerp$5 } = {}) {
    if (!isObject(data)) {
      throw new TypeError(`ApplicationState - restore error: 'data' is not an object.`);
    }
    const application = this.#application;
    if (!isObject(data?.position)) {
      console.warn(`ApplicationState.set warning: 'data.position' is not an object.`);
      return application;
    }
    const rendered = application.rendered;
    if (animateTo && !rendered) {
      console.warn(`ApplicationState.set warning: Application is not rendered and 'animateTo' is true.`);
      return application;
    }
    if (animateTo) {
      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, interpolate: interpolate2 }
      ).finished.then((cancelled) => {
        if (cancelled) {
          return application;
        }
        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 });
        }
        return application;
      });
      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);
      }
    }
    return application;
  }
}
class GetSvelteData {
  /**
   * @type {MountedAppShell[]|null[]}
   */
  #applicationShellHolder;
  /**
   * @type {SvelteData[]}
   */
  #svelteData;
  /**
   * Keep a direct reference to the SvelteData array in an associated {@link SvelteApplication}.
   *
   * @param {MountedAppShell[]|null[]}  applicationShellHolder - A reference to the MountedAppShell array.
   *
   * @param {SvelteData[]}  svelteData - A reference to the SvelteData array of mounted components.
   */
  constructor(applicationShellHolder, svelteData) {
    this.#applicationShellHolder = applicationShellHolder;
    this.#svelteData = svelteData;
  }
  /**
   * Returns any mounted {@link MountedAppShell}.
   *
   * @returns {MountedAppShell|null} Any mounted application shell.
   */
  get applicationShell() {
    return this.#applicationShellHolder[0];
  }
  /**
   * Returns the indexed Svelte component.
   *
   * @param {number}   index -
   *
   * @returns {object} The loaded Svelte component.
   */
  component(index) {
    const data = this.#svelteData[index];
    return isObject(data) ? data?.component : void 0;
  }
  /**
   * Returns the Svelte component entries iterator.
   *
   * @returns {Generator<Array<number|SvelteComponent>>} Svelte component entries iterator.
   * @yields
   */
  *componentEntries() {
    for (let cntr = 0; cntr < this.#svelteData.length; cntr++) {
      yield [cntr, this.#svelteData[cntr].component];
    }
  }
  /**
   * Returns the Svelte component values iterator.
   *
   * @returns {Generator<SvelteComponent>} Svelte component values iterator.
   * @yields
   */
  *componentValues() {
    for (let cntr = 0; cntr < this.#svelteData.length; cntr++) {
      yield this.#svelteData[cntr].component;
    }
  }
  /**
   * Returns the indexed SvelteData entry.
   *
   * @param {number}   index -
   *
   * @returns {SvelteData} The loaded Svelte config + component.
   */
  data(index) {
    return this.#svelteData[index];
  }
  /**
   * Returns the {@link SvelteData} instance for a given component.
   *
   * @param {object} component - Svelte component.
   *
   * @returns {SvelteData} -  The loaded Svelte config + component.
   */
  dataByComponent(component) {
    for (const data of this.#svelteData) {
      if (data.component === component) {
        return data;
      }
    }
    return void 0;
  }
  /**
   * Returns the SvelteData entries iterator.
   *
   * @returns {IterableIterator<[number, SvelteData]>} SvelteData entries iterator.
   */
  dataEntries() {
    return this.#svelteData.entries();
  }
  /**
   * Returns the SvelteData values iterator.
   *
   * @returns {IterableIterator<SvelteData>} SvelteData values iterator.
   */
  dataValues() {
    return this.#svelteData.values();
  }
  /**
   * Returns the length of the mounted Svelte component list.
   *
   * @returns {number} Length of mounted Svelte component list.
   */
  get length() {
    return this.#svelteData.length;
  }
}
function loadSvelteConfig({ app, template, config, elementRootUpdate } = {}) {
  const svelteOptions = isObject(config.options) ? config.options : {};
  let target;
  if (config.target instanceof HTMLElement) {
    target = config.target;
  } else if (template instanceof HTMLElement && typeof config.target === "string") {
    target = template.querySelector(config.target);
  } else {
    target = document.createDocumentFragment();
  }
  if (target === void 0) {
    console.log(
      `%c[TRL] loadSvelteConfig error - could not find target selector, '${config.target}', for config:
`,
      "background: rgb(57,34,34)",
      config
    );
    throw new Error();
  }
  const NewSvelteComponent = config.class;
  const svelteConfig = parseSvelteConfig({ ...config, target }, 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);
  svelteConfig.context.set("external", new Proxy({}, {
    get(targetUnused, prop) {
      console.warn(`[TRL] Deprecation warning: Please change getContext('external') to getContext('#external').`);
      return externalContext[prop];
    }
  }));
  const component = new NewSvelteComponent(svelteConfig);
  svelteConfig.eventbus = eventbus;
  let element2;
  if (isApplicationShell(component)) {
    element2 = component.elementRoot;
  }
  if (target instanceof DocumentFragment && target.firstElementChild) {
    if (element2 === void 0) {
      element2 = target.firstElementChild;
    }
    template.append(target);
  } else if (config.target instanceof HTMLElement && element2 === void 0) {
    if (config.target instanceof HTMLElement && typeof svelteOptions.selectorElement !== "string") {
      console.log(
        `%c[TRL] loadSvelteConfig error - HTMLElement target with no 'selectorElement' defined.

Note: If configuring an application shell and directly targeting a HTMLElement did you bind an'elementRoot' and include '<svelte:options accessors={true}/>'?

Offending config:
`,
        "background: rgb(57,34,34)",
        config
      );
      throw new Error();
    }
    element2 = target.querySelector(svelteOptions.selectorElement);
    if (element2 === null || element2 === void 0) {
      console.log(
        `%c[TRL] loadSvelteConfig error - HTMLElement target with 'selectorElement', '${svelteOptions.selectorElement}', not found for config:
`,
        "background: rgb(57,34,34)",
        config
      );
      throw new Error();
    }
  }
  const injectHTML = !(config.target instanceof HTMLElement);
  return { config: svelteConfig, component, element: element2, injectHTML };
}
class SvelteReactive {
  /**
   * @type {SvelteApplication}
   */
  #application;
  /**
   * @type {boolean}
   */
  #initialized = false;
  /** @type {TJSSessionStorage} */
  #sessionStorage;
  /**
   * The Application option store which is injected into mounted Svelte component context under the `external` key.
   *
   * @type {StoreAppOptions}
   */
  #storeAppOptions;
  /**
   * Stores the update function for `#storeAppOptions`.
   *
   * @type {import('svelte/store').Writable.update}
   */
  #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 {StoreUIOptions}
   */
  #storeUIState;
  /**
   * Stores the update function for `#storeUIState`.
   *
   * @type {import('svelte/store').Writable.update}
   */
  #storeUIStateUpdate;
  /**
   * Stores the unsubscribe functions from local store subscriptions.
   *
   * @type {import('svelte/store').Unsubscriber[]}
   */
  #storeUnsubscribe = [];
  /**
   * @param {SvelteApplication} application - The host Foundry application.
   */
  constructor(application) {
    this.#application = application;
    const optionsSessionStorage = application?.options?.sessionStorage;
    if (optionsSessionStorage !== void 0 && !(optionsSessionStorage instanceof TJSSessionStorage)) {
      throw new TypeError(`'options.sessionStorage' is not an instance of TJSSessionStorage.`);
    }
    this.#sessionStorage = optionsSessionStorage !== void 0 ? optionsSessionStorage : new TJSSessionStorage();
  }
  /**
   * Initializes reactive support. Package private for internal use.
   *
   * @returns {SvelteStores|void} Internal methods to interact with Svelte stores.
   * @package
   */
  initialize() {
    if (this.#initialized) {
      return;
    }
    this.#initialized = true;
    this.#storesInitialize();
    return {
      appOptionsUpdate: this.#storeAppOptionsUpdate,
      uiOptionsUpdate: this.#storeUIStateUpdate,
      subscribe: this.#storesSubscribe.bind(this),
      unsubscribe: this.#storesUnsubscribe.bind(this)
    };
  }
  // Store getters -----------------------------------------------------------------------------------------------------
  /**
   * @returns {TJSSessionStorage} Returns TJSSessionStorage instance.
   */
  get sessionStorage() {
    return this.#sessionStorage;
  }
  /**
   * Returns the store for app options.
   *
   * @returns {StoreAppOptions} App options store.
   */
  get storeAppOptions() {
    return this.#storeAppOptions;
  }
  /**
   * Returns the store for UI options.
   *
   * @returns {StoreUIOptions} UI options store.
   */
  get storeUIState() {
    return this.#storeUIState;
  }
  // Only reactive getters ---------------------------------------------------------------------------------------------
  /**
   * 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;
  }
  // 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 SvelteApplicationOptions.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}
   * 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|void}  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 SvelteApplication.position.set}.
   *
   * @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.
   *
   * // TODO DOCUMENT the accessor in more detail.
   *
   * @param {string}   accessor - The path / key to set. You can set multiple levels.
   *
   * @param {*}        value - Value to set.
   */
  setOptions(accessor, value) {
    const success = safeSet(this.#application.options, accessor, value);
    if (success) {
      this.#storeAppOptionsUpdate(() => this.#application.options);
    }
  }
  /**
   * 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$1(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 = {
      dragging: false,
      headerButtons: [],
      minimized: this.#application._minimized,
      resizing: false
    };
    const writableUIOptions = writable$1(this.#dataUIState);
    this.#storeUIStateUpdate = writableUIOptions.update;
    const storeUIState = {
      subscribe: writableUIOptions.subscribe,
      dragging: propertyStore(writableUIOptions, "dragging"),
      headerButtons: derived(writableUIOptions, ($options, set) => set($options.headerButtons)),
      minimized: derived(writableUIOptions, ($options, set) => set($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 SvelteApplication._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 SvelteApplication.close
   */
  #storesUnsubscribe() {
    this.#storeUnsubscribe.forEach((unsubscribe) => unsubscribe());
    this.#storeUnsubscribe = [];
  }
  /**
   * 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 SvelteApplication app options {@link SvelteApplicationOptions.headerButtonNoClose}
   * to remove the close button and {@link SvelteApplicationOptions.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;
    });
  }
}
class SvelteApplication extends Application {
  /**
   * Stores the first mounted component which follows the application shell contract.
   *
   * @type {MountedAppShell[]|null[]} Application shell.
   */
  #applicationShellHolder = [null];
  /**
   * Stores and manages application state for saving / restoring / serializing.
   *
   * @type {ApplicationState}
   */
  #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;
  /**
   * 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 {Position}
   */
  #position;
  /**
   * Contains the Svelte stores and reactive accessors.
   *
   * @type {SvelteReactive}
   */
  #reactive;
  /**
   * Stores SvelteData entries with instantiated Svelte components.
   *
   * @type {SvelteData[]}
   */
  #svelteData = [];
  /**
   * Provides a helper class that combines multiple methods for interacting with the mounted components tracked in
   * {@link SvelteData}.
   *
   * @type {GetSvelteData}
   */
  #getSvelteData = new GetSvelteData(this.#applicationShellHolder, this.#svelteData);
  /**
   * Contains methods to interact with the Svelte stores.
   *
   * @type {SvelteStores}
   */
  #stores;
  /**
   * @param {SvelteApplicationOptions} options - The options for the application.
   *
   * @inheritDoc
   */
  constructor(options = {}) {
    super(options);
    this.#applicationState = new ApplicationState(this);
    this.#position = new Position(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 SvelteApplication supports.
   *
   * @returns {SvelteApplicationOptions} options - Application options.
   * @see https://foundryvtt.com/api/interfaces/client.ApplicationOptions.html
   */
  static get defaultOptions() {
    return 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: Position.Initial.browserCentered,
      // A helper for initial position placement.
      positionOrtho: true,
      // When true Position is optimized for orthographic use.
      positionValidator: Position.Validators.transformWindow,
      // A function providing the default validator.
      sessionStorage: void 0,
      // An instance of SessionStorage to share across SvelteApplications.
      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 SvelteApplication.
   *
   * @returns {SvelteReactive} The reactive accessors & Svelte stores.
   */
  get reactive() {
    return this.#reactive;
  }
  /**
   * Returns the application state manager.
   *
   * @returns {ApplicationState} The application state manager.
   */
  get state() {
    return this.#applicationState;
  }
  /**
   * Returns the Svelte helper class w/ various methods to access mounted Svelte components.
   *
   * @returns {GetSvelteData} GetSvelteData
   */
  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.
   *
   * @inheritDoc
   * @protected
   * @ignore
   */
  _activateCoreListeners(html) {
    super._activateCoreListeners(typeof this.options.template === "string" ? html : [this.#elementTarget]);
  }
  /**
   * Provide an override to set this application as the active window regardless of z-index. Changes behaviour from
   * Foundry core. This is important / used for instance in dialog key handling for left / right button selection.
   *
   * @param {object} [opts] - Optional parameters.
   *
   * @param {boolean} [opts.force=false] - Force bring to top; will increment z-index by popOut order.
   *
   */
  bringToTop({ force = false } = {}) {
    if (force || this.popOut) {
      super.bringToTop();
    }
    if (document.activeElement !== document.body && !this.elementTarget.contains(document.activeElement)) {
      if (document.activeElement instanceof HTMLElement) {
        document.activeElement.blur();
      }
      document.body.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 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.
   * @ignore
   */
  async close(options = {}) {
    const states = Application.RENDER_STATES;
    if (!options.force && ![states.RENDERED, states.ERROR].includes(this._state)) {
      return;
    }
    this.#stores.unsubscribe();
    this._state = states.CLOSING;
    const el = this.#elementTarget;
    if (!el) {
      return this._state = states.CLOSED;
    }
    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) {
      svelteDestroyPromises.push(outroAndDestroy(entry.component));
      const eventbus = entry.config.eventbus;
      if (isObject(eventbus) && typeof eventbus.off === "function") {
        eventbus.off();
        entry.config.eventbus = void 0;
      }
    }
    await Promise.all(svelteDestroyPromises);
    this.#svelteData.length = 0;
    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.uiOptionsUpdate((storeOptions) => deepMerge(storeOptions, { minimized: this._minimized }));
    A11yHelper.applyFocusSource(this.options.focusSource);
    delete this.options.focusSource;
  }
  /**
   * 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.
   *
   * @param {JQuery} html -
   *
   * @inheritDoc
   * @ignore
   */
  _injectHTML(html) {
    if (this.popOut && html.length === 0 && Array.isArray(this.options.svelte)) {
      throw new Error(
        "SvelteApplication - _injectHTML - A popout app with no template can only support one Svelte component."
      );
    }
    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 (Array.isArray(this.options.svelte)) {
      for (const svelteConfig of this.options.svelte) {
        const svelteData = loadSvelteConfig({
          app: this,
          template: html[0],
          config: svelteConfig,
          elementRootUpdate
        });
        if (isApplicationShell(svelteData.component)) {
          if (this.svelte.applicationShell !== null) {
            throw new Error(
              `SvelteApplication - _injectHTML - An application shell is already mounted; offending config:
                    ${JSON.stringify(svelteConfig)}`
            );
          }
          this.#applicationShellHolder[0] = svelteData.component;
          if (isHMRProxy(svelteData.component) && Array.isArray(svelteData.component?.$$?.on_hmr)) {
            svelteData.component.$$.on_hmr.push(() => () => this.#updateApplicationShell());
          }
        }
        this.#svelteData.push(svelteData);
      }
    } else if (isObject(this.options.svelte)) {
      const svelteData = loadSvelteConfig({
        app: this,
        template: html[0],
        config: this.options.svelte,
        elementRootUpdate
      });
      if (isApplicationShell(svelteData.component)) {
        if (this.svelte.applicationShell !== null) {
          throw new Error(
            `SvelteApplication - _injectHTML - An application shell is already mounted; offending config:
                 ${JSON.stringify(this.options.svelte)}`
          );
        }
        this.#applicationShellHolder[0] = svelteData.component;
        if (isHMRProxy(svelteData.component) && Array.isArray(svelteData.component?.$$?.on_hmr)) {
          svelteData.component.$$.on_hmr.push(() => () => this.#updateApplicationShell());
        }
      }
      this.#svelteData.push(svelteData);
    }
    const isDocumentFragment = html.length && html[0] instanceof DocumentFragment;
    let injectHTML = true;
    for (const svelteData of this.#svelteData) {
      if (!svelteData.injectHTML) {
        injectHTML = false;
        break;
      }
    }
    if (injectHTML) {
      super._injectHTML(html);
    }
    if (this.svelte.applicationShell !== null) {
      this._element = $(this.svelte.applicationShell.elementRoot);
      this.#elementContent = hasGetter(this.svelte.applicationShell, "elementContent") ? this.svelte.applicationShell.elementContent : null;
      this.#elementTarget = hasGetter(this.svelte.applicationShell, "elementTarget") ? this.svelte.applicationShell.elementTarget : null;
    } else if (isDocumentFragment) {
      for (const svelteData of this.#svelteData) {
        if (svelteData.element instanceof HTMLElement) {
          this._element = $(svelteData.element);
          break;
        }
      }
    }
    if (this.#elementTarget === null) {
      this.#elementTarget = typeof this.options.selectorTarget === "string" ? this._element[0].querySelector(this.options.selectorTarget) : this._element[0];
    }
    if (this.#elementTarget === null || this.#elementTarget === void 0) {
      throw new Error(`SvelteApplication - _injectHTML: Target element '${this.options.selectorTarget}' not found.`);
    }
    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 SvelteApplication.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.uiOptionsUpdate((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 SvelteApplication.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.uiOptionsUpdate((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.
   *
   * @param {object}      [opts] - Optional parameters.
   *
   * @param {HTMLElement} [opts.element] - HTMLElement container for main application element.
   *
   * @param {HTMLElement} [opts.elementContent] - HTMLElement container for content area of application shells.
   *
   * @param {HTMLElement} [opts.elementTarget] - HTMLElement container for main application target element.
   */
  onSvelteMount({ element: element2, elementContent, elementTarget } = {}) {
  }
  // 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.
   *
   * @param {object}      [opts] - Optional parameters.
   *
   * @param {HTMLElement} [opts.element] - HTMLElement container for main application element.
   *
   * @param {HTMLElement} [opts.elementContent] - HTMLElement container for content area of application shells.
   *
   * @param {HTMLElement} [opts.elementTarget] - HTMLElement container for main application target element.
   */
  onSvelteRemount({ element: element2, elementContent, elementTarget } = {}) {
  }
  // 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.
   *
   * @inheritDoc
   * @ignore
   */
  _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 SvelteApplication 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 Position.set}.
   *
   * @inheritDoc
   * @protected
   * @ignore
   */
  async _render(force = false, options = {}) {
    if (isObject(options?.focusSource)) {
      this.options.focusSource = options.focusSource;
    }
    if (this._state === Application.RENDER_STATES.NONE && document.querySelector(`#${this.id}`) instanceof HTMLElement) {
      console.warn(`SvelteApplication - _render: A DOM element already exists for CSS ID '${this.id}'. Cancelling initial render for new application with appId '${this.appId}'.`);
      return;
    }
    await super._render(force, options);
    if (!this.#onMount) {
      this.onSvelteMount({ element: this._element[0], elementContent: this.#elementContent, elementTarget: this.#elementTarget });
      this.#onMount = true;
    }
  }
  /**
   * Render the inner application content. Only render a template if one is defined otherwise provide an empty
   * JQuery element per the core Foundry API.
   *
   * @param {object} data         The data used to render the inner template
   *
   * @returns {Promise.<JQuery>}   A promise resolving to the constructed jQuery object
   *
   * @protected
   * @ignore
   */
  async _renderInner(data) {
    const html = typeof this.template === "string" ? await renderTemplate(this.template, data) : 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.
   *
   * @returns {Promise<JQuery>} Outer frame / unused.
   * @protected
   * @ignore
   */
  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 Position.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 Position.validators} functionality.
   *
   * @param {PositionDataExtended}   [position] - Position data.
   *
   * @returns {Position} The updated position object for the application containing the new values
   */
  setPosition(position) {
    return this.position.set(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 SvelteApplication.
   *
   * This method may also be invoked by HMR / hot module replacement via `svelte-hmr`.
   */
  #updateApplicationShell() {
    const applicationShell = this.svelte.applicationShell;
    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.#elementTarget]);
      this.onSvelteRemount({ element: this._element[0], elementContent: this.#elementContent, elementTarget: this.#elementTarget });
    }
  }
}
const s_STYLE_KEY = "#__trl-root-styles";
const cssVariables = new StyleManager({ docKey: s_STYLE_KEY, version: 1 });
const TJSContainer_svelte_svelte_type_style_lang = "";
function resizeObserver(node, target) {
  ResizeObserverManager.add(node, target);
  return {
    update: (newTarget) => {
      ResizeObserverManager.remove(node, target);
      target = newTarget;
      ResizeObserverManager.add(node, target);
    },
    destroy: () => {
      ResizeObserverManager.remove(node, target);
    }
  };
}
resizeObserver.updateCache = function(el) {
  if (!(el instanceof HTMLElement)) {
    throw new TypeError(`resizeObserverUpdate error: 'el' is not an HTMLElement.`);
  }
  const subscribers = s_MAP.get(el);
  if (Array.isArray(subscribers)) {
    const computed = globalThis.getComputedStyle(el);
    const borderBottom = styleParsePixels(el.style.borderBottom) ?? styleParsePixels(computed.borderBottom) ?? 0;
    const borderLeft = styleParsePixels(el.style.borderLeft) ?? styleParsePixels(computed.borderLeft) ?? 0;
    const borderRight = styleParsePixels(el.style.borderRight) ?? styleParsePixels(computed.borderRight) ?? 0;
    const borderTop = styleParsePixels(el.style.borderTop) ?? styleParsePixels(computed.borderTop) ?? 0;
    const paddingBottom = styleParsePixels(el.style.paddingBottom) ?? styleParsePixels(computed.paddingBottom) ?? 0;
    const paddingLeft = styleParsePixels(el.style.paddingLeft) ?? styleParsePixels(computed.paddingLeft) ?? 0;
    const paddingRight = styleParsePixels(el.style.paddingRight) ?? styleParsePixels(computed.paddingRight) ?? 0;
    const paddingTop = styleParsePixels(el.style.paddingTop) ?? styleParsePixels(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;
      s_UPDATE_SUBSCRIBER(subscriber, subscriber.contentWidth, subscriber.contentHeight);
    }
  }
};
const s_MAP = /* @__PURE__ */ new Map();
class ResizeObserverManager {
  /**
   * Add an HTMLElement and ResizeObserverTarget 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 {ResizeObserverTarget} target - A target that contains one of several mechanisms for updating resize data.
   */
  static add(el, target) {
    const updateType = s_GET_UPDATE_TYPE(target);
    if (updateType === 0) {
      throw new Error(`'target' does not match supported ResizeObserverManager update mechanisms.`);
    }
    const computed = globalThis.getComputedStyle(el);
    const borderBottom = styleParsePixels(el.style.borderBottom) ?? styleParsePixels(computed.borderBottom) ?? 0;
    const borderLeft = styleParsePixels(el.style.borderLeft) ?? styleParsePixels(computed.borderLeft) ?? 0;
    const borderRight = styleParsePixels(el.style.borderRight) ?? styleParsePixels(computed.borderRight) ?? 0;
    const borderTop = styleParsePixels(el.style.borderTop) ?? styleParsePixels(computed.borderTop) ?? 0;
    const paddingBottom = styleParsePixels(el.style.paddingBottom) ?? styleParsePixels(computed.paddingBottom) ?? 0;
    const paddingLeft = styleParsePixels(el.style.paddingLeft) ?? styleParsePixels(computed.paddingLeft) ?? 0;
    const paddingRight = styleParsePixels(el.style.paddingRight) ?? styleParsePixels(computed.paddingRight) ?? 0;
    const paddingTop = styleParsePixels(el.style.paddingTop) ?? styleParsePixels(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 (s_MAP.has(el)) {
      const subscribers = s_MAP.get(el);
      subscribers.push(data);
    } else {
      s_MAP.set(el, [data]);
    }
    s_RESIZE_OBSERVER.observe(el);
  }
  /**
   * Removes all targets 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 {ResizeObserverTarget} [target] - A specific target to remove from monitoring.
   */
  static remove(el, target = void 0) {
    const subscribers = s_MAP.get(el);
    if (Array.isArray(subscribers)) {
      const index = subscribers.findIndex((entry) => entry.target === target);
      if (index >= 0) {
        s_UPDATE_SUBSCRIBER(subscribers[index], void 0, void 0);
        subscribers.splice(index, 1);
      }
      if (subscribers.length === 0) {
        s_MAP.delete(el);
        s_RESIZE_OBSERVER.unobserve(el);
      }
    }
  }
}
const s_UPDATE_TYPES = {
  none: 0,
  attribute: 1,
  function: 2,
  resizeObserved: 3,
  setContentBounds: 4,
  setDimension: 5,
  storeObject: 6,
  storesObject: 7
};
const s_RESIZE_OBSERVER = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const subscribers = s_MAP.get(entry?.target);
    if (Array.isArray(subscribers)) {
      const contentWidth = entry.contentRect.width;
      const contentHeight = entry.contentRect.height;
      for (const subscriber of subscribers) {
        s_UPDATE_SUBSCRIBER(subscriber, contentWidth, contentHeight);
      }
    }
  }
});
function s_GET_UPDATE_TYPE(target) {
  if (target?.resizeObserved instanceof Function) {
    return s_UPDATE_TYPES.resizeObserved;
  }
  if (target?.setDimension instanceof Function) {
    return s_UPDATE_TYPES.setDimension;
  }
  if (target?.setContentBounds instanceof Function) {
    return s_UPDATE_TYPES.setContentBounds;
  }
  const targetType = typeof target;
  if (targetType !== null && (targetType === "object" || targetType === "function")) {
    if (isUpdatableStore(target.resizeObserved)) {
      return s_UPDATE_TYPES.storeObject;
    }
    const stores = target?.stores;
    if (isObject(stores) || typeof stores === "function") {
      if (isUpdatableStore(stores.resizeObserved)) {
        return s_UPDATE_TYPES.storesObject;
      }
    }
  }
  if (targetType !== null && targetType === "object") {
    return s_UPDATE_TYPES.attribute;
  }
  if (targetType === "function") {
    return s_UPDATE_TYPES.function;
  }
  return s_UPDATE_TYPES.none;
}
function s_UPDATE_SUBSCRIBER(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 s_UPDATE_TYPES.attribute:
      target.contentWidth = contentWidth;
      target.contentHeight = contentHeight;
      target.offsetWidth = offsetWidth;
      target.offsetHeight = offsetHeight;
      break;
    case s_UPDATE_TYPES.function:
      target?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
      break;
    case s_UPDATE_TYPES.resizeObserved:
      target.resizeObserved?.(offsetWidth, offsetHeight, contentWidth, contentHeight);
      break;
    case s_UPDATE_TYPES.setContentBounds:
      target.setContentBounds?.(contentWidth, contentHeight);
      break;
    case s_UPDATE_TYPES.setDimension:
      target.setDimension?.(offsetWidth, offsetHeight);
      break;
    case s_UPDATE_TYPES.storeObject:
      target.resizeObserved.update((object) => {
        object.contentHeight = contentHeight;
        object.contentWidth = contentWidth;
        object.offsetHeight = offsetHeight;
        object.offsetWidth = offsetWidth;
        return object;
      });
      break;
    case s_UPDATE_TYPES.storesObject:
      target.stores.resizeObserved.update((object) => {
        object.contentHeight = contentHeight;
        object.contentWidth = contentWidth;
        object.offsetHeight = offsetHeight;
        object.offsetWidth = offsetWidth;
        return object;
      });
      break;
  }
}
function applyStyles(node, properties) {
  function setProperties() {
    if (typeof properties !== "object") {
      return;
    }
    for (const prop of Object.keys(properties)) {
      node.style.setProperty(`${prop}`, properties[prop]);
    }
  }
  setProperties();
  return {
    update(newProperties) {
      properties = newProperties;
      setProperties();
    }
  };
}
function draggable(node, {
  position,
  active: active2 = true,
  button = 0,
  storeDragging = void 0,
  ease = false,
  easeOptions = { duration: 0.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.`);
  }
  let initialPosition = null;
  let initialDragPoint = {};
  let dragging = false;
  let quickTo = position.animate.quickTo(["top", "left"], easeOptions);
  const handlers = {
    dragDown: ["pointerdown", (e) => onDragPointerDown(e), false],
    dragMove: ["pointermove", (e) => onDragPointerChange(e), false],
    dragUp: ["pointerup", (e) => onDragPointerUp(e), 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 (active2) {
    activateListeners();
  }
  function onDragPointerDown(event) {
    if (event.button !== button || !event.isPrimary) {
      return;
    }
    if (!position.enabled) {
      return;
    }
    if (ignoreTargetClassList !== void 0 && event.target instanceof HTMLElement) {
      for (const targetClass of ignoreTargetClassList) {
        if (event.target.classList.contains(targetClass)) {
          return;
        }
      }
    }
    if (hasTargetClassList !== void 0 && event.target instanceof HTMLElement) {
      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 = position.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 (ease) {
      quickTo(newTop, newLeft);
    } else {
      s_POSITION_DATA.left = newLeft;
      s_POSITION_DATA.top = newTop;
      position.set(s_POSITION_DATA);
    }
  }
  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 active being true won't automatically add listeners twice.
    update: (options) => {
      if (typeof options.active === "boolean") {
        active2 = options.active;
        if (active2) {
          activateListeners();
        } else {
          removeListeners();
        }
      }
      if (typeof options.button === "number") {
        button = options.button;
      }
      if (options.position !== void 0 && options.position !== position) {
        position = options.position;
        quickTo = position.animate.quickTo(["top", "left"], easeOptions);
      }
      if (typeof options.ease === "boolean") {
        ease = options.ease;
      }
      if (isObject(options.easeOptions)) {
        easeOptions = options.easeOptions;
        quickTo.options(easeOptions);
      }
      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 DraggableOptions {
  #ease = false;
  #easeOptions = { duration: 0.1, ease: cubicOut };
  /**
   * Stores the subscribers.
   *
   * @type {(function(DraggableOptions): void)[]}
   */
  #subscriptions = [];
  constructor({ ease, easeOptions } = {}) {
    Object.defineProperty(this, "ease", {
      get: () => {
        return this.#ease;
      },
      set: (newEase) => {
        if (typeof newEase !== "boolean") {
          throw new TypeError(`'ease' is not a boolean.`);
        }
        this.#ease = newEase;
        this.#updateSubscribers();
      },
      enumerable: true
    });
    Object.defineProperty(this, "easeOptions", {
      get: () => {
        return this.#easeOptions;
      },
      set: (newEaseOptions) => {
        if (newEaseOptions === null || typeof newEaseOptions !== "object") {
          throw new TypeError(`'easeOptions' is not an object.`);
        }
        if (newEaseOptions.duration !== void 0) {
          if (!Number.isFinite(newEaseOptions.duration)) {
            throw new TypeError(`'easeOptions.duration' is not a finite number.`);
          }
          if (newEaseOptions.duration < 0) {
            throw new Error(`'easeOptions.duration' is less than 0.`);
          }
          this.#easeOptions.duration = newEaseOptions.duration;
        }
        if (newEaseOptions.ease !== void 0) {
          if (typeof newEaseOptions.ease !== "function" && typeof newEaseOptions.ease !== "string") {
            throw new TypeError(`'easeOptions.ease' is not a function or string.`);
          }
          this.#easeOptions.ease = newEaseOptions.ease;
        }
        this.#updateSubscribers();
      },
      enumerable: true
    });
    if (ease !== void 0) {
      this.ease = ease;
    }
    if (easeOptions !== void 0) {
      this.easeOptions = easeOptions;
    }
  }
  /**
   * @returns {number} Get ease duration
   */
  get easeDuration() {
    return this.#easeOptions.duration;
  }
  /**
   * @returns {string|Function} Get easing function value.
   */
  get easeValue() {
    return this.#easeOptions.ease;
  }
  /**
   * @param {number}   duration - Set ease duration.
   */
  set easeDuration(duration) {
    if (!Number.isFinite(duration)) {
      throw new TypeError(`'duration' is not a finite number.`);
    }
    if (duration < 0) {
      throw new Error(`'duration' is less than 0.`);
    }
    this.#easeOptions.duration = duration;
    this.#updateSubscribers();
  }
  /**
   * @param {string|Function} value - Get easing function value.
   */
  set easeValue(value) {
    if (typeof value !== "function" && typeof value !== "string") {
      throw new TypeError(`'value' is not a function or string.`);
    }
    this.#easeOptions.ease = value;
    this.#updateSubscribers();
  }
  /**
   * Resets all options data to default values.
   */
  reset() {
    this.#ease = false;
    this.#easeOptions = { duration: 0.1, ease: cubicOut };
    this.#updateSubscribers();
  }
  /**
   * Resets easing options to default values.
   */
  resetEase() {
    this.#easeOptions = { duration: 0.1, ease: cubicOut };
    this.#updateSubscribers();
  }
  /**
   *
   * @param {function(DraggableOptions): void} handler - Callback function that is invoked on update / changes.
   *                                                 Receives the DraggableOptions object / instance.
   *
   * @returns {(function(): void)} Unsubscribe function.
   */
  subscribe(handler) {
    this.#subscriptions.push(handler);
    handler(this);
    return () => {
      const index = this.#subscriptions.findIndex((sub) => sub === handler);
      if (index >= 0) {
        this.#subscriptions.splice(index, 1);
      }
    };
  }
  #updateSubscribers() {
    const subscriptions = this.#subscriptions;
    if (subscriptions.length > 0) {
      for (let cntr = 0; cntr < subscriptions.length; cntr++) {
        subscriptions[cntr](this);
      }
    }
  }
}
draggable.options = (options) => new DraggableOptions(options);
const s_POSITION_DATA = { left: 0, top: 0 };
const s_DEFAULT_TRANSITION_OPTIONS = {};
const TJSGlassPane_svelte_svelte_type_style_lang = "";
class AppShellContextInternal {
  /** @type {InternalAppStores} */
  #stores;
  constructor() {
    this.#stores = {
      elementContent: writable$1(void 0),
      elementRoot: writable$1(void 0)
    };
    Object.freeze(this.#stores);
    Object.seal(this);
  }
  /**
   * @returns {InternalAppStores} The internal context stores for elementContent / elementRoot
   */
  get stores() {
    return this.#stores;
  }
}
function localize(stringId, data) {
  const result = typeof data !== "object" ? globalThis.game.i18n.localize(stringId) : globalThis.game.i18n.format(stringId, data);
  return result !== void 0 ? result : "";
}
const TJSHeaderButton_svelte_svelte_type_style_lang = "";
function create_if_block$a(ctx) {
  let span;
  let t;
  return {
    c() {
      span = element("span");
      t = text$1(
        /*label*/
        ctx[3]
      );
      attr(span, "class", "svelte-ese-166l8wd");
      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$p(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$a(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-ese-166l8wd");
      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$a(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-ese-166l8wd")) {
        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 = /^\s*<.*>$/;
function instance$p($$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.call(button, event);
      $$invalidate(0, button);
    }
  }
  function onContextMenu(event) {
    const invoke = button?.onContextMenu;
    if (typeof invoke === "function") {
      invoke.call(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.call(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.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$p, create_fragment$p, safe_not_equal, { button: 0 });
  }
  get button() {
    return this.$$.ctx[0];
  }
  set button(button) {
    this.$$set({ button });
    flush();
  }
}
const TJSApplicationHeader_svelte_svelte_type_style_lang = "";
function get_each_context$7(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$9(ctx) {
  let img;
  let img_src_value;
  return {
    c() {
      img = element("img");
      attr(img, "class", "tjs-app-icon keep-minimized svelte-ese-1wviwl9");
      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) {
    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]);
    }
    return { props: switch_instance_props };
  }
  if (switch_value) {
    switch_instance = construct_svelte_component(switch_value, switch_props());
  }
  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) {
      const switch_instance_changes = dirty[0] & /*buttonsLeft*/
      2 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
        /*button*/
        ctx2[31].props
      )]) : {};
      if (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());
          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) {
        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$7(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) {
    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]);
    }
    return { props: switch_instance_props };
  }
  if (switch_value) {
    switch_instance = construct_svelte_component(switch_value, switch_props());
  }
  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) {
      const switch_instance_changes = dirty[0] & /*buttonsRight*/
      4 ? get_spread_update(switch_instance_spread_levels, [get_spread_object(
        /*button*/
        ctx2[31].props
      )]) : {};
      if (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());
          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) {
        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$9(ctx);
  let each_value_1 = (
    /*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 = (
    /*buttonsRight*/
    ctx[2]
  );
  let each_blocks = [];
  for (let i = 0; i < each_value.length; i += 1) {
    each_blocks[i] = create_each_block$7(get_each_context$7(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-ese-1wviwl9");
      set_style(
        h4,
        "display",
        /*displayHeaderTitle*/
        ctx[4]
      );
      attr(span, "class", "tjs-window-header-spacer keep-minimized svelte-ese-1wviwl9");
      attr(header, "class", "window-header flexrow svelte-ese-1wviwl9");
    },
    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) {
        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) {
        each_blocks[i].m(header, null);
      }
      current = true;
      if (!mounted) {
        dispose = [
          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]
          )),
          listen(
            header,
            "pointerdown",
            /*onPointerdown*/
            ctx[19]
          )
        ];
        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$9(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 = /*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 = /*buttonsRight*/
        ctx2[2];
        let i;
        for (i = 0; i < each_value.length; i += 1) {
          const child_ctx = get_each_context$7(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$7(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$o(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$o($$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");
  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;
    if ($focusAuto && rootEl instanceof HTMLElement && rootEl?.isConnected) {
      if ($focusKeep) {
        const focusOutside = document.activeElement instanceof HTMLElement && !rootEl.contains(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(
        {},
        {
          ease: true,
          easeOptions: { duration: 0.08, ease: cubicOut }
        },
        isObject(draggableOptions) ? draggableOptions : {},
        {
          position: application.position,
          active: $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(isSvelteComponent(button) ? { class: button, props: {} } : {
            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$o, create_fragment$o, safe_not_equal, { draggable: 0, draggableOptions: 20 }, null, [-1, -1]);
  }
}
const TJSFocusWrap_svelte_svelte_type_style_lang = "";
function create_fragment$n(ctx) {
  let div;
  let mounted;
  let dispose;
  return {
    c() {
      div = element("div");
      attr(div, "class", "tjs-focus-wrap svelte-ese-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$n($$self, $$props, $$invalidate) {
  let { elementRoot = void 0 } = $$props;
  let { enabled = true } = $$props;
  let ignoreElements, wrapEl;
  function onFocus() {
    if (!enabled) {
      return;
    }
    if (elementRoot instanceof HTMLElement) {
      const firstFocusEl = A11yHelper.getFirstFocusableElement(elementRoot, ignoreElements);
      if (firstFocusEl instanceof HTMLElement && 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$n, create_fragment$n, safe_not_equal, { elementRoot: 2, enabled: 3 });
  }
}
function create_fragment$m(ctx) {
  let div;
  let resizable_action;
  let mounted;
  let dispose;
  return {
    c() {
      div = element("div");
      div.innerHTML = `<i class="fas fa-arrows-alt-h"></i>`;
      attr(div, "class", "window-resizable-handle");
    },
    m(target, anchor) {
      insert(target, div, anchor);
      ctx[10](div);
      if (!mounted) {
        dispose = action_destroyer(resizable_action = /*resizable*/
        ctx[6].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[10](null);
      mounted = false;
      dispose();
    }
  };
}
function instance$m($$self, $$props, $$invalidate) {
  let $storeElementRoot;
  let $storeMinimized;
  let $storeResizable;
  let { isResizable = false } = $$props;
  const application = getContext("#external").application;
  const storeElementRoot = getContext("storeElementRoot");
  component_subscribe($$self, storeElementRoot, (value) => $$invalidate(8, $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(9, $storeMinimized = value));
  const storeResizing = application.reactive.storeUIState.resizing;
  let elementResize;
  function resizable(node, { active: active2 = true, storeResizing: storeResizing2 = void 0 } = {}) {
    let position = null;
    let initialPosition = {};
    let resizing = false;
    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(7, 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(7, 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;
      }
      initialPosition = { x: event.clientX, y: 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);
      }
      application.position.set({
        width: position.width + (event.clientX - initialPosition.x),
        height: position.height + (event.clientY - initialPosition.y)
      });
    }
    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(7, isResizable), $$invalidate(9, $storeMinimized), $$invalidate(8, $storeElementRoot);
    });
  }
  $$self.$$set = ($$props2) => {
    if ("isResizable" in $$props2)
      $$invalidate(7, isResizable = $$props2.isResizable);
  };
  $$self.$$.update = () => {
    if ($$self.$$.dirty & /*elementResize, isResizable, $storeMinimized, $storeElementRoot*/
    897) {
      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,
    resizable,
    isResizable,
    $storeElementRoot,
    $storeMinimized,
    div_binding
  ];
}
class ResizableHandle extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, instance$m, create_fragment$m, safe_not_equal, { isResizable: 7 });
  }
}
const ApplicationShell_svelte_svelte_type_style_lang = "";
function create_else_block$2(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 current;
  let mounted;
  let dispose;
  tjsapplicationheader = new TJSApplicationHeader({
    props: {
      draggable: (
        /*draggable*/
        ctx[6]
      ),
      draggableOptions: (
        /*draggableOptions*/
        ctx[7]
      )
    }
  });
  const default_slot_template = (
    /*#slots*/
    ctx[36].default
  );
  const default_slot = create_slot(
    default_slot_template,
    ctx,
    /*$$scope*/
    ctx[35],
    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-ese-oz81f7");
      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-ese-oz81f7");
      attr(div, "data-appid", div_data_appid_value = /*application*/
      ctx[10].appId);
      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[39](section);
      append(div, t1);
      mount_component(resizablehandle, div, null);
      append(div, t2);
      mount_component(tjsfocuswrap, div, null);
      ctx[40](div);
      current = true;
      if (!mounted) {
        dispose = [
          listen(
            section,
            "pointerdown",
            /*onPointerdownContent*/
            ctx[21]
          ),
          action_destroyer(applyStyles_action = applyStyles.call(
            null,
            section,
            /*stylesContent*/
            ctx[9]
          )),
          action_destroyer(
            /*contentResizeObserver*/
            ctx[13].call(
              null,
              section,
              /*resizeObservedContent*/
              ctx[22]
            )
          ),
          listen(div, "close:popup", stop_propagation(prevent_default(
            /*onClosePopup*/
            ctx[18]
          ))),
          listen(
            div,
            "keydown",
            /*onKeydown*/
            ctx[19],
            true
          ),
          listen(
            div,
            "pointerdown",
            /*onPointerdownApp*/
            ctx[20]
          ),
          action_destroyer(applyStyles_action_1 = applyStyles.call(
            null,
            div,
            /*stylesApp*/
            ctx[8]
          )),
          action_destroyer(
            /*appResizeObserver*/
            ctx[12].call(
              null,
              div,
              /*resizeObservedApp*/
              ctx[23]
            )
          )
        ];
        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*/
        16)) {
          update_slot_base(
            default_slot,
            default_slot_template,
            ctx2,
            /*$$scope*/
            ctx2[35],
            !current ? get_all_dirty_from_scope(
              /*$$scope*/
              ctx2[35]
            ) : get_slot_changes(
              default_slot_template,
              /*$$scope*/
              ctx2[35],
              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-ese-oz81f7")) {
        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]
        );
    },
    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[39](null);
      destroy_component(resizablehandle);
      destroy_component(tjsfocuswrap);
      ctx[40](null);
      mounted = false;
      run_all(dispose);
    }
  };
}
function create_if_block$8(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 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[36].default
  );
  const default_slot = create_slot(
    default_slot_template,
    ctx,
    /*$$scope*/
    ctx[35],
    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-ese-oz81f7");
      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-ese-oz81f7");
      attr(div, "data-appid", div_data_appid_value = /*application*/
      ctx[10].appId);
      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[37](section);
      append(div, t1);
      mount_component(resizablehandle, div, null);
      append(div, t2);
      mount_component(tjsfocuswrap, div, null);
      ctx[38](div);
      current = true;
      if (!mounted) {
        dispose = [
          listen(
            section,
            "pointerdown",
            /*onPointerdownContent*/
            ctx[21]
          ),
          action_destroyer(applyStyles_action = applyStyles.call(
            null,
            section,
            /*stylesContent*/
            ctx[9]
          )),
          action_destroyer(
            /*contentResizeObserver*/
            ctx[13].call(
              null,
              section,
              /*resizeObservedContent*/
              ctx[22]
            )
          ),
          listen(div, "close:popup", stop_propagation(prevent_default(
            /*onClosePopup*/
            ctx[18]
          ))),
          listen(
            div,
            "keydown",
            /*onKeydown*/
            ctx[19],
            true
          ),
          listen(
            div,
            "pointerdown",
            /*onPointerdownApp*/
            ctx[20]
          ),
          action_destroyer(applyStyles_action_1 = applyStyles.call(
            null,
            div,
            /*stylesApp*/
            ctx[8]
          )),
          action_destroyer(
            /*appResizeObserver*/
            ctx[12].call(
              null,
              div,
              /*resizeObservedApp*/
              ctx[23]
            )
          )
        ];
        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*/
        16)) {
          update_slot_base(
            default_slot,
            default_slot_template,
            ctx,
            /*$$scope*/
            ctx[35],
            !current ? get_all_dirty_from_scope(
              /*$$scope*/
              ctx[35]
            ) : get_slot_changes(
              default_slot_template,
              /*$$scope*/
              ctx[35],
              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-ese-oz81f7")) {
        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]
        );
    },
    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 (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[37](null);
      destroy_component(resizablehandle);
      destroy_component(tjsfocuswrap);
      ctx[38](null);
      if (detaching && div_outro)
        div_outro.end();
      mounted = false;
      run_all(dispose);
    }
  };
}
function create_fragment$l(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 (
      /*inTransition*/
      ctx2[2] || /*outTransition*/
      ctx2[3]
    )
      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_blocks[current_block_type_index].d(detaching);
      if (detaching)
        detach(if_block_anchor);
    }
  };
}
function instance$l($$self, $$props, $$invalidate) {
  let $focusKeep;
  let $focusAuto;
  let $minimized;
  let $focusTrap;
  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;
  let { appOffsetHeight = false } = $$props;
  let { appOffsetWidth = false } = $$props;
  const appResizeObserver = !!appOffsetHeight || !!appOffsetWidth ? resizeObserver : () => null;
  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);
  const { application } = getContext("#external");
  const { focusAuto, focusKeep, focusTrap } = application.reactive.storeAppOptions;
  component_subscribe($$self, focusAuto, (value) => $$invalidate(32, $focusAuto = value));
  component_subscribe($$self, focusKeep, (value) => $$invalidate(41, $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));
  let focusWrapEnabled;
  let { transition = void 0 } = $$props;
  let { inTransition = void 0 } = $$props;
  let { outTransition = void 0 } = $$props;
  let { transitionOptions = void 0 } = $$props;
  let { inTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS } = $$props;
  let { outTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS } = $$props;
  let oldTransition = void 0;
  let oldTransitionOptions = void 0;
  onMount(() => elementRoot.focus());
  function onClosePopup(event) {
    if (!$focusAuto) {
      return;
    }
    const targetEl = event?.detail?.target;
    if (!(targetEl instanceof HTMLElement)) {
      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 (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;
      if (elementRoot === document.activeElement || firstFocusEl === document.activeElement) {
        if (lastFocusEl instanceof HTMLElement && 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 focusOutside = document.activeElement instanceof HTMLElement && !elementRoot.contains(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(35, $$scope = $$props2.$$scope);
  };
  $$self.$$.update = () => {
    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 : void 0;
        $$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 !== s_DEFAULT_TRANSITION_OPTIONS && isObject(transitionOptions) ? transitionOptions : s_DEFAULT_TRANSITION_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 = void 0);
      }
    }
    if ($$self.$$.dirty[0] & /*outTransition, application*/
    1032) {
      {
        if (typeof outTransition !== "function") {
          $$invalidate(3, outTransition = void 0);
        }
        if (application && typeof application?.options?.defaultCloseAnimation === "boolean") {
          $$invalidate(10, application.options.defaultCloseAnimation = outTransition === void 0, application);
        }
      }
    }
    if ($$self.$$.dirty[0] & /*inTransitionOptions*/
    16) {
      if (typeof inTransitionOptions !== "object") {
        $$invalidate(4, inTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS);
      }
    }
    if ($$self.$$.dirty[0] & /*outTransitionOptions*/
    32) {
      if (typeof outTransitionOptions !== "object") {
        $$invalidate(5, outTransitionOptions = s_DEFAULT_TRANSITION_OPTIONS);
      }
    }
  };
  return [
    elementContent,
    elementRoot,
    inTransition,
    outTransition,
    inTransitionOptions,
    outTransitionOptions,
    draggable2,
    draggableOptions,
    stylesApp,
    stylesContent,
    application,
    focusWrapEnabled,
    appResizeObserver,
    contentResizeObserver,
    focusAuto,
    focusKeep,
    focusTrap,
    minimized,
    onClosePopup,
    onKeydown,
    onPointerdownApp,
    onPointerdownContent,
    resizeObservedContent,
    resizeObservedApp,
    appOffsetHeight,
    appOffsetWidth,
    contentOffsetHeight,
    contentOffsetWidth,
    transition,
    transitionOptions,
    oldTransition,
    oldTransitionOptions,
    $focusAuto,
    $minimized,
    $focusTrap,
    $$scope,
    slots,
    section_binding,
    div_binding,
    section_binding_1,
    div_binding_1
  ];
}
class ApplicationShell extends SvelteComponent {
  constructor(options) {
    super();
    init(
      this,
      options,
      instance$l,
      create_fragment$l,
      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();
  }
}
const EmptyApplicationShell_svelte_svelte_type_style_lang = "";
const TJSApplicationShell_svelte_svelte_type_style_lang = "";
const DialogContent_svelte_svelte_type_style_lang = "";
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);
Hooks.on("PopOut:loading", (app) => {
  if (app instanceof SvelteApplication) {
    app.position.enabled = false;
  }
});
Hooks.on("PopOut:popin", (app) => {
  if (app instanceof SvelteApplication) {
    app.position.enabled = true;
  }
});
Hooks.on("PopOut:close", (app) => {
  if (app instanceof SvelteApplication) {
    app.position.enabled = true;
  }
});
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 SequencerFileCache = {
  _videos: {},
  _preloadedFiles: /* @__PURE__ */ new Set(),
  _totalCacheSize: 0,
  _validTypes: ["video/webm", "video/x-webm", "application/octet-stream"],
  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: +new Date()
      };
    }
    this._videos[inSrc].lastUsed = +new Date();
    return this._videos[inSrc].blob;
  },
  srcExists(inSrc) {
    if (this._preloadedFiles.has(inSrc)) {
      return true;
    }
    return 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 (AudioHelper.hasAudioExtension(inSrc)) {
      try {
        const audio2 = await 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 loadTexture(inSrc);
    if (texture) {
      this._preloadedFiles.add(inSrc);
    }
    return texture;
  }
};
async function get_video_texture(inBlob) {
  return new Promise(async (resolve) => {
    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-pixi-fix")) {
        baseTexture.alphaMode = PIXI.ALPHA_MODES.PREMULTIPLIED_ALPHA;
      }
      const texture = new PIXI.Texture(baseTexture);
      resolve(texture);
    };
    video.onerror = () => {
      URL.revokeObjectURL(video.src);
      reject();
    };
  });
}
const flipBookTextureCache = {};
class SequencerFileBase {
  static make(inData, inDBPath, inMetadata) {
    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 SequencerFile extends SequencerFileBase {
  rangeFind = false;
  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.fileTextureMap = Object.fromEntries(
      this.getAllFiles().map((file) => {
        return [file, false];
      })
    );
    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;
  }
  destroy() {
    if (this.originalMetadata?.flipbook)
      return;
    for (let texture of Object.values(this.fileTextureMap)) {
      if (!texture)
        continue;
      try {
        texture?.baseTexture?.resource?.source?.removeAttribute("src");
      } catch (err) {
      }
      try {
        texture?.baseTexture?.resource?.source?.pause();
      } catch (err) {
      }
      try {
        texture?.baseTexture?.resource?.source?.remove();
      } catch (err) {
      }
      try {
        texture?.baseTexture?.resource?.source?.load();
      } catch (err) {
      }
      texture.destroy();
    }
  }
  async _getTexture(file) {
    if (this.fileTextureMap[file])
      return this.fileTextureMap[file];
    this.fileTextureMap[file] = await SequencerFileCache.loadFile(file);
    return this.fileTextureMap[file];
  }
  _adjustScaleForPadding(distance, width2) {
    return distance / (width2 - (this.template ? this.template[1] + this.template[2] : 0));
  }
  _adjustAnchorForPadding(width2) {
    return this.template ? this.template[1] / width2 : void 0;
  }
  async _getFlipBookSheet(filePath) {
    if (!this.originalMetadata?.flipbook)
      return false;
    if (flipBookTextureCache[filePath]) {
      return flipBookTextureCache[filePath];
    }
    flipBookTextureCache[filePath] = this.file.map((file) => {
      return PIXI.Texture.from(file);
    });
    return flipBookTextureCache[filePath];
  }
  async getTexture(distance) {
    const filePath = this.getFile();
    const texture = await this._getTexture(this.getFile());
    const sheet = await this._getFlipBookSheet(filePath);
    return {
      filePath,
      texture,
      sheet,
      spriteScale: this._adjustScaleForPadding(distance, texture.width),
      spriteAnchor: this._adjustAnchorForPadding(texture.width)
    };
  }
}
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) {
    if (inFt && this.file[inFt]) {
      if (Array.isArray(this.file[inFt])) {
        const fileIndex = is_real_number(this.fileIndex) ? 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);
  }
  async getTexture(distance = 400) {
    const { filePath, texture } = await this._getTextureForDistance(distance);
    return {
      filePath,
      texture,
      spriteScale: this._adjustScaleForPadding(distance, texture.width),
      spriteAnchor: this._adjustAnchorForPadding(texture.width)
    };
  }
  _getMatchingDistance(inEntry) {
    return SequencerFileRangeFind.ftToDistanceMap[inEntry] / this._gridSizeDiff;
  }
  _rangeFind(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];
  }
  async _getTextureForDistance(distance) {
    const filePath = this._rangeFind(distance);
    const texture = await this._getTexture(filePath);
    return { filePath, texture };
  }
}
class Database {
  #entriesStore = writable$1({});
  privateModules = [];
  flattenedEntries = [];
  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];
      })
    );
  }
  /**
   *  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
   * @return {boolean}
   */
  registerEntries(inModuleName, inEntries, isPrivate = false) {
    if (inModuleName.includes("."))
      return this._throwError(
        "registerEntries",
        "module name must not contain periods"
      );
    if (this.entries[inModuleName])
      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);
    this.entries = foundry.utils.mergeObject(this.entries, {
      [inModuleName]: processedEntries
    });
    if (isPrivate)
      this.privateModules.push(inModuleName);
    console.log(
      `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 } = {}) {
    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`
      );
    let 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) => e.split(inPath)[1]).map((e) => e ? e.split(".")[1] : "").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.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));
    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 = 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 = 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) {
          moduleEntries.push(new SequencerFileProxy(wholeDBPath, data));
          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();
const TreeViewEntry_svelte_svelte_type_style_lang = "";
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-ese-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-ese-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-ese-uyryhb"></i>`;
      attr(i0, "class", "fas fa-database svelte-ese-uyryhb");
      toggle_class(
        i0,
        "flash-it",
        /*flashDBPath*/
        ctx[2]
      );
      attr(a0, "class", "database-entry-button svelte-ese-uyryhb");
      attr(a1, "class", "database-entry-button svelte-ese-uyryhb");
    },
    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 (if_block)
        if_block.d(detaching);
      if (detaching)
        detach(t0);
      if (detaching)
        detach(a0);
      if (detaching)
        detach(t1);
      if (detaching)
        detach(a1);
      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-ese-uyryhb");
      toggle_class(
        i,
        "flash-it",
        /*flashFilePath*/
        ctx[1]
      );
      attr(a, "class", "database-entry-button svelte-ese-uyryhb");
    },
    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$k(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-ese-uyryhb");
      attr(div1, "class", "database-entry-text svelte-ese-uyryhb");
      attr(div1, "title", div1_title_value = /*data*/
      ctx[0].path);
      attr(div2, "class", "database-entry-text-container svelte-ese-uyryhb");
      attr(div3, "class", "database-entry svelte-ese-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$k, safe_not_equal, { data: 0 });
  }
}
function create_fragment$j(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$j, safe_not_equal, { data: 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 isImage = !lowerCaseEntry.endsWith("webm") && !isAudio;
  const isVideo = !isAudio && !isImage;
  const icon = previewFile ? isVideo ? "fa-film" : isAudio ? "fa-volume-high" : "fa-image" : "fa-question-mark";
  const title = previewFile ? isVideo ? "Animated WebM" : isAudio ? "Audio" : "Image" : "Unknown";
  return {
    file: previewFile ?? "unknown.jpg",
    dbEntry: entry,
    icon,
    title,
    isAudio,
    isImage,
    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 (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");
}
function playFile(entry) {
  const { file, isAudio, isImage, isVideo } = getFileData(entry);
  databaseStore.elements.audio.classList.toggle("hidden", !isAudio);
  databaseStore.elements.image.classList.toggle("hidden", !isImage);
  databaseStore.elements.player.classList.toggle("hidden", !isVideo);
  if (isImage) {
    databaseStore.elements.image.src = file;
    databaseStore.metadata.set({
      type: "Image",
      duration: "n/a"
    });
    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$1({});
const visibleTreeStore = writable$1([]);
let flattenedEntries = [];
const entriesStore = SequencerDatabase.entriesStore;
const packStore = writable$1(SequencerDatabase.publicModules);
const selectedPackStore = writable$1("all");
const searchStore = writable$1("");
const cleanSearchStore = writable$1("");
const searchRegexStore = writable$1(new RegExp("", "gu"));
SequencerDatabase.entriesStore.subscribe(() => {
  packStore.set(SequencerDatabase.publicModules);
});
const databaseStore = {
  metadata: writable$1(false),
  allRanges: writable$1(false),
  subLists: writable$1(false),
  listView: writable$1(false),
  packStore,
  selectedPackStore,
  visibleTreeStore,
  search: searchStore,
  cleanSearchStore,
  searchRegex: searchRegexStore,
  elements: {},
  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 (!getProperty(acc, path)) {
          setProperty(
            acc,
            path,
            foundry.utils.mergeObject(
              {
                path: part,
                fullPath,
                open: false,
                children: {}
              },
              getProperty(acc, path)
            )
          );
        }
      }
      return acc;
    }, {})
  );
}
function openTreePath(fullPath, open, openAll = false) {
  treeStore.update((tree) => {
    const fullTreePath = fullPath.split(".").join(".children.");
    const node = getProperty(tree, fullTreePath);
    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: randomID(),
        class: TreeViewSeparator
      });
    }
    return leaf;
  });
}
const DatabaseEntry_svelte_svelte_type_style_lang = "";
function create_fragment$i(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-ese-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-ese-flzvpb");
      attr(i1, "class", "fas fa-file svelte-ese-flzvpb");
      toggle_class(
        i1,
        "flash-it",
        /*flashFilePath*/
        ctx[1]
      );
      attr(button1, "type", "button");
      attr(button1, "class", "btn_copy_filepath svelte-ese-flzvpb");
      attr(i2, "class", "fas fa-database svelte-ese-flzvpb");
      toggle_class(
        i2,
        "flash-it",
        /*flashDBPath*/
        ctx[2]
      );
      attr(button2, "type", "button");
      attr(button2, "class", "btn_copy_databasepath svelte-ese-flzvpb");
      attr(div0, "class", "database-entry-text-highlight svelte-ese-flzvpb");
      attr(div1, "class", "database-entry-text svelte-ese-flzvpb");
      attr(
        div1,
        "title",
        /*entry*/
        ctx[0]
      );
      attr(div2, "class", "database-entry svelte-ese-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$i, 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.lastCalcIndex = 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 create_fragment$h(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$h, safe_not_equal, { horizontal: 1, uniqueKey: 2, type: 3 });
  }
}
const get_footer_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
4 });
const get_footer_slot_context = (ctx) => ({ data: (
  /*dataItem*/
  ctx[39]
) });
function get_each_context$6(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[39] = list[i];
  return child_ctx;
}
const get_default_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
4 });
const get_default_slot_context = (ctx) => ({ data: (
  /*dataItem*/
  ctx[39]
) });
const get_header_slot_changes = (dirty) => ({ data: dirty[0] & /*displayItems*/
4 });
const get_header_slot_context = (ctx) => ({ data: (
  /*dataItem*/
  ctx[39]
) });
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, displayItems*/
      536870916) {
        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, displayItems*/
        536870916)) {
          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 (default_slot)
        default_slot.d(detaching);
      if (detaching)
        detach(t);
    }
  };
}
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, displayItems*/
      536870916) {
        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, displayItems*/
        536870916)) {
          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$g(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 = (
    /*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(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");
    },
    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) {
        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 = /*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) {
      return document.documentElement[directionKey] || document.body[directionKey];
    } else {
      return root ? Math.ceil(root[directionKey]) : 0;
    }
  }
  function getClientSize() {
    const key2 = isHorizontal ? "clientWidth" : "clientHeight";
    if (pageMode) {
      return document.documentElement[key2] || document.body[key2];
    } else {
      return root ? Math.ceil(root[key2]) : 0;
    }
  }
  function getScrollSize() {
    const key2 = isHorizontal ? "scrollWidth" : "scrollHeight";
    if (pageMode) {
      return document.documentElement[key2] || document.body[key2];
    } else {
      return root ? Math.ceil(root[key2]) : 0;
    }
  }
  function updatePageModeFront() {
    if (root) {
      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 (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) {
      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$g,
      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];
  }
}
const databaseShell_svelte_svelte_type_style_lang = "";
function get_each_context$5(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[41] = list[i];
  child_ctx[43] = i;
  return child_ctx;
}
function create_each_block$5(ctx) {
  let option;
  let t_value = (
    /*pack*/
    ctx[41] + ""
  );
  let t;
  let option_value_value;
  return {
    c() {
      option = element("option");
      t = text$1(t_value);
      option.__value = option_value_value = /*pack*/
      ctx[41];
      option.value = option.__value;
    },
    m(target, anchor) {
      insert(target, option, anchor);
      append(option, t);
    },
    p(ctx2, dirty) {
      if (dirty[0] & /*$packStore*/
      128 && t_value !== (t_value = /*pack*/
      ctx2[41] + ""))
        set_data(t, t_value);
      if (dirty[0] & /*$packStore*/
      128 && option_value_value !== (option_value_value = /*pack*/
      ctx2[41])) {
        option.__value = option_value_value;
        option.value = 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[9]
      ),
      key: "fullPath",
      $$slots: {
        default: [
          create_default_slot_2,
          ({ data }) => ({ 40: data }),
          ({ data }) => [0, data ? 512 : 0]
        ]
      },
      $$scope: { ctx }
    }
  });
  return {
    c() {
      div = element("div");
      create_component(virtualscroll.$$.fragment);
      attr(div, "class", "sequencer-database-entries-tree svelte-ese-mpsiyo");
    },
    m(target, anchor) {
      insert(target, div, anchor);
      mount_component(virtualscroll, div, null);
      current = true;
    },
    p(ctx2, dirty) {
      const virtualscroll_changes = {};
      if (dirty[0] & /*$visibleTreeStore*/
      512)
        virtualscroll_changes.data = /*$visibleTreeStore*/
        ctx2[9];
      if (dirty[1] & /*$$scope, data*/
      8704) {
        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[6]
      ),
      key: "entry",
      $$slots: {
        default: [
          create_default_slot_1,
          ({ data }) => ({ 40: data }),
          ({ data }) => [0, data ? 512 : 0]
        ]
      },
      $$scope: { ctx }
    }
  });
  return {
    c() {
      div = element("div");
      create_component(virtualscroll.$$.fragment);
      attr(div, "class", "sequencer-database-entries svelte-ese-mpsiyo");
    },
    m(target, anchor) {
      insert(target, div, anchor);
      mount_component(virtualscroll, div, null);
      current = true;
    },
    p(ctx2, dirty) {
      const virtualscroll_changes = {};
      if (dirty[0] & /*filteredEntries*/
      64)
        virtualscroll_changes.data = /*filteredEntries*/
        ctx2[6];
      if (dirty[1] & /*$$scope, data*/
      8704) {
        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[40].class
  );
  function switch_props(ctx2) {
    return { props: { data: (
      /*data*/
      ctx2[40]
    ) } };
  }
  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) {
      const switch_instance_changes = {};
      if (dirty[1] & /*data*/
      512)
        switch_instance_changes.data = /*data*/
        ctx2[40];
      if (switch_value !== (switch_value = /*data*/
      ctx2[40].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) {
        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[40].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*/
      512)
        databaseentry_changes.entry = /*data*/
        ctx2[40].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[10].type + ""
  );
  let t1;
  let t2;
  let t3_value = (
    /*$metadata*/
    ctx[10].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*/
      1024 && t1_value !== (t1_value = /*$metadata*/
      ctx2[10].type + ""))
        set_data(t1, t1_value);
      if (dirty[0] & /*$metadata*/
      1024 && t3_value !== (t3_value = /*$metadata*/
      ctx2[10].duration + ""))
        set_data(t3, t3_value);
    },
    d(detaching) {
      if (detaching)
        detach(t0);
      if (detaching)
        detach(t1);
      if (detaching)
        detach(t2);
      if (detaching)
        detach(t3);
    }
  };
}
function create_default_slot$1(ctx) {
  let div4;
  let div0;
  let select;
  let option;
  let t1;
  let input0;
  let t2;
  let input1;
  let t3;
  let label0;
  let t5;
  let input2;
  let t6;
  let label1;
  let t8;
  let input3;
  let t9;
  let label2;
  let t11;
  let div3;
  let current_block_type_index;
  let if_block0;
  let t12;
  let div2;
  let video;
  let t13;
  let img;
  let t14;
  let audio2;
  let t15;
  let div1;
  let current;
  let mounted;
  let dispose;
  let each_value = (
    /*$packStore*/
    ctx[7]
  );
  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[4]
    )
      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[10]
    )
      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() {
      div4 = element("div");
      div0 = element("div");
      select = element("select");
      option = element("option");
      option.textContent = `${localize("SEQUENCER.Database.AllPacks")}`;
      for (let i = 0; i < each_blocks.length; i += 1) {
        each_blocks[i].c();
      }
      t1 = space();
      input0 = element("input");
      t2 = space();
      input1 = element("input");
      t3 = space();
      label0 = element("label");
      label0.textContent = `${localize("SEQUENCER.Database.ShowAllRanges")}`;
      t5 = space();
      input2 = element("input");
      t6 = space();
      label1 = element("label");
      label1.textContent = `${localize("SEQUENCER.Database.ShowSubLists")}`;
      t8 = space();
      input3 = element("input");
      t9 = space();
      label2 = element("label");
      label2.textContent = `${localize("SEQUENCER.Database.ListView")}`;
      t11 = space();
      div3 = element("div");
      if_block0.c();
      t12 = space();
      div2 = element("div");
      video = element("video");
      t13 = space();
      img = element("img");
      t14 = space();
      audio2 = element("audio");
      audio2.innerHTML = `<source type="audio/ogg"/>`;
      t15 = space();
      div1 = element("div");
      if_block1.c();
      option.__value = "all";
      option.value = option.__value;
      attr(select, "name", "pack-select");
      attr(select, "class", "svelte-ese-mpsiyo");
      if (
        /*$selectedPackStore*/
        ctx[2] === void 0
      )
        add_render_callback(() => (
          /*select_change_handler*/
          ctx[26].call(select)
        ));
      attr(input0, "class", "ml-2 svelte-ese-mpsiyo");
      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-ese-mpsiyo");
      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-ese-mpsiyo");
      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-ese-mpsiyo");
      attr(label2, "for", "treeview");
      attr(div0, "class", "sequencer-database-header svelte-ese-mpsiyo");
      video.autoplay = true;
      attr(video, "class", "database-player svelte-ese-mpsiyo");
      attr(video, "height", "335");
      video.loop = true;
      attr(video, "preload", "");
      attr(video, "width", "335");
      attr(img, "class", "database-image hidden svelte-ese-mpsiyo");
      attr(audio2, "class", "database-audio hidden svelte-ese-mpsiyo");
      attr(div1, "class", "sequencer-database-metadata-container svelte-ese-mpsiyo");
      attr(div2, "class", "sequencer-database-player-container svelte-ese-mpsiyo");
      attr(div3, "class", "sequencer-database-entries-container svelte-ese-mpsiyo");
      attr(div4, "class", "sequencer-database-content svelte-ese-mpsiyo");
    },
    m(target, anchor) {
      insert(target, div4, anchor);
      append(div4, div0);
      append(div0, select);
      append(select, option);
      for (let i = 0; i < each_blocks.length; i += 1) {
        each_blocks[i].m(select, null);
      }
      select_option(
        select,
        /*$selectedPackStore*/
        ctx[2]
      );
      append(div0, t1);
      append(div0, input0);
      set_input_value(
        input0,
        /*$search*/
        ctx[1]
      );
      append(div0, t2);
      append(div0, input1);
      input1.checked = /*$allRanges*/
      ctx[3];
      append(div0, t3);
      append(div0, label0);
      append(div0, t5);
      append(div0, input2);
      input2.checked = /*$subLists*/
      ctx[8];
      append(div0, t6);
      append(div0, label1);
      append(div0, t8);
      append(div0, input3);
      input3.checked = /*$listView*/
      ctx[4];
      append(div0, t9);
      append(div0, label2);
      append(div4, t11);
      append(div4, div3);
      if_blocks[current_block_type_index].m(div3, null);
      append(div3, t12);
      append(div3, div2);
      append(div2, video);
      ctx[31](video);
      append(div2, t13);
      append(div2, img);
      ctx[34](img);
      append(div2, t14);
      append(div2, audio2);
      ctx[35](audio2);
      append(div2, t15);
      append(div2, div1);
      if_block1.m(div1, null);
      current = true;
      if (!mounted) {
        dispose = [
          listen(
            select,
            "change",
            /*select_change_handler*/
            ctx[26]
          ),
          listen(
            input0,
            "input",
            /*input0_input_handler*/
            ctx[27]
          ),
          listen(
            input1,
            "change",
            /*input1_change_handler*/
            ctx[28]
          ),
          listen(
            input2,
            "change",
            /*input2_change_handler*/
            ctx[29]
          ),
          listen(
            input3,
            "change",
            /*input3_change_handler*/
            ctx[30]
          ),
          listen(
            video,
            "mouseenter",
            /*mouseenter_handler*/
            ctx[32]
          ),
          listen(
            video,
            "mouseleave",
            /*mouseleave_handler*/
            ctx[33]
          ),
          listen(
            audio2,
            "mouseenter",
            /*mouseenter_handler_1*/
            ctx[36]
          ),
          listen(
            audio2,
            "mouseleave",
            /*mouseleave_handler_1*/
            ctx[37]
          )
        ];
        mounted = true;
      }
    },
    p(ctx2, dirty) {
      if (dirty[0] & /*$packStore*/
      128) {
        each_value = /*$packStore*/
        ctx2[7];
        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(select, null);
          }
        }
        for (; i < each_blocks.length; i += 1) {
          each_blocks[i].d(1);
        }
        each_blocks.length = each_value.length;
      }
      if (dirty[0] & /*$selectedPackStore, $packStore*/
      132) {
        select_option(
          select,
          /*$selectedPackStore*/
          ctx2[2]
        );
      }
      if (dirty[0] & /*$search*/
      2 && input0.value !== /*$search*/
      ctx2[1]) {
        set_input_value(
          input0,
          /*$search*/
          ctx2[1]
        );
      }
      if (dirty[0] & /*$allRanges*/
      8) {
        input1.checked = /*$allRanges*/
        ctx2[3];
      }
      if (dirty[0] & /*$subLists*/
      256) {
        input2.checked = /*$subLists*/
        ctx2[8];
      }
      if (dirty[0] & /*$listView*/
      16) {
        input3.checked = /*$listView*/
        ctx2[4];
      }
      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(div3, t12);
      }
      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(div1, 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(div4);
      destroy_each(each_blocks, detaching);
      if_blocks[current_block_type_index].d();
      ctx[31](null);
      ctx[34](null);
      ctx[35](null);
      if_block1.d();
      mounted = false;
      run_all(dispose);
    }
  };
}
function create_fragment$f(ctx) {
  let applicationshell;
  let updating_elementRoot;
  let current;
  function applicationshell_elementRoot_binding(value) {
    ctx[38](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, $selectedPackStore, $packStore*/
      2046 | dirty[1] & /*$$scope*/
      8192) {
        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 $search;
  let $selectedPackStore;
  let $searchRegex;
  let $cleanSearchStore;
  let $allRanges;
  let $entriesStore;
  let $listView;
  let $packStore;
  let $subLists;
  let $visibleTreeStore;
  let $metadata;
  getContext("#external");
  let { elementRoot } = $$props;
  let entries = [];
  let filteredEntries = [];
  const selectedPackStore2 = databaseStore.selectedPackStore;
  component_subscribe($$self, selectedPackStore2, (value) => $$invalidate(2, $selectedPackStore = value));
  const packStore2 = databaseStore.packStore;
  component_subscribe($$self, packStore2, (value) => $$invalidate(7, $packStore = value));
  const metadata = databaseStore.metadata;
  component_subscribe($$self, metadata, (value) => $$invalidate(10, $metadata = value));
  const allRanges = databaseStore.allRanges;
  component_subscribe($$self, allRanges, (value) => $$invalidate(3, $allRanges = value));
  const subLists = databaseStore.subLists;
  component_subscribe($$self, subLists, (value) => $$invalidate(8, $subLists = value));
  const listView = databaseStore.listView;
  component_subscribe($$self, listView, (value) => $$invalidate(4, $listView = value));
  const visibleTreeStore2 = databaseStore.visibleTreeStore;
  component_subscribe($$self, visibleTreeStore2, (value) => $$invalidate(9, $visibleTreeStore = value));
  const search = databaseStore.search;
  component_subscribe($$self, search, (value) => $$invalidate(1, $search = value));
  const cleanSearchStore2 = databaseStore.cleanSearchStore;
  component_subscribe($$self, cleanSearchStore2, (value) => $$invalidate(24, $cleanSearchStore = value));
  const searchRegex = databaseStore.searchRegex;
  component_subscribe($$self, searchRegex, (value) => $$invalidate(23, $searchRegex = value));
  const entriesStore2 = SequencerDatabase.entriesStore;
  component_subscribe($$self, entriesStore2, (value) => $$invalidate(25, $entriesStore = value));
  listView.set(game.settings.get(CONSTANTS.MODULE_NAME, "db-list-view"));
  function select_change_handler() {
    $selectedPackStore = select_value(this);
    selectedPackStore2.set($selectedPackStore);
  }
  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(5, databaseStore);
    });
  }
  const mouseenter_handler = () => {
    $$invalidate(5, databaseStore.elements.player.controls = true, databaseStore);
  };
  const mouseleave_handler = () => {
    $$invalidate(5, databaseStore.elements.player.controls = false, databaseStore);
  };
  function img_binding($$value) {
    binding_callbacks[$$value ? "unshift" : "push"](() => {
      databaseStore.elements.image = $$value;
      $$invalidate(5, databaseStore);
    });
  }
  function audio_binding($$value) {
    binding_callbacks[$$value ? "unshift" : "push"](() => {
      databaseStore.elements.audio = $$value;
      $$invalidate(5, databaseStore);
    });
  }
  const mouseenter_handler_1 = () => {
    $$invalidate(5, databaseStore.elements.audio.controls = true, databaseStore);
  };
  const mouseleave_handler_1 = () => {
    $$invalidate(5, databaseStore.elements.audio.controls = false, 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*/
    16) {
      game.settings.set(CONSTANTS.MODULE_NAME, "db-list-view", $listView);
    }
    if ($$self.$$.dirty[0] & /*$entriesStore, $allRanges*/
    33554440) {
      {
        const specificRanges = $allRanges ? Sequencer.Database.publicFlattenedEntries : Sequencer.Database.publicFlattenedSimpleEntries;
        $$invalidate(22, entries = specificRanges.map((entry) => {
          return { pack: entry.split(".")[0], entry };
        }));
      }
    }
    if ($$self.$$.dirty[0] & /*$cleanSearchStore, entries, $searchRegex, $selectedPackStore, $search*/
    29360134) {
      {
        const searchParts = $cleanSearchStore.split("|");
        $$invalidate(6, filteredEntries = entries.filter((part) => {
          const matchParts = make_array_unique(part.entry.match($searchRegex) || []);
          return ($selectedPackStore === "all" || $selectedPackStore === part.pack) && ($search === "" || matchParts.length >= searchParts.length);
        }));
      }
    }
  };
  return [
    elementRoot,
    $search,
    $selectedPackStore,
    $allRanges,
    $listView,
    databaseStore,
    filteredEntries,
    $packStore,
    $subLists,
    $visibleTreeStore,
    $metadata,
    selectedPackStore2,
    packStore2,
    metadata,
    allRanges,
    subLists,
    listView,
    visibleTreeStore2,
    search,
    cleanSearchStore2,
    searchRegex,
    entriesStore2,
    entries,
    $searchRegex,
    $cleanSearchStore,
    $entriesStore,
    select_change_handler,
    input0_input_handler,
    input1_change_handler,
    input2_change_handler,
    input3_change_handler,
    video_binding,
    mouseenter_handler,
    mouseleave_handler,
    img_binding,
    audio_binding,
    mouseenter_handler_1,
    mouseleave_handler_1,
    applicationshell_elementRoot_binding
  ];
}
class Database_shell extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, instance$f, create_fragment$f, safe_not_equal, { elementRoot: 0 }, null, [-1, -1]);
  }
  get elementRoot() {
    return this.$$.ctx[0];
  }
  set elementRoot(elementRoot) {
    this.$$set({ elementRoot });
    flush();
  }
}
class DatabaseViewerApp extends SvelteApplication {
  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 });
    });
  }
}
const HowTo_svelte_svelte_type_style_lang = "";
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);
      if (detaching)
        detach(t0);
      if (detaching)
        detach(button);
      mounted = false;
      dispose();
    }
  };
}
function create_fragment$e(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-ese-1gfsmnk");
      html_tag_1.a = null;
      attr(li1, "class", "svelte-ese-1gfsmnk");
      html_tag_2.a = null;
      attr(li2, "class", "svelte-ese-1gfsmnk");
      html_tag_3.a = null;
      attr(li3, "class", "svelte-ese-1gfsmnk");
      attr(li4, "class", "svelte-ese-1gfsmnk");
      attr(div, "class", "howto-container svelte-ese-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$e, safe_not_equal, {});
  }
}
const Tabs_svelte_svelte_type_style_lang = "";
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-ese-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-ese-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-ese-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);
      if (if_block0)
        if_block0.d(detaching);
      if (detaching)
        detach(t0);
      if (detaching)
        detach(div);
      if (if_block1)
        if_block1.d();
      mounted = false;
      dispose();
    }
  };
}
function create_fragment$d(ctx) {
  let nav;
  let each_blocks = [];
  let each_1_lookup = /* @__PURE__ */ new Map();
  let nav_style_value;
  let each_value = (
    /*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-ese-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) {
        each_blocks[i].m(nav, null);
      }
    },
    p(ctx2, [dirty]) {
      if (dirty & /*underscore, activeTab, tabs, localize, separateElements*/
      15) {
        each_value = /*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$d, safe_not_equal, {
      activeTab: 0,
      tabs: 1,
      underscore: 2,
      separateElements: 3
    });
  }
}
const SequenceManager = {
  VisibleEffects: writable$1({}),
  RunningSounds: writable$1({}),
  RunningSequences: writable$1({})
};
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((effects) => {
    effects[id] = data;
    return effects;
  });
};
SequenceManager.RunningSounds.delete = (id) => {
  SequenceManager.RunningSounds.update((effects) => {
    delete effects[id];
    return effects;
  });
};
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 (get_store_value(sequence.status) === CONSTANTS.STATUS.COMPLETE || get_store_value(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.filters.ColorMatrixFilter {
  /**
   * Properties & default values:
   *     - hue [false]
   *     - brightness [1]
   *     - contrast [1]
   *     - saturate [1]
   */
  constructor(inData) {
    super();
    this.isValid = true;
    this.values = {};
    for (let [key, value] of Object.entries(inData)) {
      this.setValue(key, value);
      if (!this.isValid)
        break;
    }
  }
  setValue(key, value) {
    try {
      this.values[key] = value;
      this[key](value, true);
    } catch (err) {
      ui.notifications.warn(
        `Sequencer | ${this.constructor.name} | Could not set property ${key}`
      );
    }
  }
}
class BlurFilter extends globalThis.PIXI.filters.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.filters.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.filters.GlowFilter {
  /**
   * Properties & default values:
   *     - distance [10]
   *     - outerStrength [4]
   *     - innerStrength [0]
   *     - color [0xffffff]
   *     - quality [0.1]
   *     - knockout [false]
   */
  constructor(inData = {}) {
    inData = foundry.utils.mergeObject(
      {
        distance: 10,
        outerStrength: 4,
        innerStrength: 0,
        color: 16777215,
        quality: 0.1,
        knockout: false
      },
      inData
    );
    super(inData);
    this.isValid = true;
  }
}
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
};
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.started = false;
          attribute.initialized = false;
          attribute.finishing = false;
          attribute.complete = false;
          attribute.progress = 0;
          attribute.value = 0;
          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
      });
      if (!this.ticker || !this.ticker.started) {
        this.start();
      }
      debug(`Added animations to Animation Engine`);
    });
  },
  endAnimations(target) {
    this._animations = this._animations.filter(
      (animation2) => animation2.origin !== target
    );
  },
  start() {
    debug(`Animation Engine Started`);
    if (!this.ticker) {
      this.ticker = new PIXI.Ticker();
      this.ticker.add(this.nextFrame.bind(this));
    }
    this.ticker.start();
  },
  nextFrame() {
    if (this._animations.length === 0) {
      debug(`Animation Engine Paused`);
      this.ticker.stop();
      this._startingValues = {};
      return;
    }
    this._animations.forEach((animation2) => this._animate(animation2));
    this._animations = this._animations.filter(
      (animation2) => !animation2.complete
    );
    this._applyDeltas();
    for (const targetId of Object.keys(this._startingValues)) {
      if (!this._animations.some(
        (_a) => _a.attributes.some((_b) => _b.targetId === targetId)
      )) {
        delete this._startingValues[targetId];
      }
    }
  },
  _startingValues: {},
  _applyDeltas() {
    const deltas = [];
    for (const animation2 of this._animations) {
      for (const attribute of animation2.attributes) {
        if (!attribute.started || attribute.complete)
          continue;
        if (attribute.finishing) {
          attribute.complete = true;
        }
        let delta = deltas.find(
          (delta2) => attribute.targetId === delta2.targetId && attribute.setPropertyName === delta2.setPropertyName
        );
        if (!delta) {
          delta = {
            targetId: attribute.targetId,
            target: attribute.target,
            getPropertyName: attribute.getPropertyName ?? attribute.propertyName,
            setPropertyName: attribute.propertyName,
            value: 0
          };
          if (attribute.target instanceof PIXI.filters.ColorMatrixFilter) {
            delta.value = attribute.previousValue;
          }
          deltas.push(delta);
        }
        delta.value += attribute.delta;
      }
    }
    for (let delta of deltas) {
      const finalValue = deep_get(delta.target, delta.getPropertyName) + delta.value;
      try {
        deep_set(delta.target, delta.setPropertyName, finalValue);
      } catch (err) {
      }
    }
  },
  _animate(animation2) {
    animation2.totalDt += this.ticker.elapsedMS;
    animation2.attributes.filter((attribute) => !attribute.complete).forEach(
      (attribute) => this._animateAttribute(animation2.totalDt, attribute)
    );
    animation2.complete = animation2.attributes.filter((attribute) => !attribute.complete).length === 0;
    if (animation2.complete) {
      animation2.resolve();
    }
  },
  _animateAttribute(totalDt, attribute) {
    if (totalDt < attribute.delay)
      return;
    if (!attribute.started) {
      const funkyProperty = attribute.propertyName.includes("scale") || attribute.propertyName.includes("alpha");
      if (this._startingValues[attribute.targetId] === void 0 || attribute.absolute) {
        const getProperty2 = funkyProperty || attribute.from === void 0;
        this._startingValues[attribute.targetId] = getProperty2 ? deep_get(
          attribute.target,
          attribute.getPropertyName ?? attribute.propertyName
        ) : attribute.from;
        if (!attribute.propertyName.includes("scale")) {
          deep_set(
            attribute.target,
            attribute.propertyName,
            this._startingValues[attribute.targetId]
          );
        }
      }
      attribute.previousValue = this._startingValues[attribute.targetId];
      if (attribute?.looping) {
        attribute.values = attribute.values.map((value) => {
          return value + attribute.previousValue - (funkyProperty ? 1 : 0);
        });
      } else if (attribute.from === void 0) {
        attribute.from = attribute.previousValue;
      }
    }
    attribute.started = true;
    if (attribute?.looping && attribute?.indefinite) {
      this._handleIndefiniteLoop(attribute);
    } else if (attribute?.looping) {
      this._handleLoops(attribute);
    } else {
      this._handleDefault(attribute);
    }
    attribute.delta = attribute.value - attribute.previousValue;
    attribute.previousValue = attribute.value;
  },
  _handleBaseLoop(attribute) {
    if (!attribute.initialized) {
      if (attribute.values.length === 1) {
        attribute.values.unshift(
          deep_get(attribute.target, attribute.propertyName)
        );
      }
      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) {
    attribute.durationDone += this.ticker.deltaMS;
    attribute.progress = attribute.durationDone / attribute.duration;
    attribute.value = interpolate(
      attribute.from,
      attribute.to,
      attribute.progress,
      attribute.ease
    );
    if (attribute.progress >= 1) {
      attribute.value = attribute.to;
      attribute.finishing = true;
    }
  }
};
let SequencerAudioHelper$1 = class SequencerAudioHelper2 {
  /**
   * Play an audio file.
   *
   * @param {{src: string, loop?: boolean, volume?: number, _fadeIn?: {duration: number}, _fadeOut?: {duration: number}, duration?: number}} data The data that describes the audio to play.
   * @param {boolean} [push=false] A flag indicating whether or not 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 {{src: string, loop?: boolean, volume: number, _fadeIn?: {duration: number}, _fadeOut?: {duration: number}, duration?: number}} data
   * @returns {Number}
   * @private
   */
  static async _play(data) {
    if (!game.settings.get("sequencer", "soundsEnabled") || game.user.viewedScene !== data.sceneId || data?.users?.length && !data?.users?.includes(game.userId)) {
      return new Promise((resolve) => setTimeout(resolve, data.duration));
    }
    Hooks.callAll("createSequencerSound", data);
    debug(`Playing sound:`, data);
    data.volume = (data.volume ?? 0.8) * game.settings.get("core", "globalInterfaceVolume");
    const sound = await game.audio.play(data.src, {
      volume: data.fadeIn ? 0 : data.volume,
      loop: data.loop,
      offset: data.startTime
    });
    SequenceManager.RunningSounds.add(data.id, sound);
    if (data.fadeIn) {
      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)
      });
    }
    if (data.fadeOut) {
      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
        )
      });
    }
    if (data.duration) {
      setTimeout(() => {
        sound.stop();
      }, data.duration);
    }
    new Promise((resolve) => {
      sound.on("stop", resolve);
      sound.on("end", resolve);
    }).then(() => {
      SequenceManager.RunningSounds.delete(data.id);
      Hooks.callAll("endedSequencerSound", data);
    });
    return data.duration;
  }
  static stop(ids, push = true) {
    if (push && game.user.isGM)
      sequencerSocket.executeForOthers(SOCKET_HANDLERS.STOP_SOUNDS, ids);
    return this._stop(ids);
  }
  static _stop(ids) {
    for (const id of ids) {
      const sound = SequenceManager.RunningSounds.get(id);
      if (sound) {
        sound.stop();
      }
    }
  }
};
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 _validateObject(inObject, sceneId) {
    if (is_UUID(inObject) || !is_object_canvas_data(inObject)) {
      inObject = get_object_from_scene(inObject, sceneId);
    }
    return inObject?._object ?? inObject;
  }
  static _getPositionFromData(data) {
    const source = this._validateObject(data.source, data.sceneId);
    const position = source instanceof PlaceableObject ? get_object_position(source) : source?.worldPosition || source?.center || source;
    const multiplier = data.randomOffset;
    const twister = new MersenneTwister(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;
  }
  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(
      this._getPositionFromData(data),
      data.content,
      data.options
    );
    return data.options?.duration ?? 2e3;
  }
  static panCanvas(data, push = true) {
    if (push) {
      sequencerSocket.executeForOthers(
        SOCKET_HANDLERS.CREATE_SCROLLING_TEXT,
        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;
    const position = this._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);
    }
    return data.duration + (data.lockView ?? 0);
  }
}
const SOCKET_HANDLERS = {
  PLAY_EFFECT: "playEffect",
  END_EFFECTS: "endEffects",
  UPDATE_EFFECT: "updateEffects",
  ADD_EFFECT_ANIMATIONS: "addEffectAnimations",
  PLAY_SOUND: "playSound",
  STOP_SOUNDS: "stopSounds",
  PRELOAD: "preload",
  PRELOAD_RESPONSE: "preloadResponse",
  PRELOAD_DONE: "preloadDone",
  UPDATE_DOCUMENT: "updateDocument",
  ADD_FLAGS: "addFlags",
  REMOVE_FLAGS: "removeFlags",
  UPDATE_POSITION: "updatePosition",
  CREATE_SCROLLING_TEXT: "createScrollingText",
  PAN_CANVAS: "panCanvas",
  RUN_SEQUENCE_LOCALLY: "runSequenceLocally"
};
let sequencerSocket;
function registerSocket() {
  console.log("Sequencer | Registered sequencerSocket");
  sequencerSocket = socketlib.registerModule(CONSTANTS.MODULE_NAME);
  sequencerSocket.register(
    SOCKET_HANDLERS.PLAY_EFFECT,
    (...args) => Sequencer.EffectManager._playEffect(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.END_EFFECTS,
    (...args) => Sequencer.EffectManager._endManyEffects(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.UPDATE_EFFECT,
    (...args) => Sequencer.EffectManager._updateEffect(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
    (...args) => Sequencer.EffectManager._addEffectAnimations(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.PLAY_SOUND,
    (...args) => SequencerAudioHelper$1._play(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.STOP_SOUNDS,
    (...args) => SequencerAudioHelper$1._stop(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.PRELOAD,
    (...args) => Sequencer.Preloader.respond(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.PRELOAD_RESPONSE,
    (...args) => Sequencer.Preloader.handleResponse(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.UPDATE_DOCUMENT,
    (...args) => updateDocument(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.ADD_FLAGS,
    (...args) => flagManager._addFlags(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.REMOVE_FLAGS,
    (...args) => flagManager._removeFlags(...args)
  );
  sequencerSocket.register(
    SOCKET_HANDLERS.UPDATE_POSITION,
    (...args) => Sequencer.EffectManager._updatePosition(...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 flagManager = {
  flagAddBuffer: /* @__PURE__ */ new Map(),
  flagRemoveBuffer: /* @__PURE__ */ new Map(),
  _latestFlagVersion: false,
  get latestFlagVersion() {
    if (!this._latestFlagVersion) {
      const versions = Object.keys(this.migrations);
      versions.sort((a, b) => {
        return 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}
   */
  getFlags(inDocument) {
    let effects = 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";
      if (effectData.flagVersion === this.latestFlagVersion)
        continue;
      for (let [version, migration] of Object.entries(this.migrations)) {
        if (!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;
      changes.push(effectData);
    }
    if (changes.length) {
      flagManager.addFlags(inDocument.uuid, changes);
    }
    return effects;
  },
  migrations: {
    "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;
    }
  },
  /**
   * Adds effects to a given document
   *
   * @param inObjectUUID
   * @param inEffects
   */
  addFlags: (inObjectUUID, inEffects) => {
    if (!Array.isArray(inEffects))
      inEffects = [inEffects];
    sequencerSocket.executeAsGM(
      SOCKET_HANDLERS.ADD_FLAGS,
      inObjectUUID,
      inEffects
    );
  },
  /**
   * Removes effects from a given document
   *
   * @param inObjectUUID
   * @param inEffects
   * @param removeAll
   */
  removeFlags: (inObjectUUID, inEffects, removeAll = false) => {
    sequencerSocket.executeAsGM(
      SOCKET_HANDLERS.REMOVE_FLAGS,
      inObjectUUID,
      inEffects,
      removeAll
    );
  },
  _addFlags: (inObjectUUID, inEffects) => {
    if (!Array.isArray(inEffects))
      inEffects = [inEffects];
    let flagsToSet = flagManager.flagAddBuffer.get(inObjectUUID) ?? {
      effects: []
    };
    flagsToSet.effects.push(...inEffects);
    flagManager.flagAddBuffer.set(inObjectUUID, flagsToSet);
    flagManager.updateFlags();
  },
  _removeFlags: (inObjectUUID, inEffects, removeAll = false) => {
    if (inEffects && !Array.isArray(inEffects))
      inEffects = [inEffects];
    let flagsToSet = flagManager.flagRemoveBuffer.get(inObjectUUID) ?? {
      effects: [],
      removeAll
    };
    if (inEffects)
      flagsToSet.effects.push(...inEffects);
    flagManager.flagRemoveBuffer.set(inObjectUUID, flagsToSet);
    flagManager.updateFlags();
  },
  updateFlags: debounce(async () => {
    let flagsToAdd = Array.from(flagManager.flagAddBuffer);
    let flagsToRemove = Array.from(flagManager.flagRemoveBuffer);
    flagManager.flagAddBuffer.clear();
    flagManager.flagRemoveBuffer.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 = from_uuid_fast(objectUUID);
      if (!object) {
        custom_warning(
          "Sequencer",
          `Failed to set flags on non-existent object with UUID: ${objectUUID}`
        );
        continue;
      }
      let toAdd = flagsToAdd.get(objectUUID) ?? { effects: [] };
      let toRemove = flagsToRemove.get(objectUUID) ?? {
        effects: [],
        removeAll: false
      };
      const existingFlags = new Map(
        getProperty(object, CONSTANTS.EFFECTS_FLAG) ?? []
      );
      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 = {};
      const isLinkedToken = object instanceof TokenDocument && object.actorLink;
      const isLinkedActor = object instanceof Actor && object.prototypeToken.actorLink;
      if ((isLinkedToken || isLinkedActor) && (toAdd.original || toRemove.original)) {
        const actor = isLinkedActor ? object : object.actor;
        actorUpdates[actor.id] = flagsToSet.filter(
          (effect) => effect[1]?.persistOptions?.persistTokenPrototype
        );
        flagsToSet = flagsToSet.filter(
          (effect) => !effect[1]?.persistOptions?.persistTokenPrototype
        );
        if (isLinkedToken && game.modules.get("multilevel-tokens")?.active && 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)) {
        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)
};
const PositionContainer = /* @__PURE__ */ new Map();
const TemporaryPositionsContainer = /* @__PURE__ */ new Map();
class SequencerEffectManager {
  /**
   * Returns all of 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 Effects 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);
    if (data?.persistOptions?.persistTokenPrototype) {
      this._playPrototypeTokenEffects(data, push);
    }
    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 ? 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 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 PlaceableObject || typeof object === "string")) {
      throw custom_error(
        "Sequencer",
        "EffectManager | object must be instance of PlaceableObject or of type string"
      );
    } else if (object instanceof 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 && !data.temporary && !data.remote) {
      flagManager.addFlags(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._ticker.add(() => {
        if (effect.source && !effect.isSourceDestroyed) {
          const sourceData = effect.getSourceData();
          if (JSON.stringify(sourceData) !== lastSourcePosition) {
            sequencerSocket.executeForOthers(
              SOCKET_HANDLERS.UPDATE_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_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 setUpPersists() {
    await this.tearDownPersists();
    const allObjects = get_all_documents_from_scene();
    allObjects.push(canvas.scene);
    const docEffectsMap = allObjects.reduce((acc, doc) => {
      let tokenEffects = flagManager.getFlags(doc);
      if (doc instanceof TokenDocument && doc?.actorLink) {
        const actorEffects = flagManager.getFlags(doc?.actor);
        actorEffects.forEach((e) => {
          e[1]._id = randomID();
          e[1].source = doc.uuid;
          e[1].sceneId = doc.parent.id;
        });
        tokenEffects = tokenEffects.concat(actorEffects);
      }
      if (tokenEffects.length) {
        acc[doc.uuid] = tokenEffects;
      }
      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();
      })
    );
  }
  /**
   * 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.getFlags(inDocument);
    if (!effects?.length)
      return;
    const updates = {};
    let documentUuid;
    if (!inDocument._id) {
      const documentId = 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] = 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.getFlags(inDocument);
    if (inDocument instanceof TokenDocument && inDocument?.actorLink) {
      let actorEffects = flagManager.getFlags(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(async (effect) => {
        if (!CanvasEffect.checkValid(effect[1])) {
          if (game.user.isGM) {
            custom_warning(
              `Removed effect from ${inDocument.uuid} as it no longer had a valid source or target`
            );
          }
          return flagManager.removeFlags(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.removeFlags(
        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) => data?.persistOptions?.persistTokenPrototype
      );
      if (!persistentEffectData.length)
        return;
      const actorEffects = flagManager.getFlags(effectContext.actor);
      const applicableActorEffects = actorEffects.filter((effect) => {
        return effect[1]?.persistOptions?.persistTokenPrototype && persistentEffectData.some(
          (persistentEffect) => persistentEffect.persistOptions.id === effect[1]?.persistOptions?.id
        );
      }).map((e) => e[0]);
      flagManager.removeFlags(
        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.getFlags(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.removeFlags(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();
  }
  static async _playPrototypeTokenEffects(data, push) {
    if (!is_UUID(data.source))
      return;
    const object = from_uuid_fast(data.source);
    if (!(object instanceof TokenDocument))
      return;
    const tokenEffectsToPlay = game.scenes.map(
      (scene) => scene.tokens.filter((token) => {
        return token.actorLink && token.actor === object.actor && token !== object;
      })
    ).deepFlatten();
    for (const tokenDocument of tokenEffectsToPlay) {
      const duplicatedData = foundry.utils.deepClone(data);
      duplicatedData._id = randomID();
      duplicatedData.sceneId = tokenDocument.uuid.split(".")[1];
      duplicatedData.masks = duplicatedData.masks.map((uuid) => uuid.replace(duplicatedData.source, tokenDocument.uuid)).filter((uuid) => uuid.includes(duplicatedData.sceneId));
      duplicatedData.source = tokenDocument.uuid;
      if (CanvasEffect.checkValid(duplicatedData)) {
        if (push)
          sequencerSocket.executeForOthers(
            SOCKET_HANDLERS.PLAY_EFFECT,
            duplicatedData
          );
        if (duplicatedData.sceneId === game.user.viewedScene) {
          await this._playEffect(duplicatedData, false);
        }
      }
    }
  }
}
class BaseEffectsLayer extends InteractionLayer {
  static get layerOptions() {
    return foundry.utils.mergeObject(super.layerOptions, {
      elevation: 1e8,
      name: "sequencerEffects"
    });
  }
}
class SequencerInterfaceLayer extends InteractionLayer {
  constructor(...args) {
    super(...args);
  }
  static get layerOptions() {
    return foundry.utils.mergeObject(super.layerOptions, {
      elevation: 1e8,
      name: "sequencerInterfaceEffects"
    });
  }
  deactivate() {
    super.deactivate();
    if (!this.active)
      return;
    this._clearChildren();
    this.active = 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.filters.AlphaFilter(0.75)];
      this.effectSourcePosition.filters = [new PIXI.filters.AlphaFilter(0.75)];
      this.effectTargetPosition.filters = [new PIXI.filters.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.active)
      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 !== "play-effect")
      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 !== "play-effect")
      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 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(name, zIndex = 0.1) {
    this.canvas = document.createElement("canvas");
    this.canvas.id = name;
    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.uiEffectsLayer;
  }
  static addChild(...args) {
    const result = this.getLayer().addChild(...args);
    layer.app.stage.renderable = layer.app.stage.children.length > 0;
    return result;
  }
  static sortChildren() {
    return this.getLayer().sortChildren();
  }
  static removeContainerByEffect(inEffect) {
    const child = this.getLayer().children.find((child2) => child2 === inEffect);
    if (!child)
      return;
    this.getLayer().removeChild(child);
    layer.app.stage.renderable = layer.app.stage.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();
      }
    }
  }
}
class VisionSamplerShader extends BaseSamplerShader {
  /** @override */
  static classPluginName = null;
  /** @inheritdoc */
  static vertexShader = `
      precision ${PIXI.settings.PRECISION_VERTEX} float;
      attribute vec2 aVertexPosition;
      attribute vec2 aTextureCoord;
      uniform mat3 projectionMatrix;
      uniform vec2 screenDimensions;
      varying vec2 vUvsMask;
      varying vec2 vUvs;
      void main() {
        vUvs = aTextureCoord;
        vUvsMask = aVertexPosition / screenDimensions;
        gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
      }
    `;
  /** @inheritdoc */
  static fragmentShader = `
      precision ${PIXI.settings.PRECISION_FRAGMENT} float;
      varying vec2 vUvs;
      varying vec2 vUvsMask;
      uniform vec4 tintAlpha;
      uniform sampler2D sampler;
      uniform sampler2D maskSampler;
      uniform bool enableVisionMasking;
      void main() {
        float mask = enableVisionMasking ? texture2D(maskSampler, vUvsMask).r : 1.0;
        gl_FragColor = texture2D(sampler, vUvs) * tintAlpha * mask;
      }
    `;
  /** @inheritdoc */
  static defaultUniforms = {
    tintAlpha: [1, 1, 1, 1],
    sampler: 0,
    maskSampler: 0,
    screenDimensions: [1, 1],
    enableVisionMasking: false
  };
  /** @override */
  _preRender(mesh) {
    super._preRender(mesh);
    this.uniforms.maskSampler = canvas.masks.vision.renderTexture;
    this.uniforms.screenDimensions = canvas.screenDimensions;
    this.uniforms.enableVisionMasking = canvas.effects.visibility.visible;
  }
}
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]));
  }
};
class CanvasEffect extends PIXI.Container {
  #elevation = 0;
  #sort = 0;
  constructor(inData) {
    super();
    this.sortableChildren = true;
    this.actualCreationTime = +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.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;
  }
  get context() {
    return this.data.attachTo?.active && this.sourceDocument ? this.sourceDocument : game.scenes.get(this.data.sceneId);
  }
  get isIsometricActive() {
    const sceneIsIsometric = getProperty(
      game.scenes.get(this.data.sceneId),
      CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED
    );
    return CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE && sceneIsIsometric;
  }
  /**
   * 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.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?._destroyed);
  }
  /**
   * 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?._destroyed);
  }
  /**
   * The source object (or source location) of the effect
   *
   * @returns {boolean|object}
   */
  get source() {
    if (!this._source && this.data.source) {
      this._source = this._getObjectByID(this.data.source);
      this._source = this._source?._object ?? this._source;
    }
    return this._source;
  }
  /**
   * Retrieves the source document
   *
   * @returns {Document|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);
    return {
      x: position.x - offset2.x,
      y: position.y - offset2.y
    };
  }
  /**
   * The target object (or target location) of the effect
   *
   * @returns {boolean|object}
   */
  get target() {
    if (!this._target && this.data.target) {
      this._target = this._getObjectByID(this.data.target);
      this._target = this._target?._object ?? this._target;
    }
    return this._target;
  }
  /**
   * Retrieves the document of the target
   *
   * @returns {Document|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,
      y: position.y - offset2.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;
  }
  /**
   * 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 game.settings.get(CONSTANTS.MODULE_NAME, "user-effect-opacity") !== 0 && 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);
  }
  /**
   * Getter for the current playing video of the effect
   *
   * @returns {null|*}
   */
  get video() {
    return this._video;
  }
  /**
   * Setter for the current playing video of the effect
   */
  set video(inVideo) {
    if (!inVideo)
      return;
    inVideo.playbackRate = this.data.playbackRate ? this.data.playbackRate : 1;
    inVideo.muted = !this.data.volume;
    inVideo.volume = (this.data.volume ?? 0) * game.settings.get("core", "globalInterfaceVolume");
    if (!this._video) {
      this._video = inVideo;
      return;
    }
    const isLooping = this._video?.loop;
    const currentTime = this._video.currentTime;
    this._video = inVideo;
    this._video.currentTime = this.playNaturally ? 0 : Math.min(currentTime, this._video.duration);
    this._video.loop = isLooping;
    this._texture.update();
  }
  async playMedia() {
    if (this.animatedSprite) {
      await this.sprite.play();
    } else if (this.video) {
      try {
        await this.video.play();
      } catch (err) {
      }
    }
    this._setupTimestampHook(this.mediaCurrentTime * 1e3);
  }
  async pauseMedia() {
    if (this.animatedSprite) {
      return this.sprite.stop();
    } else if (this.video) {
      return this.video.pause();
    }
  }
  get mediaLooping() {
    if (this.animatedSprite) {
      return this.sprite.loop;
    }
    return this.video?.loop ?? false;
  }
  set mediaLooping(looping) {
    if (this.animatedSprite) {
      this.sprite.loop = looping;
      return;
    }
    if (this.video) {
      this.video.loop = looping;
    }
  }
  get mediaIsPlaying() {
    if (this.animatedSprite) {
      return this.sprite.playing;
    }
    return this.video;
  }
  get mediaCurrentTime() {
    if (this.animatedSprite) {
      return this.sprite.currentFrame / this.sprite.totalFrames * (this.sprite.totalFrames / 24);
    }
    return this.video?.currentTime ?? null;
  }
  set mediaPlaybackRate(inPlaybackRate) {
    if (this.animatedSprite) {
      this.sprite.animationSpeed = 0.4 * inPlaybackRate;
    } else if (this.video) {
      this.video.playbackRate = inPlaybackRate;
    }
  }
  set mediaCurrentTime(newTime) {
    if (this.animatedSprite) {
      const newFrame = Math.floor(newTime * this.sprite.totalFrames);
      const clampedFrame = Math.max(
        0,
        Math.min(newFrame, this.sprite.totalFrames)
      );
      if (this.mediaIsPlaying) {
        this.sprite.gotoAndPlay(clampedFrame);
      } else {
        this.sprite.gotoAndStop(clampedFrame);
      }
    } else if (this.video) {
      this.video.currentTime = newTime;
    }
  }
  get mediaDuration() {
    if (this.animatedSprite) {
      return this.sprite.totalFrames / this.sprite.animationSpeed / PIXI.Ticker.shared.FPS;
    } else if (this.video) {
      return this.video?.duration;
    }
    return 1;
  }
  get hasAnimatedMedia() {
    return !!(this.video || this.animatedSprite);
  }
  /**
   * The template of the effect, determining the effect's internal grid size, and start/end padding
   *
   * @returns {object}
   */
  get template() {
    return foundry.utils.mergeObject(
      {
        gridSize: 100,
        startPoint: 0,
        endPoint: 0
      },
      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;
  }
  /**
   * Whether the effect should be flipped on any given axis
   *
   * @returns {number}
   */
  get flipX() {
    return this.data.flipX ? -1 : 1;
  }
  get flipY() {
    return this.data.flipY ? -1 : 1;
  }
  /**
   * 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 (isNewerVersion(game.version, "10.289") && 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;
  }
  /**
   * Whether this effect should play naturally, or be constrained to a subsection of the video
   *
   * @returns {boolean}
   */
  get playNaturally() {
    return (!this.data.time || this._startTime === 0 && this._endTime === this.mediaDuration) && this._animationTimes.loopStart === void 0 && this._animationTimes.loopEnd === void 0;
  }
  static make(inData) {
    return !inData.persist ? new CanvasEffect(inData) : new PersistentCanvasEffect(inData);
  }
  static checkValid(effectData) {
    let sourceExists = true;
    let targetExists = true;
    if (effectData.source && is_UUID(effectData.source)) {
      sourceExists = from_uuid_fast(effectData.source);
    }
    if (effectData.target && is_UUID(effectData.target)) {
      targetExists = from_uuid_fast(effectData.target);
    }
    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);
    }
    const position = this.source instanceof PlaceableObject && !this.isSourceTemporary ? get_object_position(this.source) : this.source?.worldPosition || this.source?.center || this.source;
    const { width: width2, height } = get_object_dimensions(this.source);
    if (this.isIsometricActive && this.source instanceof PlaceableObject) {
      position.x += (this.sourceDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
      position.y -= (this.sourceDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size;
      if (this.data.isometric?.overlay || this.target instanceof PlaceableObject) {
        position.x += (this.source?.height ?? height) / 2;
        position.y -= (this.source?.height ?? height) / 2;
      }
    }
    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 MeasuredTemplate && this.sourceDocument?.t !== "rect") {
      rotation2 = Math.normalizeRadians(
        Math.toRadians(this.sourceDocument?.direction)
      );
    } else if (!(this.source instanceof 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?.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();
    }
    const position = this.target instanceof PlaceableObject && !this.isTargetTemporary ? get_object_position(this.target, { measure: true }) : this.target?.worldPosition || this.target?.center || this.target;
    const { width: width2, height } = get_object_dimensions(this.target);
    if (this.isIsometricActive && this.target instanceof PlaceableObject) {
      const targetHeight = this.target?.height ?? height;
      position.x += (this.targetDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size + targetHeight;
      position.y -= (this.targetDocument.elevation ?? 0) / canvas.scene.grid.distance * canvas.grid.size + targetHeight;
    }
    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 MeasuredTemplate && this.targetDocument?.t !== "rect") {
      rotation2 = Math.normalizeRadians(
        Math.toRadians(this.targetDocument?.direction)
      );
    } else if (!(this.target instanceof 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) {
        newOffset = rotateAroundPoint(
          0,
          0,
          newOffset.x,
          newOffset.y,
          -this.rotationContainer.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 = new MersenneTwister(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, reject2) => {
      this._durationResolve = resolve;
    });
    const finishPromise = new Promise(async (resolve, reject2) => {
      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) => {
      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.removeFlags(originalSourceUUID, newData);
      }
      flagManager.addFlags(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 = +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 = +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.addFlags(originalSourceUUID, newData);
    }
    return sequencerSocket.executeForEveryone(
      SOCKET_HANDLERS.ADD_EFFECT_ANIMATIONS,
      this.id,
      animationsToAdd
    );
  }
  async _addAnimations(inAnimations) {
    this._playAnimations(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
   *
   * @param {boolean} play
   * @returns {Promise}
   * @private
   */
  async _initialize(play = true) {
    this.ready = false;
    this._initializeVariables();
    await this._contextLostCallback();
    await this._loadTexture();
    this._addToContainer();
    this._createSprite();
    this._calculateDuration();
    this._createShapes();
    await this._setupMasks();
    await this._transformSprite();
    this._playCustomAnimations();
    this._playPresetAnimations();
    this._setEndTimeout();
    this._timeoutVisibility();
    if (play)
      await this.playMedia();
    this.ready = true;
  }
  /**
   * Reinitializes the effect after it has been updated
   *
   * @param play
   * @returns {Promise}
   * @private
   */
  async _reinitialize(play = true) {
    this.renderable = false;
    if (!this.shouldPlay) {
      return Sequencer.EffectManager._removeEffect(this);
    }
    this.actualCreationTime = +new Date();
    return this._initialize(play);
  }
  /**
   * 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.isometricContainer = this.rotationContainer.addChild(
      new PIXI.Container()
    );
    this.isometricContainer.id = this.id + "-isometricContainer";
    this.spriteContainer = this.isometricContainer.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 = new MersenneTwister(this.data.creationTimestamp);
    this._video = null;
    this._distanceCache = null;
    this._isRangeFind = false;
    this._customAngle = 0;
    this._currentFilePath = this.data.file;
    this._relatedSprites = {};
    this._hooks = [];
    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;
    const maxPerformance = game.settings.get("core", "performanceMode") === 3;
    const maxFPS = game.settings.get("core", "maxFPS");
    this._ticker = new PIXI.Ticker();
    this._ticker.maxFPS = maxPerformance && maxFPS === 60 ? 60 : maxFPS;
    this._ticker.start();
  }
  /**
   * 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);
    try {
      this._ticker.stop();
      this._ticker.destroy();
    } catch (err) {
    }
    this._ticker = null;
    Object.values(this._relatedSprites).forEach(
      (sprite) => sprite.destroy({ children: true })
    );
    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) {
      }
    }
    if (this._file instanceof SequencerFileBase) {
      this._file.destroy();
    }
    if (this.video) {
      try {
        this.video.removeAttribute("src");
        this.video.pause();
        this.video.load();
      } catch (err) {
      }
    }
    try {
      if (this.data.screenSpace) {
        SequencerAboveUILayer.removeContainerByEffect(this);
      }
    } catch (err) {
    }
    this.removeChildren().forEach((child) => child.destroy({ children: true }));
  }
  /**
   * Plays preset animations
   *
   * @private
   */
  _playPresetAnimations() {
    this._moveTowards();
    this._fadeIn();
    this._fadeInAudio();
    this._scaleIn();
    this._rotateIn();
    this._fadeOut();
    this._fadeOutAudio();
    this._scaleOut();
    this._rotateOut();
  }
  /**
   * 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
   * @returns {*}
   * @private
   */
  _getObjectByID(inIdentifier) {
    let source = inIdentifier;
    let offsetMap = this._nameOffsetMap?.[inIdentifier];
    if (offsetMap) {
      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.aboveLighting) {
      layer2 = canvas.interface;
    } else {
      layer2 = canvas.primary;
    }
    layer2.addChild(this);
    layer2.sortChildren();
  }
  /**
   * Loads the texture for this effect, handling cases where it's a simple path or a database path
   *
   * @private
   */
  async _loadTexture() {
    if (this.data.file === "") {
      return;
    }
    if (this.data.customRange) {
      this._file = SequencerFileBase.make(
        this.data.file,
        Object.values(this.template),
        "temporary.range.file"
      );
    } else {
      if (!Sequencer.Database.entryExists(this.data.file)) {
        let texture = await SequencerFileCache.loadFile(this.data.file);
        this.video = this.data.file.toLowerCase().endsWith(".webm") ? texture?.baseTexture?.resource?.source ?? false : false;
        this._texture = texture;
        this._file = texture;
        this._currentFilePath = this.data.file;
        return;
      }
      this._file = Sequencer.Database.getEntry(this.data.file).clone();
    }
    this._file.fileIndex = this.data.forcedIndex;
    this._file.twister = this._twister;
    this._isRangeFind = this._file?.rangeFind;
    this.spriteSheet = false;
    if (this.data.stretchTo) {
      let ray = new Ray(this.sourcePosition, this.targetPosition);
      this._rotateTowards(ray);
      ray = new Ray(this.sourcePosition, this.targetPosition);
      let { filePath, texture, sheet } = await this._getTextureForDistance(
        ray.distance
      );
      this._currentFilePath = filePath;
      this._texture = texture;
      this.spriteSheet = sheet;
    } else if (!this._isRangeFind || this._isRangeFind && !this.data.stretchTo) {
      const { filePath, texture, sheet } = await this._file.getTexture();
      this._currentFilePath = filePath;
      this._texture = texture;
      this.spriteSheet = sheet;
    }
    if (this._isRangeFind && (this.data.stretchTo?.attachTo?.active || this.data.attachTo?.active)) {
      let sprite;
      let spriteType = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
      if (this.data.xray) {
        sprite = new spriteType(this._texture);
      } else {
        sprite = new spriteType(this._texture, VisionSamplerShader);
      }
      this._relatedSprites[this._currentFilePath] = sprite;
      new Promise(async (resolve) => {
        for (let filePath of this._file.getAllFiles()) {
          if (filePath === this._currentFilePath)
            continue;
          let texture = await this._file._getTexture(filePath);
          let sprite2;
          let spriteType2 = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
          if (this.data.xray) {
            sprite2 = new spriteType2(texture);
          } else {
            sprite2 = new spriteType2(texture, VisionSamplerShader);
          }
          sprite2.renderable = false;
          this._relatedSprites[filePath] = sprite2;
        }
        resolve();
      });
    }
    this._template = this._file.template ?? this._template;
    this.video = this._currentFilePath.toLowerCase().endsWith(".webm") ? this._texture?.baseTexture?.resource?.source : false;
  }
  /**
   * Calculates the duration of this effect, based on animation durations, the video source duration, end/start times, etc
   *
   * @private
   */
  _calculateDuration() {
    this._animationDuration = this.data.duration || this.mediaDuration * 1e3;
    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 ? 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 = this.mediaCurrentTime;
    }
    if (this.data.time?.end) {
      this._animationDuration = !this.data.time.end.isPerc ? this.data.time.isRange ? this.data.time.end.value - this.data.time.start.value : this._animationDuration - this.data.time.end.value : this._animationDuration * this.data.time.end.value;
    }
    this._endTime = this._animationDuration / 1e3;
    if (this._file?.markers && this._startTime === 0 && this._endTime === this.mediaDuration) {
      this._animationTimes.loopStart = this._file.markers.loop.start / 1e3;
      this._animationTimes.loopEnd = this._file.markers.loop.end / 1e3;
      this._animationTimes.forcedEnd = this._file.markers.forcedEnd / 1e3;
    }
    this._animationDuration /= this.data.playbackRate ?? 1;
    this._durationResolve(this._animationDuration);
    this.mediaLooping = this._animationDuration / 1e3 > this.mediaDuration && !this.data.noLoop;
    this.mediaPlaybackRate = this.data.playbackRate ? this.data.playbackRate : 1;
  }
  /**
   * 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() {
    setTimeout(
      () => {
        this._setupHooks();
      },
      this.data.animations ? 50 : 0
    );
  }
  /**
   * If this effect is attached to an object, check whether the object has been destroyed, if so, end the effect
   *
   * @private
   */
  _contextLostCallback() {
    if (this.isSourceTemporary) {
      this._ticker.add(() => {
        if (this.isSourceDestroyed) {
          this._ticker.stop();
          this._source = this.sourcePosition;
          SequencerEffectManager.endEffects({ effects: this });
        }
      });
    }
    if (this.isTargetTemporary) {
      this._ticker.add(() => {
        if (this.isTargetDestroyed) {
          this._ticker.stop();
          this._target = this.targetPosition;
          SequencerEffectManager.endEffects({ effects: this });
        }
      });
    }
  }
  /**
   * Creates the sprite, and the relevant containers that manage the position and offsets of the overall visual look of the sprite
   *
   * @private
   */
  _createSprite() {
    this.renderable = false;
    const args = [this.spriteSheet ? this.spriteSheet : null];
    if (!this.data.xray && !this.spriteSheet && !this.data.screenSpace && !this.data.screenSpaceAboveUI) {
      args.push(VisionSamplerShader);
    }
    const spriteType = this.spriteSheet ? PIXI.AnimatedSprite : SpriteMesh;
    const sprite = new spriteType(...args);
    this.sprite = this.spriteContainer.addChild(sprite);
    this.sprite.id = this.id + "-sprite";
    Object.values(this._relatedSprites).forEach((sprite2) => {
      this.sprite.addChild(sprite2);
    });
    this.animatedSprite = false;
    if (this.spriteSheet) {
      this.animatedSprite = true;
      this.sprite.animationSpeed = 0.4;
      this.sprite.loop = false;
    }
    let textSprite;
    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);
      textSprite = new PIXI.Text(text2, fontSettings);
      textSprite.resolution = 5;
      textSprite.zIndex = 1;
      textSprite.anchor.set(
        this.data.text?.anchor?.x ?? 0.5,
        this.data.text?.anchor?.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();
        this.sprite.filters.push(filter2);
        const filterKeyName = filterData.name || filterData.className;
        this.effectFilters[filterKeyName] = filter2;
      }
    }
    this.alphaFilter = new PIXI.filters.AlphaFilter(this.data.opacity);
    this.alphaFilter.id = this.id + "-alphaFilter";
    this.sprite.filters.push(this.alphaFilter);
    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
    );
    this.sprite.rotation = Math.normalizeRadians(
      Math.toRadians(this.data.spriteRotation ?? 0)
    );
    this._customAngle = this.data.angle ?? 0;
    if (this.data.randomRotation) {
      this._customAngle += random_float_between(-360, 360, this._twister);
    }
    this.spriteContainer.rotation = -Math.normalizeRadians(
      Math.toRadians(this._customAngle)
    );
    if (CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE) {
      this.isometricContainer.rotation = Math.PI / 4;
    }
    if (this.data.tint) {
      this.sprite.tint = this.data.tint;
    }
    if (textSprite) {
      if (this.data.tint) {
        textSprite.tint = this.data.tint;
      }
      this.sprite.addChild(textSprite);
    }
    if (this.shouldShowFadedVersion) {
      this.filters = [
        new PIXI.filters.ColorMatrixFilter({ saturation: -1 }),
        new PIXI.filters.AlphaFilter(
          game.settings.get(CONSTANTS.MODULE_NAME, "user-effect-opacity") / 100
        )
      ];
    }
    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-" + randomID()] = graphic;
    }
  }
  updateElevation() {
    const targetElevation = Math.max(
      get_object_elevation(this.source ?? {}),
      get_object_elevation(this.target ?? {})
    ) + 1;
    let effectElevation = this.data.elevation?.elevation ?? 0;
    if (!this.data.elevation?.absolute) {
      effectElevation += targetElevation;
    }
    const isIsometric = getProperty(
      game.scenes.get(this.data.sceneId),
      CONSTANTS.INTEGRATIONS.ISOMETRIC.SCENE_ENABLED
    );
    if (CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE && isIsometric) {
      const sourceSort = this.source ? this.sourceMesh.sort + (this.data.isometric?.overlay ? 1 : -1) : 0;
      const targetSort = this.target ? this.targetMesh.sort + (this.data.isometric?.overlay ? 1 : -1) : 0;
      this.sort = Math.max(sourceSort, targetSort);
    } else {
      this.sort = !is_real_number(this.data.zIndex) ? this.data.index + this.parent.children.length : 1e5 + this.data.zIndex;
    }
    this.elevation = effectElevation;
    this.parent.sortChildren();
  }
  updateTransform() {
    super.updateTransform();
    if (this.data.screenSpace || this.data.screenSpaceAboveUI) {
      const [screenWidth, screenHeight] = canvas.screenDimensions;
      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;
        if (scaleData.fitX) {
          scaleX = scaleX * (screenWidth / this.sprite.width);
        }
        if (scaleData.fitY) {
          scaleY = scaleY * (screenHeight / this.sprite.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;
    this.masksReady = false;
    this._maskContainer = new PIXI.Container();
    this._maskSprite = new PIXI.Sprite();
    this.parent.addChild(this._maskSprite);
    if (this.sprite) {
      this.sprite.mask = this._maskSprite;
    }
    const blurFilter = new filters.Blur({ strength: 2 });
    this._maskContainer.filters = [blurFilter];
    for (const uuid of this.data.masks) {
      const documentType = uuid.split(".")[2];
      const documentObj = await fromUuid(uuid);
      if (!documentObj || documentObj.parent !== this.sourceDocument.parent)
        continue;
      const placeableObject = documentObj.object;
      const objMaskSprite = documentType === "Token" || documentType === "Tile" ? new PIXI.Sprite() : new PIXI.Graphics();
      objMaskSprite.uuid = uuid;
      objMaskSprite.placeableObject = placeableObject;
      objMaskSprite.documentType = documentType;
      const clipFilter = new filters.Clip();
      const blurFilter2 = new filters.Blur({ strength: 1 });
      objMaskSprite.filters = [blurFilter2, clipFilter];
      const spriteContainer = new PIXI.Container();
      spriteContainer.addChild(objMaskSprite);
      spriteContainer.maskSprite = objMaskSprite;
      spriteContainer.exclude = false;
      this._maskContainer.addChild(spriteContainer);
      hooksManager.addHook(this.uuid, "delete" + documentType, (doc) => {
        if (doc !== documentObj)
          return;
        const mask = this._maskContainer.children.find(
          (mask2) => mask2.maskSprite.uuid === doc.uuid
        );
        if (!mask)
          return;
        mask.destroy();
        this._updateMaskSprite();
        if (!this._maskContainer.children.length) {
          if (this.sprite) {
            this.sprite.mask = null;
          }
        }
      });
      hooksManager.addHook(this.uuid, "update" + documentType, (doc) => {
        if (doc !== documentObj)
          return;
        const mask = this._maskContainer.children.find(
          (mask2) => mask2.maskSprite.uuid === doc.uuid
        );
        if (!mask)
          return;
        const changed = this._handleUpdatingMask(mask);
        if (changed)
          this._updateMaskSprite();
      });
    }
    let anyMaskChanged = false;
    for (const maskShape of maskShapes) {
      const graphic = createShape(maskShape);
      const clipFilter = new filters.Clip();
      const blurFilter2 = new filters.Blur({ strength: 1 });
      graphic.filters = [blurFilter2, clipFilter];
      const spriteContainer = new PIXI.Container();
      spriteContainer.addChild(graphic);
      spriteContainer.maskSprite = graphic;
      spriteContainer.exclude = true;
      this._maskContainer.addChild(spriteContainer);
      anyMaskChanged = true;
    }
    if (!this._maskContainer.children.length) {
      if (this.sprite) {
        this.sprite.mask = null;
      }
      return false;
    }
    this._ticker.add(() => {
      for (let container of this._maskContainer.children) {
        if (!container.exclude) {
          anyMaskChanged = anyMaskChanged || this._handleUpdatingMask(container);
        }
      }
      if (anyMaskChanged) {
        this._updateMaskSprite();
      }
    });
    this.masksReady = true;
  }
  _handleUpdatingMask(container) {
    const mask = container.maskSprite;
    let objectSprite;
    let objectWidth = 0;
    let objectHeight = 0;
    let additionalData = {
      walledmask: getProperty(
        mask.placeableObject,
        "flags.walledtemplates.enabled"
      )
    };
    try {
      if (mask.documentType === "Token") {
        objectSprite = mask.placeableObject.mesh;
        objectWidth = objectSprite.width / 2;
        objectHeight = objectSprite.height / 2;
        additionalData["img"] = mask.placeableObject.document.texture.src;
        additionalData["elevation"] = mask.placeableObject.document.elevation;
      } else if (mask.documentType === "Tile") {
        objectSprite = mask.placeableObject.mesh;
        objectWidth = objectSprite.width / 2;
        objectHeight = objectSprite.height / 2;
        additionalData["img"] = mask.placeableObject.document.texture.src;
      } else if (mask.documentType === "Drawing") {
        objectSprite = mask.placeableObject.shape;
      } else if (mask.documentType === "MeasuredTemplate") {
        objectSprite = mask.placeableObject.template;
        additionalData["direction"] = mask.placeableObject.direction;
        additionalData["distance"] = mask.placeableObject.distance;
        additionalData["angle"] = mask.placeableObject.angle;
        additionalData["width"] = mask.placeableObject.width;
      }
    } catch (err) {
      return false;
    }
    let position = {
      x: objectSprite.parent.x + objectSprite.x - objectWidth,
      y: objectSprite.parent.y + objectSprite.y - objectHeight
    };
    const angle = objectSprite.angle;
    const data = duplicate(additionalData);
    const noChange = container.position.x === position.x && container.position.y === position.y && mask.scale.x === objectSprite.scale.x && mask.scale.y === objectSprite.scale.y && mask.texture === objectSprite.texture && mask.angle === angle && foundry.utils.isEmpty(foundry.utils.diffObject(mask.oldData, data));
    if (noChange)
      return false;
    if (mask.documentType === "Drawing") {
      mask.clear();
      mask.beginFill(16777215, 1);
      const drawingType = mask.placeableObject.type;
      if (drawingType === CONST.DRAWING_TYPES.RECTANGLE) {
        mask.drawRect(
          objectSprite.width / -2,
          objectSprite.height / -2,
          objectSprite.width,
          objectSprite.height
        );
      } else if (drawingType === CONST.DRAWING_TYPES.ELLIPSE) {
        mask.drawEllipse(
          objectSprite.width / -2,
          objectSprite.height / -2,
          objectSprite.width / 2,
          objectSprite.height / 2
        );
      } else {
        const vertices = mask.placeableObject.points;
        if (drawingType === CONST.DRAWING_TYPES.FREEHAND) {
          let factor = mask.placeableObject.bezierFactor ?? 0.5;
          let last = vertices[vertices.length - 1];
          let isClosed = vertices[0].equals(last);
          mask.moveTo(...vertices[0]);
          if (vertices.length < 2)
            return;
          else if (vertices.length === 2) {
            mask.lineTo(...vertices[1]);
            return;
          }
          let [previous, point] = vertices.slice(0, 2);
          let cp0 = getBezierControlPoints(
            factor,
            last,
            previous,
            point
          ).next_cp0;
          let cp1, next_cp0, next;
          for (let i = 1; i < vertices.length; i++) {
            next = vertices[i + 1];
            if (next) {
              let bp = getBezierControlPoints(
                factor,
                previous,
                point,
                next
              );
              cp1 = bp.cp1;
              next_cp0 = bp.next_cp0;
            }
            if (i === 1 && !isClosed) {
              mask.quadraticCurveTo(cp1.x, cp1.y, point[0], point[1]);
            } else if (i === vertices.length - 1 && !isClosed) {
              mask.quadraticCurveTo(cp0.x, cp0.y, point[0], point[1]);
            } else {
              mask.bezierCurveTo(
                cp0.x,
                cp0.y,
                cp1.x,
                cp1.y,
                point[0],
                point[1]
              );
            }
            previous = point;
            point = next;
            cp0 = next_cp0;
          }
        } else {
          mask.moveTo(...vertices[0]);
          for (let i = 1; i < vertices.length; i++) {
            mask.lineTo(...vertices[i]);
          }
        }
      }
      mask.endFill();
    } else if (mask.documentType === "MeasuredTemplate") {
      mask.clear();
      mask.beginFill(16777215, 1);
      const shape = mask.placeableObject.shape.clone();
      mask.drawShape(shape);
    }
    mask.texture = objectSprite.texture;
    container.position.set(position.x, position.y);
    mask.scale.set(objectSprite.scale.x, objectSprite.scale.y);
    mask.angle = angle;
    mask.oldData = additionalData;
    if (mask instanceof PIXI.Sprite) {
      mask.anchor.set(0.5, 0.5);
      mask.position.set(mask.width / 2, mask.height / 2);
      if (CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE) {
        const elevation = game.settings.get(
          CONSTANTS.INTEGRATIONS.ISOMETRIC.MODULE_NAME,
          "token_elevation"
        ) && mask.placeableObject.document?.elevation ? canvas.scene.grid.distance / mask.placeableObject.document.elevation * mask.placeableObject.document.height : Infinity;
        const isometricType = getProperty(
          mask.placeableObject.document,
          CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_FLAG
        );
        switch (isometricType) {
          case CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_TYPES.TOPDOWN:
            break;
          case CONSTANTS.INTEGRATIONS.ISOMETRIC.PROJECTION_TYPES.DIAMETRIC:
            mask.anchor.set(0.5, 0.75 + 0.505 / elevation);
            break;
          default:
            mask.anchor.set(0.5, 0.69 + 0.63 / elevation);
            break;
        }
      }
    }
    return true;
  }
  _updateMaskSprite() {
    if (!this.masksReady)
      return;
    const smallestX = this._maskContainer.children.reduce((acc, container) => {
      let x;
      const bounds = container.getBounds();
      if (container.exclude) {
        x = this.x - bounds.width / 2 + container.maskSprite.offset.x;
      } else {
        x = bounds.x;
      }
      return acc >= x ? x : acc;
    }, Infinity);
    const smallestY = this._maskContainer.children.reduce((acc, container) => {
      let y;
      const bounds = container.getBounds(true);
      if (container.exclude) {
        y = this.y - bounds.height / 2 + container.maskSprite.offset.y;
      } else {
        y = bounds.y;
      }
      return acc >= y ? y : acc;
    }, Infinity);
    this._maskSprite.position.set(smallestX, smallestY);
    this._maskSprite.texture.destroy(true);
    this._maskSprite.texture = canvas.app.renderer.generateTexture(
      this._maskContainer
    );
  }
  /**
   * 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.data.attachTo?.bindVisibility) {
        hooksManager.addHook(
          this.uuid,
          "sightRefresh",
          () => {
            const sourceVisible = this.source && (this.sourceMesh?.visible ?? true);
            const sourceHidden = this.sourceDocument && (this.sourceDocument?.hidden ?? false);
            const targetVisible = this.target && (!attachedToTarget || (this.targetMesh?.visible ?? true));
            this.renderable = baseRenderable && (sourceVisible || targetVisible);
            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._cachedSourceData.alpha;
          }
          if (this.data.attachTo?.bindElevation) {
            this.updateElevation();
          }
        });
      }
      if (this.data.attachTo?.bindAlpha) {
        alpha = this._cachedSourceData.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);
      });
      hooksManager.addHook(this.uuid, this.getTargetHook("update"), (doc) => {
        if (doc !== this.target)
          return;
        this.updateElevation();
      });
    }
    for (let uuid of this.data?.tiedDocuments ?? []) {
      const tiedDocument = from_uuid_fast(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 distance
   * @returns {Object}
   * @private
   */
  async _getTextureForDistance(distance) {
    if (!this._distanceCache || this._distanceCache?.distance !== distance) {
      let scaleX = 1;
      let scaleY = 1;
      let texture;
      let filePath;
      let spriteAnchor = this.data.anchor?.x ?? 1;
      if (this._file instanceof SequencerFileBase) {
        const scaledDistance = distance / (this.data.scale.x ?? 1);
        const result = await this._file.getTexture(scaledDistance);
        filePath = result.filePath;
        texture = result.texture;
        spriteAnchor = result.spriteAnchor ?? this.data.anchor?.x ?? 0;
        scaleX = result.spriteScale;
        if (this.data.stretchTo?.onlyX) {
          const widthWithPadding = texture.width - (this.template.startPoint + this.template.endPoint);
          scaleY = widthWithPadding / texture.width;
        } else {
          scaleY = result.spriteScale;
        }
      } else if (this._file instanceof PIXI.Texture) {
        filePath = this.data.file;
        texture = this._file;
        spriteAnchor = this.template.startPoint / texture.width;
        const widthWithPadding = texture.width - (this.template.startPoint + this.template.endPoint);
        let spriteScale = distance / widthWithPadding;
        scaleX = spriteScale;
        if (this.data.stretchTo?.onlyX) {
          scaleY = widthWithPadding / texture.width;
        } else {
          scaleY = spriteScale;
        }
      }
      this._distanceCache = {
        filePath,
        texture,
        spriteAnchor,
        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);
    let { filePath, texture, spriteAnchor, scaleX, scaleY, distance } = await this._getTextureForDistance(ray.distance);
    if (this._currentFilePath !== filePath || !this._relatedSprites[filePath]) {
      this._texture = texture;
      this.video = filePath.toLowerCase().endsWith(".webm") ? texture?.baseTexture?.resource?.source ?? false : false;
      Object.values(this._relatedSprites).forEach((subsprite) => {
        subsprite.renderable = false;
      });
      this._currentFilePath = filePath;
      if (this._relatedSprites[filePath]) {
        this._relatedSprites[filePath].renderable = true;
      } else {
        let sprite;
        let spriteType = this.data.tilingTexture ? PIXI.TilingSprite : SpriteMesh;
        if (this.data.xray) {
          sprite = new spriteType(texture);
        } else {
          sprite = new spriteType(texture, VisionSamplerShader);
        }
        this._relatedSprites[filePath] = sprite;
        if (this.data.tint) {
          sprite.tint = this.data.tint;
        }
        this.sprite.addChild(sprite);
      }
    }
    try {
      this._relatedSprites[filePath].texture?.baseTexture?.resource?.source.play().then(() => {
        this._relatedSprites[filePath].texture.update();
      });
    } catch (err) {
    }
    if (this._relatedSprites[filePath]) {
      if (this.data.attachTo?.active) {
        this._applyAttachmentOffset();
      }
      const sprite = this._relatedSprites[filePath];
      if (!sprite.parent) {
        this.sprite.addChild(sprite);
      }
      if (this.data.tilingTexture) {
        const scaleX2 = (this.data.scale.x ?? 1) * this.gridSizeDifference;
        const scaleY2 = (this.data.scale.y ?? 1) * this.gridSizeDifference;
        sprite.width = distance / scaleX2;
        sprite.height = texture.height;
        sprite.scale.set(scaleX2 * this.flipX, scaleY2 * this.flipY);
        sprite.tileScale.x = this.data.tilingTexture.scale.x;
        sprite.tileScale.y = this.data.tilingTexture.scale.y;
        sprite.tilePosition = this.data.tilingTexture.position;
      } else {
        sprite.scale.set(
          scaleX * (this.data.scale.x ?? 1) * this.flipX,
          scaleY * (this.data.scale.y ?? 1) * this.flipY
        );
      }
      sprite.anchor.set(
        this.flipX === 1 ? spriteAnchor : 1 - spriteAnchor,
        this.data.anchor?.y ?? 0.5
      );
    }
  }
  /**
   * 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)
    );
    this._tweakRotationForIsometric();
  }
  _tweakRotationForIsometric() {
    if (!CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE)
      return;
    if (this.data.stretchTo) {
      let skew = Math.normalizeRadians(
        this.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;
      }
      this.isometricContainer.skew.set(Math.normalizeRadians(skew), 0);
      this.isometricContainer.rotation = 0;
    } else if (this.data?.isometric?.overlay) {
      this.rotationContainer.rotation = 0;
      let skew = Math.PI / 4 + this.rotationContainer.rotation;
      this.isometricContainer.skew.set(
        Math.normalizeRadians(skew - Math.PI / 4),
        0
      );
      this.isometricContainer.scale.set(
        1,
        window.scale ?? CONSTANTS.INTEGRATIONS.ISOMETRIC.ISOMETRIC_CONVERSION
      );
    } else {
      this.isometricContainer.rotation = 0;
    }
  }
  /**
   * Transforms the sprite, rotating it, stretching it, scaling it, sizing it according its data
   *
   * @private
   */
  async _transformSprite() {
    if (this.data.stretchTo) {
      if (this.data.stretchTo?.attachTo) {
        this._transformStretchToAttachedSprite();
      }
      await this._applyDistanceScaling();
    } else {
      if (!this.sprite?.texture?.valid && this._texture?.valid) {
        this.sprite.texture = this._texture;
      }
    }
    if (this.video && (this._startTime || this._loopOffset > 0) && this.video?.currentTime !== void 0) {
      await wait$1(20);
      this.sprite.texture.update();
    }
    if (!this.data.stretchTo) {
      this._transformNoStretchSprite();
    }
    if (this.data.attachTo?.active && !this.data.stretchTo?.attachTo) {
      await this._transformAttachedNoStretchSprite();
    } else {
      if (!this.data.screenSpace) {
        this.position.set(this.sourcePosition.x, this.sourcePosition.y);
      }
    }
    if (this.data.rotateTowards) {
      this._rotateTowards();
      if (this.data.rotateTowards?.attachTo) {
        this._transformRotateTowardsAttachedSprite();
      }
    }
    this._tweakRotationForIsometric();
    if (!this.data.anchor && this.data.rotateTowards) {
      const startPointRatio = this.template.startPoint / this._texture.width / 2;
      this.spriteContainer.pivot.set(
        this.sprite.width * (-0.5 + startPointRatio),
        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
        )
      );
    }
  }
  _transformStretchToAttachedSprite() {
    this._ticker.add(async () => {
      try {
        await this._applyDistanceScaling();
      } 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 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;
    const heightWidthRatio = this.sprite.height / this.sprite.width;
    const widthHeightRatio = this.sprite.width / this.sprite.height;
    const ratioToUse = heightWidthRatio > widthHeightRatio;
    if (this.data.scaleToObject) {
      let { width: width2, height } = this.target ? this.getTargetData() : this.getSourceData();
      const target = this.targetDocument || this.sourceDocument;
      if (target instanceof TokenDocument) {
        width2 *= this.data.scaleToObject?.considerTokenScale ? target.texture.scaleX : 1;
        height *= this.data.scaleToObject?.considerTokenScale ? target.texture.scaleY : 1;
      }
      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;
    } 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 {
      this.sprite.scale.set(
        baseScaleX * this.gridSizeDifference,
        baseScaleY * this.gridSizeDifference
      );
    }
  }
  async _transformAttachedNoStretchSprite() {
    const applyRotation = this.data.attachTo?.followRotation && !(this.sourceDocument instanceof TokenDocument && this.sourceDocument.lockRotation) && (this.sourceDocument?.rotation !== void 0 || this.sourceDocument?.direction !== void 0) && !this.data.rotateTowards && !this.data.stretchTo;
    this._ticker.add(() => {
      if (this.isDestroyed)
        return;
      if (applyRotation) {
        this.rotationContainer.rotation = this.getSourceData().rotation;
      }
      this._tweakRotationForIsometric();
      try {
        this._applyAttachmentOffset();
      } catch (err) {
        debug_error(err);
      }
    });
  }
  _applyAttachmentOffset() {
    let offset2 = { x: 0, y: 0 };
    if (this.data.attachTo?.align && this.data.attachTo?.align !== "center") {
      offset2 = align({
        context: this.source,
        spriteWidth: this.sprite.width,
        spriteHeight: this.sprite.height,
        align: this.data.attachTo?.align,
        edge: this.data.attachTo?.edge
      });
    }
    this.position.set(
      this.sourcePosition.x - offset2.x,
      this.sourcePosition.y - offset2.y
    );
  }
  _transformRotateTowardsAttachedSprite() {
    this._ticker.add(async () => {
      if (this.isDestroyed)
        return;
      try {
        this._rotateTowards();
      } 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.data.creationTimestamp
    );
  }
  _playAnimations(animations, timeDifference = 0) {
    let animationsToSend = [];
    const oneShotAnimations = animations.filter(
      (animation2) => !animation2.looping && !animation2.fromEnd
    );
    for (let animation2 of oneShotAnimations) {
      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 (["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) {
      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._animationDuration - 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.data.creationTimestamp + fadeIn.duration + fadeIn.delay) > 0) {
      return;
    }
    this.alphaFilter.alpha = 0;
    SequencerAnimationEngine.addAnimation(this.id, {
      target: this.alphaFilter,
      propertyName: "alpha",
      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.video)
      return 0;
    let fadeInAudio = this.data.fadeInAudio;
    if (this.actualCreationTime - (this.data.creationTimestamp + fadeInAudio.duration + fadeInAudio.delay) > 0)
      return;
    this.video.volume = 0;
    SequencerAnimationEngine.addAnimation(this.id, {
      target: this,
      propertyName: "video.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._animationDuration - fadeOut.duration + fadeOut.delay, 0);
    SequencerAnimationEngine.addAnimation(this.id, {
      target: this.alphaFilter,
      propertyName: "alpha",
      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.video)
      return 0;
    let fadeOutAudio = this.data.fadeOutAudio;
    fadeOutAudio.delay = is_real_number(immediate) ? Math.max(immediate - fadeOutAudio.duration + fadeOutAudio.delay, 0) : Math.max(
      this._animationDuration - fadeOutAudio.duration + fadeOutAudio.delay,
      0
    );
    SequencerAnimationEngine.addAnimation(this.id, {
      target: this,
      propertyName: "video.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.data.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._animationDuration - 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.data.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._animationDuration - 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._animationDuration;
    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.data.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
      },
      {
        target: this,
        propertyName: "position.y",
        to: this.targetPosition.y,
        duration,
        ease: moves2.ease,
        delay: moves2.delay
      }
    ]);
    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._animationDuration);
  }
  _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;
      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);
    }
  }
}
class PersistentCanvasEffect extends CanvasEffect {
  /**
   * @OVERRIDE
   * @returns {Promise<void>}
   * @private
   */
  async _initialize() {
    await super._initialize(false);
    await this._startEffect();
  }
  /**
   * @OVERRIDE
   * @returns {Promise<void>}
   * @private
   */
  async _reinitialize() {
    await super._reinitialize(false);
  }
  /** @OVERRIDE */
  _playPresetAnimations() {
    this._moveTowards();
    this._fadeIn();
    this._scaleIn();
    this._rotateIn();
  }
  /**
   * 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.actualCreationTime - this.data.creationTimestamp;
    if (!this.data.noLoop) {
      return this._startLoop(creationTimeDifference);
    }
    if (creationTimeDifference < this._animationDuration) {
      this.mediaCurrentTime = creationTimeDifference / 1e3;
      if (this._endTime !== this.mediaDuration) {
        setTimeout(() => {
          this.mediaCurrentTime = this._endTime;
          this.sprite.texture.update();
        }, this._endTime * 1e3 - creationTimeDifference);
      }
      await this.playMedia();
      return;
    }
    await this.pauseMedia();
    this.mediaCurrentTime = this._endTime;
    if (this.sprite.texture && this.video) {
      const oldRenderable = this.renderable;
      this.renderable = false;
      setTimeout(() => {
        this.renderable = oldRenderable;
        this.sprite.texture.update();
      }, 350);
    }
  }
  /**
   * Kicks off the loop, or just sets the video to loop
   *
   * @param creationTimeDifference
   * @returns {Promise<void>}
   * @private
   */
  async _startLoop(creationTimeDifference) {
    this.mediaLooping = this.playNaturally;
    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;
    }
    return this._resetLoop();
  }
  /**
   * Continuously reset the video to the right time so that the start and end time can be preserved
   *
   * @returns {Promise<void>}
   * @private
   */
  async _resetLoop(firstLoop = true) {
    if (this._ended)
      return;
    let loopWaitTime = 0;
    if (this._animationTimes.loopStart) {
      if (this._isEnding)
        return;
      this.mediaCurrentTime = (firstLoop ? 0 : this._animationTimes.loopStart) + (this._loopOffset > 0 ? this._loopOffset : 0);
      loopWaitTime = (this._animationTimes.loopEnd - this.mediaCurrentTime) * 1e3;
    } else {
      this.mediaCurrentTime = this._startTime + this._loopOffset;
      loopWaitTime = this._animationDuration - this._loopOffset * 1e3;
    }
    await this.playMedia();
    if (this.mediaLooping) {
      return;
    }
    this._resetTimeout = setTimeout(() => {
      if (this._ended)
        return;
      this._loopOffset = 0;
      this._resetLoop(false);
    }, loopWaitTime);
  }
  /** @OVERRIDE */
  _timeoutVisibility() {
    let creationTimeDifference = this.actualCreationTime - this.data.creationTimestamp;
    let timeout = creationTimeDifference === 0 && !this.data.animations ? 0 : 50;
    setTimeout(() => {
      this._setupHooks();
    }, timeout);
  }
  /** @OVERRIDE */
  _setEndTimeout() {
    let creationTimeDifference = this.actualCreationTime - this.data.creationTimestamp;
    if (!this.data.noLoop || creationTimeDifference >= this._animationDuration || !(this.hasAnimatedMedia || this.data.text))
      return;
    setTimeout(() => {
      this.pauseMedia();
    }, this._animationDuration);
  }
  /** @OVERRIDE */
  async endEffect() {
    if (this._isEnding)
      return;
    this._isEnding = true;
    let fullWaitDuration = 0;
    let extraEndDuration = this.data.extraEndDuration ?? 0;
    if (this._animationTimes?.forcedEnd) {
      this.mediaCurrentTime = this._animationTimes.forcedEnd;
      fullWaitDuration = (this.mediaDuration - (this._animationTimes?.forcedEnd ?? 0)) * 1e3;
    } else if (this._animationTimes?.loopEnd) {
      fullWaitDuration = (this.mediaDuration - this.mediaCurrentTime) * 1e3;
      this.mediaLooping = false;
      extraEndDuration = Math.max(extraEndDuration, fullWaitDuration);
    }
    const fromEndCustomAnimations = this._getFromEndCustomAnimations(extraEndDuration);
    const durations = [
      this._fadeOut(extraEndDuration),
      this._fadeOutAudio(extraEndDuration),
      this._scaleOut(extraEndDuration),
      this._rotateOut(extraEndDuration),
      this.data.extraEndDuration,
      fullWaitDuration,
      ...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.Graphics();
  graphic.beginFill(
    shape?.fillColor ?? 16777215,
    shape?.fillColor !== void 0 ? shape?.fillAlpha ?? 1 : 0
  );
  graphic.lineStyle(
    shape.lineSize ?? (shape?.lineColor !== void 0 ? 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, index) => {
          return new PIXI.Point(
            point[0] * sizeMultiplier + graphic.offset.x,
            point[1] * sizeMultiplier + graphic.offset.y
          );
        })
      );
      break;
  }
  graphic.alpha = shape.alpha ?? 1;
  graphic.endFill();
  return graphic;
}
function calculate_missed_position(source, target, twister) {
  const sourcePosition = get_object_position(source);
  if (!target) {
    const sourceDimensions = get_object_dimensions(source, true);
    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;
  let distance = ray.distance / canvas.grid.size - 1;
  let angle;
  if (distance < 1) {
    angle = twister.random() > 0.5 ? startRadians : endRadians;
  } else {
    distance = Math.max(Math.abs(distance - 15), 6);
    endRadians -= Math.PI / distance;
    startRadians += Math.PI / distance;
    angle = interpolate(startRadians, endRadians, twister.random());
  }
  let x = Math.cos(angle) * targetDimensions.width;
  let 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 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 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 Token) {
    pos = {
      x: obj.mesh.x,
      y: obj.mesh.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 ?? 0,
    y: pos.y ?? obj?.y ?? obj?.position?.y ?? obj?.position?._y ?? obj?.document?.y ?? obj?.document?.position?.y ?? 0
  };
  if (!is_real_number(pos.x) || !is_real_number(pos.y)) {
    return false;
  }
  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?.width ?? canvas.grid.size;
  let height = inObj?.hitArea?.height ?? inObj?.h ?? inObj?.shape?.height ?? (inObj?.shape?.radius ? inObj?.shape?.radius * 2 : void 0) ?? 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) {
  inObject = inObject?.object ?? inObject;
  return {
    ...get_object_position(inObject, { measure }),
    ...get_object_dimensions(inObject?.mesh ?? inObject?.tile ?? inObject),
    elevation: get_object_elevation(inObject),
    uuid: inObject?.document?.uuid ?? inObject?.uuid,
    cachedLocation: true
  };
}
function get_object_elevation(inObject) {
  return inObject?.document?.elevation ?? inObject?.elevation ?? 0;
}
function get_mouse_position(snapToGrid = false, gridSnap = 2) {
  const pos = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(
    canvas.app.stage
  );
  return !snapToGrid ? new PIXI.Point(pos.x, pos.y) : canvas.grid.getSnappedPosition(pos.x, pos.y, gridSnap);
}
function distance_between(p1, p2) {
  return new Ray(p1, p2).distance;
}
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 getBezierControlPoints(factor, previous, point, next) {
  let vector = { x: next[0] - previous[0], y: next[1] - previous[1] }, preDistance = Math.hypot(previous[0] - point[0], previous[1] - point[1]), postDistance = Math.hypot(next[0] - point[0], next[1] - point[1]), distance = preDistance + postDistance;
  let cp0d = distance === 0 ? 0 : factor * (preDistance / distance), cp1d = distance === 0 ? 0 : factor * (postDistance / distance);
  return {
    cp1: {
      x: point[0] - vector.x * cp0d,
      y: point[1] - vector.y * cp0d
    },
    next_cp0: {
      x: point[0] + vector.x * cp1d,
      y: point[1] + vector.y * cp1d
    }
  };
}
function rotateAroundPoint(cx, cy, x, y, angle) {
  let radians = Math.PI / 180 * angle, cos = Math.cos(radians), sin = Math.sin(radians), nx = cos * (x - cx) + sin * (y - cy) + cx, 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?.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,
    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
  };
}
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?.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
  };
}
const PlayerSettings = {
  file: {
    label: "SEQUENCER.Player.Option.File",
    store: writable$1(""),
    default: ""
  },
  scale: {
    label: "SEQUENCER.Player.Option.Scale",
    store: writable$1(1),
    default: 1
  },
  users: {
    label: "SEQUENCER.Player.Option.ForUsers",
    store: writable$1([]),
    default: []
  },
  belowTokens: {
    label: "SEQUENCER.Player.Option.BelowTokens",
    store: writable$1(false),
    default: false
  },
  snapToGrid: {
    label: "SEQUENCER.Player.Option.SnapToGrid",
    store: writable$1(false),
    default: false
  },
  rotation: {
    label: "SEQUENCER.Player.Option.Rotation",
    store: writable$1(0),
    default: 0
  },
  randomRotation: {
    label: "SEQUENCER.Player.Option.Randomize",
    store: writable$1(false),
    default: false
  },
  fadeIn: {
    label: "SEQUENCER.Player.Option.FadeIn",
    store: writable$1(0),
    default: 0
  },
  fadeOut: {
    label: "SEQUENCER.Player.Option.FadeOut",
    store: writable$1(0),
    default: 0
  },
  scaleIn: {
    label: "SEQUENCER.Player.Option.ScaleIn",
    store: writable$1(0),
    default: 0
  },
  scaleOut: {
    label: "SEQUENCER.Player.Option.ScaleOut",
    store: writable$1(0),
    default: 0
  },
  mirrorX: {
    label: "SEQUENCER.Player.Option.MirrorX",
    store: writable$1(false),
    default: false
  },
  mirrorY: {
    label: "SEQUENCER.Player.Option.MirrorY",
    store: writable$1(false),
    default: false
  },
  randomMirrorX: {
    label: "SEQUENCER.Player.Option.Randomize",
    store: writable$1(false),
    default: false
  },
  randomMirrorY: {
    label: "SEQUENCER.Player.Option.Randomize",
    store: writable$1(false),
    default: false
  },
  offsetX: {
    label: "SEQUENCER.Player.Option.OffsetX",
    store: writable$1(0),
    default: 0
  },
  offsetY: {
    label: "SEQUENCER.Player.Option.OffsetY",
    store: writable$1(0),
    default: 0
  },
  offsetGridUnits: {
    label: "SEQUENCER.Player.Option.GridUnits",
    store: writable$1(false),
    default: false
  },
  randomOffsetAmount: {
    label: "SEQUENCER.Player.Option.RandomOffset",
    store: writable$1(0),
    default: 0
  },
  randomOffset: {
    label: "SEQUENCER.Player.Option.Randomize",
    store: writable$1(false),
    default: false
  },
  preload: {
    label: "SEQUENCER.Player.Option.Preload",
    store: writable$1(false),
    default: false
  },
  moveTowards: {
    label: "SEQUENCER.Player.Option.DragBehavior",
    label_off: "SEQUENCER.Player.Option.DragStretch",
    label_on: "SEQUENCER.Player.Option.DragMove",
    store: writable$1(false),
    default: false
  },
  moveSpeed: {
    label: "SEQUENCER.Player.Option.MoveSpeed",
    store: writable$1(0),
    default: 0
  },
  attachTo: {
    label: "SEQUENCER.Player.Option.AttachTo",
    store: writable$1(false),
    default: false,
    callback: (e) => {
      EffectPlayer.sourceAttach = e.target.checked;
    }
  },
  stretchToAttach: {
    label: "SEQUENCER.Player.Option.StretchToAttach",
    store: writable$1(false),
    default: false,
    callback: (e) => {
      EffectPlayer.targetAttach = e.target.checked;
    }
  },
  persist: {
    label: "SEQUENCER.Player.Option.Persist",
    store: writable$1(false),
    default: false
  },
  repeat: {
    label: "SEQUENCER.Player.Option.Repeat",
    store: writable$1(false),
    default: false
  },
  repetitions: {
    label: "SEQUENCER.Player.Option.Repetitions",
    store: writable$1(1),
    default: 1
  },
  repeatDelayMin: {
    label: "SEQUENCER.Player.Option.DelayMin",
    store: writable$1(200),
    default: 200
  },
  repeatDelayMax: {
    label: "SEQUENCER.Player.Option.DelayMax",
    store: writable$1(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 = (name) => {
  const effectPresets = game.settings.get(
    CONSTANTS.MODULE_NAME,
    "effectPresets"
  );
  return PlayerSettings.import(effectPresets[name]);
};
PlayerSettings.savePreset = async (name) => {
  const newName = await promptNewPresetName(name);
  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 (name) => {
  const newName = await promptNewPresetName(name, 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 = (name) => {
  const effectPresets = game.settings.get(
    CONSTANTS.MODULE_NAME,
    "effectPresets"
  );
  delete effectPresets[name];
  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 name = html.find("#newPresetName").val();
            if (name === "" || !name) {
              name = false;
            }
            resolve(name);
          }
        },
        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(([name, preset]) => {
      if (preset?.version)
        return [name, 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 [name, 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;
      const hover = document.elementFromPoint(event.clientX, event.clientY);
      if (!hover || hover.id !== "board")
        return;
      if (!this.isLayerActive)
        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 === "play-effect";
  },
  /**
   * 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 === "select-effect";
  },
  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;
  }
};
const EffectEntry_svelte_svelte_type_style_lang = "";
function create_fragment$c(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-ese-1fyjvdk");
      attr(button, "type", "button");
      attr(div0, "class", "effect-text hover-text svelte-ese-1fyjvdk");
      attr(div1, "class", "effect hover-highlight svelte-ese-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 = "Unknown effect";
    if (effect2.data.file) {
      effectName = effect2.data.file.split("\\").pop().split("/").pop();
    } else if (effect2.data.text) {
      effectName = "Text: " + effect2.data.text.text;
    } else {
      effectName = "Shape: " + effect2.data.shapes[0].type;
    }
    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$c, safe_not_equal, { effect: 0 });
  }
}
const SoundEntry_svelte_svelte_type_style_lang = "";
function create_fragment$b(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-ese-1fyjvdk");
      attr(button, "type", "button");
      attr(div0, "class", "effect-text hover-text svelte-ese-1fyjvdk");
      attr(div1, "class", "effect hover-highlight svelte-ese-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() {
    SequencerAudioHelper$1.stop([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$b, safe_not_equal, { id: 2, sound: 0 });
  }
}
const Manager_svelte_svelte_type_style_lang = "";
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);
    },
    p: noop,
    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-ese-nc5j73");
      attr(button, "type", "button");
      attr(div, "class", "effects svelte-ese-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);
      if (detaching)
        detach(t1);
      if (detaching)
        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 = (
    /*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) {
        each_blocks[i].m(div, null);
      }
      current = true;
    },
    p(ctx2, dirty) {
      if (dirty & /*persistentEffects*/
      4) {
        each_value_2 = /*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);
      if (detaching)
        detach(t1);
      if (detaching)
        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 = (
    /*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) {
        each_blocks[i].m(div, null);
      }
      current = true;
    },
    p(ctx2, dirty) {
      if (dirty & /*temporaryEffects*/
      2) {
        each_value_1 = /*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);
      if (detaching)
        detach(t1);
      if (detaching)
        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 = (
    /*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-ese-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) {
        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 = /*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);
      if (detaching)
        detach(t1);
      if (detaching)
        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$a(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-ese-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) {
          if_block0.p(ctx2, dirty);
        } 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() {
    SequencerAudioHelper.stop(RunningSounds.keys());
  }
  $$self.$$.update = () => {
    if ($$self.$$.dirty & /*$VisibleEffects*/
    512) {
      $$invalidate(0, effects = Object.values($VisibleEffects));
    }
    if ($$self.$$.dirty & /*$RunningSounds*/
    256) {
      $$invalidate(3, sounds = Object.entries($RunningSounds));
    }
    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$a, safe_not_equal, {});
  }
}
const SliderInput_svelte_svelte_type_style_lang = "";
function create_fragment$9(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-ese-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-ese-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-ese-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$1(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$9, safe_not_equal, {
      setting: 0,
      lock: 10,
      min: 1,
      max: 2,
      maxInput: 3,
      step: 4,
      styles: 5
    });
  }
}
function create_fragment$8(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-" + randomID();
  const store = setting.store;
  component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
  const isLocked = lock ? lock.store : writable$1(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$8, safe_not_equal, {
      setting: 0,
      label: 8,
      lock: 9,
      inverse: 1,
      styles: 2
    });
  }
}
const NumberInput_svelte_svelte_type_style_lang = "";
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-ese-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$7(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-ese-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-" + randomID();
  const store = setting.store;
  component_subscribe($$self, store, (value) => $$invalidate(4, $store = value));
  const isLocked = lock ? lock.store : writable$1(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$7, safe_not_equal, {
      setting: 0,
      lock: 8,
      inverse: 1,
      styles: 2
    });
  }
}
const SwitchToggle_svelte_svelte_type_style_lang = "";
function create_fragment$6(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-ese-o0yoxs");
      toggle_class(div0, "active", !/*$store*/
      ctx[2]);
      attr(div1, "class", "second svelte-ese-o0yoxs");
      toggle_class(
        div1,
        "active",
        /*$store*/
        ctx[2]
      );
      set_style(div2, "display", "flex");
      set_style(div2, "align-items", "center");
      attr(div2, "class", "svelte-ese-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$6, safe_not_equal, { setting: 0, styles: 4 });
  }
}
const Player_svelte_svelte_type_style_lang = "";
function get_each_context$2(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[20] = list[i];
  return child_ctx;
}
function get_each_context_1(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[23] = list[i];
  return child_ctx;
}
function get_each_context_2(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[26] = list[i];
  return child_ctx;
}
function create_each_block_2(ctx) {
  let option;
  let t_value = (
    /*suggestion*/
    ctx[26] + ""
  );
  let t;
  let option_value_value;
  return {
    c() {
      option = element("option");
      t = text$1(t_value);
      option.__value = option_value_value = /*suggestion*/
      ctx[26];
      option.value = 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[26] + ""))
        set_data(t, t_value);
      if (dirty & /*suggestions*/
      2 && option_value_value !== (option_value_value = /*suggestion*/
      ctx2[26])) {
        option.__value = option_value_value;
        option.value = option.__value;
      }
    },
    d(detaching) {
      if (detaching)
        detach(option);
    }
  };
}
function create_each_block_1(key_1, ctx) {
  let option;
  let t_value = (
    /*user*/
    ctx[23].name + ""
  );
  let t;
  return {
    key: key_1,
    first: null,
    c() {
      option = element("option");
      t = text$1(t_value);
      option.__value = /*user*/
      ctx[23].id;
      option.value = 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[20] + ""
  );
  let t;
  return {
    c() {
      option = element("option");
      t = text$1(t_value);
      option.__value = /*preset*/
      ctx[20];
      option.value = option.__value;
    },
    m(target, anchor) {
      insert(target, option, anchor);
      append(option, t);
    },
    p: noop,
    d(detaching) {
      if (detaching)
        detach(option);
    }
  };
}
function create_fragment$5(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 = (
    /*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 = (
    /*users*/
    ctx[5]
  );
  const get_key = (ctx2) => (
    /*user*/
    ctx2[23].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 = (
    /*presets*/
    ctx[8]
  );
  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-ese-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-ese-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-ese-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-ese-1ipnpu1");
      attr(button1, "type", "button");
      attr(datalist, "id", "dblist");
      attr(div0, "class", "file-settings svelte-ese-1ipnpu1");
      attr(label, "for", "user-select");
      option0.selected = true;
      option0.__value = "all";
      option0.value = 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[11].call(select0)
        ));
      attr(div1, "class", "user-settings flexcol svelte-ese-1ipnpu1");
      attr(div2, "class", "row w-100");
      option1.__value = "default";
      option1.value = option1.__value;
      attr(select1, "class", "preset-select svelte-ese-1ipnpu1");
      if (
        /*selectedPreset*/
        ctx[2] === void 0
      )
        add_render_callback(() => (
          /*select1_change_handler*/
          ctx[12].call(select1)
        ));
      attr(button2, "class", "save-preset small-button svelte-ese-1ipnpu1");
      attr(button2, "data-tooltip", "Save Preset");
      attr(button2, "type", "button");
      attr(i2, "class", "fas fa-copy svelte-ese-1ipnpu1");
      attr(button3, "class", "copy-preset small-button svelte-ese-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-ese-1ipnpu1");
      attr(button4, "class", "delete-preset small-button svelte-ese-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-ese-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) {
        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) {
        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) {
        each_blocks[i].m(select1, null);
      }
      select_option(
        select1,
        /*selectedPreset*/
        ctx[2]
      );
      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[9]
          ),
          listen(
            input,
            "input",
            /*input_input_handler*/
            ctx[10]
          ),
          listen(
            button1,
            "click",
            /*handleClick*/
            ctx[7]
          ),
          listen(
            select0,
            "change",
            /*select0_change_handler*/
            ctx[11]
          ),
          listen(
            select1,
            "change",
            /*select1_change_handler*/
            ctx[12]
          ),
          listen(
            select1,
            "change",
            /*change_handler*/
            ctx[13]
          ),
          listen(
            button2,
            "click",
            /*click_handler_1*/
            ctx[14]
          ),
          listen(
            button3,
            "click",
            /*click_handler_2*/
            ctx[15]
          ),
          listen(
            button4,
            "click",
            /*click_handler_3*/
            ctx[16]
          )
        ];
        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 = /*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 = /*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*/
      256) {
        each_value = /*presets*/
        ctx2[8];
        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*/
      260) {
        select_option(
          select1,
          /*selectedPreset*/
          ctx2[2]
        );
      }
      if (!current || dirty & /*selectedPreset, presets*/
      260 && button3_disabled_value !== (button3_disabled_value = /*selectedPreset*/
      ctx2[2] === "default")) {
        button3.disabled = button3_disabled_value;
      }
      if (!current || dirty & /*selectedPreset, presets*/
      260 && 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 = "";
async function activateLayer() {
  ui.controls.initialize({
    control: "sequencer",
    tool: "play-effect"
  });
  canvas.sequencerInterfaceLayer.activate({ tool: "play-effect" });
}
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
  );
  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(8, 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,
    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$5, safe_not_equal, {});
  }
}
const SequenceStatus_svelte_svelte_type_style_lang = "";
function create_fragment$4(ctx) {
  let i0;
  let t;
  let i1;
  return {
    c() {
      i0 = element("i");
      t = space();
      i1 = element("i");
      attr(i0, "class", "fa-solid background-circle svelte-ese-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, CONSTANTS*/
      2) {
        toggle_class(
          i0,
          "invisible",
          /*$status*/
          ctx2[1] === CONSTANTS.STATUS.READY
        );
      }
      if (dirty & /*$status, CONSTANTS*/
      2) {
        toggle_class(
          i0,
          "fa-arrow-right",
          /*$status*/
          ctx2[1] === CONSTANTS.STATUS.RUNNING || /*$status*/
          ctx2[1] === CONSTANTS.STATUS.READY
        );
      }
      if (dirty & /*$status, CONSTANTS*/
      2) {
        toggle_class(
          i0,
          "fa-check",
          /*$status*/
          ctx2[1] === CONSTANTS.STATUS.COMPLETE
        );
      }
      if (dirty & /*$status, CONSTANTS*/
      2) {
        toggle_class(
          i0,
          "fa-arrow-down",
          /*$status*/
          ctx2[1] === CONSTANTS.STATUS.SKIPPED
        );
      }
      if (dirty & /*$status, CONSTANTS*/
      2) {
        toggle_class(
          i0,
          "fa-times",
          /*$status*/
          ctx2[1] === CONSTANTS.STATUS.ABORTED
        );
      }
    },
    i: noop,
    o: noop,
    d(detaching) {
      if (detaching)
        detach(i0);
      if (detaching)
        detach(t);
      if (detaching)
        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$4, safe_not_equal, { status: 0 });
  }
}
const SequenceSection_svelte_svelte_type_style_lang = "";
function create_fragment$3(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-ese-1ee9h3");
      attr(a, "class", "svelte-ese-1ee9h3");
      toggle_class(
        a,
        "section-done",
        /*$status*/
        ctx[1] > CONSTANTS.STATUS.READY
      );
      attr(span2, "class", "sequence-actions svelte-ese-1ee9h3");
      attr(span2, "data-tooltip", localize("SEQUENCER.Sequences.AbortSection"));
      attr(div, "class", "svelte-ese-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, CONSTANTS*/
      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$3, safe_not_equal, { section: 0 });
  }
}
const Sequence_svelte_svelte_type_style_lang = "";
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$2(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 i0;
  let t5;
  let a1;
  let i1;
  let t6;
  let each_1_anchor;
  let current;
  let mounted;
  let dispose;
  sequencestatus = new SequenceStatus({ props: { status: (
    /*status*/
    ctx[3]
  ) } });
  let each_value = (
    /*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");
      i0 = element("i");
      t5 = space();
      a1 = element("a");
      i1 = element("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-ese-1dcwqos");
      attr(i0, "class", "fas fa-trash-can");
      attr(a0, "class", "clear-sequence svelte-ese-1dcwqos");
      attr(a0, "data-tooltip", localize("SEQUENCER.Sequences.Clear"));
      toggle_class(
        a0,
        "sequence-done-show",
        /*$status*/
        ctx[2] > CONSTANTS.STATUS.RUNNING
      );
      attr(i1, "class", "fas fa-stop");
      attr(a1, "data-tooltip", localize("SEQUENCER.Sequences.AbortSequence"));
      attr(a1, "class", "svelte-ese-1dcwqos");
      toggle_class(
        a1,
        "sequence-done-hide",
        /*$status*/
        ctx[2] > CONSTANTS.STATUS.RUNNING
      );
      attr(span2, "class", "sequence-actions svelte-ese-1dcwqos");
      attr(div, "class", "sequence-name-container svelte-ese-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(a0, i0);
      append(span2, t5);
      append(span2, a1);
      append(a1, i1);
      insert(target, t6, anchor);
      for (let i = 0; i < each_blocks.length; i += 1) {
        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, CONSTANTS*/
      4) {
        toggle_class(
          a0,
          "sequence-done-show",
          /*$status*/
          ctx2[2] > CONSTANTS.STATUS.RUNNING
        );
      }
      if (!current || dirty & /*$status, CONSTANTS*/
      4) {
        toggle_class(
          a1,
          "sequence-done-hide",
          /*$status*/
          ctx2[2] > CONSTANTS.STATUS.RUNNING
        );
      }
      if (dirty & /*sequence*/
      1) {
        each_value = /*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);
      destroy_component(sequencestatus);
      if (detaching)
        detach(t6);
      destroy_each(each_blocks, detaching);
      if (detaching)
        detach(each_1_anchor);
      mounted = false;
      run_all(dispose);
    }
  };
}
function instance$2($$self, $$props, $$invalidate) {
  let $status;
  let { sequence } = $$props;
  let { index } = $$props;
  const status = sequence.status;
  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 Sequence2 extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, instance$2, create_fragment$2, safe_not_equal, { sequence: 0, index: 1 });
  }
};
const Sequences_svelte_svelte_type_style_lang = "";
function get_each_context(ctx, list, i) {
  const child_ctx = ctx.slice();
  child_ctx[7] = list[i][0];
  child_ctx[8] = list[i][1];
  child_ctx[10] = 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 = (
    /*runningSequences*/
    ctx[0]
  );
  const get_key = (ctx2) => (
    /*id*/
    ctx2[7]
  );
  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-ese-1ismzan");
      attr(button1, "type", "button");
      attr(button1, "class", "svelte-ese-1ismzan");
      attr(div0, "class", "sequence-button-header svelte-ese-1ismzan");
      attr(div1, "class", "running-sequences svelte-ese-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) {
        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 = /*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);
      if (detaching)
        detach(t3);
      if (detaching)
        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;
  let current;
  sequence = new Sequence$2({
    props: {
      sequence: (
        /*sequence*/
        ctx[8]
      ),
      index: (
        /*index*/
        ctx[10] + 1
      )
    }
  });
  return {
    key: key_1,
    first: null,
    c() {
      first = empty();
      create_component(sequence.$$.fragment);
      this.first = first;
    },
    m(target, anchor) {
      insert(target, first, anchor);
      mount_component(sequence, target, anchor);
      current = true;
    },
    p(new_ctx, dirty) {
      ctx = new_ctx;
      const sequence_changes = {};
      if (dirty & /*runningSequences*/
      1)
        sequence_changes.sequence = /*sequence*/
        ctx[8];
      if (dirty & /*runningSequences*/
      1)
        sequence_changes.index = /*index*/
        ctx[10] + 1;
      sequence.$set(sequence_changes);
    },
    i(local) {
      if (current)
        return;
      transition_in(sequence.$$.fragment, local);
      current = true;
    },
    o(local) {
      transition_out(sequence.$$.fragment, local);
      current = false;
    },
    d(detaching) {
      if (detaching)
        detach(first);
      destroy_component(sequence, detaching);
    }
  };
}
function create_fragment$1(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-ese-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));
  onDestroy(() => {
    SequenceManager.RunningSequences.clearFinishedSequences();
  });
  const click_handler = () => {
    SequenceManager.RunningSequences.clearFinishedSequences();
  };
  const click_handler_1 = () => {
    SequenceManager.RunningSequences.stopAll();
  };
  $$self.$$.update = () => {
    if ($$self.$$.dirty & /*$RunningSequences*/
    4) {
      Object.values($RunningSequences);
    }
    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$1, 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) {
    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 (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) {
      destroy_component(tabs_1, detaching);
      if (detaching)
        detach(t);
      if (detaching)
        detach(switch_instance_anchor);
      if (switch_instance)
        destroy_component(switch_instance, detaching);
    }
  };
}
function create_fragment(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, safe_not_equal, { elementRoot: 0 });
  }
  get elementRoot() {
    return this.$$.ctx[0];
  }
  set elementRoot(elementRoot) {
    this.$$set({ elementRoot });
    flush();
  }
}
class EffectsUIApp extends SvelteApplication {
  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-pixi-fix", {
    name: "SEQUENCER.Setting.EnablePixiFix.Title",
    hint: "SEQUENCER.Setting.EnablePixiFix.Label",
    scope: "client",
    config: true,
    default: true,
    requiresReload: true,
    type: Boolean
  });
  game.settings.register(CONSTANTS.MODULE_NAME, "enable-global-pixi-fix", {
    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
  });
  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 selectTool = {
      icon: "fas fa-expand",
      name: "select-effect",
      title: "SEQUENCER.SidebarButtons.Select",
      visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools")
    };
    const playTool = {
      icon: "fas fa-play",
      name: "play-effect",
      title: "SEQUENCER.SidebarButtons.Play",
      visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
      onClick: () => {
        EffectsUIApp.show({ inFocus: true, tab: "player" });
      }
    };
    const viewer = {
      icon: "fas fa-film",
      name: "effectviewer",
      title: "SEQUENCER.SidebarButtons.Manager",
      button: true,
      visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
      onClick: () => {
        EffectsUIApp.show({ inFocus: true, tab: "manager" });
      }
    };
    const database = {
      icon: "fas fa-database",
      name: "effectdatabase",
      title: "SEQUENCER.SidebarButtons.Database",
      button: true,
      visible: user_can_do("permissions-sidebar-tools"),
      onClick: () => {
        DatabaseViewerApp.show();
      }
    };
    controls.push({
      name: CONSTANTS.MODULE_NAME,
      title: "Sequencer Layer",
      icon: "fas fa-list-ol",
      layer: "sequencerInterfaceLayer",
      visible: user_can_do("permissions-effect-create") && user_can_do("permissions-sidebar-tools"),
      activeTool: "select-effect",
      tools: [selectTool, playTool, database, viewer]
    });
    if (!game.settings.get(CONSTANTS.MODULE_NAME, "showTokenSidebarTools"))
      return;
    const bar = controls.find((c) => c.name === "token");
    bar.tools.push(database);
    bar.tools.push(viewer);
  });
  console.log("Sequencer | Registered settings");
}
async function migrateSettings() {
  const oldPixiFixSetting = game.settings.storage.get("client").getItem("sequencer.disable-pixi-fix");
  if (oldPixiFixSetting) {
    const value = oldPixiFixSetting === "true";
    game.settings.storage.get("client").removeItem("sequencer.disable-pixi-fix");
    await game.settings.set(CONSTANTS.MODULE_NAME, "enable-pixi-fix", !value);
  }
  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(Canvas.layers, {
    sequencerEffects: {
      layerClass: BaseEffectsLayer,
      group: "primary"
    },
    sequencerInterfaceLayer: {
      layerClass: SequencerInterfaceLayer,
      group: "interface"
    },
    sequencerEffectsUILayer: {
      layerClass: UIEffectsLayer,
      group: "interface"
    }
  });
  if (!Object.is(Canvas.layers, CONFIG.Canvas.layers)) {
    const layers = Canvas.layers;
    Object.defineProperty(Canvas, "layers", {
      get: function() {
        return foundry.utils.mergeObject(layers, CONFIG.Canvas.layers);
      }
    });
  }
  console.log("Sequencer | Registered Layers");
}
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);
    },
    attachToUp: () => {
      if (!hotkeys._ready)
        return;
      PlayerSettings.attachTo.store.set(false);
      PlayerSettings.stretchToAttach.store.set(false);
    }
  },
  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);
    console.log(`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
   * @returns {Function}
   */
  static get(name) {
    return presetMap.get(name);
  }
}
class Section {
  constructor(inSequence) {
    this.sequence = inSequence;
    this._applyTraits();
    this._sectionStatus = writable$1(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.fromEnd   - makes this animation play from the end, like fadeOut, scaleOut, etc
   *
   * @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
   *
   * @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,
  _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,
  /**
   * 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;
  },
  /**
   * 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,
  /**
   *  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 (!(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"
      );
    this._temporaryEffect = this._temporaryEffect || (inLocation instanceof foundry.abstract.Document ? !is_UUID(inLocation?.uuid) : false);
    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) : 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 traits = {
  animation,
  audio,
  files,
  moves,
  opacity,
  rotation,
  scale,
  time,
  users,
  filter,
  tint,
  location,
  offset,
  text
};
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._from = null;
    this._origin = 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._name = null;
    this._zIndex = null;
    this._offset = null;
    this._spriteOffset = null;
    this._size = null;
    this._persist = null;
    this._persistOptions = null;
    this._zeroSpriteRotation = null;
    this._extraEndDuration = null;
    this._noLoop = 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._masks = [];
    this._tiedDocuments = [];
    this._selfMask = false;
    this._temporaryEffect = false;
    this._spriteRotation = 0;
    this._isRangedEffect = null;
    this._offsetLegacy = null;
    this._randomOffsetLegacy = null;
    this._aboveLighting = 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's position to be stored and can then be used  with .atLocation(), .stretchTowards(),
   * and .rotateTowards() to refer to previous effects' locations
   *
   * @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;
  }
  /**
   * 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: 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;
  }
  /**
   * 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 (!(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,
        followRotation: 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"
      );
    let isValidObject = true;
    if (typeof inObject === "string") {
      isValidObject = validatedObject instanceof Token || validatedObject instanceof TokenDocument || validatedObject instanceof Tile || validatedObject instanceof TileDocument || validatedObject instanceof Drawing || validatedObject instanceof DrawingDocument || validatedObject instanceof MeasuredTemplate || validatedObject instanceof MeasuredTemplateDocument || validatedObject instanceof CanvasEffect;
      if (!isValidObject) {
        this.sequence._showWarning(
          this,
          "attachTo",
          "Only Tokens, Tiles, Drawings, and MeasuredTemplates may have attached effects - will play effect on target's location"
        );
      }
    }
    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 (typeof inOptions.followRotation !== "boolean")
      throw this.sequence._customError(
        this,
        "attachTo",
        `inOptions.followRotation 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.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;
    this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document || validatedObject instanceof MeasuredTemplate ? !is_UUID(validatedObject?.uuid) : false);
    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: isValidObject,
      align: inOptions.align,
      edge: inOptions.edge,
      bindVisibility: inOptions.bindVisibility,
      bindAlpha: inOptions.bindAlpha,
      bindElevation: inOptions.bindElevation,
      followRotation: inOptions.followRotation
    };
    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 (!(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
      },
      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 (inOptions.tiling)
      this.tilingTexture();
    this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document ? !is_UUID(validatedObject?.uuid) : false);
    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 }) : validatedObject,
      attachTo: inOptions.attachTo,
      onlyX: inOptions.onlyX
    };
    return this;
  }
  /**
   * Sets the location to rotate the object to
   *
   * @param {object|string} inLocation
   * @param {object} inOptions
   * @returns this
   */
  rotateTowards(inLocation, inOptions = {}) {
    if (!(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
      },
      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"
      );
    this._temporaryEffect = this._temporaryEffect || (validatedObject instanceof foundry.abstract.Document ? !is_UUID(validatedObject?.uuid) : false);
    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._rotateTowards = {
      target: inOptions.cacheLocation ? get_object_canvas_data(validatedObject, { measure: true }) : validatedObject,
      rotationOffset: inOptions.rotationOffset,
      cacheLocation: inOptions.cacheLocation,
      attachTo: inOptions.attachTo
    };
    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.
   *
   * @param {Object} inObject
   * @param {Object} inOptions
   * @returns {EffectSection}
   */
  from(inObject, inOptions = {}) {
    if (!(inObject instanceof Token || inObject instanceof Tile || inObject instanceof TokenDocument || inObject instanceof TileDocument)) {
      throw this.sequence._customError(
        this,
        "from",
        "inObject must be of type Token, Tile, TokenDocument, or TileDocument"
      );
    }
    if (typeof inOptions !== "object")
      throw this.sequence._customError(
        this,
        "from",
        `inOptions must be of type object`
      );
    inObject = inObject.document ?? inObject;
    if (!inObject?.texture?.src)
      throw this.sequence._customError(
        this,
        "from",
        "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,
        "from",
        "inOptions.cacheLocation must be of type boolean"
      );
    if (!(typeof inOptions.randomOffset === "boolean" || is_real_number(inOptions.randomOffset)))
      throw this.sequence._customError(
        this,
        "from",
        "inOptions.randomOffset must be of type boolean or number"
      );
    this._temporaryEffect = this._temporaryEffect || (inObject instanceof foundry.abstract.Document ? !is_UUID(inObject?.uuid) : false);
    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._from = {
      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.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 to be offset relative to its location based on a given vector
   *
   * @param {Object} inOffset
   * @param {Object} inOptions
   * @returns {EffectSection}
   */
  offset(inOffset, inOptions = {}) {
    this.sequence._showWarning(
      this,
      "offset",
      "This method is becoming deprecated, please use the secondary offset option in atLocation, attachTo, stretchTo instead.",
      true
    );
    if (inOffset === void 0)
      throw this.sequence._customError(
        this,
        "offset",
        "inOffset must not be undefined"
      );
    if (typeof inOptions !== "object")
      throw this.sequence._customError(
        this,
        "offset",
        "options must be of type object"
      );
    this._offsetLegacy = this._validateOffset("offset", inOffset, inOptions);
    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.uniform !== "boolean")
      throw this.sequence._customError(
        this,
        "scaleToObject",
        "inBool 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 random offset on its target location, usually within the object's bounds. The optional parameter
   * scales how much offset should be added. Defaults to 1.0, which covers the entire target position, 0.5 would cover half.
   *
   * @param {Number} inOffsetScale
   * @returns {EffectSection}
   */
  randomOffset(inOffsetScale = 1) {
    this.sequence._showWarning(
      this,
      "randomOffset",
      "This method has been deprecated, please use randomOffset as a second parameter on atLocation, stretchTo, etc.",
      true
    );
    if (!is_real_number(inOffsetScale))
      throw this.sequence._customError(
        this,
        "randomOffset",
        "inBool must be of type number"
      );
    this._randomOffsetLegacy = inOffsetScale;
    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 (!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 (!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;
    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;
  }
  /**
   * Sets the zIndex of the effect, potentially displaying it on top of other effects the same elevation
   *
   * @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;
  }
  /**
   * 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;
  }
  /**
   * If the effect would loop due to its duration or persistence, this causes it not to
   *
   * @param {Boolean} [inBool=true] inBool
   * @returns {EffectSection}
   */
  noLoop(inBool = true) {
    if (typeof inBool !== "boolean")
      throw this.sequence._customError(
        this,
        "noLoop",
        "inBool must be of type boolean"
      );
    this._noLoop = inBool;
    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;
  }
  /**
   *  This is for adding extra information to an effect, like the origin of the effect 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;
  }
  /**
   * 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 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 = from_uuid_fast(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;
  }
  /**
   * 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() {
    if (this._from) {
      this._file = this._file || this._from.object?.texture?.src;
      if (this._source === null) {
        this._source = this._validateLocation(this._from.object);
      }
      if (this._size === null) {
        const size = get_object_dimensions(this._from.object);
        this._size = {
          width: size?.width ?? canvas.grid.size,
          height: size?.height ?? canvas.grid.size,
          gridUnits: false
        };
      }
      if (this._mirrorX === null && (this._from.object.mirrorX || this._from.object?.tile && this._from.object?.tile.scale.x < 0)) {
        this._mirrorX = true;
      }
      if (this._mirrorY === null && (this._from.object.mirrorY || this._from.object?.tile && this._from.object?.tile.scale.y < 0)) {
        this._mirrorY = true;
      }
      if (this._angle === null && this._from.object?.rotation) {
        this._angle = -this._from.object.rotation;
      }
      this._randomOffset = {
        source: this._randomOffset?.source ?? this._from.options.randomOffset,
        target: this._randomOffset?.target ?? false
      };
    }
  }
  /**
   * @OVERRIDE
   * @returns {Promise<void>}
   */
  async run() {
    if (!user_can_do("permissions-effect-create") || !this._playEffect) {
      if (!user_can_do("permissions-effect-create")) {
        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);
  }
  /**
   * @private
   */
  async _initialize() {
    if (this._name) {
      if (!this.sequence.nameOffsetMap) {
        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}-${randomID()}`,
          source,
          target,
          randomOffset: this._randomOffset,
          missed: this._missed,
          offset: this._offset,
          repetitions: this._repetitions,
          twister: {}
        };
      }
    }
    if (!this._file && !this._from && !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?.cachedLocation) {
      return get_object_canvas_data(this._source);
    }
    return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
  }
  /**
   * @private
   */
  _getTargetObject() {
    if (!this._target?.target)
      return this._target;
    if (typeof this._target.target !== "object")
      return this._target.target;
    if (this._target?.target?.cachedLocation) {
      return get_object_canvas_data(this._target.target, true);
    }
    return get_object_identifier(this._target.target) ?? get_object_canvas_data(this._target.target, true);
  }
  /**
   * @private
   */
  async _sanitizeEffectData() {
    if (this._deserializedData) {
      this._deserializedData.creationTimestamp = +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
    };
    const source = this._getSourceObject();
    const target = this._getTargetObject();
    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)
      );
    }
    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: randomID(),
      flagVersion: flagManager.latestFlagVersion,
      sequenceId: this.sequence.id,
      creationTimestamp: +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
      } : 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,
      text: this._text,
      tilingTexture: this._tilingTexture,
      masks: Array.from(new Set(this._masks)),
      shapes: this._shapes,
      volume: this._volume,
      isometric: this._isometric,
      // 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,
      aboveLighting: this._aboveLighting,
      xray: this._xray,
      // Appearance
      zIndex: this._zIndex,
      opacity: is_real_number(this._opacity) ? this._opacity : 1,
      filters: this._filters,
      noLoop: this._noLoop,
      spriteRotation: this._spriteRotation,
      tint: this._tint?.decimal,
      flipX: this._mirrorX || this._randomMirrorX && Math.random() < 0.5,
      flipY: this._mirrorY || this._randomMirrorY && Math.random() < 0.5,
      /**
       * 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._overrides = [];
  }
  static niceName = "Sound";
  /**
   * 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;
  }
  /**
   * @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);
  }
  /**
   * @OVERRIDE
   * @returns {Promise}
   */
  async run() {
    const playData = await this._sanitizeSoundData();
    if (!playData.play && this.sequence.softFail) {
      return new Promise((reject2) => {
        reject2();
      });
    }
    if (!playData?.play) {
      this.sequence._customError(
        this,
        "Play",
        `File not found: ${playData.src}`
      );
      return new Promise((reject2) => reject2());
    }
    if (Hooks.call("preCreateSequencerSound", playData) === false)
      return;
    let push = !(playData?.users?.length === 1 && playData?.users?.includes(game.userId)) && !this.sequence.localOnly;
    SequencerAudioHelper$1.play(playData, push);
    await new Promise(
      (resolve) => setTimeout(resolve, this._currentWaitTime + playData.duration)
    );
  }
  /**
   * @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 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: randomID(),
      play: true,
      src: file,
      loop: this._duration > duration,
      volume: this._volume,
      fadeIn: this._fadeInAudio,
      fadeOut: this._fadeOutAudio,
      startTime,
      duration: this._duration || duration,
      sceneId: game.user.viewedScene,
      users: this._users ? Array.from(this._users) : null
    };
    for (let override of this._overrides) {
      data = await override(this, data);
    }
    if (typeof data.src !== "string" || data.src === "") {
      throw this.sequence._customError(
        this,
        "file",
        "a sound must have a src of type string!"
      );
    }
    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 {
  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);
  }
  static niceName = "Animation";
  /**
   * 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 }
    );
  }
  /**
   * @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 () => {
        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;
    }
    return {
      x: originLoc.x + dx,
      y: originLoc.y + dy
    };
  }
  /**
   * @private
   */
  _snapLocationToGrid(inLocation) {
    return canvas.grid.getSnappedPosition(inLocation.x, inLocation.y);
  }
  /**
   * This needs a rewrite, jeesus.
   */
  async _runAnimate() {
    let animData = {
      attributes: [],
      maxFPS: 1e3 / game.settings.get("core", "maxFPS"),
      lastTimespan: performance.now(),
      totalDt: 0
    };
    let overallDuration = this._duration ? this._duration : 0;
    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 = this._snapLocationToGrid(targetLoc);
      }
      if (this._originObject instanceof TokenDocument) {
        setTimeout(async () => {
          let target = this._rotateTowards.target?.object ?? this._rotateTowards.target;
          if (this._rotateTowards.towardsCenter) {
            target = target?.center ?? target;
          }
          let ray = new Ray(targetLoc, target);
          let angle = ray.angle * 180 / Math.PI - 90;
          angle += offset2;
          await this._updateObject(
            this._originObject,
            { rotation: angle },
            this._rotateTowards.duration > 0,
            {
              duration: this._rotateTowards.duration,
              easing: this._rotateTowards.ease
            }
          );
        }, 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,
            easing: this._rotateIn.ease
          });
        }, 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 originLocation = 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 = this._snapLocationToGrid(targetLocation);
      }
      let originalDx = targetLocation.x - originLocation.x;
      let originalDy = targetLocation.y - originLocation.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,
            easing: this._moveTowards.ease
          });
        }, this._moveTowards.delay ?? 0);
      } else {
        if (!(duration === 0 || originalDistance === 0)) {
          animData.attributes.push({
            name: "position",
            origin: originLocation,
            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,
            easing: this._fadeOut.ease
          });
        }, 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,
            easing: this._rotateOut.ease
          });
        }, 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
        });
        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 = this._snapLocationToGrid(targetLocation);
        }
        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["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(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] || 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 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;
    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 ?? "",
      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._seed = get_hash(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;
  }
  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;
    return get_object_identifier(this._source) ?? get_object_canvas_data(this._source);
  }
  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
    };
  }
  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);
  }
}
let Sequence$1 = class Sequence3 {
  constructor(options = {
    moduleName: "Sequencer",
    softFail: false
  }, softFail = false) {
    this.id = randomID();
    this.moduleName = typeof options === "string" ? options : options?.moduleName ?? "Sequencer";
    this.softFail = options?.softFail ?? softFail;
    this.sections = [];
    this.nameOffsetMap = false;
    this.effectIndex = 0;
    this.sectionToCreate = void 0;
    this.localOnly = false;
    this._status = writable$1(CONSTANTS.STATUS.READY);
    return sequence_proxy_wrap(this);
  }
  /**
   * Plays all of this sequence's sections
   *
   * @returns {Promise}
   */
  async play({ remote = false } = {}) {
    if (remote) {
      this.localOnly = true;
      const data = await this.toJSON();
      sequencerSocket.executeForOthers(
        SOCKET_HANDLERS.RUN_SEQUENCE_LOCALLY,
        data
      );
      return new Sequence3().fromJSON(data).play();
    }
    Hooks.callAll("createSequencerSequence", this);
    debug("Initializing sections");
    for (let section of this.sections) {
      await section._initialize();
    }
    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 (get_store_value(this.status) === CONSTANTS.STATUS.ABORTED) {
        continue;
      }
      if (!section._isLastSection) {
        await new Promise((resolve) => setTimeout(resolve, 1));
      }
    }
    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 {*} 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`
      );
    }
    if (args && args.length && !game.modules.get("advanced-macros")?.active) {
      custom_warning(
        this.moduleName,
        `macro - Supplying macros with arguments require the advanced-macros module to be active`,
        true
      );
    }
    const func2 = section_proxy_wrap(
      new FunctionSection(
        this,
        async () => {
          if (compendium) {
            const macroData = (await compendium.getDocuments()).find((i) => i.name === macro[3])?.toObject();
            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_PERMISSION_LEVELS.OWNER;
          }
          const version = game.modules.get("advanced-macros")?.version;
          const bugAdvancedMacros = game.modules.get("advanced-macros")?.active && isNewerVersion(
            version.startsWith("v") ? version.slice(1) : version,
            "1.18.2"
          ) && !isNewerVersion(
            version.startsWith("v") ? version.slice(1) : version,
            "1.19.1"
          );
          if (bugAdvancedMacros) {
            await macro.execute([...args]);
          } else {
            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;
  }
  /**
   * 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;
    }
    return preset(this, ...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 Sequence3)) {
      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) {
    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 this._status;
  }
  _abort() {
    this.status = CONSTANTS.STATUS.ABORTED;
    for (const section of this.sections) {
      section._abortSection();
    }
  }
};
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;
      for (let src of inSrcs) {
        const blob = await SequencerFileCache.loadFile(src, true);
        if (showProgressBar)
          LoadingBar.incrementProgress();
        if (!blob) {
          numFilesFailedToLoad++;
        }
      }
      const timeTaken = (performance.now() - startTime) / 1e3;
      let failedToLoad = ` (${numFilesFailedToLoad} failed to load)`;
      debug(
        `Preloading ${numFilesToLoad} files took ${timeTaken}s` + failedToLoad
      );
      resolve(numFilesFailedToLoad);
    });
  }
};
class SequencerSectionManager {
  constructor() {
    this.externalSections = {};
  }
  /**
   * 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.externalSections[inMethodName] && !overwrite) {
      throw custom_error(
        inModuleName,
        `${inMethodName} is already a registered Section with the class ${this.externalSections[inMethodName].constructor.name}`
      );
    }
    coreMethods = coreMethods.concat(Object.keys(this.externalSections));
    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.externalSections[inMethodName] = inClass;
    return true;
  }
}
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() {
  const override = isNewerVersion(game.version, "11") ? "PIXI.BaseImageResource.prototype.upload" : "PIXI.resources.BaseImageResource.prototype.upload";
  libWrapper.register(CONSTANTS.MODULE_NAME, override, PIXIUPLOAD);
}
function PIXIUPLOAD(wrapped, ...args) {
  let baseTexture = args[1];
  if (baseTexture.sequencer_patched || !game.settings.get(CONSTANTS.MODULE_NAME, "enable-global-pixi-fix")) {
    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 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, index) => {
      if (tokenFilter) {
        return tokenFilter(token, index);
      }
      const effects = getProperty(token, CONSTANTS.EFFECTS_FLAG) ?? [];
      const effectsOutOfDate = effects.filter(
        (e) => isNewerVersion(version, e[1].flagVersion)
      );
      return effectsOutOfDate.length;
    })
  ]).filter(([_, tokens]) => tokens.length);
}
function getSequencerEffectActors(version, actorFilter = false) {
  return Array.from(game.actors).filter((actor, index) => {
    if (actorFilter) {
      return actorFilter(actor, index);
    }
    const effects = getProperty(actor, CONSTANTS.EFFECTS_FLAG) ?? [];
    const effectsOutOfDate = effects.filter(
      (e) => isNewerVersion(version, e[1].flagVersion)
    );
    return effectsOutOfDate.length;
  });
}
const migrations = {
  "3.0.0": async (version) => {
    const actorsToUpdate = getSequencerEffectActors(version, (actor) => {
      const effects = getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
      const effectsOutOfDate = effects.filter(
        (e) => isNewerVersion(version, e[1].flagVersion)
      );
      return effectsOutOfDate.length;
    });
    const actorUpdateArray = actorsToUpdate.map((actor) => {
      const effectsToMoveFromTokenPrototype = getProperty(
        actor.prototypeToken,
        CONSTANTS.EFFECTS_FLAG
      ).filter(([_, effect]) => {
        return effect.persistOptions?.persistTokenPrototype;
      }).map(([id, effect]) => {
        effect.flagVersion = version;
        return [id, effect];
      });
      const effectsToKeepOnTokenPrototype = 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 = getProperty(t, CONSTANTS.EFFECTS_FLAG) ?? [];
      const prototypeTokenEffects = getProperty(actor, "prototypeToken." + CONSTANTS.EFFECTS_FLAG) ?? [];
      const effectsOutOfDate = effects.filter(
        (e) => isNewerVersion(version, e[1].flagVersion)
      );
      const prototypeEffectsOutOfDate = prototypeTokenEffects.filter(
        (e) => 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 = 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) {
        console.log(
          `Sequencer | Updated ${updates.length} tokens' effects on scene ${scene.id} to version ${version}`
        );
        await scene.updateEmbeddedDocuments("Token", updates);
      }
    }
    if (actorUpdateArray.length) {
      console.log(
        `Sequencer | Updated ${actorUpdateArray.length} actors' effects to version ${version}`
      );
      await Actor.updateDocuments(actorUpdateArray);
    }
  }
};
Hooks.once("init", async function() {
  if (!game.modules.get("socketlib")?.active)
    return;
  CONSTANTS.INTEGRATIONS.ISOMETRIC.ACTIVE = false;
  initialize_module();
});
Hooks.once("socketlib.ready", () => {
  registerSocket();
});
Hooks.once("ready", async function() {
  if (!game.modules.get("socketlib")?.active) {
    ui.notifications.error(
      "Sequencer requires the SocketLib module to be active and will not work without it!",
      { console: true }
    );
    return;
  }
  for (const [name, func2] of Object.entries(easeFunctions)) {
    if (!CanvasAnimation[name]) {
      CanvasAnimation[name] = func2;
    }
  }
  await runMigrations();
  PlayerSettings.migrateOldPresets();
  SequencerFoundryReplicator.registerHooks();
  InteractionManager.initialize();
  setTimeout(() => {
    console.log("Sequencer | Ready to go!");
    Hooks.callAll("sequencer.ready");
    Hooks.callAll("sequencerReady");
    migrateSettings();
    SequencerEffectManager.setUpPersists();
    Hooks.on("canvasReady", () => {
      SequencerEffectManager.setUpPersists();
    });
  }, 50);
});
function initialize_module() {
  window.Sequence = Sequence$1;
  window.Sequencer = {
    Player: EffectPlayer,
    Presets: SequencerPresets,
    Database: SequencerDatabase,
    DatabaseViewer: DatabaseViewerApp,
    Preloader: SequencerPreloader,
    EffectManager: SequencerEffectManager,
    SectionManager: new SequencerSectionManager(),
    registerEase,
    BaseSection: Section,
    CONSTANTS: {
      EASE
    },
    Helpers: {
      wait: wait$1,
      clamp,
      interpolate,
      random_float_between,
      random_int_between,
      shuffle_array,
      random_array_element,
      random_object_element,
      make_array_unique
    }
  };
  registerSettings();
  registerLayers();
  registerHotkeys();
  registerLibwrappers();
  SequencerAboveUILayer.setup();
  Hooks.on(
    "preCreateToken",
    (...args) => Sequencer.EffectManager.patchCreationData(...args)
  );
  Hooks.on(
    "preCreateDrawing",
    (...args) => Sequencer.EffectManager.patchCreationData(...args)
  );
  Hooks.on(
    "preCreateTile",
    (...args) => Sequencer.EffectManager.patchCreationData(...args)
  );
  Hooks.on(
    "preCreateMeasuredTemplate",
    (...args) => Sequencer.EffectManager.patchCreationData(...args)
  );
  Hooks.on(
    "createToken",
    (...args) => Sequencer.EffectManager.documentCreated(...args)
  );
  Hooks.on(
    "createDrawing",
    (...args) => Sequencer.EffectManager.documentCreated(...args)
  );
  Hooks.on(
    "createTile",
    (...args) => Sequencer.EffectManager.documentCreated(...args)
  );
  Hooks.on(
    "createMeasuredTemplate",
    (...args) => Sequencer.EffectManager.documentCreated(...args)
  );
}
Hooks.once("monaco-editor.ready", registerTypes);
//# sourceMappingURL=module.js.map
